diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-01-31 12:55:33 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-02-03 09:13:29 +0100 |
| commit | 2860aed09fce784bc0e6719319dae78cb4d5cafc (patch) | |
| tree | 88bac97b810154ba570a29c9a7f0e1ac74abff5e /windows/driverlogic/src/driverlogic.cpp | |
| parent | 8d4b57def51b2fc63328a6ab1619fa1f78810a4b (diff) | |
| download | mullvadvpn-2860aed09fce784bc0e6719319dae78cb4d5cafc.tar.xz mullvadvpn-2860aed09fce784bc0e6719319dae78cb4d5cafc.zip | |
Migrate functions from driverlogic plugin to the driverlogic process
Diffstat (limited to 'windows/driverlogic/src/driverlogic.cpp')
| -rw-r--r-- | windows/driverlogic/src/driverlogic.cpp | 405 |
1 files changed, 394 insertions, 11 deletions
diff --git a/windows/driverlogic/src/driverlogic.cpp b/windows/driverlogic/src/driverlogic.cpp index ce7ce55d75..1a77aaf15b 100644 --- a/windows/driverlogic/src/driverlogic.cpp +++ b/windows/driverlogic/src/driverlogic.cpp @@ -1,24 +1,72 @@ #include "stdafx.h" #include <iostream> +#include <sstream> +#include <string> #include <optional> +#include <set> #include <libcommon/error.h> +#include <libcommon/guid.h> #include <libcommon/memory.h> +#include <libcommon/network/nci.h> +#include <libcommon/string.h> #include <setupapi.h> +#include <initguid.h> #include <devguid.h> +#include <devpkey.h> #include <newdev.h> namespace { -const wchar_t TAP_HARDWARE_ID[] = L"tap0901"; +constexpr wchar_t DEPRECATED_TAP_HARDWARE_ID[] = L"tap0901"; +constexpr wchar_t TAP_HARDWARE_ID[] = L"tapmullvad0901"; +constexpr wchar_t TAP_BASE_ALIAS[] = L"Mullvad"; enum ReturnCodes { - MULLVAD_GENERAL_ERROR, - MULLVAD_SUCCESS + GENERAL_ERROR, + GENERAL_SUCCESS, + DELETE_NO_ADAPTERS_REMAIN, + DELETE_SOME_ADAPTERS_REMAIN }; +struct NetworkAdapter +{ + std::wstring guid; + std::wstring name; + std::wstring alias; + std::wstring deviceInstanceId; + + NetworkAdapter(std::wstring guid, std::wstring name, std::wstring alias, std::wstring deviceInstanceId) + : guid(guid) + , name(name) + , alias(alias) + , deviceInstanceId(deviceInstanceId) + { + } + + bool operator<(const NetworkAdapter &rhs) const + { + return _wcsicmp(deviceInstanceId.c_str(), rhs.deviceInstanceId.c_str()) < 0; + } +}; + +void LogAdapters(const std::wstring &description, const std::set<NetworkAdapter> &adapters) +{ + std::wcout << description << std::endl; + + for (const auto &adapter : adapters) + { + std::wcout << L" Adapter\n" + << L" Guid: " << adapter.guid << L'\n' + << L" Name: " << adapter.name << L'\n' + << L" Alias: " << adapter.alias << L'\n' + << L" Alias: " << adapter.deviceInstanceId + << std::endl; + } +} + std::optional<std::wstring> GetDeviceRegistryStringProperty( HDEVINFO devInfo, SP_DEVINFO_DATA *devInfoData, @@ -137,6 +185,161 @@ std::wstring GetDeviceStringProperty( return buffer.data(); } +std::wstring GetDeviceInstanceId( + HDEVINFO devInfo, + SP_DEVINFO_DATA *devInfoData +) +{ + DWORD requiredSize = 0; + + SetupDiGetDeviceInstanceIdW( + devInfo, + devInfoData, + nullptr, + 0, + &requiredSize + ); + + std::vector<wchar_t> deviceInstanceId(1 + requiredSize); + + const auto status = SetupDiGetDeviceInstanceIdW( + devInfo, + devInfoData, + &deviceInstanceId[0], + requiredSize, + nullptr + ); + + if (FALSE == status) + { + THROW_WINDOWS_ERROR(GetLastError(), "SetupDiGetDeviceInstanceIdW"); + } + + return deviceInstanceId.data(); +} + +std::wstring GetNetCfgInstanceId(HDEVINFO devInfo, const SP_DEVINFO_DATA &devInfoData) +{ + HKEY hNet = SetupDiOpenDevRegKey( + devInfo, + const_cast<SP_DEVINFO_DATA *>(&devInfoData), + DICS_FLAG_GLOBAL, + 0, + DIREG_DRV, + KEY_READ + ); + + if (hNet == INVALID_HANDLE_VALUE) + { + THROW_WINDOWS_ERROR(GetLastError(), "SetupDiOpenDevRegKey"); + } + + std::vector<wchar_t> instanceId(MAX_PATH + 1); + DWORD strSize = static_cast<DWORD>(instanceId.size() * sizeof(wchar_t)); + + const auto status = RegGetValueW( + hNet, + nullptr, + L"NetCfgInstanceId", + RRF_RT_REG_SZ, + nullptr, + instanceId.data(), + &strSize + ); + + RegCloseKey(hNet); + + if (ERROR_SUCCESS != status) + { + THROW_WINDOWS_ERROR(status, "RegGetValueW"); + } + + return instanceId.data(); +} + +std::set<NetworkAdapter> GetTapAdapters(const std::wstring &tapHardwareId) +{ + std::set<NetworkAdapter> adapters; + + HDEVINFO devInfo = SetupDiGetClassDevs( + &GUID_DEVCLASS_NET, + nullptr, + nullptr, + DIGCF_PRESENT + ); + + if (INVALID_HANDLE_VALUE == devInfo) + { + THROW_WINDOWS_ERROR(GetLastError(), "SetupDiGetClassDevs() failed"); + } + + common::memory::ScopeDestructor scopeDestructor; + scopeDestructor += [devInfo]() + { + SetupDiDestroyDeviceInfoList(devInfo); + }; + + common::network::Nci nci; + + for (int memberIndex = 0; ; memberIndex++) + { + SP_DEVINFO_DATA devInfoData = { 0 }; + devInfoData.cbSize = sizeof(devInfoData); + + if (FALSE == SetupDiEnumDeviceInfo(devInfo, memberIndex, &devInfoData)) + { + const auto lastError = GetLastError(); + + if (ERROR_NO_MORE_ITEMS == lastError) + { + // Done + break; + } + + THROW_WINDOWS_ERROR(lastError, "SetupDiEnumDeviceInfo() failed while enumerating network adapters"); + } + + try + { + // + // Check whether this is a TAP adapter + // + + const auto hardwareId = GetDeviceRegistryStringProperty(devInfo, &devInfoData, SPDRP_HARDWAREID); + if (!hardwareId.has_value() + || wcscmp(hardwareId.value().c_str(), tapHardwareId.c_str()) != 0) + { + continue; + } + + // + // Construct NetworkAdapter + // + + const std::wstring guid = GetNetCfgInstanceId(devInfo, devInfoData); + GUID guidObj = common::Guid::FromString(guid); + + adapters.emplace(NetworkAdapter( + guid, + GetDeviceStringProperty(devInfo, &devInfoData, &DEVPKEY_Device_DriverDesc), + nci.getConnectionName(guidObj), + GetDeviceInstanceId(devInfo, &devInfoData) + )); + } + catch (const std::exception & e) + { + // + // Log exception and skip this adapter + // + + std::cerr << "Skipping TAP adapter due to exception caught while iterating: " + << e.what(); + } + } + + return adapters; +} + void CreateTapDevice() { GUID classGuid = GUID_DEVCLASS_NET; @@ -242,6 +445,172 @@ ATTEMPT_UPDATE: << rebootRequired << std::endl; } +std::optional<NetworkAdapter> FindMullvadAdapter(const std::set<NetworkAdapter> &tapAdapters) +{ + if (tapAdapters.empty()) + { + return std::nullopt; + } + + // + // Look for TAP adapter with alias "Mullvad". + // + + auto findByAlias = [](const std::set<NetworkAdapter> &adapters, const std::wstring &alias) + { + const auto it = std::find_if(adapters.begin(), adapters.end(), [&alias](const NetworkAdapter &candidate) + { + return 0 == _wcsicmp(candidate.alias.c_str(), alias.c_str()); + }); + + return it; + }; + + const auto firstMullvadAdapter = findByAlias(tapAdapters, TAP_BASE_ALIAS); + + if (tapAdapters.end() != firstMullvadAdapter) + { + return { *firstMullvadAdapter }; + } + + // + // Look for TAP adapter with alias "Mullvad-1", "Mullvad-2", etc. + // + + for (auto i = 0; i < 10; ++i) + { + std::wstringstream ss; + + ss << TAP_BASE_ALIAS << L"-" << i; + + const auto alias = ss.str(); + + const auto mullvadAdapter = findByAlias(tapAdapters, alias); + + if (tapAdapters.end() != mullvadAdapter) + { + return { *mullvadAdapter }; + } + } + + return std::nullopt; +} + +NetworkAdapter FindBrandedTap() +{ + std::set<NetworkAdapter> added = GetTapAdapters(TAP_HARDWARE_ID); + + if (added.empty()) + { + THROW_ERROR("Could not identify TAP"); + } + else if (added.size() > 1) + { + LogAdapters(L"Enumerable network TAP adapters", added); + + THROW_ERROR("Identified more TAP adapters than expected"); + } + + return *added.begin(); +} + +enum class DeletionResult +{ + NO_REMAINING_TAP_ADAPTERS, + SOME_REMAINING_TAP_ADAPTERS +}; + +DeletionResult DeleteVanillaMullvadAdapter() +{ + auto tapAdapters = GetTapAdapters(DEPRECATED_TAP_HARDWARE_ID); + std::optional<NetworkAdapter> mullvadAdapter = FindMullvadAdapter(tapAdapters); + + if (!mullvadAdapter.has_value()) + { + THROW_ERROR("Mullvad TAP adapter not found"); + } + + const auto mullvadGuid = mullvadAdapter.value().guid; + + HDEVINFO devInfo = SetupDiGetClassDevsW( + &GUID_DEVCLASS_NET, + nullptr, + nullptr, + DIGCF_PRESENT + ); + + if (INVALID_HANDLE_VALUE == devInfo) + { + THROW_WINDOWS_ERROR(GetLastError(), "SetupDiGetClassDevsW() failed"); + } + + common::memory::ScopeDestructor cleanupDevList; + cleanupDevList += [&devInfo]() + { + SetupDiDestroyDeviceInfoList(devInfo); + }; + + int numRemainingAdapters = 0; + + for (int memberIndex = 0; ; memberIndex++) + { + SP_DEVINFO_DATA devInfoData = { 0 }; + devInfoData.cbSize = sizeof(devInfoData); + + if (FALSE == SetupDiEnumDeviceInfo(devInfo, memberIndex, &devInfoData)) + { + const auto lastError = GetLastError(); + + if (ERROR_NO_MORE_ITEMS == lastError) + { + break; + } + + THROW_WINDOWS_ERROR(lastError, "Error enumerating network adapters"); + } + + try + { + const auto hardwareId = GetDeviceRegistryStringProperty(devInfo, &devInfoData, SPDRP_HARDWAREID); + + if (!hardwareId.has_value()) + { + continue; + } + if (0 != wcscmp(DEPRECATED_TAP_HARDWARE_ID, hardwareId.value().data())) + { + continue; + } + if (0 != GetNetCfgInstanceId(devInfo, devInfoData).compare(mullvadGuid)) + { + numRemainingAdapters++; + continue; + } + + if (FALSE == SetupDiRemoveDevice( + devInfo, + &devInfoData + )) + { + THROW_WINDOWS_ERROR(GetLastError(), "Error removing Mullvad TAP device"); + } + } + catch (const std::exception & e) + { + // + // Log exception and skip this adapter + // + + std::cerr << "Skipping TAP adapter due to exception caught while iterating: " + << e.what(); + } + } + + return (numRemainingAdapters > 0) + ? DeletionResult::SOME_REMAINING_TAP_ADAPTERS + : DeletionResult::NO_REMAINING_TAP_ADAPTERS; +} + } // anonymous namespace int wmain(int argc, const wchar_t * argv[], const wchar_t * []) @@ -251,10 +620,6 @@ int wmain(int argc, const wchar_t * argv[], const wchar_t * []) goto INVALID_ARGUMENTS; } - // - // Run setup - // - try { if (0 == _wcsicmp(argv[1], L"install")) @@ -276,6 +641,24 @@ int wmain(int argc, const wchar_t * argv[], const wchar_t * []) UpdateTapDriver(argv[2]); } + else if (0 == _wcsicmp(argv[1], L"remove-vanilla-tap")) + { + switch (DeleteVanillaMullvadAdapter()) + { + case DeletionResult::NO_REMAINING_TAP_ADAPTERS: + std::wcout << L"Removed vanilla Mullvad TAP."; + return DELETE_NO_ADAPTERS_REMAIN; + + case DeletionResult::SOME_REMAINING_TAP_ADAPTERS: + std::wcout << L"Removed vanilla Mullvad TAP."; + return DELETE_SOME_ADAPTERS_REMAIN; + } + } + else if (0 == _wcsicmp(argv[1], L"find-tap")) + { + const auto tap = FindBrandedTap(); + std::wcout << tap.alias; + } else { goto INVALID_ARGUMENTS; @@ -284,17 +667,17 @@ int wmain(int argc, const wchar_t * argv[], const wchar_t * []) catch (const std::exception &e) { std::cerr << e.what() << std::endl; - return MULLVAD_GENERAL_ERROR; + return GENERAL_ERROR; } catch (...) { std::wcerr << L"Unhandled exception." << std::endl; - return MULLVAD_GENERAL_ERROR; + return GENERAL_ERROR; } - return MULLVAD_SUCCESS; + return GENERAL_SUCCESS; INVALID_ARGUMENTS: std::wcerr << L"Invalid arguments."; - return MULLVAD_GENERAL_ERROR; + return GENERAL_ERROR; } |
