netbirdio/netbird · error
add nat rule: %w
Error message
add nat rule: %w
What it means
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.
Source
Thrown at client/firewall/iptables/router_linux.go:279
log.Debugf("Deleted unused ipset %s", setName)
return nil
}
// AddNatRule inserts an iptables rule pair into the nat chain
func (r *router) AddNatRule(pair firewall.RouterPair) error {
if r.legacyManagement {
log.Warnf("This peer is connected to a NetBird Management service with an older version. Allowing all traffic for %s", pair.Destination)
if err := r.addLegacyRouteRule(pair); err != nil {
return fmt.Errorf("add legacy routing rule: %w", err)
}
}
if !pair.Masquerade {
return nil
}
if err := r.addNatRule(pair); err != nil {
return fmt.Errorf("add nat rule: %w", err)
}
if err := r.addNatRule(firewall.GetInversePair(pair)); err != nil {
return fmt.Errorf("add inverse nat rule: %w", err)
}
r.updateState()
return nil
}
// RemoveNatRule removes an iptables rule pair from forwarding and nat chains
func (r *router) RemoveNatRule(pair firewall.RouterPair) error {
if pair.Masquerade {
if err := r.removeNatRule(pair); err != nil {
return fmt.Errorf("remove nat rule: %w", err)
}
View on GitHub (pinned to 93e97f4bf1)
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
Defensive patterns
Strategy: validation
Validate before calling
# preflight the matches the rule needs modprobe xt_conntrack xt_mark xt_set sudo iptables -t mangle -S NETBIRD-RT-PRE # chain must exist
Try / catch
if err := r.addNatRule(pair); err != nil {
if isXtablesLockErr(err) { // 'Permission denied'/'Resource temporarily unavailable' on the lock
time.Sleep(200 * time.Millisecond)
return r.addNatRule(pair)
}
return fmt.Errorf("add nat rule: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- add inverse nat rule: %w
- remove nat rule: %w
- remove inverse nat rule: %w
- add static nat rules: %w
- add outbound masquerade rule: %v
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/28ff464d8bcdced7.
Report an issue: GitHub.