{"record":{"id":"28ff464d8bcdced7","repo":"netbirdio/netbird","slug":"add-nat-rule-w-28ff46","errorCode":null,"errorMessage":"add nat rule: %w","messagePattern":"add nat rule: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/router_linux.go","lineNumber":279,"sourceCode":"\tlog.Debugf(\"Deleted unused ipset %s\", setName)\n\treturn nil\n}\n\n// 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","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/router_linux.go#L261-L297","documentation":"Returned by router.AddNatRule when addNatRule(pair) fails for the forward direction. addNatRule removes any stale rule under the same key, then Inserts a conntrack NEW match ending in '-j MARK --set-mark <value>' at position 1 of NETBIRD-RT-PRE (mangle table) so POSTROUTING masquerades the traffic. Failures come from the iptables Insert itself or from building the -s/-d expressions.","triggerScenarios":"Adding a masquerading routing pair (exit node or network route with masquerade on). The Insert fails when NETBIRD-RT-PRE is missing (init failed), xt_conntrack or xt_mark modules are absent, an ipset referenced by the rule does not exist, or the xtables lock is contended.","commonSituations":"Enabling an exit node or routed network on minimal kernels without xt_mark/xt_conntrack; a prior createContainers failure that init logged but the caller ignored for jump rules; manual iptables flushes between operations; concurrent firewall tooling (firewalld, ufw scripts).","solutions":["Confirm chains exist: sudo iptables -t mangle -S NETBIRD-RT-PRE; if absent, restart the agent to re-init","Load match modules: modprobe xt_conntrack xt_mark xt_set","Check the log for the inner cause ('error while adding marking rule' / 'apply network') and resolve it","Free the xtables lock and avoid concurrent iptables tools while the agent applies routes"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# preflight the matches the rule needs\nmodprobe xt_conntrack xt_mark xt_set\nsudo iptables -t mangle -S NETBIRD-RT-PRE   # chain must exist","typeGuard":null,"tryCatchPattern":"if err := r.addNatRule(pair); err != nil {\n\tif isXtablesLockErr(err) { // 'Permission denied'/'Resource temporarily unavailable' on the lock\n\t\ttime.Sleep(200 * time.Millisecond)\n\t\treturn r.addNatRule(pair)\n\t}\n\treturn fmt.Errorf(\"add nat rule: %w\", err)\n}","preventionTips":["Ensure xt_conntrack/xt_mark/xt_set are loadable before enabling masqueraded routes","Keep a single iptables backend (legacy or nft) for the daemon's lifetime","Avoid parallel firewall tooling during route application"],"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"}