Browse code

Fixed a client-side bug that occurred when the "dhcp-pre-release" or "dhcp-renew" options were combined with "route-gateway dhcp".

The problem is that the IP Helper functions for DHCP release and
renew are blocking, and so calling them from a single-threaded
client stops tunnel traffic forwarding, and hence breaks
"route-gateway dhcp" which requires an active tunnel. The fix is
to call the IP Helper functions for DHCP release and renew from
another process.

Version 2.1_rc21b.


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

james authored on 2009/11/20 01:42:51
Showing 7 changed files
... ...
@@ -1040,7 +1040,8 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
1040 1040
 	      if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
1041 1041
 		{
1042 1042
 		  const in_addr_t dhcp_router = dhcp_extract_router_msg (&ipbuf);
1043
-		  route_list_add_default_gateway (c->c1.route_list, c->c2.es, dhcp_router);
1043
+		  if (dhcp_router)
1044
+		    route_list_add_default_gateway (c->c1.route_list, c->c2.es, dhcp_router);
1044 1045
 		}
1045 1046
 	    }
1046 1047
 	}
... ...
@@ -2780,6 +2780,14 @@ positive_atoi (const char *str)
2780 2780
   return i < 0 ? 0 : i;
2781 2781
 }
2782 2782
 
2783
+static unsigned int
2784
+atou (const char *str)
2785
+{
2786
+  unsigned int val = 0;
2787
+  sscanf (str, "%u", &val);
2788
+  return val;
2789
+}
2790
+
2783 2791
 static inline bool
2784 2792
 space (unsigned char c)
2785 2793
 {
... ...
@@ -5097,6 +5105,19 @@ add_option (struct options *options,
5097 5097
       VERIFY_PERMISSION (OPT_P_IPWIN32);
5098 5098
       options->tuntap_options.dhcp_release = true;
5099 5099
     }
5100
+  else if (streq (p[0], "dhcp-rr") && p[1]) /* standalone method for internal use */
5101
+    {
5102
+      unsigned int adapter_index;
5103
+      VERIFY_PERMISSION (OPT_P_GENERAL);
5104
+      set_debug_level (options->verbosity, SDL_CONSTRAIN);
5105
+      adapter_index = atou (p[1]);
5106
+      sleep (options->tuntap_options.tap_sleep);
5107
+      if (options->tuntap_options.dhcp_pre_release)
5108
+	dhcp_release_by_adapter_index (adapter_index);
5109
+      if (options->tuntap_options.dhcp_renew)
5110
+	dhcp_renew_by_adapter_index (adapter_index);
5111
+      openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
5112
+    }
5100 5113
   else if (streq (p[0], "show-valid-subnets"))
5101 5114
     {
5102 5115
       VERIFY_PERMISSION (OPT_P_GENERAL);
... ...
@@ -3292,59 +3292,73 @@ tap_allow_nonadmin_access (const char *dev_node)
3292 3292
 /*
3293 3293
  * DHCP release/renewal
3294 3294
  */
3295
-
3296 3295
 bool
3297
-dhcp_release (const struct tuntap *tt)
3296
+dhcp_release_by_adapter_index(const DWORD adapter_index)
3298 3297
 {
3299 3298
   struct gc_arena gc = gc_new ();
3300 3299
   bool ret = false;
3301
-  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
3300
+  const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
3301
+
3302
+  if (inter)
3302 3303
     {
3303
-      const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc);
3304
-      if (inter)
3304
+      DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter);
3305
+      if (status == NO_ERROR)
3305 3306
 	{
3306
-	  DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter);
3307
-	  if (status == NO_ERROR)
3308
-	    {
3309
-	      msg (D_TUNTAP_INFO, "TAP: DHCP address released");
3310
-	      ret = true;
3311
-	    }
3312
-	  else
3313
-	    msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)",
3314
-		 strerror_win32 (status, &gc),
3315
-		 (unsigned int)status);
3307
+	  msg (D_TUNTAP_INFO, "TAP: DHCP address released");
3308
+	  ret = true;
3316 3309
 	}
3310
+      else
3311
+	msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)",
3312
+	     strerror_win32 (status, &gc),
3313
+	     (unsigned int)status);
3317 3314
     }
3315
+
3318 3316
   gc_free (&gc);
3319 3317
   return ret;
3320 3318
 }
3321 3319
 
3320
+static bool
3321
+dhcp_release (const struct tuntap *tt)
3322
+{
3323
+  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
3324
+    return dhcp_release_by_adapter_index (tt->adapter_index);
3325
+  else
3326
+    return false;
3327
+}
3328
+
3322 3329
 bool
3323
-dhcp_renew (const struct tuntap *tt)
3330
+dhcp_renew_by_adapter_index (const DWORD adapter_index)
3324 3331
 {
3325 3332
   struct gc_arena gc = gc_new ();
3326 3333
   bool ret = false;
3327
-  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
3334
+  const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
3335
+
3336
+  if (inter)
3328 3337
     {
3329
-      const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc);
3330
-      if (inter)
3338
+      DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter);
3339
+      if (status == NO_ERROR)
3331 3340
 	{
3332
-	  DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter);
3333
-	  if (status == NO_ERROR)
3334
-	    {
3335
-	      msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded");
3336
-	      ret = true;
3337
-	    }
3338
-	  else
3339
-	    msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)",
3340
-		 strerror_win32 (status, &gc),
3341
-		 (unsigned int)status);
3341
+	  msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded");
3342
+	  ret = true;
3342 3343
 	}
