]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added --auto-proxy directive to auto-detect HTTP or SOCKS
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 12 Dec 2005 19:46:10 +0000 (19:46 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 12 Dec 2005 19:46:10 +0000 (19:46 +0000)
proxy settings (currently Windows only).

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@850 e7ae566f-a301-0410-adde-c780ea21d3b5

17 files changed:
ChangeLog
Makefile.am
base64.c
base64.h
buffer.c
buffer.h
init.c
makefile.w32
openvpn.8
options.c
options.h
proxy.c
proxy.h
socket.c
socks.c
socks.h
syshead.h

index 1fe18e7fd0f534f9c0998f9e4709f7dee1273d49..a186b6f03d6cc6e6c3a4ef3aebaa0d31e77b2b9f 100644 (file)
--- 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
index ebfa22d1fc0e9cad60888c6bce55871d55b0bceb..424b167d05ed9a65d447845c291eee93d9a149aa 100644 (file)
@@ -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
index dcdb0eeda259c5bbf8776e78fe0057cf2c8e9b73..a69633d40bb02d7de31667781d40c9e4d2271b3d 100644 (file)
--- a/base64.c
+++ b/base64.c
@@ -39,7 +39,7 @@
 
 #include "syshead.h"
 
-#if NTLM
+#ifdef ENABLE_HTTP_PROXY
 
 #include "base64.h"
 
 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
index 0cd43faad5672f3bc9f9eb33558f94b2a25608ce..a966b2d768596dfafbea1b653ea60bd5e40a1020 100644 (file)
--- a/base64.h
+++ b/base64.h
  * 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);
index 5ff612380c2c4a9735ae9ad97337126ca71d9f7a..e66c6a4de28c173ee63b5805f86ba659f424fd8e 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -620,6 +620,18 @@ buf_parse (struct buffer *buf, const int delim, char *line, const int size)
   return !(eol && !strlen (line));
 }
 
+/*
+ * 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.
  */
index 63a476329171191d96599373e7664fd94e4ac3a5..f95c5e166208f68acd79cda6caa5157b36061521 100644 (file)
--- 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 ea1acc3f73176519bbd9afd0751c88f25551321c..c90cb5da19a21ac360e6971832654ebb5e8d3310 100644 (file)
--- 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
index c612512a610815233ede50459d1c9bb15319bd01..22fbc282932d294ff05f0a784e7267bc4bc09319 100755 (executable)
@@ -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 \
index 8cd2b256300f379dc231da64fd2306a85b2edf40..3b14a3ed08adc6bbe683151f4de0f8f1181f99a4 100644 (file)
--- 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
index ebe61d02ce4c980019f15c0f5142169bd1c306c9..d02530ea60f1194d4e0d4d0a88925bf8ae460343 100644 (file)
--- 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])
index 21484b7b632ae85063640750c20b7a0ada83b862..644d7cb31a6661f009fb8e4a57a1b75c27e3aee0 100644 (file)
--- 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 0cfd51ca99f8b3e1e1f319409099dc2c0236fdb3..d2cc34b2a8f7b7a2b670f6b9cdc2fe8ce3a4867d 100644 (file)
--- 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
 
 #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 5e7178cb740ba4c6dc9cc9d4a166e170936dc483..235f5f01400b1af17fca40e03c8098e822027706 100644 (file)
--- a/proxy.h
+++ b/proxy.h
 #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 */
index 54a24b2a68359a151fad85d7dd82bbb61b750d38..6bc8530ec866069217870e5ccf069f25ac0dda68 100644 (file)
--- 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 66cf20995835c97e0d5acf103c6a6477cd9f5674..cc9d82f29e7586923fc33e3db457bd9359f4d0d1 100644 (file)
--- 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 3d3f06732711be1e8457cec038644bfafd1e9a0a..506aeb3498c313c74e61d8679721b104e297301c 100644 (file)
--- 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,
index 6426241e6676d9ea2dd64e44a1b3cbf3d74eb1f4..bc6ad1b22ca2dbc1bd874c90f26e41cf738ee1a0 100644 (file)
--- a/syshead.h
+++ b/syshead.h
 
 #ifdef WIN32
 #include <iphlpapi.h>
+#include <WinInet.h>
 #endif
 
 #ifdef HAVE_SYS_MMAN_H
@@ -435,6 +436,13 @@ socket_defined (const socket_descriptor_t sd)
 #define NTLM 0
 #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?
  */