mirror of https://github.com/perkeep/perkeep.git
Merge "netutil: On FreeBSD replace call to lsof(1) with sockstat(1)."
This commit is contained in:
commit
f665ca05d3
|
@ -29,6 +29,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -84,10 +85,12 @@ func AddrPairUserid(local, remote net.Addr) (uid int, err error) {
|
|||
localv4, remotev4)
|
||||
}
|
||||
|
||||
if runtime.GOOS == "darwin" || runtime.GOOS == "freebsd" {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
return uidFromLsof(lAddr.IP, lAddr.Port, rAddr.IP, rAddr.Port)
|
||||
}
|
||||
if runtime.GOOS == "linux" {
|
||||
case "freebsd":
|
||||
return uidFromSockstat(lAddr.IP, lAddr.Port, rAddr.IP, rAddr.Port)
|
||||
case "linux":
|
||||
file := "/proc/net/tcp"
|
||||
if !localv4 {
|
||||
file = "/proc/net/tcp6"
|
||||
|
@ -97,7 +100,7 @@ func AddrPairUserid(local, remote net.Addr) (uid int, err error) {
|
|||
return -1, fmt.Errorf("Error opening %s: %v", file, err)
|
||||
}
|
||||
defer f.Close()
|
||||
return uidFromReader(lAddr.IP, lAddr.Port, rAddr.IP, rAddr.Port, f)
|
||||
return uidFromProcReader(lAddr.IP, lAddr.Port, rAddr.IP, rAddr.Port, f)
|
||||
}
|
||||
return 0, ErrUnsupportedOS
|
||||
}
|
||||
|
@ -125,6 +128,19 @@ func (p maybeBrackets) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
// Store in a var so we can override for testing.
|
||||
var uidFromUsername = func(username string) (uid int, err error) {
|
||||
if uid := os.Getuid(); uid != 0 && username == os.Getenv("USER") {
|
||||
return uid, nil
|
||||
}
|
||||
u, err := user.Lookup(username)
|
||||
if err == nil {
|
||||
uid, err := strconv.Atoi(u.Uid)
|
||||
return uid, err
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
func uidFromLsof(lip net.IP, lport int, rip net.IP, rport int) (uid int, err error) {
|
||||
seek := fmt.Sprintf("%s:%d->%s:%d", maybeBrackets(lip), lport, maybeBrackets(rip), rport)
|
||||
seekb := []byte(seek)
|
||||
|
@ -169,21 +185,52 @@ func uidFromLsof(lip net.IP, lport int, rip net.IP, rport int) (uid int, err err
|
|||
continue
|
||||
}
|
||||
username := string(f[2])
|
||||
if uid := os.Getuid(); uid != 0 && username == os.Getenv("USER") {
|
||||
return uid, nil
|
||||
}
|
||||
u, err := user.Lookup(username)
|
||||
if err == nil {
|
||||
uid, err := strconv.Atoi(u.Uid)
|
||||
return uid, err
|
||||
}
|
||||
return 0, err
|
||||
return uidFromUsername(username)
|
||||
}
|
||||
return -1, ErrNotFound
|
||||
|
||||
}
|
||||
|
||||
func uidFromReader(lip net.IP, lport int, rip net.IP, rport int, r io.Reader) (uid int, err error) {
|
||||
func uidFromSockstat(lip net.IP, lport int, rip net.IP, rport int) (int, error) {
|
||||
cmd := exec.Command("sockstat", "-Ptcp")
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer cmd.Wait()
|
||||
defer stdout.Close()
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
return uidFromSockstatReader(lip, lport, rip, rport, stdout)
|
||||
}
|
||||
|
||||
func uidFromSockstatReader(lip net.IP, lport int, rip net.IP, rport int, r io.Reader) (int, error) {
|
||||
pat, err := regexp.Compile(fmt.Sprintf(`^([^ ]+).*%s:%d *%s:%d$`,
|
||||
lip.String(), lport, rip.String(), rport))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
m := pat.FindStringSubmatch(l)
|
||||
if len(m) == 2 {
|
||||
return uidFromUsername(m[1])
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return -1, ErrNotFound
|
||||
}
|
||||
|
||||
func uidFromProcReader(lip net.IP, lport int, rip net.IP, rport int, r io.Reader) (uid int, err error) {
|
||||
buf := bufio.NewReader(r)
|
||||
|
||||
localHex := ""
|
||||
|
|
|
@ -127,13 +127,62 @@ func TestHTTPAuth(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func testUidFromUsername(username string) (int, error) {
|
||||
switch username {
|
||||
case "really-long-user":
|
||||
return 1000, nil
|
||||
case "root":
|
||||
return 0, nil
|
||||
}
|
||||
panic("Unhandled username specified in test")
|
||||
}
|
||||
|
||||
func TestParseFreeBSDSockstat(t *testing.T) {
|
||||
uidFromUsername = testUidFromUsername
|
||||
pairs := []struct {
|
||||
uid int
|
||||
lip, rip net.IP
|
||||
lport, rport int
|
||||
}{
|
||||
{
|
||||
// "really-long-user"
|
||||
uid: 1000,
|
||||
lip: net.ParseIP("192.168.123.5"), lport: 8000,
|
||||
rip: net.ParseIP("192.168.123.21"), rport: 49826,
|
||||
},
|
||||
{
|
||||
// "really-long-user"
|
||||
uid: 1000,
|
||||
lip: net.ParseIP("192.168.123.5"), lport: 9000,
|
||||
rip: net.ParseIP("192.168.123.21"), rport: 49866,
|
||||
},
|
||||
{
|
||||
// "root"
|
||||
uid: 0,
|
||||
lip: net.ParseIP("192.168.123.5"), lport: 22,
|
||||
rip: net.ParseIP("192.168.123.21"), rport: 49747,
|
||||
},
|
||||
}
|
||||
|
||||
for _, p := range pairs {
|
||||
uid, err := uidFromSockstatReader(p.lip, p.lport, p.rip, p.rport, strings.NewReader(sockstatPtcp))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if p.uid != uid {
|
||||
t.Error("Got", uid, "want", p.uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseLinuxTCPStat4(t *testing.T) {
|
||||
lip, lport := net.ParseIP("67.218.110.129"), 43436
|
||||
rip, rport := net.ParseIP("207.7.148.195"), 80
|
||||
|
||||
// 816EDA43:A9AC C39407CF:0050
|
||||
// 43436 80
|
||||
uid, err := uidFromReader(lip, lport, rip, rport, strings.NewReader(tcpstat4))
|
||||
uid, err := uidFromProcReader(lip, lport, rip, rport, strings.NewReader(tcpstat4))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -157,3 +206,43 @@ var tcpstat4 = ` sl local_address rem_address st tx_queue rx_queue tr tm->wh
|
|||
12: 816EDA43:AFEF 51357D4A:01BB 01 00000000:00000000 02:00000685 00000000 61652 0 8752937 2 ffff880136375480 87 4 2 4 -1
|
||||
13: 0100007F:D981 0100007F:C204 01 00000000:00000000 00:00000000 00000000 61652 0 8722933 1 ffff880036b30d00 21 4 0 3 -1
|
||||
`
|
||||
|
||||
// Output of 'sockstat -Ptcp'. User 'really-long-user' running two instances
|
||||
// of nc copied to 'really-only-process-name' and 'spc in name' run with -l
|
||||
// 8000 and -l 9000 respectively. Two connections were then open from
|
||||
// 192.167.123.21 using 'nc 192.168.123.5 8000' and 'nc 192.168.123.5 9000'.
|
||||
var sockstatPtcp = `
|
||||
sockstat -Ptcp
|
||||
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
|
||||
really-long-user spc in nam63210 3 tcp4 *:9000 *:*
|
||||
really-long-user spc in nam63210 4 tcp4 192.168.123.5:9000192.168.123.21:49866
|
||||
www nginx 62982 7 tcp4 *:80 *:*
|
||||
www nginx 62982 8 tcp6 *:80 *:*
|
||||
really-long-user really-lon62928 3 tcp4 *:8000 *:*
|
||||
really-long-user really-lon62928 4 tcp4 192.168.123.5:8000192.168.123.21:49826
|
||||
root sshd 62849 5 tcp4 192.168.123.5:22 192.168.123.21:49819
|
||||
root sshd 61819 5 tcp4 192.168.123.5:22 192.168.123.21:49747
|
||||
camlistore sshd 61746 5 tcp4 192.168.123.5:22 192.168.123.21:49739
|
||||
root sshd 61744 5 tcp4 192.168.123.5:22 192.168.123.21:49739
|
||||
camlistore camlistore10941 7 tcp4 6 *:3179 *:*
|
||||
camlistore sshd 91620 5 tcp4 192.168.123.5:22 192.168.123.2:13404
|
||||
root sshd 91618 5 tcp4 192.168.123.5:22 192.168.123.2:13404
|
||||
root sshd 2309 4 tcp6 *:22 *:*
|
||||
root sshd 2309 5 tcp4 *:22 *:*
|
||||
root nginx 2152 7 tcp4 *:80 *:*
|
||||
root nginx 2152 8 tcp6 *:80 *:*
|
||||
root python2.7 2076 3 tcp4 127.0.0.1:9042 *:*
|
||||
root python2.7 2076 6 tcp4 127.0.0.1:9042 127.0.0.1:51930
|
||||
root python2.7 2076 7 tcp4 127.0.0.1:9042 127.0.0.1:20433
|
||||
root python2.7 2076 8 tcp4 127.0.0.1:9042 127.0.0.1:55807
|
||||
root rpc.statd 1630 5 tcp6 *:664 *:*
|
||||
root rpc.statd 1630 7 tcp4 *:664 *:*
|
||||
root nfsd 1618 5 tcp4 *:2049 *:*
|
||||
root nfsd 1618 6 tcp6 *:2049 *:*
|
||||
root mountd 1604 6 tcp6 *:792 *:*
|
||||
root mountd 1604 8 tcp4 *:792 *:*
|
||||
root rpcbind 1600 8 tcp6 *:111 *:*
|
||||
root rpcbind 1600 11 tcp4 *:111 *:*
|
||||
? ? ? ? tcp4 *:895 *:*
|
||||
? ? ? ? tcp6 *:777 *:*
|
||||
`
|
||||
|
|
Loading…
Reference in New Issue