From a64726d30972199aea1d4cc60d878f9a7995053d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kau=C3=AA=20Abade?= Date: Thu, 28 May 2026 17:25:42 -0300 Subject: [PATCH] [feature] Add shared_ips support to WireGuard schema and converters --- .../openwrt/converters/wireguard_peers.py | 1 + netjsonconfig/backends/openwrt/schema.py | 11 ++++++ .../backends/wireguard/converters.py | 7 +++- netjsonconfig/backends/wireguard/schema.py | 11 ++++++ tests/openwrt/test_wireguard.py | 32 +++++++++++++++++ tests/wireguard/test_backend.py | 34 +++++++++++++++++++ 6 files changed, 95 insertions(+), 1 deletion(-) diff --git a/netjsonconfig/backends/openwrt/converters/wireguard_peers.py b/netjsonconfig/backends/openwrt/converters/wireguard_peers.py index a1f38168c..3b45cc33a 100644 --- a/netjsonconfig/backends/openwrt/converters/wireguard_peers.py +++ b/netjsonconfig/backends/openwrt/converters/wireguard_peers.py @@ -21,6 +21,7 @@ def __intermediate_peer(self, peer, index): if index > 1: uci_name = f"{uci_name}_{index}" peer.update({".type": f"wireguard_{interface}", ".name": uci_name}) + peer.pop("shared_ips", None) if not peer.get("endpoint_host") and "endpoint_port" in peer: del peer["endpoint_port"] return self.sorted_dict(peer) diff --git a/netjsonconfig/backends/openwrt/schema.py b/netjsonconfig/backends/openwrt/schema.py index 2daf1983e..b4bb95cbb 100644 --- a/netjsonconfig/backends/openwrt/schema.py +++ b/netjsonconfig/backends/openwrt/schema.py @@ -1229,6 +1229,17 @@ "minLength": 1, }, }, + "shared_ips": { + "type": "array", + "title": "shared IPs", + "propertyOrder": 3, + "uniqueItems": True, + "items": { + "type": "string", + "title": "IP/prefix", + "minLength": 1, + }, + }, "endpoint_host": wireguard_peers["endpoint_host"], "endpoint_port": wireguard_peers["endpoint_port"], "preshared_key": wireguard_peers["preshared_key"], diff --git a/netjsonconfig/backends/wireguard/converters.py b/netjsonconfig/backends/wireguard/converters.py index ff9b3e4ca..f0a0ca48d 100644 --- a/netjsonconfig/backends/wireguard/converters.py +++ b/netjsonconfig/backends/wireguard/converters.py @@ -49,7 +49,12 @@ def __intermediate_vpn(self, config, remove=None): def __intermediate_peers(self, peers): peer_list = [] for peer in peers: - peer["AllowedIPs"] = peer.pop("allowed_ips") + allowed_ips = peer.pop("allowed_ips") + shared_ips = peer.pop("shared_ips", []) + if shared_ips: + extra = ", ".join(ip for ip in shared_ips if ip) + allowed_ips = f"{allowed_ips}, {extra}" + peer["AllowedIPs"] = allowed_ips peer["PublicKey"] = peer.pop("public_key") peer["PreSharedKey"] = peer.pop("preshared_key", None) host = peer.pop("endpoint_host", None) diff --git a/netjsonconfig/backends/wireguard/schema.py b/netjsonconfig/backends/wireguard/schema.py index 7d21b581d..ac049b77a 100644 --- a/netjsonconfig/backends/wireguard/schema.py +++ b/netjsonconfig/backends/wireguard/schema.py @@ -181,6 +181,17 @@ "pattern": "^[^\\s]*$", "propertyOrder": 5, }, + "shared_ips": { + "title": "shared IP addresses", + "type": "array", + "uniqueItems": True, + "propertyOrder": 6, + "items": { + "type": "string", + "title": "IP/prefix", + "minLength": 1, + }, + }, }, }, }, diff --git a/tests/openwrt/test_wireguard.py b/tests/openwrt/test_wireguard.py index d8c7b6dd2..2df9f3b65 100644 --- a/tests/openwrt/test_wireguard.py +++ b/tests/openwrt/test_wireguard.py @@ -136,6 +136,38 @@ def test_render_wireguard_peer(self): ) expected = self._tabs("""package network +config wireguard_wg0 'wgpeer_wg0' + list allowed_ips '10.0.0.1/32' + option endpoint_host '192.168.1.42' + option endpoint_port '40840' + option persistent_keepalive '30' + option preshared_key 'oPZmGdHBseaV1TF0julyElNuJyeKs2Eo+o62R/09IB4=' + option public_key 'rn+isMBpyQ4HX6ZzE709bKnZw5IaLZoIS3hIjmfKCkk=' + option route_allowed_ips '1' +""") + self.assertEqual(o.render(), expected) + + def test_render_wireguard_peer_shared_ips(self): + o = OpenWrt( + { + "wireguard_peers": [ + { + "interface": "wg0", + "public_key": "rn+isMBpyQ4HX6ZzE709bKnZw5IaLZoIS3hIjmfKCkk=", + "allowed_ips": ["10.0.0.1/32"], + "shared_ips": ["192.168.1.0/24"], + "endpoint_host": "192.168.1.42", + "endpoint_port": 40840, + "preshared_key": "oPZmGdHBseaV1TF0julyElNuJyeKs2Eo+o62R/09IB4=", + "persistent_keepalive": 30, + "route_allowed_ips": True, + } + ] + } + ) + o.validate() + expected = self._tabs("""package network + config wireguard_wg0 'wgpeer_wg0' list allowed_ips '10.0.0.1/32' option endpoint_host '192.168.1.42' diff --git a/tests/wireguard/test_backend.py b/tests/wireguard/test_backend.py index 08174a64a..53fe3dab3 100644 --- a/tests/wireguard/test_backend.py +++ b/tests/wireguard/test_backend.py @@ -116,6 +116,40 @@ def test_peers(self): Endpoint = 192.168.1.35:4908 PreSharedKey = xisFXck9KfEZga4hlkproH6+86S8ki1tmLtMtqVipjg= PublicKey = 94a+MnZSdzHCzOy5y2K+0+Xe7lQzaa4v7lEiBZ7elVE= +""" + self.assertEqual(c.render(), expected) + + def test_peers_shared_ips(self): + c = Wireguard( + { + "wireguard": [ + { + "name": "test1", + "private_key": "QFdbnuYr7rrF4eONCAs7FhZwP7BXX/jD/jq2LXCpaXI=", + "port": 40842, + "address": "10.0.0.1/24", + "peers": [ + { + "public_key": "jqHs76yCH0wThMSqogDshndAiXelfffUJVcFmz352HI=", + "allowed_ips": "10.0.0.3/32", + "shared_ips": ["192.168.1.0/24"], + } + ], + } + ] + } + ) + c.validate() + expected = """# wireguard config: test1 + +[Interface] +Address = 10.0.0.1/24 +ListenPort = 40842 +PrivateKey = QFdbnuYr7rrF4eONCAs7FhZwP7BXX/jD/jq2LXCpaXI= + +[Peer] +AllowedIPs = 10.0.0.3/32, 192.168.1.0/24 +PublicKey = jqHs76yCH0wThMSqogDshndAiXelfffUJVcFmz352HI= """ self.assertEqual(c.render(), expected)