git: 684dd4e8c008 - stable/14 - kern: wg: add support for removing Allowed-IPs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 21 Jul 2025 02:13:58 UTC
The branch stable/14 has been updated by kevans:
URL: https://cgit.FreeBSD.org/src/commit/?id=684dd4e8c0085f4e64016a44d4cd699b2fc29681
commit 684dd4e8c0085f4e64016a44d4cd699b2fc29681
Author: Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2025-06-26 02:57:02 +0000
Commit: Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2025-07-21 02:12:59 +0000
kern: wg: add support for removing Allowed-IPs
This was recently added to Linux to improve incremental update support,
as you could previously add Allowed-IPs but not remove without replacing
the whole set (and thus, potentially disrupting existing traffic).
Removal is incredibly straightforward; we'll find it in p_aips first
to ensure that it's actually valid for this peer, then we'll delete it
from the radix tree before we remove the corresponding p_aips entry.
Reviewed by: Jason A. Donenfeld, jhb
(cherry picked from commit d15d610fac97df4fefed3f14b31dcfbdcec65bf9)
(cherry picked from commit d1ac3e245f084ee0637bde9a446687621358c418)
---
sys/dev/wg/if_wg.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
sys/dev/wg/if_wg.h | 6 +++++
2 files changed, 77 insertions(+), 1 deletion(-)
diff --git a/sys/dev/wg/if_wg.c b/sys/dev/wg/if_wg.c
index 380e579eed07..75af5e279669 100644
--- a/sys/dev/wg/if_wg.c
+++ b/sys/dev/wg/if_wg.c
@@ -314,6 +314,8 @@ static void wg_timers_run_zero_key_material(void *);
static void wg_timers_run_persistent_keepalive(void *);
static int wg_aip_add(struct wg_softc *, struct wg_peer *, sa_family_t,
const void *, uint8_t);
+static int wg_aip_del(struct wg_softc *, struct wg_peer *, sa_family_t,
+ const void *, uint8_t);
static struct wg_peer *wg_aip_lookup(struct wg_softc *, sa_family_t, void *);
static void wg_aip_remove_all(struct wg_softc *, struct wg_peer *);
static struct wg_peer *wg_peer_create(struct wg_softc *,
@@ -530,10 +532,12 @@ wg_peer_get_endpoint(struct wg_peer *peer, struct wg_endpoint *e)
static int
wg_aip_addrinfo(struct wg_aip *aip, const void *baddr, uint8_t cidr)
{
+#if defined(INET) || defined(INET6)
struct aip_addr *addr, *mask;
addr = &aip->a_addr;
mask = &aip->a_mask;
+#endif
switch (aip->a_af) {
#ifdef INET
case AF_INET:
@@ -608,6 +612,58 @@ wg_aip_add(struct wg_softc *sc, struct wg_peer *peer, sa_family_t af,
return (ret);
}
+static int
+wg_aip_del(struct wg_softc *sc, struct wg_peer *peer, sa_family_t af,
+ const void *baddr, uint8_t cidr)
+{
+ struct radix_node_head *root = NULL;
+ struct radix_node *dnode __diagused, *node;
+ struct wg_aip *aip, addr;
+ int ret = 0;
+
+ /*
+ * We need to be sure that all padding is cleared, as it is above when
+ * new AllowedIPs are added, since we want to do a direct comparison.
+ */
+ memset(&addr, 0, sizeof(addr));
+ addr.a_af = af;
+
+ ret = wg_aip_addrinfo(&addr, baddr, cidr);
+ if (ret != 0)
+ return (ret);
+
+ root = af == AF_INET ? sc->sc_aip4 : sc->sc_aip6;
+
+ MPASS(root != NULL);
+ RADIX_NODE_HEAD_LOCK(root);
+
+ node = root->rnh_lookup(&addr.a_addr, &addr.a_mask, &root->rh);
+ if (node == NULL) {
+ RADIX_NODE_HEAD_UNLOCK(root);
+ return (0);
+ }
+
+ aip = (struct wg_aip *)node;
+ if (aip->a_peer != peer) {
+ /*
+ * They could have specified an allowed-ip that belonged to a
+ * different peer, in which case our job is done because the
+ * AllowedIP has been removed.
+ */
+ RADIX_NODE_HEAD_UNLOCK(root);
+ return (0);
+ }
+
+ dnode = root->rnh_deladdr(&aip->a_addr, &aip->a_mask, &root->rh);
+ MPASS(dnode == node);
+ RADIX_NODE_HEAD_UNLOCK(root);
+
+ LIST_REMOVE(aip, a_entry);
+ peer->p_aips_num--;
+ free(aip, M_WG);
+ return (0);
+}
+
static struct wg_peer *
wg_aip_lookup(struct wg_softc *sc, sa_family_t af, void *a)
{
@@ -2477,11 +2533,19 @@ wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl)
aipl = nvlist_get_nvlist_array(nvl, "allowed-ips", &allowedip_count);
for (size_t idx = 0; idx < allowedip_count; idx++) {
sa_family_t ipaf;
+ int ipflags;
if (!nvlist_exists_number(aipl[idx], "cidr"))
continue;
ipaf = AF_UNSPEC;
+ ipflags = 0;
+ if (nvlist_exists_number(aipl[idx], "flags"))
+ ipflags = nvlist_get_number(aipl[idx], "flags");
+ if ((ipflags & ~WGALLOWEDIP_VALID_FLAGS) != 0) {
+ err = EOPNOTSUPP;
+ goto out;
+ }
cidr = nvlist_get_number(aipl[idx], "cidr");
if (nvlist_exists_binary(aipl[idx], "ipv4")) {
addr = nvlist_get_binary(aipl[idx], "ipv4", &size);
@@ -2504,7 +2568,13 @@ wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl)
}
MPASS(ipaf != AF_UNSPEC);
- if ((err = wg_aip_add(sc, peer, ipaf, addr, cidr)) != 0)
+ if ((ipflags & WGALLOWEDIP_REMOVE_ME) != 0) {
+ err = wg_aip_del(sc, peer, ipaf, addr, cidr);
+ } else {
+ err = wg_aip_add(sc, peer, ipaf, addr, cidr);
+ }
+
+ if (err != 0)
goto out;
}
}
diff --git a/sys/dev/wg/if_wg.h b/sys/dev/wg/if_wg.h
index f00b7f676319..801eaf38141d 100644
--- a/sys/dev/wg/if_wg.h
+++ b/sys/dev/wg/if_wg.h
@@ -32,4 +32,10 @@ struct wg_data_io {
#define SIOCSWG _IOWR('i', 210, struct wg_data_io)
#define SIOCGWG _IOWR('i', 211, struct wg_data_io)
+
+/* Keep these in sync with wireguard-tools:containers.h */
+#define WGALLOWEDIP_REMOVE_ME 0x0001
+
+#define WGALLOWEDIP_VALID_FLAGS WGALLOWEDIP_REMOVE_ME
+
#endif /* __IF_WG_H__ */