From 5fcd49336812053aa1503078c0ebb72a2737a6b8 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:47 +0200 Subject: get_default_gateway_ipv6(): Win32 implementation using GetBestRoute2() To get access to that functionality, bump Windows API level for MinGW compilation from NTDDI_WINXP/_WIN32_WINNT_WINXP to ..._VISTA, and shuffle around WIN32 includes a bit in syshead.h MinGW 32 seems to be broken regarding MIB_TCP_STATE enum, so add typedef for that - surrounding #ifdefs found by googling do not work yet -> TODO! Extend add_route_ipv6() and delete_route_ipv6() to handle routes not on the tap adapter but on ifindex-addressed interfaces ("interface=nn"), and while at it, fix deletion of IPv6 routes with gateway address. NOTE: this breaks Windows XP compatibility as GetBestRoute2() is not available there, so even when not using IPv6, the binary will not run. (Lightly) tested on Win7/64. Signed-off-by: Gert Doering Lazy-ACK-by: Gert Doering Message-Id: <1441985627-14822-11-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10085 --- configure.ac | 2 +- src/openvpn/route.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++---- src/openvpn/syshead.h | 7 +++- 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 31cff25..2e651d8 100644 --- a/configure.ac +++ b/configure.ac @@ -348,7 +348,7 @@ case "$host" in AC_DEFINE([TARGET_WIN32], [1], [Are we running WIN32?]) AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["W"], [Target prefix]) CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN" - CPPFLAGS="${CPPFLAGS} -DNTDDI_VERSION=NTDDI_WINXP -D_WIN32_WINNT=_WIN32_WINNT_WINXP" + CPPFLAGS="${CPPFLAGS} -DNTDDI_VERSION=NTDDI_VISTA -D_WIN32_WINNT=_WIN32_WINNT_VISTA" WIN32=yes ;; *-*-dragonfly*) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 1b35396..096e3bc 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1767,6 +1767,14 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla #elif defined (WIN32) + if ( r6->adapter_index ) /* vpn server special route */ + { + struct buffer out = alloc_buf_gc (64, &gc); + buf_printf (&out, "interface=%d", r6->adapter_index ); + device = buf_bptr(&out); + gateway_needed = true; + } + /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s", get_win_sys_path(), @@ -1782,7 +1790,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla */ if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) argv_printf_cat( &argv, " %s", "fe80::8" ); - else + else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) argv_printf_cat( &argv, " %s", gateway ); #if 0 @@ -2157,6 +2165,14 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne #elif defined (WIN32) + if ( r6->adapter_index ) /* vpn server special route */ + { + struct buffer out = alloc_buf_gc (64, &gc); + buf_printf (&out, "interface=%d", r6->adapter_index ); + device = buf_bptr(&out); + gateway_needed = true; + } + /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s", get_win_sys_path(), @@ -2171,9 +2187,9 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne * knows about and will answer ND (neighbor discovery) packets for * (and "route deletion without specifying next-hop" does not work...) */ - if ( tt->type == DEV_TYPE_TUN ) + if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) argv_printf_cat( &argv, " %s", "fe80::8" ); - else + else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) argv_printf_cat( &argv, " %s", gateway ); #if 0 @@ -2497,15 +2513,79 @@ windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt return ret; } -/* IPv6 implementation using GetIpForwardTable2() and dynamic linking (TBD) - * https://msdn.microsoft.com/en-us/library/windows/desktop/aa814416(v=vs.85).aspx +/* IPv6 implementation using GetBestRoute2() + * (TBD: dynamic linking so the binary can still run on XP?) + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365922(v=vs.85).aspx + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa814411(v=vs.85).aspx */ void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, const struct in6_addr *dest) { - msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (windows)"); + struct gc_arena gc = gc_new (); + MIB_IPFORWARD_ROW2 BestRoute; + SOCKADDR_INET DestinationAddress, BestSourceAddress; + DWORD BestIfIndex; + DWORD status; + NET_LUID InterfaceLuid; + CLEAR(*rgi6); + CLEAR(InterfaceLuid); // cleared = not used for lookup + CLEAR(DestinationAddress); + + DestinationAddress.si_family = AF_INET6; + if ( dest ) + { + DestinationAddress.Ipv6.sin6_addr = *dest; + } + + status = GetBestInterfaceEx( &DestinationAddress, &BestIfIndex ); + + if (status != NO_ERROR) + { + msg (D_ROUTE, "NOTE: GetBestInterfaceEx returned error: %s (code=%u)", + strerror_win32 (status, &gc), + (unsigned int)status); + goto done; + } + + msg( D_ROUTE, "GetBestInterfaceEx() returned if=%d", (int) BestIfIndex ); + + status = GetBestRoute2( &InterfaceLuid, BestIfIndex, NULL, + &DestinationAddress, 0, + &BestRoute, &BestSourceAddress ); + + if (status != NO_ERROR) + { + msg (D_ROUTE, "NOTE: GetIpForwardEntry2 returned error: %s (code=%u)", + strerror_win32 (status, &gc), + (unsigned int)status); + goto done; + } + + msg( D_ROUTE, "GDG6: II=%d DP=%s/%d NH=%s", + BestRoute.InterfaceIndex, + print_in6_addr( BestRoute.DestinationPrefix.Prefix.Ipv6.sin6_addr, 0, &gc), + BestRoute.DestinationPrefix.PrefixLength, + print_in6_addr( BestRoute.NextHop.Ipv6.sin6_addr, 0, &gc) ); + msg( D_ROUTE, "GDG6: Metric=%d, Loopback=%d, AA=%d, I=%d", + (int) BestRoute.Metric, + (int) BestRoute.Loopback, + (int) BestRoute.AutoconfigureAddress, + (int) BestRoute.Immortal ); + + rgi6->gateway.addr_ipv6 = BestRoute.NextHop.Ipv6.sin6_addr; + rgi6->adapter_index = BestRoute.InterfaceIndex; + rgi6->flags |= RGI_ADDR_DEFINED | RGI_IFACE_DEFINED; + + /* on-link is signalled by receiving an empty (::) NextHop */ + if ( IN6_IS_ADDR_UNSPECIFIED(&BestRoute.NextHop.Ipv6.sin6_addr) ) + { + rgi6->flags |= RGI_ON_LINK; + } + + done: + gc_free (&gc); } bool diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 4bebb25..ba3b7e4 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -358,8 +358,13 @@ #endif /* TARGET_DARWIN */ #ifdef WIN32 -#include + // Missing declarations for MinGW 32. + // #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2 + typedef int MIB_TCP_STATE; + // #endif +#include #include +#include #include #include /* The following two headers are needed of PF_INET6 */ -- cgit