Browse code

Implemented http-proxy-override and http-proxy-fallback directives to make it easier for OpenVPN client UIs to start a pre-existing client config file with proxy options, or to adaptively fall back to a proxy connection if a direct connection fails.

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

James Yonan authored on 2010/05/25 07:51:16
Showing 14 changed files
... ...
@@ -724,6 +724,12 @@ void gc_transfer (struct gc_arena *dest, struct gc_arena *src);
724 724
 
725 725
 void x_gc_free (struct gc_arena *a);
726 726
 
727
+static inline bool
728
+gc_defined (struct gc_arena *a)
729
+{
730
+  return a->list != NULL;
731
+}
732
+
727 733
 static inline void
728 734
 gc_init (struct gc_arena *a)
729 735
 {
... ...
@@ -687,14 +687,25 @@ read_incoming_link (struct context *c)
687 687
 	if (c->options.inetd)
688 688
 	  {
689 689
 	    c->sig->signal_received = SIGTERM;
690
+	    c->sig->signal_text = "connection-reset-inetd";
690 691
 	    msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status);
691 692
 	  }
692 693
 	else
693 694
 	  {
694
-	    c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- TCP connection reset */
695
-	    msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status);
695
+#ifdef ENABLE_OCC
696
+	    if (event_timeout_defined(&c->c2.explicit_exit_notification_interval))
697
+	      {
698
+		msg (D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status);
699
+		openvpn_sleep(1);
700
+	      }
701
+	    else
702
+#endif
703
+	      {
704
+		c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- TCP connection reset */
705
+		c->sig->signal_text = "connection-reset";
706
+		msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status);
707
+	      }
696 708
 	  }
697
-	c->sig->signal_text = "connection-reset";
698 709
       }
699 710
       perf_pop ();
700 711
       return;
... ...
@@ -111,6 +111,103 @@ update_options_ce_post (struct options *options)
111 111
 #endif
112 112
 }
113 113
 
114
+#if HTTP_PROXY_FALLBACK
115
+
116
+static bool
117
+ce_http_proxy_fallback_defined(const struct context *c)
118
+{
119
+  const struct connection_list *l = c->options.connection_list;
120
+  if (l && l->current == 0)
121
+    {
122
+      int i;
123
+      for (i = 0; i < l->len; ++i)
124
+	{
125
+	  if (l->array[i]->flags & CE_HTTP_PROXY_FALLBACK)
126
+	    return true;
127
+	}
128
+    }
129
+  return false;
130
+}
131
+
132
+static void
133
+ce_http_proxy_fallback_start(struct context *c, const char *remote_ip_hint)
134
+{
135
+  const struct connection_list *l = c->options.connection_list;
136
+  if (l)
137
+    {
138
+      int i;
139
+      for (i = 0; i < l->len; ++i)
140
+	{
141
+	  struct connection_entry *ce = l->array[i];
142
+	  if (ce->flags & CE_HTTP_PROXY_FALLBACK)
143
+	    {
144
+	      ce->http_proxy_options = NULL;
145
+	      ce->ce_http_proxy_fallback_timestamp = 0;
146
+	      if (!remote_ip_hint)
147
+		remote_ip_hint = ce->remote;
148
+	    }
149
+	}
150
+    }
151
+
152
+  if (management)
153
+    management_http_proxy_fallback_notify(management, "NEED_LATER", remote_ip_hint);
154
+}
155
+
156
+static bool
157
+ce_http_proxy_fallback (struct context *c, volatile const struct connection_entry *ce)
158
+{
159
+  const int proxy_info_expire = 120; /* seconds before proxy info expires */
160
+
161
+  update_time();
162
+  if (management)
163
+    {
164
+      if (!ce->ce_http_proxy_fallback_timestamp)
165
+	{
166
+	  management_http_proxy_fallback_notify(management, "NEED_NOW", NULL);
167
+	  while (!ce->ce_http_proxy_fallback_timestamp)
168
+	    {
169
+	      management_event_loop_n_seconds (management, 1);
170
+	      if (IS_SIG (c))
171
+		return false;
172
+	    }
173
+	}
174
+      return (now < ce->ce_http_proxy_fallback_timestamp + proxy_info_expire && ce->http_proxy_options);
175
+    }
176
+  return false;
177
+}
178
+
179
+static bool
180
+management_callback_http_proxy_fallback_cmd (void *arg, const char *server, const char *port, const char *flags)
181
+{
182
+  struct context *c = (struct context *) arg;
183
+  const struct connection_list *l = c->options.connection_list;
184
+  int ret = false;
185
+  struct http_proxy_options *ho = parse_http_proxy_fallback (c, server, port, flags, M_WARN);
186
+
187
+  update_time();
188
+  if (l)
189
+    {
190
+      int i;
191
+      for (i = 0; i < l->len; ++i)
192
+	{
193
+	  struct connection_entry *ce = l->array[i];
194
+	  if (ce->flags & CE_HTTP_PROXY_FALLBACK)
195
+	    {
196
+	      if (ho)
197
+		{
198
+		  ce->http_proxy_options = ho;
199
+		  ret = true;
200
+		}
201
+	      ce->ce_http_proxy_fallback_timestamp = now;
202
+	    }
203
+	}
204
+    }
205
+  
206
+  return ret;
207
+}
208
+
209
+#endif
210
+
114 211
 /*
115 212
  * Initialize and possibly randomize connection list.
116 213
  */
