Skip to content

Commit

Permalink
[net]linux: implement processInet().
Browse files Browse the repository at this point in the history
  • Loading branch information
shirou committed Mar 4, 2016
1 parent 6c35201 commit 32c62b5
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 73 deletions.
196 changes: 134 additions & 62 deletions net/net_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,58 +199,80 @@ func NetFilterCounters() ([]NetFilterStat, error) {
return stats, nil
}

// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
var TCPStatuses = map[string]string{
"01": "ESTABLISHED",
"02": "SYN_SENT",
"03": "SYN_RECV",
"04": "FIN_WAIT1",
"05": "FIN_WAIT2",
"06": "TIME_WAIT",
"07": "CLOSE",
"08": "CLOSE_WAIT",
"09": "LAST_ACK",
"0A": "LISTEN",
"0B": "CLOSING",
}

type netConnectionKindType struct {
family int
sockType int
family uint32
sockType uint32
f string // file name
}

var KindTCP4 = netConnectionKindType{
var kindTCP4 = netConnectionKindType{
family: syscall.AF_INET,
sockType: syscall.SOCK_STREAM,
f: "tcp",
}
var KindTCP6 = netConnectionKindType{
var kindTCP6 = netConnectionKindType{
family: syscall.AF_INET6,
sockType: syscall.SOCK_STREAM,
f: "tcp6",
}
var KindUDP4 = netConnectionKindType{
var kindUDP4 = netConnectionKindType{
family: syscall.AF_INET,
sockType: syscall.SOCK_DGRAM,
f: "udp",
}
var KindUDP6 = netConnectionKindType{
var kindUDP6 = netConnectionKindType{
family: syscall.AF_INET6,
sockType: syscall.SOCK_DGRAM,
f: "udp6",
}
var KindUNIX = netConnectionKindType{
var kindUNIX = netConnectionKindType{
family: syscall.AF_UNIX,
f: "unix",
}

var netConnectionKindMap = map[string][]netConnectionKindType{
"all": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6, KindUNIX},
"tcp": []netConnectionKindType{KindTCP4, KindTCP6},
"tcp4": []netConnectionKindType{KindTCP4},
"tcp6": []netConnectionKindType{KindTCP6},
"udp": []netConnectionKindType{KindUDP4, KindUDP6},
"udp4": []netConnectionKindType{KindUDP4},
"udp6": []netConnectionKindType{KindUDP6},
"unix": []netConnectionKindType{KindUNIX},
"inet": []netConnectionKindType{KindTCP4, KindTCP6, KindUDP4, KindUDP6},
"inet4": []netConnectionKindType{KindTCP4, KindUDP4},
"inet6": []netConnectionKindType{KindTCP6, KindUDP6},
"all": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
"tcp": []netConnectionKindType{kindTCP4, kindTCP6},
"tcp4": []netConnectionKindType{kindTCP4},
"tcp6": []netConnectionKindType{kindTCP6},
"udp": []netConnectionKindType{kindUDP4, kindUDP6},
"udp4": []netConnectionKindType{kindUDP4},
"udp6": []netConnectionKindType{kindUDP6},
"unix": []netConnectionKindType{kindUNIX},
"inet": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6},
"inet4": []netConnectionKindType{kindTCP4, kindUDP4},
"inet6": []netConnectionKindType{kindTCP6, kindUDP6},
}

type inodeMap struct {
pid int32
fd string
fd uint32
}

type bb struct {
fd int
family int
sockType int
laddr string
raddr string
status string
bound_pid int32
type connTmp struct {
fd uint32
family uint32
sockType uint32
laddr Addr
raddr Addr
status string
pid int32
boundPid int32
}

// Return a list of network connections opened.
Expand All @@ -271,46 +293,54 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) {
inodes, err = getProcInodesAll(root)
} else {
inodes, err = getProcInodes(root, pid)
if len(inodes) == 0 {
// no connection for the pid
return []NetConnectionStat{}, nil
}
}
if err != nil {
return nil, fmt.Errorf("cound not get pid(s), %d", pid)
}

for _, t := range tmap {
fmt.Println(t)
fmt.Println(inodes)
var ret []NetConnectionStat

for _, t := range tmap {
var path string
var ls []string
var ls []connTmp
path = fmt.Sprintf("%s/net/%s", root, t.f)
switch t.family {
case syscall.AF_INET:
path = fmt.Sprintf("%d/net/%s", pid, "tcp")
ls, err = processInet(path, t, inodes, pid)
fallthrough
case syscall.AF_INET6:
path = fmt.Sprintf("%d/net/%s", pid, "tcp6")
ls, err = processInet(path, t, inodes, pid)
case syscall.AF_UNIX:
path = fmt.Sprintf("%d/net/%s", pid, "unix")
ls, err = processInet(path, t, inodes, pid)
ls, err = processUnix(path, t, inodes, pid)
}
if err != nil {
return nil, err
}
for _, sss := range ls {
fmt.Println(sss)
for _, c := range ls {
ret = append(ret, NetConnectionStat{
Fd: c.fd,
Family: t.family,
Type: t.sockType,
Laddr: c.laddr,
Raddr: c.raddr,
Status: c.status,
Pid: c.pid,
})
}

}

return []NetConnectionStat{}, nil
return ret, nil
}

// getProcInodes returnes fd of the pid.
func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) {
ret := make(map[string][]inodeMap)

dir := fmt.Sprintf("%s/%d/fd", root, pid)

files, err := ioutil.ReadDir(dir)
if err != nil {
return ret, nil
Expand All @@ -322,8 +352,6 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) {
if err != nil {
continue
}

fmt.Println(inodePath)
if strings.HasPrefix(inode, "socket:[") {
// the process is using a socket
l := len(inode)
Expand All @@ -334,10 +362,14 @@ func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) {
if !ok {
ret[inode] = make([]inodeMap, 0)
}
fd, err := strconv.Atoi(fd.Name())
if err != nil {
continue
}

i := inodeMap{
pid: pid,
fd: fd.Name(),
fd: uint32(fd),
}
ret[inode] = append(ret[inode], i)
}
Expand Down Expand Up @@ -390,30 +422,28 @@ func getProcInodesAll(root string) (map[string][]inodeMap, error) {
continue
}
// TODO: update ret.

fmt.Println(t)
ret = updateMap(ret, t)
}

return ret, nil
}

// decodeAddress decode addresse represents addr in proc/net/*
// ex:
// "0500000A:0016" -> "10.0.0.5", 22
// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53
func decodeAddress(family int, src string) (net.IP, int, error) {
func decodeAddress(family uint32, src string) (Addr, error) {
t := strings.Split(src, ":")
if len(t) != 2 {
return nil, 0, fmt.Errorf("does not contain port, %s", src)
return Addr{}, fmt.Errorf("does not contain port, %s", src)
}
addr := t[0]
port, err := strconv.ParseInt("0x"+t[1], 0, 64)
if err != nil {
return nil, 0, fmt.Errorf("invalid port, %s", src)
return Addr{}, fmt.Errorf("invalid port, %s", src)
}
decoded, err := hex.DecodeString(addr)
if err != nil {
return nil, 0, fmt.Errorf("decode error:", err)
return Addr{}, fmt.Errorf("decode error:", err)
}
var ip net.IP
// Assumes this is little_endian
Expand All @@ -422,10 +452,13 @@ func decodeAddress(family int, src string) (net.IP, int, error) {
} else { // IPv6
ip, err = parseIPv6HexString(decoded)
if err != nil {
return nil, 0, err
return Addr{}, err
}
}
return ip, int(port), nil
return Addr{
IP: ip.String(),
Port: uint32(port),
}, nil
}

// Reverse reverses array of bytes.
Expand All @@ -450,17 +483,18 @@ func parseIPv6HexString(src []byte) (net.IP, error) {
return net.IP(buf), nil
}

func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]string, error) {
func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {

if strings.HasSuffix(file, "6") && !common.PathExists(file) {
// IPv6 not supported, return empty.
return []string{}, nil
return []connTmp{}, nil
}
lines, err := common.ReadLines(file)
if err != nil {
return nil, err
}
// skip first line
var ret []connTmp
for _, line := range lines[1:] {
l := strings.Fields(line)
if len(l) < 10 {
Expand All @@ -469,20 +503,58 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in
laddr := l[1]
raddr := l[2]
status := l[3]
inode, err := strconv.Atoi(l[9])
inode := l[9]
pid := int32(0)
fd := uint32(0)
i, exists := inodes[inode]
if exists {
pid = i[0].pid
fd = i[0].fd
}
if filterPid > 0 && filterPid != pid {
continue
}
if kind.sockType == syscall.SOCK_STREAM {
status = TCPStatuses[status]
} else {
status = "NONE"
}
la, err := decodeAddress(kind.family, laddr)
if err != nil {
continue
}
ra, err := decodeAddress(kind.family, raddr)
if err != nil {
continue
}
fmt.Println(laddr)
fmt.Println(raddr)
fmt.Println(status)
fmt.Println(inode)

ret = append(ret, connTmp{
fd: fd,
family: kind.family,
sockType: kind.sockType,
laddr: la,
raddr: ra,
status: status,
pid: pid,
})
}

return nil, nil
return ret, nil
}

func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]string, error) {
func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {

return []connTmp{}, nil
}

return nil, nil
func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap {
for key, value := range add {
a, exists := src[key]
if !exists {
src[key] = value
continue
}
src[key] = append(a, value...)
}
return src
}
19 changes: 8 additions & 11 deletions net/net_linux_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net

import (
"fmt"
"syscall"
"testing"

Expand All @@ -11,14 +10,12 @@ import (

func TestGetProcInodes(t *testing.T) {
root := common.HostProc("")
// checkPid := os.Getpid() // process.test
checkPid := 13378

// /proc/19957/fd

v, err := getProcInodes(root, 19957)
if err != nil {
t.Fatal(err)
}
fmt.Println(v)
v, err := getProcInodes(root, int32(checkPid))
assert.Nil(t, err)
assert.NotEmpty(t, v)
}

type AddrTest struct {
Expand Down Expand Up @@ -59,13 +56,13 @@ func TestDecodeAddress(t *testing.T) {
if len(src) > 13 {
family = syscall.AF_INET6
}
ip, port, err := decodeAddress(family, src)
addr, err := decodeAddress(uint32(family), src)
if dst.Error {
assert.NotNil(err, src)
} else {
assert.Nil(err, src)
assert.Equal(dst.IP, ip.String(), src)
assert.Equal(dst.Port, port, src)
assert.Equal(dst.IP, addr.IP, src)
assert.Equal(dst.Port, int(addr.Port), src)
}
}
}

0 comments on commit 32c62b5

Please sign in to comment.