{"record":{"id":"b280800916f88394","repo":"netbirdio/netbird","slug":"add-mangle-prerouting-rule-w","errorCode":null,"errorMessage":"add mangle prerouting rule: %w","messagePattern":"add mangle prerouting rule: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/router_linux.go","lineNumber":495,"sourceCode":"\n\tif err := r.addMSSClampingRules(); err != nil {\n\t\tlog.Errorf(\"failed to add MSS clamping rules: %s\", err)\n\t}\n\n\treturn nil\n}\n\n// setupDataPlaneMark configures the fwmark for the data plane\nfunc (r *router) setupDataPlaneMark() error {\n\tvar merr *multierror.Error\n\tpreRule := []string{\n\t\t\"-i\", r.wgIface.Name(),\n\t\t\"-m\", \"conntrack\", \"--ctstate\", \"NEW\",\n\t\t\"-j\", \"CONNMARK\", \"--set-mark\", fmt.Sprintf(\"%#x\", nbnet.DataPlaneMarkIn),\n\t}\n\n\tif err := r.iptablesClient.AppendUnique(tableMangle, chainPREROUTING, preRule...); err != nil {\n\t\tmerr = multierror.Append(merr, fmt.Errorf(\"add mangle prerouting rule: %w\", err))\n\t} else {\n\t\tr.rules[markManglePre] = preRule\n\t}\n\n\tpostRule := []string{\n\t\t\"-o\", r.wgIface.Name(),\n\t\t\"-m\", \"conntrack\", \"--ctstate\", \"NEW\",\n\t\t\"-j\", \"CONNMARK\", \"--set-mark\", fmt.Sprintf(\"%#x\", nbnet.DataPlaneMarkOut),\n\t}\n\n\tif err := r.iptablesClient.AppendUnique(tableMangle, chainPOSTROUTING, postRule...); err != nil {\n\t\tmerr = multierror.Append(merr, fmt.Errorf(\"add mangle postrouting rule: %w\", err))\n\t} else {\n\t\tr.rules[markManglePost] = postRule\n\t}\n\n\treturn nberrors.FormatErrorOrNil(merr)\n}","sourceCodeStart":477,"sourceCodeEnd":513,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/router_linux.go#L477-L513","documentation":"One half of setupDataPlaneMark(): the agent appends a CONNMARK rule to mangle PREROUTING that stamps incoming NEW connections on the NetBird interface with nbnet.DataPlaneMarkIn. go-iptables AppendUnique() fails when the iptables invocation errors (it is not a duplicate-rule error, duplicates are tolerated), and the error is accumulated into a multierror that init() only logs, so the agent keeps running but without inbound data-plane marks.","triggerScenarios":"AppendUnique(\"mangle\", \"PREROUTING\", \"-i\", wgIface, \"-m\", \"conntrack\", \"--ctstate\", \"NEW\", \"-j\", \"CONNMARK\", ...) failing because iptable_mangle, xt_conntrack, or xt_connmark is missing, the process lacks CAP_NET_ADMIN, or the xtables lock is contended. Also fails when the interface name referenced does not exist at rule-programming time.","commonSituations":"Minimal/container hosts without conntrack helper modules; NetBird running as a non-root service after a permission change; CONNMARK support compiled out of the kernel (rare, custom kernels); concurrent iptables batch updates from other tooling.","solutions":["Check the agent log for the sibling 'add mangle postrouting rule' entry to see the full multierror","Manually run: `iptables -t mangle -A PREROUTING -i wt0 -m conntrack --ctstate NEW -j CONNMARK --set-mark 0x...`","`modprobe iptable_mangle xt_conntrack xt_connmark` (ip6table_mangle for IPv6)","Confirm the NetBird service runs as root (`systemctl show netbird -p User`)","Restart the agent after freeing the xtables lock so init() retries the mark setup"],"exampleFix":"// before\nif err := r.iptablesClient.AppendUnique(tableMangle, chainPREROUTING, preRule...); err != nil {\n    merr = multierror.Append(merr, fmt.Errorf(\"add mangle prerouting rule: %w\", err))\n}\n\n// after: distinguish 'already there' (benign) from real failure\nexists, xerr := r.iptablesClient.Exists(tableMangle, chainPREROUTING, preRule...)\nif xerr == nil && exists {\n    r.rules[markManglePre] = preRule\n} else if err := r.iptablesClient.AppendUnique(tableMangle, chainPREROUTING, preRule...); err != nil {\n    merr = multierror.Append(merr, fmt.Errorf(\"add mangle prerouting rule: %w\", err))\n}","handlingStrategy":"try-catch","validationCode":"func connmarkSupported(ipt *iptables.IPTables) bool {\n    probe := []string{\"-m\", \"conntrack\", \"--ctstate\", \"NEW\", \"-j\", \"CONNMARK\", \"--set-mark\", \"0x0\"}\n    if err := ipt.AppendUnique(\"mangle\", \"PREROUTING\", probe...); err != nil {\n        return false\n    }\n    _ = ipt.DeleteIfExists(\"mangle\", \"PREROUTING\", probe...)\n    return true\n}","typeGuard":null,"tryCatchPattern":"Accumulate both mangle errors in the existing multierror, then log a single warning with remediation hints (module list) instead of two bare wrapped errors; keep the agent running since marks are an optimization.","preventionTips":["Load xt_conntrack and xt_connmark on routed peers","Monitor agent logs for 'failed to set up data plane mark' after upgrades","Test mangle programmability in your base image CI (`iptables -t mangle -L`)"],"tags":["network","linux","iptables","mangle","conntrack"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}