]> git.ipfire.org Git - thirdparty/util-linux.git/blame - misc-utils/lsfd-sock-xinfo.c
lsfd: (style) reformat colinfo array
[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) */
73df46fc 24#include <inttypes.h> /* SCNu16 */
2e38e61c 25#include <linux/net.h> /* SS_* */
b53cc896 26#include <linux/netlink.h> /* NETLINK_* */
2e38e61c 27#include <linux/un.h> /* UNIX_PATH_MAX */
0ee16e43
MY
28#include <sched.h> /* for setns(2) */
29#include <search.h>
2e38e61c
MY
30#include <stdint.h>
31#include <string.h>
32#include <sys/socket.h> /* SOCK_* */
0ee16e43
MY
33
34#include "xalloc.h"
35#include "nls.h"
36#include "libsmartcols.h"
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);
2e38e61c 55
0ee16e43 56static int self_netns_fd = -1;
44f9aec7 57static struct stat self_netns_sb;
0ee16e43
MY
58
59static void *xinfo_tree; /* for tsearch/tfind */
60static void *netns_tree;
61
62static int netns_compare(const void *a, const void *b)
63{
64 if (*(ino_t *)a < *(ino_t *)b)
65 return -1;
66 else if (*(ino_t *)a > *(ino_t *)b)
67 return 1;
68 else
69 return 0;
70}
71
72static bool is_sock_xinfo_loaded(ino_t netns)
73{
74 return tfind(&netns, &netns_tree, netns_compare)? true: false;
75}
76
77static void mark_sock_xinfo_loaded(ino_t ino)
78{
79 ino_t *netns = xmalloc(sizeof(ino));
80 ino_t **tmp;
81
82 *netns = ino;
83 tmp = tsearch(netns, &netns_tree, netns_compare);
84 if (tmp == NULL)
85 errx(EXIT_FAILURE, _("failed to allocate memory"));
86}
87
2e38e61c 88static void load_sock_xinfo_no_nsswitch(ino_t netns)
0ee16e43 89{
2e38e61c 90 load_xinfo_from_proc_unix(netns);
7b2a9be0 91 load_xinfo_from_proc_tcp(netns);
92a0dbce 92 load_xinfo_from_proc_udp(netns);
c779f412 93 load_xinfo_from_proc_udplite(netns);
0188afb3 94 load_xinfo_from_proc_raw(netns);
1656da13 95 load_xinfo_from_proc_tcp6(netns);
28cf2b21 96 load_xinfo_from_proc_udp6(netns);
93bca151 97 load_xinfo_from_proc_udplite6(netns);
2dd373c3 98 load_xinfo_from_proc_raw6(netns);
a7cba6f3 99 load_xinfo_from_proc_icmp(netns);
0b1dfd03 100 load_xinfo_from_proc_icmp6(netns);
b53cc896 101 load_xinfo_from_proc_netlink(netns);
0ee16e43
MY
102}
103
104static void load_sock_xinfo_with_fd(int fd, ino_t netns)
105{
b3649945 106 if (setns(fd, CLONE_NEWNET) == 0) {
0ee16e43 107 load_sock_xinfo_no_nsswitch(netns);
b3649945 108 setns(self_netns_fd, CLONE_NEWNET);
0ee16e43
MY
109 }
110}
111
112void load_sock_xinfo(struct path_cxt *pc, const char *name, ino_t netns)
113{
114 if (self_netns_fd == -1)
115 return;
116
117 if (!is_sock_xinfo_loaded(netns)) {
118 int fd;
119
120 mark_sock_xinfo_loaded(netns);
121 fd = ul_path_open(pc, O_RDONLY, name);
122 if (fd < 0)
123 return;
124
125 load_sock_xinfo_with_fd(fd, netns);
126 close(fd);
127 }
128}
129
130void initialize_sock_xinfos(void)
131{
132 struct path_cxt *pc;
133 DIR *dir;
134 struct dirent *d;
135
136 self_netns_fd = open("/proc/self/ns/net", O_RDONLY);
137
138 if (self_netns_fd < 0)
139 load_sock_xinfo_no_nsswitch(0);
140 else {
141 if (fstat(self_netns_fd, &self_netns_sb) == 0) {
142 mark_sock_xinfo_loaded(self_netns_sb.st_ino);
143 load_sock_xinfo_no_nsswitch(self_netns_sb.st_ino);
144 }
145 }
146
147 /* Load /proc/net/{unix,...} of the network namespace
148 * specified with netns files under /var/run/netns/.
149 *
150 * `ip netns' command pins a network namespace on
151 * /var/run/netns.
152 */
153 pc = ul_new_path("/var/run/netns");
154 if (!pc)
155 err(EXIT_FAILURE, _("failed to alloc path context for /var/run/netns"));
156 dir = ul_path_opendir(pc, NULL);
157 if (dir == NULL) {
158 ul_unref_path(pc);
159 return;
160 }
161 while ((d = readdir(dir))) {
162 struct stat sb;
163 int fd;
164 if (ul_path_stat(pc, &sb, 0, d->d_name) < 0)
165 continue;
166 if (is_sock_xinfo_loaded(sb.st_ino))
167 continue;
168 mark_sock_xinfo_loaded(sb.st_ino);
169 fd = ul_path_open(pc, O_RDONLY, d->d_name);
170 if (fd < 0)
171 continue;
172 load_sock_xinfo_with_fd(fd, sb.st_ino);
173 close(fd);
174 }
175 closedir(dir);
176 ul_unref_path(pc);
177}
178
b3649945 179static void free_sock_xinfo(void *node)
0ee16e43
MY
180{
181 struct sock_xinfo *xinfo = node;
182 if (xinfo->class->free)
b3649945 183 xinfo->class->free(xinfo);
0ee16e43
MY
184 free(node);
185}
186
187void finalize_sock_xinfos(void)
188{
189 if (self_netns_fd != -1)
190 close(self_netns_fd);
191 tdestroy(netns_tree, free);
192 tdestroy(xinfo_tree, free_sock_xinfo);
193}
194
195static int xinfo_compare(const void *a, const void *b)
196{
197 if (((struct sock_xinfo *)a)->inode < ((struct sock_xinfo *)b)->inode)
198 return -1;
199 if (((struct sock_xinfo *)a)->inode > ((struct sock_xinfo *)b)->inode)
200 return 1;
201 return 0;
202}
203
2e38e61c
MY
204static void add_sock_info(struct sock_xinfo *xinfo)
205{
206 struct sock_xinfo **tmp = tsearch(xinfo, &xinfo_tree, xinfo_compare);
207
208 if (tmp == NULL)
209 errx(EXIT_FAILURE, _("failed to allocate memory"));
210}
211
0ee16e43
MY
212struct sock_xinfo *get_sock_xinfo(ino_t netns_inode)
213{
214 struct sock_xinfo **xinfo = tfind(&netns_inode, &xinfo_tree, xinfo_compare);
215
216 if (xinfo)
217 return *xinfo;
218 return NULL;
219}
220
221bool is_nsfs_dev(dev_t dev)
222{
621cf7e9 223 return dev == self_netns_sb.st_dev;
0ee16e43 224}
2e38e61c
MY
225
226static const char *sock_decode_type(uint16_t type)
227{
228 switch (type) {
229 case SOCK_STREAM:
230 return "stream";
231 case SOCK_DGRAM:
232 return "dgram";
233 case SOCK_RAW:
234 return "raw";
235 case SOCK_RDM:
236 return "rdm";
237 case SOCK_SEQPACKET:
238 return "seqpacket";
239 case SOCK_DCCP:
240 return "dccp";
241 case SOCK_PACKET:
242 return "packet";
243 default:
244 return "unknown";
245 }
246}
247
248/*
249 * Protocol specific code
250 */
251
252/*
253 * UNIX
254 */
255struct unix_xinfo {
256 struct sock_xinfo sock;
257 int acceptcon; /* flags */
258 uint16_t type;
259 uint8_t st;
260 char path[
261 UNIX_PATH_MAX
262 + 1 /* for @ */
263 + 1 /* \0? */
264 ];
265};
266
267static const char *unix_decode_state(uint8_t st)
268{
269 switch (st) {
270 case SS_FREE:
271 return "free";
272 case SS_UNCONNECTED:
273 return "unconnected";
274 case SS_CONNECTING:
275 return "connecting";
276 case SS_CONNECTED:
277 return "connected";
278 case SS_DISCONNECTING:
279 return "disconnecting";
280 default:
281 return "unknown";
282 }
283}
284
285static char *unix_get_name(struct sock_xinfo *sock_xinfo,
286 struct sock *sock)
287{
288 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
289 const char *state = unix_decode_state(ux->st);
290 char *str = NULL;
291
292 if (sock->protoname && (strcmp(sock->protoname, "UNIX-STREAM") == 0))
293 xasprintf(&str, "state=%s%s%s",
294 (ux->acceptcon)? "listen": state,
295 *(ux->path)? " path=": "",
296 *(ux->path)? ux->path: "");
297 else
298 xasprintf(&str, "state=%s%s%s type=%s",
299 (ux->acceptcon)? "listen": state,
300 *(ux->path)? " path=": "",
301 *(ux->path)? ux->path: "",
302 sock_decode_type(ux->type));
303 return str;
304}
305
306static char *unix_get_type(struct sock_xinfo *sock_xinfo,
307 struct sock *sock __attribute__((__unused__)))
308{
309 const char *str;
310 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
311
312 str = sock_decode_type(ux->type);
e0dc84da 313 return xstrdup(str);
2e38e61c
MY
314}
315
316static char *unix_get_state(struct sock_xinfo *sock_xinfo,
317 struct sock *sock __attribute__((__unused__)))
318{
319 const char *str;
320 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
321
322 if (ux->acceptcon)
e0dc84da 323 return xstrdup("listen");
2e38e61c
MY
324
325 str = unix_decode_state(ux->st);
e0dc84da 326 return xstrdup(str);
2e38e61c
MY
327}
328
45d61bff
MY
329static bool unix_get_listening(struct sock_xinfo *sock_xinfo,
330 struct sock *sock __attribute__((__unused__)))
331{
332 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
333
334 return ux->acceptcon;
335}
336
2e38e61c
MY
337static bool unix_fill_column(struct proc *proc __attribute__((__unused__)),
338 struct sock_xinfo *sock_xinfo,
339 struct sock *sock __attribute__((__unused__)),
340 struct libscols_line *ln __attribute__((__unused__)),
341 int column_id,
342 size_t column_index __attribute__((__unused__)),
343 char **str)
344{
345 struct unix_xinfo *ux = (struct unix_xinfo *)sock_xinfo;
346
854ddd0d 347 switch (column_id) {
2e38e61c
MY
348 case COL_UNIX_PATH:
349 if (*ux->path) {
e0dc84da 350 *str = xstrdup(ux->path);
2e38e61c
MY
351 return true;
352 }
353 break;
354 }
355
356 return false;
357}
358
54a06438 359static const struct sock_xinfo_class unix_xinfo_class = {
2e38e61c
MY
360 .get_name = unix_get_name,
361 .get_type = unix_get_type,
362 .get_state = unix_get_state,
45d61bff 363 .get_listening = unix_get_listening,
2e38e61c
MY
364 .fill_column = unix_fill_column,
365 .free = NULL,
366};
367
e8e14a28 368/* UNIX_LINE_LEN need at least 54 + 21 + UNIX_PATH_MAX + 1.
eeaf7677
MY
369 *
370 * An actual number must be used in this definition
371 * since UNIX_LINE_LEN is specified as an argument for
372 * stringify_value().
373 */
2e38e61c
MY
374#define UNIX_LINE_LEN 256
375static void load_xinfo_from_proc_unix(ino_t netns_inode)
376{
377 char line[UNIX_LINE_LEN];
378 FILE *unix_fp;
379
380 unix_fp = fopen("/proc/net/unix", "r");
381 if (!unix_fp)
382 return;
383
384 if (fgets(line, sizeof(line), unix_fp) == NULL)
385 goto out;
b3649945 386 if (!(line[0] == 'N' && line[1] == 'u' && line[2] == 'm'))
2e38e61c
MY
387 /* Unexpected line */
388 goto out;
389
390 while (fgets(line, sizeof(line), unix_fp)) {
391 uint64_t flags;
392 uint32_t type;
393 unsigned int st;
394 unsigned long inode;
2e38e61c 395 struct unix_xinfo *ux;
eeaf7677 396 char path[UNIX_LINE_LEN + 1] = { 0 };
91a484fe 397
2e38e61c 398
eeaf7677
MY
399 if (sscanf(line, "%*x: %*x %*x %" SCNx64 " %x %x %lu %"
400 stringify_value(UNIX_LINE_LEN) "[^\n]",
2e38e61c
MY
401 &flags, &type, &st, &inode, path) < 4)
402 continue;
403
404 if (inode == 0)
405 continue;
406
8ff22ccb 407 ux = xcalloc(1, sizeof(*ux));
2e38e61c
MY
408 ux->sock.class = &unix_xinfo_class;
409 ux->sock.inode = (ino_t)inode;
410 ux->sock.netns_inode = netns_inode;
411
412 ux->acceptcon = !!flags;
413 ux->type = type;
414 ux->st = st;
91a484fe 415 xstrncpy(ux->path, path, sizeof(ux->path));
2e38e61c 416
2ac8d1a3 417 add_sock_info(&ux->sock);
2e38e61c
MY
418 }
419
420 out:
421 fclose(unix_fp);
422}
7b2a9be0
MY
423
424/*
425 * AF_INET
426 */
427struct inet_xinfo {
428 struct sock_xinfo sock;
643f30c7
MY
429 struct in_addr local_addr;
430 struct in_addr remote_addr;
7b2a9be0
MY
431};
432
9020c2e0 433static uint32_t kernel32_to_cpu(enum sysfs_byteorder byteorder, uint32_t v)
7b2a9be0 434{
9020c2e0
MY
435 if (byteorder == SYSFS_BYTEORDER_LITTLE)
436 return le32_to_cpu(v);
437 else
438 return be32_to_cpu(v);
7b2a9be0
MY
439}
440
1656da13
MY
441/*
442 * AF_INET6
443 */
444struct inet6_xinfo {
445 struct sock_xinfo sock;
446 struct in6_addr local_addr;
447 struct in6_addr remote_addr;
448};
449
7b2a9be0 450/*
4a2b51c1 451 * L4 abstract-layer for protocols stacked on IP and IP6.
7b2a9be0 452 */
303b41fe 453enum l4_state {
7b2a9be0
MY
454 /*
455 * Taken from linux/include/net/tcp_states.h.
456 * (GPL-2.0-or-later)
303b41fe
MY
457 *
458 * UDP and RAW sockets also uses the contents in Linux.
7b2a9be0
MY
459 */
460 TCP_ESTABLISHED = 1,
461 TCP_SYN_SENT,
462 TCP_SYN_RECV,
463 TCP_FIN_WAIT1,
464 TCP_FIN_WAIT2,
465 TCP_TIME_WAIT,
466 TCP_CLOSE,
467 TCP_CLOSE_WAIT,
468 TCP_LAST_ACK,
469 TCP_LISTEN,
470 TCP_CLOSING,
471 TCP_NEW_SYN_RECV,
472
473 TCP_MAX_STATES /* Leave at the end! */
474};
475
303b41fe 476static const char *l4_decode_state(enum l4_state st)
7b2a9be0
MY
477{
478 const char * table [] = {
479 [TCP_ESTABLISHED] = "established",
480 [TCP_SYN_SENT] = "syn-sent",
481 [TCP_SYN_RECV] = "syn-recv",
482 [TCP_FIN_WAIT1] = "fin-wait1",
483 [TCP_FIN_WAIT2] = "fin-wait2",
484 [TCP_TIME_WAIT] = "time-wait",
485 [TCP_CLOSE] = "close",
486 [TCP_CLOSE_WAIT] = "close-wait",
487 [TCP_LAST_ACK] = "last-ack",
488 [TCP_LISTEN] = "listen",
489 [TCP_CLOSING] = "closing",
490 [TCP_NEW_SYN_RECV] = "new-syn-recv",
491 };
492
493 if (st < TCP_MAX_STATES)
494 return table[st];
495 return "unknown";
496}
497
4a2b51c1 498struct l4_xinfo {
1656da13
MY
499 union {
500 struct inet_xinfo inet;
501 struct inet6_xinfo inet6;
502 };
303b41fe 503 enum l4_state st;
4a2b51c1
MY
504};
505
2a4f2b1b 506enum l4_side { L4_LOCAL, L4_REMOTE };
1656da13 507enum l3_decorator { L3_DECO_START, L3_DECO_END };
2a4f2b1b 508
4a2b51c1
MY
509struct l4_xinfo_class {
510 struct sock_xinfo_class sock;
19e40223
MY
511 struct sock_xinfo *(*scan_line)(const struct sock_xinfo_class *,
512 char *,
513 ino_t,
514 enum sysfs_byteorder);
2a4f2b1b
MY
515 void * (*get_addr)(struct l4_xinfo *, enum l4_side);
516 bool (*is_any_addr)(void *);
517 int family;
1656da13 518 const char *l3_decorator[2];
4a2b51c1
MY
519};
520
838fa270
MY
521#define l3_fill_column_handler(L3, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
522 ({ \
523 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
524 struct l4_xinfo *l4 = (struct l4_xinfo *)SOCK_XINFO; \
525 void *n = NULL; \
526 char s[BUFSIZ]; \
527 bool r = false; \
528 \
529 switch (COLUMN_ID) { \
530 case COL_##L3##_LADDR: \
531 n = class->get_addr(l4, L4_LOCAL); \
532 break; \
533 case COL_##L3##_RADDR: \
534 n = class->get_addr(l4, L4_REMOTE); \
535 break; \
536 default: \
537 break; \
538 } \
539 \
540 if (n && inet_ntop(class->family, n, s, sizeof(s))) { \
e0dc84da 541 *STR = xstrdup(s); \
838fa270
MY
542 r = true; \
543 } \
544 r; \
545 })
546
7b2a9be0
MY
547/*
548 * TCP
549 */
550struct tcp_xinfo {
4a2b51c1 551 struct l4_xinfo l4;
7b2a9be0
MY
552 uint16_t local_port;
553 uint16_t remote_port;
7b2a9be0
MY
554};
555
7b2a9be0
MY
556static char *tcp_get_name(struct sock_xinfo *sock_xinfo,
557 struct sock *sock __attribute__((__unused__)))
558{
559 char *str = NULL;
7b2a9be0 560 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
8db07ebc 561 struct l4_xinfo *l4 = &tcp->l4;
303b41fe 562 const char *st_str = l4_decode_state(l4->st);
838fa270
MY
563 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
564 void *laddr = class->get_addr(l4, L4_LOCAL);
565 void *raddr = class->get_addr(l4, L4_REMOTE);
566 char local_s[BUFSIZ];
567 char remote_s[BUFSIZ];
1656da13
MY
568 const char *start = class->l3_decorator[L3_DECO_START];
569 const char *end = class->l3_decorator[L3_DECO_END];
7b2a9be0 570
838fa270 571 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
3b182ee7
MY
572 xasprintf(&str, "state=%s", st_str);
573 else if (l4->st == TCP_LISTEN
838fa270 574 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
b4e39841 575 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16,
3b182ee7 576 st_str,
1656da13 577 start, local_s, end, tcp->local_port);
7b2a9be0 578 else
b4e39841 579 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16" raddr=%s%s%s:%"PRIu16,
3b182ee7 580 st_str,
1656da13
MY
581 start, local_s, end, tcp->local_port,
582 start, remote_s, end, tcp->remote_port);
7b2a9be0
MY
583 return str;
584}
585
586static char *tcp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
587 struct sock *sock __attribute__((__unused__)))
588{
e0dc84da 589 return xstrdup("stream");
7b2a9be0
MY
590}
591
592static char *tcp_get_state(struct sock_xinfo *sock_xinfo,
593 struct sock *sock __attribute__((__unused__)))
594{
e0dc84da 595 return xstrdup(l4_decode_state(((struct l4_xinfo *)sock_xinfo)->st));
7b2a9be0
MY
596}
597
598static bool tcp_get_listening(struct sock_xinfo *sock_xinfo,
599 struct sock *sock __attribute__((__unused__)))
600{
8db07ebc 601 return ((struct l4_xinfo *)sock_xinfo)->st == TCP_LISTEN;
7b2a9be0
MY
602}
603
838fa270
MY
604#define l4_fill_column_handler(L4, SOCK_XINFO, COLUMN_ID, STR) __extension__ \
605 ({ \
606 struct l4_xinfo_class *class = (struct l4_xinfo_class *)SOCK_XINFO->class; \
607 struct tcp_xinfo *tcp = (struct tcp_xinfo *)SOCK_XINFO; \
608 struct l4_xinfo *l4 = &tcp->l4; \
609 void *n = NULL; \
92a0dbce 610 bool has_laddr = false; \
73df46fc 611 unsigned short p; \
92a0dbce 612 bool has_lport = false; \
838fa270
MY
613 char s[BUFSIZ]; \
614 bool r = true; \
92a0dbce 615 \
838fa270 616 switch (COLUMN_ID) { \
cda2b2a0 617 case COL_##L4##_LADDR: \
838fa270 618 n = class->get_addr(l4, L4_LOCAL); \
92a0dbce 619 has_laddr = true; \
73df46fc 620 p = tcp->local_port; \
92a0dbce 621 /* FALL THROUGH */ \
cda2b2a0 622 case COL_##L4##_RADDR: \
92a0dbce 623 if (!has_laddr) { \
838fa270 624 n = class->get_addr(l4, L4_REMOTE); \
73df46fc 625 p = tcp->remote_port; \
92a0dbce 626 } \
838fa270 627 if (n && inet_ntop(class->family, n, s, sizeof(s))) \
b4e39841 628 xasprintf(STR, "%s%s%s:%"PRIu16, \
1656da13
MY
629 class->l3_decorator[L3_DECO_START], \
630 s, \
631 class->l3_decorator[L3_DECO_END], \
632 p); \
92a0dbce 633 break; \
cda2b2a0 634 case COL_##L4##_LPORT: \
73df46fc 635 p = tcp->local_port; \
92a0dbce
MY
636 has_lport = true; \
637 /* FALL THROUGH */ \
cda2b2a0 638 case COL_##L4##_RPORT: \
92a0dbce 639 if (!has_lport) \
73df46fc 640 p = tcp->remote_port; \
b4e39841 641 xasprintf(STR, "%"PRIu16, p); \
92a0dbce
MY
642 break; \
643 default: \
838fa270
MY
644 r = false; \
645 break; \
92a0dbce 646 } \
838fa270
MY
647 r; \
648 })
7b2a9be0 649
19e40223
MY
650static struct sock_xinfo *tcp_xinfo_scan_line(const struct sock_xinfo_class *class,
651 char * line,
652 ino_t netns_inode,
653 enum sysfs_byteorder byteorder)
654{
655 unsigned long local_addr;
656 unsigned long local_port;
657 unsigned long remote_addr;
658 unsigned long remote_port;
659 unsigned long st;
660 unsigned long long inode;
661 struct tcp_xinfo *tcp;
662 struct inet_xinfo *inet;
663 struct sock_xinfo *sock;
664
665 if (sscanf(line, "%*d: %lx:%lx %lx:%lx %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
666 &local_addr, &local_port, &remote_addr, &remote_port,
667 &st, &inode) != 6)
668 return NULL;
669
670 if (inode == 0)
671 return NULL;
672
8ff22ccb 673 tcp = xcalloc(1, sizeof(*tcp));
19e40223
MY
674 inet = &tcp->l4.inet;
675 sock = &inet->sock;
676 sock->class = class;
677 sock->inode = (ino_t)inode;
678 sock->netns_inode = netns_inode;
679 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
680 tcp->local_port = local_port;
681 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
682 tcp->remote_port = remote_port;
8db07ebc 683 tcp->l4.st = st;
19e40223
MY
684
685 return sock;
686}
687
2a4f2b1b
MY
688static void *tcp_xinfo_get_addr(struct l4_xinfo *l4, enum l4_side side)
689{
690 return (side == L4_LOCAL)
691 ? &l4->inet.local_addr
692 : &l4->inet.remote_addr;
693}
694
695static bool tcp_xinfo_is_any_addr(void *addr)
696{
697 return ((struct in_addr *)addr)->s_addr == INADDR_ANY;
698}
699
838fa270
MY
700static bool tcp_fill_column(struct proc *proc __attribute__((__unused__)),
701 struct sock_xinfo *sock_xinfo,
702 struct sock *sock __attribute__((__unused__)),
703 struct libscols_line *ln __attribute__((__unused__)),
704 int column_id,
705 size_t column_index __attribute__((__unused__)),
706 char **str)
707{
708 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
709 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
710}
711
4a2b51c1
MY
712static const struct l4_xinfo_class tcp_xinfo_class = {
713 .sock = {
714 .get_name = tcp_get_name,
715 .get_type = tcp_get_type,
716 .get_state = tcp_get_state,
717 .get_listening = tcp_get_listening,
718 .fill_column = tcp_fill_column,
719 .free = NULL,
720 },
19e40223 721 .scan_line = tcp_xinfo_scan_line,
2a4f2b1b
MY
722 .get_addr = tcp_xinfo_get_addr,
723 .is_any_addr = tcp_xinfo_is_any_addr,
724 .family = AF_INET,
1656da13 725 .l3_decorator = {"", ""},
7b2a9be0
MY
726};
727
cda2b2a0 728static bool L4_verify_initial_line(const char *line)
58d2f31e
MY
729{
730 /* At least we expect two white spaces. */
cb097fb7 731 if (strncmp(line, " ", 2) != 0)
58d2f31e
MY
732 return false;
733 line += 2;
734
735 /* Skip white spaces. */
4658bfb1 736 line = skip_space(line);
58d2f31e 737
621cf7e9 738 return strncmp(line, "sl", 2) == 0;
db79a100
TW
739}
740
7b2a9be0 741#define TCP_LINE_LEN 256
cda2b2a0 742static void load_xinfo_from_proc_inet_L4(ino_t netns_inode, const char *proc_file,
4a2b51c1 743 const struct l4_xinfo_class *class)
7b2a9be0
MY
744{
745 char line[TCP_LINE_LEN];
746 FILE *tcp_fp;
747
92a0dbce 748 tcp_fp = fopen(proc_file, "r");
7b2a9be0
MY
749 if (!tcp_fp)
750 return;
751
752 if (fgets(line, sizeof(line), tcp_fp) == NULL)
753 goto out;
cda2b2a0 754 if (!L4_verify_initial_line(line))
7b2a9be0
MY
755 /* Unexpected line */
756 goto out;
757
7578e03f 758 enum sysfs_byteorder byteorder = sysfs_get_byteorder(NULL);
db79a100 759
7b2a9be0 760 while (fgets(line, sizeof(line), tcp_fp)) {
19e40223
MY
761 struct sock_xinfo *sock = class->scan_line(&class->sock, line, netns_inode, byteorder);
762 if (sock)
763 add_sock_info(sock);
7b2a9be0
MY
764 }
765
766 out:
767 fclose(tcp_fp);
768}
92a0dbce 769
92a0dbce
MY
770static void load_xinfo_from_proc_tcp(ino_t netns_inode)
771{
cda2b2a0 772 load_xinfo_from_proc_inet_L4(netns_inode,
58d2f31e 773 "/proc/net/tcp",
92a0dbce
MY
774 &tcp_xinfo_class);
775}
776
777/*
778 * UDP
779 */
780static char *udp_get_name(struct sock_xinfo *sock_xinfo,
781 struct sock *sock __attribute__((__unused__)))
782{
783 char *str = NULL;
92a0dbce 784 struct tcp_xinfo *tcp = ((struct tcp_xinfo *)sock_xinfo);
8db07ebc 785 struct l4_xinfo *l4 = &tcp->l4;
8db07ebc 786 unsigned int st = l4->st;
303b41fe 787 const char *st_str = l4_decode_state(st);
838fa270
MY
788 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
789 void *laddr = class->get_addr(l4, L4_LOCAL);
790 void *raddr = class->get_addr(l4, L4_REMOTE);
791 char local_s[BUFSIZ];
792 char remote_s[BUFSIZ];
28cf2b21
MY
793 const char *start = class->l3_decorator[L3_DECO_START];
794 const char *end = class->l3_decorator[L3_DECO_END];
92a0dbce 795
838fa270 796 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
3b182ee7 797 xasprintf(&str, "state=%s", st_str);
838fa270
MY
798 else if ((class->is_any_addr(raddr) && tcp->remote_port == 0)
799 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
28cf2b21 800 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16,
3b182ee7 801 st_str,
28cf2b21 802 start, local_s, end, tcp->local_port);
92a0dbce 803 else
28cf2b21 804 xasprintf(&str, "state=%s laddr=%s%s%s:%"PRIu16" raddr=%s%s%s:%"PRIu16,
3b182ee7 805 st_str,
28cf2b21
MY
806 start, local_s, end, tcp->local_port,
807 start, remote_s, end, tcp->remote_port);
92a0dbce
MY
808 return str;
809}
810
811static char *udp_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
812 struct sock *sock __attribute__((__unused__)))
813{
e0dc84da 814 return xstrdup("dgram");
92a0dbce
MY
815}
816
838fa270
MY
817static bool udp_fill_column(struct proc *proc __attribute__((__unused__)),
818 struct sock_xinfo *sock_xinfo,
819 struct sock *sock __attribute__((__unused__)),
820 struct libscols_line *ln __attribute__((__unused__)),
821 int column_id,
822 size_t column_index __attribute__((__unused__)),
823 char **str)
824{
825 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
826 || l4_fill_column_handler(UDP, sock_xinfo, column_id, str);
827}
828
4a2b51c1
MY
829static const struct l4_xinfo_class udp_xinfo_class = {
830 .sock = {
831 .get_name = udp_get_name,
832 .get_type = udp_get_type,
833 .get_state = tcp_get_state,
834 .get_listening = NULL,
835 .fill_column = udp_fill_column,
836 .free = NULL,
837 },
19e40223 838 .scan_line = tcp_xinfo_scan_line,
2a4f2b1b
MY
839 .get_addr = tcp_xinfo_get_addr,
840 .is_any_addr = tcp_xinfo_is_any_addr,
841 .family = AF_INET,
1656da13 842 .l3_decorator = {"", ""},
92a0dbce
MY
843};
844
92a0dbce
MY
845static void load_xinfo_from_proc_udp(ino_t netns_inode)
846{
cda2b2a0 847 load_xinfo_from_proc_inet_L4(netns_inode,
92a0dbce 848 "/proc/net/udp",
92a0dbce
MY
849 &udp_xinfo_class);
850}
0188afb3 851
c779f412
MY
852/*
853 * UDP-Lite
854 */
855static bool udplite_fill_column(struct proc *proc __attribute__((__unused__)),
856 struct sock_xinfo *sock_xinfo,
857 struct sock *sock __attribute__((__unused__)),
858 struct libscols_line *ln __attribute__((__unused__)),
859 int column_id,
860 size_t column_index __attribute__((__unused__)),
861 char **str)
862{
863 return l3_fill_column_handler(INET, sock_xinfo, column_id, str)
864 || l4_fill_column_handler(UDPLITE, sock_xinfo, column_id, str);
865}
866
867static const struct l4_xinfo_class udplite_xinfo_class = {
868 .sock = {
869 .get_name = udp_get_name,
870 .get_type = udp_get_type,
871 .get_state = tcp_get_state,
872 .get_listening = NULL,
873 .fill_column = udplite_fill_column,
874 .free = NULL,
875 },
876 .scan_line = tcp_xinfo_scan_line,
877 .get_addr = tcp_xinfo_get_addr,
878 .is_any_addr = tcp_xinfo_is_any_addr,
879 .family = AF_INET,
880 .l3_decorator = {"", ""},
881};
882
883static void load_xinfo_from_proc_udplite(ino_t netns_inode)
884{
885 load_xinfo_from_proc_inet_L4(netns_inode,
886 "/proc/net/udplite",
887 &udplite_xinfo_class);
888}
889
0188afb3
MY
890/*
891 * RAW
892 */
893struct raw_xinfo {
894 struct l4_xinfo l4;
895 uint16_t protocol;
896};
897
a7cba6f3
MY
898static char *raw_get_name_common(struct sock_xinfo *sock_xinfo,
899 struct sock *sock __attribute__((__unused__)),
900 const char *port_label)
0188afb3
MY
901{
902 char *str = NULL;
903 struct l4_xinfo_class *class = (struct l4_xinfo_class *)sock_xinfo->class;
904 struct raw_xinfo *raw = ((struct raw_xinfo *)sock_xinfo);
905 struct l4_xinfo *l4 = &raw->l4;
303b41fe 906 const char *st_str = l4_decode_state(l4->st);
0188afb3
MY
907 void *laddr = class->get_addr(l4, L4_LOCAL);
908 void *raddr = class->get_addr(l4, L4_REMOTE);
909 char local_s[BUFSIZ];
910 char remote_s[BUFSIZ];
911
912 if (!inet_ntop(class->family, laddr, local_s, sizeof(local_s)))
913 xasprintf(&str, "state=%s", st_str);
914 else if (class->is_any_addr(raddr)
915 || !inet_ntop(class->family, raddr, remote_s, sizeof(remote_s)))
a7cba6f3 916 xasprintf(&str, "state=%s %s=%"PRIu16" laddr=%s",
0188afb3 917 st_str,
a7cba6f3 918 port_label,
0188afb3
MY
919 raw->protocol, local_s);
920 else
a7cba6f3 921 xasprintf(&str, "state=%s %s=%"PRIu16" laddr=%s raddr=%s",
0188afb3 922 st_str,
a7cba6f3 923 port_label,
0188afb3
MY
924 raw->protocol, local_s, remote_s);
925 return str;
926}
927
a7cba6f3
MY
928static char *raw_get_name(struct sock_xinfo *sock_xinfo,
929 struct sock *sock __attribute__((__unused__)))
930{
931 return raw_get_name_common(sock_xinfo, sock, "protocol");
932}
933
0188afb3
MY
934static char *raw_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
935 struct sock *sock __attribute__((__unused__)))
936{
e0dc84da 937 return xstrdup("raw");
0188afb3
MY
938}
939
940static bool raw_fill_column(struct proc *proc __attribute__((__unused__)),
941 struct sock_xinfo *sock_xinfo,
942 struct sock *sock __attribute__((__unused__)),
943 struct libscols_line *ln __attribute__((__unused__)),
944 int column_id,
945 size_t column_index __attribute__((__unused__)),
946 char **str)
947{
948 if (l3_fill_column_handler(INET, sock_xinfo, column_id, str))
949 return true;
950
951 if (column_id == COL_RAW_PROTOCOL) {
b4e39841 952 xasprintf(str, "%"PRIu16,
73df46fc 953 ((struct raw_xinfo *)sock_xinfo)->protocol);
0188afb3
MY
954 return true;
955 }
956
957 return false;
958}
959
960static struct sock_xinfo *raw_xinfo_scan_line(const struct sock_xinfo_class *class,
961 char * line,
962 ino_t netns_inode,
963 enum sysfs_byteorder byteorder)
964{
965 unsigned long local_addr;
966 unsigned long protocol;
967 unsigned long remote_addr;
968 unsigned long st;
969 unsigned long long inode;
970 struct raw_xinfo *raw;
971 struct inet_xinfo *inet;
972 struct sock_xinfo *sock;
973
974 if (sscanf(line, "%*d: %lx:%lx %lx:%*x %lx %*x:%*x %*x:%*x %*x %*u %*u %lld",
975 &local_addr, &protocol, &remote_addr,
976 &st, &inode) != 5)
977 return NULL;
978
979 if (inode == 0)
980 return NULL;
981
8ff22ccb 982 raw = xcalloc(1, sizeof(*raw));
0188afb3
MY
983 inet = &raw->l4.inet;
984 sock = &inet->sock;
985 sock->class = class;
986 sock->inode = (ino_t)inode;
987 sock->netns_inode = netns_inode;
988 inet->local_addr.s_addr = kernel32_to_cpu(byteorder, local_addr);
989 inet->remote_addr.s_addr = kernel32_to_cpu(byteorder, remote_addr);
990 raw->protocol = protocol;
991 raw->l4.st = st;
992
993 return sock;
994}
995
996static const struct l4_xinfo_class raw_xinfo_class = {
997 .sock = {
998 .get_name = raw_get_name,
999 .get_type = raw_get_type,
1000 .get_state = tcp_get_state,
1001 .get_listening = NULL,
1002 .fill_column = raw_fill_column,
1003 .free = NULL,
1004 },
1005 .scan_line = raw_xinfo_scan_line,
1006 .get_addr = tcp_xinfo_get_addr,
1007 .is_any_addr = tcp_xinfo_is_any_addr,
1008 .family = AF_INET,
1656da13 1009 .l3_decorator = {"", ""},
0188afb3
MY
1010};
1011
1012static void load_xinfo_from_proc_raw(ino_t netns_inode)
1013{
1014 load_xinfo_from_proc_inet_L4(netns_inode,
1015 "/proc/net/raw",
1016 &raw_xinfo_class);
1017}
1656da13 1018
a7cba6f3
MY
1019/*
1020 * PING
1021 */
1022static char *ping_get_name(struct sock_xinfo *sock_xinfo,
1023 struct sock *sock __attribute__((__unused__)))
1024{
1025 return raw_get_name_common(sock_xinfo, sock, "id");
1026}
1027
1028static char *ping_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
1029 struct sock *sock __attribute__((__unused__)))
1030{
e0dc84da 1031 return xstrdup("dgram");
a7cba6f3
MY
1032}
1033
1034static bool ping_fill_column(struct proc *proc __attribute__((__unused__)),
1035 struct sock_xinfo *sock_xinfo,
1036 struct sock *sock __attribute__((__unused__)),
1037 struct libscols_line *ln __attribute__((__unused__)),
1038 int column_id,
1039 size_t column_index __attribute__((__unused__)),
1040 char **str)
1041{
1042 if (l3_fill_column_handler(INET, sock_xinfo, column_id, str))
1043 return true;
1044
1045 if (column_id == COL_PING_ID) {
1046 xasprintf(str, "%"PRIu16,
1047 ((struct raw_xinfo *)sock_xinfo)->protocol);
1048 return true;
1049 }
1050
1051 return false;
1052}
1053
1054static const struct l4_xinfo_class ping_xinfo_class = {
1055 .sock = {
1056 .get_name = ping_get_name,
1057 .get_type = ping_get_type,
1058 .get_state = tcp_get_state,
1059 .get_listening = NULL,
1060 .fill_column = ping_fill_column,
1061 .free = NULL,
1062 },
1063 .scan_line = raw_xinfo_scan_line,
1064 .get_addr = tcp_xinfo_get_addr,
1065 .is_any_addr = tcp_xinfo_is_any_addr,
1066 .family = AF_INET,
1067 .l3_decorator = {"", ""},
1068};
1069
1070static void load_xinfo_from_proc_icmp(ino_t netns_inode)
1071{
1072 load_xinfo_from_proc_inet_L4(netns_inode,
1073 "/proc/net/icmp",
1074 &ping_xinfo_class);
1075}
1076
1656da13
MY
1077/*
1078 * TCP6
1079 */
1080static struct sock_xinfo *tcp6_xinfo_scan_line(const struct sock_xinfo_class *class,
1081 char * line,
1082 ino_t netns_inode,
1083 enum sysfs_byteorder byteorder)
1084{
1085 uint32_t local_addr[4];
1086 unsigned int local_port;
1087 uint32_t remote_addr[4];
1088 unsigned int remote_port;
1089 unsigned int st;
1090 unsigned long inode;
1091 struct tcp_xinfo *tcp;
1092 struct inet6_xinfo *inet6;
1093 struct sock_xinfo *sock;
1094
1095 if (sscanf(line,
1096 "%*d: "
1097 "%08x%08x%08x%08x:%04x "
1098 "%08x%08x%08x%08x:%04x "
1099 "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
1100 local_addr+0, local_addr+1, local_addr+2, local_addr+3, &local_port,
1101 remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3, &remote_port,
1102 &st, &inode) != 12)
1103 return NULL;
1104
1105 if (inode == 0)
1106 return NULL;
1107
8ff22ccb 1108 tcp = xmalloc(sizeof(*tcp));
1656da13
MY
1109 inet6 = &tcp->l4.inet6;
1110 sock = &inet6->sock;
1111 sock->class = class;
1112 sock->inode = (ino_t)inode;
1113 sock->netns_inode = netns_inode;
1114 tcp->local_port = local_port;
1115 for (int i = 0; i < 4; i++) {
1116 inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
1117 inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
1118 }
1119 tcp->remote_port = remote_port;
1120 tcp->l4.st = st;
1121
1122 return sock;
1123}
1124
1125static bool tcp6_fill_column(struct proc *proc __attribute__((__unused__)),
1126 struct sock_xinfo *sock_xinfo,
1127 struct sock *sock __attribute__((__unused__)),
1128 struct libscols_line *ln __attribute__((__unused__)),
1129 int column_id,
1130 size_t column_index __attribute__((__unused__)),
1131 char **str)
1132{
1133 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1134 || l4_fill_column_handler(TCP, sock_xinfo, column_id, str);
1135}
1136
1137static void *tcp6_xinfo_get_addr(struct l4_xinfo * l4, enum l4_side side)
1138{
1139 return (side == L4_LOCAL)
1140 ? &l4->inet6.local_addr
1141 : &l4->inet6.remote_addr;
1142}
1143
1144static bool tcp6_xinfo_is_any_addr(void *addr)
1145{
1146 return IN6_ARE_ADDR_EQUAL(addr, &(struct in6_addr)IN6ADDR_ANY_INIT);
1147}
1148
1149static const struct l4_xinfo_class tcp6_xinfo_class = {
1150 .sock = {
1151 .get_name = tcp_get_name,
1152 .get_type = tcp_get_type,
1153 .get_state = tcp_get_state,
1154 .get_listening = tcp_get_listening,
1155 .fill_column = tcp6_fill_column,
1156 .free = NULL,
1157 },
1158 .scan_line = tcp6_xinfo_scan_line,
1159 .get_addr = tcp6_xinfo_get_addr,
1160 .is_any_addr = tcp6_xinfo_is_any_addr,
1161 .family = AF_INET6,
1162 .l3_decorator = {"[", "]"},
1163};
1164
1165static void load_xinfo_from_proc_tcp6(ino_t netns_inode)
1166{
1167 load_xinfo_from_proc_inet_L4(netns_inode,
1168 "/proc/net/tcp6",
1169 &tcp6_xinfo_class);
1170}
28cf2b21
MY
1171
1172/*
1173 * UDP6
1174 */
1175static bool udp6_fill_column(struct proc *proc __attribute__((__unused__)),
1176 struct sock_xinfo *sock_xinfo,
1177 struct sock *sock __attribute__((__unused__)),
1178 struct libscols_line *ln __attribute__((__unused__)),
1179 int column_id,
1180 size_t column_index __attribute__((__unused__)),
1181 char **str)
1182{
1183 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1184 || l4_fill_column_handler(UDP, sock_xinfo, column_id, str);
1185}
1186
1187static const struct l4_xinfo_class udp6_xinfo_class = {
1188 .sock = {
1189 .get_name = udp_get_name,
1190 .get_type = udp_get_type,
1191 .get_state = tcp_get_state,
1192 .get_listening = NULL,
1193 .fill_column = udp6_fill_column,
1194 .free = NULL,
1195 },
1196 .scan_line = tcp6_xinfo_scan_line,
1197 .get_addr = tcp6_xinfo_get_addr,
1198 .is_any_addr = tcp6_xinfo_is_any_addr,
1199 .family = AF_INET6,
1200 .l3_decorator = {"[", "]"},
1201};
1202
1203static void load_xinfo_from_proc_udp6(ino_t netns_inode)
1204{
1205 load_xinfo_from_proc_inet_L4(netns_inode,
1206 "/proc/net/udp6",
1207 &udp6_xinfo_class);
1208}
2dd373c3 1209
93bca151
MY
1210/*
1211 * UDPLITEv6
1212 */
1213static bool udplite6_fill_column(struct proc *proc __attribute__((__unused__)),
1214 struct sock_xinfo *sock_xinfo,
1215 struct sock *sock __attribute__((__unused__)),
1216 struct libscols_line *ln __attribute__((__unused__)),
1217 int column_id,
1218 size_t column_index __attribute__((__unused__)),
1219 char **str)
1220{
1221 return l3_fill_column_handler(INET6, sock_xinfo, column_id, str)
1222 || l4_fill_column_handler(UDPLITE, sock_xinfo, column_id, str);
1223}
1224
1225static const struct l4_xinfo_class udplite6_xinfo_class = {
1226 .sock = {
1227 .get_name = udp_get_name,
1228 .get_type = udp_get_type,
1229 .get_state = tcp_get_state,
1230 .get_listening = NULL,
1231 .fill_column = udplite6_fill_column,
1232 .free = NULL,
1233 },
1234 .scan_line = tcp6_xinfo_scan_line,
1235 .get_addr = tcp6_xinfo_get_addr,
1236 .is_any_addr = tcp6_xinfo_is_any_addr,
1237 .family = AF_INET6,
1238 .l3_decorator = {"[", "]"},
1239};
1240
1241static void load_xinfo_from_proc_udplite6(ino_t netns_inode)
1242{
1243 load_xinfo_from_proc_inet_L4(netns_inode,
1244 "/proc/net/udplite6",
1245 &udplite6_xinfo_class);
1246}
1247
2dd373c3
MY
1248/*
1249 * RAW6
1250 */
1251static struct sock_xinfo *raw6_xinfo_scan_line(const struct sock_xinfo_class *class,
1252 char * line,
1253 ino_t netns_inode,
1254 enum sysfs_byteorder byteorder)
1255{
1256 uint32_t local_addr[4];
1257 unsigned int protocol;
1258 uint32_t remote_addr[4];
1259 unsigned int st;
1260 unsigned long inode;
1261 struct raw_xinfo *raw;
1262 struct inet6_xinfo *inet6;
1263 struct sock_xinfo *sock;
1264
1265 if (sscanf(line,
1266 "%*d: "
1267 "%08x%08x%08x%08x:%04x "
1268 "%08x%08x%08x%08x:0000 "
1269 "%x %*x:%*x %*x:%*x %*x %*u %*d %lu ",
1270 local_addr+0, local_addr+1, local_addr+2, local_addr+3, &protocol,
1271 remote_addr+0, remote_addr+1, remote_addr+2, remote_addr+3,
1272 &st, &inode) != 11)
1273 return NULL;
1274
1275 if (inode == 0)
1276 return NULL;
1277
1278 raw = xmalloc(sizeof(*raw));
1279 inet6 = &raw->l4.inet6;
1280 sock = &inet6->sock;
1281 sock->class = class;
1282 sock->inode = (ino_t)inode;
1283 sock->netns_inode = netns_inode;
1284 for (int i = 0; i < 4; i++) {
1285 inet6->local_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, local_addr[i]);
1286 inet6->remote_addr.s6_addr32[i] = kernel32_to_cpu(byteorder, remote_addr[i]);
1287 }
1288 raw->protocol = protocol;
1289 raw->l4.st = st;
1290
1291 return sock;
1292}
1293
1294static bool raw6_fill_column(struct proc *proc __attribute__((__unused__)),
1295 struct sock_xinfo *sock_xinfo,
1296 struct sock *sock __attribute__((__unused__)),
1297 struct libscols_line *ln __attribute__((__unused__)),
1298 int column_id,
1299 size_t column_index __attribute__((__unused__)),
1300 char **str)
1301{
1302 struct raw_xinfo *raw;
1303
1304 if (l3_fill_column_handler(INET6, sock_xinfo, column_id, str))
1305 return true;
1306
1307 raw = (struct raw_xinfo *)sock_xinfo;
1308 if (column_id == COL_RAW_PROTOCOL) {
1309 xasprintf(str, "%"PRIu16, raw->protocol);
1310 return true;
1311 }
1312
1313 return false;
1314}
1315
1316static const struct l4_xinfo_class raw6_xinfo_class = {
1317 .sock = {
1318 .get_name = raw_get_name,
1319 .get_type = raw_get_type,
1320 .get_state = tcp_get_state,
1321 .get_listening = NULL,
1322 .fill_column = raw6_fill_column,
1323 .free = NULL,
1324 },
1325 .scan_line = raw6_xinfo_scan_line,
1326 .get_addr = tcp6_xinfo_get_addr,
1327 .is_any_addr = tcp6_xinfo_is_any_addr,
1328 .family = AF_INET6,
1329 .l3_decorator = {"[", "]"},
1330};
1331
1332static void load_xinfo_from_proc_raw6(ino_t netns_inode)
1333{
1334 load_xinfo_from_proc_inet_L4(netns_inode,
1335 "/proc/net/raw6",
1336 &raw6_xinfo_class);
1337}
0b1dfd03
MY
1338
1339/*
1340 * PINGv6
1341 */
1342static bool ping6_fill_column(struct proc *proc __attribute__((__unused__)),
1343 struct sock_xinfo *sock_xinfo,
1344 struct sock *sock __attribute__((__unused__)),
1345 struct libscols_line *ln __attribute__((__unused__)),
1346 int column_id,
1347 size_t column_index __attribute__((__unused__)),
1348 char **str)
1349{
1350 if (l3_fill_column_handler(INET6, sock_xinfo, column_id, str))
1351 return true;
1352
1353 if (column_id == COL_PING_ID) {
1354 xasprintf(str, "%"PRIu16,
1355 ((struct raw_xinfo *)sock_xinfo)->protocol);
1356 return true;
1357 }
1358
1359 return false;
1360}
1361
1362static const struct l4_xinfo_class ping6_xinfo_class = {
1363 .sock = {
1364 .get_name = ping_get_name,
1365 .get_type = ping_get_type,
1366 .get_state = tcp_get_state,
1367 .get_listening = NULL,
1368 .fill_column = ping6_fill_column,
1369 .free = NULL,
1370 },
1371 .scan_line = raw6_xinfo_scan_line,
1372 .get_addr = tcp6_xinfo_get_addr,
1373 .is_any_addr = tcp6_xinfo_is_any_addr,
1374 .family = AF_INET6,
1375 .l3_decorator = {"[", "]"},
1376};
1377
1378static void load_xinfo_from_proc_icmp6(ino_t netns_inode)
1379{
1380 load_xinfo_from_proc_inet_L4(netns_inode,
1381 "/proc/net/icmp6",
1382 &ping6_xinfo_class);
1383}
b53cc896
MY
1384
1385/*
1386 * NETLINK
1387 */
1388struct netlink_xinfo {
1389 struct sock_xinfo sock;
1390 uint16_t protocol;
1391 uint32_t lportid; /* netlink_diag may provide rportid. */
1392 uint32_t groups;
1393};
1394
1395static const char *netlink_decode_protocol(uint16_t protocol)
1396{
1397 switch (protocol) {
1398 case NETLINK_ROUTE:
1399 return "route";
1400 case NETLINK_UNUSED:
1401 return "unused";
1402 case NETLINK_USERSOCK:
1403 return "usersock";
1404 case NETLINK_FIREWALL:
1405 return "firewall";
1406 case NETLINK_SOCK_DIAG:
1407 return "sock_diag";
1408 case NETLINK_NFLOG:
1409 return "nflog";
1410 case NETLINK_XFRM:
1411 return "xfrm";
1412 case NETLINK_SELINUX:
1413 return "selinux";
1414 case NETLINK_ISCSI:
1415 return "iscsi";
1416 case NETLINK_AUDIT:
1417 return "audit";
1418 case NETLINK_FIB_LOOKUP:
1419 return "fib_lookup";
1420 case NETLINK_CONNECTOR:
1421 return "connector";
1422 case NETLINK_NETFILTER:
1423 return "netfilter";
1424 case NETLINK_IP6_FW:
1425 return "ip6_fw";
1426 case NETLINK_DNRTMSG:
1427 return "dnrtmsg";
1428 case NETLINK_KOBJECT_UEVENT:
1429 return "kobject_uevent";
1430 case NETLINK_GENERIC:
1431 return "generic";
1432 case NETLINK_SCSITRANSPORT:
1433 return "scsitransport";
1434 case NETLINK_ECRYPTFS:
1435 return "ecryptfs";
1436 case NETLINK_RDMA:
1437 return "rdma";
1438 case NETLINK_CRYPTO:
1439 return "crypto";
1440#ifdef NETLINK_SMC
1441 case NETLINK_SMC:
1442 return "smc";
1443#endif
1444 default:
1445 return "unknown";
1446 }
1447}
1448
1449static char *netlink_get_name(struct sock_xinfo *sock_xinfo,
1450 struct sock *sock __attribute__((__unused__)))
1451{
1452 struct netlink_xinfo *nl = (struct netlink_xinfo *)sock_xinfo;
1453 char *str = NULL;
1454 const char *protocol = netlink_decode_protocol(nl->protocol);
1455
1456 if (nl->groups)
1457 xasprintf(&str, "protocol=%s lport=%"PRIu16 " groups=%"PRIu32,
1458 protocol,
1459 nl->lportid, nl->groups);
1460 else
1461 xasprintf(&str, "protocol=%s lport=%"PRIu16,
1462 protocol,
1463 nl->lportid);
1464 return str;
1465}
1466
1467static char *netlink_get_type(struct sock_xinfo *sock_xinfo __attribute__((__unused__)),
1468 struct sock *sock __attribute__((__unused__)))
1469{
e0dc84da 1470 return xstrdup("raw");
b53cc896
MY
1471}
1472
1473static bool netlink_fill_column(struct proc *proc __attribute__((__unused__)),
1474 struct sock_xinfo *sock_xinfo,
1475 struct sock *sock __attribute__((__unused__)),
1476 struct libscols_line *ln __attribute__((__unused__)),
1477 int column_id,
1478 size_t column_index __attribute__((__unused__)),
1479 char **str)
1480{
1481 struct netlink_xinfo *nl = (struct netlink_xinfo *)sock_xinfo;
1482
1483 switch (column_id) {
1484 case COL_NETLINK_GROUPS:
1485 xasprintf(str, "%"PRIu32, nl->groups);
1486 return true;
1487 case COL_NETLINK_LPORT:
1488 xasprintf(str, "%"PRIu32, nl->lportid);
1489 return true;
1490 case COL_NETLINK_PROTOCOL:
e0dc84da 1491 *str = xstrdup(netlink_decode_protocol(nl->protocol));
b53cc896
MY
1492 return true;
1493 }
1494
1495 return false;
1496}
1497
1498static const struct sock_xinfo_class netlink_xinfo_class = {
1499 .get_name = netlink_get_name,
1500 .get_type = netlink_get_type,
1501 .get_state = NULL,
1502 .get_listening = NULL,
1503 .fill_column = netlink_fill_column,
1504 .free = NULL,
1505};
1506
1507static void load_xinfo_from_proc_netlink(ino_t netns_inode)
1508{
1509 char line[BUFSIZ];
1510 FILE *netlink_fp;
1511
1512 netlink_fp = fopen("/proc/net/netlink", "r");
1513 if (!netlink_fp)
1514 return;
1515
1516 if (fgets(line, sizeof(line), netlink_fp) == NULL)
1517 goto out;
1518 if (!(line[0] == 's' && line[1] == 'k'))
1519 /* Unexpected line */
1520 goto out;
1521
1522 while (fgets(line, sizeof(line), netlink_fp)) {
1523 uint16_t protocol;
1524 uint32_t lportid;
1525 uint32_t groups;
1526 unsigned long inode;
1527 struct netlink_xinfo *nl;
1528
1529 if (sscanf(line, "%*x %" SCNu16 " %" SCNu32 " %" SCNx32 " %*d %*d %*d %*d %*u %lu",
1530 &protocol, &lportid, &groups, &inode) < 4)
1531 continue;
1532
1533 if (inode == 0)
1534 continue;
1535
1536 nl = xcalloc(1, sizeof(*nl));
1537 nl->sock.class = &netlink_xinfo_class;
1538 nl->sock.inode = (ino_t)inode;
1539 nl->sock.netns_inode = netns_inode;
1540
1541 nl->protocol = protocol;
1542 nl->lportid = lportid;
1543 nl->groups = groups;
1544
1545 add_sock_info(&nl->sock);
1546 }
1547
1548 out:
1549 fclose(netlink_fp);
1550}