From: Lev Stipakov <l...@openvpn.net> To open wintun device, we cannot use "\\.\Global\Wintun<luid>" 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 <l...@openvpn.net> --- 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 @@ </ClCompile> <ResourceCompile /> <Link> - <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;%(AdditionalDependencies)</AdditionalDependencies> + <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)</AdditionalDependencies> <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <SubSystem>Console</SubSystem> </Link> @@ -117,7 +117,7 @@ </ClCompile> <ResourceCompile /> <Link> - <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;%(AdditionalDependencies)</AdditionalDependencies> + <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)</AdditionalDependencies> <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <SubSystem>Console</SubSystem> </Link> @@ -301,4 +301,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> 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 <winioctl.h> #include <tap-windows.h> +#include <setupapi.h> +#include <cfgmgr32.h> #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); -- 2.7.4 _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel