]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Fixed a client-side bug that occurred when the "dhcp-pre-release"
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Thu, 19 Nov 2009 16:42:51 +0000 (16:42 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Thu, 19 Nov 2009 16:42:51 +0000 (16:42 +0000)
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

forward.c
options.c
tun.c
tun.h
version.m4
win32.c
win32.h

index 661ac5c0a3685e3feaa42a080c00672cfed7e2dd..207b876b19dab2e0be1ec4d076cff8061f161614 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -1040,7 +1040,8 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
              if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
                {
                  const in_addr_t dhcp_router = dhcp_extract_router_msg (&ipbuf);
-                 route_list_add_default_gateway (c->c1.route_list, c->c2.es, dhcp_router);
+                 if (dhcp_router)
+                   route_list_add_default_gateway (c->c1.route_list, c->c2.es, dhcp_router);
                }
            }
        }
index 183c21a848a235bc023a1c1b728407094d1c27a8..ae4825c60194ca9684cca79682388b1efa2dac78 100644 (file)
--- a/options.c
+++ b/options.c
@@ -2780,6 +2780,14 @@ positive_atoi (const char *str)
   return i < 0 ? 0 : i;
 }
 
+static unsigned int
+atou (const char *str)
+{
+  unsigned int val = 0;
+  sscanf (str, "%u", &val);
+  return val;
+}
+
 static inline bool
 space (unsigned char c)
 {
@@ -5097,6 +5105,19 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_IPWIN32);
       options->tuntap_options.dhcp_release = true;
     }
+  else if (streq (p[0], "dhcp-rr") && p[1]) /* standalone method for internal use */
+    {
+      unsigned int adapter_index;
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      set_debug_level (options->verbosity, SDL_CONSTRAIN);
+      adapter_index = atou (p[1]);
+      sleep (options->tuntap_options.tap_sleep);
+      if (options->tuntap_options.dhcp_pre_release)
+       dhcp_release_by_adapter_index (adapter_index);
+      if (options->tuntap_options.dhcp_renew)
+       dhcp_renew_by_adapter_index (adapter_index);
+      openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
+    }
   else if (streq (p[0], "show-valid-subnets"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
diff --git a/tun.c b/tun.c
index 29278b84f5a590b0ee3932a68811d45a311797bb..d82ac49a56d88575cfabc39900d76a5ac0f30eb3 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -3292,59 +3292,73 @@ tap_allow_nonadmin_access (const char *dev_node)
 /*
  * DHCP release/renewal
  */
-
 bool
-dhcp_release (const struct tuntap *tt)
+dhcp_release_by_adapter_index(const DWORD adapter_index)
 {
   struct gc_arena gc = gc_new ();
   bool ret = false;
-  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
+  const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
+
+  if (inter)
     {
-      const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc);
-      if (inter)
+      DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter);
+      if (status == NO_ERROR)
        {
-         DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter);
-         if (status == NO_ERROR)
-           {
-             msg (D_TUNTAP_INFO, "TAP: DHCP address released");
-             ret = true;
-           }
-         else
-           msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)",
-                strerror_win32 (status, &gc),
-                (unsigned int)status);
+         msg (D_TUNTAP_INFO, "TAP: DHCP address released");
+         ret = true;
        }
+      else
+       msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)",
+            strerror_win32 (status, &gc),
+            (unsigned int)status);
     }
+
   gc_free (&gc);
   return ret;
 }
 
+static bool
+dhcp_release (const struct tuntap *tt)
+{
+  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
+    return dhcp_release_by_adapter_index (tt->adapter_index);
+  else
+    return false;
+}
+
 bool
-dhcp_renew (const struct tuntap *tt)
+dhcp_renew_by_adapter_index (const DWORD adapter_index)
 {
   struct gc_arena gc = gc_new ();
   bool ret = false;
-  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
+  const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc);
+
+  if (inter)
     {
-      const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc);
-      if (inter)
+      DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter);
+      if (status == NO_ERROR)
        {
-         DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter);
-         if (status == NO_ERROR)
-           {
-             msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded");
-             ret = true;
-           }
-         else
-           msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)",
-                strerror_win32 (status, &gc),
-                (unsigned int)status);
+         msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded");
+         ret = true;
        }
+      else
+       msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)",
+            strerror_win32 (status, &gc),
+            (unsigned int)status);
     }
   gc_free (&gc);
   return ret;
 }
 
+static bool
+dhcp_renew (const struct tuntap *tt)
+{
+  if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0)
+    return dhcp_renew_by_adapter_index (tt->adapter_index);
+  else
+    return false;
+}
+
 /*
  * netsh functions
  */
