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