Attention is currently required from: flichtenheld, mrbff.

Hello flichtenheld, plaisthos,

I'd like you to reexamine a change. Please visit

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

to look at the new patch set (#12).


Change subject: route: extended logic to omit gateway when unnecessary
......................................................................

route: extended logic to omit gateway when unnecessary

Extracted and extended the logic behind gateway_needed both in
add_route() and add_route_ipv6(). Checking dev-type, special
routes, if the gateway is on-link and if the gateway is in the
vpn subnet. Additionally, extended support for these checks and
conditions to DARWIN and BSD-based operating systems.

These changes ensure that the gateway is only included when
necessary, optimizing route configuration and potentially
reducing redundant route entries.

Additionally, Dragonfly's do_ifconfig_ipv4() code is now shared
with NetBSD's, rather than FreeBSD's.

Change-Id: I87777e74b1fd34781e1d72c9f994eb84f39d800c
Signed-off-by: Marco Baffo <[email protected]>
---
M src/openvpn/route.c
M src/openvpn/tun.c
2 files changed, 210 insertions(+), 130 deletions(-)


  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/21/721/12

diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index c249b38..4dc4005 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -42,6 +42,7 @@
 #include "options.h"
 #include "networking.h"
 #include "integer.h"
+#include "openvpn.h"

 #include "memdbg.h"

@@ -1396,6 +1397,7 @@
     }
     gc_free(&gc);
 }
+
 void
 setenv_routes_ipv6(struct env_set *es, const struct route_ipv6_list *rl6)
 {
@@ -1472,6 +1474,37 @@
 }
 #endif

+static bool
+is_gateway_needed_ipv4(const struct route_ipv4 *r4,
+                       const struct route_gateway_info *rgi,
+                       const struct tuntap *tt)
+{
+#ifndef _WIN32
+    /* server told us which interface to use; pass gateway if it gave one */
+    if (rgi && (rgi->flags & RGI_IFACE_DEFINED) && rgi->iface[0] != 0)
+    {
+        if (rgi->flags & RGI_ADDR_DEFINED && r4->gateway != 0)
+        {
+            return true;
+        }
+    }
+#endif
+
+    /* TAP is an L2 device, so for destinations that are not explicitly
+     * on-link the kernel needs a gateway so it can ARP/ND for the
+     * MAC address. We make an exception only when the user explicitly sets
+     * metric 0, which is taken as a request for an on-link “route to
+     * interface” (no gateway). This keeps parity with the IPv6 code.
+     */
+    if (tt->type == DEV_TYPE_TAP
+        && !((r4->flags & RT_METRIC_DEFINED) && r4->metric == 0))
+    {
+        return true;
+    }
+
+    return false;
+}
+
 bool
 add_route(struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags,
           const struct route_gateway_info *rgi, /* may be NULL */
@@ -1503,28 +1536,7 @@
         goto done;
     }

-#ifndef _WIN32
-    /* server told us which interface to use; pass gateway if it gave one */
-    if (rgi && (rgi->flags & RGI_IFACE_DEFINED) && rgi->iface[0] != 0)
-    {
-        if (rgi->flags & RGI_ADDR_DEFINED && r->gateway != 0)
-        {
-            gateway_needed = true;
-        }
-    }
-#endif
-
-    /* TAP is an L2 device, so for destinations that are not explicitly
-     * on-link the kernel needs a gateway so it can ARP/ND for the
-     * MAC address. We make an exception only when the user explicitly sets
-     * metric 0, which is taken as a request for an on-link “route to
-     * interface” (no gateway). This keeps parity with the IPv6 code.
-     */
-    if (tt->type == DEV_TYPE_TAP
-        && !((r->flags & RT_METRIC_DEFINED) && r->metric == 0))
-    {
-        gateway_needed = true;
-    }
+    gateway_needed = is_gateway_needed_ipv4(r, rgi, tt);

     if (gateway_needed && r->gateway == 0)
     {
@@ -1537,18 +1549,21 @@
         goto done;
     }

-#if defined(TARGET_LINUX)
-    const char *iface = tt->actual_name;
+#if !defined(_WIN32) && !defined(TARGET_SOLARIS) \
+    && !defined(TARGET_AIX)
+    const char *device = tt->actual_name;
     if (!gateway_needed && rgi && (rgi->flags & RGI_IFACE_DEFINED) && 
rgi->iface[0] != 0) /* vpn server special route */
     {
-        iface = rgi->iface;
+        device = rgi->iface;
     }
