cmd/xdpderper: add autodetection for default interface name

This makes deployment easier in hetrogenous environments.

Updates ENG-4274

Signed-off-by: James Tucker <james@tailscale.com>
pull/12659/head
James Tucker 3 months ago committed by James Tucker
parent 781f79408d
commit b565a9faa7

@ -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,

@ -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
}

@ -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")
}
}
Loading…
Cancel
Save