Skip to content

Instantly share code, notes, and snippets.

@roninhack
Forked from johnboy2/configure_wininet_proxy.c
Created December 18, 2017 15:21
Show Gist options
  • Select an option

  • Save roninhack/3a90ec759fcb7ec4a8165e780fa26b8f to your computer and use it in GitHub Desktop.

Select an option

Save roninhack/3a90ec759fcb7ec4a8165e780fa26b8f to your computer and use it in GitHub Desktop.
/*
* 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 = &current[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