#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)
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;
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)
return first;
}
-const struct panel_reg *
+static const struct panel_reg *
get_panel_reg(struct gc_arena *gc)
{
LONG status;
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)
{
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;
}
}
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;
/* 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);
}
sizeof(actual_buffer),
tap_reg,
panel_reg,
+ NULL,
&gc);
if (!device_guid)
}
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;
}
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;
{
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);
}
/* 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
/* 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++;
}
}
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);
}
/* get driver MTU */
+ if (!tt->wintun)
{
ULONG mtu;
if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_MTU,
/* 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)
{
/* 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];
}
/* set driver media status to 'connected' */
+ if (!tt->wintun)
{
ULONG status = TRUE;
if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS,