summaryrefslogtreecommitdiffhomepage
path: root/windows
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-09-11 19:20:25 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-11-09 14:54:58 +0100
commitc3921b60fd92e114368e1df07b977ec7178a5e65 (patch)
tree286ed72b083e4993110686a5219aaff1cfc5be8b /windows
parentfc26f6223269889cf1d23579ac4ab07a2d603d4e (diff)
downloadmullvadvpn-c3921b60fd92e114368e1df07b977ec7178a5e65.tar.xz
mullvadvpn-c3921b60fd92e114368e1df07b977ec7178a5e65.zip
Add winnet function for obtaining the best default route
Diffstat (limited to 'windows')
-rw-r--r--windows/winnet/src/winnet/converters.cpp40
-rw-r--r--windows/winnet/src/winnet/converters.h1
-rw-r--r--windows/winnet/src/winnet/routing/helpers.cpp33
-rw-r--r--windows/winnet/src/winnet/routing/helpers.h3
-rw-r--r--windows/winnet/src/winnet/routing/routemanager.cpp7
-rw-r--r--windows/winnet/src/winnet/winnet.cpp61
-rw-r--r--windows/winnet/src/winnet/winnet.def1
-rw-r--r--windows/winnet/src/winnet/winnet.h27
8 files changed, 159 insertions, 14 deletions
diff --git a/windows/winnet/src/winnet/converters.cpp b/windows/winnet/src/winnet/converters.cpp
index 3584f8e34f..dc3f333c6c 100644
--- a/windows/winnet/src/winnet/converters.cpp
+++ b/windows/winnet/src/winnet/converters.cpp
@@ -37,6 +37,33 @@ SOCKADDR_INET IpToNative(const WINNET_IP &from)
return to;
}
+WINNET_IP IpFromNative(const SOCKADDR_INET &from)
+{
+ WINNET_IP to = { 0 };
+
+ switch (from.si_family)
+ {
+ case AF_INET:
+ {
+ *reinterpret_cast<uint32_t*>(to.bytes) = static_cast<uint32_t>(from.Ipv4.sin_addr.s_addr);
+ to.family = WINNET_ADDR_FAMILY_IPV4;
+ break;
+ }
+ case AF_INET6:
+ {
+ memcpy(to.bytes, from.Ipv6.sin6_addr.u.Byte, 16);
+ to.family = WINNET_ADDR_FAMILY_IPV6;
+ break;
+ }
+ default:
+ {
+ THROW_ERROR("Invalid network address family");
+ }
+ }
+
+ return to;
+}
+
} // anonymous namespace
namespace winnet
@@ -115,4 +142,17 @@ std::vector<SOCKADDR_INET> ConvertAddresses(const WINNET_IP *addresses, uint32_t
return out;
}
+std::vector<WINNET_IP> ConvertNativeAddresses(const SOCKADDR_INET *addresses, uint32_t numAddresses)
+{
+ std::vector<WINNET_IP> out;
+ out.reserve(numAddresses);
+
+ for (uint32_t i = 0; i < numAddresses; ++i)
+ {
+ out.emplace_back(IpFromNative(addresses[i]));
+ }
+
+ return out;
+}
+
}
diff --git a/windows/winnet/src/winnet/converters.h b/windows/winnet/src/winnet/converters.h
index 8a1c59e4da..e094728902 100644
--- a/windows/winnet/src/winnet/converters.h
+++ b/windows/winnet/src/winnet/converters.h
@@ -12,5 +12,6 @@ routing::Network ConvertNetwork(const WINNET_IP_NETWORK &in);
std::optional<routing::Node> ConvertNode(const WINNET_NODE *in);
std::vector<routing::Route> ConvertRoutes(const WINNET_ROUTE *routes, uint32_t numRoutes);
std::vector<SOCKADDR_INET> ConvertAddresses(const WINNET_IP *addresses, uint32_t numAddresses);
+std::vector<WINNET_IP> ConvertNativeAddresses(const SOCKADDR_INET *addresses, uint32_t numAddresses);
}
diff --git a/windows/winnet/src/winnet/routing/helpers.cpp b/windows/winnet/src/winnet/routing/helpers.cpp
index 2f171c08a1..9e46b203d4 100644
--- a/windows/winnet/src/winnet/routing/helpers.cpp
+++ b/windows/winnet/src/winnet/routing/helpers.cpp
@@ -6,6 +6,25 @@
#include <libcommon/error.h>
#include <libcommon/memory.h>
+namespace
+{
+
+bool IsRouteOnPhysicalInterface(const MIB_IPFORWARD_ROW2 &route)
+{
+ switch (route.InterfaceLuid.Info.IfType)
+ {
+ case IF_TYPE_SOFTWARE_LOOPBACK:
+ case IF_TYPE_TUNNEL:
+ case IF_TYPE_PROP_VIRTUAL:
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+} // anonymous namespace
+
namespace winnet::routing
{
@@ -124,7 +143,7 @@ bool RouteHasGateway(const MIB_IPFORWARD_ROW2 &route)
};
}
-InterfaceAndGateway GetBestDefaultRoute(ADDRESS_FAMILY family)
+std::optional<InterfaceAndGateway> GetBestDefaultRoute(ADDRESS_FAMILY family)
{
PMIB_IPFORWARD_TABLE2 table;
@@ -146,7 +165,8 @@ InterfaceAndGateway GetBestDefaultRoute(ADDRESS_FAMILY family)
candidates.reserve(table->NumEntries);
//
- // Enumerate routes looking for: route 0/0 && gateway specified.
+ // Enumerate routes looking for: route 0/0
+ // The WireGuard interface route has no gateway.
//
for (ULONG i = 0; i < table->NumEntries; ++i)
@@ -154,7 +174,8 @@ InterfaceAndGateway GetBestDefaultRoute(ADDRESS_FAMILY family)
const MIB_IPFORWARD_ROW2 &candidate = table->Table[i];
if (0 == candidate.DestinationPrefix.PrefixLength
- && RouteHasGateway(candidate))
+ && RouteHasGateway(candidate)
+ && IsRouteOnPhysicalInterface(candidate))
{
candidates.emplace_back(&candidate);
}
@@ -164,7 +185,7 @@ InterfaceAndGateway GetBestDefaultRoute(ADDRESS_FAMILY family)
if (annotated.empty())
{
- THROW_ERROR("Unable to determine details of default route");
+ return std::nullopt;
}
//
@@ -187,10 +208,10 @@ InterfaceAndGateway GetBestDefaultRoute(ADDRESS_FAMILY family)
if (false == annotated[0].active)
{
- THROW_ERROR("Unable to identify active default route");
+ return std::nullopt;
}
- return InterfaceAndGateway { annotated[0].route->InterfaceLuid, annotated[0].route->NextHop };
+ return std::make_optional(InterfaceAndGateway { annotated[0].route->InterfaceLuid, annotated[0].route->NextHop });
}
bool AdapterInterfaceEnabled(const IP_ADAPTER_ADDRESSES *adapter, ADDRESS_FAMILY family)
diff --git a/windows/winnet/src/winnet/routing/helpers.h b/windows/winnet/src/winnet/routing/helpers.h
index 37a0acc611..9d73585da9 100644
--- a/windows/winnet/src/winnet/routing/helpers.h
+++ b/windows/winnet/src/winnet/routing/helpers.h
@@ -2,6 +2,7 @@
#include "types.h"
#include <vector>
+#include <optional>
namespace winnet::routing
{
@@ -29,7 +30,7 @@ std::vector<AnnotatedRoute> AnnotateRoutes(const std::vector<const MIB_IPFORWARD
bool RouteHasGateway(const MIB_IPFORWARD_ROW2 &route);
-InterfaceAndGateway GetBestDefaultRoute(ADDRESS_FAMILY family);
+std::optional<InterfaceAndGateway> GetBestDefaultRoute(ADDRESS_FAMILY family);
bool AdapterInterfaceEnabled(const IP_ADAPTER_ADDRESSES *adapter, ADDRESS_FAMILY family);
diff --git a/windows/winnet/src/winnet/routing/routemanager.cpp b/windows/winnet/src/winnet/routing/routemanager.cpp
index 9d5b36ff98..dc38466440 100644
--- a/windows/winnet/src/winnet/routing/routemanager.cpp
+++ b/windows/winnet/src/winnet/routing/routemanager.cpp
@@ -125,7 +125,12 @@ InterfaceAndGateway ResolveNode(ADDRESS_FAMILY family, const std::optional<Node>
if (false == optionalNode.has_value())
{
- return GetBestDefaultRoute(family);
+ const auto default_route = GetBestDefaultRoute(family);
+ if (!default_route.has_value())
+ {
+ THROW_ERROR("Unable to determine details of default route");
+ }
+ return default_route.value();
}
const auto &node = optionalNode.value();
diff --git a/windows/winnet/src/winnet/winnet.cpp b/windows/winnet/src/winnet/winnet.cpp
index c52fc57d60..4532e43d14 100644
--- a/windows/winnet/src/winnet/winnet.cpp
+++ b/windows/winnet/src/winnet/winnet.cpp
@@ -94,6 +94,55 @@ WinNet_EnableIpv6ForAdapter(
extern "C"
WINNET_LINKAGE
+WINNET_GBDR_STATUS
+WINNET_API
+WinNet_GetBestDefaultRoute(
+ WINNET_ADDR_FAMILY family,
+ WINNET_DEFAULT_ROUTE *route,
+ MullvadLogSink logSink,
+ void *logSinkContext
+)
+{
+ try
+ {
+ if (nullptr == route)
+ {
+ THROW_ERROR("Invalid argument: route");
+ }
+
+ static const std::pair<WINNET_ADDR_FAMILY, ADDRESS_FAMILY> familyMap[] =
+ {
+ { WINNET_ADDR_FAMILY_IPV4, static_cast<ADDRESS_FAMILY>(AF_INET) },
+ { WINNET_ADDR_FAMILY_IPV6, static_cast<ADDRESS_FAMILY>(AF_INET6) }
+ };
+ const auto win_family = common::ValueMapper::Map<>(family, familyMap);
+
+ const auto ifaceAndGateway = GetBestDefaultRoute(win_family);
+
+ if (!ifaceAndGateway.has_value())
+ {
+ return WINNET_GBDR_STATUS_NOT_FOUND;
+ }
+
+ route->interfaceLuid = ifaceAndGateway->iface.Value;
+ const auto ips = winnet::ConvertNativeAddresses(&ifaceAndGateway->gateway, 1);
+ route->gateway = ips[0];
+
+ return WINNET_GBDR_STATUS_SUCCESS;
+ }
+ catch (const std::exception & err)
+ {
+ shared::logging::UnwindAndLog(logSink, logSinkContext, err);
+ return WINNET_GBDR_STATUS_FAILURE;
+ }
+ catch (...)
+ {
+ return WINNET_GBDR_STATUS_FAILURE;
+ }
+}
+
+extern "C"
+WINNET_LINKAGE
bool
WINNET_API
WinNet_GetTapInterfaceAlias(
@@ -480,22 +529,24 @@ WinNet_RegisterDefaultRouteChangedCallback(
const auto translatedFamily = common::ValueMapper::Map<>(family, familyMap);
+ WINNET_DEFAULT_ROUTE defaultRoute = { 0 };
+
//
- // Determine which LUID to forward.
+ // Determine which LUID and gateway to forward.
//
- uint64_t translatedLuid = 0;
-
if (RouteManager::DefaultRouteChangedEventType::Updated == eventType)
{
- translatedLuid = route.value().iface.Value;
+ const auto ips = winnet::ConvertNativeAddresses(&route.value().gateway, 1);
+ defaultRoute.gateway = ips[0];
+ defaultRoute.interfaceLuid = route.value().iface.Value;
}
//
// Forward to client.
//
- callback(translatedEventType, translatedFamily, translatedLuid, context);
+ callback(translatedEventType, translatedFamily, defaultRoute, context);
};
*registrationHandle = g_RouteManager->registerDefaultRouteChangedCallback(forwarder);
diff --git a/windows/winnet/src/winnet/winnet.def b/windows/winnet/src/winnet/winnet.def
index 5a1bbfe99f..187ce253d9 100644
--- a/windows/winnet/src/winnet/winnet.def
+++ b/windows/winnet/src/winnet/winnet.def
@@ -10,3 +10,4 @@ EXPORTS
WinNet_ActivateRouteManager
WinNet_DeactivateRouteManager
WinNet_AddDeviceIpAddresses
+ WinNet_GetBestDefaultRoute
diff --git a/windows/winnet/src/winnet/winnet.h b/windows/winnet/src/winnet/winnet.h
index 3597b01a26..c102ebdba3 100644
--- a/windows/winnet/src/winnet/winnet.h
+++ b/windows/winnet/src/winnet/winnet.h
@@ -180,6 +180,31 @@ WINNET_API
WinNet_DeleteAppliedRoutes(
);
+typedef struct tag_WINNET_DEFAULT_ROUTE
+{
+ uint64_t interfaceLuid;
+ WINNET_IP gateway;
+}
+WINNET_DEFAULT_ROUTE;
+
+enum WINNET_GBDR_STATUS
+{
+ WINNET_GBDR_STATUS_SUCCESS = 0,
+ WINNET_GBDR_STATUS_NOT_FOUND = 1,
+ WINNET_GBDR_STATUS_FAILURE = 2,
+};
+
+extern "C"
+WINNET_LINKAGE
+WINNET_GBDR_STATUS
+WINNET_API
+WinNet_GetBestDefaultRoute(
+ WINNET_ADDR_FAMILY family,
+ WINNET_DEFAULT_ROUTE *route,
+ MullvadLogSink logSink,
+ void *logSinkContext
+);
+
enum WINNET_DEFAULT_ROUTE_CHANGED_EVENT_TYPE
{
// Best default route changed.
@@ -197,7 +222,7 @@ typedef void (WINNET_API *WinNetDefaultRouteChangedCallback)
WINNET_ADDR_FAMILY family,
// For update events, indicates the interface associated with the new best default route.
- uint64_t interfaceLuid,
+ WINNET_DEFAULT_ROUTE route,
void *context
);