supply system proxy settings to management itf

Proxy settings are fetched from the users Internet Options
for the active connection. If WPAD or a PAC script is configured
they are preferred and used for automatic proxy detection.
Proxy bypass configuration is completely ignored.
pull/1/head
Heiko Hund 2012-07-19 15:14:34 +02:00
parent 2156479232
commit e84834a08a
9 changed files with 248 additions and 30 deletions

View File

@ -91,7 +91,8 @@ openvpn_gui_LDADD = \
openvpn-gui-res.o \ openvpn-gui-res.o \
$(OPENSSL_CRYPTO_LIBS) \ $(OPENSSL_CRYPTO_LIBS) \
-lws2_32 \ -lws2_32 \
-lcomctl32 -lcomctl32 \
-lwinhttp
openvpn-gui-res.o: $(openvpn_gui_RESOURCES) $(srcdir)/openvpn-gui-res.h openvpn-gui-res.o: $(openvpn_gui_RESOURCES) $(srcdir)/openvpn-gui-res.h
$(RCCOMPILE) -i $< -o $@ $(RCCOMPILE) -i $< -o $@

1
main.c
View File

@ -105,6 +105,7 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance,
{ log, OnLogLine }, { log, OnLogLine },
{ state, OnStateChange }, { state, OnStateChange },
{ password, OnPassword }, { password, OnPassword },
{ proxy, OnProxy },
{ stop, OnStop }, { stop, OnStop },
{ 0, NULL } { 0, NULL }
}; };

View File

