net_linux.go 22 KB

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