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 "netlink_diag.h"
17 : : #include "files.h"
18 : : #include "util-pie.h"
19 : : #include "sk-packet.h"
20 : : #include "namespaces.h"
21 : : #include "net.h"
22 : : #include "fs-magic.h"
23 : :
24 : : #ifndef NETLINK_SOCK_DIAG
25 : : #define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
26 : : #endif
27 : :
28 : : #ifndef SOCK_DIAG_BY_FAMILY
29 : : #define SOCK_DIAG_BY_FAMILY 20
30 : : #endif
31 : :
32 : : #define SK_HASH_SIZE 32
33 : :
34 : : #ifndef SO_GET_FILTER
35 : : #define SO_GET_FILTER SO_ATTACH_FILTER
36 : : #endif
37 : :
38 : : enum socket_cl_bits
39 : : {
40 : : NETLINK_CL_BIT,
41 : : INET_TCP_CL_BIT,
42 : : INET_UDP_CL_BIT,
43 : : INET_UDPLITE_CL_BIT,
44 : : INET6_TCP_CL_BIT,
45 : : INET6_UDP_CL_BIT,
46 : : INET6_UDPLITE_CL_BIT,
47 : : UNIX_CL_BIT,
48 : : PACKET_CL_BIT,
49 : : _MAX_CL_BIT,
50 : : };
51 : :
52 : : #define MAX_CL_BIT (_MAX_CL_BIT - 1)
53 : :
54 : : static DECLARE_BITMAP(socket_cl_bits, MAX_CL_BIT);
55 : :
56 : : static inline
57 : 4364 : enum socket_cl_bits get_collect_bit_nr(unsigned int family, unsigned int proto)
58 : : {
59 [ + + ]: 4364 : if (family == AF_NETLINK)
60 : : return NETLINK_CL_BIT;
61 [ + + ]: 3898 : if (family == AF_UNIX)
62 : : return UNIX_CL_BIT;
63 [ + + ]: 3244 : if (family == AF_PACKET)
64 : : return PACKET_CL_BIT;
65 [ + + ]: 2786 : if (family == AF_INET) {
66 [ + + ]: 1410 : if (proto == IPPROTO_TCP)
67 : : return INET_TCP_CL_BIT;
68 [ + + ]: 920 : if (proto == IPPROTO_UDP)
69 : : return INET_UDP_CL_BIT;
70 [ - + ]: 458 : if (proto == IPPROTO_UDPLITE)
71 : : return INET_UDPLITE_CL_BIT;
72 : : }
73 [ + - ]: 1376 : if (family == AF_INET6) {
74 [ + + ]: 1376 : if (proto == IPPROTO_TCP)
75 : : return INET6_TCP_CL_BIT;
76 [ + + ]: 908 : if (proto == IPPROTO_UDP)
77 : : return INET6_UDP_CL_BIT;
78 [ - + ]: 450 : if (proto == IPPROTO_UDPLITE)
79 : : return INET6_UDPLITE_CL_BIT;
80 : : }
81 : :
82 : 0 : pr_err("Unknown pair family %d proto %d\n", family, proto);
83 : 0 : BUG();
84 : 0 : return -1;
85 : : }
86 : :
87 : : static void set_collect_bit(unsigned int family, unsigned int proto)
88 : : {
89 : : enum socket_cl_bits nr;
90 : :
91 : 4050 : nr = get_collect_bit_nr(family, proto);
92 : 4050 : set_bit(nr, socket_cl_bits);
93 : : }
94 : :
95 : 0 : bool socket_test_collect_bit(unsigned int family, unsigned int proto)
96 : : {
97 : : enum socket_cl_bits nr;
98 : :
99 : 314 : nr = get_collect_bit_nr(family, proto);
100 : 314 : return test_bit(nr, socket_cl_bits) != 0;
101 : : }
102 : :
103 : 228 : static int dump_bound_dev(int sk, SkOptsEntry *soe)
104 : : {
105 : : int ret;
106 : : char dev[IFNAMSIZ];
107 : 228 : socklen_t len = sizeof(dev);
108 : :
109 : 228 : ret = getsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE, &dev, &len);
110 [ - + ]: 228 : if (ret) {
111 : 0 : pr_perror("Can't get bound dev");
112 : : return ret;
113 : : }
114 : :
115 [ + + ]: 228 : if (len == 0)
116 : : return 0;
117 : :
118 : 4 : pr_debug("\tDumping %s bound dev for sk\n", dev);
119 [ - + ]: 4 : soe->so_bound_dev = xmalloc(len);
120 [ + - ]: 4 : if (soe->so_bound_dev == NULL)
121 : : return -1;
122 : : strcpy(soe->so_bound_dev, dev);
123 : : return 0;
124 : : }
125 : :
126 : 144 : static int restore_bound_dev(int sk, SkOptsEntry *soe)
127 : : {
128 : 144 : char *n = soe->so_bound_dev;
129 : :
130 [ + + ]: 144 : if (!n)
131 : : return 0;
132 : :
133 : 2 : pr_debug("\tBinding socket to %s dev\n", n);
134 : 2 : return do_restore_opt(sk, SOL_SOCKET, SO_BINDTODEVICE, n, strlen(n));
135 : : }
136 : :
137 : : /*
138 : : * Protobuf handles le/be himself, but the sock_filter is not just u64,
139 : : * it's a structure and we have to preserve the fields order to be able
140 : : * to move socket image across architectures.
141 : : */
142 : :
143 : 4 : static void encode_filter(struct sock_filter *f, u64 *img, int n)
144 : : {
145 : : int i;
146 : :
147 : : BUILD_BUG_ON(sizeof(*f) != sizeof(*img));
148 : :
149 [ + + ]: 60 : for (i = 0; i < n; i++)
150 : 168 : img[i] = ((u64)f[i].code << 48) |
151 : 112 : ((u64)f[i].jt << 40) |
152 : 112 : ((u64)f[i].jf << 32) |
153 : 56 : ((u64)f[i].k << 0);
154 : 4 : }
155 : :
156 : 2 : static void decode_filter(u64 *img, struct sock_filter *f, int n)
157 : : {
158 : : int i;
159 : :
160 [ + + ]: 30 : for (i = 0; i < n; i++) {
161 : 28 : f[i].code = img[i] >> 48;
162 : 28 : f[i].jt = img[i] >> 40;
163 : 28 : f[i].jf = img[i] >> 32;
164 : 28 : f[i].k = img[i] >> 0;
165 : : }
166 : 2 : }
167 : :
168 : 456 : static int dump_socket_filter(int sk, SkOptsEntry *soe)
169 : : {
170 : 228 : socklen_t len = 0;
171 : : int ret;
172 : : struct sock_filter *flt;
173 : :
174 : 228 : ret = getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, NULL, &len);
175 [ - + ]: 228 : if (ret) {
176 : 0 : pr_perror("Can't get socket filter len");
177 : : return ret;
178 : : }
179 : :
180 [ + + ]: 228 : if (!len) {
181 : 224 : pr_info("No filter for socket\n");
182 : : return 0;
183 : : }
184 : :
185 [ - + ]: 4 : flt = xmalloc(len * sizeof(*flt));
186 [ + - ]: 4 : if (!flt)
187 : : return -1;
188 : :
189 : 4 : ret = getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, flt, &len);
190 [ - + ]: 4 : if (ret) {
191 : 0 : pr_perror("Can't get socket filter");
192 [ # # ]: 0 : xfree(flt);
193 : : return ret;
194 : : }
195 : :
196 [ - + ]: 4 : soe->so_filter = xmalloc(len * sizeof(*soe->so_filter));
197 [ - + ]: 4 : if (!soe->so_filter) {
198 [ # # ]: 0 : xfree(flt);
199 : : return -1;
200 : : }
201 : :
202 : 4 : encode_filter(flt, soe->so_filter, len);
203 : 4 : soe->n_so_filter = len;
204 [ + - ]: 4 : xfree(flt);
205 : : return 0;
206 : : }
207 : :
208 : 288 : static int restore_socket_filter(int sk, SkOptsEntry *soe)
209 : : {
210 : : int ret;
211 : : struct sock_fprog sfp;
212 : :
213 [ + + ]: 144 : if (!soe->n_so_filter)
214 : : return 0;
215 : :
216 : 2 : pr_info("Restoring socket filter\n");
217 : 2 : sfp.len = soe->n_so_filter;
218 [ - + ]: 2 : sfp.filter = xmalloc(soe->n_so_filter * sfp.len);
219 [ + - ]: 2 : if (!sfp.filter)
220 : : return -1;
221 : :
222 : 2 : decode_filter(soe->so_filter, sfp.filter, sfp.len);
223 : 2 : ret = restore_opt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &sfp);
224 [ + - ]: 2 : xfree(sfp.filter);
225 : :
226 : : return ret;
227 : : }
228 : :
229 : : static struct socket_desc *sockets[SK_HASH_SIZE];
230 : :
231 : 314 : struct socket_desc *lookup_socket(int ino, int family, int proto)
232 : : {
233 : : struct socket_desc *sd;
234 : :
235 [ - + ]: 314 : if (!socket_test_collect_bit(family, proto)) {
236 : 0 : pr_err("Sockets (family %d, proto %d) are not collected\n",
237 : : family, proto);
238 : 0 : return ERR_PTR(-EINVAL);
239 : : }
240 : :
241 : 314 : pr_debug("\tSearching for socket %x (family %d)\n", ino, family);
242 [ + + ]: 2375 : for (sd = sockets[ino % SK_HASH_SIZE]; sd; sd = sd->next)
243 [ + + ]: 2355 : if (sd->ino == ino) {
244 [ - + ]: 294 : BUG_ON(sd->family != family);
245 : 294 : return sd;
246 : : }
247 : :
248 : : return NULL;
249 : : }
250 : :
251 : 173166 : int sk_collect_one(int ino, int family, struct socket_desc *d)
252 : : {
253 : : struct socket_desc **chain;
254 : :
255 : 173166 : d->ino = ino;
256 : 173166 : d->family = family;
257 : 173166 : d->already_dumped = 0;
258 : :
259 : 173166 : chain = &sockets[ino % SK_HASH_SIZE];
260 : 173166 : d->next = *chain;
261 : 173166 : *chain = d;
262 : :
263 : 173166 : return 0;
264 : : }
265 : :
266 : 1280 : int do_restore_opt(int sk, int level, int name, void *val, int len)
267 : : {
268 [ - + ]: 1280 : if (setsockopt(sk, level, name, val, len) < 0) {
269 : 0 : pr_perror("Can't set %d:%d (len %d)", level, name, len);
270 : 0 : return -1;
271 : : }
272 : :
273 : : return 0;
274 : : }
275 : :
276 : : /*
277 : : * Set sizes of buffers to maximum and prevent blocking
278 : : * Caller of this fn should call other socket restoring
279 : : * routines to drop the non-blocking and set proper send
280 : : * and receive buffers.
281 : : */
282 : 72 : int restore_prepare_socket(int sk)
283 : : {
284 : : int flags;
285 : :
286 : : /* In kernel a bufsize has type int and a value is doubled. */
287 : 72 : u32 maxbuf = INT_MAX / 2;
288 : :
289 [ + - ]: 72 : if (restore_opt(sk, SOL_SOCKET, SO_SNDBUFFORCE, &maxbuf))
290 : : return -1;
291 [ + - ]: 72 : if (restore_opt(sk, SOL_SOCKET, SO_RCVBUFFORCE, &maxbuf))
292 : : return -1;
293 : :
294 : : /* Prevent blocking on restore */
295 : 72 : flags = fcntl(sk, F_GETFL, 0);
296 [ - + ]: 72 : if (flags == -1) {
297 : 0 : pr_perror("Unable to get flags for %d", sk);
298 : 0 : return -1;
299 : : }
300 [ - + ]: 72 : if (fcntl(sk, F_SETFL, flags | O_NONBLOCK) ) {
301 : 0 : pr_perror("Unable to set O_NONBLOCK for %d", sk);
302 : 0 : return -1;
303 : : }
304 : :
305 : : return 0;
306 : : }
307 : :
308 : 144 : int restore_socket_opts(int sk, SkOptsEntry *soe)
309 : : {
310 : : int ret = 0, val;
311 : : struct timeval tv;
312 : :
313 : 144 : pr_info("%d restore sndbuf %d rcv buf %d\n", sk, soe->so_sndbuf, soe->so_rcvbuf);
314 : :
315 : : /* setsockopt() multiplies the input values by 2 */
316 : 144 : val = soe->so_sndbuf / 2;
317 : 144 : ret |= restore_opt(sk, SOL_SOCKET, SO_SNDBUFFORCE, &val);
318 : 144 : val = soe->so_rcvbuf / 2;
319 : 144 : ret |= restore_opt(sk, SOL_SOCKET, SO_RCVBUFFORCE, &val);
320 : :
321 [ + - ]: 144 : if (soe->has_so_priority) {
322 : 144 : pr_debug("\trestore priority %d for socket\n", soe->so_priority);
323 : 144 : ret |= restore_opt(sk, SOL_SOCKET, SO_PRIORITY, &soe->so_priority);
324 : : }
325 [ + - ]: 144 : if (soe->has_so_rcvlowat) {
326 : 144 : pr_debug("\trestore rcvlowat %d for socket\n", soe->so_rcvlowat);
327 : 144 : ret |= restore_opt(sk, SOL_SOCKET, SO_RCVLOWAT, &soe->so_rcvlowat);
328 : : }
329 [ + - ]: 144 : if (soe->has_so_mark) {
330 : 144 : pr_debug("\trestore mark %d for socket\n", soe->so_mark);
331 : 144 : ret |= restore_opt(sk, SOL_SOCKET, SO_MARK, &soe->so_mark);
332 : : }
333 [ + - ][ + + ]: 144 : if (soe->has_so_passcred && soe->so_passcred) {
334 : 2 : val = 1;
335 : 2 : pr_debug("\tset passcred for socket\n");
336 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_PASSCRED, &val);
337 : : }
338 [ + - ][ + + ]: 144 : if (soe->has_so_passsec && soe->so_passsec) {
339 : 2 : val = 1;
340 : 2 : pr_debug("\tset passsec for socket\n");
341 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_PASSSEC, &val);
342 : : }
343 [ + - ][ + + ]: 144 : if (soe->has_so_dontroute && soe->so_dontroute) {
344 : 2 : val = 1;
345 : 2 : pr_debug("\tset dontroute for socket\n");
346 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_DONTROUTE, &val);
347 : : }
348 [ + - ][ + + ]: 144 : if (soe->has_so_no_check && soe->so_no_check) {
349 : 2 : val = 1;
350 : 2 : pr_debug("\tset no_check for socket\n");
351 : 2 : ret |= restore_opt(sk, SOL_SOCKET, SO_NO_CHECK, &val);
352 : : }
353 : :
354 : 144 : tv.tv_sec = soe->so_snd_tmo_sec;
355 : 144 : tv.tv_usec = soe->so_snd_tmo_usec;
356 : 144 : ret |= restore_opt(sk, SOL_SOCKET, SO_SNDTIMEO, &tv);
357 : :
358 : 144 : tv.tv_sec = soe->so_rcv_tmo_sec;
359 : 144 : tv.tv_usec = soe->so_rcv_tmo_usec;
360 : 144 : ret |= restore_opt(sk, SOL_SOCKET, SO_RCVTIMEO, &tv);
361 : :
362 : 144 : ret |= restore_bound_dev(sk, soe);
363 : 144 : ret |= restore_socket_filter(sk, soe);
364 : :
365 : : /* The restore of SO_REUSEADDR depends on type of socket */
366 : :
367 : 144 : return ret;
368 : : }
369 : :
370 : 3180 : int do_dump_opt(int sk, int level, int name, void *val, int len)
371 : : {
372 : 3180 : socklen_t aux = len;
373 : :
374 [ - + ]: 3180 : if (getsockopt(sk, level, name, val, &aux) < 0) {
375 : 0 : pr_perror("Can't get %d:%d opt", level, name);
376 : 0 : return -1;
377 : : }
378 : :
379 [ - + ]: 3180 : if (aux != len) {
380 : 0 : pr_err("Len mismatch on %d:%d : %d, want %d\n",
381 : : level, name, aux, len);
382 : 0 : return -1;
383 : : }
384 : :
385 : : return 0;
386 : : }
387 : :
388 : 228 : int dump_socket_opts(int sk, SkOptsEntry *soe)
389 : : {
390 : : int ret = 0, val;
391 : : struct timeval tv;
392 : :
393 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_SNDBUF, &soe->so_sndbuf);
394 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_RCVBUF, &soe->so_rcvbuf);
395 : 228 : soe->has_so_priority = true;
396 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_PRIORITY, &soe->so_priority);
397 : 228 : soe->has_so_rcvlowat = true;
398 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_RCVLOWAT, &soe->so_rcvlowat);
399 : 228 : soe->has_so_mark = true;
400 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_MARK, &soe->so_mark);
401 : :
402 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_SNDTIMEO, &tv);
403 : 228 : soe->so_snd_tmo_sec = tv.tv_sec;
404 : 228 : soe->so_snd_tmo_usec = tv.tv_usec;
405 : :
406 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_RCVTIMEO, &tv);
407 : 228 : soe->so_rcv_tmo_sec = tv.tv_sec;
408 : 228 : soe->so_rcv_tmo_usec = tv.tv_usec;
409 : :
410 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_REUSEADDR, &val);
411 : 228 : soe->reuseaddr = val ? true : false;
412 : 228 : soe->has_reuseaddr = true;
413 : :
414 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_PASSCRED, &val);
415 : 228 : soe->has_so_passcred = true;
416 : 228 : soe->so_passcred = val ? true : false;
417 : :
418 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_PASSSEC, &val);
419 : 228 : soe->has_so_passsec = true;
420 : 228 : soe->so_passsec = val ? true : false;
421 : :
422 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_DONTROUTE, &val);
423 : 228 : soe->has_so_dontroute = true;
424 : 228 : soe->so_dontroute = val ? true : false;
425 : :
426 : 228 : ret |= dump_opt(sk, SOL_SOCKET, SO_NO_CHECK, &val);
427 : 228 : soe->has_so_no_check = true;
428 : 228 : soe->so_no_check = val ? true : false;
429 : :
430 : 228 : ret |= dump_bound_dev(sk, soe);
431 : 228 : ret |= dump_socket_filter(sk, soe);
432 : :
433 : 228 : return ret;
434 : : }
435 : :
436 : 212 : void release_skopts(SkOptsEntry *soe)
437 : : {
438 [ + + ]: 212 : xfree(soe->so_filter);
439 [ + + ]: 212 : xfree(soe->so_bound_dev);
440 : 212 : }
441 : :
442 : 228 : int dump_socket(struct fd_parms *p, int lfd, const int fdinfo)
443 : : {
444 : : int family;
445 : : const struct fdtype_ops *ops;
446 : :
447 [ + - ]: 228 : if (dump_opt(lfd, SOL_SOCKET, SO_DOMAIN, &family))
448 : : return -1;
449 : :
450 [ + + + + : 228 : switch (family) {
- + ]
451 : : case AF_UNIX:
452 : : ops = &unix_dump_ops;
453 : : break;
454 : : case AF_INET:
455 : : ops = &inet_dump_ops;
456 : 60 : break;
457 : : case AF_INET6:
458 : : ops = &inet6_dump_ops;
459 : 26 : break;
460 : : case AF_PACKET:
461 : : ops = &packet_dump_ops;
462 : 8 : break;
463 : : case AF_NETLINK:
464 : : ops = &netlink_dump_ops;
465 : 16 : break;
466 : : default:
467 : 0 : pr_err("BUG! Unknown socket collected (family %d)\n", family);
468 : 0 : return -1;
469 : : }
470 : :
471 : 228 : return do_dump_gen_file(p, lfd, ops, fdinfo);
472 : : }
473 : :
474 : 21028 : static int inet_receive_one(struct nlmsghdr *h, void *arg)
475 : : {
476 : : struct inet_diag_req_v2 *i = arg;
477 : : int type;
478 : :
479 [ + - + ]: 21028 : switch (i->sdiag_protocol) {
480 : : case IPPROTO_TCP:
481 : : type = SOCK_STREAM;
482 : : break;
483 : : case IPPROTO_UDP:
484 : : case IPPROTO_UDPLITE:
485 : : type = SOCK_DGRAM;
486 : 10915 : break;
487 : : default:
488 : 0 : BUG_ON(1);
489 : 0 : return -1;
490 : : }
491 : :
492 : 21028 : return inet_collect_one(h, i->sdiag_family, type);
493 : : }
494 : :
495 : : struct sock_diag_req {
496 : : struct nlmsghdr hdr;
497 : : union {
498 : : struct unix_diag_req u;
499 : : struct inet_diag_req_v2 i;
500 : : struct packet_diag_req p;
501 : : struct netlink_diag_req n;
502 : : } r;
503 : : };
504 : :
505 : 4050 : static int do_collect_req(int nl, struct sock_diag_req *req, int size,
506 : : int (*receive_callback)(struct nlmsghdr *h, void *), void *arg)
507 : : {
508 : : int tmp;
509 : :
510 : 4050 : tmp = do_rtnl_req(nl, req, size, receive_callback, arg);
511 : :
512 [ + - ]: 4050 : if (tmp == 0)
513 : 4050 : set_collect_bit(req->r.n.sdiag_family, req->r.n.sdiag_protocol);
514 : :
515 : 4050 : return tmp;
516 : : }
517 : :
518 : 450 : int collect_sockets(int pid)
519 : : {
520 : : int err = 0, tmp;
521 : 450 : int rst = -1;
522 : : int nl;
523 : : struct sock_diag_req req;
524 : :
525 [ + + ]: 450 : if (root_ns_mask & CLONE_NEWNET) {
526 : 214 : pr_info("Switching to %d's net for collecting sockets\n", pid);
527 : :
528 [ + - ]: 214 : if (switch_ns(pid, &net_ns_desc, &rst))
529 : : return -1;
530 : : }
531 : :
532 : 450 : nl = socket(PF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
533 [ - + ]: 450 : if (nl < 0) {
534 : 0 : pr_perror("Can't create sock diag socket");
535 : : err = -1;
536 : 0 : goto out;
537 : : }
538 : :
539 : : memset(&req, 0, sizeof(req));
540 : 450 : req.hdr.nlmsg_len = sizeof(req);
541 : 450 : req.hdr.nlmsg_type = SOCK_DIAG_BY_FAMILY;
542 : 450 : req.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
543 : 450 : req.hdr.nlmsg_seq = CR_NLMSG_SEQ;
544 : :
545 : : /* Collect UNIX sockets */
546 : 450 : req.r.u.sdiag_family = AF_UNIX;
547 : 450 : req.r.u.udiag_states = -1; /* All */
548 : 450 : req.r.u.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_VFS |
549 : : UDIAG_SHOW_PEER | UDIAG_SHOW_ICONS |
550 : : UDIAG_SHOW_RQLEN;
551 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), unix_receive_one, NULL);
552 [ - + ]: 450 : if (tmp)
553 : : err = tmp;
554 : :
555 : : /* Collect IPv4 TCP sockets */
556 : 450 : req.r.i.sdiag_family = AF_INET;
557 : 450 : req.r.i.sdiag_protocol = IPPROTO_TCP;
558 : 450 : req.r.i.idiag_ext = 0;
559 : : /* Only listening and established sockets supported yet */
560 : 450 : req.r.i.idiag_states = (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
561 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
562 [ - + ]: 450 : if (tmp)
563 : : err = tmp;
564 : :
565 : : /* Collect IPv4 UDP sockets */
566 : 450 : req.r.i.sdiag_family = AF_INET;
567 : 450 : req.r.i.sdiag_protocol = IPPROTO_UDP;
568 : 450 : req.r.i.idiag_ext = 0;
569 : 450 : req.r.i.idiag_states = -1; /* All */
570 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
571 [ - + ]: 450 : if (tmp)
572 : : err = tmp;
573 : :
574 : : /* Collect IPv4 UDP-lite sockets */
575 : 450 : req.r.i.sdiag_family = AF_INET;
576 : 450 : req.r.i.sdiag_protocol = IPPROTO_UDPLITE;
577 : 450 : req.r.i.idiag_ext = 0;
578 : 450 : req.r.i.idiag_states = -1; /* All */
579 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
580 [ - + ]: 450 : if (tmp)
581 : : err = tmp;
582 : :
583 : : /* Collect IPv6 TCP sockets */
584 : 450 : req.r.i.sdiag_family = AF_INET6;
585 : 450 : req.r.i.sdiag_protocol = IPPROTO_TCP;
586 : 450 : req.r.i.idiag_ext = 0;
587 : : /* Only listening sockets supported yet */
588 : 450 : req.r.i.idiag_states = (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED);
589 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
590 [ - + ]: 450 : if (tmp)
591 : : err = tmp;
592 : :
593 : : /* Collect IPv6 UDP sockets */
594 : 450 : req.r.i.sdiag_family = AF_INET6;
595 : 450 : req.r.i.sdiag_protocol = IPPROTO_UDP;
596 : 450 : req.r.i.idiag_ext = 0;
597 : 450 : req.r.i.idiag_states = -1; /* All */
598 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
599 [ - + ]: 450 : if (tmp)
600 : : err = tmp;
601 : :
602 : : /* Collect IPv6 UDP-lite sockets */
603 : 450 : req.r.i.sdiag_family = AF_INET6;
604 : 450 : req.r.i.sdiag_protocol = IPPROTO_UDPLITE;
605 : 450 : req.r.i.idiag_ext = 0;
606 : 450 : req.r.i.idiag_states = -1; /* All */
607 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), inet_receive_one, &req.r.i);
608 [ - + ]: 450 : if (tmp)
609 : : err = tmp;
610 : :
611 : 450 : req.r.p.sdiag_family = AF_PACKET;
612 : 450 : req.r.p.sdiag_protocol = 0;
613 : 450 : req.r.p.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MCLIST |
614 : : PACKET_SHOW_FANOUT | PACKET_SHOW_RING_CFG;
615 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), packet_receive_one, NULL);
616 [ - + ]: 450 : if (tmp) {
617 : 0 : pr_warn("The current kernel doesn't support packet_diag\n");
618 [ # # ]: 0 : if (pid == 0 || tmp != -ENOENT) /* Fedora 19 */
619 : : err = tmp;
620 : : }
621 : :
622 : 450 : req.r.n.sdiag_family = AF_NETLINK;
623 : 450 : req.r.n.sdiag_protocol = NDIAG_PROTO_ALL;
624 : 450 : req.r.n.ndiag_show = NDIAG_SHOW_GROUPS;
625 : 450 : tmp = do_collect_req(nl, &req, sizeof(req), netlink_receive_one, NULL);
626 [ - + ]: 450 : if (tmp) {
627 : 0 : pr_warn("The current kernel doesn't support netlink_diag\n");
628 [ # # ]: 0 : if (pid == 0 || tmp != -ENOENT) /* Fedora 19 */
629 : : err = tmp;
630 : : }
631 : :
632 : 450 : close(nl);
633 : : out:
634 [ + + ]: 450 : if (rst >= 0) {
635 [ - + ]: 214 : if (restore_ns(rst, &net_ns_desc) < 0)
636 : : err = -1;
637 [ + + ]: 236 : } else if (pid != 0) {
638 : : /*
639 : : * If netns isn't dumped, criu will fail only
640 : : * if an unsupported socket will be really dumped.
641 : : */
642 : 234 : pr_info("Uncollected sockets! Will probably fail later.\n");
643 : : err = 0;
644 : : }
645 : :
646 : 450 : return err;
647 : : }
648 : :
649 : : static inline char *unknown(u32 val)
650 : : {
651 : : static char unk[12];
652 : : snprintf(unk, sizeof(unk), "x%d", val);
653 : : return unk;
654 : : }
655 : :
656 : 0 : char *skfamily2s(u32 f)
657 : : {
658 [ # # ]: 0 : if (f == AF_INET)
659 : : return " inet";
660 [ # # ]: 0 : else if (f == AF_INET6)
661 : : return "inet6";
662 : : else
663 : 0 : return unknown(f);
664 : : }
665 : :
666 : 0 : char *sktype2s(u32 t)
667 : : {
668 [ # # ]: 0 : if (t == SOCK_STREAM)
669 : : return "stream";
670 [ # # ]: 0 : else if (t == SOCK_DGRAM)
671 : : return " dgram";
672 : : else
673 : 0 : return unknown(t);
674 : : }
675 : :
676 : 0 : char *skproto2s(u32 p)
677 : : {
678 [ # # ]: 0 : if (p == IPPROTO_UDP)
679 : : return "udp";
680 [ # # ]: 0 : else if (p == IPPROTO_UDPLITE)
681 : : return "udpl";
682 [ # # ]: 0 : else if (p == IPPROTO_TCP)
683 : : return "tcp";
684 : : else
685 : 0 : return unknown(p);
686 : : }
687 : :
688 : 0 : char *skstate2s(u32 state)
689 : : {
690 [ # # ]: 0 : if (state == TCP_ESTABLISHED)
691 : : return " estab";
692 [ # # ]: 0 : else if (state == TCP_CLOSE)
693 : : return "closed";
694 [ # # ]: 0 : else if (state == TCP_LISTEN)
695 : : return "listen";
696 : : else
697 : 0 : return unknown(state);
698 : : }
|