netbirdio/netbird · error

allow netbird v4 interface traffic: %w

Error message

allow netbird v4 interface traffic: %w

What it means

AllowNetbird installs a blanket ACCEPT for all v4 overlay traffic (0.0.0.0, ProtocolALL) via AddPeerFiltering, so that packet filtering happens in userspace when USPFilter wraps the native firewall (called from client/firewall/create_linux.go:108). This error means the v4 accept rule could not be appended to NETBIRD-ACL-INPUT; the uspfilter wrapper logs it and continues, but the kernel chain may then drop overlay traffic that userspace expected to be pre-allowed.

Source

Thrown at client/firewall/iptables/manager_linux.go:381

	}

	// attempt to delete state only if all other operations succeeded
	if merr == nil {
		if err := stateManager.DeleteState(&ShutdownState{}); err != nil {
			merr = multierror.Append(merr, fmt.Errorf("delete state: %w", err))
		}
	}

	return nberrors.FormatErrorOrNil(merr)
}

// AllowNetbird allows netbird interface traffic.
// This is called when USPFilter wraps the native firewall, adding blanket accept
// rules so that packet filtering is handled in userspace instead of by netfilter.
func (m *Manager) AllowNetbird() error {
	var merr *multierror.Error
	if _, err := m.AddPeerFiltering(nil, net.IP{0, 0, 0, 0}, firewall.ProtocolALL, nil, nil, firewall.ActionAccept, ""); err != nil {
		merr = multierror.Append(merr, fmt.Errorf("allow netbird v4 interface traffic: %w", err))
	}
	if m.hasIPv6() {
		if _, err := m.AddPeerFiltering(nil, net.IPv6zero, firewall.ProtocolALL, nil, nil, firewall.ActionAccept, ""); err != nil {
			merr = multierror.Append(merr, fmt.Errorf("allow netbird v6 interface traffic: %w", err))
		}
	}

	if err := firewalld.TrustInterface(m.wgIface.Name()); err != nil {
		log.Warnf("failed to trust interface in firewalld: %v", err)
	}

	return nberrors.FormatErrorOrNil(merr)
}

// Flush doesn't need to be implemented for this manager
func (m *Manager) Flush() error { return nil }

// SetLogLevel sets the log level for the firewall manager

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Restart the agent: Init re-creates the ACL chains and AllowNetbird is retried during firewall creation
  2. Verify the chain exists as root: iptables -S NETBIRD-ACL-INPUT
  3. If it recurs, find the external tool rewriting the filter table and exclude the NETBIRD chains
Defensive patterns

Strategy: try-catch

Validate before calling

// before relying on userspace filtering, confirm the v4 accept chain exists
if out, err := exec.Command("iptables", "-S", "NETBIRD-ACL-INPUT").Output(); err != nil {
    log.Warnf("ACL chain missing; AllowNetbird rule cannot hold: %s", out)
}

Try / catch

if err := fm.AllowNetbird(); err != nil {
    log.Errorf("userspace pre-allow failed; overlay traffic may be dropped by kernel chains: %v", err)
    // recreate chains via restart rather than proceeding degraded
}

Prevention

When it happens

Trigger: AllowNetbird when the v4 aclManager append fails - NETBIRD-ACL-INPUT missing after an external flush, iptables erroring, or a race with Close/reset.

Common situations: Userspace-bind agents (no kernel WireGuard) whose native chains were wiped by docker/podman/firewalld mid-run; chains removed between Init and AllowNetbird.

Related errors


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