@ -256,6 +256,11 @@ OnManagement(SOCKET sk, LPARAM lParam)
if (rtmsg_handler[password]) if (rtmsg_handler[password])
rtmsg_handler[password](c, pos + 9); rtmsg_handler[password](c, pos + 9);
} }
else if (strncmp(pos, "PROXY:", 6) == 0)
{
if (rtmsg_handler[proxy])
rtmsg_handler[proxy](c, pos + 6);
}
else if (strncmp(pos, "INFO:", 5) == 0) else if (strncmp(pos, "INFO:", 5) == 0)
{ {
/* delay until management interface accepts input */ /* delay until management interface accepts input */

View File

@ -34,6 +34,7 @@ typedef enum {
hold, hold,
log, log,
password, password,
proxy,
state, state,
needok, needok,
needstr, needstr,

21
misc.c
View File

@ -102,3 +102,24 @@ ManagementCommandFromInput(connection_t *c, LPSTR fmt, HWND hDlg, int id)
return retval; return retval;
} }
/*
* Various string helper functions
*/
BOOL
streq(LPCSTR str1, LPCSTR str2)
{
return (strcmp(str1, str2) == 0);
}
BOOL
wcsbegins(LPCWSTR str, LPCWSTR begin)
{
return (wcsncmp(str, begin, wcslen(begin)) == 0);
}
BOOL
wcseq(LPCWSTR str1, LPCWSTR str2)
{
return (wcscmp(str1, str2) == 0);
}

4
misc.h
View File

@ -24,4 +24,8 @@
BOOL ManagementCommandFromInput(connection_t *, LPSTR, HWND, int); BOOL ManagementCommandFromInput(connection_t *, LPSTR, HWND, int);
BOOL streq(LPCSTR, LPCSTR);
BOOL wcsbegins(LPCWSTR, LPCWSTR);
BOOL wcseq(LPCWSTR, LPCWSTR);
#endif #endif

View File

@ -621,7 +621,6 @@ StartOpenVPN(connection_t *c)
{ {
TCHAR cmdline[1024]; TCHAR cmdline[1024];
TCHAR *options = cmdline + 8; TCHAR *options = cmdline + 8;
TCHAR proxy_string[100];
TCHAR exit_event_name[17]; TCHAR exit_event_name[17];
HANDLE hStdInRead = NULL, hStdInWrite = NULL; HANDLE hStdInRead = NULL, hStdInWrite = NULL;
HANDLE hNul = NULL, hThread = NULL, service = NULL; HANDLE hNul = NULL, hThread = NULL, service = NULL;
@ -659,18 +658,14 @@ StartOpenVPN(connection_t *c)
/* Create a management interface password */ /* Create a management interface password */
GetRandomPassword(c->manage.password, sizeof(c->manage.password) - 1); GetRandomPassword(c->manage.password, sizeof(c->manage.password) - 1);
/* Construct proxy string to append to command line */
ConstructProxyCmdLine(proxy_string, _countof(proxy_string));
/* Construct command line */ /* Construct command line */
_sntprintf_0(cmdline, _T("openvpn " _sntprintf_0(cmdline, _T("openvpn "
"--config \"%s\" %s --service %s 0 --log%s \"%s\" " "--config \"%s\" --service %s 0 --log%s \"%s\" --auth-retry interact "
"--management %S %hd stdin --auth-retry interact " "--management %S %hd stdin --management-query-passwords %s"
"--management-hold --management-query-passwords --tls-exit"), "--management-hold --tls-exit"), c->config_file, exit_event_name,
c->config_file, proxy_string, exit_event_name, (o.append_string[0] == '1' ? _T("-append") : _T("")), c->log_path,
(o.append_string[0] == '1' ? _T("-append") : _T("")), inet_ntoa(c->manage.skaddr.sin_addr), ntohs(c->manage.skaddr.sin_port),
c->log_path, inet_ntoa(c->manage.skaddr.sin_addr), (o.proxy_source != config ? _T("--management-query-proxy ") : _T("")));
ntohs(c->manage.skaddr.sin_port));
/* Try to open the service pipe */ /* Try to open the service pipe */
service = CreateFile(_T("\\\\.\\pipe\\openvpn\\service"), service = CreateFile(_T("\\\\.\\pipe\\openvpn\\service"),

207
proxy.c
View File

@ -28,7 +28,7 @@
#include <windows.h> #include <windows.h>
#include <prsht.h> #include <prsht.h>
#include <tchar.h> #include <tchar.h>
#include <wininet.h> #include <winhttp.h>
#include <stdlib.h> #include <stdlib.h>
#include "main.h" #include "main.h"
@ -361,28 +361,211 @@ ProxyAuthDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
} }
/* typedef enum { HTTPS_URL, SOCKS_URL } url_scheme;
* Construct the proxy options to append to the cmd-line. static LPCWSTR
*/ UrlSchemeStr(const url_scheme scheme)
void ConstructProxyCmdLine(TCHAR *proxy_string, unsigned int size)
{ {
proxy_string[0] = _T('\0'); static LPCWSTR scheme_strings[] = { L"https", L"socks" };
return scheme_strings[scheme];
}
static LPWSTR
QueryWindowsProxySettings(const url_scheme scheme, LPCSTR host)
{
LPWSTR proxy = NULL;
BOOL auto_detect = TRUE;
LPWSTR auto_config_url = NULL;
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxy_config;
if (WinHttpGetIEProxyConfigForCurrentUser(&proxy_config))
{
proxy = proxy_config.lpszProxy;
auto_detect = proxy_config.fAutoDetect;
auto_config_url = proxy_config.lpszAutoConfigUrl;
GlobalFree(proxy_config.lpszProxyBypass);
}
if (auto_detect)
{
LPWSTR old_url = auto_config_url;
DWORD flags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
if (WinHttpDetectAutoProxyConfigUrl(flags, &auto_config_url))
GlobalFree(old_url);
}
if (auto_config_url)
{
HINTERNET session = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (session)
{
int size = _snwprintf(NULL, 0, L"%s://%S", UrlSchemeStr(scheme), host) + 1;
LPWSTR url = malloc(size * sizeof(WCHAR));
if (url)
{
_snwprintf(url, size, L"%s://%S", UrlSchemeStr(scheme), host);
LPWSTR old_proxy = proxy;
WINHTTP_PROXY_INFO proxy_info;
WINHTTP_AUTOPROXY_OPTIONS options = {
.fAutoLogonIfChallenged = TRUE,
.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL,
.lpszAutoConfigUrl = auto_config_url,
.dwAutoDetectFlags = 0,
.lpvReserved = NULL,
.dwReserved = 0
};
if (WinHttpGetProxyForUrl(session, url, &options, &proxy_info))
{
GlobalFree(old_proxy);
GlobalFree(proxy_info.lpszProxyBypass);
proxy = proxy_info.lpszProxy;
}
free(url);
}
WinHttpCloseHandle(session);
}
GlobalFree(auto_config_url);
}
return proxy;
}
static VOID
ParseProxyString(LPWSTR proxy_str, url_scheme scheme,
LPCSTR *type, LPCWSTR *host, LPCWSTR *port)
{
LPCWSTR delim = L"; ";
LPWSTR token = wcstok(proxy_str, delim);
LPCWSTR scheme_str = UrlSchemeStr(scheme);
LPCWSTR socks_str = UrlSchemeStr(SOCKS_URL);
/* Token format: [<scheme>=][<scheme>"://"]<server>[":"<port>] */
while (token)
{
BOOL match = FALSE;
LPWSTR eq = wcschr(token, '=');
LPWSTR css = wcsstr(token, L"://");
/*
* If the token has a <scheme>, test for the one we're looking for.
* If we're looking for a https proxy, socks will also do.
* If it's a proxy without a <scheme> it's only good for https.
*/
if (eq || css)
{
if (wcsbegins(token, scheme_str))
{
match = TRUE;
}
else if (scheme == HTTPS_URL && wcsbegins(token, socks_str))
{
match = TRUE;
scheme = SOCKS_URL;
}
}
else if (scheme == HTTPS_URL)
{
match = TRUE;
}
if (match)
{
LPWSTR server = token;
if (css)
server = css + 3;
else if (eq)
server = eq + 1;
/* IPv6 addresses are surrounded by brackets */
LPWSTR port_delim;
if (server[0] == '[')
{
server += 1;
LPWSTR end = wcschr(server, ']');
if (end == NULL)
continue;
*end++ = '\0';
port_delim = (*end == ':' ? end : NULL);
}
else
{
port_delim = wcsrchr(server, ':');
if (port_delim)
*port_delim = '\0';
}
*type = (scheme == HTTPS_URL ? "HTTP" : "SOCKS");
*host = server;
if (port_delim)
*port = port_delim + 1;
else
*port = (scheme == HTTPS_URL ? L"80": L"1080");
break;
}
token = wcstok(NULL, delim);
}
}
/*
* Respond to management interface PROXY notifications
* Input format: REMOTE_NO,PROTOCOL,HOST
*/
void
OnProxy(connection_t *c, char *line)
{
LPSTR proto, host;
char *pos = strchr(line, ',');
if (pos == NULL)
return;
proto = ++pos;
pos = strchr(pos, ',');
if (pos == NULL)
return;
*pos = '\0';
host = ++pos;
if (host[0] == '\0')
return;
LPCSTR type = "NONE";
LPCWSTR addr = L"", port = L"";
LPWSTR proxy_str = NULL;
if (o.proxy_source == manual) if (o.proxy_source == manual)
{ {
if (o.proxy_type == http) if (o.proxy_type == http && streq(proto, "TCP"))
{ {
__sntprintf_0(proxy_string, size, _T(" --http-proxy %s %s auto"), type = "HTTP";
o.proxy_http_address, o.proxy_http_port); addr = o.proxy_http_address;
port = o.proxy_http_port;
} }
else if (o.proxy_type == socks) else if (o.proxy_type == socks)
{ {
__sntprintf_0(proxy_string, size, _T(" --socks-proxy %s %s"), type = "SOCKS";
o.proxy_socks_address, o.proxy_socks_port); addr = o.proxy_socks_address;
port = o.proxy_socks_port;
} }
} }
else if (o.proxy_source == windows) else if (o.proxy_source == windows)
{ {
__sntprintf_0(proxy_string, size, _T(" --auto-proxy")); url_scheme scheme = (streq(proto, "TCP") ? HTTPS_URL : SOCKS_URL);
proxy_str = QueryWindowsProxySettings(scheme, host);
ParseProxyString(proxy_str, scheme, &type, &addr, &port);
} }
char cmd[128];
snprintf(cmd, sizeof(cmd), "proxy %s %S %S", type, addr, port);
cmd[sizeof(cmd) - 1] = '\0';
ManagementCommand(c, cmd, NULL, regular);
GlobalFree(proxy_str);
} }

19
proxy.h
View File

@ -19,10 +19,17 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
INT_PTR CALLBACK ProxySettingsDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); #ifndef PROXY_H
int CheckProxySettings(HWND hwndDlg); #define PROXY_H
void LoadProxySettings(HWND hwndDlg);
void SaveProxySettings(HWND hwndDlg); INT_PTR CALLBACK ProxySettingsDialogFunc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK ProxyAuthDialogFunc(HWND, UINT, WPARAM, LPARAM);
void OnProxy(connection_t *, char *);
int CheckProxySettings(HWND);
void LoadProxySettings(HWND);
void SaveProxySettings(HWND);
void GetProxyRegistrySettings(); void GetProxyRegistrySettings();
INT_PTR CALLBACK ProxyAuthDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
void ConstructProxyCmdLine(TCHAR *proxy_string_ptr, unsigned int size); #endif