From 36daea95511637dbf1b907927ba131ee8c8cc3ec Mon Sep 17 00:00:00 2001 From: JackDoan Date: Thu, 2 Oct 2025 16:18:34 -0500 Subject: [PATCH 1/2] linux: opt out of naming your tun device yourself --- overlay/tun_linux.go | 45 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/overlay/tun_linux.go b/overlay/tun_linux.go index 44d87465..8bd08cb3 100644 --- a/overlay/tun_linux.go +++ b/overlay/tun_linux.go @@ -4,6 +4,7 @@ package overlay import ( + "errors" "fmt" "io" "net" @@ -101,12 +102,18 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, multiqueu } } + tunNameTemplate := c.GetString("tun.dev", "nebula%d") + tunName, err := findNextTunName(tunNameTemplate) + if err != nil { + return nil, err + } + var req ifReq req.Flags = uint16(unix.IFF_TUN | unix.IFF_NO_PI) if multiqueue { req.Flags |= unix.IFF_MULTI_QUEUE } - copy(req.Name[:], c.GetString("tun.dev", "")) + copy(req.Name[:], tunName) if err = ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil { return nil, err } @@ -123,6 +130,38 @@ func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, multiqueu return t, nil } +func findNextTunName(tunName string) (string, error) { + if !strings.HasSuffix(tunName, "%d") { + return tunName, nil + } + if len(tunName) == 2 { + return "", errors.New("please don't name your tun device '%d'") + } + tunNameTemplate := tunName[:len(tunName)-2] + links, err := netlink.LinkList() + if err != nil { + return "", err + } + var candidateName string + for i := 0; i < 100000; i++ { + candidateName = fmt.Sprintf("%s%d", tunNameTemplate, i) + good := true + for _, link := range links { + if candidateName == link.Attrs().Name { + good = false + break + } + } + if good { + if len(candidateName) > 16 { + return "", errors.New("you have too many nebula networks") + } + return candidateName, nil + } + } + return "", errors.New("failed to find a tun device name") +} + func newTunGeneric(c *config.C, l *logrus.Logger, file *os.File, vpnNetworks []netip.Prefix) (*tun, error) { t := &tun{ ReadWriteCloser: file, @@ -582,9 +621,7 @@ func (t *tun) isGatewayInVpnNetworks(gwAddr netip.Addr) bool { } func (t *tun) getGatewaysFromRoute(r *netlink.Route) routing.Gateways { - var gateways routing.Gateways - link, err := netlink.LinkByName(t.Device) if err != nil { t.l.WithField("Devicename", t.Device).Error("Ignoring route update: failed to get link by name") @@ -633,9 +670,7 @@ func (t *tun) getGatewaysFromRoute(r *netlink.Route) routing.Gateways { } func (t *tun) updateRoutes(r netlink.RouteUpdate) { - gateways := t.getGatewaysFromRoute(&r.Route) - if len(gateways) == 0 { // No gateways relevant to our network, no routing changes required. t.l.WithField("route", r).Debug("Ignoring route update, no gateways") From 3583a3f7aba2cccc6f8d1a1e16338430771c5b64 Mon Sep 17 00:00:00 2001 From: JackDoan Date: Tue, 14 Oct 2025 13:46:21 -0500 Subject: [PATCH 2/2] feedback --- overlay/tun_linux.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/overlay/tun_linux.go b/overlay/tun_linux.go index 8bd08cb3..3148388e 100644 --- a/overlay/tun_linux.go +++ b/overlay/tun_linux.go @@ -137,13 +137,19 @@ func findNextTunName(tunName string) (string, error) { if len(tunName) == 2 { return "", errors.New("please don't name your tun device '%d'") } - tunNameTemplate := tunName[:len(tunName)-2] + + if (len(tunName) - len("%d") + len("0")) > unix.IFNAMSIZ { + return "", fmt.Errorf("your tun device name template %s would result in a name longer than the maximum allowed length of %d", tunName, unix.IFNAMSIZ) + } + + tunNameTemplate := tunName[:len(tunName)-len("%d")] links, err := netlink.LinkList() if err != nil { return "", err } var candidateName string - for i := 0; i < 100000; i++ { + i := 0 + for { candidateName = fmt.Sprintf("%s%d", tunNameTemplate, i) good := true for _, link := range links { @@ -152,10 +158,10 @@ func findNextTunName(tunName string) (string, error) { break } } + if len(candidateName) > unix.IFNAMSIZ { + return "", fmt.Errorf("first available tun device is %s, which is longer than the max allowed size of %d", candidateName, unix.IFNAMSIZ) + } if good { - if len(candidateName) > 16 { - return "", errors.New("you have too many nebula networks") - } return candidateName, nil } }