From 22bc63c78439ed23b974b8f822330d75ec79c7fc Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Wed, 12 Oct 2022 16:59:15 +0200 Subject: [PATCH] FreeBSD DCO: introduce real subnet mode 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 Acked-by: Kristof Provost 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 --- src/openvpn/dco_freebsd.c | 35 ++++++++++++++++++++++++++++++++++ src/openvpn/ovpn_dco_freebsd.h | 1 + 2 files changed, 36 insertions(+) diff --git a/src/openvpn/dco_freebsd.c b/src/openvpn/dco_freebsd.c index c6da6ce37..c83610288 100644 --- a/src/openvpn/dco_freebsd.c +++ b/src/openvpn/dco_freebsd.c @@ -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; } diff --git a/src/openvpn/ovpn_dco_freebsd.h b/src/openvpn/ovpn_dco_freebsd.h index 7ceec06e6..cf92d597c 100644 --- a/src/openvpn/ovpn_dco_freebsd.h +++ b/src/openvpn/ovpn_dco_freebsd.h @@ -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_ */ -- 2.47.2