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 |