From 4fc910031b08432f70faaed01cfb54fcfabccfae Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 10 Apr 2026 13:21:05 +0200 Subject: [PATCH] Check chain existence before deleting NAT OUTPUT jump rule The cleanup path tried to delete the jump rule to NETBIRD-NAT-OUTPUT unconditionally, producing a noisy debug log when the chain was never created (common for the v6 router when no OutputDNAT rules exist). Check ChainExists first, consistent with the chain deletion loop below. --- client/firewall/iptables/router_linux.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/firewall/iptables/router_linux.go b/client/firewall/iptables/router_linux.go index 6db364457..5f5a09d21 100644 --- a/client/firewall/iptables/router_linux.go +++ b/client/firewall/iptables/router_linux.go @@ -401,9 +401,13 @@ func (r *router) cleanUpDefaultForwardRules() error { // Remove jump rules from built-in chains before deleting custom chains, // otherwise the chain deletion fails with "device or resource busy". - jumpRule := []string{"-j", chainNATOutput} - if err := r.iptablesClient.Delete(tableNat, "OUTPUT", jumpRule...); err != nil { - log.Debugf("clean OUTPUT jump rule: %v", err) + if ok, err := r.iptablesClient.ChainExists(tableNat, chainNATOutput); err != nil { + return fmt.Errorf("check chain %s: %w", chainNATOutput, err) + } else if ok { + jumpRule := []string{"-j", chainNATOutput} + if err := r.iptablesClient.Delete(tableNat, "OUTPUT", jumpRule...); err != nil { + log.Debugf("clean OUTPUT jump rule: %v", err) + } } for _, chainInfo := range []struct {