Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <sys/socket.h>
3 : : #include <linux/netlink.h>
4 : : #include <linux/rtnetlink.h>
5 : : #include <netinet/tcp.h>
6 : : #include <errno.h>
7 : : #include <linux/if.h>
8 : : #include <linux/filter.h>
9 : : #include <string.h>
10 : :
11 : : #include "libnetlink.h"
12 : : #include "sockets.h"
13 : : #include "unix_diag.h"
14 : : #include "inet_diag.h"
15 : : #include "packet_diag.h"
16 : : #include "files.h"
17 : : #include "util-net.h"
18 : : #include "sk-packet.h"
19 : : #include "namespaces.h"
20 : : #include "crtools.h"
21 : : #include "net.h"
22 : :
23 : : #ifndef NETLINK_SOCK_DIAG
24 : : #define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
25 : : #endif
26 : :
27 : : #ifndef SOCK_DIAG_BY_FAMILY
28 : : #define SOCK_DIAG_BY_FAMILY 20
29 : : #endif
30 : :
31 : : #ifndef SOCKFS_MAGIC
32 : : #define SOCKFS_MAGIC 0x534F434B
33 : : #endif
34 : :
35 : : #define SK_HASH_SIZE 32
36 : :
37 : : #ifndef SO_GET_FILTER
38 : : #define SO_GET_FILTER SO_ATTACH_FILTER
39 : : #endif
40 : :
41 : 99 : static int dump_bound_dev(int sk, SkOptsEntry *soe)
42 : : {
43 : : int ret;
44 : : char dev[IFNAMSIZ];
45 : 99 : socklen_t len = sizeof(dev);
46 : :
47 : 99 : ret = getsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE, &dev, &len);
48 [ - + ]: 99 : if (ret) {
49 [ # # ]: 0 : if (errno == ENOPROTOOPT) {
50 : 0 : pr_warn("Bound device may be missing for socket\n");
51 : : return 0;
52 : : }
53 : :
54 : 0 : pr_perror("Can't get bound dev");
55 : : return ret;
56 : : }
57 : :
58 [ + + ]: 99 : if (len == 0)
59 : : return 0;
60 : :
61 : 2 : pr_debug("\tDumping %s bound dev for sk\n", dev);
62 [ - + ]: 2 : soe->so_bound_dev = xmalloc(len);
63 : 99 : strcpy(soe->so_bound_dev, dev);
64 : : return 0;
65 : : }
66 : :
67 : 108 : static int restore_bound_dev(int sk, SkOptsEntry *soe)
68 : : {
69 : 108 : char *n = soe->so_bound_dev;
70 : :
71 [ + + ]: 108 : if (!n)
72 : : return 0;
73 : :
74 : 2 : pr_debug("\tBinding socket to %s dev\n", n);
75 : 108 : return do_restore_opt(sk, SOL_SOCKET, SO_BINDTODEVICE, n, strlen(n));
76 : : }
77 : :
78 : : /*
79 : : * Protobuf handles le/be himself, but the sock_filter is not just u64,
80 : : * it's a structure and we have to preserve the fields order to be able
81 : : * to move socket image across architectures.
82 : : */
83 : :
84 : 2 : static void encode_filter(struct sock_filter *f, uint64_t *img, int n)
85 : : {
86 : : int i;
87 : :
88 : : BUILD_BUG_ON(sizeof(*f) != sizeof(*img));
89 : :
90 [ + + ]: 30 : for (i = 0; i < n; i++)
91 : 84 : img[i] = ((uint64_t)f[i].code << 48) |
92 : 56 : ((uint64_t)f[i].jt << 40) |
93 : 56 : ((uint64_t)f[i].jf << 32) |
94 : 28 : ((uint64_t)f[i].k << 0);
95 : 2 : }
96 : :
97 : 2 : static void decode_filter(uint64_t *img, struct sock_filter *f, int n)
98 : : {
99 : : int i;
100 : :
101 [ + + ]: 30 : for (i = 0; i < n; i++) {
102 : 28 : f[i].code = img[i] >> 48;
103 : 28 : f[i].jt = img[i] >> 40;
104 : 28 : f[i].jf = img[i] >> 32;
105 : 28 : f[i].k = img[i] >> 0;
106 : : }
107 : 2 : }
108 : :
109 : 99 : static int dump_socket_filter(int sk, SkOptsEntry *soe)
110 : : {
111 : 99 : socklen_t len = 0;
112 : : int ret;
113 : : struct sock_filter *flt;
114 : :
115 : 99 : ret = getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, NULL, &len);
116 [ # # ][ - + ]: 99 : if (ret && errno != ENOPROTOOPT) {
117 : 0 : pr_perror("Can't get socket filter len");
118 : : return ret;
119 : : }
120 : :
121 [ + + ]: 99 : if (!len) {
122 : 97 : pr_info("No filter for socket\n");
123 : : return 0;
124 : : }
125 : :
126 [ - + ]: 2 : flt = xmalloc(len * sizeof(*flt));
127 [ + - ]: 2 : if (!flt)
128 : : return -1;
129 : :
130 : 2 : ret = getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, flt, &len);
131 [ - + ]: 2 : if (ret) {
132 : 0 : pr_perror("Can't get socket filter\n");
133 : : return ret;
134 : : }
135 : :
136 [ - + ]: 2 : soe->so_filter = xmalloc(len * sizeof(*soe->so_filter));
137 [ + - ]: 2 : if (!soe->so_filter)
138 : : return -1;
139 : :
140 : 2 : encode_filter(flt, soe->so_filter, len);
141 : 2 : soe->n_so_filter = len;
142 [ + - ]: 99 : xfree(flt);
143 : : return 0;
144 : : }
145 : :
146 : 108 : static int restore_socket_filter(int sk, SkOptsEntry *soe)
147 : : {
148 : : int ret;
149 : : struct sock_fprog sfp;
150 : :
151 [ + + ]: 108 : if (!soe->n_so_filter)
152 : : return 0;
153 : :
154 : 2 : pr_info("Restoring socket filter\n");
155 : 2 : sfp.len = soe->n_so_filter;
156 [ - + ]: 2 : sfp.filter = xmalloc(soe->n_so_filter * sfp.len);
157 [ + - ]: 2 : if (!sfp.filter)
158 : : return -1;
159 : :
160 : 2 : decode_filter(soe->so_filter, sfp.filter, sfp.len);
161 : 2 : ret = restore_opt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &sfp);
162 [ + - ]: 108 : xfree(sfp.filter);
163 : :
164 : : return ret;
165 : : }
166 : :
167 : : static struct socket_desc *sockets[SK_HASH_SIZE];
168 : :
169 : 142 : struct socket_desc *lookup_socket(int ino, int family)
170 : : {
171 : : struct socket_desc *sd;
172 : :
173 : 142 : pr_debug("\tSearching for socket %x (family %d)\n", ino, family);
174 [ + + ]: 400 : for (sd = sockets[ino % SK_HASH_SIZE]; sd; sd = sd->next)
175 [ + + ]: 258 : if (sd->ino == ino) {
176 [ - + ]: 134 : BUG_ON(sd->family != family);
177 : 134 : return sd;
178 : : }
179 : :
180 : : return NULL;
181 : : }
182 : :
183 : 7091 : int sk_collect_one(int ino, int family, struct socket_desc *d)
184 : : {
185 : : struct socket_desc **chain;
186 : :
187 : 7091 : d->ino = ino;
188 : 7091 : d->family = family;
189 : 7091 : d->already_dumped = 0;
190 : :
191 : 7091 : chain = &sockets[ino % SK_HASH_SIZE];
192 : 7091 : d->next = *chain;
193 : 7091 : *chain = d;
194 : :
195 : 7091 : return 0;
196 : : }
197 : :
198 : 974 : int do_restore_opt(int sk, int level, int name, void *val, int len)
199 : : {
200 [ - + ]: 974 : if (setsockopt(sk, level, name, val, len) < 0) {
201 : 0 : pr_perror("Can't set %d:%d (len %d)", level, name, len);
202 : 974 : return -1;
203 : : }
204 : :
205 : : return 0;
206 : : }
207 : :
208 : : /*
209 : : * Set sizes of buffers to maximum and prevent blocking
210 : : * Caller of this fn should call other socket restoring
211 : : * routines to drop the non-blocking and set proper send
212 : : * and receive buffers.
213 : : */
214 : 53 : int restore_prepare_socket(int sk)
215 : : {
216 : : int flags;
217 : :
218 : : /* In kernel a bufsize has type int and a value is doubled. */
219 : 53 : u32 maxbuf = INT_MAX / 2;
220 : :
221 [ + - ]: 53 : if (restore_opt(sk, SOL_SOCKET, SO_SNDBUFFORCE, &maxbuf))
222 : : return -1;
223 [ + - ]: 53 : if (restore_opt(sk, SOL_SOCKET, SO_RCVBUFFORCE, &maxbuf))
224 : : return -1;
225 : :
226 : : /* Prevent blocking on restore */
227 : 53 : flags = fcntl(sk, F_GETFL, 0);
228 [ - + ]: 53 : if (flags == -1) {
229 : 0 : pr_perror("Unable to get flags for %d", sk);
230 : : return -1;
231 : : }
232 [ - + ]: 53 : if (fcntl(sk, F_SETFL, flags | O_NONBLOCK) ) {
233 : 53 : pr_perror("Unable to set O_NONBLOCK for %d", sk);
234 : : return -1;
235 : : }
236 : :
237 : : return 0;
238 : : }
239 : :
240 : 108 : int restore_socket_opts(int sk, SkOptsEntry *soe)
241 : : {
242 : 108 : int ret = 0, val;
243 : : struct timeval tv;
244 : :
245 : 108 : pr_info("%d restore sndbuf %d rcv buf %d\n", sk, soe->so_sndbuf, soe->so_rcvbuf);
246 : 108 : ret |= restore_opt(sk, SOL_SOCKET, SO_SNDBUFFORCE, &soe->so_sndbuf);
247 : 108 : ret |= restore_opt(sk, SOL_SOCKET, SO_RCVBUFFORCE, &soe->so_rcvbuf);
248 [ + - ]: 108 : if (soe->has_so_priority) {
249 : 108 : pr_debug("\trestore priority %d for socket\n", soe->so_priority);
250 : 108 : ret |= restore_opt(sk, SOL_SOCKET, SO_PRIORITY, &soe->so_priority);
251 : : }
252 [ + - ]: 108 : if (soe->has_so_rcvlowat) {
253 : 108 : pr_debug("\trestore rcvlowat %d for socket\n", soe->so_rcvlowat);
254 : 108 : ret |= restore_opt(sk, SOL_SOCKET, SO_RCVLOWAT, &soe->so_rcvlowat);
255 : : }
256 [ + - ]: 108 : if (soe->has_so_mark) {
257 : 108 : pr_debug("\trestore mark %d for socket\n", soe->so_mark);
258 : 108 : ret |= restore_opt(sk, SOL_SOCKET, SO_MARK, &soe->so_mark);
259 : : }
260 [ + - ][ + + ]: 108 : if (soe->has_so_passcred && soe->so_passcred) {
261 : 2 : val = 1;
262 : 2 : pr_debug("\tset passcred for socket\n");
263 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_PASSCRED, &val);
264 : : }
265 [ + - ][ + + ]: 108 : if (soe->has_so_passsec && soe->so_passsec) {
266 : 2 : val = 1;
267 : 2 : pr_debug("\tset passsec for socket\n");
268 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_PASSSEC, &val);
269 : : }
270 [ + - ][ + + ]: 108 : if (soe->has_so_dontroute && soe->so_dontroute) {
271 : 2 : val = 1;
272 : 2 : pr_debug("\tset dontroute for socket\n");
273 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_DONTROUTE, &val);
274 : : }
275 [ + - ][ + + ]: 108 : if (soe->has_so_no_check && soe->so_no_check) {
276 : 2 : val = 1;
277 : 2 : pr_debug("\tset no_check for socket\n");
278 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_NO_CHECK, &val);
279 : : }
280 : :
281 : 108 : tv.tv_sec = soe->so_snd_tmo_sec;
282 : 108 : tv.tv_usec = soe->so_snd_tmo_usec;
283 : 108 : ret |= restore_opt(sk, SOL_SOCKET, SO_SNDTIMEO, &tv);
284 : :
285 : 108 : tv.tv_sec = soe->so_rcv_tmo_sec;
286 : 108 : tv.tv_usec = soe->so_rcv_tmo_usec;
287 : 108 : ret |= restore_opt(sk, SOL_SOCKET, SO_RCVTIMEO, &tv);
288 : :
289 : 108 : ret |= restore_bound_dev(sk, soe);
290 : 108 : ret |= restore_socket_filter(sk, soe);
291 : :
292 : : /* The restore of SO_REUSEADDR depends on type of socket */
293 : :
294 : 108 : return ret;
295 : : }
296 : :
297 : 1332 : int do_dump_opt(int sk, int level, int name, void *val, int len)
298 : : {
299 : 1332 : socklen_t aux = len;
300 : :
301 [ - + ]: 1332 : if (getsockopt(sk, level, name, val, &aux) < 0) {
302 : 0 : pr_perror("Can't get %d:%d opt", level, name);
303 : : return -1;
304 : : }
305 : :
306 [ - + ]: 1332 : if (aux != len) {
307 : 1332 : pr_err("Len mismatch on %d:%d : %d, want %d\n",
308 : : level, name, aux, len);
309 : : return -1;
310 : : }
311 : :
312 : : return 0;
313 : : }
314 : :
315 : 99 : int dump_socket_opts(int sk, SkOptsEntry *soe)
316 : : {
317 : 99 : int ret = 0, val;
318 : : struct timeval tv;
319 : :
320 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_SNDBUF, &soe->so_sndbuf);
321 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_RCVBUF, &soe->so_rcvbuf);
322 : 99 : soe->has_so_priority = true;
323 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_PRIORITY, &soe->so_priority);
324 : 99 : soe->has_so_rcvlowat = true;
325 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_RCVLOWAT, &soe->so_rcvlowat);
326 : 99 : soe->has_so_mark = true;
327 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_MARK, &soe->so_mark);
328 : :
329 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_SNDTIMEO, &tv);
330 : 99 : soe->so_snd_tmo_sec = tv.tv_sec;
331 : 99 : soe->so_snd_tmo_usec = tv.tv_usec;
332 : :
333 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_RCVTIMEO, &tv);
334 : 99 : soe->so_rcv_tmo_sec = tv.tv_sec;
335 : 99 : soe->so_rcv_tmo_usec = tv.tv_usec;
336 : :
337 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_REUSEADDR, &val);
338 : 99 : soe->reuseaddr = val ? true : false;
339 : 99 : soe->has_reuseaddr = true;
340 : :
341 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_PASSCRED, &val);
342 : 99 : soe->has_so_passcred = true;
343 : 99 : soe->so_passcred = val ? true : false;
344 : :
345 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_PASSSEC, &val);
346 : 99 : soe->has_so_passsec = true;
347 : 99 : soe->so_passsec = val ? true : false;
348 : :
349 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_DONTROUTE, &val);
350 : 99 : soe->has_so_dontroute = true;
351 : 99 : soe->so_dontroute = val ? true : false;
352 : :
353 : 99 : ret |= dump_opt(sk, SOL_SOCKET, SO_NO_CHECK, &val);
354 : 99 : soe->has_so_no_check = true;
355 : 99 : soe->so_no_check = val ? true : false;
356 : :
357 : 99 : ret |= dump_bound_dev(sk, soe);
358 : 99 : ret |= dump_socket_filter(sk, soe);
359 : :
360 : 99 : return ret;
361 : : }
362 : :
363 : 99 : void release_skopts(SkOptsEntry *soe)
364 : : {
365 [ + + ]: 99 : xfree(soe->so_filter);
366 [ + + ]: 99 : xfree(soe->so_bound_dev);
367 : 99 : }
368 : :
369 : 99 : int dump_socket(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset)
370 : : {
371 : : int family;
372 : :
373 [ + - ]: 99 : if (dump_opt(lfd, SOL_SOCKET, SO_DOMAIN, &family))
374 : : return -1;
375 : :
376 [ + + + + : 99 : switch (family) {
- ]
377 : : case AF_UNIX:
378 : 57 : return dump_one_unix(p, lfd, cr_fdset);
379 : : case AF_INET:
380 : 25 : return dump_one_inet(p, lfd, cr_fdset);
381 : : case AF_INET6:
382 : 13 : return dump_one_inet6(p, lfd, cr_fdset);
383 : : case AF_PACKET:
384 : 4 : return dump_one_packet_sk(p, lfd, cr_fdset);
385 : : default:
386 : 99 : pr_err("BUG! Unknown socket collected\n");
387 : : break;
388 : : }
389 : :
390 : : return -1;
391 : : }
392 : :
393 : 2040 : static int inet_receive_one(struct nlmsghdr *h, void *arg)
394 : : {
395 : 2040 : struct inet_diag_req_v2 *i = arg;
396 : : int type;
397 : :
398 [ + - + ]: 2040 : switch (i->sdiag_protocol) {
399 : : case IPPROTO_TCP:
400 : : type = SOCK_STREAM;
401 : : break;
402 : : case IPPROTO_UDP:
403 : : case IPPROTO_UDPLITE:
404 : 1104 : type = SOCK_DGRAM;
405 : 1104 : break;
406 : : default:
407 : 0 : BUG_ON(1);
408 : 0 : return -1;
409 : : }
410 : :
411 : 2040 : return inet_collect_one(h, i->sdiag_family, type, i->sdiag_protocol);
412 : : }
413 : :
414 : 167 : int collect_sockets(int pid)
415 : : {
416 : 167 : int err = 0, tmp;
417 : 167 : int rst = -1;
418 : : int nl;
419 : : struct {
420 : : struct nlmsghdr hdr;
421 : : union {
422 : : struct unix_diag_req u;
423 : : struct inet_diag_req_v2 i;
424 : : struct packet_diag_req p;
425 : : } r;
426 : : } req;
427 : :
428 [ + + ]: 167 : if (opts.namespaces_flags & CLONE_NEWNET) {
429 : 76 : pr_info("Switching to %d's net for collecting sockets\n", pid);
430 : :
431 [ + - ]: 76 : if (switch_ns(pid, CLONE_NEWNET, "net", &rst))
432 : : return -1;
433 : : }
434 : :
435 : 167 : nl = socket(PF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
436 [ - + ]: 167 : if (nl < 0) {
437 : 0 : pr_perror("Can't create sock diag socket");
438 : 0 : err = -1;
439 : 0 : goto out;
440 : : }
441 : :
442 : 167 : memset(&req, 0, sizeof(req));
443 : 167 : req.hdr.nlmsg_len = sizeof(req);
444 : 167 : req.hdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
445 : 167 : req.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
446 : 167 : req.hdr.nlmsg_seq = CR_NLMSG_SEQ;
447 : :
448 : : /* Collect UNIX sockets */
449 : 167 : req.r.u.sdiag_family = AF_UNIX;
450 : 167 : req.r.u.udiag_states = -1; /* All */
451 : 167 : req.r.u.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_VFS |
452 : : UDIAG_SHOW_PEER | UDIAG_SHOW_ICONS |
453 : : UDIAG_SHOW_RQLEN;
454 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), unix_receive_one, NULL);
455 [ - + ]: 167 : if (tmp)
456 : 0 : err = tmp;
457 : :
458 : : /* Collect IPv4 TCP sockets */
459 : 167 : req.r.i.sdiag_family = AF_INET;
460 : 167 : req.r.i.sdiag_protocol = IPPROTO_TCP;
461 : 167 : req.r.i.idiag_ext = 0;
462 : : /* Only listening and established sockets supported yet */
463 : 167 : req.r.i.idiag_states = (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
464 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
465 [ - + ]: 167 : if (tmp)
466 : 0 : err = tmp;
467 : :
468 : : /* Collect IPv4 UDP sockets */
469 : 167 : req.r.i.sdiag_family = AF_INET;
470 : 167 : req.r.i.sdiag_protocol = IPPROTO_UDP;
471 : 167 : req.r.i.idiag_ext = 0;
472 : 167 : req.r.i.idiag_states = -1; /* All */
473 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
474 [ - + ]: 167 : if (tmp)
475 : 0 : err = tmp;
476 : :
477 : : /* Collect IPv4 UDP-lite sockets */
478 : 167 : req.r.i.sdiag_family = AF_INET;
479 : 167 : req.r.i.sdiag_protocol = IPPROTO_UDPLITE;
480 : 167 : req.r.i.idiag_ext = 0;
481 : 167 : req.r.i.idiag_states = -1; /* All */
482 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
483 [ - + ]: 167 : if (tmp)
484 : 0 : err = tmp;
485 : :
486 : : /* Collect IPv6 TCP sockets */
487 : 167 : req.r.i.sdiag_family = AF_INET6;
488 : 167 : req.r.i.sdiag_protocol = IPPROTO_TCP;
489 : 167 : req.r.i.idiag_ext = 0;
490 : : /* Only listening sockets supported yet */
491 : 167 : req.r.i.idiag_states = (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
492 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
493 [ - + ]: 167 : if (tmp)
494 : 0 : err = tmp;
495 : :
496 : : /* Collect IPv6 UDP sockets */
497 : 167 : req.r.i.sdiag_family = AF_INET6;
498 : 167 : req.r.i.sdiag_protocol = IPPROTO_UDP;
499 : 167 : req.r.i.idiag_ext = 0;
500 : 167 : req.r.i.idiag_states = -1; /* All */
501 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
502 [ - + ]: 167 : if (tmp)
503 : 0 : err = tmp;
504 : :
505 : : /* Collect IPv6 UDP-lite sockets */
506 : 167 : req.r.i.sdiag_family = AF_INET6;
507 : 167 : req.r.i.sdiag_protocol = IPPROTO_UDPLITE;
508 : 167 : req.r.i.idiag_ext = 0;
509 : 167 : req.r.i.idiag_states = -1; /* All */
510 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
511 [ - + ]: 167 : if (tmp)
512 : 0 : err = tmp;
513 : :
514 : 167 : req.r.p.sdiag_family = AF_PACKET;
515 : 167 : req.r.p.sdiag_protocol = 0;
516 : 167 : req.r.p.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MCLIST |
517 : : PACKET_SHOW_FANOUT | PACKET_SHOW_RING_CFG;
518 : 167 : tmp = do_rtnl_req(nl, &req, sizeof(req), packet_receive_one, NULL);
519 [ - + ]: 167 : if (tmp)
520 : 0 : err = tmp;
521 : :
522 : 167 : close(nl);
523 : : out:
524 [ + + ][ - + ]: 167 : if (rst > 0 && restore_ns(rst, CLONE_NEWNET) < 0)
525 : 167 : err = -1;
526 : : return err;
527 : : }
528 : :
529 : 0 : static inline char *unknown(u32 val)
530 : : {
531 : : static char unk[12];
532 : 0 : snprintf(unk, sizeof(unk), "x%d", val);
533 : 0 : return unk;
534 : : }
535 : :
536 : 0 : char *skfamily2s(u32 f)
537 : : {
538 [ # # ]: 0 : if (f == AF_INET)
539 : : return " inet";
540 [ # # ]: 0 : else if (f == AF_INET6)
541 : : return "inet6";
542 : : else
543 : 0 : return unknown(f);
544 : : }
545 : :
546 : 0 : char *sktype2s(u32 t)
547 : : {
548 [ # # ]: 0 : if (t == SOCK_STREAM)
549 : : return "stream";
550 [ # # ]: 0 : else if (t == SOCK_DGRAM)
551 : : return " dgram";
552 : : else
553 : 0 : return unknown(t);
554 : : }
555 : :
556 : 0 : char *skproto2s(u32 p)
557 : : {
558 [ # # ]: 0 : if (p == IPPROTO_UDP)
559 : : return "udp";
560 [ # # ]: 0 : else if (p == IPPROTO_UDPLITE)
561 : : return "udpl";
562 [ # # ]: 0 : else if (p == IPPROTO_TCP)
563 : : return "tcp";
564 : : else
565 : 0 : return unknown(p);
566 : : }
567 : :
568 : 0 : char *skstate2s(u32 state)
569 : : {
570 [ # # ]: 0 : if (state == TCP_ESTABLISHED)
571 : : return " estab";
572 [ # # ]: 0 : else if (state == TCP_CLOSE)
573 : : return "closed";
574 [ # # ]: 0 : else if (state == TCP_LISTEN)
575 : : return "listen";
576 : : else
577 : 0 : return unknown(state);
578 : 621 : }
|