Attention is currently required from: flichtenheld, plaisthos.

Hello plaisthos, flichtenheld,

I'd like you to do a code review.
Please visit

    http://gerrit.openvpn.net/c/openvpn/+/901?usp=email

to review the following change.


Change subject: redirect-gateway: add route toward new remote host when using 
persist-tun
......................................................................

redirect-gateway: add route toward new remote host when using persist-tun

When both --redirect-gateway and --persist-tun are used together,
a route must be added for each new remote host we attempt to connect to.

Change-Id: Ic7b486ccb85df7fc1d6a573ac1315d235728822c
Signed-off-by: Marco Baffo <ma...@mandelbit.com>
---
M src/openvpn/init.c
M src/openvpn/route.c
M src/openvpn/route.h
3 files changed, 188 insertions(+), 22 deletions(-)



  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/01/901/1

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index b57e5f8..63b7bbf 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -2184,6 +2184,10 @@
                         "route-pre-down",
                         c->c2.es);

+            if (c->mode == CM_P2P && c->options.persist_tun)
+            {
+                del_route_towards_remote(c);
+            }
             delete_routes(c->c1.route_list, c->c1.route_ipv6_list,
                           c->c1.tuntap, ROUTE_OPTION_FLAGS(&c->options),
                           c->c2.es, &c->net_ctx);
@@ -2245,6 +2249,11 @@
                         c->c2.es);
         }

+        if (c->mode == CM_P2P && c->options.persist_tun)
+        {
+            del_route_towards_remote(c);
+        }
+
         del_wfp_block(c, adapter_index);
     }
     gc_free(&gc);
@@ -4825,6 +4834,17 @@
         }
     }

+    /**
+     * When using both --redirect-gateway and --persist-tun,
+     * if the connection to the server is lost, a /32 (or /128 if IPv6) route 
must be added
+     * to ensure connectivity to the next remote.
+     */
+    if (c->mode == CM_P2P
+        && c->options.persist_tun)
+    {
+        add_route_towards_remote(c);
+    }
+
     /*
      * Actually do UID/GID downgrade, and chroot, if requested.
      * May be delayed by --client, --pull, or --up-delay.
diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index bc41492..1e4deb5 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -43,6 +43,7 @@
 #include "options.h"
 #include "networking.h"
 #include "integer.h"
+#include "openvpn.h"

 #include "memdbg.h"

@@ -884,30 +885,14 @@
     }

     /* add VPN server host route if needed */