... ...
@@ -141,6 +238,30 @@ init_connection_list (struct context *c)
141 141
 #endif
142 142
 }
143 143
 
144
+#if 0 /* fixme -- disable for production */
145
+static void
146
+show_connection_list (const struct connection_list *l)
147
+{
148
+  int i;
149
+  dmsg (M_INFO, "CONNECTION_LIST len=%d current=%d",
150
+	l->len, l->current);
151
+  for (i = 0; i < l->len; ++i)
152
+    {
153
+      dmsg (M_INFO, "[%d] %s:%d proto=%s http_proxy=%d",
154
+	    i,
155
+	    l->array[i]->remote,
156
+	    l->array[i]->remote_port,
157
+	    proto2ascii(l->array[i]->proto, true),
158
+	    BOOL_CAST(l->array[i]->http_proxy_options));
159
+    }
160
+}
161
+#else
162
+static inline void
163
+show_connection_list (const struct connection_list *l)
164
+{
165
+}
166
+#endif
167
+
144 168
 /*
145 169
  * Increment to next connection entry
146 170
  */
... ...
@@ -151,27 +272,65 @@ next_connection_entry (struct context *c)
151 151
   struct connection_list *l = c->options.connection_list;
152 152
   if (l)
153 153
     {
154
-      if (l->no_advance && l->current >= 0)
155
-	{
156
-	  l->no_advance = false;
157
-	}
158
-      else
159
-	{
160
-	  int i;
161
-	  if (++l->current >= l->len)
162
-	    l->current = 0;
154
+      bool ce_defined;
155
+      struct connection_entry *ce;
156
+      int n_cycles = 0;
163 157
 
164
-	  dmsg (D_CONNECTION_LIST, "CONNECTION_LIST len=%d current=%d",
165
-		l->len, l->current);
166
-	  for (i = 0; i < l->len; ++i)
167
-	    {
168
-	      dmsg (D_CONNECTION_LIST, "[%d] %s:%d",
169
-		    i,
170
-		    l->array[i]->remote,
171
-		    l->array[i]->remote_port);
172
-	    }
173
-	}
174
-      c->options.ce = *l->array[l->current];
158
+      do {
159
+	const char *remote_ip_hint = NULL;
160
+	bool advanced = false;
161
+
162
+	ce_defined = true;
163
+	if (l->no_advance && l->current >= 0)
164
+	  {
165
+	    l->no_advance = false;
166
+	  }
167
+	else
168
+	  {
169
+	    if (++l->current >= l->len)
170
+	      {
171
+		l->current = 0;
172
+		++l->n_cycles;
173
+		if (++n_cycles >= 2)
174
+		  msg (M_FATAL, "No usable connection profiles are present");
175
+	      }
176
+
177
+	    advanced = true;
178
+	    show_connection_list(l);
179
+	  }
180
+
181
+	ce = l->array[l->current];
182
+
183
+	if (c->options.remote_ip_hint && !l->n_cycles)
184
+	  remote_ip_hint = c->options.remote_ip_hint;
185
+
186
+#if HTTP_PROXY_FALLBACK
187
+	if (advanced && ce_http_proxy_fallback_defined(c))
188
+	  ce_http_proxy_fallback_start(c, remote_ip_hint);
189
+
190
+	if (ce->flags & CE_HTTP_PROXY_FALLBACK)
191
+	  {
192
+	    ce_defined = ce_http_proxy_fallback(c, ce);
193
+	    if (IS_SIG (c))
194
+	      break;
195
+	  }
196
+#endif
197
+
198
+	if (ce->flags & CE_DISABLED)
199
+	  ce_defined = false;
200
+
201
+	c->options.ce = *ce;
202
+
203
+	if (remote_ip_hint)
204
+	  c->options.ce.remote = remote_ip_hint;
205
+
206
+#if 0 /* fixme -- disable for production, this code simulates a network where proxy fallback is the only method to reach the OpenVPN server */
207
+	if (!(c->options.ce.flags & CE_HTTP_PROXY_FALLBACK))
208
+	  {
209
+	    c->options.ce.remote = "10.10.0.1"; /* use an unreachable address here */
210
+	  }
211
+#endif
212
+      } while (!ce_defined);
175 213
     }
176 214
 #endif
177 215
   update_options_ce_post (&c->options);
... ...
@@ -2774,6 +2933,9 @@ init_management_callback_p2p (struct context *c)
2774 2774
       cb.arg = c;
2775 2775
       cb.status = management_callback_status_p2p;
2776 2776
       cb.show_net = management_show_net_callback;
2777
+#if HTTP_PROXY_FALLBACK
2778
+      cb.http_proxy_fallback_cmd = management_callback_http_proxy_fallback_cmd;
2779
+#endif
2777 2780
       management_set_callback (management, &cb);
2778 2781
     }
2779 2782
 #endif
... ...
@@ -2898,6 +3060,17 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
2898 2898
   c->sig->signal_text = NULL;
2899 2899
   c->sig->hard = false;
2900 2900
 
