summaryrefslogtreecommitdiffhomepage
path: root/windows/driverlogic/src/driverlogic.cpp
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-01-31 12:55:33 +0100
committerDavid Lönnhager <david.l@mullvad.net>2020-02-03 09:13:29 +0100
commit2860aed09fce784bc0e6719319dae78cb4d5cafc (patch)
tree88bac97b810154ba570a29c9a7f0e1ac74abff5e /windows/driverlogic/src/driverlogic.cpp
parent8d4b57def51b2fc63328a6ab1619fa1f78810a4b (diff)
downloadmullvadvpn-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.cpp405
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;
}