net_unix.go 6.0 KB

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