summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2019-04-12 16:00:03 +0200
committerOdd Stranne <odd@mullvad.net>2019-04-17 14:10:39 +0200
commite2b85d01e51ea61aaccce31b9a032492cfd81932 (patch)
tree2d2d1aef73450ac7233fca0e5b6de749c0c27642
parent9ccc27bb67e29f55333187ea2949b8a307665c0a (diff)
downloadmullvadvpn-e2b85d01e51ea61aaccce31b9a032492cfd81932.tar.xz
mullvadvpn-e2b85d01e51ea61aaccce31b9a032492cfd81932.zip
Add function to fuzzily determine TAP alias
-rw-r--r--windows/winroute/src/winroute/interfaceutils.cpp127
-rw-r--r--windows/winroute/src/winroute/interfaceutils.h39
-rw-r--r--windows/winroute/src/winroute/stdafx.h3
-rw-r--r--windows/winroute/src/winroute/winroute.cpp54
-rw-r--r--windows/winroute/src/winroute/winroute.h33
-rw-r--r--windows/winroute/src/winroute/winroute.vcxproj2
-rw-r--r--windows/winroute/src/winroute/winroute.vcxproj.filters2
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" />