244 lines
5.8 KiB
Go
244 lines
5.8 KiB
Go
package net
|
|
|
|
import (
|
|
"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)
|
|
}
|
|
|
|
// 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"`
|
|
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) {
|
|
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
|
|
}
|