Browse code

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

james authored on 2005/12/13 04:46:10
Showing 17 changed files
... ...
@@ -3,7 +3,7 @@ Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
3 3
 
4 4
 $Id$
5 5
 
6
-2005.11.xx -- Version 2.1-beta8
6
+2005.12.xx -- Version 2.1-beta8
7 7
 
8 8
 * --remap-usr1 will now also remap signals thrown during
9 9
   initialization.
... ...
@@ -17,6 +17,8 @@ $Id$
17 17
 * Fixed typo in manage.c where inline function declaration
18 18
   was declared without the "static" keyword (David Stipp).
19 19
 * Patch to support --topology subnet on Mac OS X (Mathias Sundman).
20
+* Added --auto-proxy directive to auto-detect HTTP or SOCKS
21
+  proxy settings (currently Windows only).
20 22
 
21 23
 2005.11.12 -- Version 2.1-beta7
22 24
 
... ...
@@ -29,7 +31,8 @@ $Id$
29 29
   but actually would only accept /29 or less.
30 30
 * Extend byte counters to 64 bits (M. van Cuijk).
31 31
 * PKCS#11 fixes (Alon Bar-Lev).
32
-
32
+* Removed redundant base64 code.
33
+	
33 34
 2005.11.02 -- Version 2.0.5
34 35
 
35 36
 * Fixed bug in Linux get_default_gateway function
... ...
@@ -127,8 +127,7 @@ EXTRA_DIST = \
127 127
 	plugin \
128 128
         management \
129 129
         pkcs11-headers \
130
-	cryptoki-win32.h \
131
-	ieproxy.c ieproxy.h
130
+	cryptoki-win32.h
132 131
 
133 132
 dist-hook:
134 133
 	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
... ...
@@ -39,7 +39,7 @@
39 39
 
40 40
 #include "syshead.h"
41 41
 
42
-#if NTLM
42
+#ifdef ENABLE_HTTP_PROXY
43 43
 
44 44
 #include "base64.h"
45 45
 
... ...
@@ -48,16 +48,6 @@
48 48
 static char base64_chars[] = 
49 49
     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
50 50
 
51
-static int 
52
-pos(char c)
53
-{
54
-    char *p;
55
-    for (p = base64_chars; *p; p++)
56
-	if (*p == c)
57
-	    return p - base64_chars;
58
-    return -1;
59
-}
60
-
61 51
 int 
62 52
 base64_encode(const void *data, int size, char **str)
63 53
 {
... ...
@@ -96,6 +86,18 @@ base64_encode(const void *data, int size, char **str)
96 96
     return strlen(s);
97 97
 }
98 98
 
99
+#if NTLM
100
+
101
+static int 
102
+pos(char c)
103
+{
104
+    char *p;
105
+    for (p = base64_chars; *p; p++)
106
+	if (*p == c)
107
+	    return p - base64_chars;
108
+    return -1;
109
+}
110
+
99 111
 #define DECODE_ERROR 0xffffffff
100 112
 
101 113
 static unsigned int
... ...
@@ -141,6 +143,8 @@ base64_decode(const char *str, void *data)
141 141
     return q - (unsigned char *) data;
142 142
 }
143 143
 
144
+#endif /* NTLM */
145
+
144 146
 #else
145 147
 static void dummy(void) {}
146 148
 #endif
... ...
@@ -31,12 +31,10 @@
31 31
  * SUCH DAMAGE.
32 32
  */
33 33
 
34
-/* $KTH: base64.h,v 1.2 1999/12/02 16:58:45 joda Exp $ */
35
-
36 34
 #ifndef _BASE64_H_
37 35
 #define _BASE64_H_
38 36
 
39
-#if NTLM
37
+#ifdef ENABLE_HTTP_PROXY
40 38
 
41 39
 int base64_encode(const void *data, int size, char **str);
42 40
 int base64_decode(const char *str, void *data);
... ...
@@ -621,6 +621,18 @@ buf_parse (struct buffer *buf, const int delim, char *line, const int size)
621 621
 }
622 622
 
623 623
 /*
624
+ * Print a string which might be NULL
625
+ */
626
+const char *
627
+np (const char *str)
628
+{
629
+  if (str)
630
+    return str;
631
+  else
632
+    return "[NULL]";
633
+}
634
+
635
+/*
624 636
  * Classify and mutate strings based on character types.
625 637
  */
626 638
 
... ...
@@ -553,8 +553,9 @@ xor (uint8_t *dest, const uint8_t *src, int len)
553 553
 }
554 554
 
555 555
 /*
556
- * Classify and mutate strings based on character types.
556
+ * Print a string which might be NULL
557 557
  */
558
+const char *np (const char *str);
558 559
 
559 560
 /*#define CHARACTER_CLASS_DEBUG*/
560 561
 
... ...
@@ -102,6 +102,12 @@ init_remote_list (struct context *c)
102 102
 void
103 103
 context_init_1 (struct context *c)
