]> git.proxmox.com Git - mirror_iproute2.git/blame - misc/ss.c
ss: Fix support for device filter by index
[mirror_iproute2.git] / misc / ss.c
CommitLineData
b9de3ecf 1/*
aba5acdf
SH
2 * ss.c "sockstat", socket statistics
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <syslog.h>
16#include <fcntl.h>
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <sys/uio.h>
20#include <netinet/in.h>
21#include <string.h>
22#include <errno.h>
23#include <netdb.h>
24#include <arpa/inet.h>
aba5acdf
SH
25#include <dirent.h>
26#include <fnmatch.h>
ab61159a 27#include <getopt.h>
bf4ceee6 28#include <stdbool.h>
aba5acdf
SH
29
30#include "utils.h"
31#include "rt_names.h"
32#include "ll_map.h"
33#include "libnetlink.h"
95ce04bc 34#include "namespace.h"
aba5acdf
SH
35#include "SNAPSHOT.h"
36
9cb1eccf 37#include <linux/tcp.h>
f6062360 38#include <linux/sock_diag.h>
351efcde 39#include <linux/inet_diag.h>
dfbaa90d 40#include <linux/unix_diag.h>
372c30d2
ND
41#include <linux/netdevice.h> /* for MAX_ADDR_LEN */
42#include <linux/filter.h>
43#include <linux/packet_diag.h>
ecb928c8 44#include <linux/netlink_diag.h>
aba5acdf 45
8a4025f6 46#define MAGIC_SEQ 123456
47
5fb421d4 48#define DIAG_REQUEST(_req, _r) \
49 struct { \
50 struct nlmsghdr nlh; \
51 _r; \
52 } _req = { \
53 .nlh = { \
54 .nlmsg_type = SOCK_DIAG_BY_FAMILY, \
55 .nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST,\
8a4025f6 56 .nlmsg_seq = MAGIC_SEQ, \
5fb421d4 57 .nlmsg_len = sizeof(_req), \
58 }, \
59 }
60
116ac927
RH
61#if HAVE_SELINUX
62#include <selinux/selinux.h>
63#else
64/* Stubs for SELinux functions */
65static int is_selinux_enabled(void)
66{
67 return -1;
68}
69
70static int getpidcon(pid_t pid, char **context)
71{
72 *context = NULL;
73 return -1;
74}
75
76static int getfilecon(char *path, char **context)
77{
78 *context = NULL;
79 return -1;
80}
81
82static int security_get_initial_context(char *name, char **context)
83{
84 *context = NULL;
85 return -1;
86}
87#endif
88
acd1e437 89int resolve_hosts;
aba5acdf
SH
90int resolve_services = 1;
91int preferred_family = AF_UNSPEC;
acd1e437
SH
92int show_options;
93int show_details;
94int show_users;
95int show_mem;
96int show_tcpinfo;
97int show_bpf;
98int show_proc_ctx;
99int show_sock_ctx;
116ac927 100/* If show_users & show_proc_ctx only do user_ent_hash_build() once */
acd1e437
SH
101int user_ent_hash_build_init;
102int follow_events;
aba5acdf
SH
103
104int netid_width;
105int state_width;
106int addrp_width;
107int addr_width;
108int serv_width;
109int screen_width;
110
111static const char *TCP_PROTO = "tcp";
112static const char *UDP_PROTO = "udp";
113static const char *RAW_PROTO = "raw";
acd1e437 114static const char *dg_proto;
aba5acdf 115
acd1e437 116enum {
aba5acdf 117 TCP_DB,
351efcde 118 DCCP_DB,
aba5acdf
SH
119 UDP_DB,
120 RAW_DB,
121 UNIX_DG_DB,
122 UNIX_ST_DB,
30b669d7 123 UNIX_SQ_DB,
aba5acdf
SH
124 PACKET_DG_DB,
125 PACKET_R_DB,
126 NETLINK_DB,
127 MAX_DB
128};
129
130#define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB))
30b669d7 131#define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)|(1<<UNIX_SQ_DB))
aba5acdf 132#define ALL_DB ((1<<MAX_DB)-1)
9db7bf15 133#define INET_DBM ((1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB)|(1<<RAW_DB))
aba5acdf
SH
134
135enum {
7d105b56
SH
136 SS_UNKNOWN,
137 SS_ESTABLISHED,
138 SS_SYN_SENT,
139 SS_SYN_RECV,
140 SS_FIN_WAIT1,
141 SS_FIN_WAIT2,
142 SS_TIME_WAIT,
143 SS_CLOSE,
144 SS_CLOSE_WAIT,
145 SS_LAST_ACK,
146 SS_LISTEN,
147 SS_CLOSING,
148 SS_MAX
aba5acdf
SH
149};
150
9db7bf15
VK
151#define SS_ALL ((1 << SS_MAX) - 1)
152#define SS_CONN (SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)))
aba5acdf
SH
153
154#include "ssfilter.h"
155
acd1e437 156struct filter {
aba5acdf
SH
157 int dbs;
158 int states;
159 int families;
160 struct ssfilter *f;
fb2594c1 161 bool kill;
aba5acdf
SH
162};
163
9db7bf15
VK
164static const struct filter default_dbs[MAX_DB] = {
165 [TCP_DB] = {
166 .states = SS_CONN,
167 .families = (1 << AF_INET) | (1 << AF_INET6),
168 },
169 [DCCP_DB] = {
170 .states = SS_CONN,
171 .families = (1 << AF_INET) | (1 << AF_INET6),
172 },
173 [UDP_DB] = {
f42a4574 174 .states = (1 << SS_ESTABLISHED),
9db7bf15
VK
175 .families = (1 << AF_INET) | (1 << AF_INET6),
176 },
177 [RAW_DB] = {
f42a4574 178 .states = (1 << SS_ESTABLISHED),
9db7bf15
VK
179 .families = (1 << AF_INET) | (1 << AF_INET6),
180 },
181 [UNIX_DG_DB] = {
182 .states = (1 << SS_CLOSE),
183 .families = (1 << AF_UNIX),
184 },
185 [UNIX_ST_DB] = {
186 .states = SS_CONN,
187 .families = (1 << AF_UNIX),
188 },
189 [UNIX_SQ_DB] = {
190 .states = SS_CONN,
191 .families = (1 << AF_UNIX),
192 },
193 [PACKET_DG_DB] = {
194 .states = (1 << SS_CLOSE),
195 .families = (1 << AF_PACKET),
196 },
197 [PACKET_R_DB] = {
198 .states = (1 << SS_CLOSE),
199 .families = (1 << AF_PACKET),
200 },
201 [NETLINK_DB] = {
202 .states = (1 << SS_CLOSE),
203 .families = (1 << AF_NETLINK),
204 },
aba5acdf
SH
205};
206
9db7bf15
VK
207static const struct filter default_afs[AF_MAX] = {
208 [AF_INET] = {
209 .dbs = INET_DBM,
210 .states = SS_CONN,
211 },
212 [AF_INET6] = {
213 .dbs = INET_DBM,
214 .states = SS_CONN,
215 },
216 [AF_UNIX] = {
217 .dbs = UNIX_DBM,
218 .states = SS_CONN,
219 },
220 [AF_PACKET] = {
221 .dbs = PACKET_DBM,
222 .states = (1 << SS_CLOSE),
223 },
224 [AF_NETLINK] = {
225 .dbs = (1 << NETLINK_DB),
226 .states = (1 << SS_CLOSE),
227 },
228};
229
230static int do_default = 1;
231static struct filter current_filter;
232
233static void filter_db_set(struct filter *f, int db)
234{
235 f->states |= default_dbs[db].states;
9db7bf15
VK
236 f->dbs |= 1 << db;
237 do_default = 0;
238}
239
240static void filter_af_set(struct filter *f, int af)
241{
1527a17e
VK
242 f->states |= default_afs[af].states;
243 f->families |= 1 << af;
244 do_default = 0;
245 preferred_family = af;
9db7bf15
VK
246}
247
248static int filter_af_get(struct filter *f, int af)
249{
250 return f->families & (1 << af);
251}
252
253static void filter_default_dbs(struct filter *f)
254{
255 filter_db_set(f, UDP_DB);
256 filter_db_set(f, DCCP_DB);
257 filter_db_set(f, TCP_DB);
258 filter_db_set(f, RAW_DB);
259 filter_db_set(f, UNIX_ST_DB);
260 filter_db_set(f, UNIX_DG_DB);
261 filter_db_set(f, UNIX_SQ_DB);
262 filter_db_set(f, PACKET_R_DB);
263 filter_db_set(f, PACKET_DG_DB);
264 filter_db_set(f, NETLINK_DB);
265}
266
57ff5a10 267static void filter_states_set(struct filter *f, int states)
9db7bf15 268{
57ff5a10 269 if (states)
9d320e1e 270 f->states = states;
57ff5a10 271}
9db7bf15 272
57ff5a10
VK
273static void filter_merge_defaults(struct filter *f)
274{
275 int db;
276 int af;
9db7bf15 277
57ff5a10
VK
278 for (db = 0; db < MAX_DB; db++) {
279 if (!(f->dbs & (1 << db)))
280 continue;
9db7bf15 281
57ff5a10
VK
282 if (!(default_dbs[db].families & f->families))
283 f->families |= default_dbs[db].families;
284 }
285 for (af = 0; af < AF_MAX; af++) {
286 if (!(f->families & (1 << af)))
287 continue;
288
289 if (!(default_afs[af].dbs & f->dbs))
290 f->dbs |= default_afs[af].dbs;
291 }
9db7bf15 292}
aba5acdf 293
ab01dbbb 294static FILE *generic_proc_open(const char *env, const char *name)
aba5acdf 295{
ab01dbbb 296 const char *p = getenv(env);
aba5acdf 297 char store[128];
ab01dbbb 298
aba5acdf
SH
299 if (!p) {
300 p = getenv("PROC_ROOT") ? : "/proc";
301 snprintf(store, sizeof(store)-1, "%s/%s", p, name);
302 p = store;
303 }
ab01dbbb
SH
304
305 return fopen(p, "r");
aba5acdf
SH
306}
307
ab01dbbb 308static FILE *net_tcp_open(void)
aba5acdf
SH
309{
310 return generic_proc_open("PROC_NET_TCP", "net/tcp");
311}
312
ab01dbbb 313static FILE *net_tcp6_open(void)
aba5acdf
SH
314{
315 return generic_proc_open("PROC_NET_TCP6", "net/tcp6");
316}
317
ab01dbbb 318static FILE *net_udp_open(void)
aba5acdf
SH
319{
320 return generic_proc_open("PROC_NET_UDP", "net/udp");
321}
322
ab01dbbb 323static FILE *net_udp6_open(void)
aba5acdf
SH
324{
325 return generic_proc_open("PROC_NET_UDP6", "net/udp6");
326}
327
ab01dbbb 328static FILE *net_raw_open(void)
aba5acdf
SH
329{
330 return generic_proc_open("PROC_NET_RAW", "net/raw");
331}
332
ab01dbbb 333static FILE *net_raw6_open(void)
aba5acdf
SH
334{
335 return generic_proc_open("PROC_NET_RAW6", "net/raw6");
336}
337
ab01dbbb 338static FILE *net_unix_open(void)
aba5acdf
SH
339{
340 return generic_proc_open("PROC_NET_UNIX", "net/unix");
341}
342
ab01dbbb 343static FILE *net_packet_open(void)
aba5acdf
SH
344{
345 return generic_proc_open("PROC_NET_PACKET", "net/packet");
346}
347
ab01dbbb 348static FILE *net_netlink_open(void)
aba5acdf
SH
349{
350 return generic_proc_open("PROC_NET_NETLINK", "net/netlink");
351}
352
ab01dbbb 353static FILE *slabinfo_open(void)
aba5acdf
SH
354{
355 return generic_proc_open("PROC_SLABINFO", "slabinfo");
356}
357
ab01dbbb 358static FILE *net_sockstat_open(void)
aba5acdf
SH
359{
360 return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat");
361}
362
ab01dbbb 363static FILE *net_sockstat6_open(void)
aba5acdf
SH
364{
365 return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6");
366}
367
ab01dbbb 368static FILE *net_snmp_open(void)
aba5acdf
SH
369{
370 return generic_proc_open("PROC_NET_SNMP", "net/snmp");
371}
372
ab01dbbb 373static FILE *ephemeral_ports_open(void)
aba5acdf
SH
374{
375 return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
376}
377
fbc0f876
SF
378struct user_ent {
379 struct user_ent *next;
380 unsigned int ino;
381 int pid;
382 int fd;
116ac927
RH
383 char *process;
384 char *process_ctx;
385 char *socket_ctx;
fbc0f876
SF
386};
387
388#define USER_ENT_HASH_SIZE 256
389struct user_ent *user_ent_hash[USER_ENT_HASH_SIZE];
390
391static int user_ent_hashfn(unsigned int ino)
aba5acdf 392{
fbc0f876 393 int val = (ino >> 24) ^ (ino >> 16) ^ (ino >> 8) ^ ino;
aba5acdf 394
fbc0f876
SF
395 return val & (USER_ENT_HASH_SIZE - 1);
396}
397
116ac927
RH
398static void user_ent_add(unsigned int ino, char *process,
399 int pid, int fd,
400 char *proc_ctx,
401 char *sock_ctx)
fbc0f876
SF
402{
403 struct user_ent *p, **pp;
aba5acdf 404
116ac927
RH
405 p = malloc(sizeof(struct user_ent));
406 if (!p) {
407 fprintf(stderr, "ss: failed to malloc buffer\n");
fbc0f876 408 abort();
116ac927 409 }
fbc0f876
SF
410 p->next = NULL;
411 p->ino = ino;
412 p->pid = pid;
413 p->fd = fd;
116ac927
RH
414 p->process = strdup(process);
415 p->process_ctx = strdup(proc_ctx);
416 p->socket_ctx = strdup(sock_ctx);
fbc0f876
SF
417
418 pp = &user_ent_hash[user_ent_hashfn(ino)];
419 p->next = *pp;
420 *pp = p;
421}
aba5acdf 422
116ac927
RH
423static void user_ent_destroy(void)
424{
425 struct user_ent *p, *p_next;
426 int cnt = 0;
427
428 while (cnt != USER_ENT_HASH_SIZE) {
429 p = user_ent_hash[cnt];
430 while (p) {
431 free(p->process);
432 free(p->process_ctx);
433 free(p->socket_ctx);
434 p_next = p->next;
435 free(p);
436 p = p_next;
437 }
438 cnt++;
439 }
440}
441
fbc0f876
SF
442static void user_ent_hash_build(void)
443{
444 const char *root = getenv("PROC_ROOT") ? : "/proc/";
445 struct dirent *d;
446 char name[1024];
447 int nameoff;
448 DIR *dir;
116ac927
RH
449 char *pid_context;
450 char *sock_context;
451 const char *no_ctx = "unavailable";
452
453 /* If show_users & show_proc_ctx set only do this once */
454 if (user_ent_hash_build_init != 0)
455 return;
456
457 user_ent_hash_build_init = 1;
fbc0f876 458
0ee9052f 459 strncpy(name, root, sizeof(name)-1);
460 name[sizeof(name)-1] = 0;
461
fbc0f876 462 if (strlen(name) == 0 || name[strlen(name)-1] != '/')
aba5acdf 463 strcat(name, "/");
fbc0f876 464
aba5acdf 465 nameoff = strlen(name);
fbc0f876
SF
466
467 dir = opendir(name);
468 if (!dir)
469 return;
aba5acdf
SH
470
471 while ((d = readdir(dir)) != NULL) {
aba5acdf 472 struct dirent *d1;
aba5acdf 473 char process[16];
116ac927 474 char *p;
fbc0f876
SF
475 int pid, pos;
476 DIR *dir1;
477 char crap;
aba5acdf
SH
478
479 if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
480 continue;
481
116ac927
RH
482 if (getpidcon(pid, &pid_context) != 0)
483 pid_context = strdup(no_ctx);
484
0ee9052f 485 snprintf(name + nameoff, sizeof(name) - nameoff, "%d/fd/", pid);
aba5acdf 486 pos = strlen(name);
a02371fb
PS
487 if ((dir1 = opendir(name)) == NULL) {
488 free(pid_context);
aba5acdf 489 continue;
a02371fb 490 }
aba5acdf 491
fbc0f876 492 process[0] = '\0';
116ac927 493 p = process;
aba5acdf
SH
494
495 while ((d1 = readdir(dir1)) != NULL) {
fbc0f876
SF
496 const char *pattern = "socket:[";
497 unsigned int ino;
aba5acdf 498 char lnk[64];
18445b3e 499 int fd;
788731b3 500 ssize_t link_len;
116ac927 501 char tmp[1024];
aba5acdf
SH
502
503 if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
504 continue;
505
0ee9052f 506 snprintf(name+pos, sizeof(name) - pos, "%d", fd);
788731b3
TJ
507
508 link_len = readlink(name, lnk, sizeof(lnk)-1);
509 if (link_len == -1)
510 continue;
511 lnk[link_len] = '\0';
512
513 if (strncmp(lnk, pattern, strlen(pattern)))
aba5acdf
SH
514 continue;
515
fbc0f876 516 sscanf(lnk, "socket:[%u]", &ino);
aba5acdf 517
116ac927
RH
518 snprintf(tmp, sizeof(tmp), "%s/%d/fd/%s",
519 root, pid, d1->d_name);
520
521 if (getfilecon(tmp, &sock_context) <= 0)
522 sock_context = strdup(no_ctx);
523
524 if (*p == '\0') {
aba5acdf 525 FILE *fp;
fbc0f876 526
116ac927
RH
527 snprintf(tmp, sizeof(tmp), "%s/%d/stat",
528 root, pid);
aba5acdf 529 if ((fp = fopen(tmp, "r")) != NULL) {
d572ed4d
PS
530 if (fscanf(fp, "%*d (%[^)])", p) < 1)
531 ; /* ignore */
aba5acdf
SH
532 fclose(fp);
533 }
534 }
116ac927
RH
535 user_ent_add(ino, p, pid, fd,
536 pid_context, sock_context);
537 free(sock_context);
aba5acdf 538 }
116ac927 539 free(pid_context);
aba5acdf
SH
540 closedir(dir1);
541 }
542 closedir(dir);
fbc0f876
SF
543}
544
116ac927
RH
545enum entry_types {
546 USERS,
547 PROC_CTX,
548 PROC_SOCK_CTX
549};
550
551#define ENTRY_BUF_SIZE 512
acd1e437 552static int find_entry(unsigned int ino, char **buf, int type)
fbc0f876
SF
553{
554 struct user_ent *p;
555 int cnt = 0;
556 char *ptr;
532ca40a 557 char *new_buf;
116ac927
RH
558 int len, new_buf_len;
559 int buf_used = 0;
560 int buf_len = 0;
fbc0f876
SF
561
562 if (!ino)
563 return 0;
564
565 p = user_ent_hash[user_ent_hashfn(ino)];
116ac927 566 ptr = *buf = NULL;
fbc0f876
SF
567 while (p) {
568 if (p->ino != ino)
569 goto next;
570
116ac927
RH
571 while (1) {
572 ptr = *buf + buf_used;
573 switch (type) {
574 case USERS:
575 len = snprintf(ptr, buf_len - buf_used,
576 "(\"%s\",pid=%d,fd=%d),",
577 p->process, p->pid, p->fd);
578 break;
579 case PROC_CTX:
580 len = snprintf(ptr, buf_len - buf_used,
581 "(\"%s\",pid=%d,proc_ctx=%s,fd=%d),",
582 p->process, p->pid,
583 p->process_ctx, p->fd);
584 break;
585 case PROC_SOCK_CTX:
586 len = snprintf(ptr, buf_len - buf_used,
587 "(\"%s\",pid=%d,proc_ctx=%s,fd=%d,sock_ctx=%s),",
588 p->process, p->pid,
589 p->process_ctx, p->fd,
590 p->socket_ctx);
591 break;
592 default:
593 fprintf(stderr, "ss: invalid type: %d\n", type);
594 abort();
595 }
fbc0f876 596
116ac927
RH
597 if (len < 0 || len >= buf_len - buf_used) {
598 new_buf_len = buf_len + ENTRY_BUF_SIZE;
532ca40a 599 new_buf = realloc(*buf, new_buf_len);
116ac927
RH
600 if (!new_buf) {
601 fprintf(stderr, "ss: failed to malloc buffer\n");
602 abort();
603 }
532ca40a 604 *buf = new_buf;
116ac927
RH
605 buf_len = new_buf_len;
606 continue;
607 } else {
608 buf_used += len;
609 break;
610 }
611 }
fbc0f876 612 cnt++;
116ac927 613next:
fbc0f876
SF
614 p = p->next;
615 }
116ac927
RH
616 if (buf_used) {
617 ptr = *buf + buf_used;
fbc0f876 618 ptr[-1] = '\0';
116ac927 619 }
aba5acdf
SH
620 return cnt;
621}
622
aba5acdf
SH
623/* Get stats from slab */
624
acd1e437 625struct slabstat {
aba5acdf
SH
626 int socks;
627 int tcp_ports;
628 int tcp_tws;
629 int tcp_syns;
630 int skbs;
631};
632
a221d621 633static struct slabstat slabstat;
aba5acdf 634
acd1e437
SH
635static const char *slabstat_ids[] = {
636
aba5acdf
SH
637 "sock",
638 "tcp_bind_bucket",
639 "tcp_tw_bucket",
640 "tcp_open_request",
641 "skbuff_head_cache",
642};
643
d1f28cf1 644static int get_slabstat(struct slabstat *s)
aba5acdf
SH
645{
646 char buf[256];
647 FILE *fp;
648 int cnt;
a221d621
BL
649 static int slabstat_valid;
650
651 if (slabstat_valid)
652 return 0;
aba5acdf
SH
653
654 memset(s, 0, sizeof(*s));
655
ab01dbbb
SH
656 fp = slabinfo_open();
657 if (!fp)
aba5acdf
SH
658 return -1;
659
660 cnt = sizeof(*s)/sizeof(int);
661
d572ed4d
PS
662 if (!fgets(buf, sizeof(buf), fp)) {
663 fclose(fp);
664 return -1;
665 }
acd1e437 666 while (fgets(buf, sizeof(buf), fp) != NULL) {
aba5acdf 667 int i;
acd1e437 668
62000e51 669 for (i = 0; i < ARRAY_SIZE(slabstat_ids); i++) {
aba5acdf
SH
670 if (memcmp(buf, slabstat_ids[i], strlen(slabstat_ids[i])) == 0) {
671 sscanf(buf, "%*s%d", ((int *)s) + i);
672 cnt--;
673 break;
674 }
675 }
676 if (cnt <= 0)
677 break;
678 }
679
a221d621
BL
680 slabstat_valid = 1;
681
aba5acdf
SH
682 fclose(fp);
683 return 0;
684}
685
2e7e805d 686static unsigned long long cookie_sk_get(const uint32_t *cookie)
f1b39e1b 687{
2e7e805d 688 return (((unsigned long long)cookie[1] << 31) << 1) | cookie[0];
f1b39e1b
VK
689}
690
7d105b56
SH
691static const char *sstate_name[] = {
692 "UNKNOWN",
9cb1eccf
ED
693 [SS_ESTABLISHED] = "ESTAB",
694 [SS_SYN_SENT] = "SYN-SENT",
695 [SS_SYN_RECV] = "SYN-RECV",
696 [SS_FIN_WAIT1] = "FIN-WAIT-1",
697 [SS_FIN_WAIT2] = "FIN-WAIT-2",
698 [SS_TIME_WAIT] = "TIME-WAIT",
699 [SS_CLOSE] = "UNCONN",
700 [SS_CLOSE_WAIT] = "CLOSE-WAIT",
701 [SS_LAST_ACK] = "LAST-ACK",
acd1e437 702 [SS_LISTEN] = "LISTEN",
9cb1eccf 703 [SS_CLOSING] = "CLOSING",
aba5acdf
SH
704};
705
7d105b56
SH
706static const char *sstate_namel[] = {
707 "UNKNOWN",
9cb1eccf
ED
708 [SS_ESTABLISHED] = "established",
709 [SS_SYN_SENT] = "syn-sent",
710 [SS_SYN_RECV] = "syn-recv",
711 [SS_FIN_WAIT1] = "fin-wait-1",
712 [SS_FIN_WAIT2] = "fin-wait-2",
713 [SS_TIME_WAIT] = "time-wait",
714 [SS_CLOSE] = "unconnected",
715 [SS_CLOSE_WAIT] = "close-wait",
716 [SS_LAST_ACK] = "last-ack",
acd1e437 717 [SS_LISTEN] = "listening",
9cb1eccf 718 [SS_CLOSING] = "closing",
aba5acdf
SH
719};
720
acd1e437 721struct sockstat {
ec4d0d8a
VK
722 struct sockstat *next;
723 unsigned int type;
89f634f9 724 uint16_t prot;
8250bc9f
VK
725 inet_prefix local;
726 inet_prefix remote;
727 int lport;
728 int rport;
729 int state;
730 int rq, wq;
acd1e437
SH
731 unsigned int ino;
732 unsigned int uid;
8250bc9f
VK
733 int refcnt;
734 unsigned int iface;
735 unsigned long long sk;
99bb68ff
VK
736 char *name;
737 char *peer_name;
055840f2
VK
738};
739
acd1e437 740struct dctcpstat {
055840f2
VK
741 unsigned int ce_state;
742 unsigned int alpha;
743 unsigned int ab_ecn;
744 unsigned int ab_tot;
745 bool enabled;
746};
747
acd1e437 748struct tcpstat {
055840f2 749 struct sockstat ss;
8250bc9f
VK
750 int timer;
751 int timeout;
752 int probes;
d2055ea5 753 char cong_alg[16];
8250bc9f
VK
754 double rto, ato, rtt, rttvar;
755 int qack, cwnd, ssthresh, backoff;
756 double send_bps;
757 int snd_wscale;
758 int rcv_wscale;
759 int mss;
760 unsigned int lastsnd;
761 unsigned int lastrcv;
762 unsigned int lastack;
763 double pacing_rate;
764 double pacing_rate_max;
1a4dda71
ED
765 unsigned long long bytes_acked;
766 unsigned long long bytes_received;
ecb435ea
CG
767 unsigned int segs_out;
768 unsigned int segs_in;
414aeec9
MKL
769 unsigned int data_segs_out;
770 unsigned int data_segs_in;
8250bc9f
VK
771 unsigned int unacked;
772 unsigned int retrans;
773 unsigned int retrans_total;
774 unsigned int lost;
775 unsigned int sacked;
776 unsigned int fackets;
777 unsigned int reordering;
9e99e495 778 unsigned int not_sent;
8250bc9f 779 double rcv_rtt;
9e99e495 780 double min_rtt;
8250bc9f
VK
781 int rcv_space;
782 bool has_ts_opt;
783 bool has_sack_opt;
784 bool has_ecn_opt;
785 bool has_ecnseen_opt;
786 bool has_fastopen_opt;
787 bool has_wscale_opt;
788 struct dctcpstat *dctcp;
aba5acdf
SH
789};
790
2d791bc8
VK
791static void sock_state_print(struct sockstat *s, const char *sock_name)
792{
793 if (netid_width)
794 printf("%-*s ", netid_width, sock_name);
795 if (state_width)
796 printf("%-*s ", state_width, sstate_name[s->state]);
797
798 printf("%-6d %-6d ", s->rq, s->wq);
799}
800
f1b39e1b
VK
801static void sock_details_print(struct sockstat *s)
802{
803 if (s->uid)
804 printf(" uid:%u", s->uid);
805
806 printf(" ino:%u", s->ino);
807 printf(" sk:%llx", s->sk);
808}
809
b217df10
VK
810static void sock_addr_print_width(int addr_len, const char *addr, char *delim,
811 int port_len, const char *port, const char *ifname)
812{
813 if (ifname) {
814 printf("%*s%%%s%s%-*s ", addr_len, addr, ifname, delim,
815 port_len, port);
acd1e437 816 } else {
b217df10
VK
817 printf("%*s%s%-*s ", addr_len, addr, delim, port_len, port);
818 }
819}
820
821static void sock_addr_print(const char *addr, char *delim, const char *port,
822 const char *ifname)
823{
824 sock_addr_print_width(addr_width, addr, delim, serv_width, port, ifname);
825}
826
7d105b56 827static const char *tmr_name[] = {
aba5acdf
SH
828 "off",
829 "on",
830 "keepalive",
831 "timewait",
832 "persist",
833 "unknown"
834};
835
d1f28cf1 836static const char *print_ms_timer(int timeout)
aba5acdf
SH
837{
838 static char buf[64];
839 int secs, msecs, minutes;
acd1e437 840
aba5acdf
SH
841 if (timeout < 0)
842 timeout = 0;
843 secs = timeout/1000;
844 minutes = secs/60;
845 secs = secs%60;
846 msecs = timeout%1000;
847 buf[0] = 0;
848 if (minutes) {
849 msecs = 0;
850 snprintf(buf, sizeof(buf)-16, "%dmin", minutes);
851 if (minutes > 9)
852 secs = 0;
853 }
854 if (secs) {
855 if (secs > 9)
856 msecs = 0;
857 sprintf(buf+strlen(buf), "%d%s", secs, msecs ? "." : "sec");
858 }
859 if (msecs)
860 sprintf(buf+strlen(buf), "%03dms", msecs);
861 return buf;
e7113c61 862}
aba5acdf 863
22588a0e 864struct scache {
aba5acdf
SH
865 struct scache *next;
866 int port;
867 char *name;
868 const char *proto;
869};
870
871struct scache *rlist;
872
d1f28cf1 873static void init_service_resolver(void)
aba5acdf
SH
874{
875 char buf[128];
876 FILE *fp = popen("/usr/sbin/rpcinfo -p 2>/dev/null", "r");
596307ea
PS
877
878 if (!fp)
879 return;
880
881 if (!fgets(buf, sizeof(buf), fp)) {
2bcc3c16 882 pclose(fp);
596307ea
PS
883 return;
884 }
885 while (fgets(buf, sizeof(buf), fp) != NULL) {
886 unsigned int progn, port;
887 char proto[128], prog[128] = "rpc.";
888 struct scache *c;
889
890 if (sscanf(buf, "%u %*d %s %u %s",
acd1e437 891 &progn, proto, &port, prog+4) != 4)
596307ea
PS
892 continue;
893
894 if (!(c = malloc(sizeof(*c))))
895 continue;
896
897 c->port = port;
898 c->name = strdup(prog);
899 if (strcmp(proto, TCP_PROTO) == 0)
900 c->proto = TCP_PROTO;
901 else if (strcmp(proto, UDP_PROTO) == 0)
902 c->proto = UDP_PROTO;
903 else
904 c->proto = NULL;
905 c->next = rlist;
906 rlist = c;
aba5acdf 907 }
596307ea 908 pclose(fp);
aba5acdf
SH
909}
910
ab61159a
SH
911/* Even do not try default linux ephemeral port ranges:
912 * default /etc/services contains so much of useless crap
913 * wouldbe "allocated" to this area that resolution
914 * is really harmful. I shrug each time when seeing
915 * "socks" or "cfinger" in dumps.
916 */
917static int is_ephemeral(int port)
918{
acd1e437 919 static int min = 0, max;
c29d3792
PS
920
921 if (!min) {
ab01dbbb 922 FILE *f = ephemeral_ports_open();
acd1e437 923
c29d3792
PS
924 if (!f || fscanf(f, "%d %d", &min, &max) < 2) {
925 min = 1024;
926 max = 4999;
ab61159a 927 }
c29d3792
PS
928 if (f)
929 fclose(f);
ab61159a 930 }
c29d3792 931 return port >= min && port <= max;
ab61159a
SH
932}
933
934
d1f28cf1 935static const char *__resolve_service(int port)
aba5acdf
SH
936{
937 struct scache *c;
938
939 for (c = rlist; c; c = c->next) {
940 if (c->port == port && c->proto == dg_proto)
941 return c->name;
942 }
943
ab61159a 944 if (!is_ephemeral(port)) {
aba5acdf
SH
945 static int notfirst;
946 struct servent *se;
acd1e437 947
aba5acdf
SH
948 if (!notfirst) {
949 setservent(1);
950 notfirst = 1;
ae665a52 951 }
aba5acdf
SH
952 se = getservbyport(htons(port), dg_proto);
953 if (se)
954 return se->s_name;
955 }
956
957 return NULL;
958}
959
22588a0e
ED
960#define SCACHE_BUCKETS 1024
961static struct scache *cache_htab[SCACHE_BUCKETS];
aba5acdf 962
d1f28cf1 963static const char *resolve_service(int port)
aba5acdf
SH
964{
965 static char buf[128];
22588a0e
ED
966 struct scache *c;
967 const char *res;
968 int hash;
aba5acdf
SH
969
970 if (port == 0) {
971 buf[0] = '*';
972 buf[1] = 0;
973 return buf;
974 }
975
22588a0e
ED
976 if (!resolve_services)
977 goto do_numeric;
aba5acdf 978
22588a0e
ED
979 if (dg_proto == RAW_PROTO)
980 return inet_proto_n2a(port, buf, sizeof(buf));
981
982
983 hash = (port^(((unsigned long)dg_proto)>>2)) % SCACHE_BUCKETS;
984
985 for (c = cache_htab[hash]; c; c = c->next) {
986 if (c->port == port && c->proto == dg_proto)
987 goto do_cache;
aba5acdf
SH
988 }
989
22588a0e
ED
990 c = malloc(sizeof(*c));
991 if (!c)
992 goto do_numeric;
993 res = __resolve_service(port);
994 c->port = port;
995 c->name = res ? strdup(res) : NULL;
996 c->proto = dg_proto;
997 c->next = cache_htab[hash];
998 cache_htab[hash] = c;
999
1000do_cache:
1001 if (c->name)
1002 return c->name;
1003
1004do_numeric:
aba5acdf
SH
1005 sprintf(buf, "%u", port);
1006 return buf;
1007}
1008
b217df10 1009static void inet_addr_print(const inet_prefix *a, int port, unsigned int ifindex)
aba5acdf
SH
1010{
1011 char buf[1024];
1012 const char *ap = buf;
b217df10
VK
1013 int est_len = addr_width;
1014 const char *ifname = NULL;
aba5acdf
SH
1015
1016 if (a->family == AF_INET) {
1017 if (a->data[0] == 0) {
1018 buf[0] = '*';
1019 buf[1] = 0;
1020 } else {
a418e451 1021 ap = format_host(AF_INET, 4, a->data);
aba5acdf
SH
1022 }
1023 } else {
a418e451 1024 ap = format_host(a->family, 16, a->data);
aba5acdf
SH
1025 est_len = strlen(ap);
1026 if (est_len <= addr_width)
1027 est_len = addr_width;
1028 else
1029 est_len = addr_width + ((est_len-addr_width+3)/4)*4;
1030 }
b217df10 1031
7c8a3cfb 1032 if (ifindex) {
b217df10
VK
1033 ifname = ll_index_to_name(ifindex);
1034 est_len -= strlen(ifname) + 1; /* +1 for percent char */
4fcfb6bc
MS
1035 if (est_len < 0)
1036 est_len = 0;
b217df10 1037 }
7c8a3cfb 1038
b217df10
VK
1039 sock_addr_print_width(est_len, ap, ":", serv_width, resolve_service(port),
1040 ifname);
aba5acdf
SH
1041}
1042
acd1e437 1043struct aafilter {
aba5acdf
SH
1044 inet_prefix addr;
1045 int port;
2d293212 1046 unsigned int iface;
aba5acdf
SH
1047 struct aafilter *next;
1048};
1049
d1f28cf1
SH
1050static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
1051 int plen)
aba5acdf
SH
1052{
1053 if (!inet_addr_match(a, p, plen))
1054 return 0;
7d105b56 1055
aba5acdf
SH
1056 /* Cursed "v4 mapped" addresses: v4 mapped socket matches
1057 * pure IPv4 rule, but v4-mapped rule selects only v4-mapped
1058 * sockets. Fair? */
1059 if (p->family == AF_INET && a->family == AF_INET6) {
1060 if (a->data[0] == 0 && a->data[1] == 0 &&
1061 a->data[2] == htonl(0xffff)) {
1062 inet_prefix tmp = *a;
acd1e437 1063
aba5acdf
SH
1064 tmp.data[0] = a->data[3];
1065 return inet_addr_match(&tmp, p, plen);
1066 }
1067 }
1068 return 1;
1069}
1070
d1f28cf1 1071static int unix_match(const inet_prefix *a, const inet_prefix *p)
aba5acdf 1072{
99bb68ff 1073 char *addr, *pattern;
acd1e437 1074
99bb68ff
VK
1075 memcpy(&addr, a->data, sizeof(addr));
1076 memcpy(&pattern, p->data, sizeof(pattern));
aba5acdf
SH
1077 if (pattern == NULL)
1078 return 1;
1079 if (addr == NULL)
1080 addr = "";
1081 return !fnmatch(pattern, addr, 0);
1082}
1083
055840f2 1084static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
aba5acdf
SH
1085{
1086 switch (f->type) {
1087 case SSF_S_AUTO:
1088 {
aba5acdf 1089 if (s->local.family == AF_UNIX) {
99bb68ff 1090 char *p;
acd1e437 1091
99bb68ff 1092 memcpy(&p, s->local.data, sizeof(p));
aba5acdf 1093 return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
ae665a52 1094 strspn(p+1, "0123456789abcdef") == 5);
aba5acdf
SH
1095 }
1096 if (s->local.family == AF_PACKET)
bbd303d1 1097 return s->lport == 0 && s->local.data[0] == 0;
aba5acdf
SH
1098 if (s->local.family == AF_NETLINK)
1099 return s->lport < 0;
1100
c29d3792 1101 return is_ephemeral(s->lport);
aba5acdf
SH
1102 }
1103 case SSF_DCOND:
1104 {
acd1e437
SH
1105 struct aafilter *a = (void *)f->pred;
1106
aba5acdf
SH
1107 if (a->addr.family == AF_UNIX)
1108 return unix_match(&s->remote, &a->addr);
1109 if (a->port != -1 && a->port != s->rport)
1110 return 0;
1111 if (a->addr.bitlen) {
1112 do {
1113 if (!inet2_addr_match(&s->remote, &a->addr, a->addr.bitlen))
1114 return 1;
1115 } while ((a = a->next) != NULL);
1116 return 0;
1117 }
1118 return 1;
1119 }
1120 case SSF_SCOND:
1121 {
acd1e437
SH
1122 struct aafilter *a = (void *)f->pred;
1123
aba5acdf
SH
1124 if (a->addr.family == AF_UNIX)
1125 return unix_match(&s->local, &a->addr);
1126 if (a->port != -1 && a->port != s->lport)
1127 return 0;
1128 if (a->addr.bitlen) {
1129 do {
1130 if (!inet2_addr_match(&s->local, &a->addr, a->addr.bitlen))
1131 return 1;
ae665a52 1132 } while ((a = a->next) != NULL);
aba5acdf
SH
1133 return 0;
1134 }
1135 return 1;
1136 }
1137 case SSF_D_GE:
1138 {
acd1e437
SH
1139 struct aafilter *a = (void *)f->pred;
1140
aba5acdf
SH
1141 return s->rport >= a->port;
1142 }
1143 case SSF_D_LE:
1144 {
acd1e437
SH
1145 struct aafilter *a = (void *)f->pred;
1146
aba5acdf
SH
1147 return s->rport <= a->port;
1148 }
1149 case SSF_S_GE:
1150 {
acd1e437
SH
1151 struct aafilter *a = (void *)f->pred;
1152
aba5acdf
SH
1153 return s->lport >= a->port;
1154 }
1155 case SSF_S_LE:
1156 {
acd1e437
SH
1157 struct aafilter *a = (void *)f->pred;
1158
aba5acdf
SH
1159 return s->lport <= a->port;
1160 }
2d293212
DA
1161 case SSF_DEVCOND:
1162 {
1163 struct aafilter *a = (void *)f->pred;
aba5acdf 1164
2d293212
DA
1165 return s->iface == a->iface;
1166 }
aba5acdf
SH
1167 /* Yup. It is recursion. Sorry. */
1168 case SSF_AND:
1169 return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s);
1170 case SSF_OR:
1171 return run_ssfilter(f->pred, s) || run_ssfilter(f->post, s);
1172 case SSF_NOT:
1173 return !run_ssfilter(f->pred, s);
1174 default:
1175 abort();
1176 }
1177}
1178
ae665a52 1179/* Relocate external jumps by reloc. */
b4b0b7d5 1180static void ssfilter_patch(char *a, int len, int reloc)
aba5acdf
SH
1181{
1182 while (len > 0) {
acd1e437
SH
1183 struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)a;
1184
aba5acdf
SH
1185 if (op->no == len+4)
1186 op->no += reloc;
1187 len -= op->yes;
1188 a += op->yes;
1189 }
1190 if (len < 0)
1191 abort();
1192}
1193
b4b0b7d5 1194static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
aba5acdf
SH
1195{
1196 switch (f->type) {
1197 case SSF_S_AUTO:
1198 {
acd1e437
SH
1199 if (!(*bytecode = malloc(4))) abort();
1200 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 };
df39de8d 1201 return 4;
aba5acdf
SH
1202 }
1203 case SSF_DCOND:
1204 case SSF_SCOND:
1205 {
acd1e437 1206 struct aafilter *a = (void *)f->pred;
aba5acdf
SH
1207 struct aafilter *b;
1208 char *ptr;
351efcde 1209 int code = (f->type == SSF_DCOND ? INET_DIAG_BC_D_COND : INET_DIAG_BC_S_COND);
aba5acdf
SH
1210 int len = 0;
1211
acd1e437 1212 for (b = a; b; b = b->next) {
351efcde 1213 len += 4 + sizeof(struct inet_diag_hostcond);
aba5acdf
SH
1214 if (a->addr.family == AF_INET6)
1215 len += 16;
1216 else
1217 len += 4;
1218 if (b->next)
1219 len += 4;
1220 }
1221 if (!(ptr = malloc(len))) abort();
1222 *bytecode = ptr;
acd1e437 1223 for (b = a; b; b = b->next) {
351efcde 1224 struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)ptr;
aba5acdf 1225 int alen = (a->addr.family == AF_INET6 ? 16 : 4);
351efcde 1226 int oplen = alen + 4 + sizeof(struct inet_diag_hostcond);
acd1e437 1227 struct inet_diag_hostcond *cond = (struct inet_diag_hostcond *)(ptr+4);
aba5acdf 1228
351efcde 1229 *op = (struct inet_diag_bc_op){ code, oplen, oplen+4 };
aba5acdf
SH
1230 cond->family = a->addr.family;
1231 cond->port = a->port;
1232 cond->prefix_len = a->addr.bitlen;
1233 memcpy(cond->addr, a->addr.data, alen);
1234 ptr += oplen;
1235 if (b->next) {
351efcde
SH
1236 op = (struct inet_diag_bc_op *)ptr;
1237 *op = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, len - (ptr-*bytecode)};
aba5acdf
SH
1238 ptr += 4;
1239 }
1240 }
1241 return ptr - *bytecode;
1242 }
1243 case SSF_D_GE:
1244 {
acd1e437
SH
1245 struct aafilter *x = (void *)f->pred;
1246
1247 if (!(*bytecode = malloc(8))) abort();
1248 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 };
1249 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1250 return 8;
1251 }
1252 case SSF_D_LE:
1253 {
acd1e437
SH
1254 struct aafilter *x = (void *)f->pred;
1255
1256 if (!(*bytecode = malloc(8))) abort();
1257 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 };
1258 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1259 return 8;
1260 }
1261 case SSF_S_GE:
1262 {
acd1e437
SH
1263 struct aafilter *x = (void *)f->pred;
1264
1265 if (!(*bytecode = malloc(8))) abort();
1266 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 };
1267 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1268 return 8;
1269 }
1270 case SSF_S_LE:
1271 {
acd1e437
SH
1272 struct aafilter *x = (void *)f->pred;
1273
1274 if (!(*bytecode = malloc(8))) abort();
1275 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 };
1276 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1277 return 8;
1278 }
1279
1280 case SSF_AND:
1281 {
376fb868 1282 char *a1 = NULL, *a2 = NULL, *a;
2a4fa1c3 1283 int l1, l2;
acd1e437 1284
aba5acdf
SH
1285 l1 = ssfilter_bytecompile(f->pred, &a1);
1286 l2 = ssfilter_bytecompile(f->post, &a2);
376fb868
DA
1287 if (!l1 || !l2) {
1288 free(a1);
1289 free(a2);
1290 return 0;
1291 }
aba5acdf
SH
1292 if (!(a = malloc(l1+l2))) abort();
1293 memcpy(a, a1, l1);
1294 memcpy(a+l1, a2, l2);
1295 free(a1); free(a2);
1296 ssfilter_patch(a, l1, l2);
1297 *bytecode = a;
1298 return l1+l2;
1299 }
1300 case SSF_OR:
1301 {
376fb868 1302 char *a1 = NULL, *a2 = NULL, *a;
2a4fa1c3 1303 int l1, l2;
acd1e437 1304
aba5acdf
SH
1305 l1 = ssfilter_bytecompile(f->pred, &a1);
1306 l2 = ssfilter_bytecompile(f->post, &a2);
376fb868
DA
1307 if (!l1 || !l2) {
1308 free(a1);
1309 free(a2);
1310 return 0;
1311 }
aba5acdf
SH
1312 if (!(a = malloc(l1+l2+4))) abort();
1313 memcpy(a, a1, l1);
1314 memcpy(a+l1+4, a2, l2);
1315 free(a1); free(a2);
acd1e437 1316 *(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 };
aba5acdf
SH
1317 *bytecode = a;
1318 return l1+l2+4;
1319 }
1320 case SSF_NOT:
1321 {
376fb868 1322 char *a1 = NULL, *a;
2a4fa1c3 1323 int l1;
acd1e437 1324
aba5acdf 1325 l1 = ssfilter_bytecompile(f->pred, &a1);
376fb868
DA
1326 if (!l1) {
1327 free(a1);
1328 return 0;
1329 }
aba5acdf
SH
1330 if (!(a = malloc(l1+4))) abort();
1331 memcpy(a, a1, l1);
1332 free(a1);
acd1e437 1333 *(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 };
aba5acdf
SH
1334 *bytecode = a;
1335 return l1+4;
2d293212
DA
1336 }
1337 case SSF_DEVCOND:
1338 {
1339 /* bytecompile for SSF_DEVCOND not supported yet */
1340 return 0;
aba5acdf
SH
1341 }
1342 default:
1343 abort();
1344 }
1345}
1346
b4b0b7d5 1347static int remember_he(struct aafilter *a, struct hostent *he)
aba5acdf 1348{
ae665a52 1349 char **ptr = he->h_addr_list;
aba5acdf
SH
1350 int cnt = 0;
1351 int len;
1352
1353 if (he->h_addrtype == AF_INET)
1354 len = 4;
1355 else if (he->h_addrtype == AF_INET6)
1356 len = 16;
1357 else
1358 return 0;
1359
1360 while (*ptr) {
1361 struct aafilter *b = a;
acd1e437 1362
aba5acdf
SH
1363 if (a->addr.bitlen) {
1364 if ((b = malloc(sizeof(*b))) == NULL)
1365 return cnt;
1366 *b = *a;
1367 b->next = a->next;
1368 a->next = b;
1369 }
1370 memcpy(b->addr.data, *ptr, len);
1371 b->addr.bytelen = len;
1372 b->addr.bitlen = len*8;
1373 b->addr.family = he->h_addrtype;
1374 ptr++;
1375 cnt++;
1376 }
1377 return cnt;
1378}
1379
b4b0b7d5 1380static int get_dns_host(struct aafilter *a, const char *addr, int fam)
aba5acdf
SH
1381{
1382 static int notfirst;
1383 int cnt = 0;
1384 struct hostent *he;
1385
1386 a->addr.bitlen = 0;
1387 if (!notfirst) {
1388 sethostent(1);
1389 notfirst = 1;
1390 }
1391 he = gethostbyname2(addr, fam == AF_UNSPEC ? AF_INET : fam);
1392 if (he)
1393 cnt = remember_he(a, he);
1394 if (fam == AF_UNSPEC) {
1395 he = gethostbyname2(addr, AF_INET6);
1396 if (he)
1397 cnt += remember_he(a, he);
1398 }
1399 return !cnt;
1400}
1401
acd1e437 1402static int xll_initted;
aba5acdf 1403
b4b0b7d5 1404static void xll_init(void)
aba5acdf
SH
1405{
1406 struct rtnl_handle rth;
acd1e437 1407
d2468da0
SH
1408 if (rtnl_open(&rth, 0) < 0)
1409 exit(1);
1410
aba5acdf
SH
1411 ll_init_map(&rth);
1412 rtnl_close(&rth);
1413 xll_initted = 1;
1414}
1415
b4b0b7d5 1416static const char *xll_index_to_name(int index)
aba5acdf
SH
1417{
1418 if (!xll_initted)
1419 xll_init();
1420 return ll_index_to_name(index);
1421}
1422
b4b0b7d5 1423static int xll_name_to_index(const char *dev)
aba5acdf
SH
1424{
1425 if (!xll_initted)
1426 xll_init();
1427 return ll_name_to_index(dev);
1428}
1429
2d293212
DA
1430void *parse_devcond(char *name)
1431{
1432 struct aafilter a = { .iface = 0 };
1433 struct aafilter *res;
1434
1435 a.iface = xll_name_to_index(name);
1436 if (a.iface == 0) {
1437 char *end;
930d3f28 1438 unsigned long n;
2d293212 1439
930d3f28
DA
1440 n = strtoul(name, &end, 0);
1441 if (!end || end == name || *end || n > UINT_MAX)
2d293212 1442 return NULL;
930d3f28
DA
1443
1444 a.iface = n;
2d293212
DA
1445 }
1446
1447 res = malloc(sizeof(*res));
1448 *res = a;
1449
1450 return res;
1451}
1452
7871f7db 1453void *parse_hostcond(char *addr, bool is_port)
aba5acdf
SH
1454{
1455 char *port = NULL;
1527a17e 1456 struct aafilter a = { .port = -1 };
aba5acdf 1457 struct aafilter *res;
1527a17e 1458 int fam = preferred_family;
9db7bf15 1459 struct filter *f = &current_filter;
aba5acdf 1460
1527a17e 1461 if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) {
aba5acdf 1462 char *p;
acd1e437 1463
aba5acdf
SH
1464 a.addr.family = AF_UNIX;
1465 if (strncmp(addr, "unix:", 5) == 0)
acd1e437 1466 addr += 5;
aba5acdf
SH
1467 p = strdup(addr);
1468 a.addr.bitlen = 8*strlen(p);
99bb68ff 1469 memcpy(a.addr.data, &p, sizeof(p));
9db7bf15 1470 fam = AF_UNIX;
aba5acdf
SH
1471 goto out;
1472 }
1473
1527a17e 1474 if (fam == AF_PACKET || strncmp(addr, "link:", 5) == 0) {
aba5acdf
SH
1475 a.addr.family = AF_PACKET;
1476 a.addr.bitlen = 0;
1477 if (strncmp(addr, "link:", 5) == 0)
acd1e437 1478 addr += 5;
aba5acdf
SH
1479 port = strchr(addr, ':');
1480 if (port) {
1481 *port = 0;
1482 if (port[1] && strcmp(port+1, "*")) {
1483 if (get_integer(&a.port, port+1, 0)) {
1484 if ((a.port = xll_name_to_index(port+1)) <= 0)
1485 return NULL;
1486 }
1487 }
1488 }
1489 if (addr[0] && strcmp(addr, "*")) {
1490 unsigned short tmp;
acd1e437 1491
aba5acdf
SH
1492 a.addr.bitlen = 32;
1493 if (ll_proto_a2n(&tmp, addr))
1494 return NULL;
1495 a.addr.data[0] = ntohs(tmp);
1496 }
9db7bf15 1497 fam = AF_PACKET;
aba5acdf
SH
1498 goto out;
1499 }
1500
1527a17e 1501 if (fam == AF_NETLINK || strncmp(addr, "netlink:", 8) == 0) {
aba5acdf
SH
1502 a.addr.family = AF_NETLINK;
1503 a.addr.bitlen = 0;
1504 if (strncmp(addr, "netlink:", 8) == 0)
acd1e437 1505 addr += 8;
aba5acdf
SH
1506 port = strchr(addr, ':');
1507 if (port) {
1508 *port = 0;
1509 if (port[1] && strcmp(port+1, "*")) {
1510 if (get_integer(&a.port, port+1, 0)) {
1511 if (strcmp(port+1, "kernel") == 0)
1512 a.port = 0;
1513 else
1514 return NULL;
1515 }
1516 }
1517 }
1518 if (addr[0] && strcmp(addr, "*")) {
1519 a.addr.bitlen = 32;
b00daf6a 1520 if (nl_proto_a2n(&a.addr.data[0], addr) == -1)
1521 return NULL;
aba5acdf 1522 }
9db7bf15 1523 fam = AF_NETLINK;
aba5acdf
SH
1524 goto out;
1525 }
1526
1527a17e 1527 if (fam == AF_INET || !strncmp(addr, "inet:", 5)) {
aba5acdf 1528 fam = AF_INET;
1527a17e
VK
1529 if (!strncmp(addr, "inet:", 5))
1530 addr += 5;
1531 } else if (fam == AF_INET6 || !strncmp(addr, "inet6:", 6)) {
aba5acdf 1532 fam = AF_INET6;
1527a17e
VK
1533 if (!strncmp(addr, "inet6:", 6))
1534 addr += 6;
aba5acdf
SH
1535 }
1536
1537 /* URL-like literal [] */
1538 if (addr[0] == '[') {
1539 addr++;
1540 if ((port = strchr(addr, ']')) == NULL)
1541 return NULL;
1542 *port++ = 0;
1543 } else if (addr[0] == '*') {
1544 port = addr+1;
1545 } else {
1546 port = strrchr(strchr(addr, '/') ? : addr, ':');
1547 }
7871f7db
VK
1548
1549 if (is_port)
1550 port = addr;
1551
aba5acdf 1552 if (port && *port) {
7871f7db
VK
1553 if (*port == ':')
1554 *port++ = 0;
1555
aba5acdf
SH
1556 if (*port && *port != '*') {
1557 if (get_integer(&a.port, port, 0)) {
1558 struct servent *se1 = NULL;
1559 struct servent *se2 = NULL;
acd1e437 1560
aba5acdf
SH
1561 if (current_filter.dbs&(1<<UDP_DB))
1562 se1 = getservbyname(port, UDP_PROTO);
1563 if (current_filter.dbs&(1<<TCP_DB))
1564 se2 = getservbyname(port, TCP_PROTO);
1565 if (se1 && se2 && se1->s_port != se2->s_port) {
1566 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
1567 return NULL;
1568 }
1569 if (!se1)
1570 se1 = se2;
1571 if (se1) {
1572 a.port = ntohs(se1->s_port);
1573 } else {
1574 struct scache *s;
acd1e437 1575
aba5acdf
SH
1576 for (s = rlist; s; s = s->next) {
1577 if ((s->proto == UDP_PROTO &&
1578 (current_filter.dbs&(1<<UDP_DB))) ||
1579 (s->proto == TCP_PROTO &&
1580 (current_filter.dbs&(1<<TCP_DB)))) {
1581 if (s->name && strcmp(s->name, port) == 0) {
1582 if (a.port > 0 && a.port != s->port) {
1583 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
1584 return NULL;
1585 }
1586 a.port = s->port;
1587 }
1588 }
1589 }
1590 if (a.port <= 0) {
1591 fprintf(stderr, "Error: \"%s\" does not look like a port.\n", port);
1592 return NULL;
1593 }
1594 }
1595 }
1596 }
1597 }
7871f7db 1598 if (!is_port && addr && *addr && *addr != '*') {
aba5acdf
SH
1599 if (get_prefix_1(&a.addr, addr, fam)) {
1600 if (get_dns_host(&a, addr, fam)) {
1601 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", addr);
1602 return NULL;
1603 }
1604 }
1605 }
1606
9db7bf15 1607out:
1527a17e 1608 if (fam != AF_UNSPEC) {
e56a959e 1609 int states = f->states;
1527a17e 1610 f->families = 0;
9db7bf15 1611 filter_af_set(f, fam);
e56a959e 1612 filter_states_set(f, states);
1527a17e 1613 }
9db7bf15 1614
aba5acdf
SH
1615 res = malloc(sizeof(*res));
1616 if (res)
1617 memcpy(res, &a, sizeof(a));
1618 return res;
1619}
1620
8250bc9f
VK
1621static char *proto_name(int protocol)
1622{
1623 switch (protocol) {
235c4453
NA
1624 case 0:
1625 return "raw";
8250bc9f
VK
1626 case IPPROTO_UDP:
1627 return "udp";
1628 case IPPROTO_TCP:
1629 return "tcp";
1630 case IPPROTO_DCCP:
1631 return "dccp";
1632 }
1633
1634 return "???";
1635}
1636
055840f2 1637static void inet_stats_print(struct sockstat *s, int protocol)
8250bc9f
VK
1638{
1639 char *buf = NULL;
1640
2d791bc8 1641 sock_state_print(s, proto_name(protocol));
8250bc9f 1642
b217df10
VK
1643 inet_addr_print(&s->local, s->lport, s->iface);
1644 inet_addr_print(&s->remote, s->rport, 0);
8250bc9f 1645
8250bc9f
VK
1646 if (show_proc_ctx || show_sock_ctx) {
1647 if (find_entry(s->ino, &buf,
1648 (show_proc_ctx & show_sock_ctx) ?
1649 PROC_SOCK_CTX : PROC_CTX) > 0) {
1650 printf(" users:(%s)", buf);
1651 free(buf);
1652 }
1653 } else if (show_users) {
1654 if (find_entry(s->ino, &buf, USERS) > 0) {
1655 printf(" users:(%s)", buf);
1656 free(buf);
1657 }
1658 }
1659}
1660
055840f2 1661static int proc_parse_inet_addr(char *loc, char *rem, int family, struct
acd1e437 1662 sockstat * s)
8250bc9f
VK
1663{
1664 s->local.family = s->remote.family = family;
1665 if (family == AF_INET) {
acd1e437
SH
1666 sscanf(loc, "%x:%x", s->local.data, (unsigned *)&s->lport);
1667 sscanf(rem, "%x:%x", s->remote.data, (unsigned *)&s->rport);
8250bc9f
VK
1668 s->local.bytelen = s->remote.bytelen = 4;
1669 return 0;
1670 } else {
1671 sscanf(loc, "%08x%08x%08x%08x:%x",
1672 s->local.data,
1673 s->local.data + 1,
1674 s->local.data + 2,
1675 s->local.data + 3,
1676 &s->lport);
1677 sscanf(rem, "%08x%08x%08x%08x:%x",
1678 s->remote.data,
1679 s->remote.data + 1,
1680 s->remote.data + 2,
1681 s->remote.data + 3,
1682 &s->rport);
1683 s->local.bytelen = s->remote.bytelen = 16;
1684 return 0;
1685 }
1686 return -1;
1687}
1688
1689static int proc_inet_split_line(char *line, char **loc, char **rem, char **data)
aba5acdf 1690{
aba5acdf 1691 char *p;
ae665a52 1692
aba5acdf
SH
1693 if ((p = strchr(line, ':')) == NULL)
1694 return -1;
ae665a52 1695
8250bc9f
VK
1696 *loc = p+2;
1697 if ((p = strchr(*loc, ':')) == NULL)
aba5acdf 1698 return -1;
ae665a52 1699
8250bc9f
VK
1700 p[5] = 0;
1701 *rem = p+6;
1702 if ((p = strchr(*rem, ':')) == NULL)
aba5acdf 1703 return -1;
8250bc9f 1704
aba5acdf 1705 p[5] = 0;
8250bc9f
VK
1706 *data = p+6;
1707 return 0;
1708}
ae665a52 1709
8250bc9f
VK
1710static char *sprint_bw(char *buf, double bw)
1711{
1712 if (bw > 1000000.)
acd1e437 1713 sprintf(buf, "%.1fM", bw / 1000000.);
8250bc9f 1714 else if (bw > 1000.)
acd1e437 1715 sprintf(buf, "%.1fK", bw / 1000.);
8250bc9f
VK
1716 else
1717 sprintf(buf, "%g", bw);
aba5acdf 1718
8250bc9f
VK
1719 return buf;
1720}
ae665a52 1721
8250bc9f
VK
1722static void tcp_stats_print(struct tcpstat *s)
1723{
1724 char b1[64];
1725
1726 if (s->has_ts_opt)
1727 printf(" ts");
1728 if (s->has_sack_opt)
1729 printf(" sack");
1730 if (s->has_ecn_opt)
1731 printf(" ecn");
1732 if (s->has_ecnseen_opt)
1733 printf(" ecnseen");
1734 if (s->has_fastopen_opt)
1735 printf(" fastopen");
d2055ea5 1736 if (s->cong_alg[0])
8250bc9f
VK
1737 printf(" %s", s->cong_alg);
1738 if (s->has_wscale_opt)
1739 printf(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
1740 if (s->rto)
1741 printf(" rto:%g", s->rto);
1742 if (s->backoff)
1743 printf(" backoff:%u", s->backoff);
1744 if (s->rtt)
1745 printf(" rtt:%g/%g", s->rtt, s->rttvar);
1746 if (s->ato)
1747 printf(" ato:%g", s->ato);
1748
1749 if (s->qack)
1750 printf(" qack:%d", s->qack);
1751 if (s->qack & 1)
1752 printf(" bidir");
1753
1754 if (s->mss)
1755 printf(" mss:%d", s->mss);
3bf5445c 1756 if (s->cwnd)
8250bc9f
VK
1757 printf(" cwnd:%d", s->cwnd);
1758 if (s->ssthresh)
1759 printf(" ssthresh:%d", s->ssthresh);
1760
1a4dda71
ED
1761 if (s->bytes_acked)
1762 printf(" bytes_acked:%llu", s->bytes_acked);
1763 if (s->bytes_received)
1764 printf(" bytes_received:%llu", s->bytes_received);
ecb435ea
CG
1765 if (s->segs_out)
1766 printf(" segs_out:%u", s->segs_out);
1767 if (s->segs_in)
1768 printf(" segs_in:%u", s->segs_in);
414aeec9
MKL
1769 if (s->data_segs_out)
1770 printf(" data_segs_out:%u", s->data_segs_out);
1771 if (s->data_segs_in)
1772 printf(" data_segs_in:%u", s->data_segs_in);
1a4dda71 1773
8250bc9f
VK
1774 if (s->dctcp && s->dctcp->enabled) {
1775 struct dctcpstat *dctcp = s->dctcp;
1776
3bf5445c 1777 printf(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
8250bc9f
VK
1778 dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
1779 dctcp->ab_tot);
1780 } else if (s->dctcp) {
3bf5445c 1781 printf(" dctcp:fallback_mode");
8250bc9f
VK
1782 }
1783
1784 if (s->send_bps)
1785 printf(" send %sbps", sprint_bw(b1, s->send_bps));
1786 if (s->lastsnd)
1787 printf(" lastsnd:%u", s->lastsnd);
1788 if (s->lastrcv)
1789 printf(" lastrcv:%u", s->lastrcv);
1790 if (s->lastack)
1791 printf(" lastack:%u", s->lastack);
1792
1793 if (s->pacing_rate) {
1794 printf(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
1795 if (s->pacing_rate_max)
1796 printf("/%sbps", sprint_bw(b1,
1797 s->pacing_rate_max));
1798 }
1799
1800 if (s->unacked)
1801 printf(" unacked:%u", s->unacked);
1802 if (s->retrans || s->retrans_total)
1803 printf(" retrans:%u/%u", s->retrans, s->retrans_total);
1804 if (s->lost)
1805 printf(" lost:%u", s->lost);
055840f2 1806 if (s->sacked && s->ss.state != SS_LISTEN)
8250bc9f
VK
1807 printf(" sacked:%u", s->sacked);
1808 if (s->fackets)
1809 printf(" fackets:%u", s->fackets);
1810 if (s->reordering != 3)
1811 printf(" reordering:%d", s->reordering);
1812 if (s->rcv_rtt)
1813 printf(" rcv_rtt:%g", s->rcv_rtt);
1814 if (s->rcv_space)
1815 printf(" rcv_space:%d", s->rcv_space);
9e99e495
SH
1816 if (s->not_sent)
1817 printf(" notsent:%u", s->not_sent);
1818 if (s->min_rtt)
1819 printf(" minrtt:%g", s->min_rtt);
8250bc9f
VK
1820}
1821
055840f2
VK
1822static void tcp_timer_print(struct tcpstat *s)
1823{
1824 if (s->timer) {
1825 if (s->timer > 4)
1826 s->timer = 5;
1827 printf(" timer:(%s,%s,%d)",
1828 tmr_name[s->timer],
1829 print_ms_timer(s->timeout),
1830 s->retrans);
1831 }
1832}
1833
8250bc9f
VK
1834static int tcp_show_line(char *line, const struct filter *f, int family)
1835{
1836 int rto = 0, ato = 0;
1837 struct tcpstat s = {};
1838 char *loc, *rem, *data;
1839 char opt[256];
1840 int n;
1841 int hz = get_user_hz();
1842
1843 if (proc_inet_split_line(line, &loc, &rem, &data))
1844 return -1;
1845
1846 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
acd1e437 1847
8250bc9f
VK
1848 if (!(f->states & (1 << state)))
1849 return 0;
1850
055840f2 1851 proc_parse_inet_addr(loc, rem, family, &s.ss);
ae665a52 1852
055840f2 1853 if (f->f && run_ssfilter(f->f, &s.ss) == 0)
aba5acdf 1854 return 0;
ae665a52 1855
aba5acdf 1856 opt[0] = 0;
e7113c61 1857 n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n",
055840f2
VK
1858 &s.ss.state, &s.ss.wq, &s.ss.rq,
1859 &s.timer, &s.timeout, &s.retrans, &s.ss.uid, &s.probes,
1860 &s.ss.ino, &s.ss.refcnt, &s.ss.sk, &rto, &ato, &s.qack, &s.cwnd,
1861 &s.ssthresh, opt);
ae665a52 1862
aba5acdf
SH
1863 if (n < 17)
1864 opt[0] = 0;
ae665a52 1865
aba5acdf 1866 if (n < 12) {
8250bc9f 1867 rto = 0;
aba5acdf
SH
1868 s.cwnd = 2;
1869 s.ssthresh = -1;
8250bc9f 1870 ato = s.qack = 0;
aba5acdf 1871 }
ae665a52 1872
8250bc9f
VK
1873 s.retrans = s.timer != 1 ? s.probes : s.retrans;
1874 s.timeout = (s.timeout * 1000 + hz - 1) / hz;
1875 s.ato = (double)ato / hz;
1876 s.qack /= 2;
1877 s.rto = (double)rto;
1878 s.ssthresh = s.ssthresh == -1 ? 0 : s.ssthresh;
1879 s.rto = s.rto != 3 * hz ? s.rto / hz : 0;
ae665a52 1880
055840f2
VK
1881 inet_stats_print(&s.ss, IPPROTO_TCP);
1882
1883 if (show_options)
1884 tcp_timer_print(&s);
116ac927 1885
aba5acdf 1886 if (show_details) {
f1b39e1b 1887 sock_details_print(&s.ss);
aba5acdf
SH
1888 if (opt[0])
1889 printf(" opt:\"%s\"", opt);
1890 }
aba5acdf 1891
8250bc9f
VK
1892 if (show_tcpinfo)
1893 tcp_stats_print(&s);
1894
1895 printf("\n");
aba5acdf
SH
1896 return 0;
1897}
1898
ab01dbbb
SH
1899static int generic_record_read(FILE *fp,
1900 int (*worker)(char*, const struct filter *, int),
1901 const struct filter *f, int fam)
aba5acdf 1902{
ab01dbbb 1903 char line[256];
aba5acdf 1904
ab01dbbb
SH
1905 /* skip header */
1906 if (fgets(line, sizeof(line), fp) == NULL)
aba5acdf 1907 goto outerr;
ab01dbbb
SH
1908
1909 while (fgets(line, sizeof(line), fp) != NULL) {
1910 int n = strlen(line);
acd1e437 1911
ab01dbbb
SH
1912 if (n == 0 || line[n-1] != '\n') {
1913 errno = -EINVAL;
1914 return -1;
aba5acdf 1915 }
ab01dbbb 1916 line[n-1] = 0;
aba5acdf 1917
ab01dbbb
SH
1918 if (worker(line, f, fam) < 0)
1919 return 0;
1920 }
aba5acdf 1921outerr:
ab01dbbb
SH
1922
1923 return ferror(fp) ? -1 : 0;
aba5acdf 1924}
ae665a52 1925
51ff9f24
HFS
1926static void print_skmeminfo(struct rtattr *tb[], int attrtype)
1927{
1928 const __u32 *skmeminfo;
db08bdb8
VK
1929
1930 if (!tb[attrtype]) {
1931 if (attrtype == INET_DIAG_SKMEMINFO) {
1932 if (!tb[INET_DIAG_MEMINFO])
1933 return;
1934
1935 const struct inet_diag_meminfo *minfo =
1936 RTA_DATA(tb[INET_DIAG_MEMINFO]);
1937
1938 printf(" mem:(r%u,w%u,f%u,t%u)",
1939 minfo->idiag_rmem,
1940 minfo->idiag_wmem,
1941 minfo->idiag_fmem,
1942 minfo->idiag_tmem);
1943 }
51ff9f24 1944 return;
db08bdb8
VK
1945 }
1946
51ff9f24
HFS
1947 skmeminfo = RTA_DATA(tb[attrtype]);
1948
1949 printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
1950 skmeminfo[SK_MEMINFO_RMEM_ALLOC],
1951 skmeminfo[SK_MEMINFO_RCVBUF],
1952 skmeminfo[SK_MEMINFO_WMEM_ALLOC],
1953 skmeminfo[SK_MEMINFO_SNDBUF],
1954 skmeminfo[SK_MEMINFO_FWD_ALLOC],
1955 skmeminfo[SK_MEMINFO_WMEM_QUEUED],
1956 skmeminfo[SK_MEMINFO_OPTMEM]);
1957
1958 if (RTA_PAYLOAD(tb[attrtype]) >=
1959 (SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
1960 printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
1961
6df9c7a0
ED
1962 if (RTA_PAYLOAD(tb[attrtype]) >=
1963 (SK_MEMINFO_DROPS + 1) * sizeof(__u32))
1964 printf(",d%u", skmeminfo[SK_MEMINFO_DROPS]);
1965
51ff9f24
HFS
1966 printf(")");
1967}
1968
8250bc9f
VK
1969#define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
1970
5b816047
PE
1971static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
1972 struct rtattr *tb[])
7d105b56 1973{
b4b0b7d5 1974 double rtt = 0;
8250bc9f 1975 struct tcpstat s = {};
7d105b56 1976
055840f2
VK
1977 s.ss.state = r->idiag_state;
1978
db08bdb8 1979 print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
7d105b56 1980
351efcde 1981 if (tb[INET_DIAG_INFO]) {
05e18118 1982 struct tcp_info *info;
351efcde 1983 int len = RTA_PAYLOAD(tb[INET_DIAG_INFO]);
05e18118
SH
1984
1985 /* workaround for older kernels with less fields */
1986 if (len < sizeof(*info)) {
1987 info = alloca(sizeof(*info));
351efcde 1988 memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len);
656e8fdd 1989 memset((char *)info + len, 0, sizeof(*info) - len);
05e18118 1990 } else
351efcde 1991 info = RTA_DATA(tb[INET_DIAG_INFO]);
05e18118 1992
b4b0b7d5 1993 if (show_options) {
8250bc9f
VK
1994 s.has_ts_opt = TCPI_HAS_OPT(info, TCPI_OPT_TIMESTAMPS);
1995 s.has_sack_opt = TCPI_HAS_OPT(info, TCPI_OPT_SACK);
1996 s.has_ecn_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN);
1997 s.has_ecnseen_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN);
1998 s.has_fastopen_opt = TCPI_HAS_OPT(info, TCPI_OPT_SYN_DATA);
b4b0b7d5 1999 }
52d5ac3f 2000
d2055ea5
ED
2001 if (tb[INET_DIAG_CONG])
2002 strncpy(s.cong_alg,
2003 rta_getattr_str(tb[INET_DIAG_CONG]),
2004 sizeof(s.cong_alg) - 1);
8250bc9f
VK
2005
2006 if (TCPI_HAS_OPT(info, TCPI_OPT_WSCALE)) {
2007 s.has_wscale_opt = true;
2008 s.snd_wscale = info->tcpi_snd_wscale;
2009 s.rcv_wscale = info->tcpi_rcv_wscale;
2010 }
ea8fc104 2011
7d105b56 2012 if (info->tcpi_rto && info->tcpi_rto != 3000000)
8250bc9f
VK
2013 s.rto = (double)info->tcpi_rto / 1000;
2014
2015 s.backoff = info->tcpi_backoff;
2016 s.rtt = (double)info->tcpi_rtt / 1000;
2017 s.rttvar = (double)info->tcpi_rttvar / 1000;
11ba90fc 2018 s.ato = (double)info->tcpi_ato / 1000;
8250bc9f
VK
2019 s.mss = info->tcpi_snd_mss;
2020 s.rcv_space = info->tcpi_rcv_space;
2021 s.rcv_rtt = (double)info->tcpi_rcv_rtt / 1000;
2022 s.lastsnd = info->tcpi_last_data_sent;
2023 s.lastrcv = info->tcpi_last_data_recv;
2024 s.lastack = info->tcpi_last_ack_recv;
2025 s.unacked = info->tcpi_unacked;
2026 s.retrans = info->tcpi_retrans;
2027 s.retrans_total = info->tcpi_total_retrans;
2028 s.lost = info->tcpi_lost;
2029 s.sacked = info->tcpi_sacked;
2030 s.reordering = info->tcpi_reordering;
2031 s.rcv_space = info->tcpi_rcv_space;
2032 s.cwnd = info->tcpi_snd_cwnd;
2033
7d105b56 2034 if (info->tcpi_snd_ssthresh < 0xFFFF)
8250bc9f 2035 s.ssthresh = info->tcpi_snd_ssthresh;
52d5ac3f 2036
b4b0b7d5 2037 rtt = (double) info->tcpi_rtt;
351efcde 2038 if (tb[INET_DIAG_VEGASINFO]) {
05e18118 2039 const struct tcpvegas_info *vinfo
351efcde 2040 = RTA_DATA(tb[INET_DIAG_VEGASINFO]);
7d105b56 2041
ae665a52 2042 if (vinfo->tcpv_enabled &&
8250bc9f 2043 vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
ea8fc104 2044 rtt = vinfo->tcpv_rtt;
b4b0b7d5
SH
2045 }
2046
907e1aca 2047 if (tb[INET_DIAG_DCTCPINFO]) {
8250bc9f
VK
2048 struct dctcpstat *dctcp = malloc(sizeof(struct
2049 dctcpstat));
2050
907e1aca
DB
2051 const struct tcp_dctcp_info *dinfo
2052 = RTA_DATA(tb[INET_DIAG_DCTCPINFO]);
2053
8250bc9f
VK
2054 dctcp->enabled = !!dinfo->dctcp_enabled;
2055 dctcp->ce_state = dinfo->dctcp_ce_state;
2056 dctcp->alpha = dinfo->dctcp_alpha;
2057 dctcp->ab_ecn = dinfo->dctcp_ab_ecn;
2058 dctcp->ab_tot = dinfo->dctcp_ab_tot;
2059 s.dctcp = dctcp;
907e1aca
DB
2060 }
2061
b4b0b7d5 2062 if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
8250bc9f
VK
2063 s.send_bps = (double) info->tcpi_snd_cwnd *
2064 (double)info->tcpi_snd_mss * 8000000. / rtt;
7d105b56 2065 }
b4b0b7d5 2066
eb6028b2 2067 if (info->tcpi_pacing_rate &&
8250bc9f
VK
2068 info->tcpi_pacing_rate != ~0ULL) {
2069 s.pacing_rate = info->tcpi_pacing_rate * 8.;
eb6028b2
ED
2070
2071 if (info->tcpi_max_pacing_rate &&
8250bc9f
VK
2072 info->tcpi_max_pacing_rate != ~0ULL)
2073 s.pacing_rate_max = info->tcpi_max_pacing_rate * 8.;
eb6028b2 2074 }
1a4dda71
ED
2075 s.bytes_acked = info->tcpi_bytes_acked;
2076 s.bytes_received = info->tcpi_bytes_received;
ecb435ea
CG
2077 s.segs_out = info->tcpi_segs_out;
2078 s.segs_in = info->tcpi_segs_in;
414aeec9
MKL
2079 s.data_segs_out = info->tcpi_data_segs_out;
2080 s.data_segs_in = info->tcpi_data_segs_in;
9e99e495 2081 s.not_sent = info->tcpi_notsent_bytes;
d9ba887e
ED
2082 if (info->tcpi_min_rtt && info->tcpi_min_rtt != ~0U)
2083 s.min_rtt = (double) info->tcpi_min_rtt / 1000;
8250bc9f 2084 tcp_stats_print(&s);
92de1c2c 2085 free(s.dctcp);
77a8ca81 2086 }
77a8ca81
PE
2087}
2088
82d73ea0 2089static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s)
aba5acdf 2090{
acd1e437 2091 struct rtattr *tb[INET_DIAG_MAX+1];
351efcde 2092 struct inet_diag_msg *r = NLMSG_DATA(nlh);
aba5acdf 2093
acd1e437 2094 parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1),
5b816047
PE
2095 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2096
82d73ea0
DA
2097 s->state = r->idiag_state;
2098 s->local.family = s->remote.family = r->idiag_family;
2099 s->lport = ntohs(r->id.idiag_sport);
2100 s->rport = ntohs(r->id.idiag_dport);
2101 s->wq = r->idiag_wqueue;
2102 s->rq = r->idiag_rqueue;
2103 s->ino = r->idiag_inode;
2104 s->uid = r->idiag_uid;
2105 s->iface = r->id.idiag_if;
2106 s->sk = cookie_sk_get(&r->id.idiag_cookie[0]);
2107
2108 if (s->local.family == AF_INET)
2109 s->local.bytelen = s->remote.bytelen = 4;
2110 else
2111 s->local.bytelen = s->remote.bytelen = 16;
8250bc9f 2112
82d73ea0
DA
2113 memcpy(s->local.data, r->id.idiag_src, s->local.bytelen);
2114 memcpy(s->remote.data, r->id.idiag_dst, s->local.bytelen);
2115}
aba5acdf 2116
82d73ea0
DA
2117static int inet_show_sock(struct nlmsghdr *nlh,
2118 struct sockstat *s,
2119 int protocol)
2120{
2121 struct rtattr *tb[INET_DIAG_MAX+1];
2122 struct inet_diag_msg *r = NLMSG_DATA(nlh);
2123
2124 parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1),
2125 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
aba5acdf 2126
6885e3bf
CG
2127 if (tb[INET_DIAG_PROTOCOL])
2128 protocol = *(__u8 *)RTA_DATA(tb[INET_DIAG_PROTOCOL]);
2129
82d73ea0 2130 inet_stats_print(s, protocol);
116ac927 2131
055840f2
VK
2132 if (show_options) {
2133 struct tcpstat t = {};
2134
2135 t.timer = r->idiag_timer;
2136 t.timeout = r->idiag_expires;
2137 t.retrans = r->idiag_retrans;
2138 tcp_timer_print(&t);
2139 }
2140
aba5acdf 2141 if (show_details) {
82d73ea0
DA
2142 sock_details_print(s);
2143 if (s->local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY]) {
f32dc746 2144 unsigned char v6only;
acd1e437 2145
f32dc746
PS
2146 v6only = *(__u8 *)RTA_DATA(tb[INET_DIAG_SKV6ONLY]);
2147 printf(" v6only:%u", v6only);
2148 }
5b816047
PE
2149 if (tb[INET_DIAG_SHUTDOWN]) {
2150 unsigned char mask;
acd1e437 2151
5b816047
PE
2152 mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
2153 printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
2154 }
aba5acdf 2155 }
8250bc9f 2156
aba5acdf 2157 if (show_mem || show_tcpinfo) {
7d105b56 2158 printf("\n\t");
5b816047 2159 tcp_show_info(nlh, r, tb);
aba5acdf 2160 }
7d105b56 2161
aba5acdf 2162 printf("\n");
aba5acdf 2163 return 0;
aba5acdf
SH
2164}
2165
746a695f 2166static int tcpdiag_send(int fd, int protocol, struct filter *f)
aba5acdf 2167{
aba5acdf
SH
2168 struct sockaddr_nl nladdr;
2169 struct {
2170 struct nlmsghdr nlh;
351efcde 2171 struct inet_diag_req r;
aba5acdf
SH
2172 } req;
2173 char *bc = NULL;
2174 int bclen;
2175 struct msghdr msg;
2176 struct rtattr rta;
aba5acdf 2177 struct iovec iov[3];
376fb868 2178 int iovlen = 1;
aba5acdf 2179
346f8ca8
PE
2180 if (protocol == IPPROTO_UDP)
2181 return -1;
2182
aba5acdf
SH
2183 memset(&nladdr, 0, sizeof(nladdr));
2184 nladdr.nl_family = AF_NETLINK;
2185
2186 req.nlh.nlmsg_len = sizeof(req);
3fe5b534
PE
2187 if (protocol == IPPROTO_TCP)
2188 req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
2189 else
2190 req.nlh.nlmsg_type = DCCPDIAG_GETSOCK;
aba5acdf
SH
2191 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
2192 req.nlh.nlmsg_pid = 0;
8a4025f6 2193 req.nlh.nlmsg_seq = MAGIC_SEQ;
aba5acdf 2194 memset(&req.r, 0, sizeof(req.r));
351efcde
SH
2195 req.r.idiag_family = AF_INET;
2196 req.r.idiag_states = f->states;
910b0397 2197 if (show_mem) {
ae665a52 2198 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
910b0397
SW
2199 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
2200 }
b4b0b7d5 2201
7d105b56 2202 if (show_tcpinfo) {
351efcde
SH
2203 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
2204 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
2205 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
7d105b56 2206 }
aba5acdf 2207
ae665a52
SH
2208 iov[0] = (struct iovec){
2209 .iov_base = &req,
2210 .iov_len = sizeof(req)
ea8fc104 2211 };
aba5acdf
SH
2212 if (f->f) {
2213 bclen = ssfilter_bytecompile(f->f, &bc);
376fb868
DA
2214 if (bclen) {
2215 rta.rta_type = INET_DIAG_REQ_BYTECODE;
2216 rta.rta_len = RTA_LENGTH(bclen);
2217 iov[1] = (struct iovec){ &rta, sizeof(rta) };
2218 iov[2] = (struct iovec){ bc, bclen };
2219 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
2220 iovlen = 3;
2221 }
aba5acdf
SH
2222 }
2223
2224 msg = (struct msghdr) {
acd1e437 2225 .msg_name = (void *)&nladdr,
ea8fc104 2226 .msg_namelen = sizeof(nladdr),
ae665a52 2227 .msg_iov = iov,
376fb868 2228 .msg_iovlen = iovlen,
aba5acdf
SH
2229 };
2230
930a75f9
ED
2231 if (sendmsg(fd, &msg, 0) < 0) {
2232 close(fd);
aba5acdf 2233 return -1;
930a75f9 2234 }
aba5acdf 2235
746a695f
PE
2236 return 0;
2237}
2238
886d19d6
PE
2239static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
2240{
2241 struct sockaddr_nl nladdr;
acd1e437 2242
5fb421d4 2243 DIAG_REQUEST(req, struct inet_diag_req_v2 r);
886d19d6
PE
2244 char *bc = NULL;
2245 int bclen;
2246 struct msghdr msg;
2247 struct rtattr rta;
2248 struct iovec iov[3];
376fb868 2249 int iovlen = 1;
886d19d6
PE
2250
2251 if (family == PF_UNSPEC)
2252 return tcpdiag_send(fd, protocol, f);
2253
2254 memset(&nladdr, 0, sizeof(nladdr));
2255 nladdr.nl_family = AF_NETLINK;
2256
886d19d6
PE
2257 memset(&req.r, 0, sizeof(req.r));
2258 req.r.sdiag_family = family;
2259 req.r.sdiag_protocol = protocol;
2260 req.r.idiag_states = f->states;
2261 if (show_mem) {
2262 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
2263 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
2264 }
2265
2266 if (show_tcpinfo) {
2267 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
2268 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
2269 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
2270 }
2271
2272 iov[0] = (struct iovec){
2273 .iov_base = &req,
2274 .iov_len = sizeof(req)
2275 };
2276 if (f->f) {
2277 bclen = ssfilter_bytecompile(f->f, &bc);
376fb868
DA
2278 if (bclen) {
2279 rta.rta_type = INET_DIAG_REQ_BYTECODE;
2280 rta.rta_len = RTA_LENGTH(bclen);
2281 iov[1] = (struct iovec){ &rta, sizeof(rta) };
2282 iov[2] = (struct iovec){ bc, bclen };
2283 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
2284 iovlen = 3;
2285 }
886d19d6
PE
2286 }
2287
2288 msg = (struct msghdr) {
acd1e437 2289 .msg_name = (void *)&nladdr,
886d19d6
PE
2290 .msg_namelen = sizeof(nladdr),
2291 .msg_iov = iov,
376fb868 2292 .msg_iovlen = iovlen,
886d19d6
PE
2293 };
2294
2295 if (sendmsg(fd, &msg, 0) < 0) {
2296 close(fd);
2297 return -1;
2298 }
2299
2300 return 0;
2301}
2302
486ccd99
VK
2303struct inet_diag_arg {
2304 struct filter *f;
2305 int protocol;
fb2594c1 2306 struct rtnl_handle *rth;
486ccd99 2307};
aba5acdf 2308
b38e7409 2309static int kill_inet_sock(struct nlmsghdr *h, void *arg)
fb2594c1
LC
2310{
2311 struct inet_diag_msg *d = NLMSG_DATA(h);
2312 struct inet_diag_arg *diag_arg = arg;
2313 struct rtnl_handle *rth = diag_arg->rth;
acd1e437 2314
fb2594c1
LC
2315 DIAG_REQUEST(req, struct inet_diag_req_v2 r);
2316
2317 req.nlh.nlmsg_type = SOCK_DESTROY;
2318 req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
2319 req.nlh.nlmsg_seq = ++rth->seq;
2320 req.r.sdiag_family = d->idiag_family;
2321 req.r.sdiag_protocol = diag_arg->protocol;
2322 req.r.id = d->id;
2323
2324 return rtnl_talk(rth, &req.nlh, NULL, 0);
2325}
2326
486ccd99
VK
2327static int show_one_inet_sock(const struct sockaddr_nl *addr,
2328 struct nlmsghdr *h, void *arg)
2329{
2330 int err;
2331 struct inet_diag_arg *diag_arg = arg;
2332 struct inet_diag_msg *r = NLMSG_DATA(h);
82d73ea0 2333 struct sockstat s = {};
aba5acdf 2334
486ccd99
VK
2335 if (!(diag_arg->f->families & (1 << r->idiag_family)))
2336 return 0;
82d73ea0
DA
2337
2338 parse_diag_msg(h, &s);
2339
2340 if (diag_arg->f->f && run_ssfilter(diag_arg->f->f, &s) == 0)
2341 return 0;
2342
b38e7409 2343 if (diag_arg->f->kill && kill_inet_sock(h, arg) != 0) {
fb2594c1
LC
2344 if (errno == EOPNOTSUPP || errno == ENOENT) {
2345 /* Socket can't be closed, or is already closed. */
2346 return 0;
2347 } else {
2348 perror("SOCK_DESTROY answers");
2349 return -1;
2350 }
2351 }
82d73ea0
DA
2352
2353 err = inet_show_sock(h, &s, diag_arg->protocol);
2354 if (err < 0)
486ccd99 2355 return err;
aba5acdf 2356
486ccd99
VK
2357 return 0;
2358}
886d19d6 2359
486ccd99
VK
2360static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)
2361{
2362 int err = 0;
fb2594c1 2363 struct rtnl_handle rth, rth2;
486ccd99
VK
2364 int family = PF_INET;
2365 struct inet_diag_arg arg = { .f = f, .protocol = protocol };
886d19d6 2366
486ccd99
VK
2367 if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
2368 return -1;
fb2594c1
LC
2369
2370 if (f->kill) {
2371 if (rtnl_open_byproto(&rth2, 0, NETLINK_SOCK_DIAG)) {
2372 rtnl_close(&rth);
2373 return -1;
2374 }
2375 arg.rth = &rth2;
2376 }
2377
486ccd99
VK
2378 rth.dump = MAGIC_SEQ;
2379 rth.dump_fp = dump_fp;
518af1e0
ED
2380 if (preferred_family == PF_INET6)
2381 family = PF_INET6;
886d19d6 2382
486ccd99
VK
2383again:
2384 if ((err = sockdiag_send(family, rth.fd, protocol, f)))
2385 goto Exit;
aba5acdf 2386
486ccd99
VK
2387 if ((err = rtnl_dump_filter(&rth, show_one_inet_sock, &arg))) {
2388 if (family != PF_UNSPEC) {
2389 family = PF_UNSPEC;
2390 goto again;
aba5acdf 2391 }
486ccd99 2392 goto Exit;
aba5acdf 2393 }
518af1e0 2394 if (family == PF_INET && preferred_family != PF_INET) {
886d19d6
PE
2395 family = PF_INET6;
2396 goto again;
2397 }
2398
486ccd99
VK
2399Exit:
2400 rtnl_close(&rth);
fb2594c1
LC
2401 if (arg.rth)
2402 rtnl_close(arg.rth);
486ccd99 2403 return err;
aba5acdf
SH
2404}
2405
ab01dbbb 2406static int tcp_show_netlink_file(struct filter *f)
aba5acdf
SH
2407{
2408 FILE *fp;
e557212e 2409 char buf[16384];
aba5acdf
SH
2410
2411 if ((fp = fopen(getenv("TCPDIAG_FILE"), "r")) == NULL) {
2412 perror("fopen($TCPDIAG_FILE)");
2413 return -1;
2414 }
2415
2416 while (1) {
2417 int status, err;
acd1e437 2418 struct nlmsghdr *h = (struct nlmsghdr *)buf;
82d73ea0 2419 struct sockstat s = {};
aba5acdf
SH
2420
2421 status = fread(buf, 1, sizeof(*h), fp);
2422 if (status < 0) {
2423 perror("Reading header from $TCPDIAG_FILE");
2424 return -1;
2425 }
2426 if (status != sizeof(*h)) {
2427 perror("Unexpected EOF reading $TCPDIAG_FILE");
2428 return -1;
2429 }
2430
2431 status = fread(h+1, 1, NLMSG_ALIGN(h->nlmsg_len-sizeof(*h)), fp);
2432
2433 if (status < 0) {
2434 perror("Reading $TCPDIAG_FILE");
2435 return -1;
2436 }
2437 if (status + sizeof(*h) < h->nlmsg_len) {
2438 perror("Unexpected EOF reading $TCPDIAG_FILE");
2439 return -1;
2440 }
2441
2442 /* The only legal exit point */
2443 if (h->nlmsg_type == NLMSG_DONE)
2444 return 0;
2445
2446 if (h->nlmsg_type == NLMSG_ERROR) {
acd1e437
SH
2447 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
2448
aba5acdf
SH
2449 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
2450 fprintf(stderr, "ERROR truncated\n");
2451 } else {
2452 errno = -err->error;
2453 perror("TCPDIAG answered");
2454 }
2455 return -1;
2456 }
2457
82d73ea0
DA
2458 parse_diag_msg(h, &s);
2459
2460 if (f && f->f && run_ssfilter(f->f, &s) == 0)
2461 continue;
2462
2463 err = inet_show_sock(h, &s, IPPROTO_TCP);
aba5acdf
SH
2464 if (err < 0)
2465 return err;
2466 }
2467}
2468
ab01dbbb 2469static int tcp_show(struct filter *f, int socktype)
aba5acdf 2470{
ab01dbbb 2471 FILE *fp = NULL;
aba5acdf
SH
2472 char *buf = NULL;
2473 int bufsize = 64*1024;
2474
1527a17e
VK
2475 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
2476 return 0;
2477
aba5acdf
SH
2478 dg_proto = TCP_PROTO;
2479
2480 if (getenv("TCPDIAG_FILE"))
2481 return tcp_show_netlink_file(f);
2482
2483 if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT")
3fe5b534 2484 && inet_show_netlink(f, NULL, socktype) == 0)
aba5acdf
SH
2485 return 0;
2486
2487 /* Sigh... We have to parse /proc/net/tcp... */
2488
ab01dbbb 2489
aba5acdf
SH
2490 /* Estimate amount of sockets and try to allocate
2491 * huge buffer to read all the table at one read.
2492 * Limit it by 16MB though. The assumption is: as soon as
2493 * kernel was able to hold information about N connections,
2494 * it is able to give us some memory for snapshot.
2495 */
2496 if (1) {
a221d621
BL
2497 get_slabstat(&slabstat);
2498
aba5acdf 2499 int guess = slabstat.socks+slabstat.tcp_syns;
acd1e437 2500
aba5acdf
SH
2501 if (f->states&(1<<SS_TIME_WAIT))
2502 guess += slabstat.tcp_tws;
2503 if (guess > (16*1024*1024)/128)
2504 guess = (16*1024*1024)/128;
2505 guess *= 128;
2506 if (guess > bufsize)
2507 bufsize = guess;
2508 }
2509 while (bufsize >= 64*1024) {
2510 if ((buf = malloc(bufsize)) != NULL)
2511 break;
2512 bufsize /= 2;
2513 }
2514 if (buf == NULL) {
2515 errno = ENOMEM;
2516 return -1;
2517 }
2518
2519 if (f->families & (1<<AF_INET)) {
69cae645 2520 if ((fp = net_tcp_open()) == NULL)
aba5acdf 2521 goto outerr;
ab01dbbb
SH
2522
2523 setbuffer(fp, buf, bufsize);
2524 if (generic_record_read(fp, tcp_show_line, f, AF_INET))
aba5acdf 2525 goto outerr;
ab01dbbb 2526 fclose(fp);
aba5acdf
SH
2527 }
2528
2529 if ((f->families & (1<<AF_INET6)) &&
69cae645 2530 (fp = net_tcp6_open()) != NULL) {
ab01dbbb
SH
2531 setbuffer(fp, buf, bufsize);
2532 if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
aba5acdf 2533 goto outerr;
ab01dbbb 2534 fclose(fp);
aba5acdf
SH
2535 }
2536
2537 free(buf);
2538 return 0;
2539
2540outerr:
2541 do {
2542 int saved_errno = errno;
acd1e437 2543
92de1c2c 2544 free(buf);
ab01dbbb
SH
2545 if (fp)
2546 fclose(fp);
aba5acdf
SH
2547 errno = saved_errno;
2548 return -1;
2549 } while (0);
2550}
2551
2552
d1f28cf1 2553static int dgram_show_line(char *line, const struct filter *f, int family)
aba5acdf 2554{
055840f2 2555 struct sockstat s = {};
aba5acdf
SH
2556 char *loc, *rem, *data;
2557 char opt[256];
2558 int n;
aba5acdf 2559
8250bc9f 2560 if (proc_inet_split_line(line, &loc, &rem, &data))
aba5acdf 2561 return -1;
aba5acdf 2562
8250bc9f 2563 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
acd1e437 2564
8250bc9f
VK
2565 if (!(f->states & (1 << state)))
2566 return 0;
aba5acdf 2567
8250bc9f 2568 proc_parse_inet_addr(loc, rem, family, &s);
aba5acdf
SH
2569
2570 if (f->f && run_ssfilter(f->f, &s) == 0)
2571 return 0;
2572
2573 opt[0] = 0;
e7113c61 2574 n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
aba5acdf
SH
2575 &s.state, &s.wq, &s.rq,
2576 &s.uid, &s.ino,
2577 &s.refcnt, &s.sk, opt);
2578
2579 if (n < 9)
2580 opt[0] = 0;
2581
235c4453 2582 inet_stats_print(&s, dg_proto == UDP_PROTO ? IPPROTO_UDP : 0);
aba5acdf 2583
f1b39e1b
VK
2584 if (show_details && opt[0])
2585 printf(" opt:\"%s\"", opt);
aba5acdf 2586
8250bc9f 2587 printf("\n");
aba5acdf
SH
2588 return 0;
2589}
2590
d1f28cf1 2591static int udp_show(struct filter *f)
aba5acdf 2592{
ab01dbbb 2593 FILE *fp = NULL;
aba5acdf 2594
1527a17e
VK
2595 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
2596 return 0;
2597
ace5cb31
VK
2598 dg_proto = UDP_PROTO;
2599
346f8ca8
PE
2600 if (!getenv("PROC_NET_UDP") && !getenv("PROC_ROOT")
2601 && inet_show_netlink(f, NULL, IPPROTO_UDP) == 0)
2602 return 0;
2603
aba5acdf 2604 if (f->families&(1<<AF_INET)) {
69cae645 2605 if ((fp = net_udp_open()) == NULL)
aba5acdf 2606 goto outerr;
ab01dbbb 2607 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
aba5acdf 2608 goto outerr;
ab01dbbb 2609 fclose(fp);
aba5acdf
SH
2610 }
2611
2612 if ((f->families&(1<<AF_INET6)) &&
69cae645 2613 (fp = net_udp6_open()) != NULL) {
ab01dbbb 2614 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
aba5acdf 2615 goto outerr;
ab01dbbb 2616 fclose(fp);
aba5acdf
SH
2617 }
2618 return 0;
2619
2620outerr:
2621 do {
2622 int saved_errno = errno;
acd1e437 2623
ab01dbbb
SH
2624 if (fp)
2625 fclose(fp);
aba5acdf
SH
2626 errno = saved_errno;
2627 return -1;
2628 } while (0);
2629}
2630
d1f28cf1 2631static int raw_show(struct filter *f)
aba5acdf 2632{
ab01dbbb 2633 FILE *fp = NULL;
aba5acdf 2634
1527a17e
VK
2635 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
2636 return 0;
2637
aba5acdf
SH
2638 dg_proto = RAW_PROTO;
2639
2640 if (f->families&(1<<AF_INET)) {
69cae645 2641 if ((fp = net_raw_open()) == NULL)
aba5acdf 2642 goto outerr;
ab01dbbb 2643 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
aba5acdf 2644 goto outerr;
ab01dbbb 2645 fclose(fp);
aba5acdf
SH
2646 }
2647
2648 if ((f->families&(1<<AF_INET6)) &&
69cae645 2649 (fp = net_raw6_open()) != NULL) {
ab01dbbb 2650 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
aba5acdf 2651 goto outerr;
ab01dbbb 2652 fclose(fp);
aba5acdf
SH
2653 }
2654 return 0;
2655
2656outerr:
2657 do {
2658 int saved_errno = errno;
acd1e437 2659
ab01dbbb
SH
2660 if (fp)
2661 fclose(fp);
aba5acdf
SH
2662 errno = saved_errno;
2663 return -1;
2664 } while (0);
2665}
2666
aba5acdf
SH
2667int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
2668 SS_ESTABLISHED, SS_CLOSING };
2669
ec4d0d8a 2670#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct sockstat))
aba5acdf 2671
ec4d0d8a 2672static void unix_list_free(struct sockstat *list)
aba5acdf
SH
2673{
2674 while (list) {
ec4d0d8a 2675 struct sockstat *s = list;
ec4d0d8a 2676
aba5acdf 2677 list = list->next;
99bb68ff 2678 free(s->name);
aba5acdf
SH
2679 free(s);
2680 }
2681}
2682
30b669d7
MY
2683static const char *unix_netid_name(int type)
2684{
2685 const char *netid;
2686
2687 switch (type) {
2688 case SOCK_STREAM:
2689 netid = "u_str";
2690 break;
2691 case SOCK_SEQPACKET:
2692 netid = "u_seq";
2693 break;
2694 case SOCK_DGRAM:
2695 default:
2696 netid = "u_dgr";
2697 break;
2698 }
2699 return netid;
2700}
2701
ec4d0d8a 2702static bool unix_type_skip(struct sockstat *s, struct filter *f)
bf4ceee6
VK
2703{
2704 if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
2705 return true;
2706 if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
2707 return true;
2708 if (s->type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
2709 return true;
2710 return false;
2711}
2712
ec4d0d8a
VK
2713static bool unix_use_proc(void)
2714{
2715 return getenv("PROC_NET_UNIX") || getenv("PROC_ROOT");
2716}
2717
2718static void unix_stats_print(struct sockstat *list, struct filter *f)
aba5acdf 2719{
ec4d0d8a 2720 struct sockstat *s;
99bb68ff 2721 char *peer;
b217df10 2722 char *ctx_buf = NULL;
ec4d0d8a 2723 bool use_proc = unix_use_proc();
b217df10 2724 char port_name[30] = {};
aba5acdf
SH
2725
2726 for (s = list; s; s = s->next) {
ec4d0d8a 2727 if (!(f->states & (1 << s->state)))
aba5acdf 2728 continue;
bf4ceee6 2729 if (unix_type_skip(s, f))
30b669d7 2730 continue;
aba5acdf 2731
99bb68ff
VK
2732 peer = "*";
2733 if (s->peer_name)
2734 peer = s->peer_name;
ec4d0d8a
VK
2735
2736 if (s->rport && use_proc) {
2737 struct sockstat *p;
bf4ceee6 2738
aba5acdf 2739 for (p = list; p; p = p->next) {
ec4d0d8a 2740 if (s->rport == p->lport)
aba5acdf
SH
2741 break;
2742 }
ec4d0d8a 2743
aba5acdf
SH
2744 if (!p) {
2745 peer = "?";
2746 } else {
99bb68ff 2747 peer = p->name ? : "*";
aba5acdf
SH
2748 }
2749 }
2750
29999b0f 2751 if (use_proc && f->f) {
99bb68ff 2752 struct sockstat st;
acd1e437 2753
99bb68ff
VK
2754 st.local.family = AF_UNIX;
2755 st.remote.family = AF_UNIX;
2756 memcpy(st.local.data, &s->name, sizeof(s->name));
aba5acdf 2757 if (strcmp(peer, "*") == 0)
99bb68ff 2758 memset(st.remote.data, 0, sizeof(peer));
aba5acdf 2759 else
99bb68ff
VK
2760 memcpy(st.remote.data, &peer, sizeof(peer));
2761 if (run_ssfilter(f->f, &st) == 0)
aba5acdf
SH
2762 continue;
2763 }
2764
2d791bc8
VK
2765 sock_state_print(s, unix_netid_name(s->type));
2766
99bb68ff 2767 sock_addr_print(s->name ?: "*", " ",
b217df10
VK
2768 int_to_str(s->lport, port_name), NULL);
2769 sock_addr_print(peer, " ", int_to_str(s->rport, port_name),
2770 NULL);
116ac927
RH
2771
2772 if (show_proc_ctx || show_sock_ctx) {
b217df10 2773 if (find_entry(s->ino, &ctx_buf,
116ac927
RH
2774 (show_proc_ctx & show_sock_ctx) ?
2775 PROC_SOCK_CTX : PROC_CTX) > 0) {
b217df10
VK
2776 printf(" users:(%s)", ctx_buf);
2777 free(ctx_buf);
116ac927
RH
2778 }
2779 } else if (show_users) {
b217df10
VK
2780 if (find_entry(s->ino, &ctx_buf, USERS) > 0) {
2781 printf(" users:(%s)", ctx_buf);
2782 free(ctx_buf);
116ac927 2783 }
aba5acdf
SH
2784 }
2785 printf("\n");
2786 }
2787}
2788
8a4025f6 2789static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
2790 void *arg)
dfbaa90d 2791{
8a4025f6 2792 struct filter *f = (struct filter *)arg;
dfbaa90d
PE
2793 struct unix_diag_msg *r = NLMSG_DATA(nlh);
2794 struct rtattr *tb[UNIX_DIAG_MAX+1];
99bb68ff
VK
2795 char name[128];
2796 struct sockstat stat = { .name = "*", .peer_name = "*" };
dfbaa90d 2797
acd1e437 2798 parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr *)(r+1),
dfbaa90d
PE
2799 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2800
bf4ceee6
VK
2801 stat.type = r->udiag_type;
2802 stat.state = r->udiag_state;
ec4d0d8a
VK
2803 stat.ino = stat.lport = r->udiag_ino;
2804 stat.local.family = stat.remote.family = AF_UNIX;
0d2e01c5 2805
bf4ceee6
VK
2806 if (unix_type_skip(&stat, f))
2807 return 0;
dfbaa90d 2808
defd61ca
HFS
2809 if (tb[UNIX_DIAG_RQLEN]) {
2810 struct unix_diag_rqlen *rql = RTA_DATA(tb[UNIX_DIAG_RQLEN]);
acd1e437 2811
bf4ceee6
VK
2812 stat.rq = rql->udiag_rqueue;
2813 stat.wq = rql->udiag_wqueue;
defd61ca 2814 }
dfbaa90d
PE
2815 if (tb[UNIX_DIAG_NAME]) {
2816 int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
2817
2818 memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
2819 name[len] = '\0';
2820 if (name[0] == '\0')
2821 name[0] = '@';
99bb68ff
VK
2822 stat.name = &name[0];
2823 memcpy(stat.local.data, &stat.name, sizeof(stat.name));
bf4ceee6 2824 }
dfbaa90d 2825 if (tb[UNIX_DIAG_PEER])
ec4d0d8a 2826 stat.rport = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
dfbaa90d 2827
29999b0f
VK
2828 if (f->f && run_ssfilter(f->f, &stat) == 0)
2829 return 0;
2830
bf4ceee6 2831 unix_stats_print(&stat, f);
dfbaa90d 2832
51ff9f24 2833 if (show_mem) {
bf4ceee6 2834 printf("\t");
51ff9f24
HFS
2835 print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
2836 }
5b816047
PE
2837 if (show_details) {
2838 if (tb[UNIX_DIAG_SHUTDOWN]) {
2839 unsigned char mask;
acd1e437 2840
5b816047
PE
2841 mask = *(__u8 *)RTA_DATA(tb[UNIX_DIAG_SHUTDOWN]);
2842 printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
2843 }
2844 }
bf4ceee6
VK
2845 if (show_mem || show_details)
2846 printf("\n");
ec4d0d8a 2847
dfbaa90d
PE
2848 return 0;
2849}
2850
8a4025f6 2851static int handle_netlink_request(struct filter *f, struct nlmsghdr *req,
2852 size_t size, rtnl_filter_t show_one_sock)
dfbaa90d 2853{
8a4025f6 2854 int ret = -1;
2855 struct rtnl_handle rth;
dfbaa90d 2856
8a4025f6 2857 if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
dfbaa90d
PE
2858 return -1;
2859
8a4025f6 2860 rth.dump = MAGIC_SEQ;
dfbaa90d 2861
8a4025f6 2862 if (rtnl_send(&rth, req, size) < 0)
2863 goto Exit;
dfbaa90d 2864
8a4025f6 2865 if (rtnl_dump_filter(&rth, show_one_sock, f))
2866 goto Exit;
dfbaa90d 2867
8a4025f6 2868 ret = 0;
2869Exit:
2870 rtnl_close(&rth);
2871 return ret;
dfbaa90d
PE
2872}
2873
8a4025f6 2874static int unix_show_netlink(struct filter *f)
d8402b96 2875{
5fb421d4 2876 DIAG_REQUEST(req, struct unix_diag_req r);
d8402b96
AV
2877
2878 req.r.sdiag_family = AF_UNIX;
2879 req.r.udiag_states = f->states;
2880 req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
2881 if (show_mem)
2882 req.r.udiag_show |= UDIAG_SHOW_MEMINFO;
2883
8a4025f6 2884 return handle_netlink_request(f, &req.nlh, sizeof(req), unix_show_sock);
d8402b96
AV
2885}
2886
d1f28cf1 2887static int unix_show(struct filter *f)
aba5acdf
SH
2888{
2889 FILE *fp;
2890 char buf[256];
2891 char name[128];
2892 int newformat = 0;
2893 int cnt;
ec4d0d8a 2894 struct sockstat *list = NULL;
aba5acdf 2895
9db7bf15
VK
2896 if (!filter_af_get(f, AF_UNIX))
2897 return 0;
2898
ec4d0d8a 2899 if (!unix_use_proc() && unix_show_netlink(f) == 0)
dfbaa90d
PE
2900 return 0;
2901
ab01dbbb 2902 if ((fp = net_unix_open()) == NULL)
aba5acdf 2903 return -1;
61170fd8 2904 if (!fgets(buf, sizeof(buf), fp)) {
d572ed4d
PS
2905 fclose(fp);
2906 return -1;
2907 }
aba5acdf 2908
ae665a52 2909 if (memcmp(buf, "Peer", 4) == 0)
aba5acdf
SH
2910 newformat = 1;
2911 cnt = 0;
2912
61170fd8 2913 while (fgets(buf, sizeof(buf), fp)) {
ec4d0d8a 2914 struct sockstat *u, **insp;
aba5acdf
SH
2915 int flags;
2916
0ee9052f 2917 if (!(u = calloc(1, sizeof(*u))))
aba5acdf 2918 break;
99bb68ff
VK
2919 u->name = NULL;
2920 u->peer_name = NULL;
aba5acdf
SH
2921
2922 if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
ec4d0d8a 2923 &u->rport, &u->rq, &u->wq, &flags, &u->type,
aba5acdf
SH
2924 &u->state, &u->ino, name) < 8)
2925 name[0] = 0;
2926
ec4d0d8a
VK
2927 u->lport = u->ino;
2928 u->local.family = u->remote.family = AF_UNIX;
2929
2930 if (flags & (1 << 16)) {
aba5acdf
SH
2931 u->state = SS_LISTEN;
2932 } else {
2933 u->state = unix_state_map[u->state-1];
ec4d0d8a 2934 if (u->type == SOCK_DGRAM && u->state == SS_CLOSE && u->rport)
aba5acdf
SH
2935 u->state = SS_ESTABLISHED;
2936 }
2937
2938 if (!newformat) {
ec4d0d8a 2939 u->rport = 0;
aba5acdf
SH
2940 u->rq = 0;
2941 u->wq = 0;
2942 }
2943
2944 insp = &list;
2945 while (*insp) {
2946 if (u->type < (*insp)->type ||
2947 (u->type == (*insp)->type &&
2948 u->ino < (*insp)->ino))
2949 break;
2950 insp = &(*insp)->next;
2951 }
2952 u->next = *insp;
2953 *insp = u;
2954
2955 if (name[0]) {
99bb68ff
VK
2956 if ((u->name = malloc(strlen(name)+1)) == NULL)
2957 break;
2958 strcpy(u->name, name);
aba5acdf
SH
2959 }
2960 if (++cnt > MAX_UNIX_REMEMBER) {
bf4ceee6 2961 unix_stats_print(list, f);
aba5acdf
SH
2962 unix_list_free(list);
2963 list = NULL;
2964 cnt = 0;
2965 }
2966 }
a3fd8e58 2967 fclose(fp);
aba5acdf 2968 if (list) {
bf4ceee6 2969 unix_stats_print(list, f);
aba5acdf
SH
2970 unix_list_free(list);
2971 list = NULL;
2972 cnt = 0;
2973 }
2974
2975 return 0;
2976}
2977
89f634f9 2978static int packet_stats_print(struct sockstat *s, const struct filter *f)
4a0053b6
VK
2979{
2980 char *buf = NULL;
b217df10
VK
2981 const char *addr, *port;
2982 char ll_name[16];
372c30d2 2983
4a0053b6 2984 if (f->f) {
89f634f9
VK
2985 s->local.family = AF_PACKET;
2986 s->remote.family = AF_PACKET;
89f634f9 2987 s->local.data[0] = s->prot;
89f634f9 2988 if (run_ssfilter(f->f, s) == 0)
4a0053b6
VK
2989 return 1;
2990 }
372c30d2 2991
2d791bc8 2992 sock_state_print(s, s->type == SOCK_RAW ? "p_raw" : "p_dgr");
372c30d2 2993
b217df10
VK
2994 if (s->prot == 3)
2995 addr = "*";
2996 else
2997 addr = ll_proto_n2a(htons(s->prot), ll_name, sizeof(ll_name));
2998
2999 if (s->iface == 0)
3000 port = "*";
3001 else
3002 port = xll_index_to_name(s->iface);
372c30d2 3003
b217df10
VK
3004 sock_addr_print(addr, ":", port, NULL);
3005 sock_addr_print("", "*", "", NULL);
116ac927
RH
3006
3007 if (show_proc_ctx || show_sock_ctx) {
4a0053b6
VK
3008 if (find_entry(s->ino, &buf,
3009 (show_proc_ctx & show_sock_ctx) ?
3010 PROC_SOCK_CTX : PROC_CTX) > 0) {
116ac927
RH
3011 printf(" users:(%s)", buf);
3012 free(buf);
3013 }
3014 } else if (show_users) {
4a0053b6 3015 if (find_entry(s->ino, &buf, USERS) > 0) {
116ac927
RH
3016 printf(" users:(%s)", buf);
3017 free(buf);
3018 }
372c30d2 3019 }
116ac927 3020
f1b39e1b
VK
3021 if (show_details)
3022 sock_details_print(s);
3023
4a0053b6
VK
3024 return 0;
3025}
3026
2631b856
VK
3027static void packet_show_ring(struct packet_diag_ring *ring)
3028{
3029 printf("blk_size:%d", ring->pdr_block_size);
3030 printf(",blk_nr:%d", ring->pdr_block_nr);
3031 printf(",frm_size:%d", ring->pdr_frame_size);
3032 printf(",frm_nr:%d", ring->pdr_frame_nr);
3033 printf(",tmo:%d", ring->pdr_retire_tmo);
3034 printf(",features:0x%x", ring->pdr_features);
3035}
3036
4a0053b6
VK
3037static int packet_show_sock(const struct sockaddr_nl *addr,
3038 struct nlmsghdr *nlh, void *arg)
3039{
3040 const struct filter *f = arg;
3041 struct packet_diag_msg *r = NLMSG_DATA(nlh);
2631b856
VK
3042 struct packet_diag_info *pinfo = NULL;
3043 struct packet_diag_ring *ring_rx = NULL, *ring_tx = NULL;
4a0053b6 3044 struct rtattr *tb[PACKET_DIAG_MAX+1];
89f634f9 3045 struct sockstat stat = {};
2631b856
VK
3046 uint32_t fanout = 0;
3047 bool has_fanout = false;
4a0053b6 3048
acd1e437 3049 parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(r+1),
4a0053b6
VK
3050 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
3051
3052 /* use /proc/net/packet if all info are not available */
3053 if (!tb[PACKET_DIAG_MEMINFO])
3054 return -1;
3055
2d791bc8
VK
3056 stat.type = r->pdiag_type;
3057 stat.prot = r->pdiag_num;
3058 stat.ino = r->pdiag_ino;
3059 stat.state = SS_CLOSE;
f1b39e1b 3060 stat.sk = cookie_sk_get(&r->pdiag_cookie[0]);
4a0053b6
VK
3061
3062 if (tb[PACKET_DIAG_MEMINFO]) {
3063 __u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
acd1e437 3064
4a0053b6
VK
3065 stat.rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
3066 }
3067
3068 if (tb[PACKET_DIAG_INFO]) {
2631b856 3069 pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
2d791bc8 3070 stat.lport = stat.iface = pinfo->pdi_index;
4a0053b6
VK
3071 }
3072
f1b39e1b
VK
3073 if (tb[PACKET_DIAG_UID])
3074 stat.uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
3075
2631b856
VK
3076 if (tb[PACKET_DIAG_RX_RING])
3077 ring_rx = RTA_DATA(tb[PACKET_DIAG_RX_RING]);
3078
3079 if (tb[PACKET_DIAG_TX_RING])
3080 ring_tx = RTA_DATA(tb[PACKET_DIAG_TX_RING]);
3081
3082 if (tb[PACKET_DIAG_FANOUT]) {
3083 has_fanout = true;
3084 fanout = *(uint32_t *)RTA_DATA(tb[PACKET_DIAG_FANOUT]);
3085 }
3086
4a0053b6
VK
3087 if (packet_stats_print(&stat, f))
3088 return 0;
3089
2631b856
VK
3090 if (show_details) {
3091 if (pinfo) {
3092 printf("\n\tver:%d", pinfo->pdi_version);
3093 printf(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
3094 printf(" flags( ");
3095 if (pinfo->pdi_flags & PDI_RUNNING)
3096 printf("running");
3097 if (pinfo->pdi_flags & PDI_AUXDATA)
3098 printf(" auxdata");
3099 if (pinfo->pdi_flags & PDI_ORIGDEV)
3100 printf(" origdev");
3101 if (pinfo->pdi_flags & PDI_VNETHDR)
3102 printf(" vnethdr");
3103 if (pinfo->pdi_flags & PDI_LOSS)
3104 printf(" loss");
3105 if (!pinfo->pdi_flags)
3106 printf("0");
3107 printf(" )");
3108 }
3109 if (ring_rx) {
3110 printf("\n\tring_rx(");
3111 packet_show_ring(ring_rx);
3112 printf(")");
3113 }
3114 if (ring_tx) {
3115 printf("\n\tring_tx(");
3116 packet_show_ring(ring_tx);
3117 printf(")");
3118 }
3119 if (has_fanout) {
3120 uint16_t type = (fanout >> 16) & 0xffff;
3121
3122 printf("\n\tfanout(");
3123 printf("id:%d,", fanout & 0xffff);
3124 printf("type:");
3125
3126 if (type == 0)
3127 printf("hash");
3128 else if (type == 1)
3129 printf("lb");
3130 else if (type == 2)
3131 printf("cpu");
3132 else if (type == 3)
3133 printf("roll");
3134 else if (type == 4)
3135 printf("random");
3136 else if (type == 5)
3137 printf("qm");
3138 else
3139 printf("0x%x", type);
3140
3141 printf(")");
3142 }
3143 }
3144
372c30d2
ND
3145 if (show_bpf && tb[PACKET_DIAG_FILTER]) {
3146 struct sock_filter *fil =
3147 RTA_DATA(tb[PACKET_DIAG_FILTER]);
3148 int num = RTA_PAYLOAD(tb[PACKET_DIAG_FILTER]) /
3149 sizeof(struct sock_filter);
3150
3151 printf("\n\tbpf filter (%d): ", num);
3152 while (num) {
3153 printf(" 0x%02x %u %u %u,",
3154 fil->code, fil->jt, fil->jf, fil->k);
3155 num--;
3156 fil++;
3157 }
3158 }
3159 printf("\n");
3160 return 0;
3161}
3162
8a4025f6 3163static int packet_show_netlink(struct filter *f)
372c30d2 3164{
5fb421d4 3165 DIAG_REQUEST(req, struct packet_diag_req r);
372c30d2 3166
372c30d2 3167 req.r.sdiag_family = AF_PACKET;
2631b856
VK
3168 req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO |
3169 PACKET_SHOW_FILTER | PACKET_SHOW_RING_CFG | PACKET_SHOW_FANOUT;
372c30d2 3170
8a4025f6 3171 return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock);
372c30d2
ND
3172}
3173
4a0053b6
VK
3174static int packet_show_line(char *buf, const struct filter *f, int fam)
3175{
3176 unsigned long long sk;
89f634f9 3177 struct sockstat stat = {};
4a0053b6
VK
3178 int type, prot, iface, state, rq, uid, ino;
3179
3180 sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
3181 &sk,
3182 &type, &prot, &iface, &state,
3183 &rq, &uid, &ino);
3184
3185 if (stat.type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
3186 return 0;
3187 if (stat.type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
3188 return 0;
3189
3190 stat.type = type;
3191 stat.prot = prot;
2d791bc8 3192 stat.lport = stat.iface = iface;
4a0053b6
VK
3193 stat.state = state;
3194 stat.rq = rq;
3195 stat.uid = uid;
3196 stat.ino = ino;
2d791bc8
VK
3197 stat.state = SS_CLOSE;
3198
4a0053b6
VK
3199 if (packet_stats_print(&stat, f))
3200 return 0;
3201
4a0053b6
VK
3202 printf("\n");
3203 return 0;
3204}
aba5acdf 3205
d1f28cf1 3206static int packet_show(struct filter *f)
aba5acdf
SH
3207{
3208 FILE *fp;
b95d28c3 3209 int rc = 0;
3d0b7439 3210
9db7bf15 3211 if (!filter_af_get(f, AF_PACKET) || !(f->states & (1 << SS_CLOSE)))
b9ea445d 3212 return 0;
aba5acdf 3213
4a0053b6
VK
3214 if (!getenv("PROC_NET_PACKET") && !getenv("PROC_ROOT") &&
3215 packet_show_netlink(f) == 0)
372c30d2
ND
3216 return 0;
3217
ab01dbbb 3218 if ((fp = net_packet_open()) == NULL)
aba5acdf 3219 return -1;
4a0053b6 3220 if (generic_record_read(fp, packet_show_line, f, AF_PACKET))
b95d28c3 3221 rc = -1;
aba5acdf 3222
b95d28c3
PS
3223 fclose(fp);
3224 return rc;
aba5acdf
SH
3225}
3226
5f24ec0e 3227static int netlink_show_one(struct filter *f,
acd1e437
SH
3228 int prot, int pid, unsigned int groups,
3229 int state, int dst_pid, unsigned int dst_group,
129709ae
AV
3230 int rq, int wq,
3231 unsigned long long sk, unsigned long long cb)
3232{
2d791bc8 3233 struct sockstat st;
acd1e437 3234
b217df10
VK
3235 SPRINT_BUF(prot_buf) = {};
3236 const char *prot_name;
3237 char procname[64] = {};
eef43b50 3238
2d791bc8
VK
3239 st.state = SS_CLOSE;
3240 st.rq = rq;
3241 st.wq = wq;
3242
129709ae 3243 if (f->f) {
055840f2
VK
3244 st.local.family = AF_NETLINK;
3245 st.remote.family = AF_NETLINK;
3246 st.rport = -1;
3247 st.lport = pid;
3248 st.local.data[0] = prot;
055840f2 3249 if (run_ssfilter(f->f, &st) == 0)
5f24ec0e 3250 return 1;
129709ae
AV
3251 }
3252
2d791bc8 3253 sock_state_print(&st, "nl");
eef43b50 3254
b217df10
VK
3255 if (resolve_services)
3256 prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf));
3257 else
3258 prot_name = int_to_str(prot, prot_buf);
eef43b50 3259
129709ae 3260 if (pid == -1) {
b217df10 3261 procname[0] = '*';
129709ae
AV
3262 } else if (resolve_services) {
3263 int done = 0;
acd1e437 3264
129709ae
AV
3265 if (!pid) {
3266 done = 1;
b217df10 3267 strncpy(procname, "kernel", 6);
129709ae 3268 } else if (pid > 0) {
129709ae 3269 FILE *fp;
acd1e437 3270
0ee9052f 3271 snprintf(procname, sizeof(procname), "%s/%d/stat",
129709ae
AV
3272 getenv("PROC_ROOT") ? : "/proc", pid);
3273 if ((fp = fopen(procname, "r")) != NULL) {
3274 if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
0ee9052f 3275 snprintf(procname+strlen(procname),
3276 sizeof(procname)-strlen(procname),
3277 "/%d", pid);
129709ae
AV
3278 done = 1;
3279 }
3280 fclose(fp);
3281 }
3282 }
3283 if (!done)
b217df10 3284 int_to_str(pid, procname);
129709ae 3285 } else {
b217df10 3286 int_to_str(pid, procname);
129709ae 3287 }
f271fe01 3288
b217df10
VK
3289 sock_addr_print(prot_name, ":", procname, NULL);
3290
f271fe01 3291 if (state == NETLINK_CONNECTED) {
b217df10
VK
3292 char dst_group_buf[30];
3293 char dst_pid_buf[30];
acd1e437 3294
b217df10
VK
3295 sock_addr_print(int_to_str(dst_group, dst_group_buf), ":",
3296 int_to_str(dst_pid, dst_pid_buf), NULL);
f271fe01 3297 } else {
b217df10 3298 sock_addr_print("", "*", "", NULL);
f271fe01 3299 }
129709ae 3300
116ac927 3301 char *pid_context = NULL;
acd1e437 3302
116ac927
RH
3303 if (show_proc_ctx) {
3304 /* The pid value will either be:
3305 * 0 if destination kernel - show kernel initial context.
3306 * A valid process pid - use getpidcon.
3307 * A unique value allocated by the kernel or netlink user
3308 * to the process - show context as "not available".
3309 */
3310 if (!pid)
3311 security_get_initial_context("kernel", &pid_context);
3312 else if (pid > 0)
3313 getpidcon(pid, &pid_context);
3314
3315 if (pid_context != NULL) {
3316 printf("proc_ctx=%-*s ", serv_width, pid_context);
3317 free(pid_context);
3318 } else {
3319 printf("proc_ctx=%-*s ", serv_width, "unavailable");
3320 }
3321 }
3322
129709ae
AV
3323 if (show_details) {
3324 printf(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
3325 }
3326 printf("\n");
3327
5f24ec0e 3328 return 0;
129709ae
AV
3329}
3330
8a4025f6 3331static int netlink_show_sock(const struct sockaddr_nl *addr,
3332 struct nlmsghdr *nlh, void *arg)
ecb928c8 3333{
8a4025f6 3334 struct filter *f = (struct filter *)arg;
ecb928c8
AV
3335 struct netlink_diag_msg *r = NLMSG_DATA(nlh);
3336 struct rtattr *tb[NETLINK_DIAG_MAX+1];
3337 int rq = 0, wq = 0;
3338 unsigned long groups = 0;
3339
acd1e437 3340 parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr *)(r+1),
ecb928c8
AV
3341 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
3342
3343 if (tb[NETLINK_DIAG_GROUPS] && RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS]))
3344 groups = *(unsigned long *) RTA_DATA(tb[NETLINK_DIAG_GROUPS]);
3345
3346 if (tb[NETLINK_DIAG_MEMINFO]) {
3347 const __u32 *skmeminfo;
acd1e437 3348
ecb928c8
AV
3349 skmeminfo = RTA_DATA(tb[NETLINK_DIAG_MEMINFO]);
3350
3351 rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
3352 wq = skmeminfo[SK_MEMINFO_WMEM_ALLOC];
3353 }
3354
5f24ec0e 3355 if (netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
ecb928c8 3356 r->ndiag_state, r->ndiag_dst_portid, r->ndiag_dst_group,
5f24ec0e
VK
3357 rq, wq, 0, 0)) {
3358 return 0;
3359 }
ecb928c8
AV
3360
3361 if (show_mem) {
3362 printf("\t");
3363 print_skmeminfo(tb, NETLINK_DIAG_MEMINFO);
3364 printf("\n");
3365 }
3366
3367 return 0;
3368}
3369
8a4025f6 3370static int netlink_show_netlink(struct filter *f)
ecb928c8 3371{
5fb421d4 3372 DIAG_REQUEST(req, struct netlink_diag_req r);
ecb928c8
AV
3373
3374 req.r.sdiag_family = AF_NETLINK;
3375 req.r.sdiag_protocol = NDIAG_PROTO_ALL;
3376 req.r.ndiag_show = NDIAG_SHOW_GROUPS | NDIAG_SHOW_MEMINFO;
3377
8a4025f6 3378 return handle_netlink_request(f, &req.nlh, sizeof(req), netlink_show_sock);
ecb928c8
AV
3379}
3380
d1f28cf1 3381static int netlink_show(struct filter *f)
aba5acdf
SH
3382{
3383 FILE *fp;
3384 char buf[256];
3385 int prot, pid;
acd1e437 3386 unsigned int groups;
aba5acdf
SH
3387 int rq, wq, rc;
3388 unsigned long long sk, cb;
3389
9db7bf15 3390 if (!filter_af_get(f, AF_NETLINK) || !(f->states & (1 << SS_CLOSE)))
b9ea445d
VK
3391 return 0;
3392
129709ae 3393 if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") &&
8a4025f6 3394 netlink_show_netlink(f) == 0)
129709ae
AV
3395 return 0;
3396
ab01dbbb 3397 if ((fp = net_netlink_open()) == NULL)
aba5acdf 3398 return -1;
61170fd8 3399 if (!fgets(buf, sizeof(buf), fp)) {
d572ed4d
PS
3400 fclose(fp);
3401 return -1;
3402 }
aba5acdf 3403
61170fd8 3404 while (fgets(buf, sizeof(buf), fp)) {
aba5acdf
SH
3405 sscanf(buf, "%llx %d %d %x %d %d %llx %d",
3406 &sk,
3407 &prot, &pid, &groups, &rq, &wq, &cb, &rc);
3408
f271fe01 3409 netlink_show_one(f, prot, pid, groups, 0, 0, 0, rq, wq, sk, cb);
aba5acdf
SH
3410 }
3411
b95d28c3 3412 fclose(fp);
aba5acdf
SH
3413 return 0;
3414}
3415
6885e3bf
CG
3416struct sock_diag_msg {
3417 __u8 sdiag_family;
3418};
3419
3420static int generic_show_sock(const struct sockaddr_nl *addr,
3421 struct nlmsghdr *nlh, void *arg)
3422{
3423 struct sock_diag_msg *r = NLMSG_DATA(nlh);
3424 struct inet_diag_arg inet_arg = { .f = arg, .protocol = IPPROTO_MAX };
3425
3426 switch (r->sdiag_family) {
3427 case AF_INET:
3428 case AF_INET6:
3429 return show_one_inet_sock(addr, nlh, &inet_arg);
3430 case AF_UNIX:
3431 return unix_show_sock(addr, nlh, arg);
3432 case AF_PACKET:
3433 return packet_show_sock(addr, nlh, arg);
3434 case AF_NETLINK:
3435 return netlink_show_sock(addr, nlh, arg);
3436 default:
3437 return -1;
3438 }
3439}
3440
3441static int handle_follow_request(struct filter *f)
3442{
3443 int ret = -1;
3444 int groups = 0;
3445 struct rtnl_handle rth;
3446
3447 if (f->families & (1 << AF_INET) && f->dbs & (1 << TCP_DB))
3448 groups |= 1 << (SKNLGRP_INET_TCP_DESTROY - 1);
3449 if (f->families & (1 << AF_INET) && f->dbs & (1 << UDP_DB))
3450 groups |= 1 << (SKNLGRP_INET_UDP_DESTROY - 1);
3451 if (f->families & (1 << AF_INET6) && f->dbs & (1 << TCP_DB))
3452 groups |= 1 << (SKNLGRP_INET6_TCP_DESTROY - 1);
3453 if (f->families & (1 << AF_INET6) && f->dbs & (1 << UDP_DB))
3454 groups |= 1 << (SKNLGRP_INET6_UDP_DESTROY - 1);
3455
3456 if (groups == 0)
3457 return -1;
3458
3459 if (rtnl_open_byproto(&rth, groups, NETLINK_SOCK_DIAG))
3460 return -1;
3461
3462 rth.dump = 0;
3463 rth.local.nl_pid = 0;
3464
3465 if (rtnl_dump_filter(&rth, generic_show_sock, f))
3466 goto Exit;
3467
3468 ret = 0;
3469Exit:
3470 rtnl_close(&rth);
3471 return ret;
3472}
3473
acd1e437 3474struct snmpstat {
aba5acdf
SH
3475 int tcp_estab;
3476};
3477
d1f28cf1 3478static int get_snmp_int(char *proto, char *key, int *result)
aba5acdf
SH
3479{
3480 char buf[1024];
3481 FILE *fp;
3482 int protolen = strlen(proto);
3483 int keylen = strlen(key);
3484
3485 *result = 0;
3486
ab01dbbb 3487 if ((fp = net_snmp_open()) == NULL)
aba5acdf
SH
3488 return -1;
3489
3490 while (fgets(buf, sizeof(buf), fp) != NULL) {
3491 char *p = buf;
3492 int pos = 0;
acd1e437 3493
aba5acdf
SH
3494 if (memcmp(buf, proto, protolen))
3495 continue;
3496 while ((p = strchr(p, ' ')) != NULL) {
3497 pos++;
3498 p++;
3499 if (memcmp(p, key, keylen) == 0 &&
3500 (p[keylen] == ' ' || p[keylen] == '\n'))
3501 break;
3502 }
3503 if (fgets(buf, sizeof(buf), fp) == NULL)
3504 break;
3505 if (memcmp(buf, proto, protolen))
3506 break;
3507 p = buf;
3508 while ((p = strchr(p, ' ')) != NULL) {
3509 p++;
3510 if (--pos == 0) {
3511 sscanf(p, "%d", result);
3512 fclose(fp);
3513 return 0;
3514 }
3515 }
3516 }
3517
3518 fclose(fp);
3519 errno = ESRCH;
3520 return -1;
3521}
3522
3523
3524/* Get stats from sockstat */
3525
acd1e437 3526struct ssummary {
aba5acdf
SH
3527 int socks;
3528 int tcp_mem;
3529 int tcp_total;
3530 int tcp_orphans;
3531 int tcp_tws;
3532 int tcp4_hashed;
3533 int udp4;
3534 int raw4;
3535 int frag4;
3536 int frag4_mem;
3537 int tcp6_hashed;
3538 int udp6;
3539 int raw6;
3540 int frag6;
3541 int frag6_mem;
3542};
3543
055840f2 3544static void get_sockstat_line(char *line, struct ssummary *s)
aba5acdf
SH
3545{
3546 char id[256], rem[256];
3547
3548 if (sscanf(line, "%[^ ] %[^\n]\n", id, rem) != 2)
3549 return;
3550
3551 if (strcmp(id, "sockets:") == 0)
3552 sscanf(rem, "%*s%d", &s->socks);
3553 else if (strcmp(id, "UDP:") == 0)
3554 sscanf(rem, "%*s%d", &s->udp4);
3555 else if (strcmp(id, "UDP6:") == 0)
3556 sscanf(rem, "%*s%d", &s->udp6);
3557 else if (strcmp(id, "RAW:") == 0)
3558 sscanf(rem, "%*s%d", &s->raw4);
3559 else if (strcmp(id, "RAW6:") == 0)
3560 sscanf(rem, "%*s%d", &s->raw6);
3561 else if (strcmp(id, "TCP6:") == 0)
3562 sscanf(rem, "%*s%d", &s->tcp6_hashed);
3563 else if (strcmp(id, "FRAG:") == 0)
3564 sscanf(rem, "%*s%d%*s%d", &s->frag4, &s->frag4_mem);
3565 else if (strcmp(id, "FRAG6:") == 0)
3566 sscanf(rem, "%*s%d%*s%d", &s->frag6, &s->frag6_mem);
3567 else if (strcmp(id, "TCP:") == 0)
3568 sscanf(rem, "%*s%d%*s%d%*s%d%*s%d%*s%d",
3569 &s->tcp4_hashed,
3570 &s->tcp_orphans, &s->tcp_tws, &s->tcp_total, &s->tcp_mem);
3571}
3572
055840f2 3573static int get_sockstat(struct ssummary *s)
aba5acdf
SH
3574{
3575 char buf[256];
3576 FILE *fp;
3577
3578 memset(s, 0, sizeof(*s));
3579
ab01dbbb 3580 if ((fp = net_sockstat_open()) == NULL)
aba5acdf 3581 return -1;
acd1e437 3582 while (fgets(buf, sizeof(buf), fp) != NULL)
aba5acdf
SH
3583 get_sockstat_line(buf, s);
3584 fclose(fp);
3585
ab01dbbb 3586 if ((fp = net_sockstat6_open()) == NULL)
aba5acdf 3587 return 0;
acd1e437 3588 while (fgets(buf, sizeof(buf), fp) != NULL)
aba5acdf
SH
3589 get_sockstat_line(buf, s);
3590 fclose(fp);
3591
3592 return 0;
3593}
3594
d1f28cf1 3595static int print_summary(void)
aba5acdf 3596{
055840f2 3597 struct ssummary s;
aba5acdf
SH
3598 struct snmpstat sn;
3599
3600 if (get_sockstat(&s) < 0)
3601 perror("ss: get_sockstat");
3602 if (get_snmp_int("Tcp:", "CurrEstab", &sn.tcp_estab) < 0)
3603 perror("ss: get_snmpstat");
3604
a221d621
BL
3605 get_slabstat(&slabstat);
3606
aba5acdf
SH
3607 printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks);
3608
3609 printf("TCP: %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
3610 s.tcp_total + slabstat.tcp_syns + s.tcp_tws,
3611 sn.tcp_estab,
3612 s.tcp_total - (s.tcp4_hashed+s.tcp6_hashed-s.tcp_tws),
3613 s.tcp_orphans,
3614 slabstat.tcp_syns,
3615 s.tcp_tws, slabstat.tcp_tws,
3616 slabstat.tcp_ports
3617 );
3618
3619 printf("\n");
3620 printf("Transport Total IP IPv6\n");
3621 printf("* %-9d %-9s %-9s\n", slabstat.socks, "-", "-");
3622 printf("RAW %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
3623 printf("UDP %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
3624 printf("TCP %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
ae665a52 3625 printf("INET %-9d %-9d %-9d\n",
aba5acdf
SH
3626 s.raw4+s.udp4+s.tcp4_hashed+
3627 s.raw6+s.udp6+s.tcp6_hashed,
3628 s.raw4+s.udp4+s.tcp4_hashed,
3629 s.raw6+s.udp6+s.tcp6_hashed);
3630 printf("FRAG %-9d %-9d %-9d\n", s.frag4+s.frag6, s.frag4, s.frag6);
3631
3632 printf("\n");
3633
3634 return 0;
3635}
3636
7a96e199 3637static void _usage(FILE *dest)
aba5acdf 3638{
7a96e199 3639 fprintf(dest,
aba5acdf
SH
3640"Usage: ss [ OPTIONS ]\n"
3641" ss [ OPTIONS ] [ FILTER ]\n"
ff041f16
VK
3642" -h, --help this message\n"
3643" -V, --version output version information\n"
3644" -n, --numeric don't resolve service names\n"
ab61159a 3645" -r, --resolve resolve host names\n"
ff041f16
VK
3646" -a, --all display all sockets\n"
3647" -l, --listening display listening sockets\n"
ab61159a
SH
3648" -o, --options show timer information\n"
3649" -e, --extended show detailed socket information\n"
3650" -m, --memory show socket memory usage\n"
ff041f16
VK
3651" -p, --processes show process using socket\n"
3652" -i, --info show internal TCP information\n"
3653" -s, --summary show socket usage summary\n"
b0f01cf6 3654" -b, --bpf show bpf filter socket information\n"
6885e3bf 3655" -E, --events continually display sockets as they are destroyed\n"
ff041f16
VK
3656" -Z, --context display process SELinux security contexts\n"
3657" -z, --contexts display process and socket SELinux security contexts\n"
95ce04bc 3658" -N, --net switch to the specified network namespace name\n"
ab61159a
SH
3659"\n"
3660" -4, --ipv4 display only IP version 4 sockets\n"
3661" -6, --ipv6 display only IP version 6 sockets\n"
ff041f16
VK
3662" -0, --packet display PACKET sockets\n"
3663" -t, --tcp display only TCP sockets\n"
3664" -u, --udp display only UDP sockets\n"
3665" -d, --dccp display only DCCP sockets\n"
3666" -w, --raw display only RAW sockets\n"
3667" -x, --unix display only Unix domain sockets\n"
ab61159a 3668" -f, --family=FAMILY display sockets of type FAMILY\n"
ebef3174 3669" FAMILY := {inet|inet6|link|unix|netlink|help}\n"
ab61159a 3670"\n"
fb2594c1
LC
3671" -K, --kill forcibly close sockets, display what was closed\n"
3672"\n"
583de149 3673" -A, --query=QUERY, --socket=QUERY\n"
56dee73e 3674" QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]\n"
ab61159a 3675"\n"
583de149 3676" -D, --diag=FILE Dump raw information about TCP sockets to FILE\n"
ab61159a 3677" -F, --filter=FILE read filter information from FILE\n"
ff041f16
VK
3678" FILTER := [ state STATE-FILTER ] [ EXPRESSION ]\n"
3679" STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}\n"
3680" TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listen|closing}\n"
3681" connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
3682" synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
3683" bucket := {syn-recv|time-wait}\n"
3684" big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listen|closing}\n"
ab61159a 3685 );
7a96e199
AH
3686}
3687
3688static void help(void) __attribute__((noreturn));
3689static void help(void)
3690{
3691 _usage(stdout);
3692 exit(0);
3693}
3694
3695static void usage(void) __attribute__((noreturn));
3696static void usage(void)
3697{
3698 _usage(stderr);
aba5acdf
SH
3699 exit(-1);
3700}
3701
3702
d1f28cf1 3703static int scan_state(const char *state)
aba5acdf
SH
3704{
3705 int i;
acd1e437 3706
aba5acdf
SH
3707 if (strcasecmp(state, "close") == 0 ||
3708 strcasecmp(state, "closed") == 0)
3709 return (1<<SS_CLOSE);
3710 if (strcasecmp(state, "syn-rcv") == 0)
3711 return (1<<SS_SYN_RECV);
1a5bad5a 3712 if (strcasecmp(state, "established") == 0)
aba5acdf
SH
3713 return (1<<SS_ESTABLISHED);
3714 if (strcasecmp(state, "all") == 0)
3715 return SS_ALL;
3716 if (strcasecmp(state, "connected") == 0)
3717 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN));
1a5bad5a 3718 if (strcasecmp(state, "synchronized") == 0)
aba5acdf
SH
3719 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN)|(1<<SS_SYN_SENT));
3720 if (strcasecmp(state, "bucket") == 0)
3721 return (1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT);
3722 if (strcasecmp(state, "big") == 0)
3723 return SS_ALL & ~((1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT));
acd1e437 3724 for (i = 0; i < SS_MAX; i++) {
1a5bad5a 3725 if (strcasecmp(state, sstate_namel[i]) == 0)
aba5acdf
SH
3726 return (1<<i);
3727 }
9db7bf15
VK
3728
3729 fprintf(stderr, "ss: wrong state name: %s\n", state);
3730 exit(-1);
aba5acdf
SH
3731}
3732
ab61159a
SH
3733static const struct option long_opts[] = {
3734 { "numeric", 0, 0, 'n' },
3735 { "resolve", 0, 0, 'r' },
3736 { "options", 0, 0, 'o' },
3737 { "extended", 0, 0, 'e' },
3738 { "memory", 0, 0, 'm' },
3739 { "info", 0, 0, 'i' },
3740 { "processes", 0, 0, 'p' },
372c30d2 3741 { "bpf", 0, 0, 'b' },
6885e3bf 3742 { "events", 0, 0, 'E' },
351efcde 3743 { "dccp", 0, 0, 'd' },
ab61159a
SH
3744 { "tcp", 0, 0, 't' },
3745 { "udp", 0, 0, 'u' },
3746 { "raw", 0, 0, 'w' },
3747 { "unix", 0, 0, 'x' },
3748 { "all", 0, 0, 'a' },
3749 { "listening", 0, 0, 'l' },
3750 { "ipv4", 0, 0, '4' },
3751 { "ipv6", 0, 0, '6' },
3752 { "packet", 0, 0, '0' },
3753 { "family", 1, 0, 'f' },
3754 { "socket", 1, 0, 'A' },
583de149 3755 { "query", 1, 0, 'A' },
c3f346b0 3756 { "summary", 0, 0, 's' },
583de149 3757 { "diag", 1, 0, 'D' },
ab61159a
SH
3758 { "filter", 1, 0, 'F' },
3759 { "version", 0, 0, 'V' },
3760 { "help", 0, 0, 'h' },
116ac927
RH
3761 { "context", 0, 0, 'Z' },
3762 { "contexts", 0, 0, 'z' },
95ce04bc 3763 { "net", 1, 0, 'N' },
fb2594c1 3764 { "kill", 0, 0, 'K' },
ab61159a 3765 { 0 }
ae665a52 3766
ab61159a
SH
3767};
3768
aba5acdf
SH
3769int main(int argc, char *argv[])
3770{
aba5acdf
SH
3771 int saw_states = 0;
3772 int saw_query = 0;
3773 int do_summary = 0;
7d105b56 3774 const char *dump_tcpdiag = NULL;
aba5acdf
SH
3775 FILE *filter_fp = NULL;
3776 int ch;
9db7bf15 3777 int state_filter = 0;
aba5acdf 3778
fb2594c1 3779 while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:K",
ab61159a 3780 long_opts, NULL)) != EOF) {
acd1e437 3781 switch (ch) {
aba5acdf
SH
3782 case 'n':
3783 resolve_services = 0;
3784 break;
3785 case 'r':
3786 resolve_hosts = 1;
3787 break;
3788 case 'o':
3789 show_options = 1;
3790 break;
3791 case 'e':
3792 show_options = 1;
3793 show_details++;
3794 break;
3795 case 'm':
3796 show_mem = 1;
3797 break;
3798 case 'i':
3799 show_tcpinfo = 1;
3800 break;
3801 case 'p':
3802 show_users++;
fbc0f876 3803 user_ent_hash_build();
aba5acdf 3804 break;
372c30d2
ND
3805 case 'b':
3806 show_options = 1;
3807 show_bpf++;
3808 break;
6885e3bf
CG
3809 case 'E':
3810 follow_events = 1;
3811 break;
351efcde 3812 case 'd':
57ff5a10 3813 filter_db_set(&current_filter, DCCP_DB);
351efcde 3814 break;
aba5acdf 3815 case 't':
57ff5a10 3816 filter_db_set(&current_filter, TCP_DB);
aba5acdf
SH
3817 break;
3818 case 'u':
57ff5a10 3819 filter_db_set(&current_filter, UDP_DB);
aba5acdf
SH
3820 break;
3821 case 'w':
57ff5a10 3822 filter_db_set(&current_filter, RAW_DB);
aba5acdf
SH
3823 break;
3824 case 'x':
9db7bf15 3825 filter_af_set(&current_filter, AF_UNIX);
aba5acdf
SH
3826 break;
3827 case 'a':
9db7bf15 3828 state_filter = SS_ALL;
aba5acdf
SH
3829 break;
3830 case 'l':
9db7bf15 3831 state_filter = (1 << SS_LISTEN) | (1 << SS_CLOSE);
aba5acdf
SH
3832 break;
3833 case '4':
9db7bf15 3834 filter_af_set(&current_filter, AF_INET);
aba5acdf
SH
3835 break;
3836 case '6':
9db7bf15 3837 filter_af_set(&current_filter, AF_INET6);
aba5acdf
SH
3838 break;
3839 case '0':
9db7bf15 3840 filter_af_set(&current_filter, AF_PACKET);
aba5acdf
SH
3841 break;
3842 case 'f':
3843 if (strcmp(optarg, "inet") == 0)
9db7bf15 3844 filter_af_set(&current_filter, AF_INET);
aba5acdf 3845 else if (strcmp(optarg, "inet6") == 0)
9db7bf15 3846 filter_af_set(&current_filter, AF_INET6);
aba5acdf 3847 else if (strcmp(optarg, "link") == 0)
9db7bf15 3848 filter_af_set(&current_filter, AF_PACKET);
aba5acdf 3849 else if (strcmp(optarg, "unix") == 0)
9db7bf15 3850 filter_af_set(&current_filter, AF_UNIX);
aba5acdf 3851 else if (strcmp(optarg, "netlink") == 0)
9db7bf15 3852 filter_af_set(&current_filter, AF_NETLINK);
aba5acdf 3853 else if (strcmp(optarg, "help") == 0)
7a96e199 3854 help();
aba5acdf 3855 else {
9db7bf15
VK
3856 fprintf(stderr, "ss: \"%s\" is invalid family\n",
3857 optarg);
aba5acdf
SH
3858 usage();
3859 }
3860 break;
3861 case 'A':
3862 {
3863 char *p, *p1;
acd1e437 3864
aba5acdf
SH
3865 if (!saw_query) {
3866 current_filter.dbs = 0;
7f9dddbe 3867 state_filter = state_filter ?
acd1e437 3868 state_filter : SS_CONN;
aba5acdf
SH
3869 saw_query = 1;
3870 do_default = 0;
3871 }
3872 p = p1 = optarg;
3873 do {
3874 if ((p1 = strchr(p, ',')) != NULL)
ae665a52 3875 *p1 = 0;
aba5acdf 3876 if (strcmp(p, "all") == 0) {
57ff5a10 3877 filter_default_dbs(&current_filter);
aba5acdf 3878 } else if (strcmp(p, "inet") == 0) {
57ff5a10
VK
3879 filter_db_set(&current_filter, UDP_DB);
3880 filter_db_set(&current_filter, DCCP_DB);
3881 filter_db_set(&current_filter, TCP_DB);
3882 filter_db_set(&current_filter, RAW_DB);
aba5acdf 3883 } else if (strcmp(p, "udp") == 0) {
57ff5a10 3884 filter_db_set(&current_filter, UDP_DB);
351efcde 3885 } else if (strcmp(p, "dccp") == 0) {
57ff5a10 3886 filter_db_set(&current_filter, DCCP_DB);
aba5acdf 3887 } else if (strcmp(p, "tcp") == 0) {
57ff5a10 3888 filter_db_set(&current_filter, TCP_DB);
aba5acdf 3889 } else if (strcmp(p, "raw") == 0) {
57ff5a10 3890 filter_db_set(&current_filter, RAW_DB);
aba5acdf 3891 } else if (strcmp(p, "unix") == 0) {
57ff5a10
VK
3892 filter_db_set(&current_filter, UNIX_ST_DB);
3893 filter_db_set(&current_filter, UNIX_DG_DB);
3894 filter_db_set(&current_filter, UNIX_SQ_DB);
1a5bad5a 3895 } else if (strcasecmp(p, "unix_stream") == 0 ||
aba5acdf 3896 strcmp(p, "u_str") == 0) {
57ff5a10 3897 filter_db_set(&current_filter, UNIX_ST_DB);
1a5bad5a 3898 } else if (strcasecmp(p, "unix_dgram") == 0 ||
aba5acdf 3899 strcmp(p, "u_dgr") == 0) {
57ff5a10 3900 filter_db_set(&current_filter, UNIX_DG_DB);
30b669d7
MY
3901 } else if (strcasecmp(p, "unix_seqpacket") == 0 ||
3902 strcmp(p, "u_seq") == 0) {
57ff5a10 3903 filter_db_set(&current_filter, UNIX_SQ_DB);
aba5acdf 3904 } else if (strcmp(p, "packet") == 0) {
57ff5a10
VK
3905 filter_db_set(&current_filter, PACKET_R_DB);
3906 filter_db_set(&current_filter, PACKET_DG_DB);
aba5acdf
SH
3907 } else if (strcmp(p, "packet_raw") == 0 ||
3908 strcmp(p, "p_raw") == 0) {
57ff5a10 3909 filter_db_set(&current_filter, PACKET_R_DB);
aba5acdf
SH
3910 } else if (strcmp(p, "packet_dgram") == 0 ||
3911 strcmp(p, "p_dgr") == 0) {
57ff5a10 3912 filter_db_set(&current_filter, PACKET_DG_DB);
aba5acdf 3913 } else if (strcmp(p, "netlink") == 0) {
57ff5a10 3914 filter_db_set(&current_filter, NETLINK_DB);
aba5acdf
SH
3915 } else {
3916 fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p);
3917 usage();
3918 }
3919 p = p1 + 1;
3920 } while (p1);
3921 break;
3922 }
3923 case 's':
3924 do_summary = 1;
3925 break;
3926 case 'D':
3927 dump_tcpdiag = optarg;
3928 break;
3929 case 'F':
3930 if (filter_fp) {
3931 fprintf(stderr, "More than one filter file\n");
3932 exit(-1);
3933 }
3934 if (optarg[0] == '-')
3935 filter_fp = stdin;
3936 else
3937 filter_fp = fopen(optarg, "r");
3938 if (!filter_fp) {
3939 perror("fopen filter file");
3940 exit(-1);
3941 }
3942 break;
3943 case 'v':
3944 case 'V':
3945 printf("ss utility, iproute2-ss%s\n", SNAPSHOT);
3946 exit(0);
116ac927
RH
3947 case 'z':
3948 show_sock_ctx++;
3949 case 'Z':
3950 if (is_selinux_enabled() <= 0) {
3951 fprintf(stderr, "ss: SELinux is not enabled.\n");
3952 exit(1);
3953 }
3954 show_proc_ctx++;
3955 user_ent_hash_build();
3956 break;
95ce04bc
VK
3957 case 'N':
3958 if (netns_switch(optarg))
3959 exit(1);
3960 break;
fb2594c1
LC
3961 case 'K':
3962 current_filter.kill = 1;
3963 break;
aba5acdf 3964 case 'h':
7a96e199 3965 help();
f73105ab 3966 case '?':
aba5acdf
SH
3967 default:
3968 usage();
3969 }
3970 }
3971
3972 argc -= optind;
3973 argv += optind;
3974
aba5acdf
SH
3975 if (do_summary) {
3976 print_summary();
3977 if (do_default && argc == 0)
3978 exit(0);
3979 }
3980
aba5acdf
SH
3981 while (argc > 0) {
3982 if (strcmp(*argv, "state") == 0) {
3983 NEXT_ARG();
3984 if (!saw_states)
9db7bf15
VK
3985 state_filter = 0;
3986 state_filter |= scan_state(*argv);
aba5acdf
SH
3987 saw_states = 1;
3988 } else if (strcmp(*argv, "exclude") == 0 ||
3989 strcmp(*argv, "excl") == 0) {
3990 NEXT_ARG();
3991 if (!saw_states)
9db7bf15
VK
3992 state_filter = SS_ALL;
3993 state_filter &= ~scan_state(*argv);
aba5acdf
SH
3994 saw_states = 1;
3995 } else {
aba5acdf
SH
3996 break;
3997 }
3998 argc--; argv++;
3999 }
4000
9db7bf15
VK
4001 if (do_default) {
4002 state_filter = state_filter ? state_filter : SS_CONN;
4003 filter_default_dbs(&current_filter);
9db7bf15
VK
4004 }
4005
57ff5a10
VK
4006 filter_states_set(&current_filter, state_filter);
4007 filter_merge_defaults(&current_filter);
4008
9db7bf15
VK
4009 if (resolve_services && resolve_hosts &&
4010 (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
4011 init_service_resolver();
4012
4013
4014 if (current_filter.dbs == 0) {
4015 fprintf(stderr, "ss: no socket tables to show with such filter.\n");
4016 exit(0);
4017 }
4018 if (current_filter.families == 0) {
4019 fprintf(stderr, "ss: no families to show with such filter.\n");
4020 exit(0);
4021 }
aba5acdf
SH
4022 if (current_filter.states == 0) {
4023 fprintf(stderr, "ss: no socket states to show with such filter.\n");
4024 exit(0);
4025 }
4026
4027 if (dump_tcpdiag) {
4028 FILE *dump_fp = stdout;
acd1e437 4029
aba5acdf
SH
4030 if (!(current_filter.dbs & (1<<TCP_DB))) {
4031 fprintf(stderr, "ss: tcpdiag dump requested and no tcp in filter.\n");
4032 exit(0);
4033 }
4034 if (dump_tcpdiag[0] != '-') {
4035 dump_fp = fopen(dump_tcpdiag, "w");
4036 if (!dump_tcpdiag) {
4037 perror("fopen dump file");
4038 exit(-1);
4039 }
4040 }
3fe5b534 4041 inet_show_netlink(&current_filter, dump_fp, IPPROTO_TCP);
aba5acdf
SH
4042 fflush(dump_fp);
4043 exit(0);
4044 }
4045
1527a17e
VK
4046 if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
4047 usage();
4048
aba5acdf
SH
4049 netid_width = 0;
4050 if (current_filter.dbs&(current_filter.dbs-1))
4051 netid_width = 5;
4052
4053 state_width = 0;
4054 if (current_filter.states&(current_filter.states-1))
4055 state_width = 10;
4056
4057 screen_width = 80;
4058 if (isatty(STDOUT_FILENO)) {
4059 struct winsize w;
4060
4061 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
4062 if (w.ws_col > 0)
4063 screen_width = w.ws_col;
4064 }
4065 }
4066
4067 addrp_width = screen_width;
4068 addrp_width -= netid_width+1;
4069 addrp_width -= state_width+1;
4070 addrp_width -= 14;
4071
4072 if (addrp_width&1) {
4073 if (netid_width)
4074 netid_width++;
4075 else if (state_width)
4076 state_width++;
4077 }
4078
4079 addrp_width /= 2;
4080 addrp_width--;
4081
4082 serv_width = resolve_services ? 7 : 5;
4083
4084 if (addrp_width < 15+serv_width+1)
4085 addrp_width = 15+serv_width+1;
4086
ae665a52 4087 addr_width = addrp_width - serv_width - 1;
aba5acdf
SH
4088
4089 if (netid_width)
4090 printf("%-*s ", netid_width, "Netid");
4091 if (state_width)
4092 printf("%-*s ", state_width, "State");
4093 printf("%-6s %-6s ", "Recv-Q", "Send-Q");
4094
d68e00f7 4095 /* Make enough space for the local/remote port field */
4096 addr_width -= 13;
4097 serv_width += 13;
2dc85485 4098
aba5acdf
SH
4099 printf("%*s:%-*s %*s:%-*s\n",
4100 addr_width, "Local Address", serv_width, "Port",
d68e00f7 4101 addr_width, "Peer Address", serv_width, "Port");
aba5acdf 4102
aba5acdf
SH
4103 fflush(stdout);
4104
6885e3bf
CG
4105 if (follow_events)
4106 exit(handle_follow_request(&current_filter));
4107
aba5acdf
SH
4108 if (current_filter.dbs & (1<<NETLINK_DB))
4109 netlink_show(&current_filter);
4110 if (current_filter.dbs & PACKET_DBM)
4111 packet_show(&current_filter);
4112 if (current_filter.dbs & UNIX_DBM)
4113 unix_show(&current_filter);
4114 if (current_filter.dbs & (1<<RAW_DB))
4115 raw_show(&current_filter);
4116 if (current_filter.dbs & (1<<UDP_DB))
4117 udp_show(&current_filter);
4118 if (current_filter.dbs & (1<<TCP_DB))
3fe5b534 4119 tcp_show(&current_filter, IPPROTO_TCP);
351efcde 4120 if (current_filter.dbs & (1<<DCCP_DB))
3fe5b534 4121 tcp_show(&current_filter, IPPROTO_DCCP);
116ac927
RH
4122
4123 if (show_users || show_proc_ctx || show_sock_ctx)
4124 user_ent_destroy();
4125
aba5acdf
SH
4126 return 0;
4127}