+#endif

+#if defined(TARGET_LINUX)
     int metric = -1;

     if (is_on_link(is_local_route, flags, rgi))
     {
-        iface = rgi->iface;
+        device = rgi->iface;
     }

     if (r->flags & RT_METRIC_DEFINED)
@@ -1560,7 +1575,7 @@
     status = RTA_SUCCESS;
     int ret = net_route_v4_add(ctx, &r->network, 
netmask_to_netbits2(r->netmask),
                                gateway_needed ? &r->gateway : NULL,
-                               iface, r->table_id, metric);
+                               device, r->table_id, metric);
     if (ret == -EEXIST)
     {
         msg(D_ROUTE, "NOTE: Linux route add command failed because route 
exists");
@@ -1577,7 +1592,7 @@

     if (rgi)
     {
-        snprintf(out, sizeof(out), "%s %s %s dev %s", network, netmask, 
gateway, rgi->iface);
+        snprintf(out, sizeof(out), "%s %s %s dev %s", network, netmask, 
gateway, device);
     }
     else
     {
@@ -1672,7 +1687,7 @@
     bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route add 
command failed");
     status = ret ? RTA_SUCCESS : RTA_ERROR;

-#elif defined(TARGET_FREEBSD)
+#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)

     argv_printf(&argv, "%s add", ROUTE_PATH);

@@ -1683,31 +1698,18 @@
     }
 #endif

-    argv_printf_cat(&argv, "-net %s %s %s", network, gateway, netmask);
-
-    /* FIXME -- add on-link support for FreeBSD */
-
-    argv_msg(D_ROUTE, &argv);
-    bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: FreeBSD route add 
command failed");
-    status = ret ? RTA_SUCCESS : RTA_ERROR;
-
-#elif defined(TARGET_DRAGONFLY)
-
-    argv_printf(&argv, "%s add", ROUTE_PATH);
-
-#if 0
-    if (r->flags & RT_METRIC_DEFINED)
+    if (gateway_needed)
     {
-        argv_printf_cat(&argv, "-rtt %d", r->metric);
+        argv_printf_cat(&argv, "-net %s %s %s", network, gateway, netmask);
     }
-#endif
-
-    argv_printf_cat(&argv, "-net %s %s %s", network, gateway, netmask);
-
-    /* FIXME -- add on-link support for Dragonfly */
+    else
+    {
+        argv_printf_cat(&argv, "-net %s -iface %s", network, device);
+    }

     argv_msg(D_ROUTE, &argv);
-    bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: DragonFly route add 
command failed");
+    bool ret = openvpn_execve_check(&argv, es, 0,
+                                    "ERROR: BSD route add command failed");
     status = ret ? RTA_SUCCESS : RTA_ERROR;

 #elif defined(TARGET_DARWIN)
@@ -1730,7 +1732,14 @@
     }
     else
     {
-        argv_printf_cat(&argv, "-net %s %s %s", network, gateway, netmask);
+        if (gateway_needed)
+        {
+            argv_printf_cat(&argv, "-net %s %s %s", network, gateway, netmask);
+        }
+        else
+        {
+            argv_printf_cat(&argv, "-net %s -interface %s", network, device);
+        }
     }

     argv_msg(D_ROUTE, &argv);
@@ -1748,9 +1757,14 @@
     }
 #endif

-    argv_printf_cat(&argv, "-net %s %s -netmask %s", network, gateway, 
netmask);
-
-    /* FIXME -- add on-link support for OpenBSD/NetBSD */
+    if (gateway_needed)
+    {
+        argv_printf_cat(&argv, "-net %s %s -netmask %s", network, gateway, 
netmask);
+    }
+    else
+    {
+        argv_printf_cat(&argv, "-net %s -netmask %s -link -iface %s", network, 
netmask, device);
+    }

     argv_msg(D_ROUTE, &argv);
     bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route 
add command failed");
@@ -1827,6 +1841,47 @@
     }
 }

