diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-09-11 19:20:25 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-11-09 14:54:58 +0100 |
| commit | c3921b60fd92e114368e1df07b977ec7178a5e65 (patch) | |
| tree | 286ed72b083e4993110686a5219aaff1cfc5be8b /windows | |
| parent | fc26f6223269889cf1d23579ac4ab07a2d603d4e (diff) | |
| download | mullvadvpn-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.cpp | 40 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/converters.h | 1 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/routing/helpers.cpp | 33 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/routing/helpers.h | 3 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/routing/routemanager.cpp | 7 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.cpp | 61 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.def | 1 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.h | 27 |
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 ); |
