diff options
| author | David Lönnhager <david.l@mullvad.net> | 2019-10-11 12:44:33 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2019-10-18 13:38:58 +0200 |
| commit | fd13e2805f7d493d8600fa4f4a9ac87f58e06d3a (patch) | |
| tree | 5629a11f547e902735e0a13a82ae602d3a51059f /windows/nsis-plugins/src | |
| parent | 6d063dd619b6b9c609f0d1bc6343df43ba7b4e88 (diff) | |
| download | mullvadvpn-fd13e2805f7d493d8600fa4f4a9ac87f58e06d3a.tar.xz mullvadvpn-fd13e2805f7d493d8600fa4f4a9ac87f58e06d3a.zip | |
Remove only the TAP driver if it's not being used by other adapters on
Windows
Diffstat (limited to 'windows/nsis-plugins/src')
5 files changed, 276 insertions, 14 deletions
diff --git a/windows/nsis-plugins/src/driverlogic/context.cpp b/windows/nsis-plugins/src/driverlogic/context.cpp index 13cb781863..4f0cb2d291 100644 --- a/windows/nsis-plugins/src/driverlogic/context.cpp +++ b/windows/nsis-plugins/src/driverlogic/context.cpp @@ -1,21 +1,33 @@ #include "stdafx.h" #include "context.h" + #include <libcommon/string.h> #include <libcommon/error.h> +#include <libcommon/memory.h> #include <log/log.h> + #include <winsock2.h> #include <ws2ipdef.h> #include <iphlpapi.h> #include <windows.h> + #include <vector> #include <list> #include <stdexcept> #include <sstream> #include <algorithm> +#include <setupapi.h> +#include <devguid.h> +#include <combaseapi.h> +#include <initguid.h> +#include <devpkey.h> + namespace { +const wchar_t TAP_HARDWARE_ID[] = L"tap0901"; + std::set<Context::NetworkAdapter> GetAllAdapters() { ULONG bufferSize = 0; @@ -89,19 +101,57 @@ void LogAdapters(const std::wstring &description, const std::set<Context::Networ PluginLogWithDetails(description, details); } -} // anonymous namespace - -Context::BaselineStatus Context::establishBaseline() +std::wstring GetNetCfgInstanceId(HDEVINFO devInfo, const SP_DEVINFO_DATA &devInfoData) { - m_baseline = GetAllAdapters(); + HKEY hNet = SetupDiOpenDevRegKey( + devInfo, + const_cast<SP_DEVINFO_DATA *>(&devInfoData), + DICS_FLAG_GLOBAL, + 0, + DIREG_DRV, + KEY_READ + ); - auto tapAdapters = GetTapAdapters(m_baseline); + if (hNet == INVALID_HANDLE_VALUE) + { + throw std::runtime_error("SetupDiOpenDevRegKey Failed"); + } - if (tapAdapters.empty()) + std::vector<wchar_t> instanceId(MAX_PATH + sizeof(L'\0')); + DWORD strSize = 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) { - return BaselineStatus::NO_TAP_ADAPTERS_PRESENT; + throw std::runtime_error("RegGetValue for NetCfgInstanceId failed"); } + instanceId[strSize / sizeof(wchar_t)] = L'\0'; + + return instanceId.data(); +} + +} // anonymous namespace + +//static +std::optional<Context::NetworkAdapter> Context::FindMullvadAdapter(const std::set<Context::NetworkAdapter> &tapAdapters) +{ + if (tapAdapters.empty()) + { + return std::nullopt; + } + // // Look for TAP adapter with alias "Mullvad". // @@ -113,14 +163,16 @@ Context::BaselineStatus Context::establishBaseline() return 0 == _wcsicmp(candidate.alias.c_str(), alias.c_str()); }); - return it != adapters.end(); + return it; }; static const wchar_t baseAlias[] = L"Mullvad"; - if (findByAlias(tapAdapters, baseAlias)) + const auto mullvadAdapter = findByAlias(tapAdapters, baseAlias); + + if (tapAdapters.end() != mullvadAdapter) { - return BaselineStatus::MULLVAD_ADAPTER_PRESENT; + return std::optional{ *mullvadAdapter }; } // @@ -135,12 +187,32 @@ Context::BaselineStatus Context::establishBaseline() const auto alias = ss.str(); - if (findByAlias(tapAdapters, alias)) + const auto mullvadAdapter = findByAlias(tapAdapters, alias); + + if (tapAdapters.end() != mullvadAdapter) { - return BaselineStatus::MULLVAD_ADAPTER_PRESENT; + return std::optional{ *mullvadAdapter }; } } + return std::nullopt; +} + +Context::BaselineStatus Context::establishBaseline() +{ + m_baseline = GetAllAdapters(); + const auto tapAdapters = GetTapAdapters(m_baseline); + + if (tapAdapters.empty()) + { + return BaselineStatus::NO_TAP_ADAPTERS_PRESENT; + } + + if (FindMullvadAdapter(tapAdapters).has_value()) + { + return BaselineStatus::MULLVAD_ADAPTER_PRESENT; + } + return BaselineStatus::SOME_TAP_ADAPTERS_PRESENT; } @@ -173,3 +245,119 @@ Context::NetworkAdapter Context::getNewAdapter() return *added.begin(); } + +//static +Context::DeletionResult Context::DeleteMullvadAdapter() +{ + auto tapAdapters = GetTapAdapters(GetAllAdapters()); + std::optional<NetworkAdapter> mullvadAdapter = FindMullvadAdapter(tapAdapters); + + if (!mullvadAdapter.has_value()) + { + throw std::runtime_error("Mullvad TAP adapter not found"); + } + + const auto mullvadGuid = mullvadAdapter.value().guid; + + HDEVINFO devInfo = SetupDiGetClassDevsW( + &GUID_DEVCLASS_NET, + nullptr, + nullptr, + DIGCF_PRESENT + ); + + THROW_GLE_IF(INVALID_HANDLE_VALUE, devInfo, "SetupDiGetClassDevs() failed"); + + common::memory::ScopeDestructor cleanupDevList; + cleanupDevList += [&devInfo]() + { + SetupDiDestroyDeviceInfoList(devInfo); + }; + + SP_DEVINFO_DATA devInfoData; + + std::vector<wchar_t> buffer; + DWORD nameLen; + + int numRemainingAdapters = 0; + + for (int memberIndex = 0; ; memberIndex++) + { + devInfoData = { 0 }; + devInfoData.cbSize = sizeof(devInfoData); + + if (FALSE == SetupDiEnumDeviceInfo(devInfo, memberIndex, &devInfoData)) + { + if (GetLastError() == ERROR_NO_MORE_ITEMS) + { + /* done */ + break; + } + THROW_GLE("Error enumerating network adapters"); + } + + if (FALSE == SetupDiGetDeviceRegistryPropertyW( + devInfo, + &devInfoData, + SPDRP_HARDWAREID, + nullptr, + nullptr, + 0, + &nameLen + )) + { + const auto status = GetLastError(); + if (ERROR_INSUFFICIENT_BUFFER != status) + { + /* ERROR_INSUFFICIENT_BUFFER is expected */ + if (ERROR_INVALID_DATA == status) + { + /* ERROR_INVALID_DATA may mean that the property does not exist */ + continue; + } + THROW_GLE("Error obtaining network adapter hardware ID length"); + } + } + + buffer.resize(nameLen / sizeof(wchar_t) + 1); + buffer[nameLen / sizeof(wchar_t)] = L'\0'; + + if (FALSE == SetupDiGetDeviceRegistryPropertyW( + devInfo, + &devInfoData, + SPDRP_HARDWAREID, + nullptr, + reinterpret_cast<PBYTE>(buffer.data()), + (buffer.size() - 1) * sizeof(wchar_t), + nullptr + )) + { + THROW_GLE("Error obtaining network adapter hardware ID"); + } + + if (wcscmp(TAP_HARDWARE_ID, buffer.data()) == 0) + { + std::wstring netCfgInstanceId = GetNetCfgInstanceId(devInfo, devInfoData); + if (netCfgInstanceId.compare(mullvadGuid) != 0) + { + numRemainingAdapters++; + continue; + } + + if (FALSE == SetupDiRemoveDevice( + devInfo, + &devInfoData + )) + { + THROW_GLE("Error removing Mullvad TAP device"); + } + } + } + + if (numRemainingAdapters > 0) + { + return DeletionResult::SOME_REMAINING_TAP_ADAPTERS; + } + + return DeletionResult::NO_REMAINING_TAP_ADAPTERS; +} diff --git a/windows/nsis-plugins/src/driverlogic/context.h b/windows/nsis-plugins/src/driverlogic/context.h index a93a3bcfcf..eabf884ba8 100644 --- a/windows/nsis-plugins/src/driverlogic/context.h +++ b/windows/nsis-plugins/src/driverlogic/context.h @@ -2,6 +2,7 @@ #include <set> #include <string> +#include <optional> class Context { @@ -46,8 +47,18 @@ public: // NetworkAdapter getNewAdapter(); + enum class DeletionResult + { + NO_REMAINING_TAP_ADAPTERS, + SOME_REMAINING_TAP_ADAPTERS + }; + + static DeletionResult DeleteMullvadAdapter(); + private: + static std::optional<NetworkAdapter> FindMullvadAdapter(const std::set<NetworkAdapter> &tapAdapters); + std::set<NetworkAdapter> m_baseline; std::set<NetworkAdapter> m_currentState; }; diff --git a/windows/nsis-plugins/src/driverlogic/driverlogic.cpp b/windows/nsis-plugins/src/driverlogic/driverlogic.cpp index 3bbe98bf8b..82259c015d 100644 --- a/windows/nsis-plugins/src/driverlogic/driverlogic.cpp +++ b/windows/nsis-plugins/src/driverlogic/driverlogic.cpp @@ -157,6 +157,68 @@ void __declspec(dllexport) NSISCALL EstablishBaseline } // +// RemoveMullvadTap +// +// Deletes the Mullvad TAP adapter. +// +// +enum class RemoveMullvadTapStatus +{ + GENERAL_ERROR = 0, + SUCCESS_NO_REMAINING_TAP_ADAPTERS, + SUCCESS_SOME_REMAINING_TAP_ADAPTERS +}; + +void __declspec(dllexport) NSISCALL RemoveMullvadTap +( + HWND hwndParent, + int string_size, + LPTSTR variables, + stack_t **stacktop, + extra_parameters *extra, + ... +) +{ + EXDLL_INIT(); + + try + { + pushstring(L""); + + switch (Context::DeleteMullvadAdapter()) + { + case Context::DeletionResult::NO_REMAINING_TAP_ADAPTERS: + { + pushint(RemoveMullvadTapStatus::SUCCESS_NO_REMAINING_TAP_ADAPTERS); + break; + } + + case Context::DeletionResult::SOME_REMAINING_TAP_ADAPTERS: + { + pushint(RemoveMullvadTapStatus::SUCCESS_SOME_REMAINING_TAP_ADAPTERS); + break; + } + + default: + { + throw std::runtime_error("Unexpected case"); + } + } + } + catch (std::exception &err) + { + pushstring(common::string::ToWide(err.what()).c_str()); + pushint(RemoveMullvadTapStatus::GENERAL_ERROR); + } + catch (...) + { + pushstring(L"Unspecified error"); + pushint(RemoveMullvadTapStatus::GENERAL_ERROR); + } +} + + +// // IdentifyNewAdapter // // Call this function after installing a TAP adapter. diff --git a/windows/nsis-plugins/src/driverlogic/driverlogic.def b/windows/nsis-plugins/src/driverlogic/driverlogic.def index 1bd484d6be..b8735f1ada 100644 --- a/windows/nsis-plugins/src/driverlogic/driverlogic.def +++ b/windows/nsis-plugins/src/driverlogic/driverlogic.def @@ -5,4 +5,5 @@ EXPORTS Initialize EstablishBaseline IdentifyNewAdapter +RemoveMullvadTap Deinitialize diff --git a/windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj b/windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj index 0e3932e8fa..d7cad2635f 100644 --- a/windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj +++ b/windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj @@ -70,7 +70,7 @@ <GenerateDebugInformation>true</GenerateDebugInformation> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> <AdditionalLibraryDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>iphlpapi.lib;log.lib;libcommon.lib;pluginapi-x86-unicode.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>setupapi.lib;iphlpapi.lib;log.lib;libcommon.lib;pluginapi-x86-unicode.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <IgnoreSpecificDefaultLibraries>libc.lib</IgnoreSpecificDefaultLibraries> <ModuleDefinitionFile>driverlogic.def</ModuleDefinitionFile> </Link> @@ -96,7 +96,7 @@ <GenerateDebugInformation>true</GenerateDebugInformation> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> <AdditionalLibraryDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>iphlpapi.lib;log.lib;libcommon.lib;pluginapi-x86-unicode.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>setupapi.lib;iphlpapi.lib;log.lib;libcommon.lib;pluginapi-x86-unicode.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <IgnoreSpecificDefaultLibraries>libc.lib</IgnoreSpecificDefaultLibraries> <ModuleDefinitionFile>driverlogic.def</ModuleDefinitionFile> </Link> |
