From patchwork Thu Nov 7 17:45:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Openvpn-devel,v2,1/7] Visual Studio: upgrade project files to VS2019 X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 882 Message-Id: <1573148729-27339-2-git-send-email-lstipakov@gmail.com> To: openvpn-devel@lists.sourceforge.net Cc: Lev Stipakov Date: Thu, 7 Nov 2019 19:45:23 +0200 From: Lev Stipakov List-Id: From: Lev Stipakov Signed-off-by: Lev Stipakov Signed-off-by: Lev Stipakov <lev@openvpn.net>
Signed-off-by: Lev Stipakov <lev@openvpn.net>
Acked-by: Simon Rozman Signed-off-by: Lev Stipakov --- src/compat/compat.vcxproj | 12 ++++++------ src/openvpn/openvpn.vcxproj | 12 ++++++------ src/openvpnmsica/openvpnmsica.vcxproj | 14 +++++++------- src/openvpnserv/openvpnserv.vcxproj | 12 ++++++------ src/tapctl/tapctl.vcxproj | 14 +++++++------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj index 111dacd..e388008 100644 --- a/src/compat/compat.vcxproj +++ b/src/compat/compat.vcxproj @@ -22,30 +22,30 @@ {4B2E2719-E661-45D7-9203-F6F456B22F19} compat Win32Proj - 10.0.17134.0 + 10.0 StaticLibrary MultiByte true - v141 + v142 StaticLibrary MultiByte true - v141 + v142 StaticLibrary MultiByte - v141 + v142 StaticLibrary MultiByte - v141 + v142 @@ -115,4 +115,4 @@ - + \ No newline at end of file diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 4ffff2b..e77f026 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -22,30 +22,30 @@ {29DF226E-4D4E-440F-ADAF-5829CFD4CA94} openvpn Win32Proj - 10.0.17134.0 + 10.0 Application true Unicode - v141 + v142 Application true Unicode - v141 + v142 Application Unicode - v141 + v142 Application Unicode - v141 + v142 @@ -301,4 +301,4 @@ - + \ No newline at end of file diff --git a/src/openvpnmsica/openvpnmsica.vcxproj b/src/openvpnmsica/openvpnmsica.vcxproj index 5f1d699..afa4fae 100644 --- a/src/openvpnmsica/openvpnmsica.vcxproj +++ b/src/openvpnmsica/openvpnmsica.vcxproj @@ -31,32 +31,32 @@ {D41AA9D6-B818-476E-992E-0E16EB86BEE2} Win32Proj openvpnmsica - 10.0.17134.0 + 10.0 DynamicLibrary true - v141 + v142 Unicode true DynamicLibrary true - v141 + v142 Unicode DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode true @@ -64,14 +64,14 @@ DynamicLibrary false - v141 + v142 true Unicode DynamicLibrary false - v141 + v142 true Unicode diff --git a/src/openvpnserv/openvpnserv.vcxproj b/src/openvpnserv/openvpnserv.vcxproj index 7407757..7061b7b 100644 --- a/src/openvpnserv/openvpnserv.vcxproj +++ b/src/openvpnserv/openvpnserv.vcxproj @@ -22,30 +22,30 @@ {9C91EE0B-817D-420A-A1E6-15A5A9D98BAD} openvpnserv Win32Proj - 10.0.17134.0 + 10.0 Application Unicode true - v141 + v142 Application Unicode true - v141 + v142 Application Unicode - v141 + v142 Application Unicode - v141 + v142 @@ -139,4 +139,4 @@ - + \ No newline at end of file diff --git a/src/tapctl/tapctl.vcxproj b/src/tapctl/tapctl.vcxproj index 5c1983b..1d593fc 100644 --- a/src/tapctl/tapctl.vcxproj +++ b/src/tapctl/tapctl.vcxproj @@ -31,32 +31,32 @@ {A06436E7-D576-490D-8BA0-0751D920334A} Win32Proj tapctl - 10.0.17134.0 + 10.0 Application true - v141 + v142 Unicode true Application true - v141 + v142 Unicode Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode true @@ -64,14 +64,14 @@ Application false - v141 + v142 true Unicode Application false - v141 + v142 true Unicode From patchwork Thu Nov 7 17:45:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Openvpn-devel,v2,2/7] wintun: add --windows-driver config option X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 880 Message-Id: <1573148729-27339-3-git-send-email-lstipakov@gmail.com> To: openvpn-devel@lists.sourceforge.net Cc: Lev Stipakov Date: Thu, 7 Nov 2019 19:45:24 +0200 From: Lev Stipakov List-Id: From: Lev Stipakov This allows to specify which tun driver openvpn should use, tap-windows6 (default) or wintun. Note than wintun support will be added in follow-up patches. Signed-off-by: Lev Stipakov --- src/openvpn/init.c | 7 +++++++ src/openvpn/options.c | 37 +++++++++++++++++++++++++++++++++++++ src/openvpn/options.h | 1 + src/openvpn/tun.h | 1 + 4 files changed, 46 insertions(+) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index ae7bd63..c6d4953 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1733,6 +1733,10 @@ do_init_tun(struct context *c) c->c2.es, &c->net_ctx); +#ifdef _WIN32 + c->c1.tuntap->wintun = c->options.wintun; +#endif + init_tun_post(c->c1.tuntap, &c->c2.frame, &c->options.tuntap_options); @@ -1775,6 +1779,9 @@ do_open_tun(struct context *c) /* store (hide) interactive service handle in tuntap_options */ c->c1.tuntap->options.msg_channel = c->options.msg_channel; msg(D_ROUTE, "interactive service msg_channel=%u", (unsigned int) c->options.msg_channel); + + c->c1.tuntap->wintun = c->options.wintun; + #endif /* allocate route list structure */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 1838a69..5c5033e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -747,6 +747,9 @@ static const char usage_message[] = " optional parameter controls the initial state of ex.\n" "--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n" " after TAP adapter is up and routes have been added.\n" + "--windows-driver : Which tun driver to use?\n" + " tap-windows6 (default)\n" + " wintun\n" #ifdef _WIN32 "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n" #endif @@ -851,6 +854,7 @@ init_options(struct options *o, const bool init_gc) o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */ o->route_method = ROUTE_METHOD_ADAPTIVE; o->block_outside_dns = false; + o->wintun = false; #endif o->vlan_accept = VLAN_ONLY_UNTAGGED_OR_PRIORITY; o->vlan_pvid = 1; @@ -2994,6 +2998,12 @@ options_postprocess_mutate_invariant(struct options *options) options->ifconfig_noexec = false; } + /* for wintun kernel doesn't send DHCP requests, so use ipapi to set IP address and netmask */ + if (options->wintun) + { + options->tuntap_options.ip_win32_type = IPW32_SET_IPAPI; + } + remap_redirect_gateway_flags(options); #endif @@ -4039,6 +4049,26 @@ foreign_option(struct options *o, char *argv[], int len, struct env_set *es) } } +#ifdef _WIN32 +bool +parse_windows_driver(const char *str, const int msglevel) +{ + if (streq(str, "tap-windows6")) + { + return false; + } + else if (streq(str, "wintun")) + { + return true; + } + else + { + msg(msglevel, "--windows-driver must be tap-windows6 or wintun"); + return false; + } +} +#endif + /* * parse/print topology coding */ @@ -5281,6 +5311,13 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); options->dev_type = p[1]; } +#ifdef _WIN32 + else if (streq(p[0], "windows-driver") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->wintun = parse_windows_driver(p[1], M_FATAL); + } +#endif else if (streq(p[0], "dev-node") && p[1] && !p[2]) { VERIFY_PERMISSION(OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index ff7a5bb..0a24e5e 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -632,6 +632,7 @@ struct options bool show_net_up; int route_method; bool block_outside_dns; + bool wintun; #endif bool use_peer_id; diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 5a0a933..df935f6 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -175,6 +175,7 @@ struct tuntap * ~0 if undefined */ DWORD adapter_index; + bool wintun; /* true if wintun is used instead of tap-windows6 */ int standby_iter; #else /* ifdef _WIN32 */ int fd; /* file descriptor for TUN/TAP dev */ From patchwork Thu Nov 7 17:45:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Openvpn-devel,v2,3/7] wintun: implement opening wintun device X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 879 Message-Id: <1573148729-27339-4-git-send-email-lstipakov@gmail.com> To: openvpn-devel@lists.sourceforge.net Cc: Lev Stipakov Date: Thu, 7 Nov 2019 19:45:25 +0200 From: Lev Stipakov List-Id: From: Lev Stipakov To open wintun device, we cannot use "\\.\Global\Wintun" path as before. To get device path which we supply to CreateFile, we have to use SetupAPI to: - enumerate network adapters with "wintun" as component id - for each adapter save its guid - open device information set - for each item in set - open corresponding registry key to get net_cfg_instance_id - get symbolic link name of device interface by instance id - path will be symbolic link name of device instance matched with adapter's guid See https://github.com/OpenVPN/openvpn3/blob/master/openvpn/tun/win/tunutil.hpp and https://github.com/WireGuard/wireguard-go/blob/master/tun/wintun/wintun_windows.go for implementation examples. Signed-off-by: Lev Stipakov Acked-by: Simon Rozman Signed-off-by: Lev Stipakov <lev@openvpn.net>

