fix: stop deriving NAT translations from IPv6 pinholes
CI / test (3.10) (push) Failing after 7s
CI / test (3.11) (push) Failing after 7s
CI / test (3.9) (push) Failing after 13s
CI / test (3.12) (push) Failing after 5m28s

Closes netork#116.

`get_port_forwards` reports IPv4 mappings and IPv6 pinholes together, which is
right — both are inbound rules someone configured. `get_nat_translations` then
iterated all of them, and that is not: a pinhole is a firewall hole, and IPv6
does not do NAT at all.

The entries it produced were nonsense in two ways. They paired an IPv6 host with
the IPv4 WAN address, and `inside_local` came out as "2001:db8::10:22", where
the last colon is a port separator and everything before it is an address that
also contains colons.

The two failing tests were pulling in opposite directions.
`TestGetNatTranslations` was right and the implementation had drifted past it
when pinhole support landed. `TestGetPortForwards::test_returns_all_rules` was
the opposite: it still expected one rule from before pinholes existed, which put
it in direct contradiction with TestIPv6Pinholes further down the same file.
This commit is contained in:
Christian Manivong
2026-08-21 13:17:37 +07:00
parent 4723c44d9d
commit 13e0073659
2 changed files with 28 additions and 3 deletions
+9
View File
@@ -618,12 +618,21 @@ class FritzBoxDriver(ResidentialGatewayDriver):
TR-064 does not expose a live connection-tracking table; this
derives static NAT-PT entries from the enabled port forwarding
rules, which is the closest equivalent FritzBox provides.
IPv6 pinholes are skipped. ``get_port_forwards`` reports them alongside
the IPv4 mappings because both are inbound rules a user configured, but
a pinhole is a firewall hole, not a translation — IPv6 does not do NAT.
Including them produced entries pairing an IPv6 host with the IPv4 WAN
address, and an ``inside_local`` of ``2001:db8::10:22`` where the last
colon is a port separator and the rest is an address.
"""
ext_ip = self._wan_external_ip()
translations: list[NATTranslationDict] = []
for forward in self.get_port_forwards():
if not forward["enabled"]:
continue
if ":" in forward["internal_ip"]:
continue
remote = forward.get("remote_host") or "0.0.0.0"
translations.append(
{