Browse code

Windows reliability changes: * Added code to make sure that the local PATH environmental variable points to the Windows system32 directory. * Added new --ip-win32 adaptive mode which tries 'dynamic' and then fails over to 'netsh' if the DHCP negotiation fails. * Made --ip-win32 adaptive the default.

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

james authored on 2005/10/31 12:01:17
Showing 12 changed files
... ...
@@ -131,6 +131,7 @@
131 131
 #define D_SHOW_PKCS11        LOGLEV(7, 70, M_DEBUG)  /* show PKCS#11 actions */
132 132
 #define D_ALIGN_DEBUG        LOGLEV(7, 70, M_DEBUG)  /* show verbose struct alignment info */
133 133
 #define D_PACKET_TRUNC_DEBUG LOGLEV(7, 70, M_DEBUG)  /* PACKET_TRUNCATION_CHECK verbose */
134
+#define D_PING               LOGLEV(7, 70, M_DEBUG)  /* PING send/receive messages */
134 135
 
135 136
 #define D_HANDSHAKE_VERBOSE  LOGLEV(8, 70, M_DEBUG)  /* show detailed description of each handshake */
136 137
 #define D_TLS_DEBUG_MED      LOGLEV(8, 70, M_DEBUG)  /* limited info from tls_session routines */
... ...
@@ -274,8 +274,12 @@ check_add_routes_dowork (struct context *c)
274 274
   else
275 275
     {
276 276
       msg (D_ROUTE, "Route: Waiting for TUN/TAP interface to come up...");
277
+      if (c->c1.tuntap)
278
+	tun_standby (c->c1.tuntap);
279
+      update_time ();
277 280
       if (c->c2.route_wakeup.n != 1)
278 281
 	event_timeout_init (&c->c2.route_wakeup, 1, now);
282
+      event_timeout_reset (&c->c2.ping_rec_interval);
279 283
     }
280 284
 }
281 285
 
... ...
@@ -773,7 +777,7 @@ process_incoming_link (struct context *c)
773 773
 #endif
774 774
 
775 775
 #ifdef PACKET_TRUNCATION_CHECK
776
-      /* if (c->c2.buf.len > 1) --c->c2.buf.len; JYFIXME */
776
+      /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
777 777
       ipv4_packet_size_verify (BPTR (&c->c2.buf),
778 778
 			       BLEN (&c->c2.buf),
779 779
 			       TUNNEL_TYPE (c->c1.tuntap),
... ...
@@ -807,7 +811,7 @@ process_incoming_link (struct context *c)
807 807
       /* Did we just receive an openvpn ping packet? */
808 808
       if (is_ping_msg (&c->c2.buf))
809 809
 	{
810
-	  dmsg (D_PACKET_CONTENT, "RECEIVED PING PACKET");
810
+	  dmsg (D_PING, "RECEIVED PING PACKET");
811 811
 	  c->c2.buf.len = 0; /* drop packet */
812 812
 	}
813 813
 
... ...
@@ -911,7 +915,7 @@ process_incoming_tun (struct context *c)
911 911
       process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf);
912 912
 
913 913
 #ifdef PACKET_TRUNCATION_CHECK
914
-      /* if (c->c2.buf.len > 1) --c->c2.buf.len; JYFIXME */
914
+      /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
915 915
       ipv4_packet_size_verify (BPTR (&c->c2.buf),
916 916
 			       BLEN (&c->c2.buf),
917 917
 			       TUNNEL_TYPE (c->c1.tuntap),
... ...
@@ -122,7 +122,7 @@ context_init_1 (struct context *c)
122 122
   }
123 123
 #endif
124 124
 
