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

  1. Confirm chains exist: sudo iptables -t mangle -S NETBIRD-RT-PRE; if absent, restart the agent to re-init
  2. Load match modules: modprobe xt_conntrack xt_mark xt_set
  3. Check the log for the inner cause ('error while adding marking rule' / 'apply network') and resolve it
  4. 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

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


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/28ff464d8bcdced7. Report an issue: GitHub.