@@ -3788,6 +3802,28 @@ build_dhcp_options_string (struct buffer *buf, const struct tuntap_options *o)
   return !error;
 }
 
+static void
+fork_dhcp_action (struct tuntap *tt)
+{
+  if (tt->options.dhcp_pre_release || tt->options.dhcp_renew)
+    {
+      struct gc_arena gc = gc_new ();
+      struct buffer cmd = alloc_buf_gc (256, &gc);
+      const int verb = 3;
+      const int pre_sleep = 1;
+  
+      buf_printf (&cmd, "openvpn --verb %d --tap-sleep %d", verb, pre_sleep);
+      if (tt->options.dhcp_pre_release)
+       buf_printf (&cmd, " --dhcp-pre-release");
+      if (tt->options.dhcp_renew)
+       buf_printf (&cmd, " --dhcp-renew");
+      buf_printf (&cmd, " --dhcp-rr %u", (unsigned int)tt->adapter_index);
+
+      fork_to_self (BSTR (&cmd));
+      gc_free (&gc);
+    }
+}
+
 void
 open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
 {
@@ -4152,6 +4188,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
        if (tt->options.dhcp_renew)
          dhcp_renew (tt);
       }
+    else
+      fork_dhcp_action (tt);
 
     if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI)
       {
diff --git a/tun.h b/tun.h
index 16598d0ee2c1e382bc84a0ee2f01eedd4d39d47f..210278a28eca508518ab76492c9c06f557677190 100644 (file)
--- a/tun.h
+++ b/tun.h
@@ -332,8 +332,8 @@ void show_valid_win32_tun_subnets (void);
 const char *tap_win32_getinfo (const struct tuntap *tt, struct gc_arena *gc);
 void tun_show_debug (struct tuntap *tt);
 
-bool dhcp_release (const struct tuntap *tt);
-bool dhcp_renew (const struct tuntap *tt);
+bool dhcp_release_by_adapter_index(const DWORD adapter_index);
+bool dhcp_renew_by_adapter_index (const DWORD adapter_index);
 
 void tun_standby_init (struct tuntap *tt);
 bool tun_standby (struct tuntap *tt);
index 6e4ab9f98743ed59a4981120d4c1b448e7c740bd..63fc338da61df69d402926a48454d754925e1390 100644 (file)
@@ -1,5 +1,5 @@
 dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1_rc21a])
+define(PRODUCT_VERSION,[2.1_rc21b])
 dnl define the TAP version
 define(PRODUCT_TAP_ID,[tap0901])
 define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])
diff --git a/win32.c b/win32.c
index 26e81a87877efe5df84579680bc1961be01c5850..eb94eb85762c0b4333f2f00c761bd2a115b7585b 100644 (file)
--- a/win32.c
+++ b/win32.c
@@ -1016,6 +1016,51 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
   return ret;
 }
 
+/*
+ * call ourself in another process
+ */
+void
+fork_to_self (const char *cmdline)
+{
+  STARTUPINFO start_info;
+  PROCESS_INFORMATION proc_info;
+  char self_exe[256];
+  char *cl = string_alloc (cmdline, NULL);
+  DWORD status;
+
+  CLEAR (start_info);
+  CLEAR (proc_info);
+  CLEAR (self_exe);
+
+  status = GetModuleFileName (NULL, self_exe, sizeof(self_exe));
+  if (status == 0 || status == sizeof(self_exe))
+    {
+      msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName");
+      goto done;
+    }
+
+  /* fill in STARTUPINFO struct */
+  GetStartupInfo(&start_info);
+  start_info.cb = sizeof(start_info);
+  start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+  start_info.wShowWindow = SW_HIDE;
+  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+  start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
+
+  if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info))
+    {
+      CloseHandle (proc_info.hThread);
+      CloseHandle (proc_info.hProcess);
+    }
+  else
+    {
+      msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline);
+    }
+
+ done:
+  free (cl);
+}
+
 char *
 get_win_sys_path (void)
 {
diff --git a/win32.h b/win32.h
index 8a79ac3f625d1391dc18a06edc7396b9f2ff29dc..a972a88eba7a6ed28159102d99804a371269027c 100644 (file)
--- a/win32.h
+++ b/win32.h
@@ -265,5 +265,8 @@ void set_win_sys_path (const char *newpath, struct env_set *es);
 void set_win_sys_path_via_env (struct env_set *es);
 char *get_win_sys_path (void);
 
+/* call self in a subprocess */
+void fork_to_self (const char *cmdline);
+
 #endif
 #endif