net_unix.go 5.9 KB

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