125
-#if 0 /* JYFIXME -- test get_user_pass with GET_USER_PASS_NEED_OK flag */
125
+#if 0 /* test get_user_pass with GET_USER_PASS_NEED_OK flag */
126 126
  {
127 127
    /*
128 128
     * In the management interface, you can okay the request by entering "needok token-insertion-request ok"
... ...
@@ -175,6 +175,8 @@ context_gc_free (struct context *c)
175 175
 bool
176 176
 init_static (void)
177 177
 {
178
+  configure_path ();
179
+
178 180
 #if defined(USE_CRYPTO) && defined(DMALLOC)
179 181
   openssl_dmalloc_init ();
180 182
 #endif
... ...
@@ -964,6 +966,8 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
964 964
 	    {
965 965
 	      event_timeout_init (&c->c2.route_wakeup, c->options.route_delay, now);
966 966
 	      event_timeout_init (&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now);
967
+	      if (c->c1.tuntap)
968
+		tun_standby_init (c->c1.tuntap);
967 969
 	    }
968 970
 	  else
969 971
 	    {
... ...
@@ -1372,3 +1372,33 @@ openvpn_sleep (const int n)
1372 1372
 #endif
1373 1373
   sleep (n);
1374 1374
 }
1375
+
1376
+/*
1377
+ * Configure PATH.  On Windows, sometimes PATH is not set correctly
1378
+ * by default.
1379
+ */
1380
+void
1381
+configure_path (void)
1382
+{
1383
+#ifdef WIN32
1384
+  FILE *fp;
1385
+  fp = fopen ("c:\\windows\\system32\\route.exe", "rb");
1386
+  if (fp)
1387
+    {
1388
+      const int bufsiz = 512;
1389
+      struct gc_arena gc = gc_new ();
1390
+      struct buffer oldpath = alloc_buf_gc (bufsiz, &gc);
1391
+      struct buffer newpath = alloc_buf_gc (bufsiz, &gc);
1392
+      DWORD status;
1393
+      fclose (fp);
1394
+      status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
1395
+      if (status > 0)
1396
+	{
1397
+	  buf_printf (&newpath, "C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;%s", BSTR(&oldpath));
1398
+	  SetEnvironmentVariable ("PATH", BSTR(&newpath));
1399
+	  /*printf ("PATH: %s\n", BSTR(&newpath));*/
1400
+	}
1401
+      gc_free (&gc);
1402
+    }
1403
+#endif
1404
+}
... ...
@@ -257,4 +257,6 @@ const char *safe_print (const char *str, struct gc_arena *gc);
257 257
  */
258 258
 void openvpn_sleep (const int n);
259 259
 
260
+void configure_path (void);
261
+
260 262
 #endif
... ...
@@ -612,7 +612,7 @@ init_options (struct options *o)
612 612
   o->tuntap_options.txqueuelen = 100;
613 613
 #endif
614 614
 #ifdef WIN32
615
-  o->tuntap_options.ip_win32_type = IPW32_SET_DHCP_MASQ;
615
+  o->tuntap_options.ip_win32_type = IPW32_SET_ADAPTIVE;
616 616
   o->tuntap_options.dhcp_lease_time = 31536000; /* one year */
617 617
   o->tuntap_options.dhcp_masq_offset = 0;       /* use network address as internal DHCP server address */
618 618
   o->route_method = ROUTE_METHOD_IPAPI;
... ...
@@ -1469,9 +1469,10 @@ options_postprocess (struct options *options, bool first_time)
1469 1469
 	  && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask)))
1470 1470
 	msg (M_USAGE, "On Windows, --ip-win32 doesn't make sense unless --ifconfig is also used");
1471 1471
 
1472
-      if (options->tuntap_options.dhcp_options &&
1473
-	  options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ)
1474
-	msg (M_USAGE, "--dhcp-options requires --ip-win32 dynamic");
1472
+      if (options->tuntap_options.dhcp_options
1473
+	  && options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ
1474
+	  && options->tuntap_options.ip_win32_type != IPW32_SET_ADAPTIVE)
1475
+	msg (M_USAGE, "--dhcp-options requires --ip-win32 dynamic or adaptive");
1475 1476
 
1476 1477
       if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined)
1477 1478
 	{
... ...
@@ -4280,6 +4281,9 @@ add_option (struct options *options,
4280 4280
 	  goto err;
4281 4281
 	}
4282 4282
 
4283
+      if (index == IPW32_SET_ADAPTIVE)
4284
+	options->route_delay_window = IPW32_SET_ADAPTIVE_DELAY_WINDOW;
4285
+
4283 4286
       if (index == IPW32_SET_DHCP_MASQ)
4284 4287
 	{
4285 4288
 	  if (p[2])
... ...
@@ -92,5 +92,5 @@ check_ping_send_dowork (struct context *c)
92 92
    * encrypt, sign, etc.
93 93
    */
94 94
   encrypt_sign (c, true);
95
-  dmsg (D_PACKET_CONTENT, "SENT PING");  
95
+  dmsg (D_PING, "SENT PING");
96 96
 } 
... ...
@@ -75,7 +75,6 @@ struct plugin {
75 75
 
76 76
 struct plugin_per_client
77 77
 {
78
-  /* bool initialized; JYFIXME */
79 78
   void *per_client_context[MAX_PLUGINS];
80 79
 };
81 80
 
... ...
@@ -22,6 +22,8 @@
22 22
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 23
  */
24 24
 
25
+/* JYFIXME WIN32 todo: add adaptive route-method */
26
+
25 27
 /*
26 28
  * Support routines for adding/deleting network routes.
27 29
  */
... ...
@@ -315,9 +315,7 @@ ssl_set_auth_nocache (void)
315 315
 void
316 316
 ssl_purge_auth (void)
317 317
 {
318
-#if 1 /* JYFIXME -- todo: bad private key should trigger a signal, then this code can be included */
319 318
   purge_user_pass (&passbuf, true);
320
-#endif
321 319
   purge_user_pass (&auth_user_pass, true);
322 320
 }
323 321
 
... ...
@@ -47,6 +47,22 @@
47 47
 
48 48
 #include "memdbg.h"
49 49
 
50
+#ifdef WIN32
51
+
52
+#define NI_TEST_FIRST  (1<<0)
53
+#define NI_IP_NETMASK  (1<<1)
54
+#define NI_OPTIONS     (1<<2)
55
+
56
+static void netsh_ifconfig (const struct tuntap_options *to,
57
+			    const char *flex_name,
58
+			    const in_addr_t ip,
59
+			    const in_addr_t netmask,
60
+			    unsigned int flags);
61
+
62
+static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);
63
+
64
+#endif
65
+
50 66
 #ifdef TARGET_SOLARIS
51 67
 static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual);
