aboutsummaryrefslogtreecommitdiff
path: root/proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'proxy.c')
-rw-r--r--proxy.c388
1 files changed, 289 insertions, 99 deletions
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 */