2901
+  if (c->mode == CM_P2P)
2902
+    init_management_callback_p2p (c);
2903
+
2904
+  /* possible sleep or management hold if restart */
2905
+  if (c->mode == CM_P2P || c->mode == CM_TOP)
2906
+    {
2907
+      do_startup_pause (c);
2908
+      if (IS_SIG (c))
2909
+	goto sig;
2910
+    }
2911
+
2901 2912
   /* map in current connection entry */
2902 2913
   next_connection_entry (c);
2903 2914
 
... ...
@@ -2916,14 +3089,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
2916 2916
   if (c->first_time && options->mlock)
2917 2917
     do_mlockall (true);
2918 2918
 
2919
-  /* possible sleep or management hold if restart */
2920
-  if (c->mode == CM_P2P || c->mode == CM_TOP)
2921
-    {
2922
-      do_startup_pause (c);
2923
-      if (IS_SIG (c))
2924
-	goto sig;
2925
-    }
2926
-
2927 2919
 #if P2MP
2928 2920
   /* get passwords if undefined */
2929 2921
   if (auth_retry_get () == AR_INTERACT)
... ...
@@ -110,6 +110,10 @@ man_help ()
110 110
   msg (M_CLIENT, "username type u        : Enter username u for a queried OpenVPN username.");
111 111
   msg (M_CLIENT, "verb [n]               : Set log verbosity level to n, or show if n is absent.");
112 112
   msg (M_CLIENT, "version                : Show current version number.");
113
+#if HTTP_PROXY_FALLBACK
114
+  msg (M_CLIENT, "http-proxy-fallback <server> <port> [flags] : Enter dynamic HTTP proxy fallback info.");
115
+  msg (M_CLIENT, "http-proxy-fallback-disable : Disable HTTP proxy fallback.");
116
+#endif
113 117
   msg (M_CLIENT, "END");
114 118
 }
115 119
 
... ...
@@ -204,12 +208,10 @@ man_update_io_state (struct management *man)
204 204
 }
205 205
 
206 206
 static void