52 68
 #endif
... ...
@@ -125,7 +141,7 @@ guess_tuntap_dev (const char *dev,
125 125
   const int dt = dev_type_enum (dev, dev_type);
126 126
   if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP)
127 127
     {
128
-      return get_netsh_id (dev_node, gc);
128
+      return netsh_get_id (dev_node, gc);
129 129
     }
130 130
 #endif
131 131
 
... ...
@@ -768,8 +784,6 @@ do_ifconfig (struct tuntap *tt,
768 768
 
769 769
 #elif defined (WIN32)
770 770
       {
771
-	const char *netmask;
772
-
773 771
 	/*
774 772
 	 * Make sure that both ifconfig addresses are part of the
775 773
 	 * same .252 subnet.
... ...
@@ -778,36 +792,30 @@ do_ifconfig (struct tuntap *tt,
778 778
 	  {
779 779
 	    verify_255_255_255_252 (tt->local, tt->remote_netmask);
780 780
 	    tt->adapter_netmask = ~3;
781
-	    netmask = print_in_addr_t (tt->adapter_netmask, 0, &gc);
782 781
 	  }
783 782
 	else
784 783
 	  {
785
-	    netmask = ifconfig_remote_netmask;
786 784
 	    tt->adapter_netmask = tt->remote_netmask;
787 785
 	  }
788 786
 
789
-	/* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */
790
-	openvpn_snprintf (command_line, sizeof (command_line),
791
-			  "netsh interface ip set address \"%s\" static %s %s",
792
-			  actual,
793
-			  ifconfig_local,
794
-			  netmask);
795
-	
796 787
 	switch (tt->options.ip_win32_type)
797 788
 	  {
798 789
 	  case IPW32_SET_MANUAL:
799 790
 	    msg (M_INFO, "******** NOTE:  Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)",
800 791
 		 actual,
801 792
 		 ifconfig_local,
802
-		 netmask);
793
+		 print_in_addr_t (tt->adapter_netmask, 0, &gc));
803 794
 	    break;
804 795
 	  case IPW32_SET_NETSH:
805 796
 	    if (!strcmp (actual, "NULL"))
806 797
 	      msg (M_FATAL, "Error: When using --ip-win32 netsh, if you have more than one TAP-Win32 adapter, you must also specify --dev-node");
807
-	    netcmd_semaphore_lock ();
808
-	    msg (M_INFO, "%s", command_line);
809
-	    system_check (command_line, es, S_FATAL, "ERROR: netsh command failed");
810
-	    netcmd_semaphore_release ();
798
+
799
+	    netsh_ifconfig (&tt->options,
800
+			    actual,
801
+			    tt->local,
802
+			    tt->adapter_netmask,
803
+			    NI_IP_NETMASK|NI_OPTIONS);
804
+
811 805
 	    break;
812 806
 	  }
813 807
 	tt->did_ifconfig = true;
... ...
@@ -2262,7 +2270,7 @@ get_unspecified_device_guid (const int device_number,
2262 2262
       if (act)
2263 2263
 	buf_printf (&actual, "%s", act);
2264 2264
       else
2265
-	buf_printf (&actual, "NULL");
2265
+	buf_printf (&actual, "%s", tap_reg->guid);
2266 2266
     }
2267 2267
 
2268 2268
   /* Save GUID for return value */
... ...
@@ -2305,7 +2313,7 @@ get_device_guid (const char *name,
2305 2305
       if (act)
2306 2306
 	buf_printf (&actual, "%s", act);
2307 2307
       else
2308
-	buf_printf (&actual, "NULL");
2308
+	buf_printf (&actual, "%s", name);
2309 2309
       return BSTR (&ret);
2310 2310
     }
2311 2311
 
... ...
@@ -2324,39 +2332,6 @@ get_device_guid (const char *name,
2324 2324
 }
2325 2325
 
2326 2326
 /*
2327
- * Return a TAP name for netsh commands.
2328
- */
2329
-const char *
2330
-get_netsh_id (const char *dev_node, struct gc_arena *gc)
2331
-{
2332
-  const struct tap_reg *tap_reg = get_tap_reg (gc);
2333
-  const struct panel_reg *panel_reg = get_panel_reg (gc);
2334
-  struct buffer actual = alloc_buf_gc (256, gc);
2335
-  const char *guid;
2336
-
2337
-  at_least_one_tap_win32 (tap_reg);
2338
-
2339
-  if (dev_node)
2340
-    {
2341
-      guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc);
2342
-    }
2343
-  else
2344
-    {
2345
-      guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc);
2346
-
2347
-      if (get_unspecified_device_guid (1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Win32 adapter */
2348
-	guid = NULL;
2349
-    }
2350
-
2351
-  if (!guid)
2352
-    return "NULL";         /* not found */
2353
-  else if (strcmp (BPTR (&actual), "NULL"))
2354
-    return BPTR (&actual); /* control panel name */
2355
-  else
2356
-    return guid;           /* no control panel name, return GUID instead */
2357
-}
2358
-
2359
-/*
2360 2327
  * Get adapter info list
2361 2328
  */
2362 2329
 const IP_ADAPTER_INFO *
... ...
@@ -2394,23 +2369,26 @@ get_per_adapter_info (const DWORD index, struct gc_arena *gc)
2394 2394
   IP_PER_ADAPTER_INFO *pi = NULL;
2395 2395
   DWORD status;
2396 2396
 
2397
-  if ((status = GetPerAdapterInfo (index, NULL, &size)) != ERROR_BUFFER_OVERFLOW)
2398
-    {
2399
-      msg (M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s",
2400
-	   (unsigned int)status,
2401
-	   strerror_win32 (status, gc));
2402
-    }
2403
-  else
2397
+  if (index != ~0)
2404 2398
     {
2405
-      pi = (PIP_PER_ADAPTER_INFO) gc_malloc (size, false, gc);
2406
-      if ((status = GetPerAdapterInfo ((ULONG)index, pi, &size)) == ERROR_SUCCESS)
2407
-	return pi;
2408
-      else
2399
+      if ((status = GetPerAdapterInfo (index, NULL, &size)) != ERROR_BUFFER_OVERFLOW)
2409 2400
 	{
2410
-	  msg (M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s",
2401
+	  msg (M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s",
2411 2402
 	       (unsigned int)status,
2412 2403
 	       strerror_win32 (status, gc));
2413 2404
 	}
2405
+      else
2406
+	{
2407
+	  pi = (PIP_PER_ADAPTER_INFO) gc_malloc (size, false, gc);
2408
+	  if ((status = GetPerAdapterInfo ((ULONG)index, pi, &size)) == ERROR_SUCCESS)
2409
+	    return pi;
2410
+	  else
2411
+	    {
2412
+	      msg (M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s",
2413
+		   (unsigned int)status,
2414
+		   strerror_win32 (status, gc));
2415
+	    }
2416
+	}
2414 2417
     }
2415 2418
   return pi;
2416 2419
 }
... ...
@@ -2547,6 +2525,20 @@ get_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const int n, in_addr_t *ip, i
2547 2547
   return ret;
2548 2548
 }
