{"record":{"id":"a310001076c9a617","repo":"netbirdio/netbird","slug":"remove-inbound-dnat-w","errorCode":null,"errorMessage":"remove inbound DNAT: %w","messagePattern":"remove inbound DNAT: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/manager_linux.go","lineNumber":486,"sourceCode":"\tdefer m.mutex.Unlock()\n\n\tif localAddr.Is6() {\n\t\tif !m.hasIPv6() {\n\t\t\treturn fmt.Errorf(\"add inbound DNAT: %w\", firewall.ErrIPv6NotInitialized)\n\t\t}\n\t\treturn m.router6.AddInboundDNAT(localAddr, protocol, originalPort, translatedPort)\n\t}\n\treturn m.router.AddInboundDNAT(localAddr, protocol, originalPort, translatedPort)\n}\n\n// RemoveInboundDNAT removes an inbound DNAT rule.\nfunc (m *Manager) RemoveInboundDNAT(localAddr netip.Addr, protocol firewall.Protocol, originalPort, translatedPort uint16) error {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tif localAddr.Is6() {\n\t\tif !m.hasIPv6() {\n\t\t\treturn fmt.Errorf(\"remove inbound DNAT: %w\", firewall.ErrIPv6NotInitialized)\n\t\t}\n\t\treturn m.router6.RemoveInboundDNAT(localAddr, protocol, originalPort, translatedPort)\n\t}\n\treturn m.router.RemoveInboundDNAT(localAddr, protocol, originalPort, translatedPort)\n}\n\n// AddOutputDNAT adds an OUTPUT chain DNAT rule for locally-generated traffic.\nfunc (m *Manager) AddOutputDNAT(localAddr netip.Addr, protocol firewall.Protocol, originalPort, translatedPort uint16) error {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tif localAddr.Is6() {\n\t\tif !m.hasIPv6() {\n\t\t\treturn fmt.Errorf(\"add output DNAT: %w\", firewall.ErrIPv6NotInitialized)\n\t\t}\n\t\treturn m.router6.AddOutputDNAT(localAddr, protocol, originalPort, translatedPort)\n\t}\n\treturn m.router.AddOutputDNAT(localAddr, protocol, originalPort, translatedPort)","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/manager_linux.go#L468-L504","documentation":"RemoveInboundDNAT for a v6 local address on a manager without the v6 half. It wraps firewall.ErrIPv6NotInitialized like the add path; note that in the current code this fires only when hasIPv6() is false - if the manager has v6, removal is delegated to router6 and cannot produce this sentinel.","triggerScenarios":"Calling RemoveInboundDNAT with localAddr.Is6() true while m.ipv6Client == nil - e.g. tearing down a v6 inbound rule after the peer restarted without v6.","commonSituations":"Service teardown after the agent reconnected v4-only; configuration drift where stored rules reference v6 addresses the current overlay cannot manage.","solutions":["Treat as a skip in callers: the rule cannot exist on this manager, so nothing to remove","Match errors.Is(err, firewall.ErrIPv6NotInitialized) and continue teardown of the remaining rules","Restore v6 on the peer if v6 inbound DNAT must keep working"],"exampleFix":"// before\nif err := mgr.RemoveInboundDNAT(localAddr, proto, origPort, xlatePort); err != nil {\n\treturn err // aborts teardown of remaining rules\n}\n\n// after\nif err := mgr.RemoveInboundDNAT(localAddr, proto, origPort, xlatePort); err != nil {\n\tif errors.Is(err, firewall.ErrIPv6NotInitialized) {\n\t\tlog.Debugf(\"no v6 manager; v6 inbound DNAT rule cannot exist\")\n\t} else {\n\t\treturn err\n\t}\n}","handlingStrategy":"validation","validationCode":"if localAddr.Is6() && !wgIface.Address().HasIPv6() {\n    return nil // the rule cannot exist on this manager; nothing to remove\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.RemoveInboundDNAT(localAddr, proto, origPort, xlatePort); err != nil {\n    if errors.Is(err, firewall.ErrIPv6NotInitialized) {\n        log.Debugf(\"v6 inbound DNAT rule cannot exist without v6 manager\")\n        return nil // continue teardown of remaining rules\n    }\n    return err\n}","preventionTips":["During teardown, treat ErrIPv6NotInitialized as 'rule cannot exist' and skip","Store the overlay family alongside installed rules so removals stay consistent","Use errors.Is so the sentinel check survives message changes"],"tags":["iptables","ipv6","firewall","dnat","cleanup","netbird","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}