mirror of
https://github.com/status-im/consul.git
synced 2025-01-11 22:34:55 +00:00
95c027a3ea
https://github.com/shirou/gopsutil/pull/895 is merged and fixes our problem. Time to update. Since there is no new version just yet, updating to the sha.
321 lines
7.2 KiB
Go
321 lines
7.2 KiB
Go
// +build openbsd
|
|
|
|
package net
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os/exec"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
|
)
|
|
|
|
var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`)
|
|
|
|
func ParseNetstat(output string, mode string,
|
|
iocs map[string]IOCountersStat) error {
|
|
lines := strings.Split(output, "\n")
|
|
|
|
exists := make([]string, 0, len(lines)-1)
|
|
|
|
columns := 6
|
|
if mode == "ind" {
|
|
columns = 10
|
|
}
|
|
for _, line := range lines {
|
|
values := strings.Fields(line)
|
|
if len(values) < 1 || values[0] == "Name" {
|
|
continue
|
|
}
|
|
if common.StringsHas(exists, values[0]) {
|
|
// skip if already get
|
|
continue
|
|
}
|
|
|
|
if len(values) < columns {
|
|
continue
|
|
}
|
|
base := 1
|
|
// sometimes Address is omitted
|
|
if len(values) < columns {
|
|
base = 0
|
|
}
|
|
|
|
parsed := make([]uint64, 0, 8)
|
|
var vv []string
|
|
if mode == "inb" {
|
|
vv = []string{
|
|
values[base+3], // BytesRecv
|
|
values[base+4], // BytesSent
|
|
}
|
|
} else {
|
|
vv = []string{
|
|
values[base+3], // Ipkts
|
|
values[base+4], // Ierrs
|
|
values[base+5], // Opkts
|
|
values[base+6], // Oerrs
|
|
values[base+8], // Drops
|
|
}
|
|
}
|
|
for _, target := range vv {
|
|
if target == "-" {
|
|
parsed = append(parsed, 0)
|
|
continue
|
|
}
|
|
|
|
t, err := strconv.ParseUint(target, 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
parsed = append(parsed, t)
|
|
}
|
|
exists = append(exists, values[0])
|
|
|
|
n, present := iocs[values[0]]
|
|
if !present {
|
|
n = IOCountersStat{Name: values[0]}
|
|
}
|
|
if mode == "inb" {
|
|
n.BytesRecv = parsed[0]
|
|
n.BytesSent = parsed[1]
|
|
} else {
|
|
n.PacketsRecv = parsed[0]
|
|
n.Errin = parsed[1]
|
|
n.PacketsSent = parsed[2]
|
|
n.Errout = parsed[3]
|
|
n.Dropin = parsed[4]
|
|
n.Dropout = parsed[4]
|
|
}
|
|
|
|
iocs[n.Name] = n
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func IOCounters(pernic bool) ([]IOCountersStat, error) {
|
|
return IOCountersWithContext(context.Background(), pernic)
|
|
}
|
|
|
|
func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
|
|
netstat, err := exec.LookPath("netstat")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out, err := invoke.CommandWithContext(ctx, netstat, "-inb")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out2, err := invoke.CommandWithContext(ctx, netstat, "-ind")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
iocs := make(map[string]IOCountersStat)
|
|
|
|
lines := strings.Split(string(out), "\n")
|
|
ret := make([]IOCountersStat, 0, len(lines)-1)
|
|
|
|
err = ParseNetstat(string(out), "inb", iocs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = ParseNetstat(string(out2), "ind", iocs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, ioc := range iocs {
|
|
ret = append(ret, ioc)
|
|
}
|
|
|
|
if pernic == false {
|
|
return getIOCountersAll(ret)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
// NetIOCountersByFile is an method which is added just a compatibility for linux.
|
|
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
|
|
return IOCountersByFileWithContext(context.Background(), pernic, filename)
|
|
}
|
|
|
|
func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
|
|
return IOCounters(pernic)
|
|
}
|
|
|
|
func FilterCounters() ([]FilterStat, error) {
|
|
return FilterCountersWithContext(context.Background())
|
|
}
|
|
|
|
func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
|
|
return nil, errors.New("NetFilterCounters not implemented for openbsd")
|
|
}
|
|
|
|
func ConntrackStats(percpu bool) ([]ConntrackStat, error) {
|
|
return ConntrackStatsWithContext(context.Background(), percpu)
|
|
}
|
|
|
|
func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
|
|
return nil, common.ErrNotImplementedError
|
|
}
|
|
|
|
// NetProtoCounters returns network statistics for the entire system
|
|
// If protocols is empty then all protocols are returned, otherwise
|
|
// just the protocols in the list are returned.
|
|
// Not Implemented for OpenBSD
|
|
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
|
|
return ProtoCountersWithContext(context.Background(), protocols)
|
|
}
|
|
|
|
func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
|
|
return nil, errors.New("NetProtoCounters not implemented for openbsd")
|
|
}
|
|
|
|
func parseNetstatLine(line string) (ConnectionStat, error) {
|
|
f := strings.Fields(line)
|
|
if len(f) < 5 {
|
|
return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
|
|
}
|
|
|
|
var netType, netFamily uint32
|
|
switch f[0] {
|
|
case "tcp":
|
|
netType = syscall.SOCK_STREAM
|
|
netFamily = syscall.AF_INET
|
|
case "udp":
|
|
netType = syscall.SOCK_DGRAM
|
|
netFamily = syscall.AF_INET
|
|
case "tcp6":
|
|
netType = syscall.SOCK_STREAM
|
|
netFamily = syscall.AF_INET6
|
|
case "udp6":
|
|
netType = syscall.SOCK_DGRAM
|
|
netFamily = syscall.AF_INET6
|
|
default:
|
|
return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[0])
|
|
}
|
|
|
|
laddr, raddr, err := parseNetstatAddr(f[3], f[4], netFamily)
|
|
if err != nil {
|
|
return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s %s", f[3], f[4])
|
|
}
|
|
|
|
n := ConnectionStat{
|
|
Fd: uint32(0), // not supported
|
|
Family: uint32(netFamily),
|
|
Type: uint32(netType),
|
|
Laddr: laddr,
|
|
Raddr: raddr,
|
|
Pid: int32(0), // not supported
|
|
}
|
|
if len(f) == 6 {
|
|
n.Status = f[5]
|
|
}
|
|
|
|
return n, nil
|
|
}
|
|
|
|
func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) {
|
|
parse := func(l string) (Addr, error) {
|
|
matches := portMatch.FindStringSubmatch(l)
|
|
if matches == nil {
|
|
return Addr{}, fmt.Errorf("wrong addr, %s", l)
|
|
}
|
|
host := matches[1]
|
|
port := matches[2]
|
|
if host == "*" {
|
|
switch family {
|
|
case syscall.AF_INET:
|
|
host = "0.0.0.0"
|
|
case syscall.AF_INET6:
|
|
host = "::"
|
|
default:
|
|
return Addr{}, fmt.Errorf("unknown family, %d", family)
|
|
}
|
|
}
|
|
lport, err := strconv.Atoi(port)
|
|
if err != nil {
|
|
return Addr{}, err
|
|
}
|
|
return Addr{IP: host, Port: uint32(lport)}, nil
|
|
}
|
|
|
|
laddr, err = parse(local)
|
|
if remote != "*.*" { // remote addr exists
|
|
raddr, err = parse(remote)
|
|
if err != nil {
|
|
return laddr, raddr, err
|
|
}
|
|
}
|
|
|
|
return laddr, raddr, err
|
|
}
|
|
|
|
// Return a list of network connections opened.
|
|
func Connections(kind string) ([]ConnectionStat, error) {
|
|
return ConnectionsWithContext(context.Background(), kind)
|
|
}
|
|
|
|
func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
|
|
var ret []ConnectionStat
|
|
|
|
args := []string{"-na"}
|
|
switch strings.ToLower(kind) {
|
|
default:
|
|
fallthrough
|
|
case "":
|
|
fallthrough
|
|
case "all":
|
|
fallthrough
|
|
case "inet":
|
|
// nothing to add
|
|
case "inet4":
|
|
args = append(args, "-finet")
|
|
case "inet6":
|
|
args = append(args, "-finet6")
|
|
case "tcp":
|
|
args = append(args, "-ptcp")
|
|
case "tcp4":
|
|
args = append(args, "-ptcp", "-finet")
|
|
case "tcp6":
|
|
args = append(args, "-ptcp", "-finet6")
|
|
case "udp":
|
|
args = append(args, "-pudp")
|
|
case "udp4":
|
|
args = append(args, "-pudp", "-finet")
|
|
case "udp6":
|
|
args = append(args, "-pudp", "-finet6")
|
|
case "unix":
|
|
return ret, common.ErrNotImplementedError
|
|
}
|
|
|
|
netstat, err := exec.LookPath("netstat")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out, err := invoke.CommandWithContext(ctx, netstat, args...)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lines := strings.Split(string(out), "\n")
|
|
for _, line := range lines {
|
|
if !(strings.HasPrefix(line, "tcp") || strings.HasPrefix(line, "udp")) {
|
|
continue
|
|
}
|
|
n, err := parseNetstatLine(line)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
ret = append(ret, n)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|