diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 82ecfe8bddc..66177a21fdf 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -37,7 +37,8 @@ typedef enum { msg_flush_neighbors, msg_add_block_dns, msg_del_block_dns, - msg_register_dns + msg_register_dns, + msg_enable_dhcp, } message_type_t; typedef struct { @@ -111,4 +112,9 @@ typedef struct { interface_t iface; } block_dns_message_t; +typedef struct { + message_header_t header; + interface_t iface; +} enable_dhcp_message_t; + #endif /* ifndef OPENVPN_MSG_H_ */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 50f158cbd65..a2d531581ad 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -5203,6 +5203,49 @@ netsh_enable_dhcp(const struct tuntap_options *to, argv_reset(&argv); } +/* Enable dhcp on tap adapter using iservice */ +static bool +service_enable_dhcp(const struct tuntap *tt) +{ + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new(); + HANDLE pipe = tt->options.msg_channel; + + enable_dhcp_message_t dhcp = { + .header = { + msg_enable_dhcp, + sizeof(enable_dhcp_message_t), + 0 + }, + .iface = { .index = tt->adapter_index, .name = "" } + }; + + if (!WriteFile(pipe, &dhcp, sizeof(dhcp), &len, NULL) + || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL)) + { + msg(M_WARN, "Enable_dhcp: could not talk to service: %s [%lu]", + strerror_win32(GetLastError(), &gc), GetLastError()); + goto out; + } + + if (ack.error_number != NO_ERROR) + { + msg(M_NONFATAL, "TUN: enabling dhcp using service failed: %s [status=%u if_index=%d]", + strerror_win32(ack.error_number, &gc), ack.error_number, dhcp.iface.index); + } + else + { + msg(M_INFO, "DHCP enabled on interface %d using service", dhcp.iface.index); + ret = true; + } + +out: + gc_free(&gc); + return ret; +} + /* * Return a TAP name for netsh commands. */ @@ -5683,7 +5726,15 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun */ if (dhcp_status(tt->adapter_index) == DHCP_STATUS_DISABLED) { - netsh_enable_dhcp(&tt->options, tt->actual_name); + /* try using the service if available, else directly execute netsh */ + if (tt->options.msg_channel) + { + service_enable_dhcp(tt); + } + else + { + netsh_enable_dhcp(&tt->options, tt->actual_name); + } } dhcp_masq = true; dhcp_masq_post = true; diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 0f402526f6d..c8733e60992 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -1164,6 +1164,45 @@ HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists) return err; } +static DWORD +HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp) +{ + DWORD err = 0; + DWORD timeout = 5000; /* in milli seconds */ + wchar_t argv0[MAX_PATH]; + + /* Path of netsh */ + swprintf(argv0, _countof(argv0), L"%s\\%s", get_win_sys_path(), L"netsh.exe"); + argv0[_countof(argv0) - 1] = L'\0'; + + /* cmd template: + * netsh interface ipv4 set address name=$if_index source=dhcp + */ + const wchar_t *fmt = L"netsh interface ipv4 set address name=\"%d\" source=dhcp"; + + /* max cmdline length in wchars -- include room for if index: + * 10 chars for 32 bit int in decimal and +1 for NUL + */ + size_t ncmdline = wcslen(fmt) + 10 + 1; + wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t)); + if (!cmdline) + { + err = ERROR_OUTOFMEMORY; + return err; + } + + openvpn_sntprintf(cmdline, ncmdline, fmt, dhcp->iface.index); + + err = ExecCommand(argv0, cmdline, timeout); + + /* Note: This could fail if dhcp is already enabled, so the caller + * may not want to treat errors as FATAL. + */ + + free(cmdline); + return err; +} + static VOID HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { @@ -1175,6 +1214,7 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists flush_neighbors_message_t flush_neighbors; block_dns_message_t block_dns; dns_cfg_message_t dns; + enable_dhcp_message_t dhcp; } msg; ack_message_t ack = { .header = { @@ -1235,6 +1275,13 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists ack.error_number = HandleDNSConfigMessage(&msg.dns, lists); break; + case msg_enable_dhcp: + if (msg.header.size == sizeof(msg.dhcp)) + { + ack.error_number = HandleEnableDHCPMessage(&msg.dhcp); + } + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type);