summaryrefslogtreecommitdiffhomepage
path: root/windows/shared
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2019-12-03 09:17:53 +0100
committerDavid Lönnhager <david.l@mullvad.net>2019-12-03 09:17:53 +0100
commitb0628860be5c03af241bbfc308887686ea561bed (patch)
tree13fec05db5a764709650c3ce4b2d92549692bd7d /windows/shared
parentc030edc99b8fa03b1090d9a8060873d6fc7ed16c (diff)
parent6d9192f46d7c1c8d447ad39b7d10e768c79650c2 (diff)
downloadmullvadvpn-b0628860be5c03af241bbfc308887686ea561bed.tar.xz
mullvadvpn-b0628860be5c03af241bbfc308887686ea561bed.zip
Merge branch 'tap-update-fix'
Diffstat (limited to 'windows/shared')
-rw-r--r--windows/shared/shared.sln13
-rw-r--r--windows/shared/src/shared/network/interfaceutils.cpp177
-rw-r--r--windows/shared/src/shared/network/interfaceutils.h79
-rw-r--r--windows/shared/src/shared/shared.vcxproj2
-rw-r--r--windows/shared/src/shared/shared.vcxproj.filters11
-rw-r--r--windows/shared/src/shared/stdafx.h3
6 files changed, 285 insertions, 0 deletions
diff --git a/windows/shared/shared.sln b/windows/shared/shared.sln
index d735b2d82d..d664af8399 100644
--- a/windows/shared/shared.sln
+++ b/windows/shared/shared.sln
@@ -3,6 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
VisualStudioVersion = 16.0.29324.140
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shared", "src\shared\shared.vcxproj", "{EE69EA4A-CF71-4B88-866B-957F60C4CE0D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -24,6 +29,14 @@ Global
{EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x86.ActiveCfg = Release|Win32
{EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x86.Build.0 = Release|Win32
{EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x86.Deploy.0 = Release|Win32
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.ActiveCfg = Debug|x64
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.Build.0 = Debug|x64
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.ActiveCfg = Debug|Win32
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.Build.0 = Debug|Win32
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.ActiveCfg = Release|x64
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.Build.0 = Release|x64
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.ActiveCfg = Release|Win32
+ {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/windows/shared/src/shared/network/interfaceutils.cpp b/windows/shared/src/shared/network/interfaceutils.cpp
new file mode 100644
index 0000000000..6d56ec82d2
--- /dev/null
+++ b/windows/shared/src/shared/network/interfaceutils.cpp
@@ -0,0 +1,177 @@
+#include "stdafx.h"
+#include <sstream>
+#include <algorithm>
+#include "interfaceutils.h"
+#include <libcommon/error.h>
+#include <libcommon/string.h>
+
+namespace shared::network
+{
+
+InterfaceUtils::NetworkAdapter::NetworkAdapter(
+ const common::network::Nci &nci,
+ const std::shared_ptr<std::vector<uint8_t>> addressesBuffer,
+ const IP_ADAPTER_ADDRESSES &entry
+)
+ : m_addressesBuffer(addressesBuffer)
+ , m_entry(entry)
+{
+ m_guid = common::string::ToWide(entry.AdapterName);
+
+ try
+ {
+ //
+ // FIXME:
+ // Work around incorrect alias sometimes
+ // being returned on Windows 8.
+ //
+ // Steps to reproduce:
+ // 1. Install NDIS 6 TAP driver v9.00.00.21.
+ // 2. Update driver to v9.24.2.601.
+ // 3. Rename TAP adapter.
+ //
+ // GetAdaptersAddresses() returns a generic name
+ // for the *first* adapter instead of the correct
+ // one, whereas ConvertInterfaceAliasToLuid() and
+ // ConvertInterfaceLuidToAlias() yield correct values.
+ //
+
+ IID guidObj = { 0 };
+ if (S_OK != IIDFromString(&m_guid[0], &guidObj))
+ {
+ throw std::runtime_error("IIDFromString() failed");
+ }
+
+ m_alias = nci.getConnectionName(guidObj);
+ }
+ catch (const std::exception &)
+ {
+ m_alias = entry.FriendlyName;
+ }
+
+ m_name = entry.Description;
+}
+
+//static
+std::set<InterfaceUtils::NetworkAdapter> InterfaceUtils::GetAllAdapters(ULONG family, ULONG flags)
+{
+ ULONG bufferSize = 0;
+
+ auto status = GetAdaptersAddresses(family, flags, nullptr, nullptr, &bufferSize);
+
+ THROW_UNLESS(ERROR_BUFFER_OVERFLOW, status, "Probe for adapter listing buffer size");
+
+ // Memory is cheap, this avoids a looping construct.
+ bufferSize *= 2;
+
+ auto buffer = std::make_shared<std::vector<uint8_t>>(bufferSize);
+ auto addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&(*buffer)[0]);
+
+ status = GetAdaptersAddresses(family, flags, nullptr, addresses, &bufferSize);
+
+ THROW_UNLESS(ERROR_SUCCESS, status, "Retrieve adapter listing");
+
+ std::set<NetworkAdapter> adapters;
+
+ common::network::Nci nci;
+
+ for (auto it = addresses; nullptr != it; it = it->Next)
+ {
+ adapters.emplace(NetworkAdapter(nci, buffer, *it));
+ }
+
+ return adapters;
+}
+
+//static
+void InterfaceUtils::AddDeviceIpAddresses(NET_LUID device, const std::vector<SOCKADDR_INET> &addresses)
+{
+ for (const auto &address : addresses)
+ {
+ MIB_UNICASTIPADDRESS_ROW row;
+ InitializeUnicastIpAddressEntry(&row);
+
+ row.InterfaceLuid = device;
+ row.Address = address;
+
+ THROW_UNLESS(NO_ERROR, CreateUnicastIpAddressEntry(&row), "Assign IP address on network interface");
+ }
+}
+
+//static
+std::set<InterfaceUtils::NetworkAdapter>
+InterfaceUtils::GetTapAdapters(const std::set<NetworkAdapter>& adapters)
+{
+ std::set<NetworkAdapter> tapAdapters;
+
+ for (const auto& adapter : adapters)
+ {
+ static const wchar_t name[] = L"TAP-Windows Adapter V9";
+
+ //
+ // Compare partial name, because once you start having more TAP adapters
+ // they're named "TAP-Windows Adapter V9 #2" and so on.
+ //
+
+ if (0 == adapter.name().compare(0, _countof(name) - 1, name))
+ {
+ tapAdapters.insert(adapter);
+ }
+ }
+
+ return tapAdapters;
+}
+
+//static
+std::wstring InterfaceUtils::GetTapInterfaceAlias()
+{
+ //
+ // Look for TAP adapter with alias "Mullvad".
+ //
+
+ using shared::network::InterfaceUtils;
+
+ auto adapters = InterfaceUtils::GetTapAdapters(InterfaceUtils::GetAllAdapters(
+ AF_INET,
+ GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST
+ ));
+
+ auto findByAlias = [](const std::set<InterfaceUtils::NetworkAdapter>& adapters, const std::wstring& alias)
+ {
+ const auto it = std::find_if(adapters.begin(), adapters.end(), [&alias](const InterfaceUtils::NetworkAdapter& candidate)
+ {
+ return 0 == _wcsicmp(candidate.alias().c_str(), alias.c_str());
+ });
+
+ return it != adapters.end();
+ };
+
+ static const wchar_t baseAlias[] = L"Mullvad";
+
+ if (findByAlias(adapters, baseAlias))
+ {
+ return baseAlias;
+ }
+
+ //
+ // Look for TAP adapter with alias "Mullvad-1", "Mullvad-2", etc.
+ //
+
+ for (auto i = 0; i < 10; ++i)
+ {
+ std::wstringstream ss;
+
+ ss << baseAlias << L"-" << i;
+
+ const auto alias = ss.str();
+
+ if (findByAlias(adapters, alias))
+ {
+ return alias;
+ }
+ }
+
+ throw std::runtime_error("Unable to find TAP adapter");
+}
+
+}
diff --git a/windows/shared/src/shared/network/interfaceutils.h b/windows/shared/src/shared/network/interfaceutils.h
new file mode 100644
index 0000000000..85a243d591
--- /dev/null
+++ b/windows/shared/src/shared/network/interfaceutils.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <string>
+#include <set>
+#include <vector>
+#include <memory>
+#include <cstdint>
+
+// Secret include order to get most common networking structs/apis
+// And avoiding compilation errors
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2def.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+#include <netioapi.h>
+// end
+
+#include <libcommon/network/nci.h>
+
+namespace shared::network
+{
+
+class InterfaceUtils
+{
+ InterfaceUtils() = delete;
+
+public:
+
+ class NetworkAdapter
+ {
+
+ public:
+
+ const std::wstring &guid() const { return m_guid; }
+ const std::wstring &name() const { return m_name; }
+ const std::wstring &alias() const { return m_alias; }
+
+ bool operator<(const NetworkAdapter &rhs) const
+ {
+ return _wcsicmp(m_guid.c_str(), rhs.m_guid.c_str()) < 0;
+ }
+
+ const IP_ADAPTER_ADDRESSES &raw() const
+ {
+ return m_entry;
+ }
+
+ private:
+
+ NetworkAdapter(
+ const common::network::Nci &nci,
+ const std::shared_ptr<std::vector<uint8_t>> addressesBuffer,
+ const IP_ADAPTER_ADDRESSES &entry
+ );
+
+ friend class InterfaceUtils;
+
+ const IP_ADAPTER_ADDRESSES &m_entry;
+ std::shared_ptr<std::vector<uint8_t>> m_addressesBuffer;
+
+ std::wstring m_guid;
+ std::wstring m_name;
+ std::wstring m_alias;
+ };
+
+ static std::set<NetworkAdapter> GetAllAdapters(ULONG family, ULONG flags);
+
+ static void AddDeviceIpAddresses(NET_LUID device, const std::vector<SOCKADDR_INET> &addresses);
+
+ static std::set<NetworkAdapter> GetTapAdapters(const std::set<NetworkAdapter> &adapters);
+
+ //
+ // Determines alias of primary TAP adapter.
+ //
+ static std::wstring GetTapInterfaceAlias();
+};
+
+}
diff --git a/windows/shared/src/shared/shared.vcxproj b/windows/shared/src/shared/shared.vcxproj
index 771aaa14bd..a5dc7cf4f2 100644
--- a/windows/shared/src/shared/shared.vcxproj
+++ b/windows/shared/src/shared/shared.vcxproj
@@ -178,10 +178,12 @@
<ItemGroup>
<ClInclude Include="logsink.h" />
<ClInclude Include="ilogsink.h" />
+ <ClInclude Include="network\interfaceutils.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="network\interfaceutils.cpp" />
<ClCompile Include="stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
diff --git a/windows/shared/src/shared/shared.vcxproj.filters b/windows/shared/src/shared/shared.vcxproj.filters
index 00c566d6e6..61b48a6937 100644
--- a/windows/shared/src/shared/shared.vcxproj.filters
+++ b/windows/shared/src/shared/shared.vcxproj.filters
@@ -5,8 +5,19 @@
<ClInclude Include="logsink.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
+ <ClInclude Include="network\interfaceutils.h">
+ <Filter>network</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
+ <ClCompile Include="network\interfaceutils.cpp">
+ <Filter>network</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="network">
+ <UniqueIdentifier>{c36884fc-7afc-42a8-b852-c0aafcfcc1c2}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/windows/shared/src/shared/stdafx.h b/windows/shared/src/shared/stdafx.h
index fc6b905b83..59e4616a97 100644
--- a/windows/shared/src/shared/stdafx.h
+++ b/windows/shared/src/shared/stdafx.h
@@ -10,3 +10,6 @@
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
+#include <string>
+#include <sstream>
+#include <algorithm>