+static bool
+is_gateway_needed_ipv6(const struct route_ipv6 *r6,
+                       const struct tuntap *tt,
+                       const char *network)
+{
+#ifndef _WIN32
+    if (r6->iface != NULL) /* VPN server special route */
+    {
+        if (!IN6_IS_ADDR_UNSPECIFIED(&r6->gateway))
+        {
+            return true;
+        }
+    }
+#endif
+
+    /*
+     * Filter out routes which are essentially no-ops
+     * (not currently done for IPv6)
+     */
+
+    /* On "tun" interface, we never set a gateway if the operating system
+     * can do "route to interface" - it does not add value, as the target
+     * dev already fully qualifies the route destination on point-to-point
+     * interfaces.   OTOH, on "tap" interface, we must always set the
+     * gateway unless the route is to be an on-link network
+     */
+    if (tt->type == DEV_TYPE_TAP
+        && !((r6->flags & RT_METRIC_DEFINED) && r6->metric == 0))
+    {
+        return true;
+    }
+
+    if (ipv6_net_contains_host(&tt->local_ipv6, tt->netbits_ipv6, 
&r6->gateway))
+    {
+        msg(D_ROUTE, "Ignoring gateway in VPN subnet for route %s/%d", 
network, r6->netbits);
+        return false;
+    }
+
+    return false;
+}
+
 bool
 add_route_ipv6(struct route_ipv6 *r6, const struct tuntap *tt, unsigned int 
flags,
                const struct env_set *es, openvpn_net_ctx_t *ctx)
@@ -1842,22 +1897,12 @@
     struct argv argv = argv_new();
     struct gc_arena gc = gc_new();

-#ifndef _WIN32
-    const char *device = tt->actual_name;
-    if (r6->iface != NULL) /* vpn server special route */
-    {
-        device = r6->iface;
-        if (!IN6_IS_ADDR_UNSPECIFIED(&r6->gateway))
-        {
-            gateway_needed = true;
-        }
-    }
-#endif
-
     route_ipv6_clear_host_bits(r6);
     const char *network = print_in6_addr(r6->network, 0, &gc);
     const char *gateway = print_in6_addr(r6->gateway, 0, &gc);

+    gateway_needed = is_gateway_needed_ipv6(r6, tt, network);
+
 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || 
defined(TARGET_DRAGONFLY) \
     || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)

@@ -1875,6 +1920,15 @@
     }
 #endif

+#if !defined(_WIN32)
+
+    const char *device = tt->actual_name;
+    if (r6->iface != NULL)
+    {
+        device = r6->iface;
+    }
+#endif
+
 #ifndef _WIN32
     msg(D_ROUTE, "add_route_ipv6(%s/%d -> %s metric %d) dev %s", network, 
r6->netbits, gateway,
         r6->metric, device);
@@ -1883,22 +1937,6 @@
         r6->metric, r6->adapter_index ? r6->adapter_index : tt->adapter_index);
 #endif

