{"record":{"id":"ea29a8d1ed509c9b","repo":"netbirdio/netbird","slug":"add-inverse-nat-rule-w","errorCode":null,"errorMessage":"add inverse nat rule: %w","messagePattern":"add inverse nat rule: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/router_linux.go","lineNumber":283,"sourceCode":"// AddNatRule inserts an iptables rule pair into the nat chain\nfunc (r *router) AddNatRule(pair firewall.RouterPair) error {\n\tif r.legacyManagement {\n\t\tlog.Warnf(\"This peer is connected to a NetBird Management service with an older version. Allowing all traffic for %s\", pair.Destination)\n\t\tif err := r.addLegacyRouteRule(pair); err != nil {\n\t\t\treturn fmt.Errorf(\"add legacy routing rule: %w\", err)\n\t\t}\n\t}\n\n\tif !pair.Masquerade {\n\t\treturn nil\n\t}\n\n\tif err := r.addNatRule(pair); err != nil {\n\t\treturn fmt.Errorf(\"add nat rule: %w\", err)\n\t}\n\n\tif err := r.addNatRule(firewall.GetInversePair(pair)); err != nil {\n\t\treturn fmt.Errorf(\"add inverse nat rule: %w\", err)\n\t}\n\n\tr.updateState()\n\n\treturn nil\n}\n\n// RemoveNatRule removes an iptables rule pair from forwarding and nat chains\nfunc (r *router) RemoveNatRule(pair firewall.RouterPair) error {\n\tif pair.Masquerade {\n\t\tif err := r.removeNatRule(pair); err != nil {\n\t\t\treturn fmt.Errorf(\"remove nat rule: %w\", err)\n\t\t}\n\n\t\tif err := r.removeNatRule(firewall.GetInversePair(pair)); err != nil {\n\t\t\treturn fmt.Errorf(\"remove inverse nat rule: %w\", err)\n\t\t}\n\t}","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/router_linux.go#L265-L301","documentation":"Returned by router.AddNatRule when addNatRule(firewall.GetInversePair(pair)) fails. The inverse rule uses '! -i <wg-interface>' plus conntrack NEW and sets the return-traffic mark (PreroutingFwmarkMasqueradeReturn) in NETBIRD-RT-PRE so replies leaving the overlay get masqueraded. This is the second half of the rule pair; if it fails after the forward rule succeeded, the pair is left half-installed.","triggerScenarios":"Same masquerade path as the forward rule, immediately after it succeeds. Fails on missing NETBIRD-RT-PRE chain, missing xt_conntrack/xt_mark/xt_set modules, or iptables backend errors. Note the code has a TODO: rollback of the forward rule/ipset counter does not happen on this branch.","commonSituations":"Transient xtables lock contention hitting the second Insert; iptables nft backend rejecting the inverted interface match after nftables ruleset changes underneath; module unload between the two inserts.","solutions":["Retry the operation (RemoveNatRule then AddNatRule) to clear the half-installed pair","Verify modules and chain as for the forward rule: iptables -t mangle -S NETBIRD-RT-PRE","Check for concurrent iptables users holding the lock","If it persists, gather 'sudo iptables-save' output and the agent debug log for the inner error"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := r.addNatRule(firewall.GetInversePair(pair)); err != nil {\n\t// pair is half-installed: remove the forward leg before surfacing the error\n\t_ = r.removeNatRule(pair)\n\treturn fmt.Errorf(\"add inverse nat rule: %w\", err)\n}","preventionTips":["Make add/remove paths idempotent so retries converge","Log the inner 'error while adding marking rule' text to catch module errors","Free the xtables lock before retry bursts"],"tags":["iptables","nat","masquerade","linux","netbird"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}