netbirdio/netbird · error

add mangle postrouting rule: %w

Error message

add mangle postrouting rule: %w

What it means

Companion of the prerouting error in setupDataPlaneMark(): appends a CONNMARK rule to mangle POSTROUTING stamping outbound NEW connections with nbnet.DataPlaneMarkOut. Failures are accumulated in a multierror and only logged by init(), so a failure leaves the agent running with asymmetric or missing marks, which can degrade policy routing that matches on those fwmarks.

Source

Thrown at client/firewall/iptables/router_linux.go:507

		"-i", r.wgIface.Name(),
		"-m", "conntrack", "--ctstate", "NEW",
		"-j", "CONNMARK", "--set-mark", fmt.Sprintf("%#x", nbnet.DataPlaneMarkIn),
	}

	if err := r.iptablesClient.AppendUnique(tableMangle, chainPREROUTING, preRule...); err != nil {
		merr = multierror.Append(merr, fmt.Errorf("add mangle prerouting rule: %w", err))
	} else {
		r.rules[markManglePre] = preRule
	}

	postRule := []string{
		"-o", r.wgIface.Name(),
		"-m", "conntrack", "--ctstate", "NEW",
		"-j", "CONNMARK", "--set-mark", fmt.Sprintf("%#x", nbnet.DataPlaneMarkOut),
	}

	if err := r.iptablesClient.AppendUnique(tableMangle, chainPOSTROUTING, postRule...); err != nil {
		merr = multierror.Append(merr, fmt.Errorf("add mangle postrouting rule: %w", err))
	} else {
		r.rules[markManglePost] = postRule
	}

	return nberrors.FormatErrorOrNil(merr)
}

func (r *router) cleanupDataPlaneMark() error {
	var merr *multierror.Error
	if preRule, exists := r.rules[markManglePre]; exists {
		if err := r.iptablesClient.DeleteIfExists(tableMangle, chainPREROUTING, preRule...); err != nil {
			merr = multierror.Append(merr, fmt.Errorf("remove mangle prerouting rule: %w", err))
		} else {
			delete(r.rules, markManglePre)
		}
	}

	if postRule, exists := r.rules[markManglePost]; exists {

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Reproduce manually with `iptables -t mangle -A POSTROUTING -o wt0 -m conntrack --ctstate NEW -j CONNMARK --set-mark 0x...`
  2. `modprobe iptable_mangle xt_conntrack xt_connmark`
  3. Verify privileges of the netbird daemon (root or CAP_NET_ADMIN)
  4. Check the full multierror in the log (both prerouting and postrouting usually fail together, confirming a table/module problem rather than the rule itself)
  5. Run `netbird down && netbird up` to retry setup once the host issue is fixed

Example fix

// before
if err := r.iptablesClient.AppendUnique(tableMangle, chainPOSTROUTING, postRule...); err != nil {
    merr = multierror.Append(merr, fmt.Errorf("add mangle postrouting rule: %w", err))
}

// after: keep bookkeeping only on success, but surface stderr of iptables in context
if err := r.iptablesClient.AppendUnique(tableMangle, chainPOSTROUTING, postRule...); err != nil {
    merr = multierror.Append(merr, fmt.Errorf("add mangle postrouting rule (iface %s): %w", r.wgIface.Name(), err))
} else {
    r.rules[markManglePost] = postRule
}
Defensive patterns

Strategy: try-catch

Validate before calling

func mangleWritable(ipt *iptables.IPTables) error {
    probe := []string{"-j", "MARK", "--set-mark", "0x0/0xff00"}
    if err := ipt.AppendUnique("mangle", "POSTROUTING", probe...); err != nil {
        return err
    }
    return ipt.DeleteIfExists("mangle", "POSTROUTING", probe...)
}

Try / catch

Treat prerouting and postrouting mark failures as one unit: log once, keep going, and re-run setupDataPlaneMark on the next Reset so a transient lock failure self-heals.

Prevention

When it happens

Trigger: AppendUnique("mangle", "POSTROUTING", "-o", wgIface, "-m", "conntrack", "--ctstate", "NEW", "-j", "CONNMARK", ...) failing on missing iptable_mangle/xt_connmark/xt_conntrack modules, missing CAP_NET_ADMIN, xtables lock contention, or an interface that disappeared between creation and rule programming.

Common situations: Same class as the prerouting variant: stripped kernels, unprivileged containers, races with other firewall managers during `netbird up`, or hosts where the mangle table exists but connmark helpers were built as unavailable modules.

Related errors


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