2549 2549
 
2550
+static bool
2551
+test_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const in_addr_t ip, const in_addr_t netmask)
2552
+{
2553
+  if (ai)
2554
+    {
2555
+      in_addr_t ip_adapter = 0;
2556
+      in_addr_t netmask_adapter = 0;
2557
+      const bool status = get_adapter_ip_netmask (ai, 0, &ip_adapter, &netmask_adapter);
2558
+      return (status && ip_adapter == ip && netmask_adapter == netmask);
2559
+    }
2560
+  else
2561
+    return false;
2562
+}
2563
+
2550 2564
 const IP_ADAPTER_INFO *
2551 2565
 get_tun_adapter (const struct tuntap *tt, const IP_ADAPTER_INFO *list)
2552 2566
 {
... ...
@@ -2675,16 +2667,28 @@ adapter_index_of_ip (const IP_ADAPTER_INFO *list, const in_addr_t ip, int *count
2675 2675
  * Given an adapter index, return true if the adapter
2676 2676
  * is DHCP disabled.
2677 2677
  */
2678
-static bool
2679
-dhcp_disabled (DWORD index)
2678
+
2679
+#define DHCP_STATUS_UNDEF     0
2680
+#define DHCP_STATUS_ENABLED   1
2681
+#define DHCP_STATUS_DISABLED  2
2682
+
2683
+static int
2684
+dhcp_status (DWORD index)
2680 2685
 {
2681 2686
   struct gc_arena gc = gc_new ();
2682
-  const IP_ADAPTER_INFO *ai = get_adapter_info (index, &gc);
2683
-  bool ret = false;
2684
-
2685
-  if (ai && !ai->DhcpEnabled)
2686
-    ret = true;
2687
+  int ret = DHCP_STATUS_UNDEF;
2688
+  if (index != ~0)
2689
+    {
2690
+      const IP_ADAPTER_INFO *ai = get_adapter_info (index, &gc);
2687 2691
 
2692
+      if (ai)
2693
+	{
2694
+	  if (ai->DhcpEnabled)
2695
+	    ret = DHCP_STATUS_ENABLED;
2696
+	  else
2697
+	    ret = DHCP_STATUS_DISABLED;
2698
+	}
2699
+    }
2688 2700
   gc_free (&gc);
2689 2701
   return ret;
2690 2702
 }
... ...
@@ -2733,28 +2737,75 @@ delete_temp_addresses (DWORD index)
2733 2733
  * Get interface index for use with IP Helper API functions.
2734 2734
  */
2735 2735
 static DWORD
2736
-get_interface_index (const char *guid)
2736
+get_adapter_index_method_1 (const char *guid)
2737 2737
 {
2738 2738
   struct gc_arena gc = gc_new ();
2739
-  ULONG index;
2739
+  ULONG index = ~0;
2740 2740
   DWORD status;
2741 2741
   wchar_t wbuf[256];
2742 2742
   snwprintf (wbuf, SIZE (wbuf), L"\\DEVICE\\TCPIP_%S", guid);
2743 2743
   wbuf [SIZE(wbuf) - 1] = 0;
2744 2744
   if ((status = GetAdapterIndex (wbuf, &index)) != NO_ERROR)
2745
+    index = ~0;
2746
+  gc_free (&gc);
2747
+  return index;
2748
+}
2749
+
2750
+static DWORD
2751
+get_adapter_index_method_2 (const char *guid)
2752
+{
2753
+  struct gc_arena gc = gc_new ();
2754
+  DWORD index = ~0;
2755
+
2756
+  const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc);
2757
+
2758
+  while (list)
2745 2759
     {
2746
-      msg (M_INFO, "NOTE: could not get adapter index for %S, status=%u : %s",
2747
-	   wbuf,
2748
-	   (unsigned int)status,
2749
-	   strerror_win32 (status, &gc));
2750
-      gc_free (&gc);
2751
-      return (DWORD)~0;
2752
-    }
2753
-  else
2754
-    {
2755
-      gc_free (&gc);
2756
-      return index;
2760
+      if (!strcmp (guid, list->AdapterName))
2761
+	{
2762
+	  index = list->Index;
2763
+	  break;
2764
+	}
2765
+      list = list->Next;
2757 2766
     }
2767
+
2768
+  gc_free (&gc);
2769
+  return index;
2770
+}
2771
+
2772
+static DWORD
2773
+get_adapter_index (const char *guid)
2774
+{
2775
+  DWORD index;
2776
+  index = get_adapter_index_method_1 (guid);
2777
+  if (index == ~0)
2778
+    index = get_adapter_index_method_2 (guid);
2779
+  if (index == ~0)
2780
+    msg (M_INFO, "NOTE: could not get adapter index for %s", guid);
2781
+  return index;
2782
+}
2783
+
2784
+static DWORD
2785
+get_adapter_index_flexible (const char *name) /* actual name or GUID */
2786
+{
2787
+  struct gc_arena gc = gc_new ();
2788
+  DWORD index;
2789
+  index = get_adapter_index_method_1 (name);
2790
+  if (index == ~0)
2791
+    index = get_adapter_index_method_2 (name);
2792
+  if (index == ~0)
2793
+    {
2794
+      const struct tap_reg *tap_reg = get_tap_reg (&gc);
2795
+      const struct panel_reg *panel_reg = get_panel_reg (&gc);
2796
+      const char *guid = name_to_guid (name, tap_reg, panel_reg);
2797
+      index = get_adapter_index_method_1 (guid);
2798
+      if (index == ~0)
2799
+	index = get_adapter_index_method_2 (guid);
2800
+    }
2801
+  if (index == ~0)
2802
+    msg (M_INFO, "NOTE: could not get adapter index for name/GUID '%s'", name);
2803
+  gc_free (&gc);
2804
+  return index;
2758 2805
 }
2759 2806
 
2760 2807
 /*
... ...
@@ -2869,7 +2920,7 @@ tap_allow_nonadmin_access (const char *dev_node)
2869 2869
   const struct panel_reg *panel_reg = get_panel_reg (&gc);
2870 2870
   const char *device_guid = NULL;
2871 2871
   HANDLE hand;
2872
-  char guid_buffer[256];
2872
+  char actual_buffer[256];
2873 2873
   char device_path[256];
2874 2874
 
2875 2875
   at_least_one_tap_win32 (tap_reg);
... ...
@@ -2877,7 +2928,7 @@ tap_allow_nonadmin_access (const char *dev_node)
2877 2877
   if (dev_node)
2878 2878
     {
2879 2879
       /* Get the device GUID for the device specified with --dev-node. */
2880
-      device_guid = get_device_guid (dev_node, guid_buffer, sizeof (guid_buffer), tap_reg, panel_reg, &gc);
2880
+      device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc);
2881 2881
 
2882 2882
       if (!device_guid)
2883 2883
 	msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node);
... ...
@@ -2912,8 +2963,8 @@ tap_allow_nonadmin_access (const char *dev_node)
2912 2912
       while (true)
2913 2913
 	{
2914 2914
 	  device_guid = get_unspecified_device_guid (device_number, 
2915
-						     guid_buffer, 
2916
-						     sizeof (guid_buffer),
2915
+						     actual_buffer, 
2916
+						     sizeof (actual_buffer),
2917 2917
 						     tap_reg,
2918 2918
 						     panel_reg,
2919 2919
 						     &gc);
... ...
@@ -3008,6 +3059,149 @@ dhcp_renew (const struct tuntap *tt)
3008 3008
 }
3009 3009
 
3010 3010
 /*
3011
+ * netsh functions
3012
+ */
3013
+
3014
+static void
3015
+netsh_command (const char *cmd, int n)
3016
+{
3017
+  int i;
3018
+  for (i = 0; i < n; ++i)
3019
+    {
3020
+      bool status;
3021
+      netcmd_semaphore_lock ();
3022
+      msg (M_INFO, "NETSH: %s", cmd);
3023
+      status = system_check (cmd, NULL, 0, "ERROR: netsh command failed");
3024
+      netcmd_semaphore_release ();
3025
+      if (status)
3026
+	return;
3027
+      openvpn_sleep (5);
3028
+    }
3029
+  msg (M_FATAL, "NETSH: command failed");
3030
+}
3031
+
3032
+static void
3033
+netsh_ifconfig (const struct tuntap_options *to,
3034
+		const char *flex_name,
3035
+		const in_addr_t ip,
3036
+		const in_addr_t netmask,
3037
+		unsigned int flags)
3038
+{
3039
+  struct gc_arena gc = gc_new ();
3040
+  struct buffer out = alloc_buf_gc (256, &gc);
3041
+  const IP_ADAPTER_INFO *ai = NULL;
3042
+  const IP_PER_ADAPTER_INFO *pai = NULL;
3043
+
3044
+  if (flags & NI_TEST_FIRST)
3045
+    {
3046
+      const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc);
3047
+      const int index = get_adapter_index_flexible (flex_name);
3048
+      ai = get_adapter (list, index);
3049
+      pai = get_per_adapter_info (index, &gc);
3050
+    }
3051
+
3052
+  if (flags & NI_IP_NETMASK)
3053
+    {
3054
+      if (test_adapter_ip_netmask (ai, ip, netmask))
3055
+	{
3056
+	  msg (M_INFO, "NETSH: \"%s\" %s/%s [already set]",
3057
+	       flex_name,
3058
+	       print_in_addr_t (ip, 0, &gc),
3059
+	       print_in_addr_t (netmask, 0, &gc));
3060
+	}
3061
+      else
3062
+	{
3063
+	  /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */
3064
+	  buf_init (&out, 0);
3065
+	  buf_printf (&out,
3066
+		      "netsh interface ip set address \"%s\" static %s %s",
3067
+		      flex_name,
3068
+		      print_in_addr_t (ip, 0, &gc),
3069
+		      print_in_addr_t (netmask, 0, &gc));
3070
+
3071
+	  netsh_command (BSTR(&out), 4);
3072
+	}
3073
+    }
3074
+
3075
+  gc_free (&gc);
3076
+}
3077
+
3078
+static void
3079
+netsh_enable_dhcp (const struct tuntap_options *to,
3080
+		   const char *actual_name)
3081
+{
3082
+  struct gc_arena gc = gc_new ();
3083
+  struct buffer out = alloc_buf_gc (256, &gc);
3084
+
3085
+  /* example: netsh interface ip set address my-tap dhcp */
3086
+  buf_printf (&out,
3087
+	      "netsh interface ip set address \"%s\" dhcp",
3088
+	      actual_name);
3089
+
3090
+  netsh_command (BSTR(&out), 4);
3091
+
3092
+  gc_free (&gc);
3093
+}
3094
+
3095
+/*
3096
+ * Return a TAP name for netsh commands.
3097
+ */
3098
+static const char *
3099
+netsh_get_id (const char *dev_node, struct gc_arena *gc)
3100
+{
3101
+  const struct tap_reg *tap_reg = get_tap_reg (gc);
3102
+  const struct panel_reg *panel_reg = get_panel_reg (gc);
3103
+  struct buffer actual = alloc_buf_gc (256, gc);
3104
+  const char *guid;
3105
+
3106
+  at_least_one_tap_win32 (tap_reg);
3107
+
3108
+  if (dev_node)
3109
+    {
3110
+      guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc);
3111
+    }
3112
+  else
3113
+    {
3114
+      guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc);
3115
+
3116
+      if (get_unspecified_device_guid (1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Win32 adapter */
3117
+	guid = NULL;
3118
+    }
3119
+
3120
+  if (!guid)
3121
+    return "NULL";         /* not found */
3122
+  else if (strcmp (BPTR (&actual), "NULL"))
3123
+    return BPTR (&actual); /* control panel name */
3124
+  else
3125
+    return guid;           /* no control panel name, return GUID instead */
3126
+}
3127
+
3128
+/*
3129
+ * Called iteratively on TAP-Win32 wait-for-initialization polling loop
3130
+ */
3131
+void
3132
+tun_standby_init (struct tuntap *tt)
3133
+{
3134
+  tt->standby_iter = 0;
3135
+}
3136
+
3137
+void
3138
+tun_standby (struct tuntap *tt)
3139
+{
3140
+  ++tt->standby_iter;
3141
+  if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE
3142
+      && tt->standby_iter % IPW32_SET_ADAPTIVE_TRY_NETSH == 0)
3143
+    {
3144
+      msg (M_INFO, "NOTE: --ip-win32 dynamic failed, now trying --ip-win32 netsh (this may take some time)");
3145
+      netsh_ifconfig (&tt->options,
3146
+		      tt->actual_name,
3147
+		      tt->local,
3148
+		      tt->adapter_netmask,
3149
+		      NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS);
3150
+    }
3151
+}
3152
+
3153
+/*
3011 3154
  * Convert DHCP options from the command line / config file
3012 3155
  * into a raw DHCP-format options string.
3013 3156
  */