104 104
 {
105
+#ifdef ENABLE_HTTP_PROXY
106
+  bool did_http = false;
107
+#else
108
+  const bool did_http = false;
109
+#endif
110
+
105 111
   context_clear_1 (c);
106 112
 
107 113
   packet_id_persist_init (&c->c1.pid_persist);
... ...
@@ -145,20 +151,24 @@ context_init_1 (struct context *c)
145 145
 #endif
146 146
 
147 147
 #ifdef ENABLE_HTTP_PROXY
148
-  if (c->options.http_proxy_options)
148
+  if (c->options.http_proxy_options || c->options.auto_proxy_info)
149 149
     {
150 150
       /* Possible HTTP proxy user/pass input */
151 151
       c->c1.http_proxy = new_http_proxy (c->options.http_proxy_options,
152
+					 c->options.auto_proxy_info,
152 153
 					 &c->gc);
154
+      if (c->c1.http_proxy)
155
+	did_http = true;
153 156
     }
154 157
 #endif
155 158
 
156 159
 #ifdef ENABLE_SOCKS
157
-  if (c->options.socks_proxy_server)
160
+  if (!did_http && (c->options.socks_proxy_server || c->options.auto_proxy_info))
158 161
     {
159 162
       c->c1.socks_proxy = new_socks_proxy (c->options.socks_proxy_server,
160 163
 					   c->options.socks_proxy_port,
161 164
 					   c->options.socks_proxy_retry,
165
+					   c->options.auto_proxy_info,
162 166
 					   &c->gc);
163 167
     }
164 168
 #endif
... ...
@@ -78,7 +78,6 @@ HEADERS = \
78 78
 	fragment.h \
79 79
         gremlin.h \
80 80
 	helper.h \
81
-	ieproxy.h \
82 81
 	init.h \
83 82
 	integer.h \
84 83
 	interval.h \
... ...
@@ -137,7 +136,6 @@ OBJS =  base64.o \
137 137
         fragment.o \
138 138
 	gremlin.o \
139 139
 	helper.o \
140
-	ieproxy.o \
141 140
 	init.o \
142 141
 	interval.o \
143 142
         list.o \
... ...
@@ -101,6 +101,7 @@ openvpn \- secure IP tunnel daemon.
101 101
 [\ \fB\-\-auth\-user\-pass\-verify\fR\ \fIscript\fR\ ]
102 102
 [\ \fB\-\-auth\-user\-pass\fR\ \fIup\fR\ ]
103 103
 [\ \fB\-\-auth\fR\ \fIalg\fR\ ]
104
+[\ \fB\-\-auto\-proxy\fR\ ]
104 105
 [\ \fB\-\-bcast\-buffers\fR\ \fIn\fR\ ]
105 106
 [\ \fB\-\-ca\fR\ \fIfile\fR\ ]
106 107
 [\ \fB\-\-ccd\-exclusive\fR\ ]
... ...
@@ -597,7 +598,19 @@ as the
597 597
 number of retries of connection attempt (default=infinite).
598 598
 .\"*********************************************************
599 599
 .TP
600
-.B --http-proxy server port [authfile] [auth-method]
600
+.B --auto-proxy
601
+Try to sense HTTP or SOCKS proxy settings automatically.
602
+If no settings are present, a direct connection will be attempted.
603
+If both HTTP and SOCKS settings are present, HTTP will be preferred.
604
+If the HTTP proxy server requires a password, it will be queried from
605
+stdin or the management interface.  If the underlying OS doesn't support an API for
606
+returning proxy settings, a direct connection will be attempted.
607
+Currently, only Windows clients support this option via the
608
+InternetQueryOption API.
609
+This option exists in OpenVPN 2.1 or higher.
610
+.\"*********************************************************
611
+.TP
612
+.B --http-proxy server port [authfile|'auto'] [auth-method]
601 613
 Connect to remote host through an HTTP proxy at address
602 614
 .B server
603 615
 and port
... ...
@@ -608,7 +621,15 @@ is a file containing a username and password on 2 lines, or
608 608
 "stdin" to prompt from console.
609 609
 
610 610
 .B auth-method
611
-should be one of "none", "basic", or "ntlm". 
611
+should be one of "none", "basic", or "ntlm".
612
+
613
+The
614
+.B auto
615
+flag causes OpenVPN to automatically determine the
616
+.B auth-method
617
+and query stdin or the management interface for
618
+username/password credentials, if required.  This flag
619
+exists on OpenVPN 2.1 or higher.
612 620
 .\"*********************************************************
613 621
 .TP
614 622
 .B --http-proxy-retry
... ...
@@ -857,6 +878,8 @@ of the TAP-Win32 driver.  When used on *nix, requires that the tun
857 857
 driver supports an
858 858
 .BR ifconfig (8)
859 859
 command which sets a subnet instead of a remote endpoint IP address.
860
+
861
+This option exists in OpenVPN 2.1 or higher.
860 862
 .\"*********************************************************
861 863
 .TP
862 864
 .B --tun-ipv6
... ...
@@ -1175,8 +1198,7 @@ bypasses the tunnel
1175 1175
 (Available on Windows clients, may not be available
1176 1176
 on non-Windows clients).
1177 1177
 
1178
-Using the def1 flag is highly recommended, and is currently
1179
-planned to become the default by OpenVPN 2.1.
1178
+Using the def1 flag is highly recommended.
1180 1179
 .\"*********************************************************
1181 1180
 .TP
1182 1181
 .B --link-mtu n
... ...
@@ -97,12 +97,18 @@ static const char usage_message[] =
97 97
   "                    between connection retries (default=%d).\n"
98 98
   "--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
99 99
   "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n"
100
+#ifdef GENERAL_PROXY_SUPPORT
101
+  "--auto-proxy    : Try to sense proxy settings (or lack thereof) automatically.\n"
102
+#endif
100 103
 #ifdef ENABLE_HTTP_PROXY
101
-  "--http-proxy s p [up] [auth] : Connect to remote host through an HTTP proxy at\n"
102
-  "                  address s and port p.  If proxy authentication is required,\n"
104
+  "--http-proxy s p [up] [auth] : Connect to remote host\n"
105
+  "                  through an HTTP proxy at address s and port p.\n"
106
+  "                  If proxy authentication is required,\n"
103 107
   "                  up is a file containing username/password on 2 lines, or\n"
104 108
   "                  'stdin' to prompt from console.  Add auth='ntlm' if\n"
105 109
   "                  the proxy requires NTLM authentication.\n"
110
+  "--http-proxy s p 'auto': Like the above directive, but automatically determine\n"
111
+  "                         auth method and query for username/password if needed.\n"
106 112
   "--http-proxy-retry     : Retry indefinitely on HTTP proxy errors.\n"
107 113
   "--http-proxy-timeout n : Proxy timeout in seconds, default=5.\n"
108 114
   "--http-proxy-option type [parm] : Set extended HTTP proxy options.\n"
... ...
@@ -1537,8 +1543,8 @@ options_postprocess (struct options *options, bool first_time)
1537 1537
     msg (M_USAGE, "--remote MUST be used in TCP Client mode");
1538 1538
 
1539 1539
 #ifdef ENABLE_HTTP_PROXY
1540
-  if (options->http_proxy_options && options->proto != PROTO_TCPv4_CLIENT)
1541
-    msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
1540
+  if ((options->http_proxy_options || options->auto_proxy_info) && options->proto != PROTO_TCPv4_CLIENT)
1541
+    msg (M_USAGE, "--http-proxy or --auto-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
1542 1542
 #endif
1543 1543
 
1544 1544
 #if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_SOCKS)
... ...
@@ -3675,67 +3681,78 @@ add_option (struct options *options,
3675 3675
 	}
3676 3676
       options->proto = proto;
3677 3677
     }
3678
-#ifdef ENABLE_HTTP_PROXY
3679
-  else if (streq (p[0], "http-proxy") && p[1])
3678
+#ifdef GENERAL_PROXY_SUPPORT
3679
+  else if (streq (p[0], "auto-proxy"))
3680 3680
     {
3681
-      struct http_proxy_options *ho;
3681
+      char *error = NULL;
3682 3682
 
3683 3683
       VERIFY_PERMISSION (OPT_P_GENERAL);
3684
+      options->auto_proxy_info = get_proxy_settings (&error, &options->gc);
3685
+      if (error)
3686
+	msg (M_WARN, "PROXY: %s", error);
3687
+    }
3688
+  else if (streq (p[0], "show-proxy-settings"))
3689
+    {
3690
+      struct auto_proxy_info *pi;
3691
+      char *error = NULL;
3684 3692
 
3685
-      if (streq (p[1], "auto"))
3693
+      VERIFY_PERMISSION (OPT_P_GENERAL);
3694
+      pi = get_proxy_settings (&error, &options->gc);
3695
+      if (pi)
3686 3696
 	{
3687
-	  struct http_proxy_options hpo;
3688
-	  bool status;
3689
-	  char *error = NULL;
3690
-
3691
-	  p[4] = p[3];
3692
-	  p[3] = p[2];
3693
-	  p[1] = p[2] = NULL;
3694
-	  CLEAR (hpo);
3695
-	  
3696
-	  status = get_http_proxy_settings (&hpo, &error, &options->gc);
3697
-	  if (status)
3698
-	    {
3699
-	      ho = init_http_options_if_undefined (options);
3700
-	      ho->server = hpo.server;
3701
-	      ho->port = hpo.port;
3702
-	    }
3703
-	  else
3704
-	    {
3705
-	      if (error)
3706
-		msg (M_WARN, "http-proxy auto error: %s", error);
3707
-	      goto err;
3708
-	    }
3697
+	  msg (M_INFO|M_NOPREFIX, "HTTP Server: %s", np(pi->http.server));
3698
+	  msg (M_INFO|M_NOPREFIX, "HTTP Port: %d", pi->http.port);
3699
+	  msg (M_INFO|M_NOPREFIX, "SOCKS Server: %s", np(pi->socks.server));
3700
+	  msg (M_INFO|M_NOPREFIX, "SOCKS Port: %d", pi->socks.port);
3709 3701
 	}
3710
-      else
3711
-	{
3712
-	  int port;
3713
-	  if (!p[2])
3714
-	    {
3715
-	      msg (msglevel, "http-proxy port number not defined");
3716
-	      goto err;
3717
-	    }
3718
-	  port = atoi (p[2]);
3719
-	  if (!legal_ipv4_port (port))
3720
-	    {
3721
-	      msg (msglevel, "Bad http-proxy port number: %s", p[2]);
3722
-	      goto err;
3723
-	    }
3702
+      if (error)
3703
+	msg (msglevel, "Proxy error: %s", error);
3704
+#ifdef WIN32
3705
+      show_win_proxy_settings (M_INFO|M_NOPREFIX);
3706
+#endif
3707
+      openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
3708
+    }
3709
+#endif /* GENERAL_PROXY_SUPPORT */
3710
+#ifdef ENABLE_HTTP_PROXY
3711
+  else if (streq (p[0], "http-proxy") && p[1])
3712
+    {
3713
+      struct http_proxy_options *ho;
3724 3714
 
3725
-	  ho = init_http_options_if_undefined (options);
3715
+      VERIFY_PERMISSION (OPT_P_GENERAL);
3726 3716
 
3727
-	  ho->server = p[1];
3728
-	  ho->port = port;
3729
-	}
3717
+      {
3718
+	int port;
3719
+	if (!p[2])
3720
+	  {
3721
+	    msg (msglevel, "http-proxy port number not defined");
3722
+	    goto err;
3723
+	  }
3724
+	port = atoi (p[2]);
3725
+	if (!legal_ipv4_port (port))
3726
+	  {
3727
+	    msg (msglevel, "Bad http-proxy port number: %s", p[2]);
3728
+	    goto err;
3729
+	  }
3730
+	
3731
+	ho = init_http_options_if_undefined (options);
3732
+	
3733
+	ho->server = p[1];
3734
+	ho->port = port;
3735
+      }
3730 3736
 
3731 3737
       if (p[3])
3732 3738
 	{
3733
-	  ho->auth_method_string = "basic";
3734
-	  ho->auth_file = p[3];
3735
-
3736
-	  if (p[4])
3739
+	  if (streq (p[3], "auto"))
3740
+	    ho->auth_retry = true;
3741
+	  else
3737 3742
 	    {
3738
-	      ho->auth_method_string = p[4];
3743
+	      ho->auth_method_string = "basic";
3744
+	      ho->auth_file = p[3];
3745
+
3746
+	      if (p[4])
3747
+		{
3748
+		  ho->auth_method_string = p[4];
3749
+		}
3739 3750
 	    }
3740 3751
 	}
3741 3752
       else
... ...
@@ -3778,29 +3795,6 @@ add_option (struct options *options,
3778 3778
 	  msg (msglevel, "Bad http-proxy-option or missing parameter: '%s'", p[1]);
3779 3779
 	}
3780 3780
     }
3781
-  else if (streq (p[0], "show-http-proxy-settings"))
3782
-    {
3783
-      struct http_proxy_options po;
3784
-      bool status;
3785
-      char *error = NULL;
3786
-
3787
-      VERIFY_PERMISSION (OPT_P_GENERAL);
3788
-      CLEAR (po);
3789
-      status = get_http_proxy_settings (&po, &error, &options->gc);
3790
-      if (status)
3791
-	{
3792
-	  msg (M_INFO|M_NOPREFIX, "Server: %s", po.server);
3793
-	  msg (M_INFO|M_NOPREFIX, "Port: %d", po.port);
3794
-	}
3795
-      else
3796
-	{
3797
-	  if (error)
3798
-	    msg (msglevel, "Proxy error: %s", error);
3799
-	  else
3800
-	    msg (msglevel, "Proxy settings are undefined");
3801
-	}
3802
-      openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
3803
-    }  
3804 3781
 #endif
3805 3782
 #ifdef ENABLE_SOCKS
3806 3783
   else if (streq (p[0], "socks-proxy") && p[1])
... ...
@@ -250,6 +250,10 @@ struct options
250 250
   struct route_option_list *routes;
251 251
   bool route_nopull;
252 252
 
253
+#ifdef GENERAL_PROXY_SUPPORT
254
+  struct auto_proxy_info *auto_proxy_info;
255
+#endif
256
+
253 257
 #ifdef ENABLE_HTTP_PROXY
254 258
   struct http_proxy_options *http_proxy_options;
255 259
 #endif
... ...
@@ -28,8 +28,6 @@
28 28
 #include "config.h"
29 29
 #endif
30 30
 
31
-#ifdef ENABLE_HTTP_PROXY
32
-
33 31
 #include "syshead.h"
34 32
 
35 33
 #include "common.h"
... ...
@@ -38,6 +36,7 @@
38 38
 #include "socket.h"
39 39
 #include "fdmisc.h"
40 40
 #include "proxy.h"
41
+#include "base64.h"
41 42
 #include "ntlm.h"
42 43
 
43 44
 #ifdef WIN32
... ...
@@ -46,55 +45,7 @@
46 46
 
47 47
 #include "memdbg.h"
48 48
 
49
-#ifdef WIN32
50
-
51
-bool
52
-get_http_proxy_settings (struct http_proxy_options *p, char **err, struct gc_arena *gc)
53
-{
54
-  bool ret = false;
55
-  const char *result;
56
-
57
-  p->server = NULL;
58
-  p->port = 0;
59
-  getIeHttpProxyError = NULL;
60
-  if (err)
61
-    *err = NULL;
62
-
63
-  result = getIeHttpProxy ();
64
-  if (result)
65
-    {
66
-      char addr_str[128];
67
-      char port_str[16];
68
-      struct buffer in;
69
-      buf_set_read (&in, (const uint8_t *)result, strlen (result));
70
-      if (buf_parse (&in, ':', addr_str, sizeof (addr_str))
71
-	  && buf_parse (&in, ':', port_str, sizeof (port_str)))
72
-	{
73
-	  p->server = string_alloc (addr_str, gc);
74
-	  p->port = atoi (port_str);
75
-	  ret = true;
76
-	}
77
-      free ((void *)result);
78
-    }
79
-  else if (getIeHttpProxyError)
80
-    {
81
-      if (err)
82
-	*err = string_alloc (getIeHttpProxyError, gc);
83
-    }
84
-  return ret;
85
-}
86
-
87
-#else
88
-
89
-bool
90
-get_http_proxy_settings (struct http_proxy_options *p, char **err, struct gc_arena *gc)
91
-{
92
-  if (err)
93
-    *err = string_alloc ("HTTP proxy detection not supported on this OS", gc);
94
-  return false;
95
-}
96
-
97
-#endif
49
+#ifdef ENABLE_HTTP_PROXY
98 50
 
99 51
 /* cached proxy username/password */
100 52
 static struct user_pass static_proxy_user_pass;
... ...
@@ -246,42 +197,12 @@ send_crlf (socket_descriptor_t sd)
246 246
 uint8_t *
247 247
 make_base64_string2 (const uint8_t *str, int src_len, struct gc_arena *gc)
248 248
 {
249
-  static const char base64_table[] =
250
-    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
251
-
252
-  uint8_t *buf;
253
-  const uint8_t *src;
254
-  uint8_t *dst;
255
-  int bits, data, dst_len;
256
-
257
-  /* make base64 string */
258
-  dst_len = (src_len + 2) / 3 * 4;
259
-  buf = gc_malloc (dst_len + 1, false, gc);
260
-  bits = data = 0;
261
-  src = str;
262
-  dst = buf;
263
-  while (dst_len--)
264
-    {
265
-      if (bits < 6)
266
-	{
267
-	  data = (data << 8) | *src;
268
-	  bits += 8;
269
-	  src++;
270
-	}
271
-      *dst++ = base64_table[0x3F & (data >> (bits - 6))];
272
-      bits -= 6;
273
-    }
274
-  *dst = '\0';
275
-
276
-  /* fix-up tail padding */
277
-  switch (src_len % 3)
278
-    {
279
-    case 1:
280
-      *--dst = '=';
281
-    case 2:
282
-      *--dst = '=';
283
-    }
284
-  return buf;
249
+  uint8_t *ret = NULL;
250
+  char *b64out = NULL;
251
+  ASSERT (base64_encode ((const void *)str, src_len, &b64out) >= 0);
252
+  ret = (uint8_t *) string_alloc (b64out, gc);
253
+  free (b64out);
254
+  return ret;
285 255
 }
286 256
 
287 257
 uint8_t *
... ...
@@ -300,18 +221,67 @@ username_password_as_base64 (const struct http_proxy_info *p,
300 300
   return (const char *)make_base64_string ((const uint8_t*)BSTR (&out), gc);
301 301
 }
302 302
 
303
+static void
304
+get_user_pass_http (struct http_proxy_info *p, const bool force)
305
+{
306
+  if (!static_proxy_user_pass.defined || force)
307
+    {
308
+      get_user_pass (&static_proxy_user_pass,
309
+		     p->options.auth_file,
310
+		     "HTTP Proxy",
311
+		     GET_USER_PASS_MANAGEMENT);
312
+      p->up = static_proxy_user_pass;
313
+    }
314
+}
315
+
303 316
 struct http_proxy_info *
304 317
 new_http_proxy (const struct http_proxy_options *o,
318
+		struct auto_proxy_info *auto_proxy_info,
305 319
 		struct gc_arena *gc)
306 320
 {
307 321
   struct http_proxy_info *p;
308
-  ALLOC_OBJ_CLEAR_GC (p, struct http_proxy_info, gc);
322
+  struct http_proxy_options opt;
323
+
324
+  if (auto_proxy_info)
325
+    {
326
+      if (o && o->server)
327
+	{
328
+	  /* if --http-proxy explicitly given, disable auto-proxy */
329
+	  auto_proxy_info = NULL;
330
+	}
331
+      else
332
+	{
333
+	  /* if no --http-proxy explicitly given and no auto settings, fail */
334
+	  if (!auto_proxy_info->http.server)
335
+	    return NULL;
309 336
 
310
-  if (!o->server)
337
+	  if (o)
338
+	    {
339
+	      opt = *o;
340
+	    }
341
+	  else
342
+	    {
343
+	      CLEAR (opt);
344
+	  
345
+	      /* These settings are only used for --auto-proxy */
346
+	      opt.timeout = 5;
347
+	      opt.http_version = "1.0";
348
+	    }
349
+
350
+	  opt.server = auto_proxy_info->http.server;
351
+	  opt.port = auto_proxy_info->http.port;
352
+	  opt.auth_retry = true;
353
+
354
+	  o = &opt;
355
+	}
356
+    }
357
+
358
+  if (!o || !o->server)
311 359
     msg (M_FATAL, "HTTP_PROXY: server not specified");
312 360
 
313 361
   ASSERT (legal_ipv4_port (o->port));
314 362
 
363
+  ALLOC_OBJ_CLEAR_GC (p, struct http_proxy_info, gc);
315 364
   p->options = *o;
316 365
 
317 366
   /* parse authentication method */
... ...
@@ -332,11 +302,7 @@ new_http_proxy (const struct http_proxy_options *o,
332 332
   /* only basic and NTLM authentication supported so far */
333 333
   if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM)
334 334
     {
335
-      get_user_pass (&static_proxy_user_pass,
336
-		     o->auth_file,
337
-		     "HTTP Proxy",
338
-		     GET_USER_PASS_MANAGEMENT);
339
-      p->up = static_proxy_user_pass;
335
+      get_user_pass_http (p, true);
340 336
     }
341 337
 
342 338
 #if !NTLM
... ...
@@ -348,7 +314,7 @@ new_http_proxy (const struct http_proxy_options *o,
348 348
   return p;
349 349
 }
350 350
 
351
-void
351
+bool
352 352
 establish_http_proxy_passthru (struct http_proxy_info *p,
353 353
 			       socket_descriptor_t sd, /* already open to proxy */
354 354
 			       const char *host,       /* openvpn server remote */
... ...
@@ -362,6 +328,12 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
362 362
   char get[80];
363 363
   int status;
364 364
   int nparms;
365
+  bool ret = false;
366
+
367
+  /* get user/pass if not previously given or if --auto-proxy is being used */
368
+  if (p->auth_method == HTTP_AUTH_BASIC
369
+      || p->auth_method == HTTP_AUTH_NTLM)
370
+    get_user_pass_http (p, false);
365 371
 
366 372
   /* format HTTP CONNECT message */
367 373
   openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
... ...
@@ -519,7 +491,21 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
519 519
 	  ASSERT (0); /* No NTLM support */
520 520
 #endif
521 521
 	}
522
-      else goto error;
522
+      else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry)
523
+	{
524
+	  /*
525
+	   * Proxy needs authentication, but we don't have a user/pass.
526
+	   * Now we will change p->auth_method and return true so that
527
+	   * our caller knows to call us again on a newly opened socket.
528
+	   * JYFIXME: This code needs to check proxy error output and set
529
+	   * JYFIXME: p->auth_method = HTTP_AUTH_NTLM if necessary.
530
+	   */
531
+	  p->auth_method = HTTP_AUTH_BASIC;
532
+	  ret = true;
533
+	  goto done;
534
+	}
535
+      else
536
+	goto error;
523 537
     }
