0
0
mirror of https://github.com/OpenVPN/openvpn.git synced 2024-09-20 12:02:28 +02:00

wintun: implement opening wintun device

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_win
dows.go for
implementation examples.

Signed-off-by: Lev Stipakov <lev@openvpn.net>
Acked-by: Simon Rozman <simon@rozman.si>
Message-Id: <1573148729-27339-4-git-send-email-lstipakov@gmail.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg19029.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
This commit is contained in:
Lev Stipakov 2019-11-07 19:45:25 +02:00 committed by Gert Doering
parent c0658271be
commit e64b4a9e68
4 changed files with 222 additions and 42 deletions

View File

@ -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

View File

@ -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>
@ -303,4 +303,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -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);
if (tt->wintun)
{
const struct device_instance_id_interface* dev_if;
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 (!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,

View File

@ -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);