portlist: ignore ports bound to localhost
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>reviewable/pr192/r1
parent
c706731dc7
commit
f8d67bb591
|
@ -75,6 +75,10 @@ func parsePortsNetstat(output string) List {
|
||||||
// not interested in non-listener sockets
|
// not interested in non-listener sockets
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(laddr, "127.0.0.1:") || strings.HasPrefix(laddr, "127.0.0.1.") {
|
||||||
|
// not interested in loopback-bound listeners
|
||||||
|
continue
|
||||||
|
}
|
||||||
} else if strings.HasPrefix(protos, "udp") {
|
} else if strings.HasPrefix(protos, "udp") {
|
||||||
if len(cols) < 3 {
|
if len(cols) < 3 {
|
||||||
continue
|
continue
|
||||||
|
@ -82,6 +86,10 @@ func parsePortsNetstat(output string) List {
|
||||||
proto = "udp"
|
proto = "udp"
|
||||||
laddr = cols[len(cols)-2]
|
laddr = cols[len(cols)-2]
|
||||||
raddr = cols[len(cols)-1]
|
raddr = cols[len(cols)-1]
|
||||||
|
if strings.HasPrefix(laddr, "127.0.0.1:") || strings.HasPrefix(laddr, "127.0.0.1.") {
|
||||||
|
// not interested in loopback-bound listeners
|
||||||
|
continue
|
||||||
|
}
|
||||||
} else if protos[0] == '[' && len(trimline) > 2 {
|
} else if protos[0] == '[' && len(trimline) > 2 {
|
||||||
// Windows: with netstat -nab, appends a line like:
|
// Windows: with netstat -nab, appends a line like:
|
||||||
// [description]
|
// [description]
|
||||||
|
@ -134,16 +142,12 @@ func parsePortsNetstat(output string) List {
|
||||||
|
|
||||||
//lint:ignore U1000 function is only used on !linux, but we want the
|
//lint:ignore U1000 function is only used on !linux, but we want the
|
||||||
// unit test to run on linux, so we don't build-tag it away.
|
// unit test to run on linux, so we don't build-tag it away.
|
||||||
func listPortsNetstat(args string) (List, error) {
|
func listPortsNetstat(arg string) (List, error) {
|
||||||
exe, err := exec.LookPath("netstat")
|
exe, err := exec.LookPath("netstat")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("netstat: lookup: %v", err)
|
return nil, fmt.Errorf("netstat: lookup: %v", err)
|
||||||
}
|
}
|
||||||
c := exec.Cmd{
|
output, err := exec.Command(exe, arg).Output()
|
||||||
Path: exe,
|
|
||||||
Args: []string{exe, args},
|
|
||||||
}
|
|
||||||
output, err := c.Output()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
xe, ok := err.(*exec.ExitError)
|
xe, ok := err.(*exec.ExitError)
|
||||||
stderr := ""
|
stderr := ""
|
||||||
|
|
|
@ -31,7 +31,7 @@ func TestParsePort(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var netstat_output = `
|
const netstatOutput = `
|
||||||
// linux
|
// linux
|
||||||
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
|
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
|
||||||
udp 0 0 0.0.0.0:5353 0.0.0.0:*
|
udp 0 0 0.0.0.0:5353 0.0.0.0:*
|
||||||
|
@ -76,7 +76,7 @@ func TestParsePortsNetstat(t *testing.T) {
|
||||||
Port{"udp", 9353, "iTunes", ""},
|
Port{"udp", 9353, "iTunes", ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
pl := parsePortsNetstat(netstat_output)
|
pl := parsePortsNetstat(netstatOutput)
|
||||||
for i := range pl {
|
for i := range pl {
|
||||||
if pl[i] != want[i] {
|
if pl[i] != want[i] {
|
||||||
t.Errorf("row#%d\n got: %#v\n\nwant: %#v\n",
|
t.Errorf("row#%d\n got: %#v\n\nwant: %#v\n",
|
||||||
|
|
|
@ -37,11 +37,7 @@ func addProcesses(pl []Port) ([]Port, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("lsof: lookup: %v", err)
|
return nil, fmt.Errorf("lsof: lookup: %v", err)
|
||||||
}
|
}
|
||||||
c := exec.Cmd{
|
output, err := exec.Command(exe, "-F", "-n", "-P", "-O", "-S2", "-T", "-i4", "-i6").Output()
|
||||||
Path: exe,
|
|
||||||
Args: []string{exe, "-F", "-n", "-P", "-O", "-S2", "-T", "-i4", "-i6"},
|
|
||||||
}
|
|
||||||
output, err := c.Output()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
xe, ok := err.(*exec.ExitError)
|
xe, ok := err.(*exec.ExitError)
|
||||||
stderr := ""
|
stderr := ""
|
||||||
|
@ -69,28 +65,32 @@ func addProcesses(pl []Port) ([]Port, error) {
|
||||||
var cmd, proto string
|
var cmd, proto string
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
if line[0] == 'p' {
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
field, val := line[0], line[1:]
|
||||||
|
switch field {
|
||||||
|
case 'p':
|
||||||
// starting a new process
|
// starting a new process
|
||||||
cmd = ""
|
cmd = ""
|
||||||
proto = ""
|
proto = ""
|
||||||
} else if line[0] == 'c' {
|
case 'c':
|
||||||
cmd = line[1:len(line)]
|
cmd = val
|
||||||
} else if line[0] == 'P' {
|
case 'P':
|
||||||
proto = strings.ToLower(line[1:len(line)])
|
proto = strings.ToLower(val)
|
||||||
} else if line[0] == 'n' {
|
case 'n':
|
||||||
rest := line[1:len(line)]
|
if strings.Contains(val, "->") {
|
||||||
i := strings.Index(rest, "->")
|
continue
|
||||||
if i < 0 {
|
}
|
||||||
// a listening port
|
// a listening port
|
||||||
port := parsePort(rest)
|
port := parsePort(val)
|
||||||
if port > 0 {
|
if port > 0 {
|
||||||
pp := ProtoPort{proto, uint16(port)}
|
pp := ProtoPort{proto, uint16(port)}
|
||||||
p := m[pp]
|
p := m[pp]
|
||||||
if p != nil {
|
if p != nil {
|
||||||
p.Process = cmd
|
p.Process = cmd
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stderr, "weird: missing %v\n", pp)
|
fmt.Fprintf(os.Stderr, "weird: missing %v\n", pp)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,10 @@ func listPorts() (List, error) {
|
||||||
rem := words[2]
|
rem := words[2]
|
||||||
inode := words[9]
|
inode := words[9]
|
||||||
|
|
||||||
|
// If a port is bound to 127.0.0.1, ignore it.
|
||||||
|
if strings.HasPrefix(local, "0100007F:") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if rem != "00000000:0000" {
|
if rem != "00000000:0000" {
|
||||||
// not a "listener" port
|
// not a "listener" port
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -4,7 +4,10 @@
|
||||||
|
|
||||||
package portlist
|
package portlist
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestGetList(t *testing.T) {
|
func TestGetList(t *testing.T) {
|
||||||
pl, err := GetList(nil)
|
pl, err := GetList(nil)
|
||||||
|
@ -17,6 +20,25 @@ func TestGetList(t *testing.T) {
|
||||||
t.Logf("As String: %v", pl.String())
|
t.Logf("As String: %v", pl.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIgnoreLocallyBoundPorts(t *testing.T) {
|
||||||
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Skipf("failed to bind: %v", err)
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
ta := ln.Addr().(*net.TCPAddr)
|
||||||
|
port := ta.Port
|
||||||
|
pl, err := GetList(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, p := range pl {
|
||||||
|
if p.Proto == "tcp" && int(p.Port) == port {
|
||||||
|
t.Fatal("didn't expect to find test's localhost ephemeral port")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkGetList(b *testing.B) {
|
func BenchmarkGetList(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
|
Loading…
Reference in New Issue