524 538
 
525 539
 
... ...
@@ -527,7 +513,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
527 527
   if (nparms < 1 || status != 200)
528 528
     {
529 529
       msg (D_LINK_ERRORS, "HTTP proxy returned bad status");
530
-#if 0 
530
+#if 0
531 531
       /* DEBUGGING -- show a multi-line HTTP error response */
532 532
       while (true)
533 533
 	{
... ...
@@ -556,17 +542,221 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
556 556
     msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0));
557 557
 #endif
558 558
 
559
+ done:
559 560
   gc_free (&gc);
560
-  return;
561
+  return ret;
561 562
 
562 563
  error:
563 564
   /* on error, should we exit or restart? */
564 565
   if (!*signal_received)
565 566
     *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */
566 567
   gc_free (&gc);
567
-  return;
568
+  return ret;
568 569
 }
569 570
 
570 571
 #else
571 572
 static void dummy(void) {}
572 573
 #endif /* ENABLE_HTTP_PROXY */
574
+
575
+#ifdef GENERAL_PROXY_SUPPORT
576
+
577
+#ifdef WIN32
578
+
579
+#if 0
580
+char *
581
+get_windows_internet_string (const DWORD dwOption, struct gc_arena *gc)
582
+{
583
+  DWORD size = 0;
584
+  char *ret = NULL;
585
+
586
+  /* Initially, get size of return buffer */
587
+  InternetQueryOption (NULL, dwOption, NULL, &size);
588
+  if (size)
589
+    {
590
+      /* Now get actual info */
591
+      ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc);
592
+      if (!InternetQueryOption (NULL, dwOption, (LPVOID) ret, &size))
593
+	ret = NULL;
594
+    }
595
+  return ret;
596
+}
597
+#endif
598
+
599
+static INTERNET_PROXY_INFO *
600
+get_windows_proxy_settings (struct gc_arena *gc)
601
+{
602
+  DWORD size = 0;
603
+  INTERNET_PROXY_INFO *ret = NULL;
604
+
605
+  /* Initially, get size of return buffer */
606
+  InternetQueryOption (NULL, INTERNET_OPTION_PROXY, NULL, &size);
607
+  if (size)
608
+    {
609
+      /* Now get actual info */
610
+      ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc);
611
+      if (!InternetQueryOption (NULL, INTERNET_OPTION_PROXY, (LPVOID) ret, &size))
612
+	ret = NULL;
613
+    }
614
+  return ret;
615
+}
616
+
617
+static const char *
618
+parse_windows_proxy_setting (const char *str, struct auto_proxy_info_entry *e, struct gc_arena *gc)
619
+{
620
+  char buf[128];
621
+  const char *ret = NULL;
622
+  struct buffer in;
623
+
624
+  CLEAR (*e);
625
+
626
+  buf_set_read (&in, (const uint8_t *)str, strlen (str));
627
+
628
+  if (strchr (str, '=') != NULL)
629
+    {
630
+      if (buf_parse (&in, '=', buf, sizeof (buf)))
631
+	ret = string_alloc (buf, gc);
632
+    }
633
+	
634
+  if (buf_parse (&in, ':', buf, sizeof (buf)))
635
+    e->server = string_alloc (buf, gc);
636
+
637
+  if (e->server && buf_parse (&in, '\0', buf, sizeof (buf)))
638
+    e->port = atoi (buf);
639
+
640
+  return ret;
641
+}
642
+
643
+static void
644
+parse_windows_proxy_setting_list (const char *str, const char *type, struct auto_proxy_info_entry *e, struct gc_arena *gc)
645
+{
646
+  struct gc_arena gc_local = gc_new ();
647
+  struct auto_proxy_info_entry el;
648
+
649
+  CLEAR (*e);
650
+  if (type)
651
+    {
652
+      char buf[128];
653
+      struct buffer in;
654
+
655
+      buf_set_read (&in, (const uint8_t *)str, strlen (str));
656
+      if (strchr (str, '=') != NULL)
657
+	{
658
+	  while (buf_parse (&in, ' ', buf, sizeof (buf)))
659
+	    {
660
+	      const char *t = parse_windows_proxy_setting (buf, &el, &gc_local);
661
+	      if (t && !strcmp (t, type))
662
+		goto found;
663
+	    }
664
+	}
665
+    }
666
+  else
667
+    {
668
+      if (!parse_windows_proxy_setting (str, &el, &gc_local))
669
+	goto found;
670
+    }
671
+  goto done;
672
+
673
+ found:
674
+  if (el.server && el.port > 0)
675
+    {
676
+      e->server = string_alloc (el.server, gc);
677
+      e->port = el.port;
678
+    }
679
+
680
+ done:
681
+  gc_free (&gc_local);
682
+}
683
+
684
+static const char *
685
+win_proxy_access_type (const DWORD dwAccessType)
686
+{
687
+  switch (dwAccessType)
688
+    {
689
+    case INTERNET_OPEN_TYPE_DIRECT:
690
+      return "INTERNET_OPEN_TYPE_DIRECT";
691
+    case INTERNET_OPEN_TYPE_PROXY:
692
+      return "INTERNET_OPEN_TYPE_PROXY";
693
+    default:
694
+      return "[UNKNOWN]";
695
+    }
696
+}
697
+
698
+void
699
+show_win_proxy_settings (const int msglevel)
700
+{
701
+  INTERNET_PROXY_INFO *info;
702
+  struct gc_arena gc = gc_new ();
703
+
704
+  info = get_windows_proxy_settings (&gc);
705
+  msg (msglevel, "PROXY INFO: %s %s",
706
+       win_proxy_access_type (info->dwAccessType),
707
+       info->lpszProxy ? info->lpszProxy : "[NULL]");
708
+
709
+  gc_free (&gc);
710
+}
711
+
712
+struct auto_proxy_info *
713
+get_proxy_settings (char **err, struct gc_arena *gc)
714
+{
715
+  struct gc_arena gc_local = gc_new ();
716
+  INTERNET_PROXY_INFO *info;
717
+  struct auto_proxy_info *pi;
718
+
719
+  ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc);
720
+
721
+  if (err)
722
+    *err = NULL;
723
+
724
+  info = get_windows_proxy_settings (&gc_local);
725
+
726
+  if (!info)
727
+    {
728
+      if (err)
729
+	*err = "PROXY: failed to obtain windows proxy info";
730
+      goto done;
731
+    }
732
+
733
+  switch (info->dwAccessType)
734
+    {
735
+    case INTERNET_OPEN_TYPE_DIRECT:
736
+      break;
737
+    case INTERNET_OPEN_TYPE_PROXY:
738
+      if (!info->lpszProxy)
739
+	break;
740
+      parse_windows_proxy_setting_list (info->lpszProxy, NULL, &pi->http, gc);
741
+      if (!pi->http.server)
742
+	parse_windows_proxy_setting_list (info->lpszProxy, "http", &pi->http, gc);
743
+      parse_windows_proxy_setting_list (info->lpszProxy, "socks", &pi->socks, gc);
744
+      break;
745
+    default:
746
+      if (err)
747
+	*err = "PROXY: unknown proxy type";
748
+      break;
749
+    }
750
+
751
+ done:
752
+  gc_free (&gc_local);
753
+  return pi;
754
+}
755
+
756
+#else
757
+
758
+struct auto_proxy_info *
759
+get_proxy_settings (char **err, struct gc_arena *gc)
760
+{
761
+#if 1
762
+  if (err)
763
+    *err = string_alloc ("PROXY: automatic detection not supported on this OS", gc);
764
+  return NULL;
765
+#else /* JYFIXME, test --auto-proxy feature */
766
+  struct auto_proxy_info *pi;
767
+  ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc);
768
+  pi->http.server = "10.10.0.2";
769
+  pi->http.port = 4000;
770
+  return pi;
771
+#endif
772
+}
773
+
774
+#endif
775
+
776
+#endif /* GENERAL_PROXY_SUPPORT */
... ...
@@ -25,11 +25,35 @@
25 25
 #ifndef PROXY_H
