net_linux.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. //go:build linux
  2. // +build linux
  3. package net
  4. import (
  5. "bytes"
  6. "context"
  7. "encoding/hex"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "io/ioutil"
  12. "net"
  13. "os"
  14. "strconv"
  15. "strings"
  16. "syscall"
  17. "github.com/shirou/gopsutil/v3/internal/common"
  18. )
  19. const ( // Conntrack Column numbers
  20. ctENTRIES = iota
  21. ctSEARCHED
  22. ctFOUND
  23. ctNEW
  24. ctINVALID
  25. ctIGNORE
  26. ctDELETE
  27. ctDELETE_LIST
  28. ctINSERT
  29. ctINSERT_FAILED
  30. ctDROP
  31. ctEARLY_DROP
  32. ctICMP_ERROR
  33. CT_EXPEctNEW
  34. ctEXPECT_CREATE
  35. CT_EXPEctDELETE
  36. ctSEARCH_RESTART
  37. )
  38. // NetIOCounters returns network I/O statistics for every network
  39. // interface installed on the system. If pernic argument is false,
  40. // return only sum of all information (which name is 'all'). If true,
  41. // every network interface installed on the system is returned
  42. // separately.
  43. func IOCounters(pernic bool) ([]IOCountersStat, error) {
  44. return IOCountersWithContext(context.Background(), pernic)
  45. }
  46. func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) {
  47. filename := common.HostProc("net/dev")
  48. return IOCountersByFileWithContext(ctx, pernic, filename)
  49. }
  50. func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
  51. return IOCountersByFileWithContext(context.Background(), pernic, filename)
  52. }
  53. func IOCountersByFileWithContext(ctx context.Context, pernic bool, filename string) ([]IOCountersStat, error) {
  54. lines, err := common.ReadLines(filename)
  55. if err != nil {
  56. return nil, err
  57. }
  58. parts := make([]string, 2)
  59. statlen := len(lines) - 1
  60. ret := make([]IOCountersStat, 0, statlen)
  61. for _, line := range lines[2:] {
  62. separatorPos := strings.LastIndex(line, ":")
  63. if separatorPos == -1 {
  64. continue
  65. }
  66. parts[0] = line[0:separatorPos]
  67. parts[1] = line[separatorPos+1:]
  68. interfaceName := strings.TrimSpace(parts[0])
  69. if interfaceName == "" {
  70. continue
  71. }
  72. fields := strings.Fields(strings.TrimSpace(parts[1]))
  73. bytesRecv, err := strconv.ParseUint(fields[0], 10, 64)
  74. if err != nil {
  75. return ret, err
  76. }
  77. packetsRecv, err := strconv.ParseUint(fields[1], 10, 64)
  78. if err != nil {
  79. return ret, err
  80. }
  81. errIn, err := strconv.ParseUint(fields[2], 10, 64)
  82. if err != nil {
  83. return ret, err
  84. }
  85. dropIn, err := strconv.ParseUint(fields[3], 10, 64)
  86. if err != nil {
  87. return ret, err
  88. }
  89. fifoIn, err := strconv.ParseUint(fields[4], 10, 64)
  90. if err != nil {
  91. return ret, err
  92. }
  93. bytesSent, err := strconv.ParseUint(fields[8], 10, 64)
  94. if err != nil {
  95. return ret, err
  96. }
  97. packetsSent, err := strconv.ParseUint(fields[9], 10, 64)
  98. if err != nil {
  99. return ret, err
  100. }
  101. errOut, err := strconv.ParseUint(fields[10], 10, 64)
  102. if err != nil {
  103. return ret, err
  104. }
  105. dropOut, err := strconv.ParseUint(fields[11], 10, 64)
  106. if err != nil {
  107. return ret, err
  108. }
  109. fifoOut, err := strconv.ParseUint(fields[12], 10, 64)
  110. if err != nil {
  111. return ret, err
  112. }
  113. nic := IOCountersStat{
  114. Name: interfaceName,
  115. BytesRecv: bytesRecv,
  116. PacketsRecv: packetsRecv,
  117. Errin: errIn,
  118. Dropin: dropIn,
  119. Fifoin: fifoIn,
  120. BytesSent: bytesSent,
  121. PacketsSent: packetsSent,
  122. Errout: errOut,
  123. Dropout: dropOut,
  124. Fifoout: fifoOut,
  125. }
  126. ret = append(ret, nic)
  127. }
  128. if !pernic {
  129. return getIOCountersAll(ret)
  130. }
  131. return ret, nil
  132. }
  133. var netProtocols = []string{
  134. "ip",
  135. "icmp",
  136. "icmpmsg",
  137. "tcp",
  138. "udp",
  139. "udplite",
  140. }
  141. // NetProtoCounters returns network statistics for the entire system
  142. // If protocols is empty then all protocols are returned, otherwise
  143. // just the protocols in the list are returned.
  144. // Available protocols:
  145. // [ip,icmp,icmpmsg,tcp,udp,udplite]
  146. func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
  147. return ProtoCountersWithContext(context.Background(), protocols)
  148. }
  149. func ProtoCountersWithContext(ctx context.Context, protocols []string) ([]ProtoCountersStat, error) {
  150. if len(protocols) == 0 {
  151. protocols = netProtocols
  152. }
  153. stats := make([]ProtoCountersStat, 0, len(protocols))
  154. protos := make(map[string]bool, len(protocols))
  155. for _, p := range protocols {
  156. protos[p] = true
  157. }
  158. filename := common.HostProc("net/snmp")
  159. lines, err := common.ReadLines(filename)
  160. if err != nil {
  161. return nil, err
  162. }
  163. linecount := len(lines)
  164. for i := 0; i < linecount; i++ {
  165. line := lines[i]
  166. r := strings.IndexRune(line, ':')
  167. if r == -1 {
  168. return nil, errors.New(filename + " is not formatted correctly, expected ':'.")
  169. }
  170. proto := strings.ToLower(line[:r])
  171. if !protos[proto] {
  172. // skip protocol and data line
  173. i++
  174. continue
  175. }
  176. // Read header line
  177. statNames := strings.Split(line[r+2:], " ")
  178. // Read data line
  179. i++
  180. statValues := strings.Split(lines[i][r+2:], " ")
  181. if len(statNames) != len(statValues) {
  182. return nil, errors.New(filename + " is not formatted correctly, expected same number of columns.")
  183. }
  184. stat := ProtoCountersStat{
  185. Protocol: proto,
  186. Stats: make(map[string]int64, len(statNames)),
  187. }
  188. for j := range statNames {
  189. value, err := strconv.ParseInt(statValues[j], 10, 64)
  190. if err != nil {
  191. return nil, err
  192. }
  193. stat.Stats[statNames[j]] = value
  194. }
  195. stats = append(stats, stat)
  196. }
  197. return stats, nil
  198. }
  199. // NetFilterCounters returns iptables conntrack statistics
  200. // the currently in use conntrack count and the max.
  201. // If the file does not exist or is invalid it will return nil.
  202. func FilterCounters() ([]FilterStat, error) {
  203. return FilterCountersWithContext(context.Background())
  204. }
  205. func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) {
  206. countfile := common.HostProc("sys/net/netfilter/nf_conntrack_count")
  207. maxfile := common.HostProc("sys/net/netfilter/nf_conntrack_max")
  208. count, err := common.ReadInts(countfile)
  209. if err != nil {
  210. return nil, err
  211. }
  212. stats := make([]FilterStat, 0, 1)
  213. max, err := common.ReadInts(maxfile)
  214. if err != nil {
  215. return nil, err
  216. }
  217. payload := FilterStat{
  218. ConnTrackCount: count[0],
  219. ConnTrackMax: max[0],
  220. }
  221. stats = append(stats, payload)
  222. return stats, nil
  223. }
  224. // ConntrackStats returns more detailed info about the conntrack table
  225. func ConntrackStats(percpu bool) ([]ConntrackStat, error) {
  226. return ConntrackStatsWithContext(context.Background(), percpu)
  227. }
  228. // ConntrackStatsWithContext returns more detailed info about the conntrack table
  229. func ConntrackStatsWithContext(ctx context.Context, percpu bool) ([]ConntrackStat, error) {
  230. return conntrackStatsFromFile(common.HostProc("net/stat/nf_conntrack"), percpu)
  231. }
  232. // conntrackStatsFromFile returns more detailed info about the conntrack table
  233. // from `filename`
  234. // If 'percpu' is false, the result will contain exactly one item with totals/summary
  235. func conntrackStatsFromFile(filename string, percpu bool) ([]ConntrackStat, error) {
  236. lines, err := common.ReadLines(filename)
  237. if err != nil {
  238. return nil, err
  239. }
  240. statlist := NewConntrackStatList()
  241. for _, line := range lines {
  242. fields := strings.Fields(line)
  243. if len(fields) == 17 && fields[0] != "entries" {
  244. statlist.Append(NewConntrackStat(
  245. common.HexToUint32(fields[ctENTRIES]),
  246. common.HexToUint32(fields[ctSEARCHED]),
  247. common.HexToUint32(fields[ctFOUND]),
  248. common.HexToUint32(fields[ctNEW]),
  249. common.HexToUint32(fields[ctINVALID]),
  250. common.HexToUint32(fields[ctIGNORE]),
  251. common.HexToUint32(fields[ctDELETE]),
  252. common.HexToUint32(fields[ctDELETE_LIST]),
  253. common.HexToUint32(fields[ctINSERT]),
  254. common.HexToUint32(fields[ctINSERT_FAILED]),
  255. common.HexToUint32(fields[ctDROP]),
  256. common.HexToUint32(fields[ctEARLY_DROP]),
  257. common.HexToUint32(fields[ctICMP_ERROR]),
  258. common.HexToUint32(fields[CT_EXPEctNEW]),
  259. common.HexToUint32(fields[ctEXPECT_CREATE]),
  260. common.HexToUint32(fields[CT_EXPEctDELETE]),
  261. common.HexToUint32(fields[ctSEARCH_RESTART]),
  262. ))
  263. }
  264. }
  265. if percpu {
  266. return statlist.Items(), nil
  267. }
  268. return statlist.Summary(), nil
  269. }
  270. // http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
  271. var tcpStatuses = map[string]string{
  272. "01": "ESTABLISHED",
  273. "02": "SYN_SENT",
  274. "03": "SYN_RECV",
  275. "04": "FIN_WAIT1",
  276. "05": "FIN_WAIT2",
  277. "06": "TIME_WAIT",
  278. "07": "CLOSE",
  279. "08": "CLOSE_WAIT",
  280. "09": "LAST_ACK",
  281. "0A": "LISTEN",
  282. "0B": "CLOSING",
  283. }
  284. type netConnectionKindType struct {
  285. family uint32
  286. sockType uint32
  287. filename string
  288. }
  289. var kindTCP4 = netConnectionKindType{
  290. family: syscall.AF_INET,
  291. sockType: syscall.SOCK_STREAM,
  292. filename: "tcp",
  293. }
  294. var kindTCP6 = netConnectionKindType{
  295. family: syscall.AF_INET6,
  296. sockType: syscall.SOCK_STREAM,
  297. filename: "tcp6",
  298. }
  299. var kindUDP4 = netConnectionKindType{
  300. family: syscall.AF_INET,
  301. sockType: syscall.SOCK_DGRAM,
  302. filename: "udp",
  303. }
  304. var kindUDP6 = netConnectionKindType{
  305. family: syscall.AF_INET6,
  306. sockType: syscall.SOCK_DGRAM,
  307. filename: "udp6",
  308. }
  309. var kindUNIX = netConnectionKindType{
  310. family: syscall.AF_UNIX,
  311. filename: "unix",
  312. }
  313. var netConnectionKindMap = map[string][]netConnectionKindType{
  314. "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
  315. "tcp": {kindTCP4, kindTCP6},
  316. "tcp4": {kindTCP4},
  317. "tcp6": {kindTCP6},
  318. "udp": {kindUDP4, kindUDP6},
  319. "udp4": {kindUDP4},
  320. "udp6": {kindUDP6},
  321. "unix": {kindUNIX},
  322. "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6},
  323. "inet4": {kindTCP4, kindUDP4},
  324. "inet6": {kindTCP6, kindUDP6},
  325. }
  326. type inodeMap struct {
  327. pid int32
  328. fd uint32
  329. }
  330. type connTmp struct {
  331. fd uint32
  332. family uint32
  333. sockType uint32
  334. laddr Addr
  335. raddr Addr
  336. status string
  337. pid int32
  338. boundPid int32
  339. path string
  340. }
  341. // Return a list of network connections opened.
  342. func Connections(kind string) ([]ConnectionStat, error) {
  343. return ConnectionsWithContext(context.Background(), kind)
  344. }
  345. func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
  346. return ConnectionsPidWithContext(ctx, kind, 0)
  347. }
  348. // Return a list of network connections opened returning at most `max`
  349. // connections for each running process.
  350. func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) {
  351. return ConnectionsMaxWithContext(context.Background(), kind, max)
  352. }
  353. func ConnectionsMaxWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
  354. return ConnectionsPidMaxWithContext(ctx, kind, 0, max)
  355. }
  356. // Return a list of network connections opened, omitting `Uids`.
  357. // WithoutUids functions are reliant on implementation details. They may be altered to be an alias for Connections or be
  358. // removed from the API in the future.
  359. func ConnectionsWithoutUids(kind string) ([]ConnectionStat, error) {
  360. return ConnectionsWithoutUidsWithContext(context.Background(), kind)
  361. }
  362. func ConnectionsWithoutUidsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) {
  363. return ConnectionsMaxWithoutUidsWithContext(ctx, kind, 0)
  364. }
  365. func ConnectionsMaxWithoutUidsWithContext(ctx context.Context, kind string, max int) ([]ConnectionStat, error) {
  366. return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, 0, max)
  367. }
  368. // Return a list of network connections opened by a process.
  369. func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
  370. return ConnectionsPidWithContext(context.Background(), kind, pid)
  371. }
  372. func ConnectionsPidWithoutUids(kind string, pid int32) ([]ConnectionStat, error) {
  373. return ConnectionsPidWithoutUidsWithContext(context.Background(), kind, pid)
  374. }
  375. func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
  376. return ConnectionsPidMaxWithContext(ctx, kind, pid, 0)
  377. }
  378. func ConnectionsPidWithoutUidsWithContext(ctx context.Context, kind string, pid int32) ([]ConnectionStat, error) {
  379. return ConnectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, 0)
  380. }
  381. // Return up to `max` network connections opened by a process.
  382. func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) {
  383. return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max)
  384. }
  385. func ConnectionsPidMaxWithoutUids(kind string, pid int32, max int) ([]ConnectionStat, error) {
  386. return ConnectionsPidMaxWithoutUidsWithContext(context.Background(), kind, pid, max)
  387. }
  388. func ConnectionsPidMaxWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
  389. return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max, false)
  390. }
  391. func ConnectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int) ([]ConnectionStat, error) {
  392. return connectionsPidMaxWithoutUidsWithContext(ctx, kind, pid, max, true)
  393. }
  394. func connectionsPidMaxWithoutUidsWithContext(ctx context.Context, kind string, pid int32, max int, skipUids bool) ([]ConnectionStat, error) {
  395. tmap, ok := netConnectionKindMap[kind]
  396. if !ok {
  397. return nil, fmt.Errorf("invalid kind, %s", kind)
  398. }
  399. root := common.HostProc()
  400. var err error
  401. var inodes map[string][]inodeMap
  402. if pid == 0 {
  403. inodes, err = getProcInodesAllWithContext(ctx, root, max)
  404. } else {
  405. inodes, err = getProcInodes(root, pid, max)
  406. if len(inodes) == 0 {
  407. // no connection for the pid
  408. return []ConnectionStat{}, nil
  409. }
  410. }
  411. if err != nil {
  412. return nil, fmt.Errorf("cound not get pid(s), %d: %w", pid, err)
  413. }
  414. return statsFromInodesWithContext(ctx, root, pid, tmap, inodes, skipUids)
  415. }
  416. func statsFromInodes(root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) {
  417. return statsFromInodesWithContext(context.Background(), root, pid, tmap, inodes, skipUids)
  418. }
  419. func statsFromInodesWithContext(ctx context.Context, root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap, skipUids bool) ([]ConnectionStat, error) {
  420. dupCheckMap := make(map[string]struct{})
  421. var ret []ConnectionStat
  422. var err error
  423. for _, t := range tmap {
  424. var path string
  425. var connKey string
  426. var ls []connTmp
  427. if pid == 0 {
  428. path = fmt.Sprintf("%s/net/%s", root, t.filename)
  429. } else {
  430. path = fmt.Sprintf("%s/%d/net/%s", root, pid, t.filename)
  431. }
  432. switch t.family {
  433. case syscall.AF_INET, syscall.AF_INET6:
  434. ls, err = processInetWithContext(ctx, path, t, inodes, pid)
  435. case syscall.AF_UNIX:
  436. ls, err = processUnix(path, t, inodes, pid)
  437. }
  438. if err != nil {
  439. return nil, err
  440. }
  441. for _, c := range ls {
  442. // Build TCP key to id the connection uniquely
  443. // socket type, src ip, src port, dst ip, dst port and state should be enough
  444. // to prevent duplications.
  445. connKey = fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status)
  446. if _, ok := dupCheckMap[connKey]; ok {
  447. continue
  448. }
  449. conn := ConnectionStat{
  450. Fd: c.fd,
  451. Family: c.family,
  452. Type: c.sockType,
  453. Laddr: c.laddr,
  454. Raddr: c.raddr,
  455. Status: c.status,
  456. Pid: c.pid,
  457. }
  458. if c.pid == 0 {
  459. conn.Pid = c.boundPid
  460. } else {
  461. conn.Pid = c.pid
  462. }
  463. if !skipUids {
  464. // fetch process owner Real, effective, saved set, and filesystem UIDs
  465. proc := process{Pid: conn.Pid}
  466. conn.Uids, _ = proc.getUids()
  467. }
  468. ret = append(ret, conn)
  469. dupCheckMap[connKey] = struct{}{}
  470. }
  471. }
  472. return ret, nil
  473. }
  474. // getProcInodes returns fd of the pid.
  475. func getProcInodes(root string, pid int32, max int) (map[string][]inodeMap, error) {
  476. ret := make(map[string][]inodeMap)
  477. dir := fmt.Sprintf("%s/%d/fd", root, pid)
  478. f, err := os.Open(dir)
  479. if err != nil {
  480. return ret, err
  481. }
  482. defer f.Close()
  483. dirEntries, err := readDir(f, max)
  484. if err != nil {
  485. return ret, err
  486. }
  487. for _, dirEntry := range dirEntries {
  488. inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, dirEntry.Name())
  489. inode, err := os.Readlink(inodePath)
  490. if err != nil {
  491. continue
  492. }
  493. if !strings.HasPrefix(inode, "socket:[") {
  494. continue
  495. }
  496. // the process is using a socket
  497. l := len(inode)
  498. inode = inode[8 : l-1]
  499. _, ok := ret[inode]
  500. if !ok {
  501. ret[inode] = make([]inodeMap, 0)
  502. }
  503. fd, err := strconv.Atoi(dirEntry.Name())
  504. if err != nil {
  505. continue
  506. }
  507. i := inodeMap{
  508. pid: pid,
  509. fd: uint32(fd),
  510. }
  511. ret[inode] = append(ret[inode], i)
  512. }
  513. return ret, nil
  514. }
  515. // Pids retunres all pids.
  516. // Note: this is a copy of process_linux.Pids()
  517. // FIXME: Import process occures import cycle.
  518. // move to common made other platform breaking. Need consider.
  519. func Pids() ([]int32, error) {
  520. return PidsWithContext(context.Background())
  521. }
  522. func PidsWithContext(ctx context.Context) ([]int32, error) {
  523. var ret []int32
  524. d, err := os.Open(common.HostProc())
  525. if err != nil {
  526. return nil, err
  527. }
  528. defer d.Close()
  529. fnames, err := d.Readdirnames(-1)
  530. if err != nil {
  531. return nil, err
  532. }
  533. for _, fname := range fnames {
  534. pid, err := strconv.ParseInt(fname, 10, 32)
  535. if err != nil {
  536. // if not numeric name, just skip
  537. continue
  538. }
  539. ret = append(ret, int32(pid))
  540. }
  541. return ret, nil
  542. }
  543. // Note: the following is based off process_linux structs and methods
  544. // we need these to fetch the owner of a process ID
  545. // FIXME: Import process occures import cycle.
  546. // see remarks on pids()
  547. type process struct {
  548. Pid int32 `json:"pid"`
  549. uids []int32
  550. }
  551. // Uids returns user ids of the process as a slice of the int
  552. func (p *process) getUids() ([]int32, error) {
  553. err := p.fillFromStatus()
  554. if err != nil {
  555. return []int32{}, err
  556. }
  557. return p.uids, nil
  558. }
  559. // Get status from /proc/(pid)/status
  560. func (p *process) fillFromStatus() error {
  561. pid := p.Pid
  562. statPath := common.HostProc(strconv.Itoa(int(pid)), "status")
  563. contents, err := ioutil.ReadFile(statPath)
  564. if err != nil {
  565. return err
  566. }
  567. lines := strings.Split(string(contents), "\n")
  568. for _, line := range lines {
  569. tabParts := strings.SplitN(line, "\t", 2)
  570. if len(tabParts) < 2 {
  571. continue
  572. }
  573. value := tabParts[1]
  574. switch strings.TrimRight(tabParts[0], ":") {
  575. case "Uid":
  576. p.uids = make([]int32, 0, 4)
  577. for _, i := range strings.Split(value, "\t") {
  578. v, err := strconv.ParseInt(i, 10, 32)
  579. if err != nil {
  580. return err
  581. }
  582. p.uids = append(p.uids, int32(v))
  583. }
  584. }
  585. }
  586. return nil
  587. }
  588. func getProcInodesAll(root string, max int) (map[string][]inodeMap, error) {
  589. return getProcInodesAllWithContext(context.Background(), root, max)
  590. }
  591. func getProcInodesAllWithContext(ctx context.Context, root string, max int) (map[string][]inodeMap, error) {
  592. pids, err := PidsWithContext(ctx)
  593. if err != nil {
  594. return nil, err
  595. }
  596. ret := make(map[string][]inodeMap)
  597. for _, pid := range pids {
  598. t, err := getProcInodes(root, pid, max)
  599. if err != nil {
  600. // skip if permission error or no longer exists
  601. if os.IsPermission(err) || os.IsNotExist(err) || errors.Is(err, io.EOF) {
  602. continue
  603. }
  604. return ret, err
  605. }
  606. if len(t) == 0 {
  607. continue
  608. }
  609. // TODO: update ret.
  610. ret = updateMap(ret, t)
  611. }
  612. return ret, nil
  613. }
  614. // decodeAddress decode addresse represents addr in proc/net/*
  615. // ex:
  616. // "0500000A:0016" -> "10.0.0.5", 22
  617. // "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53
  618. func decodeAddress(family uint32, src string) (Addr, error) {
  619. return decodeAddressWithContext(context.Background(), family, src)
  620. }
  621. func decodeAddressWithContext(ctx context.Context, family uint32, src string) (Addr, error) {
  622. t := strings.Split(src, ":")
  623. if len(t) != 2 {
  624. return Addr{}, fmt.Errorf("does not contain port, %s", src)
  625. }
  626. addr := t[0]
  627. port, err := strconv.ParseUint(t[1], 16, 16)
  628. if err != nil {
  629. return Addr{}, fmt.Errorf("invalid port, %s", src)
  630. }
  631. decoded, err := hex.DecodeString(addr)
  632. if err != nil {
  633. return Addr{}, fmt.Errorf("decode error, %w", err)
  634. }
  635. var ip net.IP
  636. if family == syscall.AF_INET {
  637. if common.IsLittleEndian() {
  638. ip = net.IP(ReverseWithContext(ctx, decoded))
  639. } else {
  640. ip = net.IP(decoded)
  641. }
  642. } else { // IPv6
  643. ip, err = parseIPv6HexStringWithContext(ctx, decoded)
  644. if err != nil {
  645. return Addr{}, err
  646. }
  647. }
  648. return Addr{
  649. IP: ip.String(),
  650. Port: uint32(port),
  651. }, nil
  652. }
  653. // Reverse reverses array of bytes.
  654. func Reverse(s []byte) []byte {
  655. return ReverseWithContext(context.Background(), s)
  656. }
  657. func ReverseWithContext(ctx context.Context, s []byte) []byte {
  658. for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
  659. s[i], s[j] = s[j], s[i]
  660. }
  661. return s
  662. }
  663. // parseIPv6HexString parse array of bytes to IPv6 string
  664. func parseIPv6HexString(src []byte) (net.IP, error) {
  665. return parseIPv6HexStringWithContext(context.Background(), src)
  666. }
  667. func parseIPv6HexStringWithContext(ctx context.Context, src []byte) (net.IP, error) {
  668. if len(src) != 16 {
  669. return nil, fmt.Errorf("invalid IPv6 string")
  670. }
  671. buf := make([]byte, 0, 16)
  672. for i := 0; i < len(src); i += 4 {
  673. r := ReverseWithContext(ctx, src[i:i+4])
  674. buf = append(buf, r...)
  675. }
  676. return net.IP(buf), nil
  677. }
  678. func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
  679. return processInetWithContext(context.Background(), file, kind, inodes, filterPid)
  680. }
  681. func processInetWithContext(ctx context.Context, file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
  682. if strings.HasSuffix(file, "6") && !common.PathExists(file) {
  683. // IPv6 not supported, return empty.
  684. return []connTmp{}, nil
  685. }
  686. // Read the contents of the /proc file with a single read sys call.
  687. // This minimizes duplicates in the returned connections
  688. // For more info:
  689. // https://github.com/shirou/gopsutil/pull/361
  690. contents, err := ioutil.ReadFile(file)
  691. if err != nil {
  692. return nil, err
  693. }
  694. lines := bytes.Split(contents, []byte("\n"))
  695. var ret []connTmp
  696. // skip first line
  697. for _, line := range lines[1:] {
  698. l := strings.Fields(string(line))
  699. if len(l) < 10 {
  700. continue
  701. }
  702. laddr := l[1]
  703. raddr := l[2]
  704. status := l[3]
  705. inode := l[9]
  706. pid := int32(0)
  707. fd := uint32(0)
  708. i, exists := inodes[inode]
  709. if exists {
  710. pid = i[0].pid
  711. fd = i[0].fd
  712. }
  713. if filterPid > 0 && filterPid != pid {
  714. continue
  715. }
  716. if kind.sockType == syscall.SOCK_STREAM {
  717. status = tcpStatuses[status]
  718. } else {
  719. status = "NONE"
  720. }
  721. la, err := decodeAddressWithContext(ctx, kind.family, laddr)
  722. if err != nil {
  723. continue
  724. }
  725. ra, err := decodeAddressWithContext(ctx, kind.family, raddr)
  726. if err != nil {
  727. continue
  728. }
  729. ret = append(ret, connTmp{
  730. fd: fd,
  731. family: kind.family,
  732. sockType: kind.sockType,
  733. laddr: la,
  734. raddr: ra,
  735. status: status,
  736. pid: pid,
  737. })
  738. }
  739. return ret, nil
  740. }
  741. func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
  742. // Read the contents of the /proc file with a single read sys call.
  743. // This minimizes duplicates in the returned connections
  744. // For more info:
  745. // https://github.com/shirou/gopsutil/pull/361
  746. contents, err := ioutil.ReadFile(file)
  747. if err != nil {
  748. return nil, err
  749. }
  750. lines := bytes.Split(contents, []byte("\n"))
  751. var ret []connTmp
  752. // skip first line
  753. for _, line := range lines[1:] {
  754. tokens := strings.Fields(string(line))
  755. if len(tokens) < 6 {
  756. continue
  757. }
  758. st, err := strconv.Atoi(tokens[4])
  759. if err != nil {
  760. return nil, err
  761. }
  762. inode := tokens[6]
  763. var pairs []inodeMap
  764. pairs, exists := inodes[inode]
  765. if !exists {
  766. pairs = []inodeMap{
  767. {},
  768. }
  769. }
  770. for _, pair := range pairs {
  771. if filterPid > 0 && filterPid != pair.pid {
  772. continue
  773. }
  774. var path string
  775. if len(tokens) == 8 {
  776. path = tokens[len(tokens)-1]
  777. }
  778. ret = append(ret, connTmp{
  779. fd: pair.fd,
  780. family: kind.family,
  781. sockType: uint32(st),
  782. laddr: Addr{
  783. IP: path,
  784. },
  785. pid: pair.pid,
  786. status: "NONE",
  787. path: path,
  788. })
  789. }
  790. }
  791. return ret, nil
  792. }
  793. func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap {
  794. for key, value := range add {
  795. a, exists := src[key]
  796. if !exists {
  797. src[key] = value
  798. continue
  799. }
  800. src[key] = append(a, value...)
  801. }
  802. return src
  803. }