Przeglądaj źródła

safesocket: refactor macOS auth code, pull out separate LocalTCPPortAndToken

Brad Fitzpatrick 5 lat temu
rodzic
commit
914a486af6

+ 1 - 1
safesocket/basic_test.go

@@ -32,7 +32,7 @@ func TestBasics(t *testing.T) {
 			errs <- err
 			return
 		}
-		fmt.Printf("server read %d bytes.\n", n)
+		t.Logf("server read %d bytes.", n)
 		if string(b[:n]) != "world" {
 			errs <- fmt.Errorf("got %#v, expected %#v\n", string(b[:n]), "world")
 			return

+ 20 - 0
safesocket/safesocket.go

@@ -7,7 +7,9 @@
 package safesocket
 
 import (
+	"errors"
 	"net"
+	"runtime"
 )
 
 type closeable interface {
@@ -43,3 +45,21 @@ func Connect(path string, port uint16) (net.Conn, error) {
 func Listen(path string, port uint16) (_ net.Listener, gotPort uint16, _ error) {
 	return listen(path, port)
 }
+
+var (
+	ErrTokenNotFound = errors.New("no token found")
+	ErrNoTokenOnOS   = errors.New("no token on " + runtime.GOOS)
+)
+
+var localTCPPortAndToken func() (port int, token string, err error)
+
+// LocalTCPPortAndToken returns the port number and auth token to connect to
+// the local Tailscale daemon. It's currently only applicable on macOS
+// when tailscaled is being run in the Mac Sandbox from the App Store version
+// of Tailscale.
+func LocalTCPPortAndToken() (port int, token string, err error) {
+	if localTCPPortAndToken == nil {
+		return 0, "", ErrNoTokenOnOS
+	}
+	return localTCPPortAndToken()
+}

+ 52 - 0
safesocket/safesocket_darwin.go

@@ -0,0 +1,52 @@
+// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package safesocket
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"os"
+	"os/exec"
+	"strconv"
+	"strings"
+)
+
+func init() {
+	localTCPPortAndToken = localTCPPortAndTokenDarwin
+}
+
+func localTCPPortAndTokenDarwin() (port int, token string, err error) {
+	out, err := exec.Command("lsof",
+		"-n",                             // numeric sockets; don't do DNS lookups, etc
+		"-a",                             // logical AND remaining options
+		fmt.Sprintf("-u%d", os.Getuid()), // process of same user only
+		"-c", "IPNExtension",             // starting with IPNExtension
+		"-F", // machine-readable output
+	).Output()
+	if err != nil {
+		return 0, "", fmt.Errorf("failed to run lsof looking for IPNExtension: %w", err)
+	}
+	bs := bufio.NewScanner(bytes.NewReader(out))
+	subStr := []byte(".tailscale.ipn.macos/sameuserproof-")
+	for bs.Scan() {
+		line := bs.Bytes()
+		i := bytes.Index(line, subStr)
+		if i == -1 {
+			continue
+		}
+		f := strings.SplitN(string(line[i+len(subStr):]), "-", 2)
+		if len(f) != 2 {
+			continue
+		}
+		portStr, token := f[0], f[1]
+		port, err := strconv.Atoi(portStr)
+		if err != nil {
+			return 0, "", fmt.Errorf("invalid port %q found in lsof", portStr)
+		}
+		return port, token, nil
+	}
+	return 0, "", ErrTokenNotFound
+}

+ 13 - 0
safesocket/safesocket_test.go

@@ -0,0 +1,13 @@
+// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package safesocket
+
+import "testing"
+
+func TestLocalTCPPortAndToken(t *testing.T) {
+	// Just test that it compiles for now (is available on all platforms).
+	port, token, err := LocalTCPPortAndToken()
+	t.Logf("got %v, %s, %v", port, token, err)
+}

+ 10 - 30
safesocket/unixsocket.go

@@ -7,17 +7,15 @@
 package safesocket
 
 import (
-	"bufio"
-	"bytes"
 	"fmt"
 	"io"
 	"io/ioutil"
 	"log"
 	"net"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"runtime"
+	"strconv"
 	"strings"
 )
 
@@ -166,42 +164,24 @@ func connectMacOSAppSandbox() (net.Conn, error) {
 		}
 		f := strings.SplitN(best.Name(), "-", 3)
 		portStr, token := f[1], f[2]
-		return connectMacTCP(portStr, token)
+		port, err := strconv.Atoi(portStr)
+		if err != nil {
+			return nil, fmt.Errorf("invalid port %q", portStr)
+		}
+		return connectMacTCP(port, token)
 	}
 
 	// Otherwise, assume we're running the cmd/tailscale binary from outside the
 	// App Sandbox.
-
-	out, err := exec.Command("lsof",
-		"-n",                             // numeric sockets; don't do DNS lookups, etc
-		"-a",                             // logical AND remaining options
-		fmt.Sprintf("-u%d", os.Getuid()), // process of same user only
-		"-c", "IPNExtension",             // starting with IPNExtension
-		"-F", // machine-readable output
-	).Output()
+	port, token, err := LocalTCPPortAndToken()
 	if err != nil {
 		return nil, err
 	}
-	bs := bufio.NewScanner(bytes.NewReader(out))
-	subStr := []byte(".tailscale.ipn.macos/sameuserproof-")
-	for bs.Scan() {
-		line := bs.Bytes()
-		i := bytes.Index(line, subStr)
-		if i == -1 {
-			continue
-		}
-		f := strings.SplitN(string(line[i+len(subStr):]), "-", 2)
-		if len(f) != 2 {
-			continue
-		}
-		portStr, token := f[0], f[1]
-		return connectMacTCP(portStr, token)
-	}
-	return nil, fmt.Errorf("failed to find Tailscale's IPNExtension process")
+	return connectMacTCP(port, token)
 }
 
-func connectMacTCP(portStr, token string) (net.Conn, error) {
-	c, err := net.Dial("tcp", "localhost:"+portStr)
+func connectMacTCP(port int, token string) (net.Conn, error) {
+	c, err := net.Dial("tcp", "localhost:"+strconv.Itoa(port))
 	if err != nil {
 		return nil, fmt.Errorf("error dialing IPNExtension: %w", err)
 	}