netbirdio/netbird · info

creating default v6 subnet: %w

Error message

creating default v6 subnet: %w

What it means

Returned when tcpip.NewSubnet rejects the default IPv6 catch-all ::/0. Like its IPv4 twin, NewSubnet only errors on a non-contiguous mask, and the code passes a literal 16-zero-byte mask, so with the constants as written this branch is unreachable defensive error handling.

Source

Thrown at client/firewall/uspfilter/forwarder/forwarder.go:125

		if err := s.AddProtocolAddress(nicID, v6Addr, stack.AddressProperties{}); err != nil {
			return nil, fmt.Errorf("add IPv6 protocol address: %s", err)
		}
	}

	defaultSubnet, err := tcpip.NewSubnet(
		tcpip.AddrFrom4([4]byte{0, 0, 0, 0}),
		tcpip.MaskFromBytes([]byte{0, 0, 0, 0}),
	)
	if err != nil {
		return nil, fmt.Errorf("creating default subnet: %w", err)
	}

	defaultSubnetV6, err := tcpip.NewSubnet(
		tcpip.AddrFrom16([16]byte{}),
		tcpip.MaskFromBytes(make([]byte, 16)),
	)
	if err != nil {
		return nil, fmt.Errorf("creating default v6 subnet: %w", err)
	}

	if err := s.SetPromiscuousMode(nicID, true); err != nil {
		return nil, fmt.Errorf("set promiscuous mode: %s", err)
	}
	if err := s.SetSpoofing(nicID, true); err != nil {
		return nil, fmt.Errorf("set spoofing: %s", err)
	}

	s.SetRouteTable([]tcpip.Route{
		{Destination: defaultSubnet, NIC: nicID},
		{Destination: defaultSubnetV6, NIC: nicID},
	})

	ctx, cancel := context.WithCancel(context.Background())
	f := &Forwarder{
		logger:        logger,
		flowLogger:    flowLogger,

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. No action needed for the literal form
  2. If the mask becomes computed, construct it exclusively via tcpip.MaskFromBits(prefixLen) with prefixLen validated to 0..128
  3. Verify gVisor version compatibility after upgrades if this ever fires
Defensive patterns

Strategy: try-catch

Try / catch

f, err := forwarder.New(iface, logger, flowLogger, netstack, mtu)
if err != nil {
    log.Errorf("forwarder init failed: %v", err)
    return err
}

Prevention

When it happens

Trigger: Only possible if the hardcoded make([]byte, 16) mask is replaced by computed bytes with holes in it, or gVisor's NewSubnet semantics change between versions.

Common situations: Not observed in practice; a developer who copies this constructor and derives the mask from a variable (e.g. a user-supplied prefix) can trigger it with an invalid mask.

Related errors


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