mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 13:05:46 +00:00
e101d8396d
Build tags have been updated to build native Apple M1 binaries, existing build tags for ios have been changed from darwin,arm64 to ios,arm64. With this change, running go build cmd/tailscale{,d}/tailscale{,d}.go on an Apple machine with the new processor works and resulting binaries show the expected architecture, e.g. tailscale: Mach-O 64-bit executable arm64. Tested using go version go1.16beta1 darwin/arm64. Updates #943 Signed-off-by: moncho <50428+moncho@users.noreply.github.com>
111 lines
2.6 KiB
Go
111 lines
2.6 KiB
Go
// Copyright (c) 2020 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.
|
|
|
|
// +build darwin,amd64 go1.16,darwin,arm64
|
|
|
|
package portlist
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// We have to run netstat, which is a bit expensive, so don't do it too often.
|
|
const pollInterval = 5 * time.Second
|
|
|
|
func listPorts() (List, error) {
|
|
return listPortsNetstat("-na")
|
|
}
|
|
|
|
var lsofFailed int64 // atomic bool
|
|
|
|
// In theory, lsof could replace the function of both listPorts() and
|
|
// addProcesses(), since it provides a superset of the netstat output.
|
|
// However, "netstat -na" runs ~100x faster than lsof on my machine, so
|
|
// we should do it only if the list of open ports has actually changed.
|
|
//
|
|
// TODO(apenwarr): this fails in a macOS sandbox (ie. our usual case).
|
|
// We might as well just delete this code if we can't find a solution.
|
|
func addProcesses(pl []Port) ([]Port, error) {
|
|
if atomic.LoadInt64(&lsofFailed) != 0 {
|
|
// This previously failed in the macOS sandbox, so don't try again.
|
|
return pl, nil
|
|
}
|
|
exe, err := exec.LookPath("lsof")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("lsof: lookup: %v", err)
|
|
}
|
|
output, err := exec.Command(exe, "-F", "-n", "-P", "-O", "-S2", "-T", "-i4", "-i6").Output()
|
|
if err != nil {
|
|
var stderr []byte
|
|
if xe, ok := err.(*exec.ExitError); ok {
|
|
stderr = xe.Stderr
|
|
}
|
|
// fails when run in a macOS sandbox, so make this non-fatal.
|
|
if atomic.CompareAndSwapInt64(&lsofFailed, 0, 1) {
|
|
log.Printf("portlist: can't run lsof in Mac sandbox; omitting process names from service list. Error details: %v, %s", err, bytes.TrimSpace(stderr))
|
|
}
|
|
return pl, nil
|
|
}
|
|
|
|
type ProtoPort struct {
|
|
proto string
|
|
port uint16
|
|
}
|
|
m := map[ProtoPort]*Port{}
|
|
for i := range pl {
|
|
pp := ProtoPort{pl[i].Proto, pl[i].Port}
|
|
m[pp] = &pl[i]
|
|
}
|
|
|
|
r := bytes.NewReader(output)
|
|
scanner := bufio.NewScanner(r)
|
|
|
|
var cmd, proto string
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
if line == "" {
|
|
continue
|
|
}
|
|
field, val := line[0], line[1:]
|
|
switch field {
|
|
case 'p':
|
|
// starting a new process
|
|
cmd = ""
|
|
proto = ""
|
|
case 'c':
|
|
cmd = val
|
|
case 'P':
|
|
proto = strings.ToLower(val)
|
|
case 'n':
|
|
if strings.Contains(val, "->") {
|
|
continue
|
|
}
|
|
// a listening port
|
|
port := parsePort(val)
|
|
if port > 0 {
|
|
pp := ProtoPort{proto, uint16(port)}
|
|
p := m[pp]
|
|
switch {
|
|
case p != nil:
|
|
p.Process = cmd
|
|
case isLoopbackAddr(val):
|
|
// ignore
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "weird: missing %v\n", pp)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pl, nil
|
|
}
|