This also has been ACKed and merged,  but two questions that may need some attention:

--- src/openvpn/Makefile.am | 2 +- src/openvpn/openvpn.vcxproj | 6 +- src/openvpn/tun.c | 244 +++++++++++++++++++++++++++++++++++++------- src/openvpn/tun.h | 14 +++ 4 files changed, 223 insertions(+), 43 deletions(-) diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index fbb86ad..a091ffc 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -139,5 +139,5 @@ openvpn_LDADD = \ $(OPTIONAL_DL_LIBS) if WIN32 openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h -openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt +openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt -lsetupapi endif diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index e77f026..9ffef9f 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -91,7 +91,7 @@ - legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies) + legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;setupapi.lib;%(AdditionalDependencies) $(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories) Console @@ -117,7 +117,7 @@ - legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies) + legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;setupapi.lib;%(AdditionalDependencies) $(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories) Console @@ -301,4 +301,4 @@ - \ No newline at end of file + diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index ce23eb6..37bf065 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -58,6 +58,9 @@ #ifdef _WIN32 +const static GUID GUID_DEVCLASS_NET = { 0x4d36e972L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } }; +const static GUID GUID_DEVINTERFACE_NET = { 0xcac88484, 0x7515, 0x4c03, { 0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61 } }; + /* #define SIMULATE_DHCP_FAILED */ /* simulate bad DHCP negotiation */ #define NI_TEST_FIRST (1<<0) @@ -3444,7 +3447,123 @@ tun_finalize( return ret; } -const struct tap_reg * +static const struct device_instance_id_interface * +get_device_instance_id_interface(struct gc_arena* gc) +{ + HDEVINFO dev_info_set; + DWORD err; + struct device_instance_id_interface *first = NULL; + struct device_instance_id_interface *last = NULL; + + dev_info_set = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); + if (dev_info_set == INVALID_HANDLE_VALUE) + { + err = GetLastError(); + msg(M_FATAL, "Error [%u] opening device information set key: %s", (unsigned int)err, strerror_win32(err, gc)); + } + + for (DWORD i = 0;; ++i) + { + SP_DEVINFO_DATA device_info_data; + BOOL res; + HKEY dev_key; + char net_cfg_instance_id_string[] = "NetCfgInstanceId"; + char net_cfg_instance_id[256]; + char device_instance_id[256]; + DWORD len; + DWORD data_type; + LONG status; + ULONG dev_interface_list_size; + CONFIGRET cr; + struct buffer dev_interface_list; + + ZeroMemory(&device_info_data, sizeof(SP_DEVINFO_DATA)); + device_info_data.cbSize = sizeof(SP_DEVINFO_DATA); + res = SetupDiEnumDeviceInfo(dev_info_set, i, &device_info_data); + if (!res) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + { + break; + } + else + { + continue; + } + } + + dev_key = SetupDiOpenDevRegKey(dev_info_set, &device_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE); + if (dev_key == INVALID_HANDLE_VALUE) + { + continue; + } + + len = sizeof(net_cfg_instance_id); + data_type = REG_SZ; + status = RegQueryValueEx(dev_key, + net_cfg_instance_id_string, + NULL, + &data_type, + net_cfg_instance_id, + &len); + if (status != ERROR_SUCCESS) + { + goto next; + } + + len = sizeof(device_instance_id); + res = SetupDiGetDeviceInstanceId(dev_info_set, &device_info_data, device_instance_id, len, &len); + if (!res) + { + goto next; + } + + cr = CM_Get_Device_Interface_List_Size(&dev_interface_list_size, + (LPGUID)& GUID_DEVINTERFACE_NET, + device_instance_id, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + + if (cr != CR_SUCCESS) + { + goto next; + } + + dev_interface_list = alloc_buf_gc(dev_interface_list_size, gc); + cr = CM_Get_Device_Interface_List((LPGUID)& GUID_DEVINTERFACE_NET, device_instance_id, + BPTR(&dev_interface_list), + dev_interface_list_size, + CM_GET_DEVICE_INTERFACE_LIST_PRESENT); + if (cr != CR_SUCCESS) + { + goto next; + } + + struct device_instance_id_interface* dev_if; + ALLOC_OBJ_CLEAR_GC(dev_if, struct device_instance_id_interface, gc); + dev_if->net_cfg_instance_id = string_alloc(net_cfg_instance_id, gc); + dev_if->device_interface_list = string_alloc(BSTR(&dev_interface_list), gc); + + /* link into return list */ + if (!first) + { + first = dev_if; + } + if (last) + { + last->next = dev_if; + } + last = dev_if; + + next: + RegCloseKey(dev_key); + } + + SetupDiDestroyDeviceInfoList(dev_info_set); + + return first; +} + +static const struct tap_reg * get_tap_reg(struct gc_arena *gc) { HKEY adapter_key; @@ -3541,11 +3660,13 @@ get_tap_reg(struct gc_arena *gc) if (status == ERROR_SUCCESS && data_type == REG_SZ) { if (!strcmp(component_id, TAP_WIN_COMPONENT_ID) || - !strcmp(component_id, "root\\" TAP_WIN_COMPONENT_ID)) + !strcmp(component_id, "root\\" TAP_WIN_COMPONENT_ID) || + !strcmp(component_id, WINTUN_COMPONENT_ID)) { struct tap_reg *reg; ALLOC_OBJ_CLEAR_GC(reg, struct tap_reg, gc); reg->guid = string_alloc(net_cfg_instance_id, gc); + reg->wintun = !strcmp(component_id, WINTUN_COMPONENT_ID); /* link into return list */ if (!first) @@ -3569,7 +3690,7 @@ get_tap_reg(struct gc_arena *gc) return first; } -const struct panel_reg * +static const struct panel_reg * get_panel_reg(struct gc_arena *gc) { LONG status; @@ -3776,7 +3897,7 @@ show_tap_win_adapters(int msglev, int warnlev) const struct tap_reg *tap_reg = get_tap_reg(&gc); const struct panel_reg *panel_reg = get_panel_reg(&gc); - msg(msglev, "Available TAP-WIN32 adapters [name, GUID]:"); + msg(msglev, "Available TAP-WIN32 / Wintun adapters [name, GUID, driver]:"); /* loop through each TAP-Windows adapter registry entry */ for (tr = tap_reg; tr != NULL; tr = tr->next) @@ -3788,7 +3909,7 @@ show_tap_win_adapters(int msglev, int warnlev) { if (!strcmp(tr->guid, pr->guid)) { - msg(msglev, "'%s' %s", pr->name, tr->guid); + msg(msglev, "'%s' %s %s", pr->name, tr->guid, tr->wintun ? "wintun" : "tap-windows6"); ++links; } } @@ -3907,6 +4028,7 @@ get_unspecified_device_guid(const int device_number, int actual_name_size, const struct tap_reg *tap_reg_src, const struct panel_reg *panel_reg_src, + bool *wintun, struct gc_arena *gc) { const struct tap_reg *tap_reg = tap_reg_src; @@ -3956,6 +4078,10 @@ get_unspecified_device_guid(const int device_number, /* Save GUID for return value */ ret = alloc_buf_gc(256, gc); buf_printf(&ret, "%s", tap_reg->guid); + if (wintun != NULL) + { + *wintun = tap_reg->wintun; + } return BSTR(&ret); } @@ -4733,6 +4859,7 @@ tap_allow_nonadmin_access(const char *dev_node) sizeof(actual_buffer), tap_reg, panel_reg, + NULL, &gc); if (!device_guid) @@ -5267,9 +5394,9 @@ netsh_get_id(const char *dev_node, struct gc_arena *gc) } else { - guid = get_unspecified_device_guid(0, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, gc); + guid = get_unspecified_device_guid(0, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, NULL, gc); - if (get_unspecified_device_guid(1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Windows adapter */ + if (get_unspecified_device_guid(1, NULL, 0, tap_reg, panel_reg, NULL, gc)) /* ambiguous if more than one TAP-Windows adapter */ { guid = NULL; } @@ -5541,7 +5668,8 @@ void open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { struct gc_arena gc = gc_new(); - char device_path[256]; + char tuntap_device_path[256]; + char *path = NULL; const char *device_guid = NULL; DWORD len; bool dhcp_masq = false; @@ -5571,6 +5699,8 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun { const struct tap_reg *tap_reg = get_tap_reg(&gc); const struct panel_reg *panel_reg = get_panel_reg(&gc); + const struct device_instance_id_interface *device_instance_id_interface = get_device_instance_id_interface(&gc); + char actual_buffer[256]; at_least_one_tap_win(tap_reg); @@ -5586,24 +5716,22 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun } /* Open Windows TAP-Windows adapter */ - openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s", + openvpn_snprintf(tuntap_device_path, sizeof(tuntap_device_path), "%s%s%s", USERMODEDEVICEDIR, device_guid, TAP_WIN_SUFFIX); - tt->hand = CreateFile( - device_path, - GENERIC_READ | GENERIC_WRITE, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); + tt->hand = CreateFile(tuntap_device_path, + GENERIC_READ | GENERIC_WRITE, + 0, /* was: FILE_SHARE_READ */ + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0); if (tt->hand == INVALID_HANDLE_VALUE) { - msg(M_ERR, "CreateFile failed on TAP device: %s", device_path); + msg(M_ERR, "CreateFile failed on TAP device: %s", tuntap_device_path); } } else @@ -5613,43 +5741,78 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun /* Try opening all TAP devices until we find one available */ while (true) { + bool is_picked_device_wintun = false; device_guid = get_unspecified_device_guid(device_number, actual_buffer, sizeof(actual_buffer), tap_reg, panel_reg, + &is_picked_device_wintun, &gc); if (!device_guid) { - msg(M_FATAL, "All TAP-Windows adapters on this system are currently in use."); + msg(M_FATAL, "All %s adapters on this system are currently in use.", tt->wintun ? "wintun" : "TAP - Windows"); } - /* Open Windows TAP-Windows adapter */ - openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); - - tt->hand = CreateFile( - device_path, - GENERIC_READ | GENERIC_WRITE, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); + if (tt->wintun) + { + const struct device_instance_id_interface* dev_if; + + if (!is_picked_device_wintun) + { + /* wintun driver specified but picked adapter is not wintun, proceed to next one */ + goto next; + } + + path = NULL; + for (dev_if = device_instance_id_interface; dev_if != NULL; dev_if = dev_if->next) + { + if (strcmp(dev_if->net_cfg_instance_id, device_guid) == 0) + { + path = (char *)dev_if->device_interface_list; + break; + } + } + if (path == NULL) + { + goto next; + } + } + else + { + if (is_picked_device_wintun) + { + /* tap-windows6 driver specified but picked adapter is wintun, proceed to next one */ + goto next; + } + + /* Open Windows TAP-Windows adapter */ + openvpn_snprintf(tuntap_device_path, sizeof(tuntap_device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAP_WIN_SUFFIX); + path = tuntap_device_path; + } + + tt->hand = CreateFile(path, + GENERIC_READ | GENERIC_WRITE, + 0, /* was: FILE_SHARE_READ */ + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0); if (tt->hand == INVALID_HANDLE_VALUE) { - msg(D_TUNTAP_INFO, "CreateFile failed on TAP device: %s", device_path); + msg(D_TUNTAP_INFO, "CreateFile failed on %s device: %s", tt->wintun ? "wintun" : "TAP", tuntap_device_path); } else { break; } + next: device_number++; } } @@ -5659,10 +5822,11 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun tt->actual_name = string_alloc(actual_buffer, NULL); } - msg(M_INFO, "TAP-WIN32 device [%s] opened: %s", tt->actual_name, device_path); + msg(M_INFO, "%s device [%s] opened: %s", tt->wintun ? "Wintun" : "TAP-WIN32", tt->actual_name, path); tt->adapter_index = get_adapter_index(device_guid); /* get driver version info */ + if (!tt->wintun) { ULONG info[3]; CLEAR(info); @@ -5702,6 +5866,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun } /* get driver MTU */ + if (!tt->wintun) { ULONG mtu; if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_MTU, @@ -5761,7 +5926,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun /* set point-to-point mode if TUN device */ - if (tt->type == DEV_TYPE_TUN) + if ((tt->type == DEV_TYPE_TUN) && !tt->wintun) { if (!tt->did_ifconfig_setup && !tt->did_ifconfig_ipv6_setup) { @@ -5816,7 +5981,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun /* should we tell the TAP-Windows driver to masquerade as a DHCP server as a means * of setting the adapter address? */ - if (dhcp_masq) + if (dhcp_masq && !tt->wintun) { uint32_t ep[4]; @@ -5894,6 +6059,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun } /* set driver media status to 'connected' */ + if (!tt->wintun) { ULONG status = TRUE; if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS, diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index df935f6..19cab7e 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -27,6 +27,8 @@ #ifdef _WIN32 #include #include +#include +#include #endif #include "buffer.h" @@ -38,6 +40,10 @@ #include "misc.h" #include "networking.h" +#ifdef _WIN32 +#define WINTUN_COMPONENT_ID "wintun" +#endif + #if defined(_WIN32) || defined(TARGET_ANDROID) #define TUN_ADAPTER_INDEX_INVALID ((DWORD)-1) @@ -340,6 +346,7 @@ route_order(void) struct tap_reg { const char *guid; + bool wintun; struct tap_reg *next; }; @@ -350,6 +357,13 @@ struct panel_reg struct panel_reg *next; }; +struct device_instance_id_interface +{ + const char *net_cfg_instance_id; + const char *device_interface_list; + struct device_instance_id_interface *next; +}; + int ascii2ipset(const char *name); const char *ipset2ascii(int index); From patchwork Thu Nov 7 17:45:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Openvpn-devel,v2,4/7] wintun: ring buffers based I/O X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 885 Message-Id: <1573148729-27339-5-git-send-email-lstipakov@gmail.com> To: openvpn-devel@lists.sourceforge.net Cc: Lev Stipakov Date: Thu, 7 Nov 2019 19:45:26 +0200 From: Lev Stipakov List-Id: From: Lev Stipakov Implemented according to Wintun documentation and reference client code. Wintun uses ring buffers to communicate between kernel driver and user process. Client allocates send and receive ring buffers, creates events and passes it to kernel driver under LocalSystem privileges. When data is available for read, wintun modifies "tail" pointer of send ring and signals via event. User process reads data from "head" to "tail" and updates "head" pointer. When user process is ready to write, it writes to receive ring, updates "tail" pointer and signals to kernel via event. In openvpn code we add send ring's event to event loop. Before performing io wait, we compare "head" and "tail" pointers of send ring and if they're different, we skip io wait and perform read. This also adds ring buffers support to tcp and udp server code. Signed-off-by: Lev Stipakov --- src/openvpn/forward.c | 42 +++++++++++++++--- src/openvpn/forward.h | 47 +++++++++++++++++++- src/openvpn/mtcp.c | 28 +++++++++++- src/openvpn/mudp.c | 14 ++++++ src/openvpn/options.c | 4 +- src/openvpn/syshead.h | 1 + src/openvpn/tun.c | 45 +++++++++++++++++++ src/openvpn/tun.h | 121 +++++++++++++++++++++++++++++++++++++++++++++++++- src/openvpn/win32.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++ src/openvpn/win32.h | 47 ++++++++++++++++++++ 10 files changed, 458 insertions(+), 11 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 8451706..0be8b6d 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1256,12 +1256,30 @@ read_incoming_tun(struct context *c) perf_push(PERF_READ_IN_TUN); c->c2.buf = c->c2.buffers->read_tun_buf; + #ifdef _WIN32 - read_tun_buffered(c->c1.tuntap, &c->c2.buf); + if (c->c1.tuntap->wintun) + { + read_wintun(c->c1.tuntap, &c->c2.buf); + if (c->c2.buf.len == -1) + { + register_signal(c, SIGHUP, "tun-abort"); + c->persist.restart_sleep_seconds = 1; + msg(M_INFO, "Wintun read error, restarting"); + perf_pop(); + return; + } + } + else + { + read_tun_buffered(c->c1.tuntap, &c->c2.buf); #else - ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame))); - ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); - c->c2.buf.len = read_tun(c->c1.tuntap, BPTR(&c->c2.buf), MAX_RW_SIZE_TUN(&c->c2.frame)); + ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame))); + ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); + c->c2.buf.len = read_tun(c->c1.tuntap, BPTR(&c->c2.buf), MAX_RW_SIZE_TUN(&c->c2.frame)); +#endif +#ifdef _WIN32 + } #endif #ifdef PACKET_TRUNCATION_CHECK @@ -2103,7 +2121,21 @@ io_wait_dowork(struct context *c, const unsigned int flags) * Configure event wait based on socket, tuntap flags. */ socket_set(c->c2.link_socket, c->c2.event_set, socket, (void *)&socket_shift, NULL); - tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)&tun_shift, NULL); + +#ifdef _WIN32 + if (c->c1.tuntap && c->c1.tuntap->wintun) + { + /* add ring buffer event */ + struct rw_handle rw = {.read = c->c1.tuntap->send_tail_moved }; + event_ctl(c->c2.event_set, &rw, EVENT_READ, (void *)&tun_shift); + } + else + { +#endif + tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)&tun_shift, NULL); +#ifdef _WIN32 + } +#endif #ifdef ENABLE_MANAGEMENT if (management) diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 48202c0..6096fa8 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -375,6 +375,19 @@ p2p_iow_flags(const struct context *c) { flags |= IOW_TO_TUN; } +#ifdef _WIN32 + { + struct tuntap *tt = c->c1.tuntap; + if (tt && tt->wintun) + { + if (tt->send_ring->head == tt->send_ring->tail) + { + /* nothing to read from tun -> remove tun read flag set by IOW_READ */ + flags &= ~IOW_READ_TUN; + } + } + } +#endif return flags; } @@ -403,8 +416,38 @@ io_wait(struct context *c, const unsigned int flags) } else { - /* slow path */ - io_wait_dowork(c, flags); +#ifdef _WIN32 + bool skip_iowait = flags & IOW_TO_TUN; + if (flags & IOW_READ_TUN) + { + /* + * don't read from tun if we have pending write to link, + * since every tun read overwrites to_link buffer filled + * by previous tun read + */ + skip_iowait = !(flags & IOW_TO_LINK); + } + if (c->c1.tuntap && c->c1.tuntap->wintun && skip_iowait) + { + unsigned int ret = 0; + if (flags & IOW_TO_TUN) + { + ret |= TUN_WRITE; + } + if (flags & IOW_READ_TUN) + { + ret |= TUN_READ; + } + c->c2.event_set_status = ret; + } + else + { +#endif + /* slow path */ + io_wait_dowork(c, flags); +#ifdef _WIN32 + } +#endif } } diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index abe2059..9ac51c3 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -270,7 +270,33 @@ multi_tcp_wait(const struct context *c, { int status; socket_set_listen_persistent(c->c2.link_socket, mtcp->es, MTCP_SOCKET); - tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); + +#ifdef _WIN32 + if (c->c1.tuntap && c->c1.tuntap->wintun) + { + if (c->c1.tuntap->send_ring->head != c->c1.tuntap->send_ring->tail) + { + /* there is data in wintun ring buffer, read it immediately */ + mtcp->esr[0].arg = MTCP_TUN; + mtcp->esr[0].rwflags = EVENT_READ; + mtcp->n_esr = 1; + return 1; + } + else + { + /* add ring buffer event */ + struct rw_handle rw = { .read = c->c1.tuntap->send_tail_moved }; + event_ctl(mtcp->es, &rw, EVENT_READ, MTCP_TUN); + } + } + else + { +#endif + tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); +#ifdef _WIN32 + } +#endif + #ifdef ENABLE_MANAGEMENT if (management) { diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index b7f061a..7715063 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -279,6 +279,20 @@ p2mp_iow_flags(const struct multi_context *m) flags |= IOW_READ; } +#ifdef _WIN32 + { + struct tuntap* tt = m->top.c1.tuntap; + if (tt && tt->wintun) + { + if (tt->send_ring->head == tt->send_ring->tail) + { + /* nothing to read from tun -> remove tun read flag set by IOW_READ */ + flags &= ~IOW_READ_TUN; + } + } + } +#endif + return flags; } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 5c5033e..1891981 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2998,10 +2998,10 @@ options_postprocess_mutate_invariant(struct options *options) options->ifconfig_noexec = false; } - /* for wintun kernel doesn't send DHCP requests, so use ipapi to set IP address and netmask */ + /* for wintun kernel doesn't send DHCP requests, so use netsh to set IP address and netmask */ if (options->wintun) { - options->tuntap_options.ip_win32_type = IPW32_SET_IPAPI; + options->tuntap_options.ip_win32_type = IPW32_SET_NETSH; } remap_redirect_gateway_flags(options); diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 899aa59..e9accb5 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -39,6 +39,7 @@ #ifdef _WIN32 #include #include +#include #define sleep(x) Sleep((x)*1000) #define random rand #define srandom srand diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 37bf065..b909b89 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -798,6 +798,18 @@ init_tun_post(struct tuntap *tt, tt->rw_handle.read = tt->reads.overlapped.hEvent; tt->rw_handle.write = tt->writes.overlapped.hEvent; tt->adapter_index = TUN_ADAPTER_INDEX_INVALID; + + tt->send_ring = malloc(sizeof(struct tun_ring)); + tt->receive_ring = malloc(sizeof(struct tun_ring)); + if ((tt->send_ring == NULL) || (tt->receive_ring == NULL)) + { + msg(M_FATAL, "Cannot allocate memory for receive ring"); + } + ZeroMemory(tt->send_ring, sizeof(struct tun_ring)); + ZeroMemory(tt->receive_ring, sizeof(struct tun_ring)); + + tt->send_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); + tt->receive_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); #endif } @@ -6207,6 +6219,30 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun tt->ipapi_context_defined = true; } } + + if (tt->wintun) + { + if (tt->options.msg_channel) + { + /* TODO */ + } + else + { + if (!impersonate_as_system()) + { + msg(M_FATAL, "ERROR: Failed to impersonate as SYSTEM, make sure process is running under privileged account"); + } + if (!register_ring_buffers(tt->hand, tt->send_ring, tt->receive_ring, tt->send_tail_moved, tt->receive_tail_moved)) + { + msg(M_FATAL, "ERROR: Failed to register ring buffers: %lu", GetLastError()); + } + if (!RevertToSelf()) + { + msg(M_FATAL, "ERROR: RevertToSelf error: %lu", GetLastError()); + } + } + } + /*netcmd_semaphore_release ();*/ gc_free(&gc); } @@ -6345,6 +6381,15 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) free(tt->actual_name); } + CloseHandle(tt->receive_tail_moved); + CloseHandle(tt->send_tail_moved); + + free(tt->receive_ring); + free(tt->send_ring); + + tt->receive_ring = NULL; + tt->send_ring = NULL; + clear_tuntap(tt); free(tt); gc_free(&gc); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 19cab7e..cbdcce4 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -183,6 +183,11 @@ struct tuntap bool wintun; /* true if wintun is used instead of tap-windows6 */ int standby_iter; + + struct tun_ring *send_ring; + struct tun_ring *receive_ring; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; #else /* ifdef _WIN32 */ int fd; /* file descriptor for TUN/TAP dev */ #endif @@ -479,10 +484,124 @@ read_tun_buffered(struct tuntap *tt, struct buffer *buf) return tun_finalize(tt->hand, &tt->reads, buf); } +static inline ULONG +wintun_ring_packet_align(ULONG size) +{ + return (size + (WINTUN_PACKET_ALIGN - 1)) & ~(WINTUN_PACKET_ALIGN - 1); +} + +static inline ULONG +wintun_ring_wrap(ULONG value) +{ + return value & (WINTUN_RING_CAPACITY - 1); +} + +static inline void +read_wintun(struct tuntap *tt, struct buffer* buf) +{ + struct tun_ring *ring = tt->send_ring; + ULONG head = ring->head; + ULONG tail = ring->tail; + ULONG content_len; + struct TUN_PACKET *packet; + ULONG aligned_packet_size; + + *buf = tt->reads.buf_init; + buf->len = 0; + + if ((head >= WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY)) + { + msg(M_INFO, "Wintun: ring capacity exceeded"); + buf->len = -1; + return; + } + + if (head == tail) + { + /* nothing to read */ + return; + } + + content_len = wintun_ring_wrap(tail - head); + if (content_len < sizeof(struct TUN_PACKET_HEADER)) + { + msg(M_INFO, "Wintun: incomplete packet header in send ring"); + buf->len = -1; + return; + } + + packet = (struct TUN_PACKET *) &ring->data[head]; + if (packet->size > WINTUN_MAX_PACKET_SIZE) + { + msg(M_INFO, "Wintun: packet too big in send ring"); + buf->len = -1; + return; + } + + aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + packet->size); + if (aligned_packet_size > content_len) + { + msg(M_INFO, "Wintun: incomplete packet in send ring"); + buf->len = -1; + return; + } + + buf_write(buf, packet->data, packet->size); + + head = wintun_ring_wrap(head + aligned_packet_size); + ring->head = head; +} + +static inline int +write_wintun(struct tuntap *tt, struct buffer *buf) +{ + struct tun_ring *ring = tt->receive_ring; + ULONG head = ring->head; + ULONG tail = ring->tail; + ULONG aligned_packet_size; + ULONG buf_space; + struct TUN_PACKET *packet; + + if ((head > WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY)) + { + msg(M_INFO, "Wintun: head/tail value is over capacity"); + return -1; + } + + aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + BLEN(buf)); + buf_space = wintun_ring_wrap(head - tail - WINTUN_PACKET_ALIGN); + if (aligned_packet_size > buf_space) + { + msg(M_INFO, "Wintun: ring is full"); + return 0; + } + + /* copy packet size and data into ring */ + packet = (struct TUN_PACKET* )&ring->data[tail]; + packet->size = BLEN(buf); + memcpy(packet->data, BPTR(buf), BLEN(buf)); + + /* move ring tail */ + ring->tail = wintun_ring_wrap(tail + aligned_packet_size); + if (ring->alertable != 0) + { + SetEvent(tt->receive_tail_moved); + } + + return BLEN(buf); +} + static inline int write_tun_buffered(struct tuntap *tt, struct buffer *buf) { - return tun_write_win32(tt, buf); + if (tt->wintun) + { + return write_wintun(tt, buf); + } + else + { + return tun_write_win32(tt, buf); + } } #else /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index eb4c030..e9e0258 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1493,4 +1493,124 @@ send_msg_iservice(HANDLE pipe, const void *data, size_t size, return ret; } +bool +impersonate_as_system() +{ + HANDLE thread_token, process_snapshot, winlogon_process, winlogon_token, duplicated_token; + PROCESSENTRY32 entry; + BOOL ret; + DWORD pid = 0; + TOKEN_PRIVILEGES privileges; + + CLEAR(entry); + CLEAR(privileges); + + entry.dwSize = sizeof(PROCESSENTRY32); + + privileges.PrivilegeCount = 1; + privileges.Privileges->Attributes = SE_PRIVILEGE_ENABLED; + + if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid)) + { + return false; + } + + if (!ImpersonateSelf(SecurityImpersonation)) + { + return false; + } + + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &thread_token)) + { + RevertToSelf(); + return false; + } + if (!AdjustTokenPrivileges(thread_token, FALSE, &privileges, sizeof(privileges), NULL, NULL)) + { + CloseHandle(thread_token); + RevertToSelf(); + return false; + } + CloseHandle(thread_token); + + process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (process_snapshot == INVALID_HANDLE_VALUE) + { + RevertToSelf(); + return false; + } + for (ret = Process32First(process_snapshot, &entry); ret; ret = Process32Next(process_snapshot, &entry)) + { + if (!_stricmp(entry.szExeFile, "winlogon.exe")) + { + pid = entry.th32ProcessID; + break; + } + } + CloseHandle(process_snapshot); + if (!pid) + { + RevertToSelf(); + return false; + } + + winlogon_process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + if (!winlogon_process) + { + RevertToSelf(); + return false; + } + + if (!OpenProcessToken(winlogon_process, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &winlogon_token)) + { + CloseHandle(winlogon_process); + RevertToSelf(); + return false; + } + CloseHandle(winlogon_process); + + if (!DuplicateToken(winlogon_token, SecurityImpersonation, &duplicated_token)) + { + CloseHandle(winlogon_token); + RevertToSelf(); + return false; + } + CloseHandle(winlogon_token); + + if (!SetThreadToken(NULL, duplicated_token)) + { + CloseHandle(duplicated_token); + RevertToSelf(); + return false; + } + CloseHandle(duplicated_token); + + return true; +} + +bool +register_ring_buffers(HANDLE device, + struct tun_ring* send_ring, + struct tun_ring* receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved) +{ + struct tun_register_rings rr; + BOOL res; + + ZeroMemory(&rr, sizeof(rr)); + + rr.send.ring = send_ring; + rr.send.ring_size = sizeof(send_ring->data); + rr.send.tail_moved = send_tail_moved; + + rr.receive.ring = receive_ring; + rr.receive.ring_size = sizeof(receive_ring->data); + rr.receive.tail_moved = receive_tail_moved; + + res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), NULL, 0, NULL, NULL); + + return res == TRUE; +} + #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 4814bbc..007c7d7 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -25,6 +25,8 @@ #ifndef OPENVPN_WIN32_H #define OPENVPN_WIN32_H +#include + #include "mtu.h" #include "openvpn-msg.h" #include "argv.h" @@ -323,5 +325,50 @@ bool send_msg_iservice(HANDLE pipe, const void *data, size_t size, int openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags); +#define WINTUN_RING_CAPACITY 0x800000 +#define WINTUN_RING_TRAILING_BYTES 0x10000 +#define WINTUN_RING_FRAMING_SIZE 12 +#define WINTUN_MAX_PACKET_SIZE 0xffff +#define WINTUN_PACKET_ALIGN 4 + +struct tun_ring +{ + volatile ULONG head; + volatile ULONG tail; + volatile LONG alertable; + UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES + WINTUN_RING_FRAMING_SIZE]; +}; + +struct tun_register_rings +{ + struct + { + ULONG ring_size; + struct tun_ring *ring; + HANDLE tail_moved; + } send, receive; +}; + +struct TUN_PACKET_HEADER +{ + uint32_t size; +}; + +struct TUN_PACKET +{ + uint32_t size; + UCHAR data[WINTUN_MAX_PACKET_SIZE]; +}; + +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +bool impersonate_as_system(); + +bool register_ring_buffers(HANDLE device, + struct tun_ring *send_ring, + struct tun_ring *receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved); + #endif /* ifndef OPENVPN_WIN32_H */ #endif /* ifdef _WIN32 */ From patchwork Thu Nov 7 17:45:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Openvpn-devel,v2,5/7] wintun: interactive service support X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 878 Message-Id: <1573148729-27339-6-git-send-email-lstipakov@gmail.com> To: openvpn-devel@lists.sourceforge.net Cc: Lev Stipakov Date: Thu, 7 Nov 2019 19:45:27 +0200 From: Lev Stipakov List-Id: From: Lev Stipakov Wintun requires ring buffers registration to be performed by privileged process. In order to use openvpn with wintun by non-Administrator, we need to use interactive service and shared memory to register buffers. Openvpn process creates memory mapping object and event for send and receive ring and passes handles to interactive service. There handles are duplicated and memory mapped object is mapped into the address space of service process. Then address of mapped view and event handle is passed to wintun kernel driver. After interactive service preformed registration, openvpn process maps memory mapped object into own address space. Thus mapped views in openvpn and service process represent the same memory region. Signed-off-by: Lev Stipakov Acked-by: Simon Rozman --- include/openvpn-msg.h | 10 ++ src/openvpn/Makefile.am | 2 +- src/openvpn/openvpn.vcxproj | 2 + src/openvpn/openvpn.vcxproj.filters | 8 +- src/openvpn/ring_buffer.c | 54 +++++++++++ src/openvpn/ring_buffer.h | 79 ++++++++++++++++ src/openvpn/tun.c | 89 +++++++++++++++--- src/openvpn/tun.h | 3 + src/openvpn/win32.c | 25 ----- src/openvpn/win32.h | 43 --------- src/openvpnserv/Makefile.am | 3 +- src/openvpnserv/interactive.c | 141 ++++++++++++++++++++++++++-- src/openvpnserv/openvpnserv.vcxproj | 2 + src/openvpnserv/openvpnserv.vcxproj.filters | 6 ++ 14 files changed, 375 insertions(+), 92 deletions(-) create mode 100644 src/openvpn/ring_buffer.c create mode 100644 src/openvpn/ring_buffer.h diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 66177a2..3ed6206 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -39,6 +39,7 @@ typedef enum { msg_del_block_dns, msg_register_dns, msg_enable_dhcp, + msg_register_ring_buffers } message_type_t; typedef struct { @@ -117,4 +118,13 @@ typedef struct { interface_t iface; } enable_dhcp_message_t; +typedef struct { + message_header_t header; + HANDLE device; + HANDLE send_ring_handle; + HANDLE receive_ring_handle; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; +} register_ring_buffers_message_t; + #endif /* ifndef OPENVPN_MSG_H_ */ diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index a091ffc..d1bb99c 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -138,6 +138,6 @@ openvpn_LDADD = \ $(OPTIONAL_SYSTEMD_LIBS) \ $(OPTIONAL_DL_LIBS) if WIN32 -openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h +openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h ring_buffer.c ring_buffer.h openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 -lncrypt -lsetupapi endif diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 9ffef9f..61e634e 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -181,6 +181,7 @@ + @@ -264,6 +265,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index e6068af..8f1b9e0 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -237,6 +237,9 @@ Source Files + + Source Files + @@ -494,10 +497,13 @@ Header Files + + Header Files + Resource Files - \ No newline at end of file + diff --git a/src/openvpn/ring_buffer.c b/src/openvpn/ring_buffer.c new file mode 100644 index 0000000..482e333 --- /dev/null +++ b/src/openvpn/ring_buffer.c @@ -0,0 +1,54 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2019 OpenVPN Inc + * 2019 Lev Stipakov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "ring_buffer.h" + +#ifdef _WIN32 + +bool +register_ring_buffers(HANDLE device, + struct tun_ring *send_ring, + struct tun_ring *receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved) +{ + struct tun_register_rings rr; + BOOL res; + + ZeroMemory(&rr, sizeof(rr)); + + rr.send.ring = send_ring; + rr.send.ring_size = sizeof(send_ring->data); + rr.send.tail_moved = send_tail_moved; + + rr.receive.ring = receive_ring; + rr.receive.ring_size = sizeof(receive_ring->data); + rr.receive.tail_moved = receive_tail_moved; + + res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), NULL, 0, NULL, NULL); + + return res == TRUE; +} + +#endif /* ifdef _WIN32 */ \ No newline at end of file diff --git a/src/openvpn/ring_buffer.h b/src/openvpn/ring_buffer.h new file mode 100644 index 0000000..9951cdf --- /dev/null +++ b/src/openvpn/ring_buffer.h @@ -0,0 +1,79 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2019 OpenVPN Inc + * 2019 Lev Stipakov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef _WIN32 +#ifndef OPENVPN_RING_BUFFER_H +#define OPENVPN_RING_BUFFER_H + +#include +#include + +#include +#include + +#define WINTUN_RING_CAPACITY 0x800000 +#define WINTUN_RING_TRAILING_BYTES 0x10000 +#define WINTUN_RING_FRAMING_SIZE 12 +#define WINTUN_MAX_PACKET_SIZE 0xffff +#define WINTUN_PACKET_ALIGN 4 + +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +struct tun_ring +{ + volatile ULONG head; + volatile ULONG tail; + volatile LONG alertable; + UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES + WINTUN_RING_FRAMING_SIZE]; +}; + +struct tun_register_rings +{ + struct + { + ULONG ring_size; + struct tun_ring* ring; + HANDLE tail_moved; + } send, receive; +}; + +struct TUN_PACKET_HEADER +{ + uint32_t size; +}; + +struct TUN_PACKET +{ + uint32_t size; + UCHAR data[WINTUN_MAX_PACKET_SIZE]; +}; + +bool register_ring_buffers(HANDLE device, + struct tun_ring *send_ring, + struct tun_ring *receive_ring, + HANDLE send_tail_moved, + HANDLE receive_tail_moved); + +#endif /* ifndef OPENVPN_RING_BUFFER_H */ +#endif /* ifdef _WIN32 */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index b909b89..ef1415c 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -799,17 +799,26 @@ init_tun_post(struct tuntap *tt, tt->rw_handle.write = tt->writes.overlapped.hEvent; tt->adapter_index = TUN_ADAPTER_INDEX_INVALID; - tt->send_ring = malloc(sizeof(struct tun_ring)); - tt->receive_ring = malloc(sizeof(struct tun_ring)); - if ((tt->send_ring == NULL) || (tt->receive_ring == NULL)) + if (tt->wintun) { - msg(M_FATAL, "Cannot allocate memory for receive ring"); - } - ZeroMemory(tt->send_ring, sizeof(struct tun_ring)); - ZeroMemory(tt->receive_ring, sizeof(struct tun_ring)); + tt->send_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(struct tun_ring), NULL); + tt->receive_ring_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, sizeof(struct tun_ring), NULL); + + if ((tt->send_ring_handle == NULL) || (tt->receive_ring_handle == NULL)) + { + msg(M_FATAL, "Cannot allocate memory for ring buffer"); + } + + tt->send_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); + tt->receive_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); - tt->send_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); - tt->receive_tail_moved = CreateEvent(NULL, FALSE, FALSE, NULL); + if ((tt->send_tail_moved == NULL) || (tt->receive_tail_moved == NULL)) + { + msg(M_FATAL, "Cannot create events for ring buffer"); + } + } #endif } @@ -5628,6 +5637,44 @@ register_dns_service(const struct tuntap *tt) gc_free(&gc); } +static void +service_register_ring_buffers(const struct tuntap *tt) +{ + HANDLE msg_channel = tt->options.msg_channel; + ack_message_t ack; + struct gc_arena gc = gc_new(); + + register_ring_buffers_message_t msg = { + .header = { + msg_register_ring_buffers, + sizeof(register_ring_buffers_message_t), + 0 + }, + .device = tt->hand, + .send_ring_handle = tt->send_ring_handle, + .receive_ring_handle = tt->receive_ring_handle, + .send_tail_moved = tt->send_tail_moved, + .receive_tail_moved = tt->receive_tail_moved + }; + + if (!send_msg_iservice(msg_channel, &msg, sizeof(msg), &ack, "Register ring buffers")) + { + gc_free(&gc); + return; + } + else if (ack.error_number != NO_ERROR) + { + msg(M_FATAL, "Register ring buffers failed using service: %s [status=0x%x]", + strerror_win32(ack.error_number, &gc), ack.error_number); + } + else + { + msg(M_INFO, "Ring buffers registered via service"); + } + + gc_free(&gc); +} + void fork_register_dns_action(struct tuntap *tt) { @@ -6222,9 +6269,12 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (tt->wintun) { + tt->send_ring = (struct tun_ring *)MapViewOfFile(tt->send_ring_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring)); + tt->receive_ring = (struct tun_ring *)MapViewOfFile(tt->receive_ring_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring)); + if (tt->options.msg_channel) { - /* TODO */ + service_register_ring_buffers(tt); } else { @@ -6381,14 +6431,23 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) free(tt->actual_name); } - CloseHandle(tt->receive_tail_moved); CloseHandle(tt->send_tail_moved); + CloseHandle(tt->receive_tail_moved); - free(tt->receive_ring); - free(tt->send_ring); + if (tt->send_ring != NULL) + { + UnmapViewOfFile(tt->send_ring); + tt->send_ring = NULL; + } + + if (tt->receive_ring != NULL) + { + UnmapViewOfFile(tt->receive_ring); + tt->receive_ring = NULL; + } - tt->receive_ring = NULL; - tt->send_ring = NULL; + CloseHandle(tt->send_ring_handle); + CloseHandle(tt->receive_ring_handle); clear_tuntap(tt); free(tt); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index cbdcce4..2799129 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -39,6 +39,7 @@ #include "proto.h" #include "misc.h" #include "networking.h" +#include "ring_buffer.h" #ifdef _WIN32 #define WINTUN_COMPONENT_ID "wintun" @@ -184,6 +185,8 @@ struct tuntap bool wintun; /* true if wintun is used instead of tap-windows6 */ int standby_iter; + HANDLE send_ring_handle; + HANDLE receive_ring_handle; struct tun_ring *send_ring; struct tun_ring *receive_ring; HANDLE send_tail_moved; diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index e9e0258..b2f2a19 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1588,29 +1588,4 @@ impersonate_as_system() return true; } -bool -register_ring_buffers(HANDLE device, - struct tun_ring* send_ring, - struct tun_ring* receive_ring, - HANDLE send_tail_moved, - HANDLE receive_tail_moved) -{ - struct tun_register_rings rr; - BOOL res; - - ZeroMemory(&rr, sizeof(rr)); - - rr.send.ring = send_ring; - rr.send.ring_size = sizeof(send_ring->data); - rr.send.tail_moved = send_tail_moved; - - rr.receive.ring = receive_ring; - rr.receive.ring_size = sizeof(receive_ring->data); - rr.receive.tail_moved = receive_tail_moved; - - res = DeviceIoControl(device, TUN_IOCTL_REGISTER_RINGS, &rr, sizeof(rr), NULL, 0, NULL, NULL); - - return res == TRUE; -} - #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 007c7d7..4b508c5 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -325,50 +325,7 @@ bool send_msg_iservice(HANDLE pipe, const void *data, size_t size, int openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags); -#define WINTUN_RING_CAPACITY 0x800000 -#define WINTUN_RING_TRAILING_BYTES 0x10000 -#define WINTUN_RING_FRAMING_SIZE 12 -#define WINTUN_MAX_PACKET_SIZE 0xffff -#define WINTUN_PACKET_ALIGN 4 - -struct tun_ring -{ - volatile ULONG head; - volatile ULONG tail; - volatile LONG alertable; - UCHAR data[WINTUN_RING_CAPACITY + WINTUN_RING_TRAILING_BYTES + WINTUN_RING_FRAMING_SIZE]; -}; - -struct tun_register_rings -{ - struct - { - ULONG ring_size; - struct tun_ring *ring; - HANDLE tail_moved; - } send, receive; -}; - -struct TUN_PACKET_HEADER -{ - uint32_t size; -}; - -struct TUN_PACKET -{ - uint32_t size; - UCHAR data[WINTUN_MAX_PACKET_SIZE]; -}; - -#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) - bool impersonate_as_system(); -bool register_ring_buffers(HANDLE device, - struct tun_ring *send_ring, - struct tun_ring *receive_ring, - HANDLE send_tail_moved, - HANDLE receive_tail_moved); - #endif /* ifndef OPENVPN_WIN32_H */ #endif /* ifdef _WIN32 */ diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index bc65070..f8d3319 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -36,4 +36,5 @@ openvpnserv_SOURCES = \ service.c service.h \ validate.c validate.h \ $(top_srcdir)/src/openvpn/block_dns.c $(top_srcdir)/src/openvpn/block_dns.h \ - openvpnserv_resources.rc + openvpnserv_resources.rc \ + $(top_srcdir)/src/openvpn/ring_buffer.c $(top_srcdir)/src/openvpn/ring_buffer.h diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 623c3ff..6e72a14 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -43,13 +43,15 @@ #include "openvpn-msg.h" #include "validate.h" #include "block_dns.h" +#include "ring_buffer.h" #define IO_TIMEOUT 2000 /*ms*/ -#define ERROR_OPENVPN_STARTUP 0x20000000 -#define ERROR_STARTUP_DATA 0x20000001 -#define ERROR_MESSAGE_DATA 0x20000002 -#define ERROR_MESSAGE_TYPE 0x20000003 +#define ERROR_OPENVPN_STARTUP 0x20000000 +#define ERROR_STARTUP_DATA 0x20000001 +#define ERROR_MESSAGE_DATA 0x20000002 +#define ERROR_MESSAGE_TYPE 0x20000003 +#define ERROR_REGISTER_RING_BUFFERS 0x20000004 static SERVICE_STATUS_HANDLE service; static SERVICE_STATUS status = { .dwServiceType = SERVICE_WIN32_SHARE_PROCESS }; @@ -58,6 +60,7 @@ static settings_t settings; static HANDLE rdns_semaphore = NULL; #define RDNS_TIMEOUT 600 /* seconds to wait for the semaphore */ +#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) openvpn_service_t interactive_service = { interactive, @@ -100,6 +103,14 @@ typedef struct { int metric_v6; } block_dns_data_t; +typedef struct { + HANDLE send_ring_handle; + HANDLE receive_ring_handle; + HANDLE send_tail_moved; + HANDLE receive_tail_moved; + HANDLE device; +} ring_buffer_handles_t; + static DWORD AddListItem(list_item_t **pfirst, LPVOID data) @@ -154,6 +165,26 @@ CloseHandleEx(LPHANDLE handle) return INVALID_HANDLE_VALUE; } +static HANDLE +OvpnUnmapViewOfFile(LPHANDLE handle) +{ + if (handle && *handle && *handle != INVALID_HANDLE_VALUE) + { + UnmapViewOfFile(*handle); + *handle = INVALID_HANDLE_VALUE; + } + return INVALID_HANDLE_VALUE; +} + +static void +CloseRingBufferHandles(ring_buffer_handles_t *ring_buffer_handles) +{ + CloseHandleEx(&ring_buffer_handles->device); + CloseHandleEx(&ring_buffer_handles->receive_tail_moved); + CloseHandleEx(&ring_buffer_handles->send_tail_moved); + OvpnUnmapViewOfFile(&ring_buffer_handles->send_ring_handle); + OvpnUnmapViewOfFile(&ring_buffer_handles->receive_ring_handle); +} static HANDLE InitOverlapped(LPOVERLAPPED overlapped) @@ -1198,8 +1229,95 @@ HandleEnableDHCPMessage(const enable_dhcp_message_t *dhcp) return err; } +static DWORD +OvpnDuplicateHandle(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE* new_handle) +{ + DWORD err = ERROR_SUCCESS; + + if (!DuplicateHandle(ovpn_proc, orig_handle, GetCurrentProcess(), new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + err = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("Could not duplicate handle")); + return err; + } + + return err; +} + +static DWORD +DuplicateAndMapRing(HANDLE ovpn_proc, HANDLE orig_handle, HANDLE *new_handle, struct tun_ring **ring) +{ + DWORD err = ERROR_SUCCESS; + + err = OvpnDuplicateHandle(ovpn_proc, orig_handle, new_handle); + if (err != ERROR_SUCCESS) + { + return err; + } + *ring = (struct tun_ring *)MapViewOfFile(*new_handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(struct tun_ring)); + if (*ring == NULL) + { + err = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("Could not map shared memory")); + return err; + } + + return err; +} + +static DWORD +HandleRegisterRingBuffers(const register_ring_buffers_message_t *rrb, HANDLE ovpn_proc, + ring_buffer_handles_t *ring_buffer_handles) +{ + DWORD err = 0; + struct tun_ring *send_ring; + struct tun_ring *receive_ring; + + CloseRingBufferHandles(ring_buffer_handles); + + err = OvpnDuplicateHandle(ovpn_proc, rrb->device, &ring_buffer_handles->device); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = DuplicateAndMapRing(ovpn_proc, rrb->send_ring_handle, &ring_buffer_handles->send_ring_handle, &send_ring); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = DuplicateAndMapRing(ovpn_proc, rrb->receive_ring_handle, &ring_buffer_handles->receive_ring_handle, &receive_ring); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = OvpnDuplicateHandle(ovpn_proc, rrb->send_tail_moved, &ring_buffer_handles->send_tail_moved); + if (err != ERROR_SUCCESS) + { + return err; + } + + err = OvpnDuplicateHandle(ovpn_proc, rrb->receive_tail_moved, &ring_buffer_handles->receive_tail_moved); + if (err != ERROR_SUCCESS) + { + return err; + } + + if (!register_ring_buffers(ring_buffer_handles->device, send_ring, receive_ring, + ring_buffer_handles->send_tail_moved, ring_buffer_handles->receive_tail_moved)) + { + MsgToEventLog(M_SYSERR, TEXT("Could not register ring buffers")); + err = ERROR_REGISTER_RING_BUFFERS; + } + + return err; +} + static VOID -HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) +HandleMessage(HANDLE pipe, HANDLE ovpn_proc, ring_buffer_handles_t *ring_buffer_handles, + DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { DWORD read; union { @@ -1210,6 +1328,7 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists block_dns_message_t block_dns; dns_cfg_message_t dns; enable_dhcp_message_t dhcp; + register_ring_buffers_message_t rrb; } msg; ack_message_t ack = { .header = { @@ -1277,6 +1396,13 @@ HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists } break; + case msg_register_ring_buffers: + if (msg.header.size == sizeof(msg.rrb)) + { + ack.error_number = HandleRegisterRingBuffers(&msg.rrb, ovpn_proc, ring_buffer_handles); + } + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); @@ -1360,6 +1486,7 @@ RunOpenvpn(LPVOID p) WCHAR *cmdline = NULL; size_t cmdline_size; undo_lists_t undo_lists; + ring_buffer_handles_t ring_buffer_handles; SECURITY_ATTRIBUTES inheritable = { .nLength = sizeof(inheritable), @@ -1380,6 +1507,7 @@ RunOpenvpn(LPVOID p) ZeroMemory(&startup_info, sizeof(startup_info)); ZeroMemory(&undo_lists, sizeof(undo_lists)); ZeroMemory(&proc_info, sizeof(proc_info)); + ZeroMemory(&ring_buffer_handles, sizeof(ring_buffer_handles)); if (!GetStartupData(pipe, &sud)) { @@ -1611,7 +1739,7 @@ RunOpenvpn(LPVOID p) break; } - HandleMessage(ovpn_pipe, bytes, 1, &exit_event, &undo_lists); + HandleMessage(ovpn_pipe, proc_info.hProcess, &ring_buffer_handles, bytes, 1, &exit_event, &undo_lists); } WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT); @@ -1638,6 +1766,7 @@ out: free(cmdline); DestroyEnvironmentBlock(user_env); FreeStartupData(&sud); + CloseRingBufferHandles(&ring_buffer_handles); CloseHandleEx(&proc_info.hProcess); CloseHandleEx(&proc_info.hThread); CloseHandleEx(&stdin_read); diff --git a/src/openvpnserv/openvpnserv.vcxproj b/src/openvpnserv/openvpnserv.vcxproj index 7061b7b..c5a34b8 100644 --- a/src/openvpnserv/openvpnserv.vcxproj +++ b/src/openvpnserv/openvpnserv.vcxproj @@ -115,6 +115,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/src/openvpnserv/openvpnserv.vcxproj.filters b/src/openvpnserv/openvpnserv.vcxproj.filters index 3ce9bb2..3cb14ef 100644 --- a/src/openvpnserv/openvpnserv.vcxproj.filters +++ b/src/openvpnserv/openvpnserv.vcxproj.filters @@ -33,6 +33,9 @@ Source Files + + Source Files + @@ -44,6 +47,9 @@ Header Files + + Header Files + From patchwork Thu Nov 7 17:45:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Openvpn-devel,v2,6/7] wintun: set adapter properties via interactive service X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 883 Message-Id: <1573148729-27339-7-git-send-email-lstipakov@gmail.com> To: openvpn-devel@lists.sourceforge.net Cc: Lev Stipakov Date: Thu, 7 Nov 2019 19:45:28 +0200 From: Lev Stipakov List-Id: From: Lev Stipakov Since Wintun doesn't do DHCP, use interactive service calls to set up adapter properties. This also fixes bug in previously unused IPv4 code of do_address_service(): - ipv4 address must be in network byte order - prefix length cannot be hardcoded /32 but must be calculated from netmask Signed-off-by: Lev Stipakov Acked-by: Simon Rozman --- src/openvpn/route.c | 2 +- src/openvpn/route.h | 3 ++- src/openvpn/tun.c | 77 +++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 97e90e5..cc6d551 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -3019,7 +3019,7 @@ out: return ret; } -static bool +bool do_route_ipv4_service(const bool add, const struct route_ipv4 *r, const struct tuntap *tt) { DWORD if_index = windows_route_find_if_index(r, tt); diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 2e68091..27b652c 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -321,7 +321,8 @@ void setenv_routes(struct env_set *es, const struct route_list *rl); void setenv_routes_ipv6(struct env_set *es, const struct route_ipv6_list *rl6); - +bool do_route_ipv4_service(const bool add, const struct route_ipv4 *r, + const struct tuntap *tt); bool is_special_addr(const char *addr_str); diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index ef1415c..c3ea4a8 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -109,8 +109,8 @@ do_address_service(const bool add, const short family, const struct tuntap *tt) if (addr.family == AF_INET) { - addr.address.ipv4.s_addr = tt->local; - addr.prefix_len = 32; + addr.address.ipv4.s_addr = htonl(tt->local); + addr.prefix_len = netmask_to_netbits2(tt->adapter_netmask); } else { @@ -139,13 +139,17 @@ out: } static bool -do_dns6_service(bool add, const struct tuntap *tt) +do_dns_service(bool add, const short family, const struct tuntap *tt) { bool ret = false; ack_message_t ack; struct gc_arena gc = gc_new(); HANDLE pipe = tt->options.msg_channel; - int addr_len = add ? tt->options.dns6_len : 0; + int len = family == AF_INET6 ? tt->options.dns6_len : tt->options.dns_len; + int addr_len = add ? len : 0; + char ip_proto_name[5]; + + strcpy(ip_proto_name, family == AF_INET6 ? "IPv6" : "IPv4"); if (addr_len == 0 && add) /* no addresses to add */ { @@ -160,7 +164,7 @@ do_dns6_service(bool add, const struct tuntap *tt) }, .iface = { .index = tt->adapter_index, .name = "" }, .domains = "", - .family = AF_INET6, + .family = family, .addr_len = addr_len }; @@ -172,17 +176,24 @@ do_dns6_service(bool add, const struct tuntap *tt) { addr_len = _countof(dns.addr); dns.addr_len = addr_len; - msg(M_WARN, "Number of IPv6 DNS addresses sent to service truncated to %d", - addr_len); + msg(M_WARN, "Number of %s DNS addresses sent to service truncated to %d", + ip_proto_name, addr_len); } for (int i = 0; i < addr_len; ++i) { - dns.addr[i].ipv6 = tt->options.dns6[i]; + if (family == AF_INET6) + { + dns.addr[i].ipv6 = tt->options.dns6[i]; + } + else + { + dns.addr[i].ipv4.s_addr = htonl(tt->options.dns[i]); + } } - msg(D_LOW, "%s IPv6 dns servers on '%s' (if_index = %d) using service", - (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index); + msg(D_LOW, "%s %s dns servers on '%s' (if_index = %d) using service", + (add ? "Setting" : "Deleting"), ip_proto_name, dns.iface.name, dns.iface.index); if (!send_msg_iservice(pipe, &dns, sizeof(dns), &ack, "TUN")) { @@ -191,13 +202,13 @@ do_dns6_service(bool add, const struct tuntap *tt) if (ack.error_number != NO_ERROR) { - msg(M_WARN, "TUN: %s IPv6 dns failed using service: %s [status=%u if_name=%s]", - (add ? "adding" : "deleting"), strerror_win32(ack.error_number, &gc), + msg(M_WARN, "TUN: %s %s dns failed using service: %s [status=%u if_name=%s]", + (add ? "adding" : "deleting"), ip_proto_name, strerror_win32(ack.error_number, &gc), ack.error_number, dns.iface.name); goto out; } - msg(M_INFO, "IPv6 dns servers %s using service", (add ? "set" : "deleted")); + msg(M_INFO, "%s dns servers %s using service", ip_proto_name, (add ? "set" : "deleted")); ret = true; out: @@ -830,7 +841,7 @@ init_tun_post(struct tuntap *tt, * an extra call to "route add..." * -> helper function to simplify code below */ -void +static void add_route_connected_v6_net(struct tuntap *tt, const struct env_set *es) { @@ -862,6 +873,21 @@ delete_route_connected_v6_net(struct tuntap *tt, } #endif /* if defined(_WIN32) || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) */ +#if defined(_WIN32) +void +do_route_ipv4_service_tun(bool add, const struct tuntap *tt) +{ + struct route_ipv4 r4; + CLEAR(r4); + r4.network = tt->local & tt->remote_netmask; + r4.netmask = tt->remote_netmask; + r4.gateway = tt->local; + r4.metric = 0; /* connected route */ + r4.flags = RT_DEFINED | RT_METRIC_DEFINED; + do_route_ipv4_service(add, &r4, tt); +} +#endif + #if defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) /* we can't use true subnet mode on tun on all platforms, as that @@ -1018,7 +1044,7 @@ do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu, else if (tt->options.msg_channel) { do_address_service(true, AF_INET6, tt); - do_dns6_service(true, tt); + do_dns_service(true, AF_INET6, tt); } else { @@ -1400,8 +1426,16 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, { ASSERT(ifname != NULL); - switch (tt->options.ip_win32_type) + if (tt->options.msg_channel && tt->wintun) + { + do_address_service(true, AF_INET, tt); + do_route_ipv4_service_tun(true, tt); + do_dns_service(true, AF_INET, tt); + } + else { + switch (tt->options.ip_win32_type) + { case IPW32_SET_MANUAL: msg(M_INFO, "******** NOTE: Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)", @@ -1414,6 +1448,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, tt->adapter_netmask, NI_IP_NETMASK|NI_OPTIONS); break; + } } } @@ -6140,6 +6175,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun } /* possibly use IP Helper API to set IP address on adapter */ + if (!tt->wintun) { const DWORD index = tt->adapter_index; @@ -6350,7 +6386,7 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) do_address_service(false, AF_INET6, tt); if (tt->options.dns6_len > 0) { - do_dns6_service(false, tt); + do_dns_service(false, AF_INET6, tt); } } else @@ -6387,6 +6423,13 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) } } #if 1 + if (tt->wintun && tt->options.msg_channel) + { + do_route_ipv4_service_tun(false, tt); + do_address_service(false, AF_INET, tt); + do_dns_service(false, AF_INET, tt); + } + else if (tt->ipapi_context_defined) { DWORD status; From patchwork Thu Nov 7 17:45:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [Openvpn-devel,v2,7/7] wintun: clear adapter settings on tun close X-Patchwork-Submitter: Lev Stipakov X-Patchwork-Id: 884 Message-Id: <1573148729-27339-8-git-send-email-lstipakov@gmail.com> To: openvpn-devel@lists.sourceforge.net Cc: Lev Stipakov Date: Thu, 7 Nov 2019 19:45:29 +0200 From: Lev Stipakov List-Id: From: Lev Stipakov With tap-windows6 we clear adapter settings with DHCP, but since wintun doesn't do DHCP we do it with netsh. Signed-off-by: Lev Stipakov --- src/openvpn/tun.c | 79 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index c3ea4a8..9bdd707 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -6369,6 +6369,50 @@ tun_show_debug(struct tuntap *tt) } } +static void +netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc) +{ + const char* ifconfig_ip_local; + struct argv argv = argv_new(); + + /* "store=active" is needed in Windows 8(.1) to delete the + * address we added (pointed out by Cedric Tabary). + */ + + /* netsh interface ipvX delete address \"%s\" %s */ + if (ipv6) + { + ifconfig_ip_local = print_in6_addr(tt->local_ipv6, 0, gc); + } + else + { + ifconfig_ip_local = print_in_addr_t(tt->local, 0, gc); + } + argv_printf(&argv, + "%s%sc interface %s delete address %s %s store=active", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + ipv6 ? "ipv6" : "ipv4", + tt->actual_name, + ifconfig_ip_local); + + netsh_command(&argv, 1, M_WARN); + + /* delete ipvX dns servers if any were set */ + int len = ipv6 ? tt->options.dns6_len : tt->options.dns_len; + if (len > 0) + { + argv_printf(&argv, + "%s%sc interface %s delete dns %s all", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + ipv6 ? "ipv6" : "ipv4", + tt->actual_name); + netsh_command(&argv, 1, M_WARN); + } + argv_reset(&argv); +} + void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) { @@ -6391,35 +6435,7 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) } else { - const char *ifconfig_ipv6_local; - struct argv argv = argv_new(); - - /* "store=active" is needed in Windows 8(.1) to delete the - * address we added (pointed out by Cedric Tabary). - */ - - /* netsh interface ipv6 delete address \"%s\" %s */ - ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc); - argv_printf(&argv, - "%s%sc interface ipv6 delete address %s %s store=active", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - tt->actual_name, - ifconfig_ipv6_local); - - netsh_command(&argv, 1, M_WARN); - - /* delete ipv6 dns servers if any were set */ - if (tt->options.dns6_len > 0) - { - argv_printf(&argv, - "%s%sc interface ipv6 delete dns %s all", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - tt->actual_name); - netsh_command(&argv, 1, M_WARN); - } - argv_reset(&argv); + netsh_delete_address_dns(tt, true, &gc); } } #if 1 @@ -6441,6 +6457,11 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) strerror_win32(status, &gc)); } } + else + if (tt->wintun) + { + netsh_delete_address_dns(tt, false, &gc); + } #endif dhcp_release(tt);