207
-man_output_list_push (struct management *man, const char *str)
207
+man_output_list_push_finalize (struct management *man)
208 208
 {
209 209
   if (management_connected (man))
210 210
     {
211
-      if (str)
212
-	buffer_list_push (man->connection.out, (const unsigned char *) str);
213 211
       man_update_io_state (man);
214 212
       if (!man->persist.standalone_disabled)
215 213
 	{
... ...
@@ -220,6 +222,22 @@ man_output_list_push (struct management *man, const char *str)
220 220
 }
221 221
 
222 222
 static void
223
+man_output_list_push_str (struct management *man, const char *str)
224
+{
225
+  if (management_connected (man) && str)
226
+    {
227
+      buffer_list_push (man->connection.out, (const unsigned char *) str);
228
+    }
229
+}
230
+
231
+static void
232
+man_output_list_push (struct management *man, const char *str)
233
+{
234
+  man_output_list_push_str (man, str);
235
+  man_output_list_push_finalize (man);
236
+}
237
+
238
+static void
223 239
 man_prompt (struct management *man)
224 240
 {
225 241
   if (man_password_needed (man))
... ...
@@ -256,12 +274,13 @@ man_close_socket (struct management *man, const socket_descriptor_t sd)
256 256
 static void
257 257
 virtual_output_callback_func (void *arg, const unsigned int flags, const char *str)
258 258
 {
259
+  struct management *man = (struct management *) arg;
259 260
   static int recursive_level = 0; /* GLOBAL */
261
+  bool did_push = false;
260 262
 
261 263
   if (!recursive_level) /* don't allow recursion */
262 264
     {
263 265
       struct gc_arena gc = gc_new ();
264
-      struct management *man = (struct management *) arg;
265 266
       struct log_entry e;
266 267
       const char *out = NULL;
267 268
 
... ...
@@ -289,13 +308,17 @@ virtual_output_callback_func (void *arg, const unsigned int flags, const char *s
289 289
 				   |   LOG_PRINT_LOG_PREFIX
290 290
 				   |   LOG_PRINT_CRLF, &gc);
291 291
 	  if (out)
292
-	    man_output_list_push (man, out);
292
+	    {
293
+	      man_output_list_push_str (man, out);
294
+	      did_push = true;
295
+	    }
293 296
 	  if (flags & M_FATAL)
294 297
 	    {
295 298
 	      out = log_entry_print (&e, LOG_FATAL_NOTIFY|LOG_PRINT_CRLF, &gc);
296 299
 	      if (out)
297 300
 		{
298
-		  man_output_list_push (man, out);
301
+		  man_output_list_push_str (man, out);
302
+		  did_push = true;
299 303
 		  man_reset_client_socket (man, true);
300 304
 		}
301 305
 	    }
... ...
@@ -304,6 +327,9 @@ virtual_output_callback_func (void *arg, const unsigned int flags, const char *s
304 304
       --recursive_level;
305 305
       gc_free (&gc);
306 306
     }
307
+
308
+  if (did_push)
309
+    man_output_list_push_finalize (man);
307 310
 }
308 311
 
309 312
 /*
... ...
@@ -998,6 +1024,31 @@ man_need (struct management *man, const char **p, const int n, unsigned int flag
998 998
   return true;
999 999
 }
1000 1000
 
1001
+#if HTTP_PROXY_FALLBACK
1002
+
1003
+static void
1004
+man_http_proxy_fallback (struct management *man, const char *server, const char *port, const char *flags)
1005
+{
1006
+  if (man->persist.callback.http_proxy_fallback_cmd)
1007
+    {
1008
+      const bool status = (*man->persist.callback.http_proxy_fallback_cmd)(man->persist.callback.arg, server, port, flags);
1009
+      if (status)
1010
+	{
1011
+	  msg (M_CLIENT, "SUCCESS: proxy-fallback command succeeded");
1012
+	}
1013
+      else
1014
+	{
1015
+	  msg (M_CLIENT, "ERROR: proxy-fallback command failed");
1016
+	}
1017
+    }
1018
+  else
1019
+    {
1020
+      msg (M_CLIENT, "ERROR: The proxy-fallback command is not supported by the current daemon mode");
1021
+    }
1022
+}
1023
+
1024
+#endif
1025
+
1001 1026
 static void
1002 1027
 man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms)
1003 1028
 {
... ...
@@ -1210,6 +1261,17 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
1210 1210
 	man_pkcs11_id_get (man, atoi(p[1]));
1211 1211
     }
1212 1212
 #endif
1213
+#if HTTP_PROXY_FALLBACK
1214
+  else if (streq (p[0], "http-proxy-fallback"))
1215
+    {
1216
+      if (man_need (man, p, 2, MN_AT_LEAST))
1217
+	man_http_proxy_fallback (man, p[1], p[2], p[3]);
1218
+    }
1219
+  else if (streq (p[0], "http-proxy-fallback-disable"))
1220
+    {
1221
+      man_http_proxy_fallback (man, NULL, NULL, NULL);
1222
+    }
1223
+#endif
1213 1224
 #if 1
1214 1225
   else if (streq (p[0], "test"))
1215 1226
     {
... ...
@@ -2103,7 +2165,7 @@ management_clear_callback (struct management *man)
2103 2103
   man->persist.standalone_disabled = false;
2104 2104
   man->persist.hold_release = false;
2105 2105
   CLEAR (man->persist.callback);
2106
-  man_output_list_push (man, NULL); /* flush output queue */
2106
+  man_output_list_push_finalize (man); /* flush output queue */
2107 2107
 }
2108 2108
 
2109 2109
 void
... ...
@@ -2402,7 +2464,7 @@ management_io (struct management *man)
2402 2402
 		  net_event_win32_clear_selected_events (&man->connection.ne32, FD_ACCEPT);
2403 2403
 		}
2404 2404
 	    }
2405
-	  else if (man->connection.state == MS_CC_WAIT_READ)
2405
+	  else if (man->connection.state == MS_CC_WAIT_READ || man->connection.state == MS_CC_WAIT_WRITE)
2406 2406
 	    {
2407 2407
 	      if (net_events & FD_READ)
2408 2408
 		{
... ...
@@ -2410,18 +2472,13 @@ management_io (struct management *man)
2410 2410
 		    ;
2411 2411
 		  net_event_win32_clear_selected_events (&man->connection.ne32, FD_READ);
2412 2412
 		}
2413
-	    }
2414 2413
 
2415
-	  if (man->connection.state == MS_CC_WAIT_WRITE)
2416
-	    {
2417 2414
 	      if (net_events & FD_WRITE)
2418 2415
 		{
2419 2416
 		  int status;
2420
-		  /* dmsg (M_INFO, "FD_WRITE set"); */
2421 2417
 		  status = man_write (man);
2422 2418
 		  if (status < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
2423 2419
 		    {
2424
-		      /* dmsg (M_INFO, "FD_WRITE cleared"); */
2425 2420
 		      net_event_win32_clear_selected_events (&man->connection.ne32, FD_WRITE);
2426 2421
 		    }
2427 2422
 		}
... ...
@@ -2512,7 +2569,7 @@ man_block (struct management *man, volatile int *signal_received, const time_t e
2512 2512
   
2513 2513
   if (man_standalone_ok (man))
2514 2514
     {
2515
-      do
2515
+      while (true)
2516 2516
 	{
2517 2517
 	  event_reset (man->connection.es);
2518 2518
 	  management_socket_set (man, man->connection.es, NULL, NULL);
... ...
@@ -2530,15 +2587,18 @@ man_block (struct management *man, volatile int *signal_received, const time_t e
2530 2530
 	      status = -1;
2531 2531
 	      break;
2532 2532
 	    }
2533
-	  /* set SIGINT signal if expiration time exceeded */
2534
-	  if (expire && now >= expire)
2533
+
2534
+	  if (status > 0)
2535
+	    break;
2536
+	  else if (expire && now >= expire)
2535 2537
 	    {
2538
+	      /* set SIGINT signal if expiration time exceeded */
2536 2539
 	      status = 0;
2537 2540
 	      if (signal_received)
2538 2541
 		*signal_received = SIGINT;
2539 2542
 	      break;
2540 2543
 	    }
2541
-	} while (status != 1);
2544
+	}
2542 2545
     }
2543 2546
   return status;
2544 2547
 }
... ...
@@ -2615,28 +2675,29 @@ management_event_loop_n_seconds (struct management *man, int sec)
2615 2615
     {
2616 2616
       volatile int signal_received = 0;
2617 2617
       const bool standalone_disabled_save = man->persist.standalone_disabled;
2618
-      time_t expire;
2618
+      time_t expire = 0;
2619 2619
 
2620 2620
       man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */
2621 2621
 
2622 2622
       /* set expire time */
2623 2623
       update_time ();
2624
-      expire = now + sec;
2624
+      if (sec)
2625
+	expire = now + sec;
2625 2626
 
2626 2627
       /* if no client connection, wait for one */
2627 2628
       man_wait_for_client_connection (man, &signal_received, expire, 0);
2628 2629
       if (signal_received)
2629 2630
 	return;
2630 2631
 
2631
-      /* run command processing event loop until we get our username/password */
2632
-      while (true)
2632
+      /* run command processing event loop */
2633
+      do
2633 2634
 	{
2634 2635
 	  man_standalone_event_loop (man, &signal_received, expire);
2635 2636
 	  if (!signal_received)
2636 2637
 	    man_check_for_signals (&signal_received);
2637 2638
 	  if (signal_received)
2638 2639
 	    return;
2639
-	}
2640
+	} while (expire);
2640 2641
 
2641 2642
       /* revert state */
2642 2643
       man->persist.standalone_disabled = standalone_disabled_save;
... ...
@@ -3028,6 +3089,19 @@ log_history_ref (const struct log_history *h, const int index)
3028 3028
     return NULL;
3029 3029
 }
3030 3030
 
3031
+#if HTTP_PROXY_FALLBACK
3032
+
3033
+void
3034
+management_http_proxy_fallback_notify (struct management *man, const char *type, const char *remote_ip_hint)
3035
+{
3036
+  if (remote_ip_hint)
3037
+    msg (M_CLIENT, ">PROXY:%s,%s", type, remote_ip_hint);
3038
+  else
3039
+    msg (M_CLIENT, ">PROXY:%s", type);
3040
+}
3041
+
3042
+#endif /* HTTP_PROXY_FALLBACK */
3043
+
3031 3044
 #else
3032 3045
 static void dummy(void) {}
3033 3046
 #endif /* ENABLE_MANAGEMENT */
... ...
@@ -170,6 +170,9 @@ struct management_callback
170 170
 		     const unsigned long cid,
171 171
 		     struct buffer_list *pf_config);   /* ownership transferred */
