]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/lsfd-sock-xinfo.c
lsfd: specify variables instead of types in sizeof operator
[thirdparty/util-linux.git] / misc-utils / lsfd-sock-xinfo.c
1 /*
2 * lsfd-sock-xinfo.c - read various information from files under /proc/net/
3 *
4 * Copyright (C) 2022 Red Hat, Inc. All rights reserved.
5 * Written by Masatake YAMATO <yamato@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 #include <arpa/inet.h> /* inet_ntop */
22 #include <netinet/in.h> /* in6_addr */
23 #include <fcntl.h> /* open(2) */
24 #include <inttypes.h> /* SCNu16 */
25 #include <linux/net.h> /* SS_* */
26 #include <linux/un.h> /* UNIX_PATH_MAX */
27 #include <sched.h> /* for setns(2) */
28 #include <search.h>
29 #include <stdint.h>
30 #include <string.h>
31 #include <sys/socket.h> /* SOCK_* */
32
33 #include "xalloc.h"
34 #include "nls.h"
35 #include "libsmartcols.h"
36 #include "sysfs.h"
37 #include "bitops.h"
38
39 #include "lsfd.h"
40 #include "lsfd-sock.h"
41
42 static void load_xinfo_from_proc_unix(ino_t netns_inode);
43 static void load_xinfo_from_proc_raw(ino_t netns_inode);
44 static void load_xinfo_from_proc_tcp(ino_t netns_inode);
45 static void load_xinfo_from_proc_udp(ino_t netns_inode);
46 static void load_xinfo_from_proc_tcp6(ino_t netns_inode);
47
48 static int self_netns_fd = -1;
49 static struct stat self_netns_sb;
50
51 static void *xinfo_tree; /* for tsearch/tfind */
52 static void *netns_tree;
53
54 static int netns_compare(const void *a, const void *b)
55 {
56 if (*(ino_t *)a < *(ino_t *)b)
57 return -1;
58 else if (*(ino_t *)a > *(ino_t *)b)
59 return 1;
60 else
61 return 0;
62 }
63
64 static bool is_sock_xinfo_loaded(ino_t netns)
65 {
66 return tfind(&netns, &netns_tree, netns_compare)? true: false;
67 }
68
69 static void mark_sock_xinfo_loaded(ino_t ino)
70 {
71 ino_t *netns = xmalloc(sizeof(ino));
72 ino_t **tmp;
73
74 *netns = ino;
75 tmp = tsearch(netns, &netns_tree, netns_compare);
76 if (tmp == NULL)
77 errx(EXIT_FAILURE, _("failed to allocate memory"));
78 }
79
80 static void load_sock_xinfo_no_nsswitch(ino_t netns)
81 {
82 load_xinfo_from_proc_unix(netns);
83 load_xinfo_from_proc_tcp(netns);
84 load_xinfo_from_proc_udp(netns);
85 load_xinfo_from_proc_raw(netns);
86 load_xinfo_from_proc_tcp6(netns);
87 }
88
89 static void load_sock_xinfo_with_fd(int fd, ino_t netns)
90 {
91 if (setns(fd, CLONE_NEWNET) == 0) {
92 load_sock_xinfo_no_nsswitch(netns);
93 setns(self_netns_fd, CLONE_NEWNET);
94 }
95 }
96
97 void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns)
98 {
99 if (self_netns_fd == -1)
100 return;
101
102 if (!is_sock_xinfo_loaded(netns)) {
103 int fd;
104
105 mark_sock_xinfo_loaded(netns);
106 fd = ul_path_open(pc, O_RDONLY, name);
107 if (fd < 0)
108 return;
109
110 load_sock_xinfo_with_fd(fd, netns);
111 close(fd);
112 }
113 }
114
115 void initialize_sock_xinfos(void)
116 {
117 struct path_cxt *pc;
118 DIR *dir;
119 struct dirent *d;
120
121 self_netns_fd = open("/proc/self/ns/net", O_RDONLY);
122
123 if (self_netns_fd < 0)
124 load_sock_xinfo_no_nsswitch(0);
125 else {
126 if (fstat(self_netns_fd, &self_netns_sb) == 0) {
127 mark_sock_xinfo_loaded(self_netns_sb.st_ino);
128 load_sock_xinfo_no_nsswitch(self_netns_sb.st_ino);
129 }
130 }
131
132 /* Load /proc/net/{unix,...} of the network namespace
133 * specified with netns files under /var/run/netns/.
134 *
135 * `ip netns' command pins a network namespace on
136 * /var/run/netns.
137 */
138 pc = ul_new_path("/var/run/netns");
139 if (!pc)
140 err(EXIT_FAILURE, _("failed to alloc path context for /var/run/netns"));
141 dir = ul_path_opendir(pc, NULL);
142 if (dir == NULL) {
143 ul_unref_path(pc);
144 return;
145 }
146 while ((d = readdir(dir))) {
147 struct stat sb;
148 int fd;
149 if (ul_path_stat(pc, &sb, 0, d->d_name) < 0)
150 continue;
151 if (is_sock_xinfo_loaded(sb.st_ino))
152 continue;
153 mark_sock_xinfo_loaded(sb.st_ino);
154 fd = ul_path_open(pc, O_RDONLY, d->d_name);
155 if (fd < 0)
156 continue;
157 load_sock_xinfo_with_fd(fd, sb.st_ino);
158 close(fd);
159 }
160 closedir(dir);
161 ul_unref_path(pc);
162 }
163
164 static void free_sock_xinfo(void *node)
165 {
166 struct sock_xinfo *xinfo = node;
167 if (xinfo->class->free)
168 xinfo->class->free(xinfo);
169 free(node);
170 }
171
172 void finalize_sock_xinfos(void)
173 {
174 if (self_netns_fd != -1)
175 close(self_netns_fd);
176 tdestroy(netns_tree, free);
177 tdestroy(xinfo_tree, free_sock_xinfo);
178 }
179
180 static int xinfo_compare(const void *a, const void *b)
181 {
182 if (((struct sock_xinfo *)a)->inode < ((struct sock_xinfo *)b)->inode)
183 return -1;
184 if (((struct sock_xinfo *)a)->inode > ((struct sock_xinfo *)b)->inode)
185 return 1;
186 return 0;
187 }
188
189 static void add_sock_info(struct sock_xinfo *xinfo)
190 {
191 struct sock_xinfo **tmp = tsearch(xinfo, &xinfo_tree, xinfo_compare);
192
193 if (tmp == NULL)
194 errx(EXIT_FAILURE, _("failed to allocate memory"));
195 }
196
197 struct sock_xinfo *get_sock_xinfo(ino_t netns_inode)
198 {
199 struct sock_xinfo **xinfo = tfind(&netns_inode, &xinfo_tree, xinfo_compare);
200
201 if (xinfo)
202 return *xinfo;
203 return NULL;
204 }
205
206 bool is_nsfs_dev(dev_t dev)
207 {
208 return dev == self_netns_sb.st_dev;
209 }
210
211 static const char *sock_decode_type(uint16_t type)
212 {
213 switch (type) {
214 case SOCK_STREAM:
215 return "stream";
216 case SOCK_DGRAM:
217 return "dgram";
218 case SOCK_RAW:
219 return "raw";
220 case SOCK_RDM:
221 return "rdm";
222 case SOCK_SEQPACKET:
223 return "seqpacket";
224 case SOCK_DCCP:
225 return "dccp";
226 case SOCK_PACKET:
227 return "packet";
228 default:
229 return "unknown";
230 }
231 }
232
233 /*
234 * Protocol specific code
235 */
236
237 /*
238 * UNIX
239 */
240 struct unix_xinfo {
241 struct sock_xinfo sock;
242 int acceptcon; /* flags */
243 uint16_t type;
244 uint8_t st;
245 char path[
246 UNIX_PATH_MAX
247 + 1 /* for @ */
248 + 1 /* \0? */
249 ];
250 };
251
252 static const char *unix_decode_state(uint8_t st)
253 {
254 switch (st) {
255 case SS_FREE:
256 return "free";
257 case SS_UNCONNECTED:
258 return "unconnected";
259 case SS_CONNECTING:
260 return "connecting";
261 case SS_CONNECTED:
262 return "connected";
263 case SS_DISCONNECTING:
264 return "disconnecting";
265 default:
266 return "unknown";
267 }
268 }
269
270 static char *unix_get_name(struct sock_xinfo *sock_xinfo,
271 struct sock *sock)
272 {
273 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
274 const char *state = unix_decode_state(ux->st);
275 char *str = NULL;
276
277 if (sock->protoname && (strcmp(sock->protoname, "UNIX-STREAM") == 0))
278 xasprintf(&str, "state=%s%s%s",
279 (ux->acceptcon)? "listen": state,
280 *(ux->path)? " path=": "",
281 *(ux->path)? ux->path: "");
282 else
283 xasprintf(&str, "state=%s%s%s type=%s",
284 (ux->acceptcon)? "listen": state,
285 *(ux->path)? " path=": "",
286 *(ux->path)? ux->path: "",
287 sock_decode_type(ux->type));
288 return str;
289 }
290
291 static char *unix_get_type(struct sock_xinfo *sock_xinfo,
292 struct sock *sock __attribute__((__unused__)))
293 {
294 const char *str;
295 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
296
297 str = sock_decode_type(ux->type);
298 return strdup(str);
299 }
300
301 static char *unix_get_state(struct sock_xinfo *sock_xinfo,
302 struct sock *sock __attribute__((__unused__)))
303 {
304 const char *str;
305 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
306
307 if (ux->acceptcon)
308 return strdup("listen");
309
310 str = unix_decode_state(ux->st);
311 return strdup(str);
312 }
313
314 static bool unix_get_listening(struct sock_xinfo *sock_xinfo,
315 struct sock *sock __attribute__((__unused__)))
316 {
317 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
318
319 return ux->acceptcon;
320 }
321
322 static bool unix_fill_column(struct proc *proc __attribute__((__unused__)),
323 struct sock_xinfo *sock_xinfo,
324 struct sock *sock __attribute__((__unused__)),
325 struct libscols_line *ln __attribute__((__unused__)),
326 int column_id,
327 size_t column_index __attribute__((__unused__)),
328 char **str)
329 {
330 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
331
332 switch (column_id) {
333 case COL_UNIX_PATH:
334 if (*ux->path) {
335 *str = strdup(ux->path);
336 return true;
337 }
338 break;
339 }
340
341 return false;
342 }
343
344 static const struct sock_xinfo_class unix_xinfo_class = {
345 .get_name = unix_get_name,
346 .get_type = unix_get_type,
347 .get_state = unix_get_state,
348 .get_listening = unix_get_listening,
349 .fill_column = unix_fill_column,
350 .free = NULL,
351 };
352
353 /* #define UNIX_LINE_LEN 54 + 21 + UNIX_LINE_LEN + 1
354 *
355 * An actual number must be used in this definition
356 * since UNIX_LINE_LEN is specified as an argument for
357 * stringify_value().
358 */
359 #define UNIX_LINE_LEN 256
360 static void load_xinfo_from_proc_unix(ino_t netns_inode)
361 {
362 char line[UNIX_LINE_LEN];
363 FILE *unix_fp;
364
365 unix_fp = fopen("/proc/net/unix", "r");
366 if (!unix_fp)
367 return;
368
369 if (fgets(line, sizeof(line), unix_fp) == NULL)
370 goto out;
371 if (!(line[0] == 'N' && line[1] == 'u' && line[2] == 'm'))
372 /* Unexpected line */
373 goto out;
374
375 while (fgets(line, sizeof(line), unix_fp)) {
376 uint64_t flags;
377 uint32_t type;
378 unsigned int st;
379 unsigned long inode;
380 struct unix_xinfo *ux;
381 char path[UNIX_LINE_LEN + 1] = { 0 };
382
383
384 if (sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %"
385 stringify_value(UNIX_LINE_LEN) "[^\n]",
386 &flags, &type, &st, &inode, path) < 4)
387 continue;
388
389 if (inode == 0)
390 continue;
391
392 ux = xcalloc(1, sizeof(*ux));
393 ux->sock.class = &unix_xinfo_class;
394 ux->sock.inode = (ino_t)inode;
395 ux->sock.netns_inode = netns_inode;
396
397 ux->acceptcon = !!flags;
398 ux->type = type;
399 ux->st = st;
400 xstrncpy(ux->path, path, sizeof(ux->path));
401
402 add_sock_info((struct sock_xinfo *)ux);
403 }
404
405 out:
406 fclose(unix_fp);
407 }
408
409 /*
410 * AF_INET
411 */
412 struct inet_xinfo {
413 struct sock_xinfo sock;
414 struct in_addr local_addr;
415 struct in_addr remote_addr;
416 };
417
418 static uint32_t kernel32_to_cpu(enum sysfs_byteorder byteorder, uint32_t v)
419 {
420 if (byteorder == SYSFS_BYTEORDER_LITTLE)
421 return le32_to_cpu(v);
422 else
423 return be32_to_cpu(v);
424 }
425
426 /*
427 * AF_INET6
428 */
429 struct inet6_xinfo {
430 struct sock_xinfo sock;
431 struct in6_addr local_addr;
432 struct in6_addr remote_addr;
433 };
434
435 /*
436 * L4 abstract-layer for protocols stacked on IP and IP6.
437 */
438 enum l4_state {
439 /*
440 * Taken from linux/include/net/tcp_states.h.
441 * (GPL-2.0-or-later)
442 *
443 * UDP and RAW sockets also uses the contents in Linux.
444 */
445 TCP_ESTABLISHED = 1,
446 TCP_SYN_SENT,
447 TCP_SYN_RECV,
448 TCP_FIN_WAIT1,
449 TCP_FIN_WAIT2,
450 TCP_TIME_WAIT,
451 TCP_CLOSE,
452 TCP_CLOSE_WAIT,
453 TCP_LAST_ACK,
454 TCP_LISTEN,
455 TCP_CLOSING,
456 TCP_NEW_SYN_RECV,
457
458 TCP_MAX_STATES /* Leave at the end! */
459 };
460
461 static const char *l4_decode_state(enum l4_state st)
462 {
463 const char * table [] = {
464 [TCP_ESTABLISHED] = "established",
465 [TCP_SYN_SENT] = "syn-sent",
466 [TCP_SYN_RECV] = "syn-recv",
467 [TCP_FIN_WAIT1] = "fin-wait1",
468 [TCP_FIN_WAIT2] = "fin-wait2",
469 [TCP_TIME_WAIT] = "time-wait",
470 [TCP_CLOSE] = "close",
471 [TCP_CLOSE_WAIT] = "close-wait",
472 [TCP_LAST_ACK] = "last-ack",
473 [TCP_LISTEN] = "listen",
474 [TCP_CLOSING] = "closing",
475 [TCP_NEW_SYN_RECV] = "new-syn-recv",
476 };
477
478 if (st < TCP_MAX_STATES)
479 return table[st];
480 return "unknown";
481 }
482
483 struct l4_xinfo {
484 union {
485 struct inet_xinfo inet;
486 struct inet6_xinfo inet6;
487 };
488 enum l4_state st;
489 };
490
491 enum l4_side { L4_LOCAL, L4_REMOTE };
492 enum l3_decorator { L3_DECO_START, L3_DECO_END };
493
494 struct l4_xinfo_class {
495 struct sock_xinfo_class sock;
496 struct sock_xinfo *(*scan_line)(const struct sock_xinfo_class *,
497 char *,
498 ino_t,
499 enum sysfs_byteorder);
500 void * (*get_addr)(struct l4_xinfo *, enum l4_side);
501 bool (*is_any_addr)(void *);
502 int family;
503 const char *l3_decorator[2];
504 };
505
506 #define l3_fill_column_handler(L3, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
507 ({ \
508 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
509 struct l4_xinfo *l4 = (struct l4_xinfo *)SOCK_XINFO; \
510 void *n = NULL; \
511 char s[BUFSIZ]; \
512 bool r = false; \
513 \
514 switch (COLUMN_ID) { \
515 case COL_##L3##_LADDR: \
516 n = class->get_addr(l4, L4_LOCAL); \
517 break; \
518 case COL_##L3##_RADDR: \
519 n = class->get_addr(l4, L4_REMOTE); \
520 break; \
521 default: \
522 break; \
523 } \
524 \
525 if (n && inet_ntop(class->family, n, s, sizeof(s))) { \
526 *STR = strdup(s); \
527 r = true; \
528 } \
529 r; \
530 })
531
532 /*
533 * TCP
534 */
535 struct tcp_xinfo {
536 struct l4_xinfo l4;
537 uint16_t local_port;
538 uint16_t remote_port;
539 };
540
541 static char *tcp_get_name(struct sock_xinfo *sock_xinfo,
542 struct sock *sock __attribute__((__unused__)))
543 {
544 char *str = NULL;
545 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
546 struct l4_xinfo *l4 = &tcp->l4;
547 const char *st_str = l4_decode_state(l4->st);
548 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
549 void *laddr = class->get_addr(l4, L4_LOCAL);
550 void *raddr = class->get_addr(l4, L4_REMOTE);
551 char local_s[BUFSIZ];
552 char remote_s[BUFSIZ];
553 const char *start = class->l3_decorator[L3_DECO_START];
554 const char *end = class->l3_decorator[L3_DECO_END];
555
556 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
557 xasprintf(&str, "state=%s", st_str);
558 else if (l4->st == TCP_LISTEN
559 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
560 xasprintf(&str, "state=%s laddr=%s%s%s:%"SCNu16,
561 st_str,
562 start, local_s, end, tcp->local_port);
563 else
564 xasprintf(&str, "state=%s laddr=%s%s%s:%"SCNu16" raddr=%s%s%s:%"SCNu16,
565 st_str,
566 start, local_s, end, tcp->local_port,
567 start, remote_s, end, tcp->remote_port);
568 return str;
569 }
570
571 static char *tcp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
572 struct sock *sock __attribute__((__unused__)))
573 {
574 return strdup("stream");
575 }
576
577 static char *tcp_get_state(struct sock_xinfo *sock_xinfo,
578 struct sock *sock __attribute__((__unused__)))
579 {
580 return strdup(l4_decode_state(((struct l4_xinfo *)sock_xinfo)->st));
581 }
582
583 static bool tcp_get_listening(struct sock_xinfo *sock_xinfo,
584 struct sock *sock __attribute__((__unused__)))
585 {
586 return ((struct l4_xinfo *)sock_xinfo)->st == TCP_LISTEN;
587 }
588
589 #define l4_fill_column_handler(L4, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
590 ({ \
591 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
592 struct tcp_xinfo *tcp = (struct tcp_xinfo *)SOCK_XINFO; \
593 struct l4_xinfo *l4 = &tcp->l4; \
594 void *n = NULL; \
595 bool has_laddr = false; \
596 unsigned short p; \
597 bool has_lport = false; \
598 char s[BUFSIZ]; \
599 bool r = true; \
600 \
601 switch (COLUMN_ID) { \
602 case COL_##L4##_LADDR: \
603 n = class->get_addr(l4, L4_LOCAL); \
604 has_laddr = true; \
605 p = tcp->local_port; \
606 /* FALL THROUGH */ \
607 case COL_##L4##_RADDR: \
608 if (!has_laddr) { \
609 n = class->get_addr(l4, L4_REMOTE); \
610 p = tcp->remote_port; \
611 } \
612 if (n && inet_ntop(class->family, n, s, sizeof(s))) \
613 xasprintf(STR, "%s%s%s:%"SCNu16, \
614 class->l3_decorator[L3_DECO_START], \
615 s, \
616 class->l3_decorator[L3_DECO_END], \
617 p); \
618 break; \
619 case COL_##L4##_LPORT: \
620 p = tcp->local_port; \
621 has_lport = true; \
622 /* FALL THROUGH */ \
623 case COL_##L4##_RPORT: \
624 if (!has_lport) \
625 p = tcp->remote_port; \
626 xasprintf(STR, "%"SCNu16, p); \
627 break; \
628 default: \
629 r = false; \
630 break; \
631 } \
632 r; \
633 })
634
635 static struct sock_xinfo *tcp_xinfo_scan_line(const struct sock_xinfo_class *class,
636 char * line,
637 ino_t netns_inode,
638 enum sysfs_byteorder byteorder)
639 {
640 unsigned long local_addr;
641 unsigned long local_port;
642 unsigned long remote_addr;
643 unsigned long remote_port;
644 unsigned long st;
645 unsigned long long inode;
646 struct tcp_xinfo *tcp;
647 struct inet_xinfo *inet;
648 struct sock_xinfo *sock;
649
650 if (sscanf(line, "%*d: %lx:%lx %lx:%lx %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
651 &local_addr, &local_port, &remote_addr, &remote_port,
652 &st, &inode) != 6)
653 return NULL;
654
655 if (inode == 0)
656 return NULL;
657
658 tcp = xcalloc(1, sizeof(*tcp));
659 inet = &tcp->l4.inet;
660 sock = &inet->sock;
661 sock->class = class;
662 sock->inode = (ino_t)inode;
663 sock->netns_inode = netns_inode;
664 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
665 tcp->local_port = local_port;
666 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
667 tcp->remote_port = remote_port;
668 tcp->l4.st = st;
669
670 return sock;
671 }
672
673 static void *tcp_xinfo_get_addr(struct l4_xinfo *l4, enum l4_side side)
674 {
675 return (side == L4_LOCAL)
676 ? &l4->inet.local_addr
677 : &l4->inet.remote_addr;
678 }
679
680 static bool tcp_xinfo_is_any_addr(void *addr)
681 {
682 return ((struct in_addr *)addr)->s_addr == INADDR_ANY;
683 }
684
685 static bool tcp_fill_column(struct proc *proc __attribute__((__unused__)),
686 struct sock_xinfo *sock_xinfo,
687 struct sock *sock __attribute__((__unused__)),
688 struct libscols_line *ln __attribute__((__unused__)),
689 int column_id,
690 size_t column_index __attribute__((__unused__)),
691 char **str)
692 {
693 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
694 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
695 }
696
697 static const struct l4_xinfo_class tcp_xinfo_class = {
698 .sock = {
699 .get_name = tcp_get_name,
700 .get_type = tcp_get_type,
701 .get_state = tcp_get_state,
702 .get_listening = tcp_get_listening,
703 .fill_column = tcp_fill_column,
704 .free = NULL,
705 },
706 .scan_line = tcp_xinfo_scan_line,
707 .get_addr = tcp_xinfo_get_addr,
708 .is_any_addr = tcp_xinfo_is_any_addr,
709 .family = AF_INET,
710 .l3_decorator = {"", ""},
711 };
712
713 static bool L4_verify_initial_line(const char *line)
714 {
715 /* At least we expect two white spaces. */
716 if (strncmp(line, " ", 2) != 0)
717 return false;
718 line += 2;
719
720 /* Skip white spaces. */
721 line = skip_space(line);
722
723 return strncmp(line, "sl", 2) == 0;
724 }
725
726 #define TCP_LINE_LEN 256
727 static void load_xinfo_from_proc_inet_L4(ino_t netns_inode, const char *proc_file,
728 const struct l4_xinfo_class *class)
729 {
730 char line[TCP_LINE_LEN];
731 FILE *tcp_fp;
732
733 tcp_fp = fopen(proc_file, "r");
734 if (!tcp_fp)
735 return;
736
737 if (fgets(line, sizeof(line), tcp_fp) == NULL)
738 goto out;
739 if (!L4_verify_initial_line(line))
740 /* Unexpected line */
741 goto out;
742
743 enum sysfs_byteorder byteorder = sysfs_get_byteorder(NULL);
744
745 while (fgets(line, sizeof(line), tcp_fp)) {
746 struct sock_xinfo *sock = class->scan_line(&class->sock, line, netns_inode, byteorder);
747 if (sock)
748 add_sock_info(sock);
749 }
750
751 out:
752 fclose(tcp_fp);
753 }
754
755 static void load_xinfo_from_proc_tcp(ino_t netns_inode)
756 {
757 load_xinfo_from_proc_inet_L4(netns_inode,
758 "/proc/net/tcp",
759 &tcp_xinfo_class);
760 }
761
762 /*
763 * UDP
764 */
765 static char *udp_get_name(struct sock_xinfo *sock_xinfo,
766 struct sock *sock __attribute__((__unused__)))
767 {
768 char *str = NULL;
769 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
770 struct l4_xinfo *l4 = &tcp->l4;
771 unsigned int st = l4->st;
772 const char *st_str = l4_decode_state(st);
773 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
774 void *laddr = class->get_addr(l4, L4_LOCAL);
775 void *raddr = class->get_addr(l4, L4_REMOTE);
776 char local_s[BUFSIZ];
777 char remote_s[BUFSIZ];
778
779 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
780 xasprintf(&str, "state=%s", st_str);
781 else if ((class->is_any_addr(raddr) && tcp->remote_port == 0)
782 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
783 xasprintf(&str, "state=%s laddr=%s:%"SCNu16,
784 st_str,
785 local_s, tcp->local_port);
786 else
787 xasprintf(&str, "state=%s laddr=%s:%"SCNu16" raddr=%s:%"SCNu16,
788 st_str,
789 local_s, tcp->local_port,
790 remote_s, tcp->remote_port);
791 return str;
792 }
793
794 static char *udp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
795 struct sock *sock __attribute__((__unused__)))
796 {
797 return strdup("dgram");
798 }
799
800 static bool udp_fill_column(struct proc *proc __attribute__((__unused__)),
801 struct sock_xinfo *sock_xinfo,
802 struct sock *sock __attribute__((__unused__)),
803 struct libscols_line *ln __attribute__((__unused__)),
804 int column_id,
805 size_t column_index __attribute__((__unused__)),
806 char **str)
807 {
808 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
809 || l4_fill_column_handler(UDP, sock_xinfo, column_id, str);
810 }
811
812 static const struct l4_xinfo_class udp_xinfo_class = {
813 .sock = {
814 .get_name = udp_get_name,
815 .get_type = udp_get_type,
816 .get_state = tcp_get_state,
817 .get_listening = NULL,
818 .fill_column = udp_fill_column,
819 .free = NULL,
820 },
821 .scan_line = tcp_xinfo_scan_line,
822 .get_addr = tcp_xinfo_get_addr,
823 .is_any_addr = tcp_xinfo_is_any_addr,
824 .family = AF_INET,
825 .l3_decorator = {"", ""},
826 };
827
828 static void load_xinfo_from_proc_udp(ino_t netns_inode)
829 {
830 load_xinfo_from_proc_inet_L4(netns_inode,
831 "/proc/net/udp",
832 &udp_xinfo_class);
833 }
834
835 /*
836 * RAW
837 */
838 struct raw_xinfo {
839 struct l4_xinfo l4;
840 uint16_t protocol;
841 };
842
843 static char *raw_get_name(struct sock_xinfo *sock_xinfo,
844 struct sock *sock __attribute__((__unused__)))
845 {
846 char *str = NULL;
847 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
848 struct raw_xinfo *raw = ((struct raw_xinfo *)sock_xinfo);
849 struct l4_xinfo *l4 = &raw->l4;
850 const char *st_str = l4_decode_state(l4->st);
851 void *laddr = class->get_addr(l4, L4_LOCAL);
852 void *raddr = class->get_addr(l4, L4_REMOTE);
853 char local_s[BUFSIZ];
854 char remote_s[BUFSIZ];
855
856 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
857 xasprintf(&str, "state=%s", st_str);
858 else if (class->is_any_addr(raddr)
859 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
860 xasprintf(&str, "state=%s protocol=%"SCNu16" laddr=%s",
861 st_str,
862 raw->protocol, local_s);
863 else
864 xasprintf(&str, "state=%s protocol=%"SCNu16" laddr=%s raddr=%s",
865 st_str,
866 raw->protocol, local_s, remote_s);
867 return str;
868 }
869
870 static char *raw_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
871 struct sock *sock __attribute__((__unused__)))
872 {
873 return strdup("raw");
874 }
875
876 static bool raw_fill_column(struct proc *proc __attribute__((__unused__)),
877 struct sock_xinfo *sock_xinfo,
878 struct sock *sock __attribute__((__unused__)),
879 struct libscols_line *ln __attribute__((__unused__)),
880 int column_id,
881 size_t column_index __attribute__((__unused__)),
882 char **str)
883 {
884 if (l3_fill_column_handler(INET, sock_xinfo, column_id, str))
885 return true;
886
887 if (column_id == COL_RAW_PROTOCOL) {
888 xasprintf(str, "%"SCNu16,
889 ((struct raw_xinfo *)sock_xinfo)->protocol);
890 return true;
891 }
892
893 return false;
894 }
895
896 static struct sock_xinfo *raw_xinfo_scan_line(const struct sock_xinfo_class *class,
897 char * line,
898 ino_t netns_inode,
899 enum sysfs_byteorder byteorder)
900 {
901 unsigned long local_addr;
902 unsigned long protocol;
903 unsigned long remote_addr;
904 unsigned long st;
905 unsigned long long inode;
906 struct raw_xinfo *raw;
907 struct inet_xinfo *inet;
908 struct sock_xinfo *sock;
909
910 if (sscanf(line, "%*d: %lx:%lx %lx:%*x %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
911 &local_addr, &protocol, &remote_addr,
912 &st, &inode) != 5)
913 return NULL;
914
915 if (inode == 0)
916 return NULL;
917
918 raw = xcalloc(1, sizeof(*raw));
919 inet = &raw->l4.inet;
920 sock = &inet->sock;
921 sock->class = class;
922 sock->inode = (ino_t)inode;
923 sock->netns_inode = netns_inode;
924 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
925 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
926 raw->protocol = protocol;
927 raw->l4.st = st;
928
929 return sock;
930 }
931
932 static const struct l4_xinfo_class raw_xinfo_class = {
933 .sock = {
934 .get_name = raw_get_name,
935 .get_type = raw_get_type,
936 .get_state = tcp_get_state,
937 .get_listening = NULL,
938 .fill_column = raw_fill_column,
939 .free = NULL,
940 },
941 .scan_line = raw_xinfo_scan_line,
942 .get_addr = tcp_xinfo_get_addr,
943 .is_any_addr = tcp_xinfo_is_any_addr,
944 .family = AF_INET,
945 .l3_decorator = {"", ""},
946 };
947
948 static void load_xinfo_from_proc_raw(ino_t netns_inode)
949 {
950 load_xinfo_from_proc_inet_L4(netns_inode,
951 "/proc/net/raw",
952 &raw_xinfo_class);
953 }
954
955 /*
956 * TCP6
957 */
958 static struct sock_xinfo *tcp6_xinfo_scan_line(const struct sock_xinfo_class *class,
959 char * line,
960 ino_t netns_inode,
961 enum sysfs_byteorder byteorder)
962 {
963 uint32_t local_addr[4];
964 unsigned int local_port;
965 uint32_t remote_addr[4];
966 unsigned int remote_port;
967 unsigned int st;
968 unsigned long inode;
969 struct tcp_xinfo *tcp;
970 struct inet6_xinfo *inet6;
971 struct sock_xinfo *sock;
972
973 if (sscanf(line,
974 "%*d: "
975 "%08x%08x%08x%08x:%04x "
976 "%08x%08x%08x%08x:%04x "
977 "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
978 local_addr+0, local_addr+1, local_addr+2, local_addr+3, &local_port,
979 remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3, &remote_port,
980 &st, &inode) != 12)
981 return NULL;
982
983 if (inode == 0)
984 return NULL;
985
986 tcp = xmalloc(sizeof(*tcp));
987 inet6 = &tcp->l4.inet6;
988 sock = &inet6->sock;
989 sock->class = class;
990 sock->inode = (ino_t)inode;
991 sock->netns_inode = netns_inode;
992 tcp->local_port = local_port;
993 for (int i = 0; i < 4; i++) {
994 inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
995 inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
996 }
997 tcp->remote_port = remote_port;
998 tcp->l4.st = st;
999
1000 return sock;
1001 }
1002
1003 static bool tcp6_fill_column(struct proc *proc __attribute__((__unused__)),
1004 struct sock_xinfo *sock_xinfo,
1005 struct sock *sock __attribute__((__unused__)),
1006 struct libscols_line *ln __attribute__((__unused__)),
1007 int column_id,
1008 size_t column_index __attribute__((__unused__)),
1009 char **str)
1010 {
1011 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1012 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
1013 }
1014
1015 static void *tcp6_xinfo_get_addr(struct l4_xinfo * l4, enum l4_side side)
1016 {
1017 return (side == L4_LOCAL)
1018 ? &l4->inet6.local_addr
1019 : &l4->inet6.remote_addr;
1020 }
1021
1022 static bool tcp6_xinfo_is_any_addr(void *addr)
1023 {
1024 return IN6_ARE_ADDR_EQUAL(addr, &(struct in6_addr)IN6ADDR_ANY_INIT);
1025 }
1026
1027 static const struct l4_xinfo_class tcp6_xinfo_class = {
1028 .sock = {
1029 .get_name = tcp_get_name,
1030 .get_type = tcp_get_type,
1031 .get_state = tcp_get_state,
1032 .get_listening = tcp_get_listening,
1033 .fill_column = tcp6_fill_column,
1034 .free = NULL,
1035 },
1036 .scan_line = tcp6_xinfo_scan_line,
1037 .get_addr = tcp6_xinfo_get_addr,
1038 .is_any_addr = tcp6_xinfo_is_any_addr,
1039 .family = AF_INET6,
1040 .l3_decorator = {"[", "]"},
1041 };
1042
1043 static void load_xinfo_from_proc_tcp6(ino_t netns_inode)
1044 {
1045 load_xinfo_from_proc_inet_L4(netns_inode,
1046 "/proc/net/tcp6",
1047 &tcp6_xinfo_class);
1048 }