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)
{
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);
/*
* 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
*/
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)
{
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)
{
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)
{