safesocket, wgengine: add some darwin failure diagnostic hints

This commit is contained in:
Brad Fitzpatrick 2021-02-15 08:40:52 -08:00
parent f4ae745b0b
commit bbb4631e04
2 changed files with 33 additions and 8 deletions

View File

@ -13,6 +13,7 @@
"log" "log"
"net" "net"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
@ -54,6 +55,9 @@ func listen(path string, port uint16) (ln net.Listener, _ uint16, err error) {
c, err := net.Dial("unix", path) c, err := net.Dial("unix", path)
if err == nil { if err == nil {
c.Close() c.Close()
if tailscaledRunningUnderLaunchd() {
return nil, 0, fmt.Errorf("%v: address already in use; tailscaled already running under launchd (to stop, run: $ sudo launchctl stop com.tailscale.tailscaled)", path)
}
return nil, 0, fmt.Errorf("%v: address already in use", path) return nil, 0, fmt.Errorf("%v: address already in use", path)
} }
_ = os.Remove(path) _ = os.Remove(path)
@ -86,6 +90,16 @@ func listen(path string, port uint16) (ln net.Listener, _ uint16, err error) {
return pipe, 0, err return pipe, 0, err
} }
func tailscaledRunningUnderLaunchd() bool {
if runtime.GOOS != "darwin" {
return false
}
plist, err := exec.Command("launchctl", "list", "com.tailscale.tailscaled").Output()
_ = plist // parse it? https://github.com/DHowett/go-plist if we need something.
running := err == nil
return running
}
// socketPermissionsForOS returns the permissions to use for the // socketPermissionsForOS returns the permissions to use for the
// tailscaled.sock. // tailscaled.sock.
func socketPermissionsForOS() os.FileMode { func socketPermissionsForOS() os.FileMode {

View File

@ -171,16 +171,16 @@ func NewFakeUserspaceEngine(logf logger.Logf, listenPort uint16, impl FakeImplFu
// NewUserspaceEngine creates the named tun device and returns a // NewUserspaceEngine creates the named tun device and returns a
// Tailscale Engine running on it. // Tailscale Engine running on it.
func NewUserspaceEngine(logf logger.Logf, tunname string, listenPort uint16) (Engine, error) { func NewUserspaceEngine(logf logger.Logf, tunName string, listenPort uint16) (Engine, error) {
if tunname == "" { if tunName == "" {
return nil, fmt.Errorf("--tun name must not be blank") return nil, fmt.Errorf("--tun name must not be blank")
} }
logf("Starting userspace wireguard engine with tun device %q", tunname) logf("Starting userspace wireguard engine with tun device %q", tunName)
tun, err := tun.CreateTUN(tunname, minimalMTU) tun, err := tun.CreateTUN(tunName, minimalMTU)
if err != nil { if err != nil {
diagnoseTUNFailure(logf) diagnoseTUNFailure(tunName, logf)
logf("CreateTUN: %v", err) logf("CreateTUN: %v", err)
return nil, err return nil, err
} }
@ -1363,16 +1363,27 @@ func (e *userspaceEngine) Ping(ip netaddr.IP, cb func(*ipnstate.PingResult)) {
// the system and log some diagnostic info that might help debug why // the system and log some diagnostic info that might help debug why
// TUN failed. Because TUN's already failed and things the program's // TUN failed. Because TUN's already failed and things the program's
// about to end, we might as well log a lot. // about to end, we might as well log a lot.
func diagnoseTUNFailure(logf logger.Logf) { func diagnoseTUNFailure(tunName string, logf logger.Logf) {
switch runtime.GOOS { switch runtime.GOOS {
case "linux": case "linux":
diagnoseLinuxTUNFailure(logf) diagnoseLinuxTUNFailure(tunName, logf)
case "darwin":
diagnoseDarwinTUNFailure(tunName, logf)
default: default:
logf("no TUN failure diagnostics for OS %q", runtime.GOOS) logf("no TUN failure diagnostics for OS %q", runtime.GOOS)
} }
} }
func diagnoseLinuxTUNFailure(logf logger.Logf) { func diagnoseDarwinTUNFailure(tunName string, logf logger.Logf) {
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'")
}
if tunName != "utun" {
logf("failed to create TUN device %q; try using tun device \"utun\" instead for automatic selection", tunName)
}
}
func diagnoseLinuxTUNFailure(tunName string, logf logger.Logf) {
kernel, err := exec.Command("uname", "-r").Output() kernel, err := exec.Command("uname", "-r").Output()
kernel = bytes.TrimSpace(kernel) kernel = bytes.TrimSpace(kernel)
if err != nil { if err != nil {