diff options
| author | David Lönnhager <david.l@mullvad.net> | 2019-12-03 09:17:53 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2019-12-03 09:17:53 +0100 |
| commit | b0628860be5c03af241bbfc308887686ea561bed (patch) | |
| tree | 13fec05db5a764709650c3ce4b2d92549692bd7d /windows/shared | |
| parent | c030edc99b8fa03b1090d9a8060873d6fc7ed16c (diff) | |
| parent | 6d9192f46d7c1c8d447ad39b7d10e768c79650c2 (diff) | |
| download | mullvadvpn-b0628860be5c03af241bbfc308887686ea561bed.tar.xz mullvadvpn-b0628860be5c03af241bbfc308887686ea561bed.zip | |
Merge branch 'tap-update-fix'
Diffstat (limited to 'windows/shared')
| -rw-r--r-- | windows/shared/shared.sln | 13 | ||||
| -rw-r--r-- | windows/shared/src/shared/network/interfaceutils.cpp | 177 | ||||
| -rw-r--r-- | windows/shared/src/shared/network/interfaceutils.h | 79 | ||||
| -rw-r--r-- | windows/shared/src/shared/shared.vcxproj | 2 | ||||
| -rw-r--r-- | windows/shared/src/shared/shared.vcxproj.filters | 11 | ||||
| -rw-r--r-- | windows/shared/src/shared/stdafx.h | 3 |
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> |
