Browse code

dco: support float notifications on FreeBSD

Signed-off-by: Kristof Provost <kprovost@netgate.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20250723083816.71604-2-kprovost@netgate.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg32282.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Kristof Provost authored on 2025/07/23 17:36:49
Showing 5 changed files
... ...
@@ -848,6 +848,15 @@ if test "$enable_dco" != "no"; then
848 848
 				else
849 849
 					AC_MSG_ERROR([DCO support can't be enabled])
850 850
 				fi
851
+			else
852
+				AC_CHECK_DECLS(
853
+					[OVPN_NOTIF_FLOAT],
854
+					[AC_DEFINE([ENABLE_DCO_FLOAT_FREEBSD], [1], [We have DCO float notifications on FreeBSD])],
855
+					,
856
+					[[
857
+						#include <net/if_ovpn.h>
858
+					]]
859
+				)
851 860
 			fi
852 861
 			;;
853 862
 		*-mingw*)
... ...
@@ -72,6 +72,63 @@ sockaddr_to_nvlist(const struct sockaddr *sa)
72 72
     return (nvl);
73 73
 }
74 74
 
75
+#ifdef ENABLE_DCO_FLOAT_FREEBSD
76
+static bool
77
+nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *ss)
78
+{
79
+    if (!nvlist_exists_number(nvl, "af"))
80
+    {
81
+        return (false);
82
+    }
83
+    if (!nvlist_exists_binary(nvl, "address"))
84
+    {
85
+        return (false);
86
+    }
87
+    if (!nvlist_exists_number(nvl, "port"))
88
+    {
89
+        return (false);
90
+    }
91
+
92
+    ss->ss_family = nvlist_get_number(nvl, "af");
93
+
94
+    switch (ss->ss_family)
95
+    {
96
+        case AF_INET:
97
+        {
98
+            struct sockaddr_in *in = (struct sockaddr_in *)ss;
99
+            const void *data;
100
+            size_t len;
101
+
102
+            in->sin_len = sizeof(*in);
103
+            data = nvlist_get_binary(nvl, "address", &len);
104
+            assert(len == sizeof(in->sin_addr));
105
+            memcpy(&in->sin_addr, data, sizeof(in->sin_addr));
106
+            in->sin_port = nvlist_get_number(nvl, "port");
107
+            break;
108
+        }
109
+
110
+        case AF_INET6:
111
+        {
112
+            struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)ss;
113
+            const void *data;
114
+            size_t len;
115
+
116
+            in6->sin6_len = sizeof(*in6);
117
+            data = nvlist_get_binary(nvl, "address", &len);
118
+            assert(len == sizeof(in6->sin6_addr));
119
+            memcpy(&in6->sin6_addr, data, sizeof(in6->sin6_addr));
120
+            in6->sin6_port = nvlist_get_number(nvl, "port");
121
+            break;
122
+        }
123
+
124
+        default:
125
+            return (false);
126
+    }
127
+
128
+    return (true);
129
+}
130
+#endif /* ifdef ENABLE_DCO_FLOAT_FREEBSD */
131
+
75 132
 int
76 133
 dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd,
77 134
              struct sockaddr *localaddr, struct sockaddr *remoteaddr,
... ...
@@ -573,6 +630,27 @@ dco_do_read(dco_context_t *dco)
573 573
             dco->dco_message_type = OVPN_CMD_SWAP_KEYS;
574 574
             break;
575 575
 
576
+#ifdef ENABLE_DCO_FLOAT_FREEBSD
577
+        case OVPN_NOTIF_FLOAT: {
578
+            const nvlist_t *address;
579
+
580
+            if (!nvlist_exists_nvlist(nvl, "address"))
581
+            {
582
+                msg(M_WARN, "Float notification without address");
583
+                break;
584
+            }
585
+
586
+            address = nvlist_get_nvlist(nvl, "address");
587
+            if (!nvlist_to_sockaddr(address, &dco->dco_float_peer_ss))
588
+            {
589
+                msg(M_WARN, "Failed to parse float notification");
590
+                break;
591
+            }
592
+            dco->dco_message_type = OVPN_CMD_FLOAT_PEER;
593
+            break;
594
+        }
595
+#endif
596
+
576 597
         default:
577 598
             msg(M_WARN, "Unknown kernel notification %d", type);
578 599
             break;
... ...
@@ -36,6 +36,7 @@ enum ovpn_message_type_t {
36 36
     OVPN_CMD_DEL_PEER,
37 37
     OVPN_CMD_PACKET,
38 38
     OVPN_CMD_SWAP_KEYS,
39
+    OVPN_CMD_FLOAT_PEER,
39 40
 };
40 41
 
41 42
 enum ovpn_del_reason_t {
... ...
@@ -55,6 +56,7 @@ typedef struct dco_context {
55 55
     int dco_message_type;
56 56
     int dco_message_peer_id;
57 57
     int dco_del_peer_reason;
58
+    struct sockaddr_storage dco_float_peer_ss;
58 59
     uint64_t dco_read_bytes;
59 60
     uint64_t dco_write_bytes;
60 61
 
... ...
@@ -3409,7 +3409,7 @@ multi_process_incoming_dco(struct multi_context *m)
3409 3409
         {
3410 3410
             process_incoming_del_peer(m, mi, dco);
3411 3411
         }
3412
-#if defined(TARGET_LINUX) || defined(TARGET_WIN32)
3412
+#if defined(TARGET_LINUX) || defined(TARGET_WIN32) || defined(TARGET_FREEBSD)
3413 3413
         else if (dco->dco_message_type == OVPN_CMD_FLOAT_PEER)
3414 3414
         {
3415 3415
             ASSERT(mi->context.c2.link_sockets[0]);
... ...
@@ -37,6 +37,7 @@
37 37
 enum ovpn_notif_type {
38 38
     OVPN_NOTIF_DEL_PEER,
39 39
     OVPN_NOTIF_ROTATE_KEY,
40
+    OVPN_NOTIF_FLOAT,
40 41
 };
41 42
 
42 43
 enum ovpn_del_reason {