diff --git a/net/net.go b/net/net.go index 4d120dc..48660ec 100644 --- a/net/net.go +++ b/net/net.go @@ -39,13 +39,14 @@ type Addr struct { } type ConnectionStat struct { - Fd uint32 `json:"fd"` - Family uint32 `json:"family"` - Type uint32 `json:"type"` - Laddr Addr `json:"localaddr"` - Raddr Addr `json:"remoteaddr"` - Status string `json:"status"` - Pid int32 `json:"pid"` + Fd uint32 `json:"fd"` + Family uint32 `json:"family"` + Type uint32 `json:"type"` + Laddr Addr `json:"localaddr"` + Raddr Addr `json:"remoteaddr"` + Status string `json:"status"` + Uids []int32 `json:"uids"` + Pid int32 `json:"pid"` } // System wide stats about different network protocols diff --git a/net/net_linux.go b/net/net_linux.go index 0803d8e..cb83e69 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -281,6 +281,7 @@ type connTmp struct { laddr Addr raddr Addr status string + uids []int32 pid int32 boundPid int32 path string @@ -338,6 +339,7 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { Type: c.sockType, Laddr: c.laddr, Raddr: c.raddr, + Uids: c.uids, Status: c.status, Pid: c.pid, } @@ -346,6 +348,11 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { } else { conn.Pid = c.pid } + + // fetch process owner Real, effective, saved set, and filesystem UIDs + proc := process{Pid: conn.Pid} + conn.Uids, _ = proc.getUids() + // check duplicate using JSON format json := conn.String() _, exists := dupCheckMap[json] @@ -429,6 +436,54 @@ func Pids() ([]int32, error) { return ret, nil } +// Note: the following is based off process_linux structs and methods +// we need these to fetch the owner of a process ID +// FIXME: Import process occures import cycle. +// see remarks on pids() +type process struct { + Pid int32 `json:"pid"` + uids []int32 +} + +// Uids returns user ids of the process as a slice of the int +func (p *process) getUids() ([]int32, error) { + err := p.fillFromStatus() + if err != nil { + return []int32{}, err + } + return p.uids, nil +} + +// Get status from /proc/(pid)/status +func (p *process) fillFromStatus() error { + pid := p.Pid + statPath := common.HostProc(strconv.Itoa(int(pid)), "status") + contents, err := ioutil.ReadFile(statPath) + if err != nil { + return err + } + lines := strings.Split(string(contents), "\n") + for _, line := range lines { + tabParts := strings.SplitN(line, "\t", 2) + if len(tabParts) < 2 { + continue + } + value := tabParts[1] + switch strings.TrimRight(tabParts[0], ":") { + case "Uid": + p.uids = make([]int32, 0, 4) + for _, i := range strings.Split(value, "\t") { + v, err := strconv.ParseInt(i, 10, 32) + if err != nil { + return err + } + p.uids = append(p.uids, int32(v)) + } + } + } + return nil +} + func getProcInodesAll(root string) (map[string][]inodeMap, error) { pids, err := Pids() if err != nil { diff --git a/net/net_test.go b/net/net_test.go index 9ec87ad..491a738 100644 --- a/net/net_test.go +++ b/net/net_test.go @@ -50,8 +50,9 @@ func TestNetConnectionStatString(t *testing.T) { Fd: 10, Family: 10, Type: 10, + Uids: []int32{10, 10}, } - e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","pid":0}` + e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","uids":[10,10],"pid":0}` if e != fmt.Sprintf("%v", v) { t.Errorf("NetConnectionStat string is invalid: %v", v) }