netbirdio/netbird · error

block wg v4 net: %w

Error message

block wg v4 net: %w

What it means

Returned by blockInvalidRouted (client/firewall/uspfilter/filter.go:372) when installing the userspace drop rule for the IPv4 overlay prefix fails: m.addRouteFiltering(nil, sources, Network{Prefix: wgPrefix}, ProtocolALL, nil, nil, ActionDrop) rejects its inputs or fails registering the rule. This is an in-memory uspfilter rule (no kernel netlink), so failures are input-validation class: an invalid wgPrefix taken from iface.Address().Network (unset address yields an invalid netip.Prefix), or an invalid source network in the sources list.

Source

Thrown at client/firewall/uspfilter/filter.go:372

	sources := []netip.Prefix{netip.PrefixFrom(netip.IPv4Unspecified(), 0)}
	v6Net := iface.Address().IPv6Net
	if v6Net.IsValid() {
		sources = append(sources, netip.PrefixFrom(netip.IPv6Unspecified(), 0))
	}

	var rules []firewall.Rule
	v4Rule, err := m.addRouteFiltering(
		nil,
		sources,
		firewall.Network{Prefix: wgPrefix},
		firewall.ProtocolALL,
		nil,
		nil,
		firewall.ActionDrop,
	)
	if err != nil {
		return rules, fmt.Errorf("block wg v4 net: %w", err)
	}
	rules = append(rules, v4Rule)

	if v6Net.IsValid() {
		log.Debugf("blocking invalid routed traffic for %s", v6Net)
		v6Rule, err := m.addRouteFiltering(
			nil,
			sources,
			firewall.Network{Prefix: v6Net},
			firewall.ProtocolALL,
			nil,
			nil,
			firewall.ActionDrop,
		)
		if err != nil {
			return rules, fmt.Errorf("block wg v6 net: %w", err)
		}
		rules = append(rules, v6Rule)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Verify iface.Address().Network.IsValid() (and Bits() within 0..32) before calling EnableRouting/blockInvalidRouted
  2. Re-run EnableRouting after the interface address is configured; EnableRouting is idempotent under the manager mutex
  3. Log the wgPrefix value in the error path so an invalid prefix is immediately visible
  4. If sources are dynamic, snapshot them under lock before building rules

Example fix

// before
v4Rule, err := m.addRouteFiltering(nil, sources, firewall.Network{Prefix: wgPrefix}, firewall.ProtocolALL, nil, nil, firewall.ActionDrop)
if err != nil {
    return rules, fmt.Errorf("block wg v4 net: %w", err)
}
// after
if !wgPrefix.IsValid() || wgPrefix.Bits() < 0 || wgPrefix.Bits() > 32 {
    return rules, fmt.Errorf("block wg v4 net: invalid overlay prefix %s", wgPrefix)
}
v4Rule, err := m.addRouteFiltering(nil, sources, firewall.Network{Prefix: wgPrefix}, firewall.ProtocolALL, nil, nil, firewall.ActionDrop)
if err != nil {
    return rules, fmt.Errorf("block wg v4 net: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

addr := iface.Address()
if !addr.Network.IsValid() || addr.Network.Bits() < 0 || addr.Network.Bits() > 32 {
    return fmt.Errorf("cannot enable routing: overlay prefix %s invalid", addr.Network)
}
if err := fw.EnableRouting(); err != nil { ... }

Type guard

func validOverlayV4Prefix(p netip.Prefix) bool {
    return p.IsValid() && p.Addr().Is4() && p.Bits() >= 0 && p.Bits() <= 32
}

Try / catch

if err := fw.EnableRouting(); err != nil {
    if strings.Contains(err.Error(), "block wg v4 net") {
        // no protection installed; fail closed for routed traffic
        return fmt.Errorf("routing blocked until overlay prefix is valid: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: EnableRouting called before the interface address was assigned, so wgPrefix (iface.Address().Network) is not a valid prefix; sources containing an invalid/expired network object; manager state reset concurrently with EnableRouting.

Common situations: Race between engine bring-up and routing enable on slow address configuration; netstack mode where Address() is populated late; management network-map updates replacing sources mid-install.

Related errors


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