... ...
@@ -3091,6 +3285,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3091 3091
   char device_path[256];
3092 3092
   const char *device_guid = NULL;
3093 3093
   DWORD len;
3094
+  bool dhcp_masq = false;
3095
+  bool dhcp_masq_post = false;
3094 3096
 
3095 3097
   /*netcmd_semaphore_lock ();*/
3096 3098
 
... ...
@@ -3117,14 +3313,14 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3117 3117
   {
3118 3118
     const struct tap_reg *tap_reg = get_tap_reg (&gc);
3119 3119
     const struct panel_reg *panel_reg = get_panel_reg (&gc);
3120
-    char guid_buffer[256];
3120
+    char actual_buffer[256];
3121 3121
 
3122 3122
     at_least_one_tap_win32 (tap_reg);
3123 3123
 
3124 3124
     if (dev_node)
3125 3125
       {
3126 3126
         /* Get the device GUID for the device specified with --dev-node. */
3127
-        device_guid = get_device_guid (dev_node, guid_buffer, sizeof (guid_buffer), tap_reg, panel_reg, &gc);
3127
+        device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc);
3128 3128
 
3129 3129
 	if (!device_guid)
3130 3130
 	  msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node);
... ...
@@ -3156,8 +3352,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3156 3156
         while (true)