172 172
 #endif
173
+#if HTTP_PROXY_FALLBACK
174
+  bool (*http_proxy_fallback_cmd) (void *arg, const char *server, const char *port, const char *flags);
175
+#endif
173 176
 };
174 177
 
175 178
 /*
... ...
@@ -502,5 +505,11 @@ management_bytes_server (struct management *man,
502 502
 
503 503
 #endif /* MANAGEMENT_DEF_AUTH */
504 504
 
505
+#if HTTP_PROXY_FALLBACK
506
+
507
+void management_http_proxy_fallback_notify (struct management *man, const char *type, const char *remote_ip_hint);
508
+
509
+#endif /* HTTP_PROXY_FALLBACK */
510
+
505 511
 #endif
506 512
 #endif
... ...
@@ -1374,6 +1374,9 @@ get_user_pass (struct user_pass *up,
1374 1374
     {
1375 1375
       const bool from_stdin = (!auth_file || !strcmp (auth_file, "stdin"));
1376 1376
 
1377
+      if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
1378
+	msg (M_WARN, "Note: previous '%s' credentials failed", prefix);
1379
+
1377 1380
 #ifdef ENABLE_MANAGEMENT
1378 1381
       /*
1379 1382
        * Get username/password from standard input?
... ...
@@ -1382,6 +1385,9 @@ get_user_pass (struct user_pass *up,
1382 1382
 	  && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT)))
1383 1383
 	  && management_query_user_pass_enabled (management))
1384 1384
 	{
1385
+	  if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
1386
+	    management_auth_failure (management, prefix, "previous auth credentials failed");
1387
+
1385 1388
 	  if (!management_query_user_pass (management, up, prefix, flags))
1386 1389
 	    {
1387 1390
 	      if ((flags & GET_USER_PASS_NOFATAL) != 0)
... ...
@@ -263,12 +263,17 @@ bool get_console_input (const char *prompt, const bool echo, char *input, const
263 263
 #define GET_USER_PASS_NEED_OK       (1<<3)
264 264
 #define GET_USER_PASS_NOFATAL       (1<<4)
265 265
 #define GET_USER_PASS_NEED_STR      (1<<5)
266
+#define GET_USER_PASS_PREVIOUS_CREDS_FAILED (1<<6)
266 267
 
267 268
 bool get_user_pass (struct user_pass *up,
268 269
 		    const char *auth_file,
269 270
 		    const char *prefix,
270 271
 		    const unsigned int flags);
271 272
 
273
+void fail_user_pass (const char *prefix,
274
+		     const unsigned int flags,
275
+		     const char *reason);
276
+
272 277
 void purge_user_pass (struct user_pass *up, const bool force);
273 278
 
274 279
 /*
... ...
@@ -55,8 +55,6 @@ tunnel_point_to_point (struct context *c)
55 55
   if (IS_SIG (c))
56 56
     return;
57 57
 
58
-  init_management_callback_p2p (c);
59
-
60 58
   /* main event loop */
61 59
   while (true)
62 60
     {
... ...
@@ -761,7 +761,9 @@ void
761 761
 uninit_options (struct options *o)
762 762
 {
763 763
   if (o->gc_owned)
764
-    gc_free (&o->gc);
764
+    {
765
+      gc_free (&o->gc);
766
+    }
765 767
 }
766 768
 
767 769
 #ifdef ENABLE_DEBUG
... ...
@@ -1412,6 +1414,137 @@ init_http_options_if_undefined (struct options *o)
1412 1412
 
1413 1413
 #endif
1414 1414
 
1415
+#if HTTP_PROXY_FALLBACK
1416
+
1417
+static struct http_proxy_options *
1418
+parse_http_proxy_override (const char *server,
1419
+			   const char *port,
1420
+			   const char *flags,
1421
+			   const int msglevel,
1422
+			   struct gc_arena *gc)
1423
+{
1424
+  if (server && port)
1425
+    {
1426
+      struct http_proxy_options *ho;
1427
+      const int int_port = atoi(port);
1428
+
1429
+      if (!legal_ipv4_port (int_port))
1430
+	{
1431
+	  msg (msglevel, "Bad http-proxy port number: %s", port);
1432
+	  return NULL;
1433
+	}
1434
+
1435
+      ALLOC_OBJ_CLEAR_GC (ho, struct http_proxy_options, gc);
1436
+      ho->server = string_alloc(server, gc);
1437
+      ho->port = int_port;
1438
+      ho->retry = true;
1439
+      ho->timeout = 5;
1440
+      if (flags && !strcmp(flags, "nct"))
1441
+	ho->auth_retry = PAR_NCT;
1442
+      else
1443
+	ho->auth_retry = PAR_ALL;
1444
+      ho->http_version = "1.0";
1445
+      ho->user_agent = "OpenVPN-Autoproxy/1.0";
1446
+      return ho;
1447
+    }
1448
+  else
1449
+    return NULL;
1450
+}
1451
+
1452
+struct http_proxy_options *
1453
+parse_http_proxy_fallback (struct context *c,
1454
+			   const char *server,
1455
+			   const char *port,
1456
+			   const char *flags,
1457
+			   const int msglevel)
1458
+{
1459
+  struct gc_arena gc = gc_new ();  
1460
+  struct http_proxy_options *hp = parse_http_proxy_override(server, port, flags, msglevel, &gc);
1461
+  struct hpo_store *hpos = c->options.hpo_store;
1462
+  if (!hpos)
1463
+    {
1464
+      ALLOC_OBJ_CLEAR_GC (hpos, struct hpo_store, &c->options.gc);
1465
+      c->options.hpo_store = hpos;
1466
+    }
1467
+  hpos->hpo = *hp;
1468
+  hpos->hpo.server = hpos->server;
1469
+  strncpynt(hpos->server, hp->server, sizeof(hpos->server));
1470
+  gc_free (&gc);
1471
+  return &hpos->hpo;
1472
+}
1473
+
1474
+static void
1475
+http_proxy_warn(const char *name)
1476
+{
1477
+  msg (M_WARN, "Note: option %s ignored because no TCP-based connection profiles are defined", name);
1478
+}
1479
+
1480
+void
1481
+options_postprocess_http_proxy_fallback (struct options *o)
1482
+{
1483
+  struct connection_list *l = o->connection_list;
1484
+  if (l)
1485
+    {
1486
+      int i;
1487
+      for (i = 0; i < l->len; ++i)
1488
+	{
1489
+	  struct connection_entry *ce = l->array[i];
1490
+	  if (ce->proto == PROTO_TCPv4_CLIENT || ce->proto == PROTO_TCPv4)
1491
+	    {
1492
+	      if (l->len < CONNECTION_LIST_SIZE)
1493
+		{
1494
+		  struct connection_entry *newce;
1495
+		  ALLOC_OBJ_GC (newce, struct connection_entry, &o->gc);
1496
+		  *newce = *ce;
1497
+		  newce->flags |= CE_HTTP_PROXY_FALLBACK;
1498
+		  newce->http_proxy_options = NULL;
1499
+		  newce->ce_http_proxy_fallback_timestamp = 0;
1500
+		  l->array[l->len++] = newce;
1501
+		}
1502
+	      return;
1503
+	    }
1504
+	}
1505
+    }
1506
+  http_proxy_warn("http-proxy-fallback");
1507
+}
1508
+
1509
+void
1510
+options_postprocess_http_proxy_override (struct options *o)
1511
+{
1512
+  const struct connection_list *l = o->connection_list;
1513
+   if (l)
1514
+    {
1515
+      int i;
1516
+      bool succeed = false;
1517
+      for (i = 0; i < l->len; ++i)
1518
+	{
1519
+	  struct connection_entry *ce = l->array[i];
1520
+	  if (ce->proto == PROTO_TCPv4_CLIENT || ce->proto == PROTO_TCPv4)
1521
+	    {
1522
+	      ce->http_proxy_options = o->http_proxy_override;
1523
+	      succeed = true;
1524
+	    }
1525
+	}
1526
+      if (succeed)
1527
+	{
1528
+	  for (i = 0; i < l->len; ++i)
1529
+	    {
1530
+	      struct connection_entry *ce = l->array[i];
1531
+	      if (ce->proto == PROTO_UDPv4)
1532
+		{
1533
+		  ce->flags |= CE_DISABLED;
1534
+		}
1535
+	    }
1536
+	}
1537
+      else
1538
+	{
1539
+	  http_proxy_warn("http-proxy-override");
1540
+	}
1541
+    }
1542
+}
1543
+
1544
+#endif
1545
+
1415 1546
 #if ENABLE_CONNECTION
1416 1547
 
1417 1548
 static struct connection_list *
... ...
@@ -2095,7 +2228,7 @@ options_postprocess_mutate (struct options *o)
2095 2095
        * For compatibility with 2.0.x, map multiple --remote options
2096 2096
        * into connection list (connection lists added in 2.1).
2097 2097
        */
2098
-      if (o->remote_list->len > 1)
2098
+      if (o->remote_list->len > 1 || o->force_connection_list)
2099 2099
 	{
2100 2100
 	  const struct remote_list *rl = o->remote_list;
2101 2101
 	  int i;
... ...
@@ -2112,7 +2245,7 @@ options_postprocess_mutate (struct options *o)
2112 2112
 	      *ace = ce;
2113 2113
 	    }
2114 2114
 	}
2115
-      else if (o->remote_list->len == 1) /* one --remote option specfied */
2115
+      else if (o->remote_list->len == 1) /* one --remote option specified */
2116 2116
 	{
2117 2117
 	  connection_entry_load_re (&o->ce, o->remote_list->array[0]);
2118 2118
 	}
... ...
@@ -2126,6 +2259,13 @@ options_postprocess_mutate (struct options *o)
2126 2126
       int i;
2127 2127
       for (i = 0; i < o->connection_list->len; ++i)
2128 2128
 	options_postprocess_mutate_ce (o, o->connection_list->array[i]);
2129
+
2130
+#if HTTP_PROXY_FALLBACK
2131
+      if (o->http_proxy_override)
2132
+	options_postprocess_http_proxy_override(o);
2133
+      else if (o->http_proxy_fallback)
2134
+	options_postprocess_http_proxy_fallback(o);
2135
+#endif
2129 2136
     }
2130 2137
   else
2131 2138
 #endif
... ...
@@ -3633,11 +3773,29 @@ add_option (struct options *options,
3633 3633
 	}
3634 3634
     }