26 26
 #define PROXY_H
27 27
 
28
-#ifdef ENABLE_HTTP_PROXY
29
-
30 28
 #include "buffer.h"
31 29
 #include "misc.h"
32 30
 
31
+#ifdef GENERAL_PROXY_SUPPORT
32
+
33
+/*
34
+ * Return value for get_proxy_settings to automatically
35
+ * determine proxy information.
36
+ */
37
+struct auto_proxy_info_entry {
38
+  char *server;
39
+  int port;
40
+};
41
+
42
+struct auto_proxy_info {
43
+  struct auto_proxy_info_entry http;
44
+  struct auto_proxy_info_entry socks;
45
+};
46
+
47
+struct auto_proxy_info *get_proxy_settings (char **err, struct gc_arena *gc);
48
+
49
+#ifdef WIN32
50
+void show_win_proxy_settings (const int msglevel);
51
+#endif /* WIN32 */
52
+
53
+#endif /* GENERAL_PROXY_SUPPORT */
54
+
55
+#ifdef ENABLE_HTTP_PROXY
56
+
33 57
 /* HTTP CONNECT authentication methods */
34 58
 #define HTTP_AUTH_NONE  0
35 59
 #define HTTP_AUTH_BASIC 1
... ...
@@ -41,6 +65,7 @@ struct http_proxy_options {
41 41
   int port;
42 42
   bool retry;
43 43
   int timeout;
44
+  bool auth_retry;
44 45
   const char *auth_method_string;
45 46
   const char *auth_file;
46 47
   const char *http_version;
... ...
@@ -55,9 +80,10 @@ struct http_proxy_info {
55 55
 };
56 56
 
57 57
 struct http_proxy_info *new_http_proxy (const struct http_proxy_options *o,
58
+					struct auto_proxy_info *auto_proxy_info,
58 59
 					struct gc_arena *gc);
59 60
 
60
-void establish_http_proxy_passthru (struct http_proxy_info *p,
61
+bool establish_http_proxy_passthru (struct http_proxy_info *p,
61 62
 				    socket_descriptor_t sd, /* already open to proxy */
62 63
 				    const char *host,       /* openvpn server remote */
63 64
 				    const int port,         /* openvpn server port */
... ...
@@ -67,7 +93,6 @@ void establish_http_proxy_passthru (struct http_proxy_info *p,
67 67
 uint8_t *make_base64_string2 (const uint8_t *str, int str_len, struct gc_arena *gc);
68 68
 uint8_t *make_base64_string (const uint8_t *str, struct gc_arena *gc);
69 69
 
70
-bool get_http_proxy_settings (struct http_proxy_options *p, char **err, struct gc_arena *gc);
70
+#endif /* ENABLE_HTTP_PROXY */
71 71
 
72
-#endif
73
-#endif
72
+#endif /* PROXY_H */
... ...
@@ -1307,44 +1307,57 @@ link_socket_init_phase2 (struct link_socket *sock,
1307 1307
 	}
1308 1308
       else if (sock->info.proto == PROTO_TCPv4_CLIENT)
1309 1309
 	{
1310
-	  socket_connect (&sock->sd,
1311
-                          &sock->info.lsa->local,
1312
-                          sock->bind_local,
1313
-			  &sock->info.lsa->actual.dest,
1314
-			  sock->remote_list,
1315
-			  remote_dynamic,
1316
-			  &remote_changed,
1317
-			  sock->connect_retry_seconds,
1318
-			  sock->connect_timeout,
1319
-			  sock->connect_retry_max,
1320
-			  signal_received);
1321
-
1322
-	  if (*signal_received)
1323
-	    goto done;
1324 1310
 
1325
-	  if (false)
1326
-	    ;
1311
+#ifdef GENERAL_PROXY_SUPPORT
1312
+	  bool proxy_retry = false;
1313
+#else
1314
+	  const bool proxy_retry = false;
1315
+#endif
1316
+	  do {
1317
+	    socket_connect (&sock->sd,
1318
+			    &sock->info.lsa->local,
1319
+			    sock->bind_local,
1320
+			    &sock->info.lsa->actual.dest,
1321
+			    sock->remote_list,
1322
+			    remote_dynamic,
1323
+			    &remote_changed,
1324
+			    sock->connect_retry_seconds,
1325
+			    sock->connect_timeout,
1326
+			    sock->connect_retry_max,
1327
+			    signal_received);
1328
+
1329
+	    if (*signal_received)
1330
+	      goto done;
1331
+
1332
+	    if (false)
1333
+	      ;
1327 1334
 #ifdef ENABLE_HTTP_PROXY
1328
-	  else if (sock->http_proxy)
1329
-	    {
1330
-	      establish_http_proxy_passthru (sock->http_proxy,
1331
-					     sock->sd,
1332
-					     sock->proxy_dest_host,
1333
-					     sock->proxy_dest_port,
1334
-					     &sock->stream_buf.residual,
1335
-					     signal_received);
1336
-	    }
1335
+	    else if (sock->http_proxy)
1336
+	      {
1337
+		proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
1338
+							     sock->sd,
1339
+							     sock->proxy_dest_host,
1340
+							     sock->proxy_dest_port,
1341
+							     &sock->stream_buf.residual,
1342
+							     signal_received);
1343
+	      }
1337 1344
 #endif
1338 1345
 #ifdef ENABLE_SOCKS
1339
-	  else if (sock->socks_proxy)
1340
-	    {
1341
-	      establish_socks_proxy_passthru (sock->socks_proxy,
1342
-					      sock->sd,
1343
-					      sock->proxy_dest_host,
1344
-					      sock->proxy_dest_port,
1345
-					      signal_received);
1346
-	    }
1346
+	    else if (sock->socks_proxy)
1347
+	      {
1348
+		establish_socks_proxy_passthru (sock->socks_proxy,
1349
+						sock->sd,
1350
+						sock->proxy_dest_host,
1351
+						sock->proxy_dest_port,
1352
+						signal_received);
1353
+	      }
1347 1354
 #endif
1355
+	    if (proxy_retry)
1356
+	      {
1357
+		openvpn_close_socket (sock->sd);
1358
+		sock->sd = create_socket_tcp ();
1359
+	      }
1360
+	  } while (proxy_retry);
1348 1361
 	}
1349 1362
 #ifdef ENABLE_SOCKS
1350 1363
       else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy)
... ...
@@ -1386,7 +1399,7 @@ link_socket_init_phase2 (struct link_socket *sock,
1386 1386
 	    goto done;
1387 1387
 	}
1388 1388
 #endif
1389
-      
1389
+
1390 1390
       if (*signal_received)
1391 1391
 	goto done;
1392 1392
 
... ...
@@ -60,10 +60,25 @@ struct socks_proxy_info *
60 60
 new_socks_proxy (const char *server,
61 61
 		 int port,
62 62
 		 bool retry,
63
+		 struct auto_proxy_info *auto_proxy_info,
63 64
 		 struct gc_arena *gc)
64 65
 {
65 66
   struct socks_proxy_info *p;
67
+
68
+  if (auto_proxy_info)
69
+    {
70
+      if (!server)
71
+	{
72
+	  if (!auto_proxy_info->socks.server)
73
+	    return NULL;
74
+
75
+	  server = auto_proxy_info->socks.server;
76
+	  port = auto_proxy_info->socks.port;
77
+	}
78
+    }
79
+
66 80
   ALLOC_OBJ_CLEAR_GC (p, struct socks_proxy_info, gc);
81
+
67 82
   ASSERT (server);
68 83
   ASSERT (legal_ipv4_port (port));
69 84
 
... ...
@@ -50,6 +50,7 @@ void socks_adjust_frame_parameters (struct frame *frame, int proto);
50 50
 struct socks_proxy_info *new_socks_proxy (const char *server,
51 51
 					  int port,
52 52
 					  bool retry,
53
+					  struct auto_proxy_info *auto_proxy_info,
53 54
 					  struct gc_arena *gc);
54 55
 
55 56
 void establish_socks_proxy_passthru (struct socks_proxy_info *p,
... ...
@@ -266,6 +266,7 @@
266 266
 
267 267
 #ifdef WIN32
268 268
 #include <iphlpapi.h>
269
+#include <WinInet.h>
269 270
 #endif
270 271
 
271 272
 #ifdef HAVE_SYS_MMAN_H
... ...
@@ -436,6 +437,13 @@ socket_defined (const socket_descriptor_t sd)
436 436
 #endif
437 437
 
438 438
 /*
439
+ * Should we include code common to all proxy methods?
440
+ */
441
+#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)
442
+#define GENERAL_PROXY_SUPPORT
443
+#endif
444
+
445
+/*
439 446
  * Do we have PKCS11 capability?
440 447
  */
441 448
 #if defined(USE_PKCS11) && defined(USE_CRYPTO) && defined(USE_SSL)