2
0
Эх сурвалжийг харах

cmd/xdpderper: add autodetection for default interface name

This makes deployment easier in hetrogenous environments.

Updates ENG-4274

Signed-off-by: James Tucker <[email protected]>
James Tucker 1 жил өмнө
parent
commit
b565a9faa7

+ 13 - 2
cmd/xdpderper/xdpderper.go

@@ -15,11 +15,12 @@ import (
 
 	"github.com/prometheus/client_golang/prometheus"
 	"tailscale.com/derp/xdp"
+	"tailscale.com/net/netutil"
 	"tailscale.com/tsweb"
 )
 
 var (
-	flagDevice  = flag.String("device", "", "target device name")
+	flagDevice  = flag.String("device", "", "target device name (default: autodetect)")
 	flagPort    = flag.Int("dst-port", 0, "destination UDP port to serve")
 	flagVerbose = flag.Bool("verbose", false, "verbose output including verifier errors")
 	flagMode    = flag.String("mode", "xdp", "XDP mode; valid modes: [xdp, xdpgeneric, xdpdrv, xdpoffload]")
@@ -41,8 +42,18 @@ func main() {
 	default:
 		log.Fatal("invalid mode")
 	}
+	deviceName := *flagDevice
+	if deviceName == "" {
+		var err error
+		deviceName, _, err = netutil.DefaultInterfacePortable()
+		if err != nil || deviceName == "" {
+			log.Fatalf("failed to detect default route interface: %v", err)
+		}
+	}
+	log.Printf("binding to device: %s", deviceName)
+
 	server, err := xdp.NewSTUNServer(&xdp.STUNServerConfig{
-		DeviceName:      *flagDevice,
+		DeviceName:      deviceName,
 		DstPort:         *flagPort,
 		AttachFlags:     attachFlags,
 		FullVerifierErr: *flagVerbose,

+ 64 - 0
net/netutil/default_interface_portable.go

@@ -0,0 +1,64 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package netutil
+
+import (
+	"errors"
+	"net"
+	"net/netip"
+)
+
+// DefaultInterfacePortable looks up the current default interface using a portable lookup method that
+// works on most systems with a BSD style socket interface.
+//
+// Returns the interface name and IP address of the default route interface.
+//
+// If the default cannot be determined, an error is returned.
+// Requires that there is a route on the system servicing UDP IPv4.
+func DefaultInterfacePortable() (string, netip.Addr, error) {
+	// Note: UDP dial just performs a connect(2), and doesn't actually send a packet.
+	c, err := net.Dial("udp4", "8.8.8.8:53")
+	if err != nil {
+		return "", netip.Addr{}, err
+	}
+	laddr := c.LocalAddr().(*net.UDPAddr)
+	c.Close()
+
+	ifs, err := net.Interfaces()
+	if err != nil {
+		return "", netip.Addr{}, err
+	}
+
+	var (
+		iface *net.Interface
+		ipnet *net.IPNet
+	)
+	for _, ifc := range ifs {
+		addrs, err := ifc.Addrs()
+		if err != nil {
+			return "", netip.Addr{}, err
+		}
+		for _, addr := range addrs {
+			if ipn, ok := addr.(*net.IPNet); ok {
+				if ipn.Contains(laddr.IP) {
+					if ipnet == nil {
+						ipnet = ipn
+						iface = &ifc
+					} else {
+						newSize, _ := ipn.Mask.Size()
+						oldSize, _ := ipnet.Mask.Size()
+						if newSize > oldSize {
+							ipnet = ipn
+							iface = &ifc
+						}
+					}
+				}
+			}
+		}
+	}
+	if iface == nil {
+		return "", netip.Addr{}, errors.New("no default interface")
+	}
+	return iface.Name, laddr.AddrPort().Addr(), nil
+}

+ 25 - 0
net/netutil/default_interface_portable_test.go

@@ -0,0 +1,25 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package netutil
+
+import (
+	"testing"
+)
+
+func TestDefaultInterfacePortable(t *testing.T) {
+	ifName, addr, err := DefaultInterfacePortable()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	t.Logf("Default interface: %s", ifName)
+	t.Logf("Default address: %s", addr)
+
+	if ifName == "" {
+		t.Fatal("Default interface name is empty")
+	}
+	if !addr.IsValid() {
+		t.Fatal("Default address is invalid")
+	}
+}