3635 3635
 #endif
3636
+#ifdef ENABLE_CONNECTION
3636 3637
   else if (streq (p[0], "remote-ip-hint") && p[1])
3637 3638
     {
3638
-      VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
3639
-      // fixme
3639
+      VERIFY_PERMISSION (OPT_P_GENERAL);
3640
+      options->remote_ip_hint = p[1];
3640 3641
     }
3642
+#endif
3643
+#if HTTP_PROXY_FALLBACK
3644
+  else if (streq (p[0], "http-proxy-fallback"))
3645
+    {
3646
+      VERIFY_PERMISSION (OPT_P_GENERAL);
3647
+      options->http_proxy_fallback = true;
3648
+      options->force_connection_list = true;
3649
+    }
3650
+  else if (streq (p[0], "http-proxy-override") && p[1] && p[2])
3651
+    {
3652
+      VERIFY_PERMISSION (OPT_P_GENERAL);
3653
+      options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc);
3654
+      if (!options->http_proxy_override)
3655
+	goto err;
3656
+      options->force_connection_list = true;
3657
+    }
3658
+#endif
3641 3659
   else if (streq (p[0], "remote") && p[1])
3642 3660
     {
3643 3661
       struct remote_entry re;
... ...
@@ -97,6 +97,14 @@ struct connection_entry
97 97
   int socks_proxy_port;
98 98
   bool socks_proxy_retry;
99 99
 #endif
100
+
101
+# define CE_DISABLED (1<<0)
102
+#if HTTP_PROXY_FALLBACK
103
+# define CE_HTTP_PROXY_FALLBACK (1<<1)
104
+  time_t ce_http_proxy_fallback_timestamp; /* time when fallback http_proxy_options was last updated */
105
+#endif
106
+
107
+  unsigned int flags;
100 108
 };
