github.com/gofiber/fiber/v2@v2.47.0/internal/gopsutil/net/net_unix.go (about)

     1  //go:build freebsd || darwin
     2  // +build freebsd darwin
     3  
     4  package net
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net"
    10  	"strconv"
    11  	"strings"
    12  	"syscall"
    13  
    14  	"github.com/gofiber/fiber/v2/internal/gopsutil/common"
    15  )
    16  
    17  // Return a list of network connections opened.
    18  func Connections(kind string) ([]ConnectionStat, error) {
    19  	return ConnectionsWithContext(context.Background(), kind)
    20  }
    21  
    22  func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
    23  	return ConnectionsPid(kind, 0)
    24  }
    25  
    26  // Return a list of network connections opened returning at most `max`
    27  // connections for each running process.
    28  func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
    29  	return ConnectionsMaxWithContext(context.Background(), kind, max)
    30  }
    31  
    32  func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
    33  	return []ConnectionStat{}, common.ErrNotImplementedError
    34  }
    35  
    36  // Return a list of network connections opened by a process.
    37  func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
    38  	return ConnectionsPidWithContext(context.Background(), kind, pid)
    39  }
    40  
    41  func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
    42  	var ret []ConnectionStat
    43  
    44  	args := []string{"-i"}
    45  	switch strings.ToLower(kind) {
    46  	default:
    47  		fallthrough
    48  	case "":
    49  		fallthrough
    50  	case "all":
    51  		fallthrough
    52  	case "inet":
    53  		args = append(args, "tcp", "-i", "udp")
    54  	case "inet4":
    55  		args = append(args, "4")
    56  	case "inet6":
    57  		args = append(args, "6")
    58  	case "tcp":
    59  		args = append(args, "tcp")
    60  	case "tcp4":
    61  		args = append(args, "4tcp")
    62  	case "tcp6":
    63  		args = append(args, "6tcp")
    64  	case "udp":
    65  		args = append(args, "udp")
    66  	case "udp4":
    67  		args = append(args, "6udp")
    68  	case "udp6":
    69  		args = append(args, "6udp")
    70  	case "unix":
    71  		args = []string{"-U"}
    72  	}
    73  
    74  	r, err := common.CallLsofWithContext(ctx, invoke, pid, args...)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	for _, rr := range r {
    79  		if strings.HasPrefix(rr, "COMMAND") {
    80  			continue
    81  		}
    82  		n, err := parseNetLine(rr)
    83  		if err != nil {
    84  
    85  			continue
    86  		}
    87  
    88  		ret = append(ret, n)
    89  	}
    90  
    91  	return ret, nil
    92  }
    93  
    94  var constMap = map[string]int{
    95  	"unix": syscall.AF_UNIX,
    96  	"TCP":  syscall.SOCK_STREAM,
    97  	"UDP":  syscall.SOCK_DGRAM,
    98  	"IPv4": syscall.AF_INET,
    99  	"IPv6": syscall.AF_INET6,
   100  }
   101  
   102  func parseNetLine(line string) (ConnectionStat, error) {
   103  	f := strings.Fields(line)
   104  	if len(f) < 8 {
   105  		return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
   106  	}
   107  
   108  	if len(f) == 8 {
   109  		f = append(f, f[7])
   110  		f[7] = "unix"
   111  	}
   112  
   113  	pid, err := strconv.Atoi(f[1])
   114  	if err != nil {
   115  		return ConnectionStat{}, err
   116  	}
   117  	fd, err := strconv.Atoi(strings.Trim(f[3], "u"))
   118  	if err != nil {
   119  		return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3])
   120  	}
   121  	netFamily, ok := constMap[f[4]]
   122  	if !ok {
   123  		return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4])
   124  	}
   125  	netType, ok := constMap[f[7]]
   126  	if !ok {
   127  		return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7])
   128  	}
   129  
   130  	var laddr, raddr Addr
   131  	if f[7] == "unix" {
   132  		laddr.IP = f[8]
   133  	} else {
   134  		laddr, raddr, err = parseNetAddr(f[8])
   135  		if err != nil {
   136  			return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8])
   137  		}
   138  	}
   139  
   140  	n := ConnectionStat{
   141  		Fd:     uint32(fd),
   142  		Family: uint32(netFamily),
   143  		Type:   uint32(netType),
   144  		Laddr:  laddr,
   145  		Raddr:  raddr,
   146  		Pid:    int32(pid),
   147  	}
   148  	if len(f) == 10 {
   149  		n.Status = strings.Trim(f[9], "()")
   150  	}
   151  
   152  	return n, nil
   153  }
   154  
   155  func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) {
   156  	parse := func(l string) (Addr, error) {
   157  		host, port, err := net.SplitHostPort(l)
   158  		if err != nil {
   159  			return Addr{}, fmt.Errorf("wrong addr, %s", l)
   160  		}
   161  		lport, err := strconv.Atoi(port)
   162  		if err != nil {
   163  			return Addr{}, err
   164  		}
   165  		return Addr{IP: host, Port: uint32(lport)}, nil
   166  	}
   167  
   168  	addrs := strings.Split(line, "->")
   169  	if len(addrs) == 0 {
   170  		return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line)
   171  	}
   172  	laddr, err = parse(addrs[0])
   173  	if len(addrs) == 2 { // remote addr exists
   174  		raddr, err = parse(addrs[1])
   175  		if err != nil {
   176  			return laddr, raddr, err
   177  		}
   178  	}
   179  
   180  	return laddr, raddr, err
   181  }
   182  
   183  // Return up to `max` network connections opened by a process.
   184  func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) {
   185  	return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max)
   186  }
   187  
   188  func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
   189  	return []ConnectionStat{}, common.ErrNotImplementedError
   190  }
   191  
   192  // Return a list of network connections opened, omitting `Uids`.
   193  // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be
   194  // removed from the API in the future.
   195  func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) {
   196  	return ConnectionsWithoutUidsWithContext(context.Background(), kind)
   197  }
   198  
   199  func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
   200  	return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
   201  }
   202  
   203  func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
   204  	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max)
   205  }
   206  
   207  func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) {
   208  	return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid)
   209  }
   210  
   211  func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
   212  	return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
   213  }
   214  
   215  func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) {
   216  	return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max)
   217  }
   218  
   219  func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
   220  	return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max)
   221  }
   222  
   223  func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
   224  	return []ConnectionStat{}, common.ErrNotImplementedError
   225  }