net/tstun: diagnose /dev/net/tun fd leak, give better failure message

Updates #5029

Change-Id: Ibee5e0c9076fe764eb5d856d5ef8b09f4d0e2921
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
pull/5071/head
Brad Fitzpatrick 2 years ago committed by Brad Fitzpatrick
parent 931f18b575
commit 0d52674a84

@ -515,7 +515,7 @@ func tryEngine(logf logger.Logf, linkMon *monitor.Mon, dialer *tsdial.Dialer, na
} else {
dev, devName, err := tstun.New(logf, name)
if err != nil {
tstun.Diagnose(logf, name)
tstun.Diagnose(logf, name, err)
return nil, false, fmt.Errorf("tstun.New(%q): %w", name, err)
}
conf.Tun = dev

@ -74,15 +74,18 @@ func New(logf logger.Logf, tunName string) (tun.Device, string, error) {
// tunDiagnoseFailure, if non-nil, does OS-specific diagnostics of why
// TUN failed to work.
var tunDiagnoseFailure func(tunName string, logf logger.Logf)
var tunDiagnoseFailure func(tunName string, logf logger.Logf, err error)
// Diagnose tries to explain a tuntap device creation failure.
// It pokes around the system and logs some diagnostic info that might
// help debug why tun creation failed. Because device creation has
// already failed and the program's about to end, log a lot.
func Diagnose(logf logger.Logf, tunName string) {
//
// The tunName is the name of the tun device that was requested but failed.
// The err error is how the tun creation failed.
func Diagnose(logf logger.Logf, tunName string, err error) {
if tunDiagnoseFailure != nil {
tunDiagnoseFailure(tunName, logf)
tunDiagnoseFailure(tunName, logf, err)
} else {
logf("no TUN failure diagnostics for OS %q", runtime.GOOS)
}

@ -6,6 +6,7 @@ package tstun
import (
"bytes"
"errors"
"os"
"os/exec"
"strings"
@ -19,7 +20,14 @@ func init() {
tunDiagnoseFailure = diagnoseLinuxTUNFailure
}
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf) {
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf, createErr error) {
if errors.Is(createErr, syscall.EBUSY) {
logf("TUN device %s is busy; another process probably still has it open (from old version of Tailscale that had a bug)", tunName)
logf("To fix, kill the process that has it open. Find with:\n\n$ sudo lsof -n /dev/net/tun\n\n")
logf("... and then kill those PID(s)")
return
}
var un syscall.Utsname
err := syscall.Uname(&un)
if err != nil {

@ -17,7 +17,7 @@ func init() {
tunDiagnoseFailure = diagnoseDarwinTUNFailure
}
func diagnoseDarwinTUNFailure(tunName string, logf logger.Logf) {
func diagnoseDarwinTUNFailure(tunName string, logf logger.Logf, err error) {
if os.Getuid() != 0 {
logf("failed to create TUN device as non-root user; use 'sudo tailscaled', or run under launchd with 'sudo tailscaled install-system-daemon'")
}

Loading…
Cancel
Save