slackhq/nebula · critical

unable to create AF_ROUTE socket: %v

Error message

unable to create AF_ROUTE socket: %v

What it means

addRoute on NetBSD needs a raw routing socket (AF_ROUTE) to inject RTM_ADD messages into the kernel routing table. This error is returned when socket(AF_ROUTE, SOCK_RAW, AF_UNSPEC) fails. It indicates the process cannot create a routing socket, so the route cannot be installed.

Source

Thrown at overlay/tun_netbsd.go:448

			t.l.Error("Failed to remove route", "error", err, "route", r)
		} else {
			t.l.Info("Removed route", "route", r)
		}
	}
	return nil
}

func (t *tun) deviceBytes() (o [16]byte) {
	for i, c := range t.Device {
		o[i] = byte(c)
	}
	return
}

func addRoute(prefix netip.Prefix, gateways []netip.Prefix) error {
	sock, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
	if err != nil {
		return fmt.Errorf("unable to create AF_ROUTE socket: %v", err)
	}
	defer unix.Close(sock)

	route := &netroute.RouteMessage{
		Version: unix.RTM_VERSION,
		Type:    unix.RTM_ADD,
		Flags:   unix.RTF_UP | unix.RTF_GATEWAY,
		Seq:     1,
	}

	if prefix.Addr().Is4() {
		gw, err := selectGateway(prefix, gateways)
		if err != nil {
			return err
		}
		route.Addrs = []netroute.Addr{
			unix.RTAX_DST:     &netroute.Inet4Addr{IP: prefix.Masked().Addr().As4()},
			unix.RTAX_NETMASK: &netroute.Inet4Addr{IP: prefixToMask(prefix).As4()},

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Run the process as root or grant the equivalent network-administration privileges.
  2. Check and raise the file-descriptor limit (ulimit -n) if errno is EMFILE/ENFILE.
  3. Inspect the wrapped errno (%v) to determine the exact kernel rejection reason.
  4. Verify no MAC/securelevel policy on the host blocks AF_ROUTE sockets for the user.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before addRoutes: check we can create a routing socket
probe, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
if err != nil {
    return fmt.Errorf("process lacks permission to create routing sockets; run as root: %w", err)
}
unix.Close(probe)

// and check fd headroom
var lim unix.Rlimit
unix.Getrlimit(unix.RLIMIT_NOFILE, &lim)
if lim.Cur < 64 {
    return fmt.Errorf("file descriptor limit too low: %d", lim.Cur)
}

Try / catch

if err := addRoute(prefix, gateways); err != nil {
    var errno syscall.Errno
    if errors.As(err, &errno) {
        switch errno {
        case unix.EPERM, unix.EACCES:
            return fmt.Errorf("need root privileges to manage routes")
        case unix.EMFILE, unix.ENFILE:
            return fmt.Errorf("fd limit reached; raise ulimit -n")
        }
    }
    return err
}

Prevention

When it happens

Trigger: addRoute (via addRoutes) calling unix.Socket(unix.AF_ROUTE, ...) which fails, typically EACCES/EPERM because the process is not root, or resource exhaustion (EMFILE/ENFILE).

Common situations: Running the VPN client without root/CAP_NET_ADMIN on a NetBSD host; hitting the process file-descriptor limit; hardened security settings (securelevel) restricting routing sockets.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/a55dd0f11b2b65d7. Report an issue: GitHub.