]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
FreeBSD DCO: introduce real subnet mode
authorGert Doering <gert@greenie.muc.de>
Wed, 12 Oct 2022 14:59:15 +0000 (16:59 +0200)
committerGert Doering <gert@greenie.muc.de>
Wed, 19 Oct 2022 07:28:28 +0000 (09:28 +0200)
To be able to configure a FreeBSD interface to "subnet" mode
(as opposed to point-to-point mode), it needs to have its
if_iflags set to IFF_BROADCAST.  For tun(4) interface this is
done with the TUNSIFMODE ioctl(), but this does not work for
more modern interfaces like ovpn(4) which communicate over
a common SIOCSDRVSPEC ioctl() that contains a "cmd" and a
"parameter list".

Introduce OVPN_SET_IFMODE cmd, add dco_set_ifmode() function
to put kernel interface into IFF_BROADCAST or IFF_POINTOPOINT
as needed.

NOTE: this needs a FreeBSD kernel that includes commit 2e797555f701c38d9d
to add the OVPN_SET_IFMODE on the kernel side - with an older kernel,
OpenVPN + ovpn(4) will log an error, and "topology subnet" setups
will not work.

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

index c6da6ce37986ce6e2a52440bdfd1a7f0d96839ad..c83610288549bdd3a2bb790c695758737d438dae 100644 (file)
@@ -165,6 +165,33 @@ ovpn_dco_init(int mode, dco_context_t *dco)
     return true;
 }
 
+static int
+dco_set_ifmode(dco_context_t *dco, int ifmode)
+{
+    struct ifdrv drv;
+    nvlist_t *nvl;
+    int ret;
+
+    nvl = nvlist_create(0);
+    nvlist_add_number(nvl, "ifmode", ifmode);
+
+    CLEAR(drv);
+    snprintf(drv.ifd_name, IFNAMSIZ, "%s", dco->ifname);
+    drv.ifd_cmd = OVPN_SET_IFMODE;
+    drv.ifd_data = nvlist_pack(nvl, &drv.ifd_len);
+
+    ret = ioctl(dco->fd, SIOCSDRVSPEC, &drv);
+    if (ret)
+    {
+        msg(M_WARN | M_ERRNO, "dco_set_ifmode: failed to set ifmode=%08x", ifmode);
+    }
+
+    free(drv.ifd_data);
+    nvlist_destroy(nvl);
+
+    return ret;
+}
+
 static int
 create_interface(struct tuntap *tt, const char *dev)
 {
@@ -205,6 +232,14 @@ create_interface(struct tuntap *tt, const char *dev)
     snprintf(tt->dco.ifname, IFNAMSIZ, "%s", ifr.ifr_data);
     tt->actual_name = string_alloc(tt->dco.ifname, NULL);
 
+    /* see "Interface Flags" in ifnet(9) */
+    int i = IFF_POINTOPOINT | IFF_MULTICAST;
+    if (tt->topology == TOP_SUBNET)
+    {
+        i = IFF_BROADCAST | IFF_MULTICAST;
+    }
+    dco_set_ifmode(&tt->dco, i);
+
     return 0;
 }
 
index 7ceec06e6bd2a1ed7ee292eb56a454b472f0e7f7..cf92d597ccff0a470f4c2d30175f0fadd0d035a5 100644 (file)
@@ -60,5 +60,6 @@ enum ovpn_key_cipher {
 #define OVPN_SEND_PKT           _IO('D', 9)
 #define OVPN_POLL_PKT           _IO('D', 10)
 #define OVPN_GET_PKT            _IO('D', 11)
+#define OVPN_SET_IFMODE         _IO('D', 12)
 
 #endif /* ifndef _NET_IF_OVPN_H_ */