-
-
Save roninhack/3a90ec759fcb7ec4a8165e780fa26b8f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * configure_wininet_proxy - Configure Internet Options proxy on Windows | |
| * Copyright (C) 2017 Hitachi ID Systems, Inc. | |
| * | |
| * This program is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation, either version 3 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| * | |
| * --------------------------------------------------------------------- | |
| * | |
| * To compile using a fully-configured SDK or MSVC environment: | |
| * cl.exe configure_wininet_proxy.c /link wininet.lib | |
| */ | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <windows.h> | |
| #include <wininet.h> | |
| static | |
| void usage(const char* prog_name) | |
| { | |
| for (const char* current = prog_name; *current; ++current) | |
| { | |
| if (*current == '\\' && current[1] != '\0') | |
| prog_name = ¤t[1]; | |
| } | |
| printf( | |
| "Usage:\n" | |
| " %s [-h] [-d] [URI [BYPASS]]\n" | |
| "\n" | |
| "Where:\n" | |
| "\n" | |
| " -h Show this help output.\n" | |
| "\n" | |
| " -d Disable automatically detect settings (default: enable).\n" | |
| "\n" | |
| " URI The proxy URI to use; eg http://10.0.0.4:80.\n" | |
| " If omitted, proxy is disabled.\n" | |
| "\n" | |
| " BYPASS Optional semicolon-separated bypass list when enabling proxy.\n" | |
| " Example: \"*.hitachi-id.com;<local>\".\n" | |
| " Default is to not bypass anything.\n" | |
| " WARNING: if including \"<local>\", be sure to double-quote the entire\n" | |
| " argument or you may unintentionally trigger I/O-redirection.\n" | |
| "\n", | |
| prog_name | |
| ); | |
| exit(0); | |
| } | |
| typedef struct { | |
| DWORD flags; | |
| const char* host_port; | |
| const char* bypass; | |
| const char* wpad_url; | |
| } config_t; | |
| static | |
| config_t parse_opts(int argc, const char* argv[]) | |
| { | |
| config_t result; | |
| result.flags = PROXY_TYPE_AUTO_DETECT | PROXY_TYPE_DIRECT; | |
| result.host_port = NULL; | |
| result.bypass = NULL; | |
| result.wpad_url = NULL; | |
| int i, num_positional=0; | |
| for (i=1; i < argc; ++i) | |
| { | |
| if (argv[i][0] == '-') | |
| { | |
| if (_stricmp(argv[i], "-h") == 0) | |
| usage(argv[0]); | |
| else if (_stricmp(argv[i], "-d") == 0) | |
| result.flags &= ~((DWORD)PROXY_TYPE_AUTO_DETECT); | |
| else | |
| { | |
| printf("Unknown option: %s\n", argv[i]); | |
| exit(2); | |
| } | |
| } | |
| else if (num_positional == 0) | |
| { | |
| if (argv[i][0] != '\0') // mustn't be an empty string | |
| { | |
| result.host_port = argv[i]; | |
| result.flags |= PROXY_TYPE_PROXY | PROXY_TYPE_DIRECT; | |
| } | |
| num_positional++; | |
| } | |
| else if (num_positional == 1 && result.host_port != NULL) | |
| { | |
| if (argv[i][0] != '\0') // mustn't be an empty string | |
| result.bypass = argv[i]; | |
| num_positional++; | |
| } | |
| else | |
| { | |
| printf("Unexpected extra argument: %s\n", argv[i]); | |
| exit(2); | |
| } | |
| } | |
| return result; | |
| } | |
| static | |
| void report_error(const char* description) | |
| { | |
| DWORD err_num = GetLastError(); | |
| char message_buffer[1024]; | |
| DWORD bytes = FormatMessage( | |
| FORMAT_MESSAGE_FROM_SYSTEM, NULL, err_num, 0, | |
| message_buffer, sizeof(message_buffer), NULL | |
| ); | |
| if (bytes) | |
| { | |
| fprintf(stderr, "%s: %s\n", description, message_buffer); | |
| exit(3); | |
| } | |
| else | |
| { | |
| fprintf(stderr, "%s: Unknown error with internal code H%08x\n", description, err_num); | |
| exit(4); | |
| } | |
| } | |
| static | |
| config_t query_existing_configuration() | |
| { | |
| INTERNET_PER_CONN_OPTION options[4]; | |
| options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI; | |
| options[0].Value.dwValue = 0xFFFFFFFFu; | |
| options[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER; | |
| options[1].Value.pszValue = NULL; | |
| options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; | |
| options[2].Value.pszValue = NULL; | |
| options[3].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; | |
| options[3].Value.pszValue = NULL; | |
| INTERNET_PER_CONN_OPTION_LIST list; | |
| list.dwSize = sizeof(list); | |
| list.pszConnection = NULL; | |
| list.dwOptionCount = sizeof(options) / sizeof(INTERNET_PER_CONN_OPTION); | |
| list.dwOptionError = 0; | |
| list.pOptions = options; | |
| DWORD result_sz = sizeof(list); | |
| BOOL rc = InternetQueryOption(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, &result_sz); | |
| if (!rc) | |
| report_error("Querying existing configuration"); | |
| config_t result; | |
| result.flags = options[0].Value.dwValue; | |
| result.host_port = options[1].Value.pszValue; | |
| result.bypass = options[2].Value.pszValue; | |
| result.wpad_url = options[3].Value.pszValue; | |
| return result; | |
| } | |
| static | |
| void configure(const config_t* requested_config) | |
| { | |
| INTERNET_PER_CONN_OPTION options[4]; | |
| options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI; | |
| options[0].Value.dwValue = requested_config->flags; | |
| options[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER; | |
| options[1].Value.pszValue = (char*)requested_config->host_port; | |
| options[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS; | |
| options[2].Value.pszValue = (char*)requested_config->bypass; | |
| options[3].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL; | |
| options[3].Value.pszValue = (char*)requested_config->wpad_url; | |
| INTERNET_PER_CONN_OPTION_LIST list; | |
| list.dwSize = sizeof(list); | |
| list.pszConnection = NULL; | |
| list.dwOptionCount = sizeof(options) / sizeof(INTERNET_PER_CONN_OPTION); | |
| list.dwOptionError = 0; | |
| list.pOptions = options; | |
| BOOL rc = InternetSetOption(NULL, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, sizeof(list)); | |
| if (!rc) | |
| report_error("Setting new configuration"); | |
| } | |
| static | |
| int compare_strings_ci(const char* s1, const char* s2) | |
| { | |
| if (s1 && s2) | |
| return _stricmp(s1, s2) == 0; | |
| else | |
| return s1 == NULL && s2 == NULL; | |
| } | |
| int main(int argc, const char* argv[]) | |
| { | |
| config_t requested_config = parse_opts(argc, argv); | |
| config_t existing_config = query_existing_configuration(); // new allocations in here! | |
| int same_flags = existing_config.flags == requested_config.flags; | |
| int same_host_port = compare_strings_ci(existing_config.host_port, requested_config.host_port); | |
| int same_bypass = compare_strings_ci(existing_config.bypass, requested_config.bypass); | |
| int same_wpad_url = compare_strings_ci(existing_config.wpad_url, requested_config.wpad_url); | |
| int change_needed = !(same_flags && same_host_port && same_bypass && same_wpad_url); | |
| if (change_needed) | |
| { | |
| configure(&requested_config); | |
| printf("Proxy configuration updated.\n"); | |
| } | |
| else | |
| { | |
| printf("Configuration already set; no changes required.\n"); | |
| } | |
| // clean-up | |
| if (GlobalFree((char*)existing_config.host_port)) report_error("freeing existing host_port reference"); | |
| if (GlobalFree((char*)existing_config.bypass)) report_error("freeing existing bypass reference"); | |
| if (GlobalFree((char*)existing_config.wpad_url)) report_error("freeing existing wpad_url reference"); | |
| return change_needed; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment