package net import ( "context" "encoding/json" "fmt" "net" "strconv" "strings" "syscall" "github.com/shirou/gopsutil/internal/common" ) var invoke common.Invoker func init() { invoke = common.Invoke{} } type IOCountersStat struct { Name string `json:"name"` // interface name BytesSent uint64 `json:"bytesSent"` // number of bytes sent BytesRecv uint64 `json:"bytesRecv"` // number of bytes received PacketsSent uint64 `json:"packetsSent"` // number of packets sent PacketsRecv uint64 `json:"packetsRecv"` // number of packets received Errin uint64 `json:"errin"` // total number of errors while receiving Errout uint64 `json:"errout"` // total number of errors while sending Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD) Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending } // Addr is implemented compatibility to psutil type Addr struct { IP string `json:"ip"` Port uint32 `json:"port"` } 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"` Uids []int32 `json:"uids"` Pid int32 `json:"pid"` } // System wide stats about different network protocols type ProtoCountersStat struct { Protocol string `json:"protocol"` Stats map[string]int64 `json:"stats"` } // NetInterfaceAddr is designed for represent interface addresses type InterfaceAddr struct { Addr string `json:"addr"` } type InterfaceStat struct { MTU int `json:"mtu"` // maximum transmission unit Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100" HardwareAddr string `json:"hardwareaddr"` // IEEE MAC-48, EUI-48 and EUI-64 form Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast Addrs []InterfaceAddr `json:"addrs"` } type FilterStat struct { ConnTrackCount int64 `json:"conntrackCount"` ConnTrackMax int64 `json:"conntrackMax"` } var constMap = map[string]int{ "TCP": syscall.SOCK_STREAM, "UDP": syscall.SOCK_DGRAM, "IPv4": syscall.AF_INET, "IPv6": syscall.AF_INET6, } func (n IOCountersStat) String() string { s, _ := json.Marshal(n) return string(s) } func (n ConnectionStat) String() string { s, _ := json.Marshal(n) return string(s) } func (n ProtoCountersStat) String() string { s, _ := json.Marshal(n) return string(s) } func (a Addr) String() string { s, _ := json.Marshal(a) return string(s) } func (n InterfaceStat) String() string { s, _ := json.Marshal(n) return string(s) } func (n InterfaceAddr) String() string { s, _ := json.Marshal(n) return string(s) } func Interfaces() ([]InterfaceStat, error) { return InterfacesWithContext(context.Background()) } func InterfacesWithContext(ctx context.Context) ([]InterfaceStat, error) { is, err := net.Interfaces() if err != nil { return nil, err } ret := make([]InterfaceStat, 0, len(is)) for _, ifi := range is { var flags []string if ifi.Flags&net.FlagUp != 0 { flags = append(flags, "up") } if ifi.Flags&net.FlagBroadcast != 0 { flags = append(flags, "broadcast") } if ifi.Flags&net.FlagLoopback != 0 { flags = append(flags, "loopback") } if ifi.Flags&net.FlagPointToPoint != 0 { flags = append(flags, "pointtopoint") } if ifi.Flags&net.FlagMulticast != 0 { flags = append(flags, "multicast") } r := InterfaceStat{ Name: ifi.Name, MTU: ifi.MTU, HardwareAddr: ifi.HardwareAddr.String(), Flags: flags, } addrs, err := ifi.Addrs() if err == nil { r.Addrs = make([]InterfaceAddr, 0, len(addrs)) for _, addr := range addrs { r.Addrs = append(r.Addrs, InterfaceAddr{ Addr: addr.String(), }) } } ret = append(ret, r) } return ret, nil } func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) { r := IOCountersStat{ Name: "all", } for _, nic := range n { r.BytesRecv += nic.BytesRecv r.PacketsRecv += nic.PacketsRecv r.Errin += nic.Errin r.Dropin += nic.Dropin r.BytesSent += nic.BytesSent r.PacketsSent += nic.PacketsSent r.Errout += nic.Errout r.Dropout += nic.Dropout } return []IOCountersStat{r}, nil } func parseNetLine(line string) (ConnectionStat, error) { f := strings.Fields(line) if len(f) < 9 { return ConnectionStat{}, fmt.Errorf("wrong line,%s", line) } pid, err := strconv.Atoi(f[1]) if err != nil { return ConnectionStat{}, err } fd, err := strconv.Atoi(strings.Trim(f[3], "u")) if err != nil { return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3]) } netFamily, ok := constMap[f[4]] if !ok { return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4]) } netType, ok := constMap[f[7]] if !ok { return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7]) } laddr, raddr, err := parseNetAddr(f[8]) if err != nil { return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8]) } n := ConnectionStat{ Fd: uint32(fd), Family: uint32(netFamily), Type: uint32(netType), Laddr: laddr, Raddr: raddr, Pid: int32(pid), } if len(f) == 10 { n.Status = strings.Trim(f[9], "()") } return n, nil } func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) { parse := func(l string) (Addr, error) { host, port, err := net.SplitHostPort(l) if err != nil { return Addr{}, fmt.Errorf("wrong addr, %s", l) } lport, err := strconv.Atoi(port) if err != nil { return Addr{}, err } return Addr{IP: host, Port: uint32(lport)}, nil } addrs := strings.Split(line, "->") if len(addrs) == 0 { return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line) } laddr, err = parse(addrs[0]) if len(addrs) == 2 { // remote addr exists raddr, err = parse(addrs[1]) if err != nil { return laddr, raddr, err } } return laddr, raddr, err }