101 109
 
102 110
 struct remote_entry
... ...
@@ -114,6 +122,7 @@ struct connection_list
114 114
 {
115 115
   int len;
116 116
   int current;
117
+  int n_cycles;
117 118
   bool no_advance;
118 119
   struct connection_entry *array[CONNECTION_LIST_SIZE];
119 120
 };
... ...
@@ -126,6 +135,14 @@ struct remote_list
126 126
 
127 127
 #endif
128 128
 
129
+#if HTTP_PROXY_FALLBACK
130
+struct hpo_store
131
+{
132
+  struct http_proxy_options hpo;
133
+  char server[80];
134
+};
135
+#endif
136
+
129 137
 /* Command line options */
130 138
 struct options
131 139
 {
... ...
@@ -162,14 +179,22 @@ struct options
162 162
   struct connection_entry ce;
163 163
 
164 164
 #ifdef ENABLE_CONNECTION
165
+  char *remote_ip_hint;
165 166
   struct connection_list *connection_list;
166 167
   struct remote_list *remote_list;
168
+  bool force_connection_list;
167 169
 #endif
168 170
 
169 171
 #ifdef GENERAL_PROXY_SUPPORT
170 172
   struct auto_proxy_info *auto_proxy_info;
171 173
 #endif
172 174
 
175
+#if HTTP_PROXY_FALLBACK
176
+  bool http_proxy_fallback;
177
+  struct http_proxy_options *http_proxy_override;
178
+  struct hpo_store *hpo_store; /* used to store dynamic proxy info given by management interface */
179
+#endif
180
+
173 181
   bool remote_random;
174 182
   const char *ipchange;
175 183
   const char *dev;
... ...
@@ -710,4 +735,15 @@ connection_list_set_no_advance (struct options *o)
710 710
 #endif
711 711
 }
