[Openvpn-devel,v4] Allowing installing FreeBSD routes with interface instead of next-hop

Message ID 20251006145844.27794-1-gert@greenie.muc.de
State New
Headers show
Series [Openvpn-devel,v4] Allowing installing FreeBSD routes with interface instead of next-hop | expand

Commit Message

Gert Doering Oct. 6, 2025, 2:58 p.m. UTC
From: Arne Schwabe <arne@rfc2549.org>

This matches the Linux behaviour of the net_route add/delete commands

Change-Id: I88e16e15fad065cb310d38f09924053efc3a6ce5
Signed-off-by: Arne Schwabe <arne@rfc2549.org>
Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1193
---

This change was reviewed on Gerrit and approved by at least one
developer. I request to merge it to master.

Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1193
This mail reflects revision 4 of this Change.

Acked-by according to Gerrit (reflected above):

Comments

Gert Doering Oct. 6, 2025, 4:56 p.m. UTC | #1
There is not much to test here, as the "new code" is only used for a
case not yet supported by the rest of the code (--ifconfig-push IPs
outside --server subnet, with DCO, on FreeBSD).  Patch for that is
in gerrit #1192, but that needs more testing.

The code in question is currently only excercised at all for --iroute
on FreeBSD DCO -> tested there, works.

At a future point in time (after 2.7.0 release) I think I/we should remove
the TARGET_FREEBSD parts from route.c, and use networking_freebsd.c
instead (adding what is missing, namely "fe80::1%em0" gateways with
embedded NIC).

As discussed in IRC, I have amended the comment a bit, and then a bit more,
to make it easier to understand what is happening and when it's needed.  No
actual code change.

Your patch has been applied to the master branch.

commit cbcfb9ab3ea90e1d09e5783bdb3bbd18ac0328d1
Author: Arne Schwabe
Date:   Mon Oct 6 16:58:37 2025 +0200

     Allowing installing FreeBSD routes with interface instead of next-hop

     Signed-off-by: Arne Schwabe <arne@rfc2549.org>
     Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1193
     Message-Id: <20251006145844.27794-1-gert@greenie.muc.de>
     URL: https://sourceforge.net/p/openvpn/mailman/message/59242876/
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/networking_freebsd.c b/src/openvpn/networking_freebsd.c
index b47444c..b020f51 100644
--- a/src/openvpn/networking_freebsd.c
+++ b/src/openvpn/networking_freebsd.c
@@ -15,17 +15,29 @@ 
     char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
     in_addr_t _dst, _gw;
     struct argv argv = argv_new();
-    bool status;
+
+    ASSERT(gw || iface);
 
     _dst = ntohl(*dst);
-    _gw = ntohl(*gw);
 
-    argv_printf(&argv, "%s %s -net %s/%d %s -fib %d", ROUTE_PATH, op,
-                inet_ntop(AF_INET, &_dst, buf1, sizeof(buf1)), prefixlen,
-                inet_ntop(AF_INET, &_gw, buf2, sizeof(buf2)), table);
+    /* if gw is NULL we are installing a route with the interface as
+     * target instead */
+    if (gw)
+    {
+        _gw = ntohl(*gw);
+        argv_printf(&argv, "%s %s -net %s/%d %s -fib %d", ROUTE_PATH, op,
+                    inet_ntop(AF_INET, &_dst, buf1, sizeof(buf1)), prefixlen,
+                    inet_ntop(AF_INET, &_gw, buf2, sizeof(buf2)), table);
+    }
+    else
+    {
+        argv_printf(&argv, "%s %s -net %s/%d -iface %s -fib %d", ROUTE_PATH, op,
+                    inet_ntop(AF_INET, &_dst, buf1, sizeof(buf1)), prefixlen,
+                    iface, table);
+    }
 
     argv_msg(M_INFO, &argv);
-    status = openvpn_execve_check(&argv, NULL, 0, "ERROR: FreeBSD route command failed");
+    bool status = openvpn_execve_check(&argv, NULL, 0, "ERROR: FreeBSD route command failed");
 
     argv_free(&argv);
 
@@ -38,14 +50,26 @@ 
 {
     char buf1[INET6_ADDRSTRLEN], buf2[INET6_ADDRSTRLEN];
     struct argv argv = argv_new();
-    bool status;
 
-    argv_printf(&argv, "%s -6 %s -net %s/%d %s -fib %d", ROUTE_PATH, op,
-                inet_ntop(AF_INET6, dst, buf1, sizeof(buf1)), prefixlen,
-                inet_ntop(AF_INET6, gw, buf2, sizeof(buf2)), table);
+    ASSERT(gw || iface);
+    /* if gw is NULL, we are installing a route with the interface as target
+     * instead */
+    if (gw)
+    {
+        argv_printf(&argv, "%s -6 %s -net %s/%d %s -fib %d", ROUTE_PATH, op,
+                    inet_ntop(AF_INET6, dst, buf1, sizeof(buf1)), prefixlen,
+                    inet_ntop(AF_INET6, gw, buf2, sizeof(buf2)), table);
+    }
+    else
+    {
+        argv_printf(&argv, "%s -6 %s -net %s/%d -iface %s -fib %d", ROUTE_PATH, op,
+                    inet_ntop(AF_INET6, dst, buf1, sizeof(buf1)), prefixlen,
+                    iface, table);
+    }
+
 
     argv_msg(M_INFO, &argv);
-    status = openvpn_execve_check(&argv, NULL, 0, "ERROR: FreeBSD route command failed");
+    bool status = openvpn_execve_check(&argv, NULL, 0, "ERROR: FreeBSD route command failed");
 
     argv_free(&argv);