summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2018-11-16 23:11:42 +0100
committerOdd Stranne <odd@mullvad.net>2018-11-19 22:32:21 +0100
commit9e408b41cf0c489119a090cbc93abe6dbe81141f (patch)
tree156b2f360089d7ef99f980fdc8d2317beee6e854
parent7b0a4354feef03bf686225837879017d0f269609 (diff)
downloadmullvadvpn-9e408b41cf0c489119a090cbc93abe6dbe81141f.tar.xz
mullvadvpn-9e408b41cf0c489119a090cbc93abe6dbe81141f.zip
Replace text parsing and WMI calls in 'driverlogic'
-rw-r--r--windows/nsis-plugins/src/driverlogic/context.cpp241
-rw-r--r--windows/nsis-plugins/src/driverlogic/context.h49
-rw-r--r--windows/nsis-plugins/src/driverlogic/driverlogic.cpp69
-rw-r--r--windows/nsis-plugins/src/driverlogic/driverlogic.def2
-rw-r--r--windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj4
5 files changed, 120 insertions, 245 deletions
diff --git a/windows/nsis-plugins/src/driverlogic/context.cpp b/windows/nsis-plugins/src/driverlogic/context.cpp
index a01fd29bac..d0ad9dfb67 100644
--- a/windows/nsis-plugins/src/driverlogic/context.cpp
+++ b/windows/nsis-plugins/src/driverlogic/context.cpp
@@ -1,243 +1,142 @@
#include "stdafx.h"
#include "context.h"
#include <libcommon/string.h>
-#include <libcommon/wmi/connection.h>
-#include <libcommon/wmi/resultset.h>
-#include <libcommon/wmi/wmi.h>
+#include <libcommon/error.h>
#include <log/log.h>
+#include <winsock2.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+#include <windows.h>
#include <vector>
+#include <list>
#include <stdexcept>
-#include <algorithm>
-#include <memory>
-#include <sstream>
-
-using namespace common;
namespace
{
-std::vector<std::wstring> BlockToRows(const std::wstring &textBlock)
+std::set<Context::NetworkAdapter> GetAllAdapters()
{
- //
- // This is such a hack :-(
- //
- // It only works because the tokenizer is greedy and because we don't care about
- // empty lines for this usage.
- //
- return common::string::Tokenize(textBlock, L"\r\n");
-}
+ ULONG bufferSize = 0;
-void LogAllAdapters(wmi::Connection &connection)
-{
- auto resultset = connection.query(L"SELECT * from Win32_NetworkAdapter");
-
- struct NetworkAdapter
- {
- size_t interfaceIndex;
- std::wstring manufacturer;
- std::wstring name;
- std::wstring pnpDeviceId;
- std::wstring alias;
- };
+ const ULONG flags = GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER;
- std::vector<NetworkAdapter> adapters;
+ auto status = GetAdaptersAddresses(AF_INET, flags, nullptr, nullptr, &bufferSize);
- //
- // Find all adapters and extract the most important data.
- //
+ THROW_UNLESS(ERROR_BUFFER_OVERFLOW, status, "Probe for adapter listing buffer size");
- auto StringOrNa = [](const _variant_t &variant)
- {
- if (VT_BSTR == V_VT(&variant))
- {
- return std::wstring(V_BSTR(&variant));
- }
+ // Memory is cheap, this avoids a looping construct.
+ bufferSize *= 2;
- return std::wstring(L"n/a");
- };
+ std::vector<uint8_t> buffer(bufferSize);
- while(resultset.advance())
- {
- auto interfaceIndex = wmi::WmiGetPropertyAlways(resultset.result(), L"InterfaceIndex");
- auto manufacturer = wmi::WmiGetProperty(resultset.result(), L"Manufacturer");
- auto name = wmi::WmiGetProperty(resultset.result(), L"Name");
- auto pnpDeviceId = wmi::WmiGetProperty(resultset.result(), L"PNPDeviceID");
- auto alias = wmi::WmiGetProperty(resultset.result(), L"NetConnectionID");
+ status = GetAdaptersAddresses(AF_INET, flags, nullptr,
+ reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer[0]), &bufferSize);
- NetworkAdapter adapter;
+ THROW_UNLESS(ERROR_SUCCESS, status, "Retrieve adapter listing");
- adapter.interfaceIndex = static_cast<size_t>(V_UI8(&interfaceIndex));
- adapter.manufacturer = StringOrNa(manufacturer);
- adapter.name = StringOrNa(name);
- adapter.pnpDeviceId = StringOrNa(pnpDeviceId);
- adapter.alias = StringOrNa(alias);
+ std::set<Context::NetworkAdapter> adapters;
- adapters.emplace_back(adapter);
+ for (auto it = (PIP_ADAPTER_ADDRESSES)&buffer[0]; nullptr != it; it = it->Next)
+ {
+ adapters.emplace(Context::NetworkAdapter(common::string::ToWide(it->AdapterName),
+ it->Description, it->FriendlyName));
}
- //
- // Flatten the adapter information so we can log it more easily.
- //
+ return adapters;
+}
- std::vector<std::wstring> details;
+std::set<Context::NetworkAdapter> GetTapAdapters(const std::set<Context::NetworkAdapter> &adapters)
+{
+ std::set<Context::NetworkAdapter> tapAdapters;
for (const auto &adapter : adapters)
{
- details.emplace_back(L"Adapter");
-
- {
- std::wstringstream ss;
+ static const wchar_t name[] = L"TAP-Windows Adapter V9";
- ss << L" InterfaceIndex: " << adapter.interfaceIndex;
+ //
+ // Compare partial name, because once you start having more TAP adapters
+ // they're named "TAP-Windows Adapter V9 #2" and so on.
+ //
- details.emplace_back(ss.str());
+ if (0 == adapter.name.compare(0, _countof(name) - 1, name))
+ {
+ tapAdapters.insert(adapter);
}
-
- details.emplace_back(std::wstring(L" Manufacturer: ").append(adapter.manufacturer));
- details.emplace_back(std::wstring(L" Name: ").append(adapter.name));
- details.emplace_back(std::wstring(L" PnpDeviceId: ").append(adapter.pnpDeviceId));
- details.emplace_back(std::wstring(L" Alias: ").append(adapter.alias));
}
- PluginLogWithDetails(L"Adapters known to WMI", details);
+ return tapAdapters;
}
-std::wstring DoubleBackslashes(const std::wstring &str)
+void LogAdapters(const std::wstring &description, const std::set<Context::NetworkAdapter> &adapters)
{
- auto result(str);
+ //
+ // Flatten the information so we can log it more easily.
+ //
- size_t offset = 0;
+ std::vector<std::wstring> details;
- for (size_t index = 0; index < str.size(); ++index)
+ for (const auto &adapter : adapters)
{
- if (L'\\' == str[index])
- {
- result.insert(index + offset, 1, L'\\');
- ++offset;
- }
+ details.emplace_back(L"Adapter");
+
+ details.emplace_back(std::wstring(L" Guid: ").append(adapter.guid));
+ details.emplace_back(std::wstring(L" Name: ").append(adapter.name));
+ details.emplace_back(std::wstring(L" Alias: ").append(adapter.alias));
}
- return result;
+ PluginLogWithDetails(description, details);
}
} // anonymous namespace
-Context::Context()
- : m_connection(wmi::Connection::Namespace::Cimv2)
+Context::BaselineStatus Context::establishBaseline()
{
-}
+ m_baseline = GetAllAdapters();
-Context::BaselineStatus Context::establishBaseline(const std::wstring &textBlock)
-{
- m_baseline = ParseVirtualNics(textBlock);
+ auto tapAdapters = GetTapAdapters(m_baseline);
- if (m_baseline.empty())
+ if (tapAdapters.empty())
{
- return BaselineStatus::NO_INTERFACES_PRESENT;
+ return BaselineStatus::NO_TAP_ADAPTERS_PRESENT;
}
- for (const auto &nic : m_baseline)
+ for (const auto &adapter : tapAdapters)
{
- if (0 == _wcsicmp(nic.alias.c_str(), L"mullvad"))
+ if (0 == _wcsicmp(adapter.alias.c_str(), L"mullvad"))
{
- return BaselineStatus::MULLVAD_INTERFACE_PRESENT;
+ return BaselineStatus::MULLVAD_ADAPTER_PRESENT;
}
}
- return BaselineStatus::SOME_INTERFACES_PRESENT;
+ return BaselineStatus::SOME_TAP_ADAPTERS_PRESENT;
}
-void Context::recordCurrentState(const std::wstring &textBlock)
+void Context::recordCurrentState()
{
- m_currentState = ParseVirtualNics(textBlock);
-}
-
-Context::VirtualNic Context::getNewAdapter()
-{
- std::vector<VirtualNic> added;
-
- for (const auto &nic : m_currentState)
- {
- if (m_baseline.end() == m_baseline.find(nic))
- {
- added.push_back(nic);
- }
- }
-
- if (added.size() != 1)
- {
- throw std::runtime_error("Unable to identify newly added virtual adapter");
- }
-
- return added[0];
+ m_currentState = GetAllAdapters();
}
-std::set<Context::VirtualNic> Context::ParseVirtualNics(const std::wstring &textBlock)
+Context::NetworkAdapter Context::getNewAdapter()
{
- // ROOT\NET\0000
- // Name: TAP - Windows Adapter V9
- // Hardware IDs :
- // tap0901
- // 1 matching device(s) found.
-
- std::set<VirtualNic> nics;
-
- auto text = BlockToRows(textBlock);
+ std::list<NetworkAdapter> added;
- size_t line = 0;
+ const auto baselineTaps = GetTapAdapters(m_baseline);
+ const auto currentTaps = GetTapAdapters(m_currentState);
- while (nullptr != wcschr(text.at(line).c_str(), L'\\'))
+ for (const auto &adapter : currentTaps)
{
- auto nameDelimiter = wcschr(text.at(line + 1).c_str(), L':');
-
- if (nullptr == nameDelimiter)
+ if (baselineTaps.end() == baselineTaps.find(adapter))
{
- throw std::runtime_error("Unexpected formatting in input data");
+ added.push_back(adapter);
}
-
- VirtualNic nic;
-
- nic.node = text.at(line);
- nic.name = std::wstring(nameDelimiter + 2);
- nic.alias = GetNicAlias(nic.node, nic.name);
-
- nics.emplace(std::move(nic));
- line += 4;
}
- return nics;
-}
-
-std::wstring Context::GetNicAlias(const std::wstring &node, const std::wstring &name)
-{
- //
- // The name cannot be used when querying WMI, because WMI sometimes normalizes the
- // names in its dataset, thereby destroying their uniqueness.
- //
- // E.g. if a network interface has a name of "TAP-Windows Adapter V9 #2" it will
- // sometimes be reported by WMI as "TAP-Windows Adapter V9".
- //
- // Also, the node string cannot be used as-is. We have to double the backslashes in it
- // or the string will be rejected by WMI.
- //
-
- const auto formattedNode = DoubleBackslashes(node);
-
- std::wstringstream ss;
-
- ss << L"SELECT * FROM Win32_NetworkAdapter WHERE PNPDeviceID = \"" << formattedNode << L"\"";
-
- auto resultset = m_connection.query(ss.str().c_str());
-
- if (false == resultset.advance())
+ if (added.size() != 1)
{
- PluginLog(std::wstring(L"WMI query failed for adapter: ").append(name));
- LogAllAdapters(m_connection);
+ LogAdapters(L"Enumerable network adapters", m_currentState);
- throw std::runtime_error("Unable to look up virtual adapter using WMI");
+ throw std::runtime_error("Unable to identify recently added TAP adapter");
}
- auto alias = wmi::WmiGetPropertyAlways(resultset.result(), L"NetConnectionID");
-
- return V_BSTR(&alias);
+ return *added.begin();
}
diff --git a/windows/nsis-plugins/src/driverlogic/context.h b/windows/nsis-plugins/src/driverlogic/context.h
index 1340d561fe..a93a3bcfcf 100644
--- a/windows/nsis-plugins/src/driverlogic/context.h
+++ b/windows/nsis-plugins/src/driverlogic/context.h
@@ -1,6 +1,5 @@
#pragma once
-#include <libcommon/wmi/connection.h>
#include <set>
#include <string>
@@ -8,49 +7,47 @@ class Context
{
public:
- Context();
+ Context()
+ {
+ }
- struct VirtualNic
+ struct NetworkAdapter
{
- std::wstring node;
+ std::wstring guid;
std::wstring name;
std::wstring alias;
- bool operator<(const VirtualNic &rhs) const
+ NetworkAdapter(std::wstring _guid, std::wstring _name, std::wstring _alias)
+ : guid(_guid)
+ , name(_name)
+ , alias(_alias)
{
- return _wcsicmp(node.c_str(), rhs.node.c_str()) < 0;
+ }
+
+ bool operator<(const NetworkAdapter &rhs) const
+ {
+ return _wcsicmp(guid.c_str(), rhs.guid.c_str()) < 0;
}
};
enum class BaselineStatus
{
- NO_INTERFACES_PRESENT,
- SOME_INTERFACES_PRESENT,
- MULLVAD_INTERFACE_PRESENT
+ NO_TAP_ADAPTERS_PRESENT,
+ SOME_TAP_ADAPTERS_PRESENT,
+ MULLVAD_ADAPTER_PRESENT
};
- //
- // Invoke with the output from "tapinstall hwids tap0901"
- //
- BaselineStatus establishBaseline(const std::wstring &textBlock);
+ BaselineStatus establishBaseline();
- //
- // Invoke with the output from "tapinstall hwids tap0901"
- //
- void recordCurrentState(const std::wstring &textBlock);
+ void recordCurrentState();
//
- // Identify a single new interface
+ // Identify a single new TAP adapter
//
- VirtualNic getNewAdapter();
+ NetworkAdapter getNewAdapter();
private:
- common::wmi::Connection m_connection;
-
- std::set<VirtualNic> ParseVirtualNics(const std::wstring &textBlock);
- std::wstring GetNicAlias(const std::wstring &node, const std::wstring &name);
-
- std::set<VirtualNic> m_baseline;
- std::set<VirtualNic> m_currentState;
+ 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 2aedaf41ee..3bbe98bf8b 100644
--- a/windows/nsis-plugins/src/driverlogic/driverlogic.cpp
+++ b/windows/nsis-plugins/src/driverlogic/driverlogic.cpp
@@ -10,36 +10,11 @@
#include <nsis/pluginapi.h>
#pragma warning (pop)
-#include <string>
-#include <vector>
-
Context *g_context = nullptr;
namespace
{
-std::wstring PopString()
-{
- //
- // NSIS functions popstring() and popstringn() require that you definitely size the buffer
- // before popping the string. Let's do it ourselves instead.
- //
-
- if (!g_stacktop || !*g_stacktop)
- {
- throw std::runtime_error("NSIS variable stack is corrupted");
- }
-
- stack_t *th = *g_stacktop;
-
- std::wstring copy(th->text);
-
- *g_stacktop = th->next;
- GlobalFree((HGLOBAL)th);
-
- return copy;
-}
-
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
void PinDll()
@@ -122,15 +97,17 @@ void __declspec(dllexport) NSISCALL Initialize
//
// EstablishBaseline
//
-// Invoke with the output from "tapinstall hwids tap0901"
-// e.g.: driverlogic::EstablishBaseline $1
+// Call this function to establish a baseline W.R.T network adapters
+// present in the system.
+//
+// The return value reflects the status of TAP presence in the system.
//
enum class EstablishBaselineStatus
{
GENERAL_ERROR = 0,
- NO_INTERFACES_PRESENT,
- SOME_INTERFACES_PRESENT,
- MULLVAD_INTERFACE_PRESENT
+ NO_TAP_ADAPTERS_PRESENT,
+ SOME_TAP_ADAPTERS_PRESENT,
+ MULLVAD_ADAPTER_PRESENT
};
void __declspec(dllexport) NSISCALL EstablishBaseline
@@ -157,12 +134,12 @@ void __declspec(dllexport) NSISCALL EstablishBaseline
const common::ValueMapper<Context::BaselineStatus, EstablishBaselineStatus> mapper =
{
- value_type(Context::BaselineStatus::NO_INTERFACES_PRESENT, EstablishBaselineStatus::NO_INTERFACES_PRESENT),
- value_type(Context::BaselineStatus::SOME_INTERFACES_PRESENT, EstablishBaselineStatus::SOME_INTERFACES_PRESENT),
- value_type(Context::BaselineStatus::MULLVAD_INTERFACE_PRESENT, EstablishBaselineStatus::MULLVAD_INTERFACE_PRESENT)
+ value_type(Context::BaselineStatus::NO_TAP_ADAPTERS_PRESENT, EstablishBaselineStatus::NO_TAP_ADAPTERS_PRESENT),
+ value_type(Context::BaselineStatus::SOME_TAP_ADAPTERS_PRESENT, EstablishBaselineStatus::SOME_TAP_ADAPTERS_PRESENT),
+ value_type(Context::BaselineStatus::MULLVAD_ADAPTER_PRESENT, EstablishBaselineStatus::MULLVAD_ADAPTER_PRESENT)
};
- const auto status = mapper.map(g_context->establishBaseline(PopString()));
+ const auto status = mapper.map(g_context->establishBaseline());
pushstring(L"");
pushint(status);
@@ -180,18 +157,20 @@ void __declspec(dllexport) NSISCALL EstablishBaseline
}
//
-// IdentifyNewInterface
+// IdentifyNewAdapter
+//
+// Call this function after installing a TAP adapter.
//
-// Invoke with the output from "tapinstall hwids tap0901"
-// e.g.: driverlogic::IdentifyNewInterface $1
+// By comparing with the previously captured baseline we're able to
+// identify the new adapter.
//
-enum class IdentifyNewInterfaceStatus
+enum class IdentifyNewAdapterStatus
{
GENERAL_ERROR = 0,
SUCCESS
};
-void __declspec(dllexport) NSISCALL IdentifyNewInterface
+void __declspec(dllexport) NSISCALL IdentifyNewAdapter
(
HWND hwndParent,
int string_size,
@@ -211,22 +190,22 @@ void __declspec(dllexport) NSISCALL IdentifyNewInterface
try
{
- g_context->recordCurrentState(PopString());
+ g_context->recordCurrentState();
- auto nic = g_context->getNewAdapter();
+ auto adapter = g_context->getNewAdapter();
- pushstring(nic.alias.c_str());
- pushint(IdentifyNewInterfaceStatus::SUCCESS);
+ pushstring(adapter.alias.c_str());
+ pushint(IdentifyNewAdapterStatus::SUCCESS);
}
catch (std::exception &err)
{
pushstring(common::string::ToWide(err.what()).c_str());
- pushint(IdentifyNewInterfaceStatus::GENERAL_ERROR);
+ pushint(IdentifyNewAdapterStatus::GENERAL_ERROR);
}
catch (...)
{
pushstring(L"Unspecified error");
- pushint(IdentifyNewInterfaceStatus::GENERAL_ERROR);
+ pushint(IdentifyNewAdapterStatus::GENERAL_ERROR);
}
}
diff --git a/windows/nsis-plugins/src/driverlogic/driverlogic.def b/windows/nsis-plugins/src/driverlogic/driverlogic.def
index 3bd78e1eea..1bd484d6be 100644
--- a/windows/nsis-plugins/src/driverlogic/driverlogic.def
+++ b/windows/nsis-plugins/src/driverlogic/driverlogic.def
@@ -4,5 +4,5 @@ EXPORTS
Initialize
EstablishBaseline
-IdentifyNewInterface
+IdentifyNewAdapter
Deinitialize
diff --git a/windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj b/windows/nsis-plugins/src/driverlogic/driverlogic.vcxproj
index 55f6b5efc1..e5a3bd7c7a 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/windows/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
- <AdditionalDependencies>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>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/windows/nsis/;$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories>
- <AdditionalDependencies>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>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>