[Openvpn-devel,v1] dco: support float notifications on FreeBSD

Message ID 20250908083354.19811-1-gert@greenie.muc.de
State New
Headers show
Series [Openvpn-devel,v1] dco: support float notifications on FreeBSD | expand

Commit Message

Gert Doering Sept. 8, 2025, 8:33 a.m. UTC
From: Kristof Provost <kp@FreeBSD.org>

this is a backport of commit b66b80b2ab and 796ad2c559
(squashed, as the second commit undoes quite a bit of #ifdef from the first)

Change-Id: I53e6d1b31c4f673cb646716dce774ef3210f36bd
Signed-off-by: Kristof Provost <kprovost@netgate.com>
Signed-off-by: Gert Doering <gert@greenie.muc.de>
Acked-by: Ralf Lici <ralf@mandelbit.com>
(cherry picked from commit b66b80b2ab73bb422826911b675798e6b789ef03)
(cherry picked from commit 796ad2c55951635382e48ea5b71d13bbb83ebfb1)
---

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

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

Acked-by according to Gerrit (reflected above):
Ralf Lici <ralf@mandelbit.com>

Comments

Gert Doering Sept. 8, 2025, 10:17 a.m. UTC | #1
So, this is the second part of the "make float notifications on FreeBSD
for the 2.6 tree work" patch series, see
  https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289303

It's a squash of two patches from master - because the first patch
introduced autoconf changes + #ifdefs that the second one then removed
again (because we decided that "nah, making this conditional does not
really help anyone").  No need to track that in release/2.6 - the 
"master" commit IDs are linked.

Both original patches are from Kristof, so recording him as author
of the squashed patch.  I did the work, Ralf verified that I got it
right :-)

Two assert() have been pointed out as "this is questionable", and the
next patch will replace these and all others in the code with OpenVPN
ASSERT(), plus explaining more background.


This patch affects only FreeBSD (dco_freebsd.h and #ifdef TARGET_FREEBSD),
and has been tested there, confirming that DCO float now works and nothing
else breaks.

Your patch has been applied to the release/2.6 branch (bugfix-ish).

commit 3c9fe881207df94e938ba7325a0cd46765d6ba6c
Author: Kristof Provost
Date:   Mon Sep 8 10:33:49 2025 +0200

     dco: support float notifications on FreeBSD

     Signed-off-by: Kristof Provost <kprovost@netgate.com>
     Signed-off-by: Gert Doering <gert@greenie.muc.de>
     Acked-by: Ralf Lici <ralf@mandelbit.com>
     Message-Id: <20250908083354.19811-1-gert@greenie.muc.de>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg32827.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c
index ed7ea92..25532d4 100644
--- a/src/openvpn/dco_freebsd.c
+++ b/src/openvpn/dco_freebsd.c
@@ -72,6 +72,61 @@ 
     return (nvl);
 }
 
+static bool
+nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *ss)
+{
+    if (!nvlist_exists_number(nvl, "af"))
+    {
+        return (false);
+    }
+    if (!nvlist_exists_binary(nvl, "address"))
+    {
+        return (false);
+    }
+    if (!nvlist_exists_number(nvl, "port"))
+    {
+        return (false);
+    }
+
+    ss->ss_family = nvlist_get_number(nvl, "af");
+
+    switch (ss->ss_family)
+    {
+        case AF_INET:
+        {
+            struct sockaddr_in *in = (struct sockaddr_in *)ss;
+            const void *data;
+            size_t len;
+
+            in->sin_len = sizeof(*in);
+            data = nvlist_get_binary(nvl, "address", &len);
+            assert(len == sizeof(in->sin_addr));
+            memcpy(&in->sin_addr, data, sizeof(in->sin_addr));
+            in->sin_port = nvlist_get_number(nvl, "port");
+            break;
+        }
+
+        case AF_INET6:
+        {
+            struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)ss;
+            const void *data;
+            size_t len;
+
+            in6->sin6_len = sizeof(*in6);
+            data = nvlist_get_binary(nvl, "address", &len);
+            assert(len == sizeof(in6->sin6_addr));
+            memcpy(&in6->sin6_addr, data, sizeof(in6->sin6_addr));
+            in6->sin6_port = nvlist_get_number(nvl, "port");
+            break;
+        }
+
+        default:
+            return (false);
+    }
+
+    return (true);
+}
+
 int
 dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd,
              struct sockaddr *localaddr, struct sockaddr *remoteaddr,
@@ -571,6 +626,25 @@ 
             dco->dco_message_type = OVPN_CMD_SWAP_KEYS;
             break;
 
+        case OVPN_NOTIF_FLOAT: {
+            const nvlist_t *address;
+
+            if (!nvlist_exists_nvlist(nvl, "address"))
+            {
+                msg(M_WARN, "Float notification without address");
+                break;
+            }
+
+            address = nvlist_get_nvlist(nvl, "address");
+            if (!nvlist_to_sockaddr(address, &dco->dco_float_peer_ss))
+            {
+                msg(M_WARN, "Failed to parse float notification");
+                break;
+            }
+            dco->dco_message_type = OVPN_CMD_FLOAT_PEER;
+            break;
+        }
+
         default:
             msg(M_WARN, "Unknown kernel notification %d", type);
             break;
diff --git a/src/openvpn/dco_freebsd.h b/src/openvpn/dco_freebsd.h
index e1a054e..ab5891e 100644
--- a/src/openvpn/dco_freebsd.h
+++ b/src/openvpn/dco_freebsd.h
@@ -36,6 +36,7 @@ 
     OVPN_CMD_DEL_PEER,
     OVPN_CMD_PACKET,
     OVPN_CMD_SWAP_KEYS,
+    OVPN_CMD_FLOAT_PEER,
 };
 
 enum ovpn_del_reason_t {
@@ -55,6 +56,7 @@ 
     int dco_message_type;
     int dco_message_peer_id;
     int dco_del_peer_reason;
+    struct sockaddr_storage dco_float_peer_ss;
     uint64_t dco_read_bytes;
     uint64_t dco_write_bytes;
 } dco_context_t;
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index eb5f932..310211c 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -3313,7 +3313,7 @@ 
         {
             process_incoming_del_peer(m, mi, dco);
         }
-#if 0
+#if defined(TARGET_FREEBSD)
         else if (dco->dco_message_type == OVPN_CMD_FLOAT_PEER)
         {
             ASSERT(mi->context.c2.link_socket);
diff --git a/src/openvpn/ovpn_dco_freebsd.h b/src/openvpn/ovpn_dco_freebsd.h
index 53f94df..7eb643b 100644
--- a/src/openvpn/ovpn_dco_freebsd.h
+++ b/src/openvpn/ovpn_dco_freebsd.h
@@ -37,6 +37,7 @@ 
 enum ovpn_notif_type {
     OVPN_NOTIF_DEL_PEER,
     OVPN_NOTIF_ROTATE_KEY,
+    OVPN_NOTIF_FLOAT,
 };
 
 enum ovpn_del_reason {