summaryrefslogtreecommitdiffhomepage
path: root/windows
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2019-10-11 12:44:33 +0200
committerDavid Lönnhager <david.l@mullvad.net>2019-10-18 13:38:58 +0200
commitfd13e2805f7d493d8600fa4f4a9ac87f58e06d3a (patch)
tree5629a11f547e902735e0a13a82ae602d3a51059f /windows
parent6d063dd619b6b9c609f0d1bc6343df43ba7b4e88 (diff)
downloadmullvadvpn-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')
-rw-r--r--windows/nsis-plugins/src/driverlogic/context.cpp212
-rw-r--r--windows/nsis-plugins/src/driverlogic/context.h11
-rw-r--r--windows/nsis-plugins/src/driverlogic/driverlogic.cpp62
-rw-r--r--windows/nsis-plugins/src/driverlogic/driverlogic.def1
-rw-r--r--windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj4
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>