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

wintun: open device with SetupAPI

With introduction of ring buffers Wintun device
must be opened via SetupAPI.

Signed-off-by: Lev Stipakov <lev@openvpn.net>
This commit is contained in:
Lev Stipakov 2019-07-29 16:41:18 +03:00
parent 4dbcd85e50
commit aeb5ce0ad7
2 changed files with 163 additions and 26 deletions

View File

@ -35,6 +35,12 @@
#include <ws2tcpip.h> // for IPv6
#include <tlhelp32.h> // for impersonating as LocalSystem
#include <SetupAPI.h>
#include <devguid.h>
#include <cfgmgr32.h>
#include <ndisguid.h>
#include <string>
#include <vector>
#include <sstream>
@ -343,12 +349,123 @@ namespace openvpn {
}
};
// given a TAP GUID, form the pathname of the TAP device node
inline std::string tap_path(const TapNameGuidPair& tap, bool wintun)
struct DeviceInstanceIdInterfacePair
{
std::string net_cfg_instance_id;
std::string device_interface_list;
};
class DevInfoSetHelper
{
public:
DevInfoSetHelper()
{
handle = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
}
bool is_valid()
{
return handle != INVALID_HANDLE_VALUE;
}
operator HDEVINFO()
{
return handle;
}
~DevInfoSetHelper()
{
if (is_valid())
{
SetupDiDestroyDeviceInfoList(handle);
}
}
private:
HDEVINFO handle;
};
struct DeviceInstanceIdInterfaceList : public std::vector<DeviceInstanceIdInterfacePair>
{
DeviceInstanceIdInterfaceList()
{
DevInfoSetHelper device_info_set;
if (!device_info_set.is_valid())
return;
for (DWORD i = 0;; ++i)
{
SP_DEVINFO_DATA dev_info_data;
ZeroMemory(&dev_info_data, sizeof(SP_DEVINFO_DATA));
dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
BOOL res = SetupDiEnumDeviceInfo(device_info_set, i, &dev_info_data);
if (!res)
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
else
continue;
}
Win::RegKey regkey;
*regkey.ref() = SetupDiOpenDevRegKey(device_info_set, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
if (!regkey.defined())
continue;
std::string str_net_cfg_instance_id;
DWORD size;
LONG status = RegQueryValueExA(regkey(), "NetCfgInstanceId", NULL, NULL, NULL, &size);
if (status != ERROR_SUCCESS)
continue;
BufferAllocatedType<char, thread_unsafe_refcount> buf_net_cfg_inst_id(size, BufferAllocated::CONSTRUCT_ZERO);
status = RegQueryValueExA(regkey(), "NetCfgInstanceId", NULL, NULL, (LPBYTE)buf_net_cfg_inst_id.data(), &size);
if (status == ERROR_SUCCESS)
{
buf_net_cfg_inst_id.data()[size - 1] = '\0';
str_net_cfg_instance_id = std::string(buf_net_cfg_inst_id.data());
}
else
continue;
res = SetupDiGetDeviceInstanceId(device_info_set, &dev_info_data, NULL, 0, &size);
if (res != FALSE && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
continue;
BufferAllocatedType<char, thread_unsafe_refcount> buf_dev_inst_id(size, BufferAllocated::CONSTRUCT_ZERO);
if (!SetupDiGetDeviceInstanceId(device_info_set, &dev_info_data, buf_dev_inst_id.data(), size, &size))
continue;
buf_dev_inst_id.set_size(size);
ULONG dev_interface_list_size = 0;
CONFIGRET cr = CM_Get_Device_Interface_List_Size(&dev_interface_list_size,
(LPGUID)& GUID_DEVINTERFACE_NET,
buf_dev_inst_id.data(),
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
continue;
BufferAllocatedType<char, thread_unsafe_refcount> buf_dev_iface_list(dev_interface_list_size, BufferAllocated::CONSTRUCT_ZERO);
cr = CM_Get_Device_Interface_List((LPGUID)& GUID_DEVINTERFACE_NET, buf_dev_inst_id.data(),
buf_dev_iface_list.data(),
dev_interface_list_size,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
continue;
DeviceInstanceIdInterfacePair pair;
pair.net_cfg_instance_id = str_net_cfg_instance_id;
pair.device_interface_list = std::string(buf_dev_iface_list.data());
push_back(pair);
}
}
};
// given a TAP GUID, form the pathname of the TAP device node
inline std::string tap_path(const TapNameGuidPair& tap)
{
if (wintun)
return std::string(USERMODEDEVICEDIR) + "WINTUN" + std::to_string(tap.net_luid_index);
else
return std::string(USERMODEDEVICEDIR) + tap.guid + std::string(TAP_WIN_SUFFIX);
}
@ -364,30 +481,50 @@ namespace openvpn {
for (TapNameGuidPairList::const_iterator i = guids.begin(); i != guids.end(); i++)
{
const TapNameGuidPair& tap = *i;
const std::string path = tap_path(tap, wintun);
{
// wintun device can be only opened under LocalSystem account
std::unique_ptr<Win::Impersonate> imp;
std::string path;
if (wintun)
imp.reset(new Win::Impersonate(true));
hand.reset(::CreateFileA(path.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, /* was: FILE_SHARE_READ */
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0));
}
if (hand.defined())
if (wintun)
{
used = tap;
path_opened = path;
break;
DeviceInstanceIdInterfaceList inst_id_interface_list;
for (const auto& inst_id_interface : inst_id_interface_list)
{
if (inst_id_interface.net_cfg_instance_id != tap.guid)
continue;
path = inst_id_interface.device_interface_list;
break;
}
}
else
{
path = tap_path(tap);
}
if (path.length() > 0)
{
// wintun device can be only opened under LocalSystem account
std::unique_ptr<Win::Impersonate> imp;
if (wintun)
imp.reset(new Win::Impersonate(true));
hand.reset(::CreateFileA(path.c_str(),
GENERIC_READ | GENERIC_WRITE,
0, /* was: FILE_SHARE_READ */
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0));
if (hand.defined())
{
used = tap;
path_opened = path;
break;
}
}
}
return hand.release();
}

View File

@ -88,7 +88,7 @@ def build(parms, srcfile, unit_test=False):
options['extra_lib'] += ' mbedtls.lib'
# build it
vc_cmd(parms, r"cl %(extra_defs)s /DNOMINMAX /bigobj /D_CRT_SECURE_NO_WARNINGS /DUSE_ASIO /DASIO_STANDALONE /DASIO_NO_DEPRECATED /I %(asio)s\asio\include /DHAVE_LZ4 /I %(lz4)s %(extra_inc)s -DTAP_WIN_COMPONENT_ID=%(tap_component_id)s /I %(tap)s /I %(ovpn3)s\core /EHsc %(link_static_dynamic_flags)s /W0 %(dbg_rel_flags)s /nologo %(srcfile)s /link /LIBPATH:%(lz4)s%(extra_lib_path)s lz4.lib%(extra_lib)s ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib shell32.lib ole32.lib rpcrt4.lib Wtsapi32.lib" % options, arch=os.environ.get("ARCH"))
vc_cmd(parms, r"cl %(extra_defs)s /DNOMINMAX /bigobj /D_CRT_SECURE_NO_WARNINGS /DUSE_ASIO /DASIO_STANDALONE /DASIO_NO_DEPRECATED /I %(asio)s\asio\include /DHAVE_LZ4 /I %(lz4)s %(extra_inc)s -DTAP_WIN_COMPONENT_ID=%(tap_component_id)s /I %(tap)s /I %(ovpn3)s\core /EHsc %(link_static_dynamic_flags)s /W0 %(dbg_rel_flags)s /nologo %(srcfile)s /link /LIBPATH:%(lz4)s%(extra_lib_path)s lz4.lib%(extra_lib)s ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib shell32.lib ole32.lib rpcrt4.lib Wtsapi32.lib Setupapi.lib Cfgmgr32.lib" % options, arch=os.environ.get("ARCH"))
if __name__ == "__main__":
import sys