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 <g...@greenie.muc.de>
---
 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 51ef93b..0a8255c 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 d97968c..d45a02e 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -1757,6 +1757,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(),
@@ -1772,7 +1780,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
@@ -2144,6 +2152,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(),
@@ -2158,9 +2174,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
@@ -2485,15 +2501,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 ff0bf41..e00af48 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -358,8 +358,13 @@
 #endif /* TARGET_DARWIN */

 #ifdef WIN32
-#include <iphlpapi.h>
+ // Missing declarations for MinGW 32.
+ // #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2
+ typedef int MIB_TCP_STATE;
+ // #endif
+#include <naptypes.h>
 #include <ntddndis.h>
+#include <iphlpapi.h>
 #include <wininet.h>
 #include <shellapi.h>
 /* The following two headers are needed of PF_INET6 */
-- 
2.3.6


Reply via email to