-    if (need_remote_ipv6_route)
+    if (need_remote_ipv6_route
+        && !(rl6->iflags & RL_DID_LOCAL))
     {
         if ( (rl6->rgi6.flags & (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) ==
              (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) )
         {
-            struct route_ipv6 *r6;
-            ALLOC_OBJ_CLEAR_GC(r6, struct route_ipv6, &rl6->gc);
-
-            r6->network = *remote_host_ipv6;
-            r6->netbits = 128;
-            if (!(rl6->rgi6.flags & RGI_ON_LINK) )
-            {
-                r6->gateway = rl6->rgi6.gateway.addr_ipv6;
-            }
-            r6->metric = 1;
-#ifdef _WIN32
-            r6->adapter_index = rl6->rgi6.adapter_index;
-#else
-            r6->iface = rl6->rgi6.iface;
-#endif
-            r6->flags = RT_DEFINED | RT_METRIC_DEFINED;
-
-            r6->next = rl6->routes_ipv6;
-            rl6->routes_ipv6 = r6;
+            rl6->routes_ipv6 = create_host_route_ipv6(*remote_host_ipv6, rl6);
+            rl6->iflags |= RL_DID_LOCAL;
         }
         else
         {
@@ -919,6 +904,30 @@
     return ret;
 }

+struct route_ipv6 *
+create_host_route_ipv6(struct in6_addr remote_host_ipv6, struct 
route_ipv6_list *rl6)
+{
+    struct route_ipv6 *r6;
+    ALLOC_OBJ_CLEAR_GC(r6, struct route_ipv6, &rl6->gc);
+
+    r6->network = remote_host_ipv6;
+    r6->netbits = 128;
+    if (!(rl6->rgi6.flags & RGI_ON_LINK) )
+    {
+        r6->gateway = rl6->rgi6.gateway.addr_ipv6;
+    }
+    r6->metric = 1;
+#ifdef _WIN32
+    r6->adapter_index = rl6->rgi6.adapter_index;
+#else
+    r6->iface = rl6->rgi6.iface;
+#endif
+    r6->flags = RT_DEFINED | RT_METRIC_DEFINED;
+    r6->next = rl6->routes_ipv6;
+
+    return r6;
+}
+
 static bool
 add_route3(in_addr_t network,
            in_addr_t netmask,
@@ -1055,7 +1064,8 @@
                 /* if remote_host is not ipv4 (ie: ipv6), just skip
                  * adding this special /32 route */
                 if ((rl->spec.flags & RTSA_REMOTE_HOST)
-                    && rl->spec.remote_host != IPV4_INVALID_ADDR)
+                    && rl->spec.remote_host != IPV4_INVALID_ADDR
+                    && !(rl->iflags & RL_DID_LOCAL))
                 {
                     ret = add_route3(rl->spec.remote_host, IPV4_NETMASK_HOST,
                                      rl->rgi.gateway.addr, tt, flags | 
ROUTE_REF_GW,
@@ -1282,7 +1292,7 @@
         {
             delete_route_ipv6(r6, tt, flags, es, ctx);
         }
-        rl6->iflags &= ~RL_ROUTES_ADDED;
+        rl6->iflags &= ~(RL_ROUTES_ADDED | RL_DID_LOCAL);
     }

     if (rl6)
@@ -1291,6 +1301,131 @@
     }
 }

+void
+add_route_towards_remote(struct context *c)
+{
+    ASSERT(c->c1.link_socket_addrs);
+
+    int current_remote_family = 
c->c1.link_socket_addrs[0].actual.dest.addr.sa.sa_family;
+
+    if (current_remote_family == AF_INET && c->c1.route_list
+        && (c->c1.route_list->flags & RG_REROUTE_GW))
+    {
+        if (c->c1.route_list->iflags & RL_DID_LOCAL)
+        {
+            del_route_towards_remote(c);
+        }
+
+        in_addr_t current_remote = 
ntohl(c->c1.link_socket_addrs[0].actual.dest.addr.in4.sin_addr.s_addr);
+
+        if (add_route3(current_remote,
+                       IPV4_NETMASK_HOST,
+                       c->c1.route_list->rgi.gateway.addr,
+                       c->c1.tuntap,
+                       ROUTE_OPTION_FLAGS(&c->options) | ROUTE_REF_GW,
+                       &c->c1.route_list->rgi,
+                       c->c2.es,
+                       &c->net_ctx))
+        {
+            c->c1.route_list->iflags |= RL_DID_LOCAL;
+            c->c1.route_list->spec.remote_host = current_remote;
+        }
+    }
+    else if (current_remote_family == AF_INET6 && c->c1.route_ipv6_list
+             && (c->c1.route_ipv6_list->flags & RG_REROUTE_GW))
+    {
+        if (c->c1.route_ipv6_list->iflags & RL_DID_LOCAL)
+        {
+            del_route_towards_remote(c);
+        }
+
+        const struct in6_addr *remote_host_ipv6 = 
&(c->c1.link_socket_addrs[0].actual.dest.addr.in6.sin6_addr);
+        struct route_ipv6_list *rl6 = c->c1.route_ipv6_list;
+
+        if ((rl6->rgi6.flags & (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED)) ==
+            (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED))
+        {
+            struct route_ipv6 *r6 = create_host_route_ipv6(*remote_host_ipv6, 
rl6);
+
+            if (add_route_ipv6(r6, c->c1.tuntap,
+                               ROUTE_OPTION_FLAGS(&c->options), c->c2.es, 
&c->net_ctx))
+            {
+                rl6->routes_ipv6 = r6;
+                rl6->iflags |= RL_DID_LOCAL;
+            }
+        }
+        else
+        {
+            msg(M_WARN, "ROUTE6: IPv6 route overlaps with IPv6 remote address, 
but could not determine IPv6 gateway address + interface, expect failure\n" );
+        }
+    }
+}
+
+void
+del_route_towards_remote(struct context *c)
+{
+    /* If the function is called from do_close_tun() it means that the socket
+     * has already been closed and c->c2.link_sockets[0]->info.lsa` used in
+     * `add_route_towards_remote()` cleaned up. So we should use
+     * `c->c1.link_socket_addrs[0]` instead.
+     */
+    ASSERT(c->c1.link_socket_addrs);
+
+    int current_remote_family = 0;
+
+    if (c->c1.link_socket_addrs[0].actual.dest.addr.sa.sa_family)
+    {
+        current_remote_family = 
c->c1.link_socket_addrs[0].actual.dest.addr.sa.sa_family;
+    }
+    else if (c->c1.link_socket_addrs[0].current_remote)
+    {
+        current_remote_family = 
c->c1.link_socket_addrs[0].current_remote->ai_family;
+    }
+
+    if (current_remote_family == AF_INET && c->c1.route_list
+        && (c->c1.route_list->flags & RG_REROUTE_GW)
+        && (c->c1.route_list->iflags & RL_DID_LOCAL))
+    {
+        del_route3(c->c1.route_list->spec.remote_host,
+                   IPV4_NETMASK_HOST,
+                   c->c1.route_list->rgi.gateway.addr,
+                   c->c1.tuntap,
+                   ROUTE_OPTION_FLAGS(&c->options) | ROUTE_REF_GW,
+                   &c->c1.route_list->rgi,
+                   c->c2.es,
+                   &c->net_ctx);
+        c->c1.route_list->iflags &= ~RL_DID_LOCAL;
+    }
+    else if (current_remote_family == AF_INET6 && c->c1.route_ipv6_list
+             && (c->c1.route_ipv6_list->flags & RG_REROUTE_GW)
+             && (c->c1.route_ipv6_list->iflags & RL_DID_LOCAL))
+    {
+        struct in6_addr *remote_host_ipv6 = 
&c->c1.route_ipv6_list->remote_host_ipv6;
+        struct route_ipv6 *host_route = 
create_host_route_ipv6(*remote_host_ipv6, c->c1.route_ipv6_list);
+
+        for (struct route_ipv6 *prev = NULL, *r6 = 
c->c1.route_ipv6_list->routes_ipv6; r6; r6 = r6->next)
+        {
+            if (memcmp(&r6->network, &host_route->network, sizeof(struct 
in6_addr))
+                || r6->netbits != host_route->netbits
+                || memcmp(&r6->gateway, &host_route->gateway, sizeof(struct 
in6_addr)))
+            {
+                continue;
+            }
+
+            delete_route_ipv6(r6, c->c1.tuntap, 
ROUTE_OPTION_FLAGS(&c->options), c->c2.es, &c->net_ctx);
+            if (!prev)
+            {
+                c->c1.route_ipv6_list->routes_ipv6 = r6->next;
+            }
+            else
+            {
+                prev->next = r6->next;
+            }
+            c->c1.route_ipv6_list->iflags &= ~RL_DID_LOCAL;
+        }
+    }
+}
+
 #ifndef ENABLE_SMALL

 static const char *
diff --git a/src/openvpn/route.h b/src/openvpn/route.h
index 98ea79e..b1b23f9 100644
--- a/src/openvpn/route.h
+++ b/src/openvpn/route.h
@@ -286,6 +286,14 @@
                const struct route_gateway_info *rgi, const struct env_set *es,
                openvpn_net_ctx_t *ctx);

+/* Function to add a route towards the new remote when using
+ * `--redirect-gateway` and `--persist-tun` options together. */
+void add_route_towards_remote(struct context *c);
+
+/* Function to delete the route towards the remote when using
+ * `--redirect-gateway` and `--persist-tun` options together. */
+void del_route_towards_remote(struct context *c);
+
 void add_route_to_option_list(struct route_option_list *l,
                               const char *network,
                               const char *netmask,
@@ -353,6 +361,9 @@
                            const struct route_gateway_info *rgi,
                            const struct route_ipv6_gateway_info *rgi6);

+/* Return a `route_ipv6 *` /128 IPv6 route toward the remote host */
+struct route_ipv6 *create_host_route_ipv6(struct in6_addr remote_host_ipv6, 
struct route_ipv6_list *rl6);
+
 /*
  * Test if addr is reachable via a local interface (return ILA_LOCAL),
  * or if it needs to be routed via the default gateway (return

--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/901?usp=email
To unsubscribe, or for help writing mail filters, visit 
http://gerrit.openvpn.net/settings

Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: Ic7b486ccb85df7fc1d6a573ac1315d235728822c
Gerrit-Change-Number: 901
Gerrit-PatchSet: 1
Gerrit-Owner: mrbff <ma...@mandelbit.com>
Gerrit-Reviewer: flichtenheld <fr...@lichtenheld.com>
Gerrit-Reviewer: plaisthos <arne-open...@rfc2549.org>
Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net>
Gerrit-Attention: plaisthos <arne-open...@rfc2549.org>
Gerrit-Attention: flichtenheld <fr...@lichtenheld.com>
Gerrit-MessageType: newchange
_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to