3344
+      else
3345
+	msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)",
3346
+	     strerror_win32 (status, &gc),
3347
+	     (unsigned int)status);
3343 3348
     }
3344 3349
   gc_free (&gc);
3345 3350
   return ret;
3346 3351
 }
3347 3352
 
3353
+static bool
3354
+dhcp_renew (const struct tuntap *tt)
3355
+{
3356
+  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
3357
+    return dhcp_renew_by_adapter_index (tt->adapter_index);
3358
+  else
3359
+    return false;
3360
+}
3361
+
3348 3362
 /*
3349 3363
  * netsh functions
3350 3364
  */
... ...
@@ -3788,6 +3802,28 @@ build_dhcp_options_string (struct buffer *buf, const struct tuntap_options *o)
3788 3788
   return !error;
3789 3789
 }
3790 3790
 
3791
+static void
3792
+fork_dhcp_action (struct tuntap *tt)
3793
+{
3794
+  if (tt->options.dhcp_pre_release || tt->options.dhcp_renew)
3795
+    {
3796
+      struct gc_arena gc = gc_new ();
3797
+      struct buffer cmd = alloc_buf_gc (256, &gc);
3798
+      const int verb = 3;
3799
+      const int pre_sleep = 1;
3800
+  
3801
+      buf_printf (&cmd, "openvpn --verb %d --tap-sleep %d", verb, pre_sleep);
3802
+      if (tt->options.dhcp_pre_release)
3803
+	buf_printf (&cmd, " --dhcp-pre-release");
3804
+      if (tt->options.dhcp_renew)
3805
+	buf_printf (&cmd, " --dhcp-renew");
3806
+      buf_printf (&cmd, " --dhcp-rr %u", (unsigned int)tt->adapter_index);
3807
+
3808
+      fork_to_self (BSTR (&cmd));
3809
+      gc_free (&gc);
3810
+    }
3811
+}
3812
+
3791 3813
 void
3792 3814
 open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
3793 3815
 {
... ...
@@ -4152,6 +4188,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
4152 4152
 	if (tt->options.dhcp_renew)
4153 4153
 	  dhcp_renew (tt);
4154 4154
       }
4155
+    else
4156
+      fork_dhcp_action (tt);
4155 4157
 
4156 4158
     if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI)
4157 4159
       {
... ...
@@ -332,8 +332,8 @@ void show_valid_win32_tun_subnets (void);
332 332
 const char *tap_win32_getinfo (const struct tuntap *tt, struct gc_arena *gc);
333 333
 void tun_show_debug (struct tuntap *tt);
334 334
 
335
-bool dhcp_release (const struct tuntap *tt);
336
-bool dhcp_renew (const struct tuntap *tt);
335
+bool dhcp_release_by_adapter_index(const DWORD adapter_index);
336
+bool dhcp_renew_by_adapter_index (const DWORD adapter_index);
337 337
 
338 338
 void tun_standby_init (struct tuntap *tt);
339 339
 bool tun_standby (struct tuntap *tt);
... ...
@@ -1,5 +1,5 @@
1 1
 dnl define the OpenVPN version
2
-define(PRODUCT_VERSION,[2.1_rc21a])
2
+define(PRODUCT_VERSION,[2.1_rc21b])
3 3
 dnl define the TAP version
4 4
 define(PRODUCT_TAP_ID,[tap0901])
5 5
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])
... ...
@@ -1016,6 +1016,51 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
1016 1016
   return ret;
1017 1017
 }
1018 1018
 
1019
+/*
1020
+ * call ourself in another process
1021
+ */
1022
+void
1023
+fork_to_self (const char *cmdline)
1024
+{
1025
+  STARTUPINFO start_info;
1026
+  PROCESS_INFORMATION proc_info;
1027
+  char self_exe[256];
1028
+  char *cl = string_alloc (cmdline, NULL);
1029
+  DWORD status;
1030
+
1031
+  CLEAR (start_info);
1032
+  CLEAR (proc_info);
1033
+  CLEAR (self_exe);
1034
+
1035
+  status = GetModuleFileName (NULL, self_exe, sizeof(self_exe));
1036
+  if (status == 0 || status == sizeof(self_exe))
1037
+    {
1038
+      msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName");
1039
+      goto done;
1040
+    }
1041
+
1042
+  /* fill in STARTUPINFO struct */
1043
+  GetStartupInfo(&start_info);
1044
+  start_info.cb = sizeof(start_info);
1045
+  start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
1046
+  start_info.wShowWindow = SW_HIDE;
1047
+  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1048
+  start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
1049
+
1050
+  if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info))
1051
+    {
1052
+      CloseHandle (proc_info.hThread);
1053
+      CloseHandle (proc_info.hProcess);
1054
+    }
1055
+  else
1056
+    {
1057
+      msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline);
1058
+    }
1059
+
1060
+ done:
1061
+  free (cl);
1062
+}
1063
+
1019 1064
 char *
1020 1065
 get_win_sys_path (void)
1021 1066
 {
... ...
@@ -265,5 +265,8 @@ void set_win_sys_path (const char *newpath, struct env_set *es);
265 265
 void set_win_sys_path_via_env (struct env_set *es);
266 266
 char *get_win_sys_path (void);
267 267
 
268
+/* call self in a subprocess */
269
+void fork_to_self (const char *cmdline);
270
+
268 271
 #endif
269 272
 #endif