summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2009-11-19 16:42:51 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2009-11-19 16:42:51 +0000
commit5c30df12ae98c0289cdfb2a24aefba2a9d2cc52e (patch)
treeb900adb66ca9a3c7d57fb89fe647f6772df027f9
parentb9437c64ddd36c7c13508977e1a348d0e45d3187 (diff)
downloadopenvpn-5c30df12ae98c0289cdfb2a24aefba2a9d2cc52e.tar.gz
openvpn-5c30df12ae98c0289cdfb2a24aefba2a9d2cc52e.tar.xz
openvpn-5c30df12ae98c0289cdfb2a24aefba2a9d2cc52e.zip
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
-rw-r--r--forward.c3
-rw-r--r--options.c21
-rw-r--r--tun.c96
-rw-r--r--tun.h4
-rw-r--r--version.m42
-rw-r--r--win32.c45
-rw-r--r--win32.h3
7 files changed, 141 insertions, 33 deletions
diff --git a/forward.c b/forward.c
index 661ac5c..207b876 100644
--- 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);
}
}
}
diff --git a/options.c b/options.c
index 183c21a..ae4825c 100644
--- 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 29278b8..d82ac49 100644
--- 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 16598d0..210278a 100644
--- 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);
diff --git a/version.m4 b/version.m4
index 6e4ab9f..63fc338 100644
--- a/version.m4
+++ b/version.m4
@@ -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 26e81a8..eb94eb8 100644
--- 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 8a79ac3..a972a88 100644
--- 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