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