712 712
 
713
+#if HTTP_PROXY_FALLBACK
714
+
715
+struct http_proxy_options *
716
+parse_http_proxy_fallback (struct context *c,
717
+			   const char *server,
718
+			   const char *port,
719
+			   const char *flags,
720
+			   const int msglevel);
721
+
722
+#endif /* HTTP_PROXY_FALLBACK */
723
+
713 724
 #endif
... ...
@@ -224,10 +224,14 @@ get_user_pass_http (struct http_proxy_info *p, const bool force)
224 224
 {
225 225
   if (!static_proxy_user_pass.defined || force)
226 226
     {
227
+      unsigned int flags = GET_USER_PASS_MANAGEMENT;
228
+      if (p->queried_creds)
229
+	flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED;
227 230
       get_user_pass (&static_proxy_user_pass,
228 231
 		     p->options.auth_file,
229 232
 		     UP_TYPE_PROXY,
230
-		     GET_USER_PASS_MANAGEMENT);
233
+		     flags);
234
+      p->queried_creds = true;
231 235
       p->up = static_proxy_user_pass;
232 236
     }
233 237
 }
... ...
@@ -755,12 +759,12 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
755 755
 			    realm,
756 756
 			    password,
757 757
 			    nonce,
758
-			    cnonce,
758
+			    (char *)cnonce,
759 759
 			    session_key);
760 760
 	      DigestCalcResponse(session_key,
761 761
 				 nonce,
762 762
 				 nonce_count,
763
-				 cnonce,
763
+				 (char *)cnonce,
764 764
 				 qop,
765 765
 				 http_method,
766 766
 				 uri,
... ...
@@ -877,6 +881,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
877 877
       goto error;
878 878
     }
879 879
 
880
+  /* SUCCESS */
881
+
880 882
   /* receive line from proxy and discard */
881 883
   if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received))
882 884
     goto error;
... ...
@@ -888,6 +894,9 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
888 888
   while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received))
889 889
     ;
890 890
 
891
+  /* reset queried_creds so that we don't think that the next creds request is due to an auth error */
892
+  p->queried_creds = false;
893
+
891 894
 #if 0
892 895
   if (lookahead && BLEN (lookahead))
893 896
     msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0));
... ...
@@ -71,7 +71,7 @@ struct http_proxy_options {
71 71
 # define PAR_NO  0  /* don't support any auth retries */
72 72
 # define PAR_ALL 1  /* allow all proxy auth protocols */
73 73
 # define PAR_NCT 2  /* disable cleartext proxy auth protocols */
74
-  bool auth_retry;
74
+  int auth_retry;
75 75
 
76 76
   const char *auth_method_string;
77 77
   const char *auth_file;
... ...
@@ -79,12 +79,19 @@ struct http_proxy_options {
79 79
   const char *user_agent;
80 80
 };
81 81
 
82
+struct http_proxy_options_simple {
83
+  const char *server;
84
+  int port;
85
+  int auth_retry;
86
+};
87
+
82 88
 struct http_proxy_info {
83 89
   bool defined;
84 90
   int auth_method;
85 91
   struct http_proxy_options options;
86 92
   struct user_pass up;
87 93
   char *proxy_authenticate;
94
+  bool queried_creds;
88 95
 };
89 96
 
90 97
 struct http_proxy_info *http_proxy_new (const struct http_proxy_options *o,
... ...
@@ -625,6 +625,22 @@ socket_defined (const socket_descriptor_t sd)
625 625
 #define ENABLE_INLINE_FILES 1
626 626
 
627 627
 /*
628
+ * Support "connection" directive
629
+ */
630
+#if ENABLE_INLINE_FILES
631
+#define ENABLE_CONNECTION 1
632
+#endif
633
+
634
+/*
635
+ * Should we include http proxy fallback functionality
636
+ */
637
+#if defined(ENABLE_CONNECTION) && defined(ENABLE_MANAGEMENT) && defined(ENABLE_HTTP_PROXY)
638
+#define HTTP_PROXY_FALLBACK 1
639
+#else
640
+#define HTTP_PROXY_FALLBACK 0
641
+#endif
642
+
643
+/*
628 644
  * Reduce sensitivity to system clock instability
629 645
  * and backtracks.
630 646
  */
... ...
@@ -646,11 +662,4 @@ socket_defined (const socket_descriptor_t sd)
646 646
 #define AUTO_USERID 0
647 647
 #endif
648 648
 
649
-/*
650
- * Support "connection" directive
651
- */
652
-#if ENABLE_INLINE_FILES
653
-#define ENABLE_CONNECTION 1
654
-#endif
655
-
656 649
 #endif
... ...
@@ -1,5 +1,5 @@
1 1
 dnl define the OpenVPN version
2
-define(PRODUCT_VERSION,[2.1.1g])
2
+define(PRODUCT_VERSION,[2.1.1h])
3 3
 dnl define the TAP version
4 4
 define(PRODUCT_TAP_ID,[tap0901])
5 5
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])