3157 3157
           {
3158 3158
             device_guid = get_unspecified_device_guid (device_number, 
3159
-						       guid_buffer, 
3160
-						       sizeof (guid_buffer),
3159
+						       actual_buffer, 
3160
+						       sizeof (actual_buffer),
3161 3161
 						       tap_reg,
3162 3162
 						       panel_reg,
3163 3163
 						       &gc);
... ...
@@ -3192,10 +3388,11 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3192 3192
 
3193 3193
     /* translate high-level device name into a device instance
3194 3194
        GUID using the registry */
3195
-    tt->actual_name = string_alloc (guid_buffer, NULL);
3195
+    tt->actual_name = string_alloc (actual_buffer, NULL);
3196 3196
   }
3197 3197
 
3198 3198
   msg (M_INFO, "TAP-WIN32 device [%s] opened: %s", tt->actual_name, device_path);
3199
+  tt->adapter_index = get_adapter_index (device_guid);
3199 3200
 
3200 3201
   /* get driver version info */
3201 3202
   {
... ...
@@ -3230,6 +3427,42 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3230 3230
       }
3231 3231
   }
3232 3232
 
3233
+  /*
3234
+   * Preliminaries for setting TAP-Win32 adapter TCP/IP
3235
+   * properties via --ip-win32 dynamic or --ip-win32 adaptive.
3236
+   */
3237
+  if (tt->did_ifconfig_setup)
3238
+    {
3239
+      if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ)
3240
+	{
3241
+	  /*
3242
+	   * If adapter is set to non-DHCP, set to DHCP mode.
3243
+	   */
3244
+	  if (dhcp_status (tt->adapter_index) == DHCP_STATUS_DISABLED)
3245
+	    netsh_enable_dhcp (&tt->options, tt->actual_name);
3246
+	  dhcp_masq = true;
3247
+	  dhcp_masq_post = true;
3248
+	}
3249
+      else if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE)
3250
+	{
3251
+	  /*
3252
+	   * If adapter is set to non-DHCP, use netsh right away.
3253
+	   */
3254
+	  if (dhcp_status (tt->adapter_index) != DHCP_STATUS_ENABLED)
3255
+	    {
3256
+	      netsh_ifconfig (&tt->options,
3257
+			      tt->actual_name,
3258
+			      tt->local,
3259
+			      tt->adapter_netmask,
3260
+			      NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS);
3261
+	    }
3262
+	  else
3263
+	    {
3264
+	      dhcp_masq = true;
3265
+	    }
3266
+	}
3267
+    }
3268
+
3233 3269
   /* set point-to-point mode if TUN device */
3234 3270
 
3235 3271
   if (tt->type == DEV_TYPE_TUN)
... ...
@@ -3273,7 +3506,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3273 3273
 
3274 3274
   /* should we tell the TAP-Win32 driver to masquerade as a DHCP server as a means
3275 3275
      of setting the adapter address? */
3276
-  if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ)
3276
+  if (dhcp_masq)
3277 3277
     {
3278 3278
       uint32_t ep[4];
3279 3279
 
... ...
@@ -3320,6 +3553,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3320 3320
 
3321 3321
       ASSERT (ep[3] > 0);
3322 3322
 
3323
+#if 1 /* TAP_IOCTL_CONFIG_DHCP_MASQ -- disable to simulate bad DHCP negotiation */
3323 3324
       if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_DHCP_MASQ,
3324 3325
 			    ep, sizeof (ep),
3325 3326
 			    ep, sizeof (ep), &len, NULL))
... ...
@@ -3332,6 +3566,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3332 3332
 	   print_in_addr_t (ep[2], IA_NET_ORDER, &gc),
