mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-16 03:14:44 +00:00
Move Linux client & common packages into a public repo.
This commit is contained in:
99
portlist/portlist_darwin.go
Normal file
99
portlist/portlist_darwin.go
Normal file
@@ -0,0 +1,99 @@
|
||||
// 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 !linux,!windows
|
||||
|
||||
package portlist
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
exec "tailscale.com/tempfork/osexec"
|
||||
)
|
||||
|
||||
// We have to run netstat, which is a bit expensive, so don't do it too often.
|
||||
const POLL_SECONDS = 5
|
||||
|
||||
func listPorts() (List, error) {
|
||||
return listPortsNetstat("-na")
|
||||
}
|
||||
|
||||
// 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) {
|
||||
exe, err := exec.LookPath("lsof")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("lsof: lookup: %v", err)
|
||||
}
|
||||
c := exec.Cmd{
|
||||
Path: exe,
|
||||
Args: []string{exe, "-F", "-n", "-P", "-O", "-S2", "-T", "-i4", "-i6"},
|
||||
}
|
||||
output, err := c.Output()
|
||||
if err != nil {
|
||||
xe, ok := err.(*exec.ExitError)
|
||||
stderr := ""
|
||||
if ok {
|
||||
stderr = strings.TrimSpace(string(xe.Stderr))
|
||||
}
|
||||
// fails when run in a macOS sandbox, so make this non-fatal.
|
||||
log.Printf("portlist: lsof: %v (%q)\n", err, 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[0] == 'p' {
|
||||
// starting a new process
|
||||
cmd = ""
|
||||
proto = ""
|
||||
} else if line[0] == 'c' {
|
||||
cmd = line[1:len(line)]
|
||||
} else if line[0] == 'P' {
|
||||
proto = strings.ToLower(line[1:len(line)])
|
||||
} else if line[0] == 'n' {
|
||||
rest := line[1:len(line)]
|
||||
i := strings.Index(rest, "->")
|
||||
if i < 0 {
|
||||
// a listening port
|
||||
port := parsePort(rest)
|
||||
if port > 0 {
|
||||
pp := ProtoPort{proto, uint16(port)}
|
||||
p := m[pp]
|
||||
if p != nil {
|
||||
p.Process = cmd
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "weird: missing %v\n", pp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pl, nil
|
||||
}
|
Reference in New Issue
Block a user