From 63bb85cdf286ff9280f6db78b8f445443fc1b7b7 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Mon, 4 May 2026 12:28:36 +0200 Subject: [PATCH] Keep v4 NAT rule when v6 mirror fails to preserve partial connectivity --- client/firewall/nftables/manager_linux.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/firewall/nftables/manager_linux.go b/client/firewall/nftables/manager_linux.go index 3f4ac4475..fdc7c2f3c 100644 --- a/client/firewall/nftables/manager_linux.go +++ b/client/firewall/nftables/manager_linux.go @@ -391,12 +391,12 @@ func (m *Manager) AddNatRule(pair firewall.RouterPair) error { // Dynamic routes need NAT in both tables since resolved IPs can be // either v4 or v6. This covers both DomainSet (modern) and the legacy // wildcard 0.0.0.0/0 destination where the client resolves DNS. + // On v6 failure we keep the v4 NAT rule rather than rolling back: half + // connectivity is better than none, and RemoveNatRule is content-keyed + // so the eventual cleanup still works. if m.hasIPv6() && pair.Dynamic { v6Pair := firewall.ToV6NatPair(pair) if err := m.router6.AddNatRule(v6Pair); err != nil { - if rbErr := m.router.RemoveNatRule(pair); rbErr != nil { - return fmt.Errorf("add v6 NAT rule: %w (rollback v4: %v)", err, rbErr) - } return fmt.Errorf("add v6 NAT rule: %w", err) } }