3333 3333
 	   ep[3]
3334 3334
 	   );
3335
+#endif
3335 3336
 
3336 3337
       /* user-supplied DHCP options capability */
3337 3338
       if (tt->options.dhcp_options)
... ...
@@ -3368,8 +3603,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3368 3368
 
3369 3369
   /* possibly use IP Helper API to set IP address on adapter */
3370 3370
   {
3371
-    DWORD index = get_interface_index (device_guid);
3372
-    tt->adapter_index = index;
3371
+    const DWORD index = tt->adapter_index;
3373 3372
     
3374 3373
     /* flush arp cache */
3375 3374
     if (index != (DWORD)~0)
... ...
@@ -3393,10 +3627,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3393 3393
      * make sure the TCP/IP properties for the adapter are
3394 3394
      * set correctly.
3395 3395
      */
3396
-    if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ)
3396
+    if (dhcp_masq_post)
3397 3397
       {
3398 3398
 	/* check dhcp enable status */
3399
-	if (dhcp_disabled (index))
3399
+	if (dhcp_status (index) == DHCP_STATUS_DISABLED)
3400 3400
 	  msg (M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'");
3401 3401
 
3402 3402
 	/* force an explicit DHCP lease renewal on TAP adapter? */
... ...
@@ -3420,7 +3654,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
3420 3420
 	  }
3421 3421
 
3422 3422
 	/* check dhcp enable status */
3423
-	if (dhcp_disabled (index))
3423
+	if (dhcp_status (index) == DHCP_STATUS_DISABLED)
3424 3424
 	  msg (M_WARN, "NOTE: You have selected (explicitly or by default) '--ip-win32 ipapi', which has a better chance of working correctly if the TAP-Win32 TCP/IP properties are set to 'Obtain an IP address automatically'");
3425 3425
 
3426 3426
 	/* delete previously added IP addresses which were not
... ...
@@ -3556,7 +3790,8 @@ static const struct ipset_names ipset_names[] = {
3556 3556
   {"manual"},
3557 3557
   {"netsh"},
3558 3558
   {"ipapi"},
3559
-  {"dynamic"}
3559
+  {"dynamic"},
3560
+  {"adaptive"}
3560 3561
 };
3561 3562
 
3562 3563
 int
... ...
@@ -40,6 +40,10 @@
40 40
 
41 41
 #ifdef WIN32
42 42
 
43
+/* time constants for --ip-win32 adaptive */
44
+#define IPW32_SET_ADAPTIVE_DELAY_WINDOW 300
45
+#define IPW32_SET_ADAPTIVE_TRY_NETSH    20
46
+
43 47
 struct tuntap_options {
44 48
   /* --ip-win32 options */
45 49
   bool ip_win32_defined;
... ...
@@ -48,7 +52,8 @@ struct tuntap_options {
48 48
 # define IPW32_SET_NETSH        1  /* "--ip-win32 netsh" */
49 49
 # define IPW32_SET_IPAPI        2  /* "--ip-win32 ipapi" */
50 50
 # define IPW32_SET_DHCP_MASQ    3  /* "--ip-win32 dynamic" */
51
-# define IPW32_SET_N            4
51
+# define IPW32_SET_ADAPTIVE     4  /* "--ip-win32 adaptive" */
52
+# define IPW32_SET_N            5
52 53
   int ip_win32_type;
53 54
 
54 55
   /* --ip-win32 dynamic options */
... ...
@@ -155,6 +160,8 @@ struct tuntap
155 155
   /* Windows adapter index for TAP-Win32 adapter,
156 156
      ~0 if undefined */
157 157
   DWORD adapter_index;
158
+
159
+  int standby_iter;
158 160
 #else
159 161
   int fd;   /* file descriptor for TUN/TAP dev */
160 162
 #endif
... ...
@@ -318,12 +325,13 @@ void tun_show_debug (struct tuntap *tt);
318 318
 bool dhcp_release (const struct tuntap *tt);
319 319
 bool dhcp_renew (const struct tuntap *tt);
320 320
 
321
+void tun_standby_init (struct tuntap *tt);
322
+void tun_standby (struct tuntap *tt);
323
+
321 324
 int tun_read_queue (struct tuntap *tt, int maxsize);
322 325
 int tun_write_queue (struct tuntap *tt, struct buffer *buf);
323 326
 int tun_finalize (HANDLE h, struct overlapped_io *io, struct buffer *buf);
324 327
 
325
-const char *get_netsh_id (const char *dev_node, struct gc_arena *gc);
326
-
327 328
 static inline bool
328 329
 tuntap_stop (int status)
329 330
 {
... ...
@@ -379,6 +387,16 @@ tuntap_stop (int status)
379 379
   return false;
380 380
 }
381 381
 
382
+static inline void
383
+tun_standby_init (struct tuntap *tt)
384
+{
385
+}
386
+
387
+static inline void
388
+tun_standby (struct tuntap *tt)
389
+{
390
+}
391
+
382 392
 #endif
383 393
 
384 394
 /*