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