Skip to content
6 changes: 5 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ Changelog
Version 1.3.0 [unreleased]
--------------------------

Work in progress.
Bugfixes
~~~~~~~~

- Fixed WireGuard auto tunnel provisioning broken with IPv6 subnets `#721
<https://github.com/openwisp/openwisp-controller/issues/721>`_

Version 1.2.2 [2026-03-06]
--------------------------
Expand Down
6 changes: 6 additions & 0 deletions openwisp_controller/config/base/vpn.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,12 @@ def auto_client(self, auto_cert=True, template_backend_class=None):
vxlan=self.config.get("vxlan", [{}])[0],
**context_keys,
)
if self.subnet and self.subnet.subnet.version == 6:
for interface in auto.get("interfaces", []):
if interface.get("type") == "wireguard":
for addr in interface.get("addresses", []):
addr["family"] = "ipv6"
addr["mask"] = 128
# If the backend is 'zerotier' then
# call auto_client and update the config
elif self._is_backend_type("zerotier") and template_backend_class:
Expand Down
42 changes: 42 additions & 0 deletions openwisp_controller/config/tests/test_vpn.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,26 @@ def test_auto_client(self):
)
self.assertEqual(auto, expected)

def test_auto_client_ipv6(self):
org = self._get_org()
device, vpn, template = self._create_wireguard_vpn_template(
vpn_options={
"organization": org,
"subnet": self._create_subnet(
name="wireguard ipv6", subnet="fdca:1234::/64", organization=org
),
}
)
auto = vpn.auto_client(template_backend_class=template.backend_class)
wg_interface = next(
(i for i in auto["interfaces"] if i.get("type") == "wireguard"), None
)
self.assertIsNotNone(wg_interface, "WireGuard interface not found")
addresses = wg_interface["addresses"]
self.assertEqual(len(addresses), 1)
self.assertEqual(addresses[0]["family"], "ipv6")
self.assertEqual(addresses[0]["mask"], 128)

def test_change_vpn_backend(self):
vpn = self._create_vpn(name="new", backend=self._BACKENDS["openvpn"])
subnet = self._create_subnet(
Expand Down Expand Up @@ -996,6 +1016,28 @@ def test_auto_client(self):
)
self.assertEqual(auto, expected)

def test_auto_client_ipv6(self):
org = self._get_org()
device, vpn, template = self._create_vxlan_vpn_template(
vpn_options={
"organization": org,
"subnet": self._create_subnet(
name="vxlan wireguard ipv6",
subnet="fdca:1234::/64",
organization=org,
),
}
)
auto = vpn.auto_client(template_backend_class=template.backend_class)
wg_interface = next(
(i for i in auto["interfaces"] if i.get("type") == "wireguard"), None
)
self.assertIsNotNone(wg_interface, "WireGuard interface not found")
addresses = wg_interface["addresses"]
self.assertEqual(len(addresses), 1)
self.assertEqual(addresses[0]["family"], "ipv6")
self.assertEqual(addresses[0]["mask"], 128)
Comment thread
coderabbitai[bot] marked this conversation as resolved.


class TestVxlanTransaction(
BaseTestVpn, TestVxlanWireguardVpnMixin, TransactionTestCase
Expand Down
4 changes: 2 additions & 2 deletions openwisp_controller/config/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ class TestVxlanWireguardVpnMixin(CreateIpamModelsMixin):
def _create_vxlan_tunnel(self, config=None, **kwargs):
if config is None:
config = {"wireguard": [{"name": "wg0", "port": 51820}]}
org = self._get_org()
subnet = self._create_subnet(
org = kwargs.pop("organization", None) or self._get_org()
subnet = kwargs.pop("subnet", None) or self._create_subnet(
name="wireguard test", subnet="10.0.0.0/16", organization=org
)
tunnel = self._create_vpn(
Expand Down
Loading