{"record":{"id":"b38ffb95a8771e7d","repo":"slackhq/nebula","slug":"newtunfromfd-not-supported-in-netbsd","errorCode":null,"errorMessage":"newTunFromFd not supported in NetBSD","messagePattern":"newTunFromFd not supported in NetBSD","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"overlay/tun_netbsd.go","lineNumber":74,"sourceCode":"\tVltime    uint32\n\tPltime    uint32\n}\n\ntype tun struct {\n\tDevice      string\n\tvpnNetworks []netip.Prefix\n\tMTU         int\n\tRoutes      atomic.Pointer[[]Route]\n\trouteTree   atomic.Pointer[bart.Table[routing.Gateways]]\n\tl           *slog.Logger\n\tf           *os.File\n\tfd          int\n}\n\nvar deviceNameRE = regexp.MustCompile(`^tun[0-9]+$`)\n\nfunc newTunFromFd(_ *config.C, _ *slog.Logger, _ int, _ []netip.Prefix) (*tun, error) {\n\treturn nil, fmt.Errorf(\"newTunFromFd not supported in NetBSD\")\n}\n\nfunc newTun(c *config.C, l *slog.Logger, vpnNetworks []netip.Prefix, _ bool) (*tun, error) {\n\t// Try to open tun device\n\tvar err error\n\tdeviceName := c.GetString(\"tun.dev\", \"\")\n\tif deviceName == \"\" {\n\t\treturn nil, fmt.Errorf(\"a device name in the format of /dev/tunN must be specified\")\n\t}\n\tif !deviceNameRE.MatchString(deviceName) {\n\t\treturn nil, fmt.Errorf(\"a device name in the format of /dev/tunN must be specified\")\n\t}\n\n\tfd, err := unix.Open(\"/dev/\"+deviceName, os.O_RDWR, 0)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/overlay/tun_netbsd.go#L56-L92","documentation":"newTunFromFd on NetBSD is an unimplemented stub that always returns this error. Passing an existing tun fd to the overlay constructor is simply not supported on NetBSD, unlike Linux. The only supported path there is newTun, which opens /dev/tunN by name.","triggerScenarios":"Any call path that constructs the tun from a pre-opened file descriptor while running on NetBSD — e.g. handoff/hot-reload flows or embedders that create the tun device themselves and pass the fd in.","commonSituations":"Deploying a fd-passing setup (systemd socket handoff, custom embedding, zero-downtime reload) that works on Linux onto a NetBSD host.","solutions":["On NetBSD, configure a device name (tun.dev) so newTun (the /dev/tunN path) is used instead of fd handoff.","Remove or gate fd-injection logic behind a Linux-only build/runtime check.","If fd handoff is required, implement newTunFromFd for NetBSD upstream or use an OS with support (Linux)."],"exampleFix":"// before: unconditional fd handoff\nt, err := overlay.NewTunFromFd(c, l, fd, networks)\n// after\nif runtime.GOOS == \"netbsd\" {\n    t, err = overlay.NewTun(c, l, networks, false)\n} else {\n    t, err = overlay.NewTunFromFd(c, l, fd, networks)\n}","handlingStrategy":"fallback","validationCode":"// choose constructor by platform before calling\nif runtime.GOOS == \"netbsd\" {\n    // fd path unsupported; must use name-based newTun\n    return errors.New(\"fd-based tun creation unsupported on netbsd; set tun.dev\")\n}","typeGuard":null,"tryCatchPattern":"t, err := tryNewTunFromFd(c, l, fd, networks)\nif err != nil && strings.Contains(err.Error(), \"newTunFromFd not supported\") {\n    t, err = newTun(c, l, networks, false) // name-based fallback\n}","preventionTips":["Gate fd-handoff code paths behind runtime.GOOS checks","Always configure tun.dev so the name-based path works on any OS","Document OS support matrix for embedding users"],"tags":["netbsd","tun","unsupported","platform"],"backgroundTag":"unsupported-platform-feature","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}