{"record":{"id":"64c8f5cef556edff","repo":"netbirdio/netbird","slug":"add-return-masquerade-rule-v","errorCode":null,"errorMessage":"add return masquerade rule: %v","messagePattern":"add return masquerade rule: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/router_linux.go","lineNumber":555,"sourceCode":"\t// First rule for outbound masquerade\n\trule1 := []string{\n\t\t\"-m\", \"mark\", \"--mark\", fmt.Sprintf(\"%#x\", nbnet.PreroutingFwmarkMasquerade),\n\t\t\"!\", \"-o\", \"lo\",\n\t\t\"-j\", routingFinalNatJump,\n\t}\n\tif err := r.iptablesClient.Append(tableNat, chainRTNAT, rule1...); err != nil {\n\t\treturn fmt.Errorf(\"add outbound masquerade rule: %v\", err)\n\t}\n\tr.rules[\"static-nat-outbound\"] = rule1\n\n\t// Second rule for return traffic masquerade\n\trule2 := []string{\n\t\t\"-m\", \"mark\", \"--mark\", fmt.Sprintf(\"%#x\", nbnet.PreroutingFwmarkMasqueradeReturn),\n\t\t\"-o\", r.wgIface.Name(),\n\t\t\"-j\", routingFinalNatJump,\n\t}\n\tif err := r.iptablesClient.Append(tableNat, chainRTNAT, rule2...); err != nil {\n\t\treturn fmt.Errorf(\"add return masquerade rule: %v\", err)\n\t}\n\tr.rules[\"static-nat-return\"] = rule2\n\n\treturn nil\n}\n\n// addMSSClampingRules adds MSS clamping rules to prevent fragmentation for forwarded traffic.\nfunc (r *router) addMSSClampingRules() error {\n\toverhead := uint16(ipv4TCPHeaderSize)\n\tif r.v6 {\n\t\toverhead = ipv6TCPHeaderSize\n\t}\n\tmss := r.mtu - overhead\n\n\t// Add jump rule from FORWARD chain in mangle table to our custom chain\n\tjumpRule := []string{\n\t\t\"-j\", chainRTMSSCLAMP,\n\t}","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/router_linux.go#L537-L573","documentation":"Second rule of addPostroutingRules(): appending the return-traffic masquerade rule (match PreroutingFwmarkMasqueradeReturn, out the NetBird interface, MASQUERADE) to NETBIRD-RT-NAT. Failure aborts createContainers() with 'add static nat rules'; note rule1 may already be installed, leaving partially programmed state that only a later Reset cleans up.","triggerScenarios":"`iptables -t nat -A NETBIRD-RT-NAT -m mark --mark 0x... -o wt0 -j MASQUERADE` failing when the NetBird interface name just changed/disappeared (e.g., interface recreated between operations), or the same missing-module/permission/lock causes as the outbound rule.","commonSituations":"Interface name churn after a quick down/up cycle; IPv6 pairs where ip6table_nat is missing while IPv4 works; systems that resolved the first append but lost the xtables lock to a concurrent docker restart mid-setup.","solutions":["Check the agent log whether the outbound rule succeeded just before (if yes, suspect the interface-name or transient-lock angle)","Reproduce: `iptables -t nat -A NETBIRD-RT-NAT -m mark --mark 0x... -o wt0 -j MASQUERADE`","`modprobe iptable_nat xt_MASQUERADE xt_mark` and verify ip6table_nat for dual-stack","Run `netbird down` (cleans the half-applied state) before retrying `netbird up`","If the interface name changed, restart the daemon so wgIface.Name() is current"],"exampleFix":"// before: rule1 already installed; on rule2 failure the half-state persists\nif err := r.iptablesClient.Append(tableNat, chainRTNAT, rule2...); err != nil {\n    return fmt.Errorf(\"add return masquerade rule: %v\", err)\n}\n\n// after: roll rule1 back so setup fails atomically\nif err := r.iptablesClient.Append(tableNat, chainRTNAT, rule2...); err != nil {\n    if delErr := r.iptablesClient.DeleteIfExists(tableNat, chainRTNAT, rule1...); delErr != nil {\n        log.Warnf(\"rollback outbound masquerade rule: %v\", delErr)\n    }\n    delete(r.rules, \"static-nat-outbound\")\n    return fmt.Errorf(\"add return masquerade rule: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"func ifaceExists(name string) bool {\n    _, err := net.InterfaceByName(name)\n    return err == nil\n}","typeGuard":null,"tryCatchPattern":"On rule2 failure, roll back rule1 (DeleteIfExists on the stored spec) before returning, keeping the nat chain either fully programmed or untouched.","preventionTips":["Keep the NetBird interface stable across route updates; avoid down/up flapping while management pushes changes","Preload the same modules as for the outbound rule","After any failed `netbird up`, run `netbird down` to clear half-applied NAT chains"],"tags":["network","linux","iptables","nat","masquerade"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}