-    /*
-     * Filter out routes which are essentially no-ops
-     * (not currently done for IPv6)
-     */
-
-    /* On "tun" interface, we never set a gateway if the operating system
-     * can do "route to interface" - it does not add value, as the target
-     * dev already fully qualifies the route destination on point-to-point
-     * interfaces.   OTOH, on "tap" interface, we must always set the
-     * gateway unless the route is to be an on-link network
-     */
-    if (tt->type == DEV_TYPE_TAP && !((r6->flags & RT_METRIC_DEFINED) && 
r6->metric == 0))
-    {
-        gateway_needed = true;
-    }
-
     if (gateway_needed && IN6_IS_ADDR_UNSPECIFIED(&r6->gateway))
     {
         msg(M_WARN,
@@ -1913,6 +1951,7 @@

 #if defined(TARGET_LINUX)
     int metric = -1;
+
     if ((r6->flags & RT_METRIC_DEFINED) && (r6->metric > 0))
     {
         metric = r6->metric;
@@ -2008,21 +2047,21 @@
     bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: MacOS X route add 
-inet6 command failed");
     status = ret ? RTA_SUCCESS : RTA_ERROR;

-#elif defined(TARGET_OPENBSD)
+#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)

-    argv_printf(&argv, "%s add -inet6 %s -prefixlen %d %s", ROUTE_PATH, 
network, r6->netbits,
-                gateway);
+    argv_printf(&argv, "%s add -inet6 %s -prefixlen %d ", ROUTE_PATH, network, 
r6->netbits);
+
+    if (gateway_needed)
+    {
+        argv_printf_cat(&argv, "%s", gateway);
+    }
+    else
+    {
+        argv_printf_cat(&argv, "-link -iface %s", device);
+    }

     argv_msg(D_ROUTE, &argv);
-    bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD route add 
-inet6 command failed");
-    status = ret ? RTA_SUCCESS : RTA_ERROR;
-
-#elif defined(TARGET_NETBSD)
-
-    argv_printf(&argv, "%s add -inet6 %s/%d %s", ROUTE_PATH, network, 
r6->netbits, gateway);
-
-    argv_msg(D_ROUTE, &argv);
-    bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: NetBSD route add 
-inet6 command failed");
+    bool ret = openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route 
add -inet6 command failed");
     status = ret ? RTA_SUCCESS : RTA_ERROR;

 #elif defined(TARGET_AIX)
@@ -2080,6 +2119,21 @@
 #endif
     int is_local_route;

+#if defined(TARGET_DARWIN) || defined(TARGET_LINUX)         \
+    || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \
+    || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
+
+    bool gateway_needed = is_gateway_needed_ipv4(r, rgi, tt);
+
+#if !defined(TARGET_OPENBSD) && !defined(TARGET_NETBSD)
+    const char *device = tt->actual_name;
+    if (!gateway_needed && rgi && (rgi->flags & RGI_IFACE_DEFINED) && 
rgi->iface[0] != 0) /* vpn server special route */
+    {
+        device = rgi->iface;
+    }
+#endif
+#endif
+
     if ((r->flags & (RT_DEFINED | RT_ADDED)) != (RT_DEFINED | RT_ADDED))
     {
         return;
@@ -2106,12 +2160,19 @@

 #if defined(TARGET_LINUX)
     metric = -1;
+
+    if (is_on_link(is_local_route, flags, rgi))
+    {
+        device = rgi->iface;
+    }
+
     if (r->flags & RT_METRIC_DEFINED)
     {
         metric = r->metric;
     }

-    if (net_route_v4_del(ctx, &r->network, netmask_to_netbits2(r->netmask), 
&r->gateway, NULL,
+    if (net_route_v4_del(ctx, &r->network, netmask_to_netbits2(r->netmask),
+                         gateway_needed ? &r->gateway : NULL, device,
                          r->table_id, metric)
         < 0)
     {
@@ -2165,19 +2226,21 @@
     argv_msg(D_ROUTE, &argv);
     openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete command 
failed");

-#elif defined(TARGET_FREEBSD)
+#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)

-    argv_printf(&argv, "%s delete -net %s %s %s", ROUTE_PATH, network, 
gateway, netmask);
+    argv_printf(&argv, "%s delete", ROUTE_PATH);
+
+    if (gateway_needed)
+    {
+        argv_printf_cat(&argv, "-net %s %s %s", network, gateway, netmask);
+    }
+    else
+    {
+        argv_printf_cat(&argv, "-net %s -iface %s", network, device);
+    }

     argv_msg(D_ROUTE, &argv);
-    openvpn_execve_check(&argv, es, 0, "ERROR: FreeBSD route delete command 
failed");
-
-#elif defined(TARGET_DRAGONFLY)
-
-    argv_printf(&argv, "%s delete -net %s %s %s", ROUTE_PATH, network, 
gateway, netmask);
-
-    argv_msg(D_ROUTE, &argv);
-    openvpn_execve_check(&argv, es, 0, "ERROR: DragonFly route delete command 
failed");
+    openvpn_execve_check(&argv, es, 0, "ERROR: BSD route delete command 
failed");

 #elif defined(TARGET_DARWIN)

@@ -2188,7 +2251,16 @@
     }
     else
     {
-        argv_printf(&argv, "%s delete -net %s %s %s", ROUTE_PATH, network, 
gateway, netmask);
+        argv_printf(&argv, "%s delete ", ROUTE_PATH);
+
+        if (gateway_needed)
+        {
+            argv_printf_cat(&argv, "-net %s %s %s", network, gateway, netmask);
+        }
+        else
+        {
+            argv_printf_cat(&argv, "-net %s -interface %s", network, device);
+        }
     }

     argv_msg(D_ROUTE, &argv);
@@ -2196,7 +2268,16 @@

 #elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)

-    argv_printf(&argv, "%s delete -net %s %s -netmask %s", ROUTE_PATH, 
network, gateway, netmask);
+    argv_printf(&argv, "%s delete ", ROUTE_PATH);
+
+    if (gateway_needed)
+    {
+        argv_printf_cat(&argv, "-net %s %s -netmask %s", network, gateway, 
netmask);
+    }
+    else
+    {
+        argv_printf_cat(&argv, "-net %s -netmask %s", network, netmask);
+    }

     argv_msg(D_ROUTE, &argv);
     openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete 
command failed");
@@ -2250,23 +2331,16 @@
 #if !defined(TARGET_LINUX)
     const char *gateway;
 #endif
-#if !defined(TARGET_SOLARIS)
-    bool gateway_needed = false;
+#if defined(TARGET_DARWIN) || defined(TARGET_LINUX) \
+    || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
+
     const char *device = tt->actual_name;
     if (r6->iface != NULL) /* vpn server special route */
     {
         device = r6->iface;
-        gateway_needed = true;
     }
     (void)device; /* unused on some platforms */

-    /* if we used a gateway on "add route", we also need to specify it on
-     * delete, otherwise some OSes will refuse to delete the route
-     */
-    if (tt->type == DEV_TYPE_TAP && !((r6->flags & RT_METRIC_DEFINED) && 
r6->metric == 0))
-    {
-        gateway_needed = true;
-    }
 #endif
 #endif

@@ -2278,6 +2352,15 @@
     gateway = print_in6_addr(r6->gateway, 0, &gc);
 #endif

+#if defined(TARGET_DARWIN) || defined(TARGET_LINUX) || defined(TARGET_FREEBSD) 
\
+    || defined(TARGET_DRAGONFLY) || defined(TARGET_OPENBSD) || 
defined(TARGET_NETBSD)
+    /* if we used a gateway on "add route", we also need to specify it on
+     * delete, otherwise some OSes will refuse to delete the route
+     */
+    bool gateway_needed = false;
+    gateway_needed = is_gateway_needed_ipv6(r6, tt, network);
+#endif
+
 #if defined(TARGET_DARWIN) || defined(TARGET_FREEBSD) || 
defined(TARGET_DRAGONFLY) \
     || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)

@@ -2362,20 +2445,17 @@
     argv_msg(D_ROUTE, &argv);
     openvpn_execve_check(&argv, es, 0, "ERROR: MacOS X route delete -inet6 
command failed");

-#elif defined(TARGET_OPENBSD)
+#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)

-    argv_printf(&argv, "%s delete -inet6 %s -prefixlen %d %s", ROUTE_PATH, 
network, r6->netbits,
-                gateway);
+    argv_printf(&argv, "%s delete -inet6 %s -prefixlen %d", ROUTE_PATH, 
network, r6->netbits);
+
+    if (gateway_needed)
+    {
+        argv_printf_cat(&argv, "%s", gateway);
+    }

     argv_msg(D_ROUTE, &argv);
-    openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD route delete -inet6 
command failed");
-
-#elif defined(TARGET_NETBSD)
-
-    argv_printf(&argv, "%s delete -inet6 %s/%d %s", ROUTE_PATH, network, 
r6->netbits, gateway);
-
-    argv_msg(D_ROUTE, &argv);
-    openvpn_execve_check(&argv, es, 0, "ERROR: NetBSD route delete -inet6 
command failed");
+    openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete 
-inet6 command failed");

 #elif defined(TARGET_AIX)

diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 06b7ae5..0df946b 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1383,7 +1383,7 @@
         add_route(&r, tt, 0, NULL, es, NULL);
     }

-#elif defined(TARGET_NETBSD)
+#elif defined(TARGET_NETBSD) || defined(TARGET_DRAGONFLY)
     in_addr_t remote_end = INADDR_ANY; /* for "virtual" subnet topology */

     if (tun_p2p)
@@ -1466,7 +1466,7 @@
         add_route(&r, tt, 0, NULL, es, NULL);
     }

-#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
+#elif defined(TARGET_FREEBSD)

     /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 
255.255.255.255 up */
     if (tun_p2p) /* point-to-point tun */

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

Gerrit-MessageType: newpatchset
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I87777e74b1fd34781e1d72c9f994eb84f39d800c
Gerrit-Change-Number: 721
Gerrit-PatchSet: 12
Gerrit-Owner: mrbff <[email protected]>
Gerrit-Reviewer: flichtenheld <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-CC: ordex <[email protected]>
Gerrit-Attention: flichtenheld <[email protected]>
Gerrit-Attention: mrbff <[email protected]>
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel

Reply via email to