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
... | ... |
@@ -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); |
... | ... |
@@ -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 |