summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2005-12-12 19:46:10 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2005-12-12 19:46:10 +0000
commitf214bb2115994cc6b4123f3d06db0452f17f2e99 (patch)
tree7a09094e169f4097ceb033204c171eba2a51ae59
parentdf5722cc68307206c5edcc94fd7ae333d3212b59 (diff)
downloadopenvpn-f214bb2115994cc6b4123f3d06db0452f17f2e99.tar.gz
openvpn-f214bb2115994cc6b4123f3d06db0452f17f2e99.tar.xz
openvpn-f214bb2115994cc6b4123f3d06db0452f17f2e99.zip
Added --auto-proxy directive to auto-detect HTTP or SOCKS
proxy settings (currently Windows only). git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@850 e7ae566f-a301-0410-adde-c780ea21d3b5
-rw-r--r--ChangeLog7
-rw-r--r--Makefile.am3
-rw-r--r--base64.c26
-rw-r--r--base64.h4
-rw-r--r--buffer.c12
-rw-r--r--buffer.h3
-rw-r--r--init.c14
-rwxr-xr-xmakefile.w322
-rw-r--r--openvpn.830
-rw-r--r--options.c146
-rw-r--r--options.h4
-rw-r--r--proxy.c388
-rw-r--r--proxy.h37
-rw-r--r--socket.c81
-rw-r--r--socks.c15
-rw-r--r--socks.h1
-rw-r--r--syshead.h8
17 files changed, 539 insertions, 242 deletions
diff --git a/ChangeLog b/ChangeLog
index 1fe18e7..a186b6f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,7 +3,7 @@ Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
$Id$
-2005.11.xx -- Version 2.1-beta8
+2005.12.xx -- Version 2.1-beta8
* --remap-usr1 will now also remap signals thrown during
initialization.
@@ -17,6 +17,8 @@ $Id$
* Fixed typo in manage.c where inline function declaration
was declared without the "static" keyword (David Stipp).
* Patch to support --topology subnet on Mac OS X (Mathias Sundman).
+* Added --auto-proxy directive to auto-detect HTTP or SOCKS
+ proxy settings (currently Windows only).
2005.11.12 -- Version 2.1-beta7
@@ -29,7 +31,8 @@ $Id$
but actually would only accept /29 or less.
* Extend byte counters to 64 bits (M. van Cuijk).
* PKCS#11 fixes (Alon Bar-Lev).
-
+* Removed redundant base64 code.
+
2005.11.02 -- Version 2.0.5
* Fixed bug in Linux get_default_gateway function
diff --git a/Makefile.am b/Makefile.am
index ebfa22d..424b167 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -127,8 +127,7 @@ EXTRA_DIST = \
plugin \
management \
pkcs11-headers \
- cryptoki-win32.h \
- ieproxy.c ieproxy.h
+ cryptoki-win32.h
dist-hook:
cd $(distdir) && for i in $(EXTRA_DIST) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done
diff --git a/base64.c b/base64.c
index dcdb0ee..a69633d 100644
--- a/base64.c
+++ b/base64.c
@@ -39,7 +39,7 @@
#include "syshead.h"
-#if NTLM
+#ifdef ENABLE_HTTP_PROXY
#include "base64.h"
@@ -48,16 +48,6 @@
static char base64_chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static int
-pos(char c)
-{
- char *p;
- for (p = base64_chars; *p; p++)
- if (*p == c)
- return p - base64_chars;
- return -1;
-}
-
int
base64_encode(const void *data, int size, char **str)
{
@@ -96,6 +86,18 @@ base64_encode(const void *data, int size, char **str)
return strlen(s);
}
+#if NTLM
+
+static int
+pos(char c)
+{
+ char *p;
+ for (p = base64_chars; *p; p++)
+ if (*p == c)
+ return p - base64_chars;
+ return -1;
+}
+
#define DECODE_ERROR 0xffffffff
static unsigned int
@@ -141,6 +143,8 @@ base64_decode(const char *str, void *data)
return q - (unsigned char *) data;
}
+#endif /* NTLM */
+
#else
static void dummy(void) {}
#endif
diff --git a/base64.h b/base64.h
index 0cd43fa..a966b2d 100644
--- a/base64.h
+++ b/base64.h
@@ -31,12 +31,10 @@
* SUCH DAMAGE.
*/
-/* $KTH: base64.h,v 1.2 1999/12/02 16:58:45 joda Exp $ */
-
#ifndef _BASE64_H_
#define _BASE64_H_
-#if NTLM
+#ifdef ENABLE_HTTP_PROXY
int base64_encode(const void *data, int size, char **str);
int base64_decode(const char *str, void *data);
diff --git a/buffer.c b/buffer.c
index 5ff6123..e66c6a4 100644
--- a/buffer.c
+++ b/buffer.c
@@ -621,6 +621,18 @@ buf_parse (struct buffer *buf, const int delim, char *line, const int size)
}
/*
+ * Print a string which might be NULL
+ */
+const char *
+np (const char *str)
+{
+ if (str)
+ return str;
+ else
+ return "[NULL]";
+}
+
+/*
* Classify and mutate strings based on character types.
*/
diff --git a/buffer.h b/buffer.h
index 63a4763..f95c5e1 100644
--- a/buffer.h
+++ b/buffer.h
@@ -553,8 +553,9 @@ xor (uint8_t *dest, const uint8_t *src, int len)
}
/*
- * Classify and mutate strings based on character types.
+ * Print a string which might be NULL
*/
+const char *np (const char *str);
/*#define CHARACTER_CLASS_DEBUG*/
diff --git a/init.c b/init.c
index ea1acc3..c90cb5d 100644
--- a/init.c
+++ b/init.c
@@ -102,6 +102,12 @@ init_remote_list (struct context *c)
void
context_init_1 (struct context *c)
{
+#ifdef ENABLE_HTTP_PROXY
+ bool did_http = false;
+#else
+ const bool did_http = false;
+#endif
+
context_clear_1 (c);
packet_id_persist_init (&c->c1.pid_persist);
@@ -145,20 +151,24 @@ context_init_1 (struct context *c)
#endif
#ifdef ENABLE_HTTP_PROXY
- if (c->options.http_proxy_options)
+ if (c->options.http_proxy_options || c->options.auto_proxy_info)
{
/* Possible HTTP proxy user/pass input */
c->c1.http_proxy = new_http_proxy (c->options.http_proxy_options,
+ c->options.auto_proxy_info,
&c->gc);
+ if (c->c1.http_proxy)
+ did_http = true;
}
#endif
#ifdef ENABLE_SOCKS
- if (c->options.socks_proxy_server)
+ if (!did_http && (c->options.socks_proxy_server || c->options.auto_proxy_info))
{
c->c1.socks_proxy = new_socks_proxy (c->options.socks_proxy_server,
c->options.socks_proxy_port,
c->options.socks_proxy_retry,
+ c->options.auto_proxy_info,
&c->gc);
}
#endif
diff --git a/makefile.w32 b/makefile.w32
index c612512..22fbc28 100755
--- a/makefile.w32
+++ b/makefile.w32
@@ -78,7 +78,6 @@ HEADERS = \
fragment.h \
gremlin.h \
helper.h \
- ieproxy.h \
init.h \
integer.h \
interval.h \
@@ -137,7 +136,6 @@ OBJS = base64.o \
fragment.o \
gremlin.o \
helper.o \
- ieproxy.o \
init.o \
interval.o \
list.o \
diff --git a/openvpn.8 b/openvpn.8
index 8cd2b25..3b14a3e 100644
--- a/openvpn.8
+++ b/openvpn.8
@@ -101,6 +101,7 @@ openvpn \- secure IP tunnel daemon.
[\ \fB\-\-auth\-user\-pass\-verify\fR\ \fIscript\fR\ ]
[\ \fB\-\-auth\-user\-pass\fR\ \fIup\fR\ ]
[\ \fB\-\-auth\fR\ \fIalg\fR\ ]
+[\ \fB\-\-auto\-proxy\fR\ ]
[\ \fB\-\-bcast\-buffers\fR\ \fIn\fR\ ]
[\ \fB\-\-ca\fR\ \fIfile\fR\ ]
[\ \fB\-\-ccd\-exclusive\fR\ ]
@@ -597,7 +598,19 @@ as the
number of retries of connection attempt (default=infinite).
.\"*********************************************************
.TP
-.B --http-proxy server port [authfile] [auth-method]
+.B --auto-proxy
+Try to sense HTTP or SOCKS proxy settings automatically.
+If no settings are present, a direct connection will be attempted.
+If both HTTP and SOCKS settings are present, HTTP will be preferred.
+If the HTTP proxy server requires a password, it will be queried from
+stdin or the management interface. If the underlying OS doesn't support an API for
+returning proxy settings, a direct connection will be attempted.
+Currently, only Windows clients support this option via the
+InternetQueryOption API.
+This option exists in OpenVPN 2.1 or higher.
+.\"*********************************************************
+.TP
+.B --http-proxy server port [authfile|'auto'] [auth-method]
Connect to remote host through an HTTP proxy at address
.B server
and port
@@ -608,7 +621,15 @@ is a file containing a username and password on 2 lines, or
"stdin" to prompt from console.
.B auth-method
-should be one of "none", "basic", or "ntlm".
+should be one of "none", "basic", or "ntlm".
+
+The
+.B auto
+flag causes OpenVPN to automatically determine the
+.B auth-method
+and query stdin or the management interface for
+username/password credentials, if required. This flag
+exists on OpenVPN 2.1 or higher.
.\"*********************************************************
.TP
.B --http-proxy-retry
@@ -857,6 +878,8 @@ of the TAP-Win32 driver. When used on *nix, requires that the tun
driver supports an
.BR ifconfig (8)
command which sets a subnet instead of a remote endpoint IP address.
+
+This option exists in OpenVPN 2.1 or higher.
.\"*********************************************************
.TP
.B --tun-ipv6
@@ -1175,8 +1198,7 @@ bypasses the tunnel
(Available on Windows clients, may not be available
on non-Windows clients).
-Using the def1 flag is highly recommended, and is currently
-planned to become the default by OpenVPN 2.1.
+Using the def1 flag is highly recommended.
.\"*********************************************************
.TP
.B --link-mtu n
diff --git a/options.c b/options.c
index ebe61d0..d02530e 100644
--- a/options.c
+++ b/options.c
@@ -97,12 +97,18 @@ static const char usage_message[] =
" between connection retries (default=%d).\n"
"--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
"--connect-retry-max n : Maximum connection attempt retries, default infinite.\n"
+#ifdef GENERAL_PROXY_SUPPORT
+ "--auto-proxy : Try to sense proxy settings (or lack thereof) automatically.\n"
+#endif
#ifdef ENABLE_HTTP_PROXY
- "--http-proxy s p [up] [auth] : Connect to remote host through an HTTP proxy at\n"
- " address s and port p. If proxy authentication is required,\n"
+ "--http-proxy s p [up] [auth] : Connect to remote host\n"
+ " through an HTTP proxy at address s and port p.\n"
+ " If proxy authentication is required,\n"
" up is a file containing username/password on 2 lines, or\n"
" 'stdin' to prompt from console. Add auth='ntlm' if\n"
" the proxy requires NTLM authentication.\n"
+ "--http-proxy s p 'auto': Like the above directive, but automatically determine\n"
+ " auth method and query for username/password if needed.\n"
"--http-proxy-retry : Retry indefinitely on HTTP proxy errors.\n"
"--http-proxy-timeout n : Proxy timeout in seconds, default=5.\n"
"--http-proxy-option type [parm] : Set extended HTTP proxy options.\n"
@@ -1537,8 +1543,8 @@ options_postprocess (struct options *options, bool first_time)
msg (M_USAGE, "--remote MUST be used in TCP Client mode");
#ifdef ENABLE_HTTP_PROXY
- if (options->http_proxy_options && options->proto != PROTO_TCPv4_CLIENT)
- msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
+ if ((options->http_proxy_options || options->auto_proxy_info) && options->proto != PROTO_TCPv4_CLIENT)
+ msg (M_USAGE, "--http-proxy or --auto-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
#endif
#if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_SOCKS)
@@ -3675,67 +3681,78 @@ add_option (struct options *options,
}
options->proto = proto;
}
-#ifdef ENABLE_HTTP_PROXY
- else if (streq (p[0], "http-proxy") && p[1])
+#ifdef GENERAL_PROXY_SUPPORT
+ else if (streq (p[0], "auto-proxy"))
{
- struct http_proxy_options *ho;
+ char *error = NULL;
VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->auto_proxy_info = get_proxy_settings (&error, &options->gc);
+ if (error)
+ msg (M_WARN, "PROXY: %s", error);
+ }
+ else if (streq (p[0], "show-proxy-settings"))
+ {
+ struct auto_proxy_info *pi;
+ char *error = NULL;
- if (streq (p[1], "auto"))
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ pi = get_proxy_settings (&error, &options->gc);
+ if (pi)
{
- struct http_proxy_options hpo;
- bool status;
- char *error = NULL;
-
- p[4] = p[3];
- p[3] = p[2];
- p[1] = p[2] = NULL;
- CLEAR (hpo);
-
- status = get_http_proxy_settings (&hpo, &error, &options->gc);
- if (status)
- {
- ho = init_http_options_if_undefined (options);
- ho->server = hpo.server;
- ho->port = hpo.port;
- }
- else
- {
- if (error)
- msg (M_WARN, "http-proxy auto error: %s", error);
- goto err;
- }
+ msg (M_INFO|M_NOPREFIX, "HTTP Server: %s", np(pi->http.server));
+ msg (M_INFO|M_NOPREFIX, "HTTP Port: %d", pi->http.port);
+ msg (M_INFO|M_NOPREFIX, "SOCKS Server: %s", np(pi->socks.server));
+ msg (M_INFO|M_NOPREFIX, "SOCKS Port: %d", pi->socks.port);
}
- else
- {
- int port;
- if (!p[2])
- {
- msg (msglevel, "http-proxy port number not defined");
- goto err;
- }
- port = atoi (p[2]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "Bad http-proxy port number: %s", p[2]);
- goto err;
- }
+ if (error)
+ msg (msglevel, "Proxy error: %s", error);
+#ifdef WIN32
+ show_win_proxy_settings (M_INFO|M_NOPREFIX);
+#endif
+ openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
+ }
+#endif /* GENERAL_PROXY_SUPPORT */
+#ifdef ENABLE_HTTP_PROXY
+ else if (streq (p[0], "http-proxy") && p[1])
+ {
+ struct http_proxy_options *ho;
- ho = init_http_options_if_undefined (options);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
- ho->server = p[1];
- ho->port = port;
- }
+ {
+ int port;
+ if (!p[2])
+ {
+ msg (msglevel, "http-proxy port number not defined");
+ goto err;
+ }
+ port = atoi (p[2]);
+ if (!legal_ipv4_port (port))
+ {
+ msg (msglevel, "Bad http-proxy port number: %s", p[2]);
+ goto err;
+ }
+
+ ho = init_http_options_if_undefined (options);
+
+ ho->server = p[1];
+ ho->port = port;
+ }
if (p[3])
{
- ho->auth_method_string = "basic";
- ho->auth_file = p[3];
-
- if (p[4])
+ if (streq (p[3], "auto"))
+ ho->auth_retry = true;
+ else
{
- ho->auth_method_string = p[4];
+ ho->auth_method_string = "basic";
+ ho->auth_file = p[3];
+
+ if (p[4])
+ {
+ ho->auth_method_string = p[4];
+ }
}
}
else
@@ -3778,29 +3795,6 @@ add_option (struct options *options,
msg (msglevel, "Bad http-proxy-option or missing parameter: '%s'", p[1]);
}
}
- else if (streq (p[0], "show-http-proxy-settings"))
- {
- struct http_proxy_options po;
- bool status;
- char *error = NULL;
-
- VERIFY_PERMISSION (OPT_P_GENERAL);
- CLEAR (po);
- status = get_http_proxy_settings (&po, &error, &options->gc);
- if (status)
- {
- msg (M_INFO|M_NOPREFIX, "Server: %s", po.server);
- msg (M_INFO|M_NOPREFIX, "Port: %d", po.port);
- }
- else
- {
- if (error)
- msg (msglevel, "Proxy error: %s", error);
- else
- msg (msglevel, "Proxy settings are undefined");
- }
- openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
- }
#endif
#ifdef ENABLE_SOCKS
else if (streq (p[0], "socks-proxy") && p[1])
diff --git a/options.h b/options.h
index 21484b7..644d7cb 100644
--- a/options.h
+++ b/options.h
@@ -250,6 +250,10 @@ struct options
struct route_option_list *routes;
bool route_nopull;
+#ifdef GENERAL_PROXY_SUPPORT
+ struct auto_proxy_info *auto_proxy_info;
+#endif
+
#ifdef ENABLE_HTTP_PROXY
struct http_proxy_options *http_proxy_options;
#endif
diff --git a/proxy.c b/proxy.c
index 0cfd51c..d2cc34b 100644
--- a/proxy.c
+++ b/proxy.c
@@ -28,8 +28,6 @@
#include "config.h"
#endif
-#ifdef ENABLE_HTTP_PROXY
-
#include "syshead.h"
#include "common.h"
@@ -38,6 +36,7 @@
#include "socket.h"
#include "fdmisc.h"
#include "proxy.h"
+#include "base64.h"
#include "ntlm.h"
#ifdef WIN32
@@ -46,55 +45,7 @@
#include "memdbg.h"
-#ifdef WIN32
-
-bool
-get_http_proxy_settings (struct http_proxy_options *p, char **err, struct gc_arena *gc)
-{
- bool ret = false;
- const char *result;
-
- p->server = NULL;
- p->port = 0;
- getIeHttpProxyError = NULL;
- if (err)
- *err = NULL;
-
- result = getIeHttpProxy ();
- if (result)
- {
- char addr_str[128];
- char port_str[16];
- struct buffer in;
- buf_set_read (&in, (const uint8_t *)result, strlen (result));
- if (buf_parse (&in, ':', addr_str, sizeof (addr_str))
- && buf_parse (&in, ':', port_str, sizeof (port_str)))
- {
- p->server = string_alloc (addr_str, gc);
- p->port = atoi (port_str);
- ret = true;
- }
- free ((void *)result);
- }
- else if (getIeHttpProxyError)
- {
- if (err)
- *err = string_alloc (getIeHttpProxyError, gc);
- }
- return ret;
-}
-
-#else
-
-bool
-get_http_proxy_settings (struct http_proxy_options *p, char **err, struct gc_arena *gc)
-{
- if (err)
- *err = string_alloc ("HTTP proxy detection not supported on this OS", gc);
- return false;
-}
-
-#endif
+#ifdef ENABLE_HTTP_PROXY
/* cached proxy username/password */
static struct user_pass static_proxy_user_pass;
@@ -246,42 +197,12 @@ send_crlf (socket_descriptor_t sd)
uint8_t *
make_base64_string2 (const uint8_t *str, int src_len, struct gc_arena *gc)
{
- static const char base64_table[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
- uint8_t *buf;
- const uint8_t *src;
- uint8_t *dst;
- int bits, data, dst_len;
-
- /* make base64 string */
- dst_len = (src_len + 2) / 3 * 4;
- buf = gc_malloc (dst_len + 1, false, gc);
- bits = data = 0;
- src = str;
- dst = buf;
- while (dst_len--)
- {
- if (bits < 6)
- {
- data = (data << 8) | *src;
- bits += 8;
- src++;
- }
- *dst++ = base64_table[0x3F & (data >> (bits - 6))];
- bits -= 6;
- }
- *dst = '\0';
-
- /* fix-up tail padding */
- switch (src_len % 3)
- {
- case 1:
- *--dst = '=';
- case 2:
- *--dst = '=';
- }
- return buf;
+ uint8_t *ret = NULL;
+ char *b64out = NULL;
+ ASSERT (base64_encode ((const void *)str, src_len, &b64out) >= 0);
+ ret = (uint8_t *) string_alloc (b64out, gc);
+ free (b64out);
+ return ret;
}
uint8_t *
@@ -300,18 +221,67 @@ username_password_as_base64 (const struct http_proxy_info *p,
return (const char *)make_base64_string ((const uint8_t*)BSTR (&out), gc);
}
+static void
+get_user_pass_http (struct http_proxy_info *p, const bool force)
+{
+ if (!static_proxy_user_pass.defined || force)
+ {
+ get_user_pass (&static_proxy_user_pass,
+ p->options.auth_file,
+ "HTTP Proxy",
+ GET_USER_PASS_MANAGEMENT);
+ p->up = static_proxy_user_pass;
+ }
+}
+
struct http_proxy_info *
new_http_proxy (const struct http_proxy_options *o,
+ struct auto_proxy_info *auto_proxy_info,
struct gc_arena *gc)
{
struct http_proxy_info *p;
- ALLOC_OBJ_CLEAR_GC (p, struct http_proxy_info, gc);
+ struct http_proxy_options opt;
+
+ if (auto_proxy_info)
+ {
+ if (o && o->server)
+ {
+ /* if --http-proxy explicitly given, disable auto-proxy */
+ auto_proxy_info = NULL;
+ }
+ else
+ {
+ /* if no --http-proxy explicitly given and no auto settings, fail */
+ if (!auto_proxy_info->http.server)
+ return NULL;
- if (!o->server)
+ if (o)
+ {
+ opt = *o;
+ }
+ else
+ {
+ CLEAR (opt);
+
+ /* These settings are only used for --auto-proxy */
+ opt.timeout = 5;
+ opt.http_version = "1.0";
+ }
+
+ opt.server = auto_proxy_info->http.server;
+ opt.port = auto_proxy_info->http.port;
+ opt.auth_retry = true;
+
+ o = &opt;
+ }
+ }
+
+ if (!o || !o->server)
msg (M_FATAL, "HTTP_PROXY: server not specified");
ASSERT (legal_ipv4_port (o->port));
+ ALLOC_OBJ_CLEAR_GC (p, struct http_proxy_info, gc);
p->options = *o;
/* parse authentication method */
@@ -332,11 +302,7 @@ new_http_proxy (const struct http_proxy_options *o,
/* only basic and NTLM authentication supported so far */
if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM)
{
- get_user_pass (&static_proxy_user_pass,
- o->auth_file,
- "HTTP Proxy",
- GET_USER_PASS_MANAGEMENT);
- p->up = static_proxy_user_pass;
+ get_user_pass_http (p, true);
}
#if !NTLM
@@ -348,7 +314,7 @@ new_http_proxy (const struct http_proxy_options *o,
return p;
}
-void
+bool
establish_http_proxy_passthru (struct http_proxy_info *p,
socket_descriptor_t sd, /* already open to proxy */
const char *host, /* openvpn server remote */
@@ -362,6 +328,12 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
char get[80];
int status;
int nparms;
+ bool ret = false;
+
+ /* get user/pass if not previously given or if --auto-proxy is being used */
+ if (p->auth_method == HTTP_AUTH_BASIC
+ || p->auth_method == HTTP_AUTH_NTLM)
+ get_user_pass_http (p, false);
/* format HTTP CONNECT message */
openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
@@ -519,7 +491,21 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
ASSERT (0); /* No NTLM support */
#endif
}
- else goto error;
+ else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry)
+ {
+ /*
+ * Proxy needs authentication, but we don't have a user/pass.
+ * Now we will change p->auth_method and return true so that
+ * our caller knows to call us again on a newly opened socket.
+ * JYFIXME: This code needs to check proxy error output and set
+ * JYFIXME: p->auth_method = HTTP_AUTH_NTLM if necessary.
+ */
+ p->auth_method = HTTP_AUTH_BASIC;
+ ret = true;
+ goto done;
+ }
+ else
+ goto error;
}
@@ -527,7 +513,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
if (nparms < 1 || status != 200)
{
msg (D_LINK_ERRORS, "HTTP proxy returned bad status");
-#if 0
+#if 0
/* DEBUGGING -- show a multi-line HTTP error response */
while (true)
{
@@ -556,17 +542,221 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0));
#endif
+ done:
gc_free (&gc);
- return;
+ return ret;
error:
/* on error, should we exit or restart? */
if (!*signal_received)
*signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */
gc_free (&gc);
- return;
+ return ret;
}
#else
static void dummy(void) {}
#endif /* ENABLE_HTTP_PROXY */
+
+#ifdef GENERAL_PROXY_SUPPORT
+
+#ifdef WIN32
+
+#if 0
+char *
+get_windows_internet_string (const DWORD dwOption, struct gc_arena *gc)
+{
+ DWORD size = 0;
+ char *ret = NULL;
+
+ /* Initially, get size of return buffer */
+ InternetQueryOption (NULL, dwOption, NULL, &size);
+ if (size)
+ {
+ /* Now get actual info */
+ ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc);
+ if (!InternetQueryOption (NULL, dwOption, (LPVOID) ret, &size))
+ ret = NULL;
+ }
+ return ret;
+}
+#endif
+
+static INTERNET_PROXY_INFO *
+get_windows_proxy_settings (struct gc_arena *gc)
+{
+ DWORD size = 0;
+ INTERNET_PROXY_INFO *ret = NULL;
+
+ /* Initially, get size of return buffer */
+ InternetQueryOption (NULL, INTERNET_OPTION_PROXY, NULL, &size);
+ if (size)
+ {
+ /* Now get actual info */
+ ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc);
+ if (!InternetQueryOption (NULL, INTERNET_OPTION_PROXY, (LPVOID) ret, &size))
+ ret = NULL;
+ }
+ return ret;
+}
+
+static const char *
+parse_windows_proxy_setting (const char *str, struct auto_proxy_info_entry *e, struct gc_arena *gc)
+{
+ char buf[128];
+ const char *ret = NULL;
+ struct buffer in;
+
+ CLEAR (*e);
+
+ buf_set_read (&in, (const uint8_t *)str, strlen (str));
+
+ if (strchr (str, '=') != NULL)
+ {
+ if (buf_parse (&in, '=', buf, sizeof (buf)))
+ ret = string_alloc (buf, gc);
+ }
+
+ if (buf_parse (&in, ':', buf, sizeof (buf)))
+ e->server = string_alloc (buf, gc);
+
+ if (e->server && buf_parse (&in, '\0', buf, sizeof (buf)))
+ e->port = atoi (buf);
+
+ return ret;
+}
+
+static void
+parse_windows_proxy_setting_list (const char *str, const char *type, struct auto_proxy_info_entry *e, struct gc_arena *gc)
+{
+ struct gc_arena gc_local = gc_new ();
+ struct auto_proxy_info_entry el;
+
+ CLEAR (*e);
+ if (type)
+ {
+ char buf[128];
+ struct buffer in;
+
+ buf_set_read (&in, (const uint8_t *)str, strlen (str));
+ if (strchr (str, '=') != NULL)
+ {
+ while (buf_parse (&in, ' ', buf, sizeof (buf)))
+ {
+ const char *t = parse_windows_proxy_setting (buf, &el, &gc_local);
+ if (t && !strcmp (t, type))
+ goto found;
+ }
+ }
+ }
+ else
+ {
+ if (!parse_windows_proxy_setting (str, &el, &gc_local))
+ goto found;
+ }
+ goto done;
+
+ found:
+ if (el.server && el.port > 0)
+ {
+ e->server = string_alloc (el.server, gc);
+ e->port = el.port;
+ }
+
+ done:
+ gc_free (&gc_local);
+}
+
+static const char *
+win_proxy_access_type (const DWORD dwAccessType)
+{
+ switch (dwAccessType)
+ {
+ case INTERNET_OPEN_TYPE_DIRECT:
+ return "INTERNET_OPEN_TYPE_DIRECT";
+ case INTERNET_OPEN_TYPE_PROXY:
+ return "INTERNET_OPEN_TYPE_PROXY";
+ default:
+ return "[UNKNOWN]";
+ }
+}
+
+void
+show_win_proxy_settings (const int msglevel)
+{
+ INTERNET_PROXY_INFO *info;
+ struct gc_arena gc = gc_new ();
+
+ info = get_windows_proxy_settings (&gc);
+ msg (msglevel, "PROXY INFO: %s %s",
+ win_proxy_access_type (info->dwAccessType),
+ info->lpszProxy ? info->lpszProxy : "[NULL]");
+
+ gc_free (&gc);
+}
+
+struct auto_proxy_info *
+get_proxy_settings (char **err, struct gc_arena *gc)
+{
+ struct gc_arena gc_local = gc_new ();
+ INTERNET_PROXY_INFO *info;
+ struct auto_proxy_info *pi;
+
+ ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc);
+
+ if (err)
+ *err = NULL;
+
+ info = get_windows_proxy_settings (&gc_local);
+
+ if (!info)
+ {
+ if (err)
+ *err = "PROXY: failed to obtain windows proxy info";
+ goto done;
+ }
+
+ switch (info->dwAccessType)
+ {
+ case INTERNET_OPEN_TYPE_DIRECT:
+ break;
+ case INTERNET_OPEN_TYPE_PROXY:
+ if (!info->lpszProxy)
+ break;
+ parse_windows_proxy_setting_list (info->lpszProxy, NULL, &pi->http, gc);
+ if (!pi->http.server)
+ parse_windows_proxy_setting_list (info->lpszProxy, "http", &pi->http, gc);
+ parse_windows_proxy_setting_list (info->lpszProxy, "socks", &pi->socks, gc);
+ break;
+ default:
+ if (err)
+ *err = "PROXY: unknown proxy type";
+ break;
+ }
+
+ done:
+ gc_free (&gc_local);
+ return pi;
+}
+
+#else
+
+struct auto_proxy_info *
+get_proxy_settings (char **err, struct gc_arena *gc)
+{
+#if 1
+ if (err)
+ *err = string_alloc ("PROXY: automatic detection not supported on this OS", gc);
+ return NULL;
+#else /* JYFIXME, test --auto-proxy feature */
+ struct auto_proxy_info *pi;
+ ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc);
+ pi->http.server = "10.10.0.2";
+ pi->http.port = 4000;
+ return pi;
+#endif
+}
+
+#endif
+
+#endif /* GENERAL_PROXY_SUPPORT */
diff --git a/proxy.h b/proxy.h
index 5e7178c..235f5f0 100644
--- a/proxy.h
+++ b/proxy.h
@@ -25,11 +25,35 @@
#ifndef PROXY_H
#define PROXY_H
-#ifdef ENABLE_HTTP_PROXY
-
#include "buffer.h"
#include "misc.h"
+#ifdef GENERAL_PROXY_SUPPORT
+
+/*
+ * Return value for get_proxy_settings to automatically
+ * determine proxy information.
+ */
+struct auto_proxy_info_entry {
+ char *server;
+ int port;
+};
+
+struct auto_proxy_info {
+ struct auto_proxy_info_entry http;
+ struct auto_proxy_info_entry socks;
+};
+
+struct auto_proxy_info *get_proxy_settings (char **err, struct gc_arena *gc);
+
+#ifdef WIN32
+void show_win_proxy_settings (const int msglevel);
+#endif /* WIN32 */
+
+#endif /* GENERAL_PROXY_SUPPORT */
+
+#ifdef ENABLE_HTTP_PROXY
+
/* HTTP CONNECT authentication methods */
#define HTTP_AUTH_NONE 0
#define HTTP_AUTH_BASIC 1
@@ -41,6 +65,7 @@ struct http_proxy_options {
int port;
bool retry;
int timeout;
+ bool auth_retry;
const char *auth_method_string;
const char *auth_file;
const char *http_version;
@@ -55,9 +80,10 @@ struct http_proxy_info {
};
struct http_proxy_info *new_http_proxy (const struct http_proxy_options *o,
+ struct auto_proxy_info *auto_proxy_info,
struct gc_arena *gc);
-void establish_http_proxy_passthru (struct http_proxy_info *p,
+bool establish_http_proxy_passthru (struct http_proxy_info *p,
socket_descriptor_t sd, /* already open to proxy */
const char *host, /* openvpn server remote */
const int port, /* openvpn server port */
@@ -67,7 +93,6 @@ void establish_http_proxy_passthru (struct http_proxy_info *p,
uint8_t *make_base64_string2 (const uint8_t *str, int str_len, struct gc_arena *gc);
uint8_t *make_base64_string (const uint8_t *str, struct gc_arena *gc);
-bool get_http_proxy_settings (struct http_proxy_options *p, char **err, struct gc_arena *gc);
+#endif /* ENABLE_HTTP_PROXY */
-#endif
-#endif
+#endif /* PROXY_H */
diff --git a/socket.c b/socket.c
index 54a24b2..6bc8530 100644
--- a/socket.c
+++ b/socket.c
@@ -1307,44 +1307,57 @@ link_socket_init_phase2 (struct link_socket *sock,
}
else if (sock->info.proto == PROTO_TCPv4_CLIENT)
{
- socket_connect (&sock->sd,
- &sock->info.lsa->local,
- sock->bind_local,
- &sock->info.lsa->actual.dest,
- sock->remote_list,
- remote_dynamic,
- &remote_changed,
- sock->connect_retry_seconds,
- sock->connect_timeout,
- sock->connect_retry_max,
- signal_received);
-
- if (*signal_received)
- goto done;
- if (false)
- ;
+#ifdef GENERAL_PROXY_SUPPORT
+ bool proxy_retry = false;
+#else
+ const bool proxy_retry = false;
+#endif
+ do {
+ socket_connect (&sock->sd,
+ &sock->info.lsa->local,
+ sock->bind_local,
+ &sock->info.lsa->actual.dest,
+ sock->remote_list,
+ remote_dynamic,
+ &remote_changed,
+ sock->connect_retry_seconds,
+ sock->connect_timeout,
+ sock->connect_retry_max,
+ signal_received);
+
+ if (*signal_received)
+ goto done;
+
+ if (false)
+ ;
#ifdef ENABLE_HTTP_PROXY
- else if (sock->http_proxy)
- {
- establish_http_proxy_passthru (sock->http_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- &sock->stream_buf.residual,
- signal_received);
- }
+ else if (sock->http_proxy)
+ {
+ proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ &sock->stream_buf.residual,
+ signal_received);
+ }
#endif
#ifdef ENABLE_SOCKS
- else if (sock->socks_proxy)
- {
- establish_socks_proxy_passthru (sock->socks_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- signal_received);
- }
+ else if (sock->socks_proxy)
+ {
+ establish_socks_proxy_passthru (sock->socks_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ signal_received);
+ }
#endif
+ if (proxy_retry)
+ {
+ openvpn_close_socket (sock->sd);
+ sock->sd = create_socket_tcp ();
+ }
+ } while (proxy_retry);
}
#ifdef ENABLE_SOCKS
else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy)
@@ -1386,7 +1399,7 @@ link_socket_init_phase2 (struct link_socket *sock,
goto done;
}
#endif
-
+
if (*signal_received)
goto done;
diff --git a/socks.c b/socks.c
index 66cf209..cc9d82f 100644
--- a/socks.c
+++ b/socks.c
@@ -60,10 +60,25 @@ struct socks_proxy_info *
new_socks_proxy (const char *server,
int port,
bool retry,
+ struct auto_proxy_info *auto_proxy_info,
struct gc_arena *gc)
{
struct socks_proxy_info *p;
+
+ if (auto_proxy_info)
+ {
+ if (!server)
+ {
+ if (!auto_proxy_info->socks.server)
+ return NULL;
+
+ server = auto_proxy_info->socks.server;
+ port = auto_proxy_info->socks.port;
+ }
+ }
+
ALLOC_OBJ_CLEAR_GC (p, struct socks_proxy_info, gc);
+
ASSERT (server);
ASSERT (legal_ipv4_port (port));
diff --git a/socks.h b/socks.h
index 3d3f067..506aeb3 100644
--- a/socks.h
+++ b/socks.h
@@ -50,6 +50,7 @@ void socks_adjust_frame_parameters (struct frame *frame, int proto);
struct socks_proxy_info *new_socks_proxy (const char *server,
int port,
bool retry,
+ struct auto_proxy_info *auto_proxy_info,
struct gc_arena *gc);
void establish_socks_proxy_passthru (struct socks_proxy_info *p,
diff --git a/syshead.h b/syshead.h
index 6426241..bc6ad1b 100644
--- a/syshead.h
+++ b/syshead.h
@@ -266,6 +266,7 @@
#ifdef WIN32
#include <iphlpapi.h>
+#include <WinInet.h>
#endif
#ifdef HAVE_SYS_MMAN_H
@@ -436,6 +437,13 @@ socket_defined (const socket_descriptor_t sd)
#endif
/*
+ * Should we include code common to all proxy methods?
+ */
+#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)
+#define GENERAL_PROXY_SUPPORT
+#endif
+
+/*
* Do we have PKCS11 capability?
*/
#if defined(USE_PKCS11) && defined(USE_CRYPTO) && defined(USE_SSL)