]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/lsfd-sock-xinfo.c
lsfd: include common headers in lsfd.h
[thirdparty/util-linux.git] / misc-utils / lsfd-sock-xinfo.c
CommitLineData
0ee16e43
MY
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 */
7b2a9be0 21#include <arpa/inet.h> /* inet_ntop */
1656da13 22#include <netinet/in.h> /* in6_addr */
2e38e61c 23#include <fcntl.h> /* open(2) */
97f54385 24#include <ifaddrs.h> /* getifaddrs */
73df46fc 25#include <inttypes.h> /* SCNu16 */
97f54385 26#include <net/if.h> /* if_nametoindex */
adfc156a 27#include <linux/if_ether.h> /* ETH_P_* */
2e38e61c 28#include <linux/net.h> /* SS_* */
b53cc896 29#include <linux/netlink.h> /* NETLINK_* */
2e38e61c 30#include <linux/un.h> /* UNIX_PATH_MAX */
0ee16e43
MY
31#include <sched.h> /* for setns(2) */
32#include <search.h>
2e38e61c
MY
33#include <stdint.h>
34#include <string.h>
35#include <sys/socket.h> /* SOCK_* */
0ee16e43 36
db79a100
TW
37#include "sysfs.h"
38#include "bitops.h"
0ee16e43
MY
39
40#include "lsfd.h"
41#include "lsfd-sock.h"
42
a7cba6f3 43static void load_xinfo_from_proc_icmp(ino_t netns_inode);
0b1dfd03 44static void load_xinfo_from_proc_icmp6(ino_t netns_inode);
2e38e61c 45static void load_xinfo_from_proc_unix(ino_t netns_inode);
0188afb3 46static void load_xinfo_from_proc_raw(ino_t netns_inode);
7b2a9be0 47static void load_xinfo_from_proc_tcp(ino_t netns_inode);
92a0dbce 48static void load_xinfo_from_proc_udp(ino_t netns_inode);
c779f412 49static void load_xinfo_from_proc_udplite(ino_t netns_inode);
1656da13 50static void load_xinfo_from_proc_tcp6(ino_t netns_inode);
28cf2b21 51static void load_xinfo_from_proc_udp6(ino_t netns_inode);
93bca151 52static void load_xinfo_from_proc_udplite6(ino_t netns_inode);
2dd373c3 53static void load_xinfo_from_proc_raw6(ino_t netns_inode);
b53cc896 54static void load_xinfo_from_proc_netlink(ino_t netns_inode);
adfc156a 55static void load_xinfo_from_proc_packet(ino_t netns_inode);
2e38e61c 56
0ee16e43 57static int self_netns_fd = -1;
44f9aec7 58static struct stat self_netns_sb;
0ee16e43
MY
59
60static void *xinfo_tree; /* for tsearch/tfind */
61static void *netns_tree;
62
97f54385
MY
63struct iface {
64 unsigned int index;
65 char name[IF_NAMESIZE];
66};
67
68static const char *get_iface_name(ino_t netns, unsigned int iface_index);
69
e6e551e8
MY
70struct netns {
71 ino_t inode;
97f54385 72 struct iface *ifaces;
e6e551e8
MY
73};
74
0ee16e43
MY
75static int netns_compare(const void *a, const void *b)
76{
e6e551e8
MY
77 const struct netns *netns_a = a;
78 const struct netns *netns_b = b;
79
80 return netns_a->inode - netns_b->inode;
81}
82
83static void netns_free(void *netns)
84{
97f54385
MY
85 struct netns *nsobj = netns;
86
87 free(nsobj->ifaces);
e6e551e8 88 free(netns);
0ee16e43
MY
89}
90
97f54385
MY
91/*
92 * iface index -> iface name mappings
93 */
94static void load_ifaces_from_getifaddrs(struct netns *nsobj)
95{
96 struct ifaddrs *ifa_list;
97 struct ifaddrs *ifa;
98 size_t i, count = 0;
99
100 if (getifaddrs(&ifa_list) < 0)
101 return;
102
103 for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next)
104 count++;
105
106 nsobj->ifaces = xcalloc(count + 1, sizeof(*nsobj->ifaces));
107
108 for (ifa = ifa_list, i = 0; ifa != NULL; ifa = ifa->ifa_next, i++) {
109 unsigned int if_index = if_nametoindex(ifa->ifa_name);
110
111 nsobj->ifaces[i].index = if_index;
112 strncpy(nsobj->ifaces[i].name, ifa->ifa_name, IF_NAMESIZE - 1);
113 /* The slot for the last byte is already filled by calloc. */
114 }
115 /* nsobj->ifaces[count] is the sentinel value. */
116
117 freeifaddrs(ifa_list);
118
119 return;
120}
121
122static const char *get_iface_name(ino_t netns, unsigned int iface_index)
123{
124 struct netns **nsobj = tfind(&netns, &netns_tree, netns_compare);
125 if (!nsobj)
126 return NULL;
127
128 for (size_t i = 0; (*nsobj)->ifaces[i].index; i++) {
129 if ((*nsobj)->ifaces[i].index == iface_index)
130 return (*nsobj)->ifaces[i].name;
131 }
132
133 return NULL;
134}
135
0ee16e43
MY
136static bool is_sock_xinfo_loaded(ino_t netns)
137{
138 return tfind(&netns, &netns_tree, netns_compare)? true: false;
139}
140
e6e551e8 141static struct netns *mark_sock_xinfo_loaded(ino_t ino)
0ee16e43 142{
97f54385 143 struct netns *netns = xcalloc(1, sizeof(*netns));
0ee16e43
MY
144 ino_t **tmp;
145
e6e551e8 146 netns->inode = ino;
0ee16e43
MY
147 tmp = tsearch(netns, &netns_tree, netns_compare);
148 if (tmp == NULL)
149 errx(EXIT_FAILURE, _("failed to allocate memory"));
e6e551e8 150 return *(struct netns **)tmp;
0ee16e43
MY
151}
152
e6e551e8 153static void load_sock_xinfo_no_nsswitch(struct netns *nsobj)
0ee16e43 154{
e6e551e8
MY
155 ino_t netns = nsobj? nsobj->inode: 0;
156
2e38e61c 157 load_xinfo_from_proc_unix(netns);
7b2a9be0 158 load_xinfo_from_proc_tcp(netns);
92a0dbce 159 load_xinfo_from_proc_udp(netns);
c779f412 160 load_xinfo_from_proc_udplite(netns);
0188afb3 161 load_xinfo_from_proc_raw(netns);
1656da13 162 load_xinfo_from_proc_tcp6(netns);
28cf2b21 163 load_xinfo_from_proc_udp6(netns);
93bca151 164 load_xinfo_from_proc_udplite6(netns);
2dd373c3 165 load_xinfo_from_proc_raw6(netns);
a7cba6f3 166 load_xinfo_from_proc_icmp(netns);
0b1dfd03 167 load_xinfo_from_proc_icmp6(netns);
b53cc896 168 load_xinfo_from_proc_netlink(netns);
adfc156a 169 load_xinfo_from_proc_packet(netns);
97f54385
MY
170
171 if (nsobj)
172 load_ifaces_from_getifaddrs(nsobj);
0ee16e43
MY
173}
174
e6e551e8 175static void load_sock_xinfo_with_fd(int fd, struct netns *nsobj)
0ee16e43 176{
b3649945 177 if (setns(fd, CLONE_NEWNET) == 0) {
e6e551e8 178 load_sock_xinfo_no_nsswitch(nsobj);
b3649945 179 setns(self_netns_fd, CLONE_NEWNET);
0ee16e43
MY
180 }
181}
182
183void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns)
184{
185 if (self_netns_fd == -1)
186 return;
187
188 if (!is_sock_xinfo_loaded(netns)) {
189 int fd;
e6e551e8 190 struct netns *nsobj = mark_sock_xinfo_loaded(netns);
0ee16e43
MY
191 fd = ul_path_open(pc, O_RDONLY, name);
192 if (fd < 0)
193 return;
194
e6e551e8 195 load_sock_xinfo_with_fd(fd, nsobj);
0ee16e43
MY
196 close(fd);
197 }
198}
199
200void initialize_sock_xinfos(void)
201{
202 struct path_cxt *pc;
203 DIR *dir;
204 struct dirent *d;
205
206 self_netns_fd = open("/proc/self/ns/net", O_RDONLY);
207
208 if (self_netns_fd < 0)
e6e551e8 209 load_sock_xinfo_no_nsswitch(NULL);
0ee16e43
MY
210 else {
211 if (fstat(self_netns_fd, &self_netns_sb) == 0) {
916b44a5 212 unsigned long m;
e6e551e8
MY
213 struct netns *nsobj = mark_sock_xinfo_loaded(self_netns_sb.st_ino);
214 load_sock_xinfo_no_nsswitch(nsobj);
916b44a5
MY
215
216 m = minor(self_netns_sb.st_dev);
217 add_nodev(m, "nsfs");
0ee16e43
MY
218 }
219 }
220
221 /* Load /proc/net/{unix,...} of the network namespace
222 * specified with netns files under /var/run/netns/.
223 *
224 * `ip netns' command pins a network namespace on
225 * /var/run/netns.
226 */
227 pc = ul_new_path("/var/run/netns");
228 if (!pc)
229 err(EXIT_FAILURE, _("failed to alloc path context for /var/run/netns"));
230 dir = ul_path_opendir(pc, NULL);
231 if (dir == NULL) {
232 ul_unref_path(pc);
233 return;
234 }
235 while ((d = readdir(dir))) {
236 struct stat sb;
237 int fd;
e6e551e8 238 struct netns *nsobj;
0ee16e43
MY
239 if (ul_path_stat(pc, &sb, 0, d->d_name) < 0)
240 continue;
241 if (is_sock_xinfo_loaded(sb.st_ino))
242 continue;
e6e551e8 243 nsobj = mark_sock_xinfo_loaded(sb.st_ino);
0ee16e43
MY
244 fd = ul_path_open(pc, O_RDONLY, d->d_name);
245 if (fd < 0)
246 continue;
e6e551e8 247 load_sock_xinfo_with_fd(fd, nsobj);
0ee16e43
MY
248 close(fd);
249 }
250 closedir(dir);
251 ul_unref_path(pc);
252}
253
b3649945 254static void free_sock_xinfo(void *node)
0ee16e43
MY
255{
256 struct sock_xinfo *xinfo = node;
257 if (xinfo->class->free)
b3649945 258 xinfo->class->free(xinfo);
0ee16e43
MY
259 free(node);
260}
261
262void finalize_sock_xinfos(void)
263{
264 if (self_netns_fd != -1)
265 close(self_netns_fd);
e6e551e8 266 tdestroy(netns_tree, netns_free);
0ee16e43
MY
267 tdestroy(xinfo_tree, free_sock_xinfo);
268}
269
270static int xinfo_compare(const void *a, const void *b)
271{
0caccbf1 272 return ((struct sock_xinfo *)a)->inode - ((struct sock_xinfo *)b)->inode;
0ee16e43
MY
273}
274
2e38e61c
MY
275static void add_sock_info(struct sock_xinfo *xinfo)
276{
277 struct sock_xinfo **tmp = tsearch(xinfo, &xinfo_tree, xinfo_compare);
278
279 if (tmp == NULL)
280 errx(EXIT_FAILURE, _("failed to allocate memory"));
281}
282
b8bcca67 283struct sock_xinfo *get_sock_xinfo(ino_t inode)
0ee16e43 284{
b8bcca67 285 struct sock_xinfo **xinfo = tfind(&inode, &xinfo_tree, xinfo_compare);
0ee16e43
MY
286
287 if (xinfo)
288 return *xinfo;
289 return NULL;
290}
291
292bool is_nsfs_dev(dev_t dev)
293{
621cf7e9 294 return dev == self_netns_sb.st_dev;
0ee16e43 295}
2e38e61c
MY
296
297static const char *sock_decode_type(uint16_t type)
298{
299 switch (type) {
300 case SOCK_STREAM:
301 return "stream";
302 case SOCK_DGRAM:
303 return "dgram";
304 case SOCK_RAW:
305 return "raw";
306 case SOCK_RDM:
307 return "rdm";
308 case SOCK_SEQPACKET:
309 return "seqpacket";
310 case SOCK_DCCP:
311 return "dccp";
312 case SOCK_PACKET:
313 return "packet";
314 default:
315 return "unknown";
316 }
317}
318
319/*
320 * Protocol specific code
321 */
322
323/*
324 * UNIX
325 */
326struct unix_xinfo {
327 struct sock_xinfo sock;
328 int acceptcon; /* flags */
329 uint16_t type;
330 uint8_t st;
331 char path[
332 UNIX_PATH_MAX
333 + 1 /* for @ */
334 + 1 /* \0? */
335 ];
336};
337
338static const char *unix_decode_state(uint8_t st)
339{
340 switch (st) {
341 case SS_FREE:
342 return "free";
343 case SS_UNCONNECTED:
344 return "unconnected";
345 case SS_CONNECTING:
346 return "connecting";
347 case SS_CONNECTED:
348 return "connected";
349 case SS_DISCONNECTING:
350 return "disconnecting";
351 default:
352 return "unknown";
353 }
354}
355
356static char *unix_get_name(struct sock_xinfo *sock_xinfo,
357 struct sock *sock)
358{
359 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
360 const char *state = unix_decode_state(ux->st);
361 char *str = NULL;
362
363 if (sock->protoname && (strcmp(sock->protoname, "UNIX-STREAM") == 0))
364 xasprintf(&str, "state=%s%s%s",
365 (ux->acceptcon)? "listen": state,
366 *(ux->path)? " path=": "",
367 *(ux->path)? ux->path: "");
368 else
369 xasprintf(&str, "state=%s%s%s type=%s",
370 (ux->acceptcon)? "listen": state,
371 *(ux->path)? " path=": "",
372 *(ux->path)? ux->path: "",
373 sock_decode_type(ux->type));
374 return str;
375}
376
377static char *unix_get_type(struct sock_xinfo *sock_xinfo,
378 struct sock *sock __attribute__((__unused__)))
379{
380 const char *str;
381 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
382
383 str = sock_decode_type(ux->type);
e0dc84da 384 return xstrdup(str);
2e38e61c
MY
385}
386
387static char *unix_get_state(struct sock_xinfo *sock_xinfo,
388 struct sock *sock __attribute__((__unused__)))
389{
390 const char *str;
391 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
392
393 if (ux->acceptcon)
e0dc84da 394 return xstrdup("listen");
2e38e61c
MY
395
396 str = unix_decode_state(ux->st);
e0dc84da 397 return xstrdup(str);
2e38e61c
MY
398}
399
45d61bff
MY
400static bool unix_get_listening(struct sock_xinfo *sock_xinfo,
401 struct sock *sock __attribute__((__unused__)))
402{
403 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
404
405 return ux->acceptcon;
406}
407
2e38e61c
MY
408static bool unix_fill_column(struct proc *proc __attribute__((__unused__)),
409 struct sock_xinfo *sock_xinfo,
410 struct sock *sock __attribute__((__unused__)),
411 struct libscols_line *ln __attribute__((__unused__)),
412 int column_id,
413 size_t column_index __attribute__((__unused__)),
414 char **str)
415{
416 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
417
854ddd0d 418 switch (column_id) {
2e38e61c
MY
419 case COL_UNIX_PATH:
420 if (*ux->path) {
e0dc84da 421 *str = xstrdup(ux->path);
2e38e61c
MY
422 return true;
423 }
424 break;
425 }
426
427 return false;
428}
429
54a06438 430static const struct sock_xinfo_class unix_xinfo_class = {
2e38e61c
MY
431 .get_name = unix_get_name,
432 .get_type = unix_get_type,
433 .get_state = unix_get_state,
45d61bff 434 .get_listening = unix_get_listening,
2e38e61c
MY
435 .fill_column = unix_fill_column,
436 .free = NULL,
437};
438
e8e14a28 439/* UNIX_LINE_LEN need at least 54 + 21 + UNIX_PATH_MAX + 1.
eeaf7677
MY
440 *
441 * An actual number must be used in this definition
442 * since UNIX_LINE_LEN is specified as an argument for
443 * stringify_value().
444 */
2e38e61c
MY
445#define UNIX_LINE_LEN 256
446static void load_xinfo_from_proc_unix(ino_t netns_inode)
447{
448 char line[UNIX_LINE_LEN];
449 FILE *unix_fp;
450
451 unix_fp = fopen("/proc/net/unix", "r");
452 if (!unix_fp)
453 return;
454
455 if (fgets(line, sizeof(line), unix_fp) == NULL)
456 goto out;
b3649945 457 if (!(line[0] == 'N' && line[1] == 'u' && line[2] == 'm'))
2e38e61c
MY
458 /* Unexpected line */
459 goto out;
460
461 while (fgets(line, sizeof(line), unix_fp)) {
462 uint64_t flags;
463 uint32_t type;
464 unsigned int st;
465 unsigned long inode;
2e38e61c 466 struct unix_xinfo *ux;
eeaf7677 467 char path[UNIX_LINE_LEN + 1] = { 0 };
91a484fe 468
2e38e61c 469
eeaf7677
MY
470 if (sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %"
471 stringify_value(UNIX_LINE_LEN) "[^\n]",
2e38e61c
MY
472 &flags, &type, &st, &inode, path) < 4)
473 continue;
474
475 if (inode == 0)
476 continue;
477
8ff22ccb 478 ux = xcalloc(1, sizeof(*ux));
2e38e61c
MY
479 ux->sock.class = &unix_xinfo_class;
480 ux->sock.inode = (ino_t)inode;
481 ux->sock.netns_inode = netns_inode;
482
483 ux->acceptcon = !!flags;
484 ux->type = type;
485 ux->st = st;
91a484fe 486 xstrncpy(ux->path, path, sizeof(ux->path));
2e38e61c 487
2ac8d1a3 488 add_sock_info(&ux->sock);
2e38e61c
MY
489 }
490
491 out:
492 fclose(unix_fp);
493}
7b2a9be0
MY
494
495/*
496 * AF_INET
497 */
498struct inet_xinfo {
499 struct sock_xinfo sock;
643f30c7
MY
500 struct in_addr local_addr;
501 struct in_addr remote_addr;
7b2a9be0
MY
502};
503
9020c2e0 504static uint32_t kernel32_to_cpu(enum sysfs_byteorder byteorder, uint32_t v)
7b2a9be0 505{
9020c2e0
MY
506 if (byteorder == SYSFS_BYTEORDER_LITTLE)
507 return le32_to_cpu(v);
508 else
509 return be32_to_cpu(v);
7b2a9be0
MY
510}
511
1656da13
MY
512/*
513 * AF_INET6
514 */
515struct inet6_xinfo {
516 struct sock_xinfo sock;
517 struct in6_addr local_addr;
518 struct in6_addr remote_addr;
519};
520
7b2a9be0 521/*
4a2b51c1 522 * L4 abstract-layer for protocols stacked on IP and IP6.
7b2a9be0 523 */
303b41fe 524enum l4_state {
7b2a9be0
MY
525 /*
526 * Taken from linux/include/net/tcp_states.h.
527 * (GPL-2.0-or-later)
303b41fe
MY
528 *
529 * UDP and RAW sockets also uses the contents in Linux.
7b2a9be0
MY
530 */
531 TCP_ESTABLISHED = 1,
532 TCP_SYN_SENT,
533 TCP_SYN_RECV,
534 TCP_FIN_WAIT1,
535 TCP_FIN_WAIT2,
536 TCP_TIME_WAIT,
537 TCP_CLOSE,
538 TCP_CLOSE_WAIT,
539 TCP_LAST_ACK,
540 TCP_LISTEN,
541 TCP_CLOSING,
542 TCP_NEW_SYN_RECV,
543
544 TCP_MAX_STATES /* Leave at the end! */
545};
546
303b41fe 547static const char *l4_decode_state(enum l4_state st)
7b2a9be0 548{
86242cb0 549 const char * const table [] = {
7b2a9be0
MY
550 [TCP_ESTABLISHED] = "established",
551 [TCP_SYN_SENT] = "syn-sent",
552 [TCP_SYN_RECV] = "syn-recv",
553 [TCP_FIN_WAIT1] = "fin-wait1",
554 [TCP_FIN_WAIT2] = "fin-wait2",
555 [TCP_TIME_WAIT] = "time-wait",
556 [TCP_CLOSE] = "close",
557 [TCP_CLOSE_WAIT] = "close-wait",
558 [TCP_LAST_ACK] = "last-ack",
559 [TCP_LISTEN] = "listen",
560 [TCP_CLOSING] = "closing",
561 [TCP_NEW_SYN_RECV] = "new-syn-recv",
562 };
563
564 if (st < TCP_MAX_STATES)
565 return table[st];
566 return "unknown";
567}
568
4a2b51c1 569struct l4_xinfo {
1656da13
MY
570 union {
571 struct inet_xinfo inet;
572 struct inet6_xinfo inet6;
573 };
303b41fe 574 enum l4_state st;
4a2b51c1
MY
575};
576
2a4f2b1b 577enum l4_side { L4_LOCAL, L4_REMOTE };
1656da13 578enum l3_decorator { L3_DECO_START, L3_DECO_END };
2a4f2b1b 579
4a2b51c1
MY
580struct l4_xinfo_class {
581 struct sock_xinfo_class sock;
19e40223
MY
582 struct sock_xinfo *(*scan_line)(const struct sock_xinfo_class *,
583 char *,
584 ino_t,
585 enum sysfs_byteorder);
2a4f2b1b
MY
586 void * (*get_addr)(struct l4_xinfo *, enum l4_side);
587 bool (*is_any_addr)(void *);
588 int family;
1656da13 589 const char *l3_decorator[2];
4a2b51c1
MY
590};
591
838fa270
MY
592#define l3_fill_column_handler(L3, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
593 ({ \
594 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
595 struct l4_xinfo *l4 = (struct l4_xinfo *)SOCK_XINFO; \
596 void *n = NULL; \
597 char s[BUFSIZ]; \
598 bool r = false; \
599 \
600 switch (COLUMN_ID) { \
601 case COL_##L3##_LADDR: \
602 n = class->get_addr(l4, L4_LOCAL); \
603 break; \
604 case COL_##L3##_RADDR: \
605 n = class->get_addr(l4, L4_REMOTE); \
606 break; \
607 default: \
608 break; \
609 } \
610 \
611 if (n && inet_ntop(class->family, n, s, sizeof(s))) { \
e0dc84da 612 *STR = xstrdup(s); \
838fa270
MY
613 r = true; \
614 } \
615 r; \
616 })
617
7b2a9be0
MY
618/*
619 * TCP
620 */
621struct tcp_xinfo {
4a2b51c1 622 struct l4_xinfo l4;
7b2a9be0
MY
623 uint16_t local_port;
624 uint16_t remote_port;
7b2a9be0
MY
625};
626
7b2a9be0
MY
627static char *tcp_get_name(struct sock_xinfo *sock_xinfo,
628 struct sock *sock __attribute__((__unused__)))
629{
630 char *str = NULL;
7b2a9be0 631 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
8db07ebc 632 struct l4_xinfo *l4 = &tcp->l4;
303b41fe 633 const char *st_str = l4_decode_state(l4->st);
838fa270
MY
634 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
635 void *laddr = class->get_addr(l4, L4_LOCAL);
636 void *raddr = class->get_addr(l4, L4_REMOTE);
637 char local_s[BUFSIZ];
638 char remote_s[BUFSIZ];
1656da13
MY
639 const char *start = class->l3_decorator[L3_DECO_START];
640 const char *end = class->l3_decorator[L3_DECO_END];
7b2a9be0 641
838fa270 642 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
3b182ee7
MY
643 xasprintf(&str, "state=%s", st_str);
644 else if (l4->st == TCP_LISTEN
838fa270 645 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
b4e39841 646 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16,
3b182ee7 647 st_str,
1656da13 648 start, local_s, end, tcp->local_port);
7b2a9be0 649 else
b4e39841 650 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16" raddr=%s%s%s:%"PRIu16,
3b182ee7 651 st_str,
1656da13
MY
652 start, local_s, end, tcp->local_port,
653 start, remote_s, end, tcp->remote_port);
7b2a9be0
MY
654 return str;
655}
656
657static char *tcp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
658 struct sock *sock __attribute__((__unused__)))
659{
e0dc84da 660 return xstrdup("stream");
7b2a9be0
MY
661}
662
663static char *tcp_get_state(struct sock_xinfo *sock_xinfo,
664 struct sock *sock __attribute__((__unused__)))
665{
e0dc84da 666 return xstrdup(l4_decode_state(((struct l4_xinfo *)sock_xinfo)->st));
7b2a9be0
MY
667}
668
669static bool tcp_get_listening(struct sock_xinfo *sock_xinfo,
670 struct sock *sock __attribute__((__unused__)))
671{
8db07ebc 672 return ((struct l4_xinfo *)sock_xinfo)->st == TCP_LISTEN;
7b2a9be0
MY
673}
674
838fa270
MY
675#define l4_fill_column_handler(L4, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
676 ({ \
677 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
678 struct tcp_xinfo *tcp = (struct tcp_xinfo *)SOCK_XINFO; \
679 struct l4_xinfo *l4 = &tcp->l4; \
680 void *n = NULL; \
92a0dbce 681 bool has_laddr = false; \
73df46fc 682 unsigned short p; \
92a0dbce 683 bool has_lport = false; \
838fa270
MY
684 char s[BUFSIZ]; \
685 bool r = true; \
92a0dbce 686 \
838fa270 687 switch (COLUMN_ID) { \
cda2b2a0 688 case COL_##L4##_LADDR: \
838fa270 689 n = class->get_addr(l4, L4_LOCAL); \
92a0dbce 690 has_laddr = true; \
73df46fc 691 p = tcp->local_port; \
92a0dbce 692 /* FALL THROUGH */ \
cda2b2a0 693 case COL_##L4##_RADDR: \
92a0dbce 694 if (!has_laddr) { \
838fa270 695 n = class->get_addr(l4, L4_REMOTE); \
73df46fc 696 p = tcp->remote_port; \
92a0dbce 697 } \
838fa270 698 if (n && inet_ntop(class->family, n, s, sizeof(s))) \
b4e39841 699 xasprintf(STR, "%s%s%s:%"PRIu16, \
1656da13
MY
700 class->l3_decorator[L3_DECO_START], \
701 s, \
702 class->l3_decorator[L3_DECO_END], \
703 p); \
92a0dbce 704 break; \
cda2b2a0 705 case COL_##L4##_LPORT: \
73df46fc 706 p = tcp->local_port; \
92a0dbce
MY
707 has_lport = true; \
708 /* FALL THROUGH */ \
cda2b2a0 709 case COL_##L4##_RPORT: \
92a0dbce 710 if (!has_lport) \
73df46fc 711 p = tcp->remote_port; \
b4e39841 712 xasprintf(STR, "%"PRIu16, p); \
92a0dbce
MY
713 break; \
714 default: \
838fa270
MY
715 r = false; \
716 break; \
92a0dbce 717 } \
838fa270
MY
718 r; \
719 })
7b2a9be0 720
19e40223
MY
721static struct sock_xinfo *tcp_xinfo_scan_line(const struct sock_xinfo_class *class,
722 char * line,
723 ino_t netns_inode,
724 enum sysfs_byteorder byteorder)
725{
726 unsigned long local_addr;
727 unsigned long local_port;
728 unsigned long remote_addr;
729 unsigned long remote_port;
730 unsigned long st;
731 unsigned long long inode;
732 struct tcp_xinfo *tcp;
733 struct inet_xinfo *inet;
734 struct sock_xinfo *sock;
735
736 if (sscanf(line, "%*d: %lx:%lx %lx:%lx %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
737 &local_addr, &local_port, &remote_addr, &remote_port,
738 &st, &inode) != 6)
739 return NULL;
740
741 if (inode == 0)
742 return NULL;
743
8ff22ccb 744 tcp = xcalloc(1, sizeof(*tcp));
19e40223
MY
745 inet = &tcp->l4.inet;
746 sock = &inet->sock;
747 sock->class = class;
748 sock->inode = (ino_t)inode;
749 sock->netns_inode = netns_inode;
750 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
751 tcp->local_port = local_port;
752 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
753 tcp->remote_port = remote_port;
8db07ebc 754 tcp->l4.st = st;
19e40223
MY
755
756 return sock;
757}
758
2a4f2b1b
MY
759static void *tcp_xinfo_get_addr(struct l4_xinfo *l4, enum l4_side side)
760{
761 return (side == L4_LOCAL)
762 ? &l4->inet.local_addr
763 : &l4->inet.remote_addr;
764}
765
766static bool tcp_xinfo_is_any_addr(void *addr)
767{
768 return ((struct in_addr *)addr)->s_addr == INADDR_ANY;
769}
770
838fa270
MY
771static bool tcp_fill_column(struct proc *proc __attribute__((__unused__)),
772 struct sock_xinfo *sock_xinfo,
773 struct sock *sock __attribute__((__unused__)),
774 struct libscols_line *ln __attribute__((__unused__)),
775 int column_id,
776 size_t column_index __attribute__((__unused__)),
777 char **str)
778{
779 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
780 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
781}
782
4a2b51c1
MY
783static const struct l4_xinfo_class tcp_xinfo_class = {
784 .sock = {
785 .get_name = tcp_get_name,
786 .get_type = tcp_get_type,
787 .get_state = tcp_get_state,
788 .get_listening = tcp_get_listening,
789 .fill_column = tcp_fill_column,
790 .free = NULL,
791 },
19e40223 792 .scan_line = tcp_xinfo_scan_line,
2a4f2b1b
MY
793 .get_addr = tcp_xinfo_get_addr,
794 .is_any_addr = tcp_xinfo_is_any_addr,
795 .family = AF_INET,
1656da13 796 .l3_decorator = {"", ""},
7b2a9be0
MY
797};
798
cda2b2a0 799static bool L4_verify_initial_line(const char *line)
58d2f31e
MY
800{
801 /* At least we expect two white spaces. */
cb097fb7 802 if (strncmp(line, " ", 2) != 0)
58d2f31e
MY
803 return false;
804 line += 2;
805
806 /* Skip white spaces. */
4658bfb1 807 line = skip_space(line);
58d2f31e 808
621cf7e9 809 return strncmp(line, "sl", 2) == 0;
db79a100
TW
810}
811
7b2a9be0 812#define TCP_LINE_LEN 256
cda2b2a0 813static void load_xinfo_from_proc_inet_L4(ino_t netns_inode, const char *proc_file,
4a2b51c1 814 const struct l4_xinfo_class *class)
7b2a9be0
MY
815{
816 char line[TCP_LINE_LEN];
817 FILE *tcp_fp;
818
92a0dbce 819 tcp_fp = fopen(proc_file, "r");
7b2a9be0
MY
820 if (!tcp_fp)
821 return;
822
823 if (fgets(line, sizeof(line), tcp_fp) == NULL)
824 goto out;
cda2b2a0 825 if (!L4_verify_initial_line(line))
7b2a9be0
MY
826 /* Unexpected line */
827 goto out;
828
7578e03f 829 enum sysfs_byteorder byteorder = sysfs_get_byteorder(NULL);
db79a100 830
7b2a9be0 831 while (fgets(line, sizeof(line), tcp_fp)) {
19e40223
MY
832 struct sock_xinfo *sock = class->scan_line(&class->sock, line, netns_inode, byteorder);
833 if (sock)
834 add_sock_info(sock);
7b2a9be0
MY
835 }
836
837 out:
838 fclose(tcp_fp);
839}
92a0dbce 840
92a0dbce
MY
841static void load_xinfo_from_proc_tcp(ino_t netns_inode)
842{
cda2b2a0 843 load_xinfo_from_proc_inet_L4(netns_inode,
58d2f31e 844 "/proc/net/tcp",
92a0dbce
MY
845 &tcp_xinfo_class);
846}
847
848/*
849 * UDP
850 */
851static char *udp_get_name(struct sock_xinfo *sock_xinfo,
852 struct sock *sock __attribute__((__unused__)))
853{
854 char *str = NULL;
92a0dbce 855 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
8db07ebc 856 struct l4_xinfo *l4 = &tcp->l4;
8db07ebc 857 unsigned int st = l4->st;
303b41fe 858 const char *st_str = l4_decode_state(st);
838fa270
MY
859 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
860 void *laddr = class->get_addr(l4, L4_LOCAL);
861 void *raddr = class->get_addr(l4, L4_REMOTE);
862 char local_s[BUFSIZ];
863 char remote_s[BUFSIZ];
28cf2b21
MY
864 const char *start = class->l3_decorator[L3_DECO_START];
865 const char *end = class->l3_decorator[L3_DECO_END];
92a0dbce 866
838fa270 867 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
3b182ee7 868 xasprintf(&str, "state=%s", st_str);
838fa270
MY
869 else if ((class->is_any_addr(raddr) && tcp->remote_port == 0)
870 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
28cf2b21 871 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16,
3b182ee7 872 st_str,
28cf2b21 873 start, local_s, end, tcp->local_port);
92a0dbce 874 else
28cf2b21 875 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16" raddr=%s%s%s:%"PRIu16,
3b182ee7 876 st_str,
28cf2b21
MY
877 start, local_s, end, tcp->local_port,
878 start, remote_s, end, tcp->remote_port);
92a0dbce
MY
879 return str;
880}
881
882static char *udp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
883 struct sock *sock __attribute__((__unused__)))
884{
e0dc84da 885 return xstrdup("dgram");
92a0dbce
MY
886}
887
838fa270
MY
888static bool udp_fill_column(struct proc *proc __attribute__((__unused__)),
889 struct sock_xinfo *sock_xinfo,
890 struct sock *sock __attribute__((__unused__)),
891 struct libscols_line *ln __attribute__((__unused__)),
892 int column_id,
893 size_t column_index __attribute__((__unused__)),
894 char **str)
895{
896 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
897 || l4_fill_column_handler(UDP, sock_xinfo, column_id, str);
898}
899
4a2b51c1
MY
900static const struct l4_xinfo_class udp_xinfo_class = {
901 .sock = {
902 .get_name = udp_get_name,
903 .get_type = udp_get_type,
904 .get_state = tcp_get_state,
905 .get_listening = NULL,
906 .fill_column = udp_fill_column,
907 .free = NULL,
908 },
19e40223 909 .scan_line = tcp_xinfo_scan_line,
2a4f2b1b
MY
910 .get_addr = tcp_xinfo_get_addr,
911 .is_any_addr = tcp_xinfo_is_any_addr,
912 .family = AF_INET,
1656da13 913 .l3_decorator = {"", ""},
92a0dbce
MY
914};
915
92a0dbce
MY
916static void load_xinfo_from_proc_udp(ino_t netns_inode)
917{
cda2b2a0 918 load_xinfo_from_proc_inet_L4(netns_inode,
92a0dbce 919 "/proc/net/udp",
92a0dbce
MY
920 &udp_xinfo_class);
921}
0188afb3 922
c779f412
MY
923/*
924 * UDP-Lite
925 */
926static bool udplite_fill_column(struct proc *proc __attribute__((__unused__)),
927 struct sock_xinfo *sock_xinfo,
928 struct sock *sock __attribute__((__unused__)),
929 struct libscols_line *ln __attribute__((__unused__)),
930 int column_id,
931 size_t column_index __attribute__((__unused__)),
932 char **str)
933{
934 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
935 || l4_fill_column_handler(UDPLITE, sock_xinfo, column_id, str);
936}
937
938static const struct l4_xinfo_class udplite_xinfo_class = {
939 .sock = {
940 .get_name = udp_get_name,
941 .get_type = udp_get_type,
942 .get_state = tcp_get_state,
943 .get_listening = NULL,
944 .fill_column = udplite_fill_column,
945 .free = NULL,
946 },
947 .scan_line = tcp_xinfo_scan_line,
948 .get_addr = tcp_xinfo_get_addr,
949 .is_any_addr = tcp_xinfo_is_any_addr,
950 .family = AF_INET,
951 .l3_decorator = {"", ""},
952};
953
954static void load_xinfo_from_proc_udplite(ino_t netns_inode)
955{
956 load_xinfo_from_proc_inet_L4(netns_inode,
957 "/proc/net/udplite",
958 &udplite_xinfo_class);
959}
960
0188afb3
MY
961/*
962 * RAW
963 */
964struct raw_xinfo {
965 struct l4_xinfo l4;
966 uint16_t protocol;
967};
968
a7cba6f3
MY
969static char *raw_get_name_common(struct sock_xinfo *sock_xinfo,
970 struct sock *sock __attribute__((__unused__)),
971 const char *port_label)
0188afb3
MY
972{
973 char *str = NULL;
974 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
975 struct raw_xinfo *raw = ((struct raw_xinfo *)sock_xinfo);
976 struct l4_xinfo *l4 = &raw->l4;
303b41fe 977 const char *st_str = l4_decode_state(l4->st);
0188afb3
MY
978 void *laddr = class->get_addr(l4, L4_LOCAL);
979 void *raddr = class->get_addr(l4, L4_REMOTE);
980 char local_s[BUFSIZ];
981 char remote_s[BUFSIZ];
982
983 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
984 xasprintf(&str, "state=%s", st_str);
985 else if (class->is_any_addr(raddr)
986 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
a7cba6f3 987 xasprintf(&str, "state=%s %s=%"PRIu16" laddr=%s",
0188afb3 988 st_str,
a7cba6f3 989 port_label,
0188afb3
MY
990 raw->protocol, local_s);
991 else
a7cba6f3 992 xasprintf(&str, "state=%s %s=%"PRIu16" laddr=%s raddr=%s",
0188afb3 993 st_str,
a7cba6f3 994 port_label,
0188afb3
MY
995 raw->protocol, local_s, remote_s);
996 return str;
997}
998
a7cba6f3
MY
999static char *raw_get_name(struct sock_xinfo *sock_xinfo,
1000 struct sock *sock __attribute__((__unused__)))
1001{
1002 return raw_get_name_common(sock_xinfo, sock, "protocol");
1003}
1004
0188afb3
MY
1005static char *raw_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
1006 struct sock *sock __attribute__((__unused__)))
1007{
e0dc84da 1008 return xstrdup("raw");
0188afb3
MY
1009}
1010
1011static bool raw_fill_column(struct proc *proc __attribute__((__unused__)),
1012 struct sock_xinfo *sock_xinfo,
1013 struct sock *sock __attribute__((__unused__)),
1014 struct libscols_line *ln __attribute__((__unused__)),
1015 int column_id,
1016 size_t column_index __attribute__((__unused__)),
1017 char **str)
1018{
1019 if (l3_fill_column_handler(INET, sock_xinfo, column_id, str))
1020 return true;
1021
1022 if (column_id == COL_RAW_PROTOCOL) {
b4e39841 1023 xasprintf(str, "%"PRIu16,
73df46fc 1024 ((struct raw_xinfo *)sock_xinfo)->protocol);
0188afb3
MY
1025 return true;
1026 }
1027
1028 return false;
1029}
1030
1031static struct sock_xinfo *raw_xinfo_scan_line(const struct sock_xinfo_class *class,
1032 char * line,
1033 ino_t netns_inode,
1034 enum sysfs_byteorder byteorder)
1035{
1036 unsigned long local_addr;
1037 unsigned long protocol;
1038 unsigned long remote_addr;
1039 unsigned long st;
1040 unsigned long long inode;
1041 struct raw_xinfo *raw;
1042 struct inet_xinfo *inet;
1043 struct sock_xinfo *sock;
1044
1045 if (sscanf(line, "%*d: %lx:%lx %lx:%*x %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
1046 &local_addr, &protocol, &remote_addr,
1047 &st, &inode) != 5)
1048 return NULL;
1049
1050 if (inode == 0)
1051 return NULL;
1052
8ff22ccb 1053 raw = xcalloc(1, sizeof(*raw));
0188afb3
MY
1054 inet = &raw->l4.inet;
1055 sock = &inet->sock;
1056 sock->class = class;
1057 sock->inode = (ino_t)inode;
1058 sock->netns_inode = netns_inode;
1059 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
1060 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
1061 raw->protocol = protocol;
1062 raw->l4.st = st;
1063
1064 return sock;
1065}
1066
1067static const struct l4_xinfo_class raw_xinfo_class = {
1068 .sock = {
1069 .get_name = raw_get_name,
1070 .get_type = raw_get_type,
1071 .get_state = tcp_get_state,
1072 .get_listening = NULL,
1073 .fill_column = raw_fill_column,
1074 .free = NULL,
1075 },
1076 .scan_line = raw_xinfo_scan_line,
1077 .get_addr = tcp_xinfo_get_addr,
1078 .is_any_addr = tcp_xinfo_is_any_addr,
1079 .family = AF_INET,
1656da13 1080 .l3_decorator = {"", ""},
0188afb3
MY
1081};
1082
1083static void load_xinfo_from_proc_raw(ino_t netns_inode)
1084{
1085 load_xinfo_from_proc_inet_L4(netns_inode,
1086 "/proc/net/raw",
1087 &raw_xinfo_class);
1088}
1656da13 1089
a7cba6f3
MY
1090/*
1091 * PING
1092 */
1093static char *ping_get_name(struct sock_xinfo *sock_xinfo,
1094 struct sock *sock __attribute__((__unused__)))
1095{
1096 return raw_get_name_common(sock_xinfo, sock, "id");
1097}
1098
1099static char *ping_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
1100 struct sock *sock __attribute__((__unused__)))
1101{
e0dc84da 1102 return xstrdup("dgram");
a7cba6f3
MY
1103}
1104
1105static bool ping_fill_column(struct proc *proc __attribute__((__unused__)),
1106 struct sock_xinfo *sock_xinfo,
1107 struct sock *sock __attribute__((__unused__)),
1108 struct libscols_line *ln __attribute__((__unused__)),
1109 int column_id,
1110 size_t column_index __attribute__((__unused__)),
1111 char **str)
1112{
1113 if (l3_fill_column_handler(INET, sock_xinfo, column_id, str))
1114 return true;
1115
1116 if (column_id == COL_PING_ID) {
1117 xasprintf(str, "%"PRIu16,
1118 ((struct raw_xinfo *)sock_xinfo)->protocol);
1119 return true;
1120 }
1121
1122 return false;
1123}
1124
1125static const struct l4_xinfo_class ping_xinfo_class = {
1126 .sock = {
1127 .get_name = ping_get_name,
1128 .get_type = ping_get_type,
1129 .get_state = tcp_get_state,
1130 .get_listening = NULL,
1131 .fill_column = ping_fill_column,
1132 .free = NULL,
1133 },
1134 .scan_line = raw_xinfo_scan_line,
1135 .get_addr = tcp_xinfo_get_addr,
1136 .is_any_addr = tcp_xinfo_is_any_addr,
1137 .family = AF_INET,
1138 .l3_decorator = {"", ""},
1139};
1140
1141static void load_xinfo_from_proc_icmp(ino_t netns_inode)
1142{
1143 load_xinfo_from_proc_inet_L4(netns_inode,
1144 "/proc/net/icmp",
1145 &ping_xinfo_class);
1146}
1147
1656da13
MY
1148/*
1149 * TCP6
1150 */
1151static struct sock_xinfo *tcp6_xinfo_scan_line(const struct sock_xinfo_class *class,
1152 char * line,
1153 ino_t netns_inode,
1154 enum sysfs_byteorder byteorder)
1155{
1156 uint32_t local_addr[4];
1157 unsigned int local_port;
1158 uint32_t remote_addr[4];
1159 unsigned int remote_port;
1160 unsigned int st;
1161 unsigned long inode;
1162 struct tcp_xinfo *tcp;
1163 struct inet6_xinfo *inet6;
1164 struct sock_xinfo *sock;
1165
1166 if (sscanf(line,
1167 "%*d: "
1168 "%08x%08x%08x%08x:%04x "
1169 "%08x%08x%08x%08x:%04x "
1170 "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
1171 local_addr+0, local_addr+1, local_addr+2, local_addr+3, &local_port,
1172 remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3, &remote_port,
1173 &st, &inode) != 12)
1174 return NULL;
1175
1176 if (inode == 0)
1177 return NULL;
1178
8ff22ccb 1179 tcp = xmalloc(sizeof(*tcp));
1656da13
MY
1180 inet6 = &tcp->l4.inet6;
1181 sock = &inet6->sock;
1182 sock->class = class;
1183 sock->inode = (ino_t)inode;
1184 sock->netns_inode = netns_inode;
1185 tcp->local_port = local_port;
1186 for (int i = 0; i < 4; i++) {
1187 inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
1188 inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
1189 }
1190 tcp->remote_port = remote_port;
1191 tcp->l4.st = st;
1192
1193 return sock;
1194}
1195
1196static bool tcp6_fill_column(struct proc *proc __attribute__((__unused__)),
1197 struct sock_xinfo *sock_xinfo,
1198 struct sock *sock __attribute__((__unused__)),
1199 struct libscols_line *ln __attribute__((__unused__)),
1200 int column_id,
1201 size_t column_index __attribute__((__unused__)),
1202 char **str)
1203{
1204 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1205 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
1206}
1207
1208static void *tcp6_xinfo_get_addr(struct l4_xinfo * l4, enum l4_side side)
1209{
1210 return (side == L4_LOCAL)
1211 ? &l4->inet6.local_addr
1212 : &l4->inet6.remote_addr;
1213}
1214
1215static bool tcp6_xinfo_is_any_addr(void *addr)
1216{
1217 return IN6_ARE_ADDR_EQUAL(addr, &(struct in6_addr)IN6ADDR_ANY_INIT);
1218}
1219
1220static const struct l4_xinfo_class tcp6_xinfo_class = {
1221 .sock = {
1222 .get_name = tcp_get_name,
1223 .get_type = tcp_get_type,
1224 .get_state = tcp_get_state,
1225 .get_listening = tcp_get_listening,
1226 .fill_column = tcp6_fill_column,
1227 .free = NULL,
1228 },
1229 .scan_line = tcp6_xinfo_scan_line,
1230 .get_addr = tcp6_xinfo_get_addr,
1231 .is_any_addr = tcp6_xinfo_is_any_addr,
1232 .family = AF_INET6,
1233 .l3_decorator = {"[", "]"},
1234};
1235
1236static void load_xinfo_from_proc_tcp6(ino_t netns_inode)
1237{
1238 load_xinfo_from_proc_inet_L4(netns_inode,
1239 "/proc/net/tcp6",
1240 &tcp6_xinfo_class);
1241}
28cf2b21
MY
1242
1243/*
1244 * UDP6
1245 */
1246static bool udp6_fill_column(struct proc *proc __attribute__((__unused__)),
1247 struct sock_xinfo *sock_xinfo,
1248 struct sock *sock __attribute__((__unused__)),
1249 struct libscols_line *ln __attribute__((__unused__)),
1250 int column_id,
1251 size_t column_index __attribute__((__unused__)),
1252 char **str)
1253{
1254 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1255 || l4_fill_column_handler(UDP, sock_xinfo, column_id, str);
1256}
1257
1258static const struct l4_xinfo_class udp6_xinfo_class = {
1259 .sock = {
1260 .get_name = udp_get_name,
1261 .get_type = udp_get_type,
1262 .get_state = tcp_get_state,
1263 .get_listening = NULL,
1264 .fill_column = udp6_fill_column,
1265 .free = NULL,
1266 },
1267 .scan_line = tcp6_xinfo_scan_line,
1268 .get_addr = tcp6_xinfo_get_addr,
1269 .is_any_addr = tcp6_xinfo_is_any_addr,
1270 .family = AF_INET6,
1271 .l3_decorator = {"[", "]"},
1272};
1273
1274static void load_xinfo_from_proc_udp6(ino_t netns_inode)
1275{
1276 load_xinfo_from_proc_inet_L4(netns_inode,
1277 "/proc/net/udp6",
1278 &udp6_xinfo_class);
1279}
2dd373c3 1280
93bca151
MY
1281/*
1282 * UDPLITEv6
1283 */
1284static bool udplite6_fill_column(struct proc *proc __attribute__((__unused__)),
1285 struct sock_xinfo *sock_xinfo,
1286 struct sock *sock __attribute__((__unused__)),
1287 struct libscols_line *ln __attribute__((__unused__)),
1288 int column_id,
1289 size_t column_index __attribute__((__unused__)),
1290 char **str)
1291{
1292 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1293 || l4_fill_column_handler(UDPLITE, sock_xinfo, column_id, str);
1294}
1295
1296static const struct l4_xinfo_class udplite6_xinfo_class = {
1297 .sock = {
1298 .get_name = udp_get_name,
1299 .get_type = udp_get_type,
1300 .get_state = tcp_get_state,
1301 .get_listening = NULL,
1302 .fill_column = udplite6_fill_column,
1303 .free = NULL,
1304 },
1305 .scan_line = tcp6_xinfo_scan_line,
1306 .get_addr = tcp6_xinfo_get_addr,
1307 .is_any_addr = tcp6_xinfo_is_any_addr,
1308 .family = AF_INET6,
1309 .l3_decorator = {"[", "]"},
1310};
1311
1312static void load_xinfo_from_proc_udplite6(ino_t netns_inode)
1313{
1314 load_xinfo_from_proc_inet_L4(netns_inode,
1315 "/proc/net/udplite6",
1316 &udplite6_xinfo_class);
1317}
1318
2dd373c3
MY
1319/*
1320 * RAW6
1321 */
1322static struct sock_xinfo *raw6_xinfo_scan_line(const struct sock_xinfo_class *class,
1323 char * line,
1324 ino_t netns_inode,
1325 enum sysfs_byteorder byteorder)
1326{
1327 uint32_t local_addr[4];
1328 unsigned int protocol;
1329 uint32_t remote_addr[4];
1330 unsigned int st;
1331 unsigned long inode;
1332 struct raw_xinfo *raw;
1333 struct inet6_xinfo *inet6;
1334 struct sock_xinfo *sock;
1335
1336 if (sscanf(line,
1337 "%*d: "
1338 "%08x%08x%08x%08x:%04x "
1339 "%08x%08x%08x%08x:0000 "
1340 "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
1341 local_addr+0, local_addr+1, local_addr+2, local_addr+3, &protocol,
1342 remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3,
1343 &st, &inode) != 11)
1344 return NULL;
1345
1346 if (inode == 0)
1347 return NULL;
1348
1349 raw = xmalloc(sizeof(*raw));
1350 inet6 = &raw->l4.inet6;
1351 sock = &inet6->sock;
1352 sock->class = class;
1353 sock->inode = (ino_t)inode;
1354 sock->netns_inode = netns_inode;
1355 for (int i = 0; i < 4; i++) {
1356 inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
1357 inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
1358 }
1359 raw->protocol = protocol;
1360 raw->l4.st = st;
1361
1362 return sock;
1363}
1364
1365static bool raw6_fill_column(struct proc *proc __attribute__((__unused__)),
1366 struct sock_xinfo *sock_xinfo,
1367 struct sock *sock __attribute__((__unused__)),
1368 struct libscols_line *ln __attribute__((__unused__)),
1369 int column_id,
1370 size_t column_index __attribute__((__unused__)),
1371 char **str)
1372{
1373 struct raw_xinfo *raw;
1374
1375 if (l3_fill_column_handler(INET6, sock_xinfo, column_id, str))
1376 return true;
1377
1378 raw = (struct raw_xinfo *)sock_xinfo;
1379 if (column_id == COL_RAW_PROTOCOL) {
1380 xasprintf(str, "%"PRIu16, raw->protocol);
1381 return true;
1382 }
1383
1384 return false;
1385}
1386
1387static const struct l4_xinfo_class raw6_xinfo_class = {
1388 .sock = {
1389 .get_name = raw_get_name,
1390 .get_type = raw_get_type,
1391 .get_state = tcp_get_state,
1392 .get_listening = NULL,
1393 .fill_column = raw6_fill_column,
1394 .free = NULL,
1395 },
1396 .scan_line = raw6_xinfo_scan_line,
1397 .get_addr = tcp6_xinfo_get_addr,
1398 .is_any_addr = tcp6_xinfo_is_any_addr,
1399 .family = AF_INET6,
1400 .l3_decorator = {"[", "]"},
1401};
1402
1403static void load_xinfo_from_proc_raw6(ino_t netns_inode)
1404{
1405 load_xinfo_from_proc_inet_L4(netns_inode,
1406 "/proc/net/raw6",
1407 &raw6_xinfo_class);
1408}
0b1dfd03
MY
1409
1410/*
1411 * PINGv6
1412 */
1413static bool ping6_fill_column(struct proc *proc __attribute__((__unused__)),
1414 struct sock_xinfo *sock_xinfo,
1415 struct sock *sock __attribute__((__unused__)),
1416 struct libscols_line *ln __attribute__((__unused__)),
1417 int column_id,
1418 size_t column_index __attribute__((__unused__)),
1419 char **str)
1420{
1421 if (l3_fill_column_handler(INET6, sock_xinfo, column_id, str))
1422 return true;
1423
1424 if (column_id == COL_PING_ID) {
1425 xasprintf(str, "%"PRIu16,
1426 ((struct raw_xinfo *)sock_xinfo)->protocol);
1427 return true;
1428 }
1429
1430 return false;
1431}
1432
1433static const struct l4_xinfo_class ping6_xinfo_class = {
1434 .sock = {
1435 .get_name = ping_get_name,
1436 .get_type = ping_get_type,
1437 .get_state = tcp_get_state,
1438 .get_listening = NULL,
1439 .fill_column = ping6_fill_column,
1440 .free = NULL,
1441 },
1442 .scan_line = raw6_xinfo_scan_line,
1443 .get_addr = tcp6_xinfo_get_addr,
1444 .is_any_addr = tcp6_xinfo_is_any_addr,
1445 .family = AF_INET6,
1446 .l3_decorator = {"[", "]"},
1447};
1448
1449static void load_xinfo_from_proc_icmp6(ino_t netns_inode)
1450{
1451 load_xinfo_from_proc_inet_L4(netns_inode,
1452 "/proc/net/icmp6",
1453 &ping6_xinfo_class);
1454}
b53cc896
MY
1455
1456/*
1457 * NETLINK
1458 */
1459struct netlink_xinfo {
1460 struct sock_xinfo sock;
1461 uint16_t protocol;
1462 uint32_t lportid; /* netlink_diag may provide rportid. */
1463 uint32_t groups;
1464};
1465
1466static const char *netlink_decode_protocol(uint16_t protocol)
1467{
1468 switch (protocol) {
1469 case NETLINK_ROUTE:
1470 return "route";
1471 case NETLINK_UNUSED:
1472 return "unused";
1473 case NETLINK_USERSOCK:
1474 return "usersock";
1475 case NETLINK_FIREWALL:
1476 return "firewall";
1477 case NETLINK_SOCK_DIAG:
1478 return "sock_diag";
1479 case NETLINK_NFLOG:
1480 return "nflog";
1481 case NETLINK_XFRM:
1482 return "xfrm";
1483 case NETLINK_SELINUX:
1484 return "selinux";
1485 case NETLINK_ISCSI:
1486 return "iscsi";
1487 case NETLINK_AUDIT:
1488 return "audit";
1489 case NETLINK_FIB_LOOKUP:
1490 return "fib_lookup";
1491 case NETLINK_CONNECTOR:
1492 return "connector";
1493 case NETLINK_NETFILTER:
1494 return "netfilter";
1495 case NETLINK_IP6_FW:
1496 return "ip6_fw";
1497 case NETLINK_DNRTMSG:
1498 return "dnrtmsg";
1499 case NETLINK_KOBJECT_UEVENT:
1500 return "kobject_uevent";
1501 case NETLINK_GENERIC:
1502 return "generic";
1503 case NETLINK_SCSITRANSPORT:
1504 return "scsitransport";
1505 case NETLINK_ECRYPTFS:
1506 return "ecryptfs";
1507 case NETLINK_RDMA:
1508 return "rdma";
1509 case NETLINK_CRYPTO:
1510 return "crypto";
1511#ifdef NETLINK_SMC
1512 case NETLINK_SMC:
1513 return "smc";
1514#endif
1515 default:
1516 return "unknown";
1517 }
1518}
1519
1520static char *netlink_get_name(struct sock_xinfo *sock_xinfo,
1521 struct sock *sock __attribute__((__unused__)))
1522{
1523 struct netlink_xinfo *nl = (struct netlink_xinfo *)sock_xinfo;
1524 char *str = NULL;
1525 const char *protocol = netlink_decode_protocol(nl->protocol);
1526
1527 if (nl->groups)
1528 xasprintf(&str, "protocol=%s lport=%"PRIu16 " groups=%"PRIu32,
1529 protocol,
1530 nl->lportid, nl->groups);
1531 else
1532 xasprintf(&str, "protocol=%s lport=%"PRIu16,
1533 protocol,
1534 nl->lportid);
1535 return str;
1536}
1537
1538static char *netlink_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
1539 struct sock *sock __attribute__((__unused__)))
1540{
e0dc84da 1541 return xstrdup("raw");
b53cc896
MY
1542}
1543
1544static bool netlink_fill_column(struct proc *proc __attribute__((__unused__)),
1545 struct sock_xinfo *sock_xinfo,
1546 struct sock *sock __attribute__((__unused__)),
1547 struct libscols_line *ln __attribute__((__unused__)),
1548 int column_id,
1549 size_t column_index __attribute__((__unused__)),
1550 char **str)
1551{
1552 struct netlink_xinfo *nl = (struct netlink_xinfo *)sock_xinfo;
1553
1554 switch (column_id) {
1555 case COL_NETLINK_GROUPS:
1556 xasprintf(str, "%"PRIu32, nl->groups);
1557 return true;
1558 case COL_NETLINK_LPORT:
1559 xasprintf(str, "%"PRIu32, nl->lportid);
1560 return true;
1561 case COL_NETLINK_PROTOCOL:
e0dc84da 1562 *str = xstrdup(netlink_decode_protocol(nl->protocol));
b53cc896
MY
1563 return true;
1564 }
1565
1566 return false;
1567}
1568
1569static const struct sock_xinfo_class netlink_xinfo_class = {
1570 .get_name = netlink_get_name,
1571 .get_type = netlink_get_type,
1572 .get_state = NULL,
1573 .get_listening = NULL,
1574 .fill_column = netlink_fill_column,
1575 .free = NULL,
1576};
1577
1578static void load_xinfo_from_proc_netlink(ino_t netns_inode)
1579{
1580 char line[BUFSIZ];
1581 FILE *netlink_fp;
1582
1583 netlink_fp = fopen("/proc/net/netlink", "r");
1584 if (!netlink_fp)
1585 return;
1586
1587 if (fgets(line, sizeof(line), netlink_fp) == NULL)
1588 goto out;
1589 if (!(line[0] == 's' && line[1] == 'k'))
1590 /* Unexpected line */
1591 goto out;
1592
1593 while (fgets(line, sizeof(line), netlink_fp)) {
1594 uint16_t protocol;
1595 uint32_t lportid;
1596 uint32_t groups;
1597 unsigned long inode;
1598 struct netlink_xinfo *nl;
1599
1600 if (sscanf(line, "%*x %" SCNu16 " %" SCNu32 " %" SCNx32 " %*d %*d %*d %*d %*u %lu",
1601 &protocol, &lportid, &groups, &inode) < 4)
1602 continue;
1603
1604 if (inode == 0)
1605 continue;
1606
1607 nl = xcalloc(1, sizeof(*nl));
1608 nl->sock.class = &netlink_xinfo_class;
1609 nl->sock.inode = (ino_t)inode;
1610 nl->sock.netns_inode = netns_inode;
1611
1612 nl->protocol = protocol;
1613 nl->lportid = lportid;
1614 nl->groups = groups;
1615
1616 add_sock_info(&nl->sock);
1617 }
1618
1619 out:
1620 fclose(netlink_fp);
1621}
adfc156a
MY
1622
1623/*
1624 * PACKET
1625 */
1626struct packet_xinfo {
1627 struct sock_xinfo sock;
1628 uint16_t type;
1629 uint16_t protocol;
1630 unsigned int iface;
1631};
1632
1633static const char *packet_decode_protocol(uint16_t proto)
1634{
1635 switch (proto) {
1636 case 0:
1637 return NULL;
1638 case ETH_P_802_3:
1639 return "802_3";
1640 case ETH_P_AX25:
1641 return "ax25";
1642 case ETH_P_ALL:
1643 return "all";
1644 case ETH_P_802_2:
1645 return "802_2";
1646 case ETH_P_SNAP:
1647 return "snap";
1648 case ETH_P_DDCMP:
1649 return "ddcmp";
1650 case ETH_P_WAN_PPP:
1651 return "wan_ppp";
1652 case ETH_P_PPP_MP:
1653 return "ppp_mp";
1654 case ETH_P_LOCALTALK:
1655 return "localtalk";
1656 case ETH_P_CAN:
1657 return "can";
1658 case ETH_P_CANFD:
1659 return "canfd";
1660#ifdef ETH_P_CANXL
1661 case ETH_P_CANXL:
1662 return "canxl";
1663#endif
1664 case ETH_P_PPPTALK:
1665 return "ppptalk";
1666 case ETH_P_TR_802_2:
1667 return "tr_802_2";
1668 case ETH_P_MOBITEX:
1669 return "mobitex";
1670 case ETH_P_CONTROL:
1671 return "control";
1672 case ETH_P_IRDA:
1673 return "irda";
1674 case ETH_P_ECONET:
1675 return "econet";
1676 case ETH_P_HDLC:
1677 return "hdlc";
1678 case ETH_P_ARCNET:
1679 return "arcnet";
1680 case ETH_P_DSA:
1681 return "dsa";
1682 case ETH_P_TRAILER:
1683 return "trailer";
1684 case ETH_P_PHONET:
1685 return "phonet";
1686 case ETH_P_IEEE802154:
1687 return "ieee802154";
1688 case ETH_P_CAIF:
1689 return "caif";
1690#ifdef ETH_P_XDSA
1691 case ETH_P_XDSA:
1692 return "xdsa";
1693#endif
1694#ifdef ETH_P_MAP
1695 case ETH_P_MAP:
1696 return "map";
1697#endif
1698#ifdef ETH_P_MCTP
1699 case ETH_P_MCTP:
1700 return "mctp";
1701#endif
1702 case ETH_P_LOOP:
1703 return "loop";
1704 case ETH_P_PUP:
1705 return "pup";
1706 case ETH_P_PUPAT:
1707 return "pupat";
1708#ifdef ETH_P_TSN
1709 case ETH_P_TSN:
1710 return "tsn";
1711#endif
1712#ifdef ETH_P_ERSPAN2
1713 case ETH_P_ERSPAN2:
1714 return "erspan2";
1715#endif
1716 case ETH_P_IP:
1717 return "ip";
1718 case ETH_P_X25:
1719 return "x25";
1720 case ETH_P_ARP:
1721 return "arp";
1722 case ETH_P_BPQ:
1723 return "bpq";
1724 case ETH_P_IEEEPUP:
1725 return "ieeepup";
1726 case ETH_P_IEEEPUPAT:
1727 return "ieeepupat";
1728 case ETH_P_BATMAN:
1729 return "batman";
1730 case ETH_P_DEC:
1731 return "dec";
1732 case ETH_P_DNA_DL:
1733 return "dna_dl";
1734 case ETH_P_DNA_RC:
1735 return "dna_rc";
1736 case ETH_P_DNA_RT:
1737 return "dna_rt";
1738 case ETH_P_LAT:
1739 return "lat";
1740 case ETH_P_DIAG:
1741 return "diag";
1742 case ETH_P_CUST:
1743 return "cust";
1744 case ETH_P_SCA:
1745 return "sca";
1746 case ETH_P_TEB:
1747 return "teb";
1748 case ETH_P_RARP:
1749 return "rarp";
1750 case ETH_P_ATALK:
1751 return "atalk";
1752 case ETH_P_AARP:
1753 return "aarp";
1754 case ETH_P_8021Q:
1755 return "8021q";
1756#ifdef ETH_P_ERSPAN
1757 case ETH_P_ERSPAN:
1758 return "erspan";
1759#endif
1760 case ETH_P_IPX:
1761 return "ipx";
1762 case ETH_P_IPV6:
1763 return "ipv6";
1764 case ETH_P_PAUSE:
1765 return "pause";
1766 case ETH_P_SLOW:
1767 return "slow";
1768 case ETH_P_WCCP:
1769 return "wccp";
1770 case ETH_P_MPLS_UC:
1771 return "mpls_uc";
1772 case ETH_P_MPLS_MC:
1773 return "mpls_mc";
1774 case ETH_P_ATMMPOA:
1775 return "atmmpoa";
1776#ifdef ETH_P_PPP_DISC
1777 case ETH_P_PPP_DISC:
1778 return "ppp_disc";
1779#endif
1780#ifdef ETH_P_PPP_SES
1781 case ETH_P_PPP_SES:
1782 return "ppp_ses";
1783#endif
1784 case ETH_P_LINK_CTL:
1785 return "link_ctl";
1786 case ETH_P_ATMFATE:
1787 return "atmfate";
1788 case ETH_P_PAE:
1789 return "pae";
1790#ifdef ETH_P_PROFINET
1791 case ETH_P_PROFINET:
1792 return "profinet";
1793#endif
1794#ifdef ETH_P_REALTEK
1795 case ETH_P_REALTEK:
1796 return "realtek";
1797#endif
1798 case ETH_P_AOE:
1799 return "aoe";
1800#ifdef ETH_P_ETHERCAT
1801 case ETH_P_ETHERCAT:
1802 return "ethercat";
1803#endif
1804 case ETH_P_8021AD:
1805 return "8021ad";
1806 case ETH_P_802_EX1:
1807 return "802_ex1";
1808#ifdef ETH_P_PREAUTH
1809 case ETH_P_PREAUTH:
1810 return "preauth";
1811#endif
1812 case ETH_P_TIPC:
1813 return "tipc";
1814#ifdef ETH_P_LLDP
1815 case ETH_P_LLDP:
1816 return "lldp";
1817#endif
1818#ifdef ETH_P_MRP
1819 case ETH_P_MRP:
1820 return "mrp";
1821#endif
1822#ifdef ETH_P_MACSEC
1823 case ETH_P_MACSEC:
1824 return "macsec";
1825#endif
1826 case ETH_P_8021AH:
1827 return "8021ah";
1828#ifdef ETH_P_MVRP
1829 case ETH_P_MVRP:
1830 return "mvrp";
1831#endif
1832 case ETH_P_1588:
1833 return "1588";
1834#ifdef ETH_P_NCSI
1835 case ETH_P_NCSI:
1836 return "ncsi";
1837#endif
1838#ifdef ETH_P_PRP
1839 case ETH_P_PRP:
1840 return "prp";
1841#endif
1842#ifdef ETH_P_CFM
1843 case ETH_P_CFM:
1844 return "cfm";
1845#endif
1846 case ETH_P_FCOE:
1847 return "fcoe";
1848#ifdef ETH_P_IBOE
1849 case ETH_P_IBOE:
1850 return "iboe";
1851#endif
1852 case ETH_P_TDLS:
1853 return "tdls";
1854 case ETH_P_FIP:
1855 return "fip";
1856#ifdef ETH_P_80221
1857 case ETH_P_80221:
1858 return "80221";
1859#endif
1860#ifdef ETH_P_HSR
1861 case ETH_P_HSR:
1862 return "hsr";
1863#endif
1864#ifdef ETH_P_NSH
1865 case ETH_P_NSH:
1866 return "nsh";
1867#endif
1868#ifdef ETH_P_LOOPBACK
1869 case ETH_P_LOOPBACK:
1870 return "loopback";
1871#endif
1872 case ETH_P_QINQ1:
1873 return "qinq1";
1874 case ETH_P_QINQ2:
1875 return "qinq2";
1876 case ETH_P_QINQ3:
1877 return "qinq3";
1878 case ETH_P_EDSA:
1879 return "edsa";
1880#ifdef ETH_P_DSA_8021Q
1881 case ETH_P_DSA_8021Q:
1882 return "dsa_8021q";
1883#endif
1884#ifdef ETH_P_DSA_A5PSW
1885 case ETH_P_DSA_A5PSW:
1886 return "dsa_a5psw";
1887#endif
1888#ifdef ETH_P_IFE
1889 case ETH_P_IFE:
1890 return "ife";
1891#endif
1892 case ETH_P_AF_IUCV:
1893 return "af_iucv";
1894#ifdef ETH_P_802_3_MIN
1895 case ETH_P_802_3_MIN:
1896 return "802_3_min";
1897#endif
1898 default:
1899 return "unknown";
1900 }
1901}
1902
1903static char *packet_get_name(struct sock_xinfo *sock_xinfo,
1904 struct sock *sock __attribute__((__unused__)))
1905{
1906 struct packet_xinfo *pkt = (struct packet_xinfo *)sock_xinfo;
1907 char *str = NULL;
1908 const char *type = sock_decode_type(pkt->type);
1909 const char *proto = packet_decode_protocol(pkt->protocol);
1910 const char *iface = get_iface_name(sock_xinfo->netns_inode,
1911 pkt->iface);
1912
1913 if (iface && proto)
1914 xasprintf(&str, "type=%s protocol=%s iface=%s",
1915 type, proto, iface);
1916 else if (proto)
1917 xasprintf(&str, "type=%s protocol=%s",
1918 type, proto);
1919 else if (iface)
1920 xasprintf(&str, "type=%s iface=%s",
1921 type, iface);
1922 else
1923 xasprintf(&str, "type=%s", type);
1924
1925 return str;
1926}
1927
1928static char *packet_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
1929 struct sock *sock __attribute__((__unused__)))
1930{
1931 const char *str;
1932 struct packet_xinfo *pkt = (struct packet_xinfo *)sock_xinfo;
1933
1934 str = sock_decode_type(pkt->type);
1935 return xstrdup(str);
1936}
1937
1938static bool packet_fill_column(struct proc *proc __attribute__((__unused__)),
1939 struct sock_xinfo *sock_xinfo,
1940 struct sock *sock __attribute__((__unused__)),
1941 struct libscols_line *ln __attribute__((__unused__)),
1942 int column_id,
1943 size_t column_index __attribute__((__unused__)),
1944 char **str)
1945{
1946 struct packet_xinfo *pkt = (struct packet_xinfo *)sock_xinfo;
1947
1948 switch (column_id) {
1949 case COL_PACKET_IFACE: {
1950 const char *iface;
1951 iface = get_iface_name(sock_xinfo->netns_inode,
1952 pkt->iface);
1953 if (iface) {
1954 *str = xstrdup(iface);
1955 return true;
1956 }
1957 break;
1958 }
1959 case COL_PACKET_PROTOCOL: {
1960 const char *proto;
1961 proto = packet_decode_protocol(pkt->protocol);
1962 if (proto) {
1963 *str = xstrdup(proto);
1964 return true;
1965 }
1966 break;
1967 }
1968 default:
1969 break;
1970 }
1971 return false;
1972}
1973
1974static const struct sock_xinfo_class packet_xinfo_class = {
1975 .get_name = packet_get_name,
1976 .get_type = packet_get_type,
1977 .get_state = NULL,
1978 .get_listening = NULL,
1979 .fill_column = packet_fill_column,
1980 .free = NULL,
1981};
1982
1983static void load_xinfo_from_proc_packet(ino_t netns_inode)
1984{
1985 char line[BUFSIZ];
1986 FILE *packet_fp;
1987
1988 packet_fp = fopen("/proc/net/packet", "r");
1989 if (!packet_fp)
1990 return;
1991
1992 if (fgets(line, sizeof(line), packet_fp) == NULL)
1993 goto out;
1994 if (!(line[0] == 's' && line[1] == 'k'))
1995 /* Unexpected line */
1996 goto out;
1997
1998 while (fgets(line, sizeof(line), packet_fp)) {
1999 uint16_t type;
2000 uint16_t protocol;
2001 unsigned int iface;
2002 unsigned long inode;
2003 struct packet_xinfo *pkt;
2004
2005 if (sscanf(line, "%*x %*d %" SCNu16 " %" SCNu16 " %u %*d %*d %*d %lu",
2006 &type, &protocol, &iface, &inode) < 4)
2007 continue;
2008
2009 pkt = xcalloc(1, sizeof(*pkt));
2010 pkt->sock.class = &packet_xinfo_class;
2011 pkt->sock.inode = (ino_t)inode;
2012 pkt->sock.netns_inode = netns_inode;
2013
2014 pkt->type = type;
2015 pkt->protocol = protocol;
2016 pkt->iface = iface;
2017
2018 add_sock_info(&pkt->sock);
2019 }
2020
2021 out:
2022 fclose(packet_fp);
2023}