diff options
| author | Odd Stranne <odd@mullvad.net> | 2019-04-12 16:00:03 +0200 |
|---|---|---|
| committer | Odd Stranne <odd@mullvad.net> | 2019-04-17 14:10:39 +0200 |
| commit | e2b85d01e51ea61aaccce31b9a032492cfd81932 (patch) | |
| tree | 2d2d1aef73450ac7233fca0e5b6de749c0c27642 | |
| parent | 9ccc27bb67e29f55333187ea2949b8a307665c0a (diff) | |
| download | mullvadvpn-e2b85d01e51ea61aaccce31b9a032492cfd81932.tar.xz mullvadvpn-e2b85d01e51ea61aaccce31b9a032492cfd81932.zip | |
Add function to fuzzily determine TAP alias
| -rw-r--r-- | windows/winroute/src/winroute/interfaceutils.cpp | 127 | ||||
| -rw-r--r-- | windows/winroute/src/winroute/interfaceutils.h | 39 | ||||
| -rw-r--r-- | windows/winroute/src/winroute/stdafx.h | 3 | ||||
| -rw-r--r-- | windows/winroute/src/winroute/winroute.cpp | 54 | ||||
| -rw-r--r-- | windows/winroute/src/winroute/winroute.h | 33 | ||||
| -rw-r--r-- | windows/winroute/src/winroute/winroute.vcxproj | 2 | ||||
| -rw-r--r-- | windows/winroute/src/winroute/winroute.vcxproj.filters | 2 |
7 files changed, 260 insertions, 0 deletions
diff --git a/windows/winroute/src/winroute/interfaceutils.cpp b/windows/winroute/src/winroute/interfaceutils.cpp new file mode 100644 index 0000000000..1f3b95d3d9 --- /dev/null +++ b/windows/winroute/src/winroute/interfaceutils.cpp @@ -0,0 +1,127 @@ +#include "stdafx.h" +#include "interfaceutils.h" +#include "libcommon/error.h" +#include "libcommon/string.h" +#include "libcommon/synchronization.h" +#include <vector> +#include <cstdint> +#include <algorithm> +#include <winsock2.h> +#include <iphlpapi.h> +#include <windows.h> + +//static +std::wstring InterfaceUtils::m_alias; + +//static +std::mutex InterfaceUtils::m_mutex; + +//static +std::set<InterfaceUtils::NetworkAdapter> InterfaceUtils::GetAllAdapters() +{ + ULONG bufferSize = 0; + + const ULONG flags = GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; + + auto status = GetAdaptersAddresses(AF_INET, 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; + + std::vector<uint8_t> buffer(bufferSize); + + status = GetAdaptersAddresses(AF_INET, flags, nullptr, + reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer[0]), &bufferSize); + + THROW_UNLESS(ERROR_SUCCESS, status, "Retrieve adapter listing"); + + std::set<NetworkAdapter> adapters; + + for (auto it = (PIP_ADAPTER_ADDRESSES)&buffer[0]; nullptr != it; it = it->Next) + { + adapters.emplace(NetworkAdapter(common::string::ToWide(it->AdapterName), + it->Description, it->FriendlyName)); + } + + return adapters; +} + +//static +std::set<InterfaceUtils::NetworkAdapter> +InterfaceUtils::GetTapAdapters(const std::set<InterfaceUtils::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() +{ + common::sync::ScopeLock<> cacheLock(m_mutex); + + if (false == m_alias.empty()) + { + return m_alias; + } + + // + // Look for TAP adapter with alias "Mullvad". + // + + auto adapters = GetTapAdapters(GetAllAdapters()); + + 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 _wcsicmp(candidate.alias.c_str(), alias.c_str()); + }); + + return it != adapters.end(); + }; + + static const wchar_t baseAlias[] = L"Mullvad"; + + if (findByAlias(adapters, baseAlias)) + { + return m_alias = 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 m_alias = alias; + } + } + + throw std::runtime_error("Unable to find TAP adapter"); +} diff --git a/windows/winroute/src/winroute/interfaceutils.h b/windows/winroute/src/winroute/interfaceutils.h new file mode 100644 index 0000000000..c016706ba5 --- /dev/null +++ b/windows/winroute/src/winroute/interfaceutils.h @@ -0,0 +1,39 @@ +#pragma once + +#include <string> +#include <set> +#include <mutex> + +class InterfaceUtils +{ + InterfaceUtils() = delete; + + static std::wstring m_alias; + static std::mutex m_mutex; + +public: + + struct NetworkAdapter + { + std::wstring guid; + std::wstring name; + std::wstring alias; + + NetworkAdapter(std::wstring _guid, std::wstring _name, std::wstring _alias) + : guid(_guid) + , name(_name) + , alias(_alias) + { + } + + bool operator<(const NetworkAdapter &rhs) const + { + return _wcsicmp(guid.c_str(), rhs.guid.c_str()) < 0; + } + }; + + static std::set<NetworkAdapter> GetAllAdapters(); + static std::set<NetworkAdapter> GetTapAdapters(const std::set<NetworkAdapter> &adapters); + + static std::wstring GetTapInterfaceAlias(); +}; diff --git a/windows/winroute/src/winroute/stdafx.h b/windows/winroute/src/winroute/stdafx.h index 677e68a9fa..254cb49b0d 100644 --- a/windows/winroute/src/winroute/stdafx.h +++ b/windows/winroute/src/winroute/stdafx.h @@ -5,6 +5,9 @@ #pragma once
+// wcscpy
+#define _CRT_SECURE_NO_WARNINGS 1
+
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
diff --git a/windows/winroute/src/winroute/winroute.cpp b/windows/winroute/src/winroute/winroute.cpp index b9f10e3786..f50da8eb48 100644 --- a/windows/winroute/src/winroute/winroute.cpp +++ b/windows/winroute/src/winroute/winroute.cpp @@ -1,6 +1,7 @@ #include "stdafx.h"
#include "winroute.h"
#include "NetworkInterfaces.h"
+#include "interfaceutils.h"
#include "libcommon/error.h"
#include <cstdint>
#include <stdexcept>
@@ -80,3 +81,56 @@ GetTapInterfaceIpv6Status( return TAP_IPV6_STATUS::FAILURE;
}
}
+
+extern "C"
+WINROUTE_LINKAGE
+TAP_GET_ALIAS_STATUS
+WINROUTE_API
+GetTapInterfaceAlias(
+ wchar_t **alias,
+ WinRouteErrorSink errorSink,
+ void* errorSinkContext
+)
+{
+ try
+ {
+ const auto currentAlias = InterfaceUtils::GetTapInterfaceAlias();
+
+ auto stringBuffer = new wchar_t[currentAlias.size() + 1];
+ wcscpy(stringBuffer, currentAlias.c_str());
+
+ *alias = stringBuffer;
+
+ return TAP_GET_ALIAS_STATUS::SUCCESS;
+ }
+ catch (std::exception &err)
+ {
+ if (nullptr != errorSink)
+ {
+ errorSink(err.what(), errorSinkContext);
+ }
+
+ return TAP_GET_ALIAS_STATUS::GENERAL_ERROR;
+ }
+ catch (...)
+ {
+ return TAP_GET_ALIAS_STATUS::GENERAL_ERROR;
+ }
+}
+
+extern "C"
+WINROUTE_LINKAGE
+void
+WINROUTE_API
+ReleaseString(
+ wchar_t *str
+)
+{
+ try
+ {
+ delete[] str;
+ }
+ catch (...)
+ {
+ }
+}
diff --git a/windows/winroute/src/winroute/winroute.h b/windows/winroute/src/winroute/winroute.h index 6b500cee7e..ac74c264c9 100644 --- a/windows/winroute/src/winroute/winroute.h +++ b/windows/winroute/src/winroute/winroute.h @@ -48,3 +48,36 @@ GetTapInterfaceIpv6Status( WinRouteErrorSink errorSink, void* errorSinkContext ); + +enum class TAP_GET_ALIAS_STATUS : uint32_t +{ + GENERAL_ERROR = 0, + SUCCESS = 1, +}; + + +// +// This has nothing to do with routing. +// We should probably rename this module and use it to gather one-off network functions. +// +extern "C" +WINROUTE_LINKAGE +TAP_GET_ALIAS_STATUS +WINROUTE_API +GetTapInterfaceAlias( + wchar_t **alias, + WinRouteErrorSink errorSink, + void* errorSinkContext +); + +// +// As of now, this is a companion function to the above function. +// Generically named in case we need other functions here that return strings. +// +extern "C" +WINROUTE_LINKAGE +void +WINROUTE_API +ReleaseString( + wchar_t *str +); diff --git a/windows/winroute/src/winroute/winroute.vcxproj b/windows/winroute/src/winroute/winroute.vcxproj index 09efb76938..e168887331 100644 --- a/windows/winroute/src/winroute/winroute.vcxproj +++ b/windows/winroute/src/winroute/winroute.vcxproj @@ -21,12 +21,14 @@ <ItemGroup> <ClCompile Include="dllmain.cpp" /> <ClCompile Include="InterfacePair.cpp" /> + <ClCompile Include="interfaceutils.cpp" /> <ClCompile Include="NetworkInterfaces.cpp" /> <ClCompile Include="stdafx.cpp" /> <ClCompile Include="winroute.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="InterfacePair.h" /> + <ClInclude Include="interfaceutils.h" /> <ClInclude Include="NetworkInterfaces.h" /> <ClInclude Include="stdafx.h" /> <ClInclude Include="targetver.h" /> diff --git a/windows/winroute/src/winroute/winroute.vcxproj.filters b/windows/winroute/src/winroute/winroute.vcxproj.filters index 216502d069..15b184cc7f 100644 --- a/windows/winroute/src/winroute/winroute.vcxproj.filters +++ b/windows/winroute/src/winroute/winroute.vcxproj.filters @@ -6,6 +6,7 @@ <ClCompile Include="winroute.cpp" /> <ClCompile Include="NetworkInterfaces.cpp" /> <ClCompile Include="InterfacePair.cpp" /> + <ClCompile Include="interfaceutils.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="stdafx.h" /> @@ -13,6 +14,7 @@ <ClInclude Include="winroute.h" /> <ClInclude Include="NetworkInterfaces.h" /> <ClInclude Include="InterfacePair.h" /> + <ClInclude Include="interfaceutils.h" /> </ItemGroup> <ItemGroup> <None Include="winroute.def" /> |
