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