]> git.proxmox.com Git - mirror_iproute2.git/blame - misc/ss.c
ss: Allow to specify sport/dport without ':'
[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
7871f7db 1383void *parse_hostcond(char *addr, bool is_port)
aba5acdf
SH
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 }
7871f7db
VK
1476
1477 if (is_port)
1478 port = addr;
1479
aba5acdf 1480 if (port && *port) {
7871f7db
VK
1481 if (*port == ':')
1482 *port++ = 0;
1483
aba5acdf
SH
1484 if (*port && *port != '*') {
1485 if (get_integer(&a.port, port, 0)) {
1486 struct servent *se1 = NULL;
1487 struct servent *se2 = NULL;
1488 if (current_filter.dbs&(1<<UDP_DB))
1489 se1 = getservbyname(port, UDP_PROTO);
1490 if (current_filter.dbs&(1<<TCP_DB))
1491 se2 = getservbyname(port, TCP_PROTO);
1492 if (se1 && se2 && se1->s_port != se2->s_port) {
1493 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
1494 return NULL;
1495 }
1496 if (!se1)
1497 se1 = se2;
1498 if (se1) {
1499 a.port = ntohs(se1->s_port);
1500 } else {
1501 struct scache *s;
1502 for (s = rlist; s; s = s->next) {
1503 if ((s->proto == UDP_PROTO &&
1504 (current_filter.dbs&(1<<UDP_DB))) ||
1505 (s->proto == TCP_PROTO &&
1506 (current_filter.dbs&(1<<TCP_DB)))) {
1507 if (s->name && strcmp(s->name, port) == 0) {
1508 if (a.port > 0 && a.port != s->port) {
1509 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
1510 return NULL;
1511 }
1512 a.port = s->port;
1513 }
1514 }
1515 }
1516 if (a.port <= 0) {
1517 fprintf(stderr, "Error: \"%s\" does not look like a port.\n", port);
1518 return NULL;
1519 }
1520 }
1521 }
1522 }
1523 }
7871f7db 1524 if (!is_port && addr && *addr && *addr != '*') {
aba5acdf
SH
1525 if (get_prefix_1(&a.addr, addr, fam)) {
1526 if (get_dns_host(&a, addr, fam)) {
1527 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", addr);
1528 return NULL;
1529 }
1530 }
1531 }
1532
9db7bf15 1533out:
1527a17e
VK
1534 if (fam != AF_UNSPEC) {
1535 f->families = 0;
9db7bf15 1536 filter_af_set(f, fam);
1527a17e
VK
1537 filter_merge(f, f, 0);
1538 }
9db7bf15 1539
aba5acdf
SH
1540 res = malloc(sizeof(*res));
1541 if (res)
1542 memcpy(res, &a, sizeof(a));
1543 return res;
1544}
1545
8250bc9f
VK
1546static char *proto_name(int protocol)
1547{
1548 switch (protocol) {
1549 case IPPROTO_UDP:
1550 return "udp";
1551 case IPPROTO_TCP:
1552 return "tcp";
1553 case IPPROTO_DCCP:
1554 return "dccp";
1555 }
1556
1557 return "???";
1558}
1559
055840f2 1560static void inet_stats_print(struct sockstat *s, int protocol)
8250bc9f
VK
1561{
1562 char *buf = NULL;
1563
2d791bc8 1564 sock_state_print(s, proto_name(protocol));
8250bc9f 1565
b217df10
VK
1566 inet_addr_print(&s->local, s->lport, s->iface);
1567 inet_addr_print(&s->remote, s->rport, 0);
8250bc9f 1568
8250bc9f
VK
1569 if (show_proc_ctx || show_sock_ctx) {
1570 if (find_entry(s->ino, &buf,
1571 (show_proc_ctx & show_sock_ctx) ?
1572 PROC_SOCK_CTX : PROC_CTX) > 0) {
1573 printf(" users:(%s)", buf);
1574 free(buf);
1575 }
1576 } else if (show_users) {
1577 if (find_entry(s->ino, &buf, USERS) > 0) {
1578 printf(" users:(%s)", buf);
1579 free(buf);
1580 }
1581 }
1582}
1583
055840f2
VK
1584static int proc_parse_inet_addr(char *loc, char *rem, int family, struct
1585 sockstat *s)
8250bc9f
VK
1586{
1587 s->local.family = s->remote.family = family;
1588 if (family == AF_INET) {
1589 sscanf(loc, "%x:%x", s->local.data, (unsigned*)&s->lport);
1590 sscanf(rem, "%x:%x", s->remote.data, (unsigned*)&s->rport);
1591 s->local.bytelen = s->remote.bytelen = 4;
1592 return 0;
1593 } else {
1594 sscanf(loc, "%08x%08x%08x%08x:%x",
1595 s->local.data,
1596 s->local.data + 1,
1597 s->local.data + 2,
1598 s->local.data + 3,
1599 &s->lport);
1600 sscanf(rem, "%08x%08x%08x%08x:%x",
1601 s->remote.data,
1602 s->remote.data + 1,
1603 s->remote.data + 2,
1604 s->remote.data + 3,
1605 &s->rport);
1606 s->local.bytelen = s->remote.bytelen = 16;
1607 return 0;
1608 }
1609 return -1;
1610}
1611
1612static int proc_inet_split_line(char *line, char **loc, char **rem, char **data)
aba5acdf 1613{
aba5acdf 1614 char *p;
ae665a52 1615
aba5acdf
SH
1616 if ((p = strchr(line, ':')) == NULL)
1617 return -1;
ae665a52 1618
8250bc9f
VK
1619 *loc = p+2;
1620 if ((p = strchr(*loc, ':')) == NULL)
aba5acdf 1621 return -1;
ae665a52 1622
8250bc9f
VK
1623 p[5] = 0;
1624 *rem = p+6;
1625 if ((p = strchr(*rem, ':')) == NULL)
aba5acdf 1626 return -1;
8250bc9f 1627
aba5acdf 1628 p[5] = 0;
8250bc9f
VK
1629 *data = p+6;
1630 return 0;
1631}
ae665a52 1632
8250bc9f
VK
1633static char *sprint_bw(char *buf, double bw)
1634{
1635 if (bw > 1000000.)
1636 sprintf(buf,"%.1fM", bw / 1000000.);
1637 else if (bw > 1000.)
1638 sprintf(buf,"%.1fK", bw / 1000.);
1639 else
1640 sprintf(buf, "%g", bw);
aba5acdf 1641
8250bc9f
VK
1642 return buf;
1643}
ae665a52 1644
8250bc9f
VK
1645static void tcp_stats_print(struct tcpstat *s)
1646{
1647 char b1[64];
1648
1649 if (s->has_ts_opt)
1650 printf(" ts");
1651 if (s->has_sack_opt)
1652 printf(" sack");
1653 if (s->has_ecn_opt)
1654 printf(" ecn");
1655 if (s->has_ecnseen_opt)
1656 printf(" ecnseen");
1657 if (s->has_fastopen_opt)
1658 printf(" fastopen");
1659 if (s->cong_alg)
1660 printf(" %s", s->cong_alg);
1661 if (s->has_wscale_opt)
1662 printf(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
1663 if (s->rto)
1664 printf(" rto:%g", s->rto);
1665 if (s->backoff)
1666 printf(" backoff:%u", s->backoff);
1667 if (s->rtt)
1668 printf(" rtt:%g/%g", s->rtt, s->rttvar);
1669 if (s->ato)
1670 printf(" ato:%g", s->ato);
1671
1672 if (s->qack)
1673 printf(" qack:%d", s->qack);
1674 if (s->qack & 1)
1675 printf(" bidir");
1676
1677 if (s->mss)
1678 printf(" mss:%d", s->mss);
1679 if (s->cwnd && s->cwnd != 2)
1680 printf(" cwnd:%d", s->cwnd);
1681 if (s->ssthresh)
1682 printf(" ssthresh:%d", s->ssthresh);
1683
1684 if (s->dctcp && s->dctcp->enabled) {
1685 struct dctcpstat *dctcp = s->dctcp;
1686
b5024ee1 1687 printf("dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
8250bc9f
VK
1688 dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
1689 dctcp->ab_tot);
1690 } else if (s->dctcp) {
b5024ee1 1691 printf("dctcp:fallback_mode");
8250bc9f
VK
1692 }
1693
1694 if (s->send_bps)
1695 printf(" send %sbps", sprint_bw(b1, s->send_bps));
1696 if (s->lastsnd)
1697 printf(" lastsnd:%u", s->lastsnd);
1698 if (s->lastrcv)
1699 printf(" lastrcv:%u", s->lastrcv);
1700 if (s->lastack)
1701 printf(" lastack:%u", s->lastack);
1702
1703 if (s->pacing_rate) {
1704 printf(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
1705 if (s->pacing_rate_max)
1706 printf("/%sbps", sprint_bw(b1,
1707 s->pacing_rate_max));
1708 }
1709
1710 if (s->unacked)
1711 printf(" unacked:%u", s->unacked);
1712 if (s->retrans || s->retrans_total)
1713 printf(" retrans:%u/%u", s->retrans, s->retrans_total);
1714 if (s->lost)
1715 printf(" lost:%u", s->lost);
055840f2 1716 if (s->sacked && s->ss.state != SS_LISTEN)
8250bc9f
VK
1717 printf(" sacked:%u", s->sacked);
1718 if (s->fackets)
1719 printf(" fackets:%u", s->fackets);
1720 if (s->reordering != 3)
1721 printf(" reordering:%d", s->reordering);
1722 if (s->rcv_rtt)
1723 printf(" rcv_rtt:%g", s->rcv_rtt);
1724 if (s->rcv_space)
1725 printf(" rcv_space:%d", s->rcv_space);
1726}
1727
055840f2
VK
1728static void tcp_timer_print(struct tcpstat *s)
1729{
1730 if (s->timer) {
1731 if (s->timer > 4)
1732 s->timer = 5;
1733 printf(" timer:(%s,%s,%d)",
1734 tmr_name[s->timer],
1735 print_ms_timer(s->timeout),
1736 s->retrans);
1737 }
1738}
1739
8250bc9f
VK
1740static int tcp_show_line(char *line, const struct filter *f, int family)
1741{
1742 int rto = 0, ato = 0;
1743 struct tcpstat s = {};
1744 char *loc, *rem, *data;
1745 char opt[256];
1746 int n;
1747 int hz = get_user_hz();
1748
1749 if (proc_inet_split_line(line, &loc, &rem, &data))
1750 return -1;
1751
1752 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
1753 if (!(f->states & (1 << state)))
1754 return 0;
1755
055840f2 1756 proc_parse_inet_addr(loc, rem, family, &s.ss);
ae665a52 1757
055840f2 1758 if (f->f && run_ssfilter(f->f, &s.ss) == 0)
aba5acdf 1759 return 0;
ae665a52 1760
aba5acdf 1761 opt[0] = 0;
e7113c61 1762 n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n",
055840f2
VK
1763 &s.ss.state, &s.ss.wq, &s.ss.rq,
1764 &s.timer, &s.timeout, &s.retrans, &s.ss.uid, &s.probes,
1765 &s.ss.ino, &s.ss.refcnt, &s.ss.sk, &rto, &ato, &s.qack, &s.cwnd,
1766 &s.ssthresh, opt);
ae665a52 1767
aba5acdf
SH
1768 if (n < 17)
1769 opt[0] = 0;
ae665a52 1770
aba5acdf 1771 if (n < 12) {
8250bc9f 1772 rto = 0;
aba5acdf
SH
1773 s.cwnd = 2;
1774 s.ssthresh = -1;
8250bc9f 1775 ato = s.qack = 0;
aba5acdf 1776 }
ae665a52 1777
8250bc9f
VK
1778 s.retrans = s.timer != 1 ? s.probes : s.retrans;
1779 s.timeout = (s.timeout * 1000 + hz - 1) / hz;
1780 s.ato = (double)ato / hz;
1781 s.qack /= 2;
1782 s.rto = (double)rto;
1783 s.ssthresh = s.ssthresh == -1 ? 0 : s.ssthresh;
1784 s.rto = s.rto != 3 * hz ? s.rto / hz : 0;
ae665a52 1785
055840f2
VK
1786 inet_stats_print(&s.ss, IPPROTO_TCP);
1787
1788 if (show_options)
1789 tcp_timer_print(&s);
116ac927 1790
aba5acdf 1791 if (show_details) {
f1b39e1b 1792 sock_details_print(&s.ss);
aba5acdf
SH
1793 if (opt[0])
1794 printf(" opt:\"%s\"", opt);
1795 }
aba5acdf 1796
8250bc9f
VK
1797 if (show_tcpinfo)
1798 tcp_stats_print(&s);
1799
1800 printf("\n");
aba5acdf
SH
1801 return 0;
1802}
1803
ab01dbbb
SH
1804static int generic_record_read(FILE *fp,
1805 int (*worker)(char*, const struct filter *, int),
1806 const struct filter *f, int fam)
aba5acdf 1807{
ab01dbbb 1808 char line[256];
aba5acdf 1809
ab01dbbb
SH
1810 /* skip header */
1811 if (fgets(line, sizeof(line), fp) == NULL)
aba5acdf 1812 goto outerr;
ab01dbbb
SH
1813
1814 while (fgets(line, sizeof(line), fp) != NULL) {
1815 int n = strlen(line);
1816 if (n == 0 || line[n-1] != '\n') {
1817 errno = -EINVAL;
1818 return -1;
aba5acdf 1819 }
ab01dbbb 1820 line[n-1] = 0;
aba5acdf 1821
ab01dbbb
SH
1822 if (worker(line, f, fam) < 0)
1823 return 0;
1824 }
aba5acdf 1825outerr:
ab01dbbb
SH
1826
1827 return ferror(fp) ? -1 : 0;
aba5acdf 1828}
ae665a52 1829
51ff9f24
HFS
1830static void print_skmeminfo(struct rtattr *tb[], int attrtype)
1831{
1832 const __u32 *skmeminfo;
db08bdb8
VK
1833
1834 if (!tb[attrtype]) {
1835 if (attrtype == INET_DIAG_SKMEMINFO) {
1836 if (!tb[INET_DIAG_MEMINFO])
1837 return;
1838
1839 const struct inet_diag_meminfo *minfo =
1840 RTA_DATA(tb[INET_DIAG_MEMINFO]);
1841
1842 printf(" mem:(r%u,w%u,f%u,t%u)",
1843 minfo->idiag_rmem,
1844 minfo->idiag_wmem,
1845 minfo->idiag_fmem,
1846 minfo->idiag_tmem);
1847 }
51ff9f24 1848 return;
db08bdb8
VK
1849 }
1850
51ff9f24
HFS
1851 skmeminfo = RTA_DATA(tb[attrtype]);
1852
1853 printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
1854 skmeminfo[SK_MEMINFO_RMEM_ALLOC],
1855 skmeminfo[SK_MEMINFO_RCVBUF],
1856 skmeminfo[SK_MEMINFO_WMEM_ALLOC],
1857 skmeminfo[SK_MEMINFO_SNDBUF],
1858 skmeminfo[SK_MEMINFO_FWD_ALLOC],
1859 skmeminfo[SK_MEMINFO_WMEM_QUEUED],
1860 skmeminfo[SK_MEMINFO_OPTMEM]);
1861
1862 if (RTA_PAYLOAD(tb[attrtype]) >=
1863 (SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
1864 printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
1865
1866 printf(")");
1867}
1868
8250bc9f
VK
1869#define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
1870
5b816047
PE
1871static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
1872 struct rtattr *tb[])
7d105b56 1873{
b4b0b7d5 1874 double rtt = 0;
8250bc9f 1875 struct tcpstat s = {};
7d105b56 1876
055840f2
VK
1877 s.ss.state = r->idiag_state;
1878
db08bdb8 1879 print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
7d105b56 1880
351efcde 1881 if (tb[INET_DIAG_INFO]) {
05e18118 1882 struct tcp_info *info;
351efcde 1883 int len = RTA_PAYLOAD(tb[INET_DIAG_INFO]);
05e18118
SH
1884
1885 /* workaround for older kernels with less fields */
1886 if (len < sizeof(*info)) {
1887 info = alloca(sizeof(*info));
1888 memset(info, 0, sizeof(*info));
351efcde 1889 memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len);
05e18118 1890 } else
351efcde 1891 info = RTA_DATA(tb[INET_DIAG_INFO]);
05e18118 1892
b4b0b7d5 1893 if (show_options) {
8250bc9f
VK
1894 s.has_ts_opt = TCPI_HAS_OPT(info, TCPI_OPT_TIMESTAMPS);
1895 s.has_sack_opt = TCPI_HAS_OPT(info, TCPI_OPT_SACK);
1896 s.has_ecn_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN);
1897 s.has_ecnseen_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN);
1898 s.has_fastopen_opt = TCPI_HAS_OPT(info, TCPI_OPT_SYN_DATA);
b4b0b7d5 1899 }
52d5ac3f 1900
8250bc9f
VK
1901 if (tb[INET_DIAG_CONG]) {
1902 const char *cong_attr = rta_getattr_str(tb[INET_DIAG_CONG]);
1903 s.cong_alg = malloc(strlen(cong_attr + 1));
1904 strcpy(s.cong_alg, cong_attr);
1905 }
1906
1907 if (TCPI_HAS_OPT(info, TCPI_OPT_WSCALE)) {
1908 s.has_wscale_opt = true;
1909 s.snd_wscale = info->tcpi_snd_wscale;
1910 s.rcv_wscale = info->tcpi_rcv_wscale;
1911 }
ea8fc104 1912
7d105b56 1913 if (info->tcpi_rto && info->tcpi_rto != 3000000)
8250bc9f
VK
1914 s.rto = (double)info->tcpi_rto / 1000;
1915
1916 s.backoff = info->tcpi_backoff;
1917 s.rtt = (double)info->tcpi_rtt / 1000;
1918 s.rttvar = (double)info->tcpi_rttvar / 1000;
11ba90fc 1919 s.ato = (double)info->tcpi_ato / 1000;
8250bc9f
VK
1920 s.mss = info->tcpi_snd_mss;
1921 s.rcv_space = info->tcpi_rcv_space;
1922 s.rcv_rtt = (double)info->tcpi_rcv_rtt / 1000;
1923 s.lastsnd = info->tcpi_last_data_sent;
1924 s.lastrcv = info->tcpi_last_data_recv;
1925 s.lastack = info->tcpi_last_ack_recv;
1926 s.unacked = info->tcpi_unacked;
1927 s.retrans = info->tcpi_retrans;
1928 s.retrans_total = info->tcpi_total_retrans;
1929 s.lost = info->tcpi_lost;
1930 s.sacked = info->tcpi_sacked;
1931 s.reordering = info->tcpi_reordering;
1932 s.rcv_space = info->tcpi_rcv_space;
1933 s.cwnd = info->tcpi_snd_cwnd;
1934
7d105b56 1935 if (info->tcpi_snd_ssthresh < 0xFFFF)
8250bc9f 1936 s.ssthresh = info->tcpi_snd_ssthresh;
52d5ac3f 1937
b4b0b7d5 1938 rtt = (double) info->tcpi_rtt;
351efcde 1939 if (tb[INET_DIAG_VEGASINFO]) {
05e18118 1940 const struct tcpvegas_info *vinfo
351efcde 1941 = RTA_DATA(tb[INET_DIAG_VEGASINFO]);
7d105b56 1942
ae665a52 1943 if (vinfo->tcpv_enabled &&
8250bc9f 1944 vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
ea8fc104 1945 rtt = vinfo->tcpv_rtt;
b4b0b7d5
SH
1946 }
1947
907e1aca 1948 if (tb[INET_DIAG_DCTCPINFO]) {
8250bc9f
VK
1949 struct dctcpstat *dctcp = malloc(sizeof(struct
1950 dctcpstat));
1951
907e1aca
DB
1952 const struct tcp_dctcp_info *dinfo
1953 = RTA_DATA(tb[INET_DIAG_DCTCPINFO]);
1954
8250bc9f
VK
1955 dctcp->enabled = !!dinfo->dctcp_enabled;
1956 dctcp->ce_state = dinfo->dctcp_ce_state;
1957 dctcp->alpha = dinfo->dctcp_alpha;
1958 dctcp->ab_ecn = dinfo->dctcp_ab_ecn;
1959 dctcp->ab_tot = dinfo->dctcp_ab_tot;
1960 s.dctcp = dctcp;
907e1aca
DB
1961 }
1962
b4b0b7d5 1963 if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
8250bc9f
VK
1964 s.send_bps = (double) info->tcpi_snd_cwnd *
1965 (double)info->tcpi_snd_mss * 8000000. / rtt;
7d105b56 1966 }
b4b0b7d5 1967
eb6028b2 1968 if (info->tcpi_pacing_rate &&
8250bc9f
VK
1969 info->tcpi_pacing_rate != ~0ULL) {
1970 s.pacing_rate = info->tcpi_pacing_rate * 8.;
eb6028b2
ED
1971
1972 if (info->tcpi_max_pacing_rate &&
8250bc9f
VK
1973 info->tcpi_max_pacing_rate != ~0ULL)
1974 s.pacing_rate_max = info->tcpi_max_pacing_rate * 8.;
eb6028b2 1975 }
8250bc9f
VK
1976 tcp_stats_print(&s);
1977 if (s.dctcp)
1978 free(s.dctcp);
1979 if (s.cong_alg)
1980 free(s.cong_alg);
77a8ca81 1981 }
77a8ca81
PE
1982}
1983
1984static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
aba5acdf 1985{
5b816047 1986 struct rtattr * tb[INET_DIAG_MAX+1];
351efcde 1987 struct inet_diag_msg *r = NLMSG_DATA(nlh);
055840f2 1988 struct sockstat s = {};
aba5acdf 1989
5b816047
PE
1990 parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr*)(r+1),
1991 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
1992
f1b39e1b
VK
1993 s.state = r->idiag_state;
1994 s.local.family = s.remote.family = r->idiag_family;
1995 s.lport = ntohs(r->id.idiag_sport);
1996 s.rport = ntohs(r->id.idiag_dport);
1997 s.wq = r->idiag_wqueue;
1998 s.rq = r->idiag_rqueue;
1999 s.ino = r->idiag_inode;
2000 s.uid = r->idiag_uid;
2001 s.iface = r->id.idiag_if;
2002 s.sk = cookie_sk_get(&r->id.idiag_cookie[0]);
8250bc9f 2003
aba5acdf
SH
2004 if (s.local.family == AF_INET) {
2005 s.local.bytelen = s.remote.bytelen = 4;
2006 } else {
2007 s.local.bytelen = s.remote.bytelen = 16;
2008 }
8250bc9f 2009
351efcde
SH
2010 memcpy(s.local.data, r->id.idiag_src, s.local.bytelen);
2011 memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen);
aba5acdf
SH
2012
2013 if (f && f->f && run_ssfilter(f->f, &s) == 0)
2014 return 0;
2015
8250bc9f 2016 inet_stats_print(&s, protocol);
116ac927 2017
055840f2
VK
2018 if (show_options) {
2019 struct tcpstat t = {};
2020
2021 t.timer = r->idiag_timer;
2022 t.timeout = r->idiag_expires;
2023 t.retrans = r->idiag_retrans;
2024 tcp_timer_print(&t);
2025 }
2026
aba5acdf 2027 if (show_details) {
f1b39e1b 2028 sock_details_print(&s);
5b816047
PE
2029 if (tb[INET_DIAG_SHUTDOWN]) {
2030 unsigned char mask;
2031 mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
2032 printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
2033 }
aba5acdf 2034 }
8250bc9f 2035
aba5acdf 2036 if (show_mem || show_tcpinfo) {
7d105b56 2037 printf("\n\t");
5b816047 2038 tcp_show_info(nlh, r, tb);
aba5acdf 2039 }
7d105b56 2040
aba5acdf 2041 printf("\n");
aba5acdf 2042 return 0;
aba5acdf
SH
2043}
2044
746a695f 2045static int tcpdiag_send(int fd, int protocol, struct filter *f)
aba5acdf 2046{
aba5acdf
SH
2047 struct sockaddr_nl nladdr;
2048 struct {
2049 struct nlmsghdr nlh;
351efcde 2050 struct inet_diag_req r;
aba5acdf
SH
2051 } req;
2052 char *bc = NULL;
2053 int bclen;
2054 struct msghdr msg;
2055 struct rtattr rta;
aba5acdf
SH
2056 struct iovec iov[3];
2057
346f8ca8
PE
2058 if (protocol == IPPROTO_UDP)
2059 return -1;
2060
aba5acdf
SH
2061 memset(&nladdr, 0, sizeof(nladdr));
2062 nladdr.nl_family = AF_NETLINK;
2063
2064 req.nlh.nlmsg_len = sizeof(req);
3fe5b534
PE
2065 if (protocol == IPPROTO_TCP)
2066 req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
2067 else
2068 req.nlh.nlmsg_type = DCCPDIAG_GETSOCK;
aba5acdf
SH
2069 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
2070 req.nlh.nlmsg_pid = 0;
8a4025f6 2071 req.nlh.nlmsg_seq = MAGIC_SEQ;
aba5acdf 2072 memset(&req.r, 0, sizeof(req.r));
351efcde
SH
2073 req.r.idiag_family = AF_INET;
2074 req.r.idiag_states = f->states;
910b0397 2075 if (show_mem) {
ae665a52 2076 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
910b0397
SW
2077 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
2078 }
b4b0b7d5 2079
7d105b56 2080 if (show_tcpinfo) {
351efcde
SH
2081 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
2082 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
2083 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
7d105b56 2084 }
aba5acdf 2085
ae665a52
SH
2086 iov[0] = (struct iovec){
2087 .iov_base = &req,
2088 .iov_len = sizeof(req)
ea8fc104 2089 };
aba5acdf
SH
2090 if (f->f) {
2091 bclen = ssfilter_bytecompile(f->f, &bc);
351efcde 2092 rta.rta_type = INET_DIAG_REQ_BYTECODE;
aba5acdf
SH
2093 rta.rta_len = RTA_LENGTH(bclen);
2094 iov[1] = (struct iovec){ &rta, sizeof(rta) };
2095 iov[2] = (struct iovec){ bc, bclen };
2096 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
2097 }
2098
2099 msg = (struct msghdr) {
ae665a52 2100 .msg_name = (void*)&nladdr,
ea8fc104 2101 .msg_namelen = sizeof(nladdr),
ae665a52 2102 .msg_iov = iov,
ea8fc104 2103 .msg_iovlen = f->f ? 3 : 1,
aba5acdf
SH
2104 };
2105
930a75f9
ED
2106 if (sendmsg(fd, &msg, 0) < 0) {
2107 close(fd);
aba5acdf 2108 return -1;
930a75f9 2109 }
aba5acdf 2110
746a695f
PE
2111 return 0;
2112}
2113
886d19d6
PE
2114static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
2115{
2116 struct sockaddr_nl nladdr;
5fb421d4 2117 DIAG_REQUEST(req, struct inet_diag_req_v2 r);
886d19d6
PE
2118 char *bc = NULL;
2119 int bclen;
2120 struct msghdr msg;
2121 struct rtattr rta;
2122 struct iovec iov[3];
2123
2124 if (family == PF_UNSPEC)
2125 return tcpdiag_send(fd, protocol, f);
2126
2127 memset(&nladdr, 0, sizeof(nladdr));
2128 nladdr.nl_family = AF_NETLINK;
2129
886d19d6
PE
2130 memset(&req.r, 0, sizeof(req.r));
2131 req.r.sdiag_family = family;
2132 req.r.sdiag_protocol = protocol;
2133 req.r.idiag_states = f->states;
2134 if (show_mem) {
2135 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
2136 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
2137 }
2138
2139 if (show_tcpinfo) {
2140 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
2141 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
2142 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
2143 }
2144
2145 iov[0] = (struct iovec){
2146 .iov_base = &req,
2147 .iov_len = sizeof(req)
2148 };
2149 if (f->f) {
2150 bclen = ssfilter_bytecompile(f->f, &bc);
2151 rta.rta_type = INET_DIAG_REQ_BYTECODE;
2152 rta.rta_len = RTA_LENGTH(bclen);
2153 iov[1] = (struct iovec){ &rta, sizeof(rta) };
2154 iov[2] = (struct iovec){ bc, bclen };
2155 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
2156 }
2157
2158 msg = (struct msghdr) {
2159 .msg_name = (void*)&nladdr,
2160 .msg_namelen = sizeof(nladdr),
2161 .msg_iov = iov,
2162 .msg_iovlen = f->f ? 3 : 1,
2163 };
2164
2165 if (sendmsg(fd, &msg, 0) < 0) {
2166 close(fd);
2167 return -1;
2168 }
2169
2170 return 0;
2171}
2172
486ccd99
VK
2173struct inet_diag_arg {
2174 struct filter *f;
2175 int protocol;
2176};
aba5acdf 2177
486ccd99
VK
2178static int show_one_inet_sock(const struct sockaddr_nl *addr,
2179 struct nlmsghdr *h, void *arg)
2180{
2181 int err;
2182 struct inet_diag_arg *diag_arg = arg;
2183 struct inet_diag_msg *r = NLMSG_DATA(h);
aba5acdf 2184
486ccd99
VK
2185 if (!(diag_arg->f->families & (1 << r->idiag_family)))
2186 return 0;
2187 if ((err = inet_show_sock(h, NULL, diag_arg->protocol)) < 0)
2188 return err;
aba5acdf 2189
486ccd99
VK
2190 return 0;
2191}
886d19d6 2192
486ccd99
VK
2193static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)
2194{
2195 int err = 0;
2196 struct rtnl_handle rth;
2197 int family = PF_INET;
2198 struct inet_diag_arg arg = { .f = f, .protocol = protocol };
886d19d6 2199
486ccd99
VK
2200 if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
2201 return -1;
2202 rth.dump = MAGIC_SEQ;
2203 rth.dump_fp = dump_fp;
886d19d6 2204
486ccd99
VK
2205again:
2206 if ((err = sockdiag_send(family, rth.fd, protocol, f)))
2207 goto Exit;
aba5acdf 2208
486ccd99
VK
2209 if ((err = rtnl_dump_filter(&rth, show_one_inet_sock, &arg))) {
2210 if (family != PF_UNSPEC) {
2211 family = PF_UNSPEC;
2212 goto again;
aba5acdf 2213 }
486ccd99 2214 goto Exit;
aba5acdf 2215 }
886d19d6
PE
2216 if (family == PF_INET) {
2217 family = PF_INET6;
2218 goto again;
2219 }
2220
486ccd99
VK
2221Exit:
2222 rtnl_close(&rth);
2223 return err;
aba5acdf
SH
2224}
2225
ab01dbbb 2226static int tcp_show_netlink_file(struct filter *f)
aba5acdf
SH
2227{
2228 FILE *fp;
e557212e 2229 char buf[16384];
aba5acdf
SH
2230
2231 if ((fp = fopen(getenv("TCPDIAG_FILE"), "r")) == NULL) {
2232 perror("fopen($TCPDIAG_FILE)");
2233 return -1;
2234 }
2235
2236 while (1) {
2237 int status, err;
2238 struct nlmsghdr *h = (struct nlmsghdr*)buf;
2239
2240 status = fread(buf, 1, sizeof(*h), fp);
2241 if (status < 0) {
2242 perror("Reading header from $TCPDIAG_FILE");
2243 return -1;
2244 }
2245 if (status != sizeof(*h)) {
2246 perror("Unexpected EOF reading $TCPDIAG_FILE");
2247 return -1;
2248 }
2249
2250 status = fread(h+1, 1, NLMSG_ALIGN(h->nlmsg_len-sizeof(*h)), fp);
2251
2252 if (status < 0) {
2253 perror("Reading $TCPDIAG_FILE");
2254 return -1;
2255 }
2256 if (status + sizeof(*h) < h->nlmsg_len) {
2257 perror("Unexpected EOF reading $TCPDIAG_FILE");
2258 return -1;
2259 }
2260
2261 /* The only legal exit point */
2262 if (h->nlmsg_type == NLMSG_DONE)
2263 return 0;
2264
2265 if (h->nlmsg_type == NLMSG_ERROR) {
2266 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
2267 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
2268 fprintf(stderr, "ERROR truncated\n");
2269 } else {
2270 errno = -err->error;
2271 perror("TCPDIAG answered");
2272 }
2273 return -1;
2274 }
2275
77a8ca81 2276 err = inet_show_sock(h, f, IPPROTO_TCP);
aba5acdf
SH
2277 if (err < 0)
2278 return err;
2279 }
2280}
2281
ab01dbbb 2282static int tcp_show(struct filter *f, int socktype)
aba5acdf 2283{
ab01dbbb 2284 FILE *fp = NULL;
aba5acdf
SH
2285 char *buf = NULL;
2286 int bufsize = 64*1024;
2287
1527a17e
VK
2288 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
2289 return 0;
2290
aba5acdf
SH
2291 dg_proto = TCP_PROTO;
2292
2293 if (getenv("TCPDIAG_FILE"))
2294 return tcp_show_netlink_file(f);
2295
2296 if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT")
3fe5b534 2297 && inet_show_netlink(f, NULL, socktype) == 0)
aba5acdf
SH
2298 return 0;
2299
2300 /* Sigh... We have to parse /proc/net/tcp... */
2301
ab01dbbb 2302
aba5acdf
SH
2303 /* Estimate amount of sockets and try to allocate
2304 * huge buffer to read all the table at one read.
2305 * Limit it by 16MB though. The assumption is: as soon as
2306 * kernel was able to hold information about N connections,
2307 * it is able to give us some memory for snapshot.
2308 */
2309 if (1) {
a221d621
BL
2310 get_slabstat(&slabstat);
2311
aba5acdf
SH
2312 int guess = slabstat.socks+slabstat.tcp_syns;
2313 if (f->states&(1<<SS_TIME_WAIT))
2314 guess += slabstat.tcp_tws;
2315 if (guess > (16*1024*1024)/128)
2316 guess = (16*1024*1024)/128;
2317 guess *= 128;
2318 if (guess > bufsize)
2319 bufsize = guess;
2320 }
2321 while (bufsize >= 64*1024) {
2322 if ((buf = malloc(bufsize)) != NULL)
2323 break;
2324 bufsize /= 2;
2325 }
2326 if (buf == NULL) {
2327 errno = ENOMEM;
2328 return -1;
2329 }
2330
2331 if (f->families & (1<<AF_INET)) {
69cae645 2332 if ((fp = net_tcp_open()) == NULL)
aba5acdf 2333 goto outerr;
ab01dbbb
SH
2334
2335 setbuffer(fp, buf, bufsize);
2336 if (generic_record_read(fp, tcp_show_line, f, AF_INET))
aba5acdf 2337 goto outerr;
ab01dbbb 2338 fclose(fp);
aba5acdf
SH
2339 }
2340
2341 if ((f->families & (1<<AF_INET6)) &&
69cae645 2342 (fp = net_tcp6_open()) != NULL) {
ab01dbbb
SH
2343 setbuffer(fp, buf, bufsize);
2344 if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
aba5acdf 2345 goto outerr;
ab01dbbb 2346 fclose(fp);
aba5acdf
SH
2347 }
2348
2349 free(buf);
2350 return 0;
2351
2352outerr:
2353 do {
2354 int saved_errno = errno;
2355 if (buf)
2356 free(buf);
ab01dbbb
SH
2357 if (fp)
2358 fclose(fp);
aba5acdf
SH
2359 errno = saved_errno;
2360 return -1;
2361 } while (0);
2362}
2363
2364
d1f28cf1 2365static int dgram_show_line(char *line, const struct filter *f, int family)
aba5acdf 2366{
055840f2 2367 struct sockstat s = {};
aba5acdf
SH
2368 char *loc, *rem, *data;
2369 char opt[256];
2370 int n;
aba5acdf 2371
8250bc9f 2372 if (proc_inet_split_line(line, &loc, &rem, &data))
aba5acdf 2373 return -1;
aba5acdf 2374
8250bc9f
VK
2375 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
2376 if (!(f->states & (1 << state)))
2377 return 0;
aba5acdf 2378
8250bc9f 2379 proc_parse_inet_addr(loc, rem, family, &s);
aba5acdf
SH
2380
2381 if (f->f && run_ssfilter(f->f, &s) == 0)
2382 return 0;
2383
2384 opt[0] = 0;
e7113c61 2385 n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
aba5acdf
SH
2386 &s.state, &s.wq, &s.rq,
2387 &s.uid, &s.ino,
2388 &s.refcnt, &s.sk, opt);
2389
2390 if (n < 9)
2391 opt[0] = 0;
2392
8250bc9f 2393 inet_stats_print(&s, IPPROTO_UDP);
aba5acdf 2394
f1b39e1b
VK
2395 if (show_details && opt[0])
2396 printf(" opt:\"%s\"", opt);
aba5acdf 2397
8250bc9f 2398 printf("\n");
aba5acdf
SH
2399 return 0;
2400}
2401
d1f28cf1 2402static int udp_show(struct filter *f)
aba5acdf 2403{
ab01dbbb 2404 FILE *fp = NULL;
aba5acdf 2405
1527a17e
VK
2406 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
2407 return 0;
2408
ace5cb31
VK
2409 dg_proto = UDP_PROTO;
2410
346f8ca8
PE
2411 if (!getenv("PROC_NET_UDP") && !getenv("PROC_ROOT")
2412 && inet_show_netlink(f, NULL, IPPROTO_UDP) == 0)
2413 return 0;
2414
aba5acdf 2415 if (f->families&(1<<AF_INET)) {
69cae645 2416 if ((fp = net_udp_open()) == NULL)
aba5acdf 2417 goto outerr;
ab01dbbb 2418 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
aba5acdf 2419 goto outerr;
ab01dbbb 2420 fclose(fp);
aba5acdf
SH
2421 }
2422
2423 if ((f->families&(1<<AF_INET6)) &&
69cae645 2424 (fp = net_udp6_open()) != NULL) {
ab01dbbb 2425 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
aba5acdf 2426 goto outerr;
ab01dbbb 2427 fclose(fp);
aba5acdf
SH
2428 }
2429 return 0;
2430
2431outerr:
2432 do {
2433 int saved_errno = errno;
ab01dbbb
SH
2434 if (fp)
2435 fclose(fp);
aba5acdf
SH
2436 errno = saved_errno;
2437 return -1;
2438 } while (0);
2439}
2440
d1f28cf1 2441static int raw_show(struct filter *f)
aba5acdf 2442{
ab01dbbb 2443 FILE *fp = NULL;
aba5acdf 2444
1527a17e
VK
2445 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
2446 return 0;
2447
aba5acdf
SH
2448 dg_proto = RAW_PROTO;
2449
2450 if (f->families&(1<<AF_INET)) {
69cae645 2451 if ((fp = net_raw_open()) == NULL)
aba5acdf 2452 goto outerr;
ab01dbbb 2453 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
aba5acdf 2454 goto outerr;
ab01dbbb 2455 fclose(fp);
aba5acdf
SH
2456 }
2457
2458 if ((f->families&(1<<AF_INET6)) &&
69cae645 2459 (fp = net_raw6_open()) != NULL) {
ab01dbbb 2460 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
aba5acdf 2461 goto outerr;
ab01dbbb 2462 fclose(fp);
aba5acdf
SH
2463 }
2464 return 0;
2465
2466outerr:
2467 do {
2468 int saved_errno = errno;
ab01dbbb
SH
2469 if (fp)
2470 fclose(fp);
aba5acdf
SH
2471 errno = saved_errno;
2472 return -1;
2473 } while (0);
2474}
2475
aba5acdf
SH
2476int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
2477 SS_ESTABLISHED, SS_CLOSING };
2478
ec4d0d8a 2479#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct sockstat))
aba5acdf 2480
ec4d0d8a 2481static void unix_list_free(struct sockstat *list)
aba5acdf
SH
2482{
2483 while (list) {
ec4d0d8a
VK
2484 struct sockstat *s = list;
2485 char *name = sock_addr_get_str(&s->local);
2486
aba5acdf 2487 list = list->next;
ec4d0d8a
VK
2488
2489 if (name)
2490 free(name);
aba5acdf
SH
2491 free(s);
2492 }
2493}
2494
30b669d7
MY
2495static const char *unix_netid_name(int type)
2496{
2497 const char *netid;
2498
2499 switch (type) {
2500 case SOCK_STREAM:
2501 netid = "u_str";
2502 break;
2503 case SOCK_SEQPACKET:
2504 netid = "u_seq";
2505 break;
2506 case SOCK_DGRAM:
2507 default:
2508 netid = "u_dgr";
2509 break;
2510 }
2511 return netid;
2512}
2513
ec4d0d8a 2514static bool unix_type_skip(struct sockstat *s, struct filter *f)
bf4ceee6
VK
2515{
2516 if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
2517 return true;
2518 if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
2519 return true;
2520 if (s->type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
2521 return true;
2522 return false;
2523}
2524
ec4d0d8a
VK
2525static bool unix_use_proc(void)
2526{
2527 return getenv("PROC_NET_UNIX") || getenv("PROC_ROOT");
2528}
2529
2530static void unix_stats_print(struct sockstat *list, struct filter *f)
aba5acdf 2531{
ec4d0d8a
VK
2532 struct sockstat *s;
2533 char *local, *peer;
b217df10 2534 char *ctx_buf = NULL;
ec4d0d8a 2535 bool use_proc = unix_use_proc();
b217df10 2536 char port_name[30] = {};
aba5acdf
SH
2537
2538 for (s = list; s; s = s->next) {
ec4d0d8a 2539 if (!(f->states & (1 << s->state)))
aba5acdf 2540 continue;
bf4ceee6 2541 if (unix_type_skip(s, f))
30b669d7 2542 continue;
aba5acdf 2543
ec4d0d8a
VK
2544 local = sock_addr_get_str(&s->local);
2545 peer = "*";
2546
2547 if (s->rport && use_proc) {
2548 struct sockstat *p;
bf4ceee6 2549
aba5acdf 2550 for (p = list; p; p = p->next) {
ec4d0d8a 2551 if (s->rport == p->lport)
aba5acdf
SH
2552 break;
2553 }
ec4d0d8a 2554
aba5acdf
SH
2555 if (!p) {
2556 peer = "?";
2557 } else {
ec4d0d8a
VK
2558 peer = sock_addr_get_str(&p->local);
2559 peer = peer ? : "*";
aba5acdf
SH
2560 }
2561 }
2562
29999b0f 2563 if (use_proc && f->f) {
aba5acdf 2564 if (strcmp(peer, "*") == 0)
ec4d0d8a 2565 memset(s->remote.data, 0, sizeof(char *));
aba5acdf 2566 else
ec4d0d8a
VK
2567 sock_addr_set_str(&s->remote, &peer);
2568
2569 if (run_ssfilter(f->f, s) == 0)
aba5acdf
SH
2570 continue;
2571 }
2572
2d791bc8
VK
2573 sock_state_print(s, unix_netid_name(s->type));
2574
b217df10
VK
2575 sock_addr_print(local ?: "*", " ",
2576 int_to_str(s->lport, port_name), NULL);
2577 sock_addr_print(peer, " ", int_to_str(s->rport, port_name),
2578 NULL);
116ac927
RH
2579
2580 if (show_proc_ctx || show_sock_ctx) {
b217df10 2581 if (find_entry(s->ino, &ctx_buf,
116ac927
RH
2582 (show_proc_ctx & show_sock_ctx) ?
2583 PROC_SOCK_CTX : PROC_CTX) > 0) {
b217df10
VK
2584 printf(" users:(%s)", ctx_buf);
2585 free(ctx_buf);
116ac927
RH
2586 }
2587 } else if (show_users) {
b217df10
VK
2588 if (find_entry(s->ino, &ctx_buf, USERS) > 0) {
2589 printf(" users:(%s)", ctx_buf);
2590 free(ctx_buf);
116ac927 2591 }
aba5acdf
SH
2592 }
2593 printf("\n");
2594 }
2595}
2596
8a4025f6 2597static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
2598 void *arg)
dfbaa90d 2599{
8a4025f6 2600 struct filter *f = (struct filter *)arg;
dfbaa90d
PE
2601 struct unix_diag_msg *r = NLMSG_DATA(nlh);
2602 struct rtattr *tb[UNIX_DIAG_MAX+1];
ec4d0d8a
VK
2603 char *name = NULL;
2604 struct sockstat stat = {};
dfbaa90d
PE
2605
2606 parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
2607 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2608
bf4ceee6
VK
2609 stat.type = r->udiag_type;
2610 stat.state = r->udiag_state;
ec4d0d8a
VK
2611 stat.ino = stat.lport = r->udiag_ino;
2612 stat.local.family = stat.remote.family = AF_UNIX;
0d2e01c5 2613
bf4ceee6
VK
2614 if (unix_type_skip(&stat, f))
2615 return 0;
dfbaa90d 2616
defd61ca
HFS
2617 if (tb[UNIX_DIAG_RQLEN]) {
2618 struct unix_diag_rqlen *rql = RTA_DATA(tb[UNIX_DIAG_RQLEN]);
bf4ceee6
VK
2619 stat.rq = rql->udiag_rqueue;
2620 stat.wq = rql->udiag_wqueue;
defd61ca 2621 }
dfbaa90d
PE
2622 if (tb[UNIX_DIAG_NAME]) {
2623 int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
2624
ec4d0d8a 2625 name = malloc(len + 1);
dfbaa90d
PE
2626 memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
2627 name[len] = '\0';
2628 if (name[0] == '\0')
2629 name[0] = '@';
ec4d0d8a 2630 sock_addr_set_str(&stat.local, &name);
bf4ceee6 2631 }
dfbaa90d 2632 if (tb[UNIX_DIAG_PEER])
ec4d0d8a 2633 stat.rport = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
dfbaa90d 2634
29999b0f
VK
2635 if (f->f && run_ssfilter(f->f, &stat) == 0)
2636 return 0;
2637
bf4ceee6 2638 unix_stats_print(&stat, f);
dfbaa90d 2639
51ff9f24 2640 if (show_mem) {
bf4ceee6 2641 printf("\t");
51ff9f24
HFS
2642 print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
2643 }
5b816047
PE
2644 if (show_details) {
2645 if (tb[UNIX_DIAG_SHUTDOWN]) {
2646 unsigned char mask;
2647 mask = *(__u8 *)RTA_DATA(tb[UNIX_DIAG_SHUTDOWN]);
2648 printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
2649 }
2650 }
bf4ceee6
VK
2651 if (show_mem || show_details)
2652 printf("\n");
ec4d0d8a
VK
2653
2654 if (name)
2655 free(name);
dfbaa90d
PE
2656 return 0;
2657}
2658
8a4025f6 2659static int handle_netlink_request(struct filter *f, struct nlmsghdr *req,
2660 size_t size, rtnl_filter_t show_one_sock)
dfbaa90d 2661{
8a4025f6 2662 int ret = -1;
2663 struct rtnl_handle rth;
dfbaa90d 2664
8a4025f6 2665 if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
dfbaa90d
PE
2666 return -1;
2667
8a4025f6 2668 rth.dump = MAGIC_SEQ;
dfbaa90d 2669
8a4025f6 2670 if (rtnl_send(&rth, req, size) < 0)
2671 goto Exit;
dfbaa90d 2672
8a4025f6 2673 if (rtnl_dump_filter(&rth, show_one_sock, f))
2674 goto Exit;
dfbaa90d 2675
8a4025f6 2676 ret = 0;
2677Exit:
2678 rtnl_close(&rth);
2679 return ret;
dfbaa90d
PE
2680}
2681
8a4025f6 2682static int unix_show_netlink(struct filter *f)
d8402b96 2683{
5fb421d4 2684 DIAG_REQUEST(req, struct unix_diag_req r);
d8402b96
AV
2685
2686 req.r.sdiag_family = AF_UNIX;
2687 req.r.udiag_states = f->states;
2688 req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
2689 if (show_mem)
2690 req.r.udiag_show |= UDIAG_SHOW_MEMINFO;
2691
8a4025f6 2692 return handle_netlink_request(f, &req.nlh, sizeof(req), unix_show_sock);
d8402b96
AV
2693}
2694
d1f28cf1 2695static int unix_show(struct filter *f)
aba5acdf
SH
2696{
2697 FILE *fp;
2698 char buf[256];
2699 char name[128];
2700 int newformat = 0;
2701 int cnt;
ec4d0d8a 2702 struct sockstat *list = NULL;
aba5acdf 2703
9db7bf15
VK
2704 if (!filter_af_get(f, AF_UNIX))
2705 return 0;
2706
ec4d0d8a 2707 if (!unix_use_proc() && unix_show_netlink(f) == 0)
dfbaa90d
PE
2708 return 0;
2709
ab01dbbb 2710 if ((fp = net_unix_open()) == NULL)
aba5acdf
SH
2711 return -1;
2712 fgets(buf, sizeof(buf)-1, fp);
2713
ae665a52 2714 if (memcmp(buf, "Peer", 4) == 0)
aba5acdf
SH
2715 newformat = 1;
2716 cnt = 0;
2717
2718 while (fgets(buf, sizeof(buf)-1, fp)) {
ec4d0d8a 2719 struct sockstat *u, **insp;
aba5acdf
SH
2720 int flags;
2721
2722 if (!(u = malloc(sizeof(*u))))
2723 break;
aba5acdf
SH
2724
2725 if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
ec4d0d8a 2726 &u->rport, &u->rq, &u->wq, &flags, &u->type,
aba5acdf
SH
2727 &u->state, &u->ino, name) < 8)
2728 name[0] = 0;
2729
ec4d0d8a
VK
2730 u->lport = u->ino;
2731 u->local.family = u->remote.family = AF_UNIX;
2732
2733 if (flags & (1 << 16)) {
aba5acdf
SH
2734 u->state = SS_LISTEN;
2735 } else {
2736 u->state = unix_state_map[u->state-1];
ec4d0d8a 2737 if (u->type == SOCK_DGRAM && u->state == SS_CLOSE && u->rport)
aba5acdf
SH
2738 u->state = SS_ESTABLISHED;
2739 }
2740
2741 if (!newformat) {
ec4d0d8a 2742 u->rport = 0;
aba5acdf
SH
2743 u->rq = 0;
2744 u->wq = 0;
2745 }
2746
2747 insp = &list;
2748 while (*insp) {
2749 if (u->type < (*insp)->type ||
2750 (u->type == (*insp)->type &&
2751 u->ino < (*insp)->ino))
2752 break;
2753 insp = &(*insp)->next;
2754 }
2755 u->next = *insp;
2756 *insp = u;
2757
2758 if (name[0]) {
ec4d0d8a
VK
2759 char *tmp = strdup(name);
2760 sock_addr_set_str(&u->local, &tmp);
aba5acdf
SH
2761 }
2762 if (++cnt > MAX_UNIX_REMEMBER) {
bf4ceee6 2763 unix_stats_print(list, f);
aba5acdf
SH
2764 unix_list_free(list);
2765 list = NULL;
2766 cnt = 0;
2767 }
2768 }
a3fd8e58 2769 fclose(fp);
aba5acdf 2770 if (list) {
bf4ceee6 2771 unix_stats_print(list, f);
aba5acdf
SH
2772 unix_list_free(list);
2773 list = NULL;
2774 cnt = 0;
2775 }
2776
2777 return 0;
2778}
2779
89f634f9 2780static int packet_stats_print(struct sockstat *s, const struct filter *f)
4a0053b6
VK
2781{
2782 char *buf = NULL;
b217df10
VK
2783 const char *addr, *port;
2784 char ll_name[16];
372c30d2 2785
4a0053b6 2786 if (f->f) {
89f634f9
VK
2787 s->local.family = AF_PACKET;
2788 s->remote.family = AF_PACKET;
89f634f9 2789 s->local.data[0] = s->prot;
89f634f9 2790 if (run_ssfilter(f->f, s) == 0)
4a0053b6
VK
2791 return 1;
2792 }
372c30d2 2793
2d791bc8 2794 sock_state_print(s, s->type == SOCK_RAW ? "p_raw" : "p_dgr");
372c30d2 2795
b217df10
VK
2796 if (s->prot == 3)
2797 addr = "*";
2798 else
2799 addr = ll_proto_n2a(htons(s->prot), ll_name, sizeof(ll_name));
2800
2801 if (s->iface == 0)
2802 port = "*";
2803 else
2804 port = xll_index_to_name(s->iface);
372c30d2 2805
b217df10
VK
2806 sock_addr_print(addr, ":", port, NULL);
2807 sock_addr_print("", "*", "", NULL);
116ac927
RH
2808
2809 if (show_proc_ctx || show_sock_ctx) {
4a0053b6
VK
2810 if (find_entry(s->ino, &buf,
2811 (show_proc_ctx & show_sock_ctx) ?
2812 PROC_SOCK_CTX : PROC_CTX) > 0) {
116ac927
RH
2813 printf(" users:(%s)", buf);
2814 free(buf);
2815 }
2816 } else if (show_users) {
4a0053b6 2817 if (find_entry(s->ino, &buf, USERS) > 0) {
116ac927
RH
2818 printf(" users:(%s)", buf);
2819 free(buf);
2820 }
372c30d2 2821 }
116ac927 2822
f1b39e1b
VK
2823 if (show_details)
2824 sock_details_print(s);
2825
4a0053b6
VK
2826 return 0;
2827}
2828
2829static int packet_show_sock(const struct sockaddr_nl *addr,
2830 struct nlmsghdr *nlh, void *arg)
2831{
2832 const struct filter *f = arg;
2833 struct packet_diag_msg *r = NLMSG_DATA(nlh);
2834 struct rtattr *tb[PACKET_DIAG_MAX+1];
89f634f9 2835 struct sockstat stat = {};
4a0053b6
VK
2836
2837 parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
2838 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2839
2840 /* use /proc/net/packet if all info are not available */
2841 if (!tb[PACKET_DIAG_MEMINFO])
2842 return -1;
2843
2d791bc8
VK
2844 stat.type = r->pdiag_type;
2845 stat.prot = r->pdiag_num;
2846 stat.ino = r->pdiag_ino;
2847 stat.state = SS_CLOSE;
f1b39e1b 2848 stat.sk = cookie_sk_get(&r->pdiag_cookie[0]);
4a0053b6
VK
2849
2850 if (tb[PACKET_DIAG_MEMINFO]) {
2851 __u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
2852 stat.rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
2853 }
2854
2855 if (tb[PACKET_DIAG_INFO]) {
2856 struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
2d791bc8 2857 stat.lport = stat.iface = pinfo->pdi_index;
4a0053b6
VK
2858 }
2859
f1b39e1b
VK
2860 if (tb[PACKET_DIAG_UID])
2861 stat.uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
2862
4a0053b6
VK
2863 if (packet_stats_print(&stat, f))
2864 return 0;
2865
372c30d2
ND
2866 if (show_bpf && tb[PACKET_DIAG_FILTER]) {
2867 struct sock_filter *fil =
2868 RTA_DATA(tb[PACKET_DIAG_FILTER]);
2869 int num = RTA_PAYLOAD(tb[PACKET_DIAG_FILTER]) /
2870 sizeof(struct sock_filter);
2871
2872 printf("\n\tbpf filter (%d): ", num);
2873 while (num) {
2874 printf(" 0x%02x %u %u %u,",
2875 fil->code, fil->jt, fil->jf, fil->k);
2876 num--;
2877 fil++;
2878 }
2879 }
2880 printf("\n");
2881 return 0;
2882}
2883
8a4025f6 2884static int packet_show_netlink(struct filter *f)
372c30d2 2885{
5fb421d4 2886 DIAG_REQUEST(req, struct packet_diag_req r);
372c30d2 2887
372c30d2
ND
2888 req.r.sdiag_family = AF_PACKET;
2889 req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO | PACKET_SHOW_FILTER;
2890
8a4025f6 2891 return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock);
372c30d2
ND
2892}
2893
4a0053b6
VK
2894static int packet_show_line(char *buf, const struct filter *f, int fam)
2895{
2896 unsigned long long sk;
89f634f9 2897 struct sockstat stat = {};
4a0053b6
VK
2898 int type, prot, iface, state, rq, uid, ino;
2899
2900 sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
2901 &sk,
2902 &type, &prot, &iface, &state,
2903 &rq, &uid, &ino);
2904
2905 if (stat.type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
2906 return 0;
2907 if (stat.type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
2908 return 0;
2909
2910 stat.type = type;
2911 stat.prot = prot;
2d791bc8 2912 stat.lport = stat.iface = iface;
4a0053b6
VK
2913 stat.state = state;
2914 stat.rq = rq;
2915 stat.uid = uid;
2916 stat.ino = ino;
2d791bc8
VK
2917 stat.state = SS_CLOSE;
2918
4a0053b6
VK
2919 if (packet_stats_print(&stat, f))
2920 return 0;
2921
4a0053b6
VK
2922 printf("\n");
2923 return 0;
2924}
aba5acdf 2925
d1f28cf1 2926static int packet_show(struct filter *f)
aba5acdf
SH
2927{
2928 FILE *fp;
3d0b7439 2929
9db7bf15 2930 if (!filter_af_get(f, AF_PACKET) || !(f->states & (1 << SS_CLOSE)))
b9ea445d 2931 return 0;
aba5acdf 2932
4a0053b6
VK
2933 if (!getenv("PROC_NET_PACKET") && !getenv("PROC_ROOT") &&
2934 packet_show_netlink(f) == 0)
372c30d2
ND
2935 return 0;
2936
ab01dbbb 2937 if ((fp = net_packet_open()) == NULL)
aba5acdf 2938 return -1;
4a0053b6
VK
2939 if (generic_record_read(fp, packet_show_line, f, AF_PACKET))
2940 return -1;
aba5acdf
SH
2941
2942 return 0;
2943}
2944
5f24ec0e 2945static int netlink_show_one(struct filter *f,
129709ae 2946 int prot, int pid, unsigned groups,
f271fe01 2947 int state, int dst_pid, unsigned dst_group,
129709ae
AV
2948 int rq, int wq,
2949 unsigned long long sk, unsigned long long cb)
2950{
2d791bc8 2951 struct sockstat st;
b217df10
VK
2952 SPRINT_BUF(prot_buf) = {};
2953 const char *prot_name;
2954 char procname[64] = {};
eef43b50 2955
2d791bc8
VK
2956 st.state = SS_CLOSE;
2957 st.rq = rq;
2958 st.wq = wq;
2959
129709ae 2960 if (f->f) {
055840f2
VK
2961 st.local.family = AF_NETLINK;
2962 st.remote.family = AF_NETLINK;
2963 st.rport = -1;
2964 st.lport = pid;
2965 st.local.data[0] = prot;
055840f2 2966 if (run_ssfilter(f->f, &st) == 0)
5f24ec0e 2967 return 1;
129709ae
AV
2968 }
2969
2d791bc8 2970 sock_state_print(&st, "nl");
eef43b50 2971
b217df10
VK
2972 if (resolve_services)
2973 prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf));
2974 else
2975 prot_name = int_to_str(prot, prot_buf);
eef43b50 2976
129709ae 2977 if (pid == -1) {
b217df10 2978 procname[0] = '*';
129709ae
AV
2979 } else if (resolve_services) {
2980 int done = 0;
2981 if (!pid) {
2982 done = 1;
b217df10 2983 strncpy(procname, "kernel", 6);
129709ae 2984 } else if (pid > 0) {
129709ae
AV
2985 FILE *fp;
2986 sprintf(procname, "%s/%d/stat",
2987 getenv("PROC_ROOT") ? : "/proc", pid);
2988 if ((fp = fopen(procname, "r")) != NULL) {
2989 if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
2990 sprintf(procname+strlen(procname), "/%d", pid);
129709ae
AV
2991 done = 1;
2992 }
2993 fclose(fp);
2994 }
2995 }
2996 if (!done)
b217df10 2997 int_to_str(pid, procname);
129709ae 2998 } else {
b217df10 2999 int_to_str(pid, procname);
129709ae 3000 }
f271fe01 3001
b217df10
VK
3002 sock_addr_print(prot_name, ":", procname, NULL);
3003
f271fe01 3004 if (state == NETLINK_CONNECTED) {
b217df10
VK
3005 char dst_group_buf[30];
3006 char dst_pid_buf[30];
3007 sock_addr_print(int_to_str(dst_group, dst_group_buf), ":",
3008 int_to_str(dst_pid, dst_pid_buf), NULL);
f271fe01 3009 } else {
b217df10 3010 sock_addr_print("", "*", "", NULL);
f271fe01 3011 }
129709ae 3012
116ac927
RH
3013 char *pid_context = NULL;
3014 if (show_proc_ctx) {
3015 /* The pid value will either be:
3016 * 0 if destination kernel - show kernel initial context.
3017 * A valid process pid - use getpidcon.
3018 * A unique value allocated by the kernel or netlink user
3019 * to the process - show context as "not available".
3020 */
3021 if (!pid)
3022 security_get_initial_context("kernel", &pid_context);
3023 else if (pid > 0)
3024 getpidcon(pid, &pid_context);
3025
3026 if (pid_context != NULL) {
3027 printf("proc_ctx=%-*s ", serv_width, pid_context);
3028 free(pid_context);
3029 } else {
3030 printf("proc_ctx=%-*s ", serv_width, "unavailable");
3031 }
3032 }
3033
129709ae
AV
3034 if (show_details) {
3035 printf(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
3036 }
3037 printf("\n");
3038
5f24ec0e 3039 return 0;
129709ae
AV
3040}
3041
8a4025f6 3042static int netlink_show_sock(const struct sockaddr_nl *addr,
3043 struct nlmsghdr *nlh, void *arg)
ecb928c8 3044{
8a4025f6 3045 struct filter *f = (struct filter *)arg;
ecb928c8
AV
3046 struct netlink_diag_msg *r = NLMSG_DATA(nlh);
3047 struct rtattr *tb[NETLINK_DIAG_MAX+1];
3048 int rq = 0, wq = 0;
3049 unsigned long groups = 0;
3050
3051 parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr*)(r+1),
3052 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
3053
3054 if (tb[NETLINK_DIAG_GROUPS] && RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS]))
3055 groups = *(unsigned long *) RTA_DATA(tb[NETLINK_DIAG_GROUPS]);
3056
3057 if (tb[NETLINK_DIAG_MEMINFO]) {
3058 const __u32 *skmeminfo;
3059 skmeminfo = RTA_DATA(tb[NETLINK_DIAG_MEMINFO]);
3060
3061 rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
3062 wq = skmeminfo[SK_MEMINFO_WMEM_ALLOC];
3063 }
3064
5f24ec0e 3065 if (netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
ecb928c8 3066 r->ndiag_state, r->ndiag_dst_portid, r->ndiag_dst_group,
5f24ec0e
VK
3067 rq, wq, 0, 0)) {
3068 return 0;
3069 }
ecb928c8
AV
3070
3071 if (show_mem) {
3072 printf("\t");
3073 print_skmeminfo(tb, NETLINK_DIAG_MEMINFO);
3074 printf("\n");
3075 }
3076
3077 return 0;
3078}
3079
8a4025f6 3080static int netlink_show_netlink(struct filter *f)
ecb928c8 3081{
5fb421d4 3082 DIAG_REQUEST(req, struct netlink_diag_req r);
ecb928c8
AV
3083
3084 req.r.sdiag_family = AF_NETLINK;
3085 req.r.sdiag_protocol = NDIAG_PROTO_ALL;
3086 req.r.ndiag_show = NDIAG_SHOW_GROUPS | NDIAG_SHOW_MEMINFO;
3087
8a4025f6 3088 return handle_netlink_request(f, &req.nlh, sizeof(req), netlink_show_sock);
ecb928c8
AV
3089}
3090
d1f28cf1 3091static int netlink_show(struct filter *f)
aba5acdf
SH
3092{
3093 FILE *fp;
3094 char buf[256];
3095 int prot, pid;
3096 unsigned groups;
3097 int rq, wq, rc;
3098 unsigned long long sk, cb;
3099
9db7bf15 3100 if (!filter_af_get(f, AF_NETLINK) || !(f->states & (1 << SS_CLOSE)))
b9ea445d
VK
3101 return 0;
3102
129709ae 3103 if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") &&
8a4025f6 3104 netlink_show_netlink(f) == 0)
129709ae
AV
3105 return 0;
3106
ab01dbbb 3107 if ((fp = net_netlink_open()) == NULL)
aba5acdf
SH
3108 return -1;
3109 fgets(buf, sizeof(buf)-1, fp);
3110
3111 while (fgets(buf, sizeof(buf)-1, fp)) {
3112 sscanf(buf, "%llx %d %d %x %d %d %llx %d",
3113 &sk,
3114 &prot, &pid, &groups, &rq, &wq, &cb, &rc);
3115
f271fe01 3116 netlink_show_one(f, prot, pid, groups, 0, 0, 0, rq, wq, sk, cb);
aba5acdf
SH
3117 }
3118
3119 return 0;
3120}
3121
3122struct snmpstat
3123{
3124 int tcp_estab;
3125};
3126
d1f28cf1 3127static int get_snmp_int(char *proto, char *key, int *result)
aba5acdf
SH
3128{
3129 char buf[1024];
3130 FILE *fp;
3131 int protolen = strlen(proto);
3132 int keylen = strlen(key);
3133
3134 *result = 0;
3135
ab01dbbb 3136 if ((fp = net_snmp_open()) == NULL)
aba5acdf
SH
3137 return -1;
3138
3139 while (fgets(buf, sizeof(buf), fp) != NULL) {
3140 char *p = buf;
3141 int pos = 0;
3142 if (memcmp(buf, proto, protolen))
3143 continue;
3144 while ((p = strchr(p, ' ')) != NULL) {
3145 pos++;
3146 p++;
3147 if (memcmp(p, key, keylen) == 0 &&
3148 (p[keylen] == ' ' || p[keylen] == '\n'))
3149 break;
3150 }
3151 if (fgets(buf, sizeof(buf), fp) == NULL)
3152 break;
3153 if (memcmp(buf, proto, protolen))
3154 break;
3155 p = buf;
3156 while ((p = strchr(p, ' ')) != NULL) {
3157 p++;
3158 if (--pos == 0) {
3159 sscanf(p, "%d", result);
3160 fclose(fp);
3161 return 0;
3162 }
3163 }
3164 }
3165
3166 fclose(fp);
3167 errno = ESRCH;
3168 return -1;
3169}
3170
3171
3172/* Get stats from sockstat */
3173
055840f2 3174struct ssummary
aba5acdf
SH
3175{
3176 int socks;
3177 int tcp_mem;
3178 int tcp_total;
3179 int tcp_orphans;
3180 int tcp_tws;
3181 int tcp4_hashed;
3182 int udp4;
3183 int raw4;
3184 int frag4;
3185 int frag4_mem;
3186 int tcp6_hashed;
3187 int udp6;
3188 int raw6;
3189 int frag6;
3190 int frag6_mem;
3191};
3192
055840f2 3193static void get_sockstat_line(char *line, struct ssummary *s)
aba5acdf
SH
3194{
3195 char id[256], rem[256];
3196
3197 if (sscanf(line, "%[^ ] %[^\n]\n", id, rem) != 2)
3198 return;
3199
3200 if (strcmp(id, "sockets:") == 0)
3201 sscanf(rem, "%*s%d", &s->socks);
3202 else if (strcmp(id, "UDP:") == 0)
3203 sscanf(rem, "%*s%d", &s->udp4);
3204 else if (strcmp(id, "UDP6:") == 0)
3205 sscanf(rem, "%*s%d", &s->udp6);
3206 else if (strcmp(id, "RAW:") == 0)
3207 sscanf(rem, "%*s%d", &s->raw4);
3208 else if (strcmp(id, "RAW6:") == 0)
3209 sscanf(rem, "%*s%d", &s->raw6);
3210 else if (strcmp(id, "TCP6:") == 0)
3211 sscanf(rem, "%*s%d", &s->tcp6_hashed);
3212 else if (strcmp(id, "FRAG:") == 0)
3213 sscanf(rem, "%*s%d%*s%d", &s->frag4, &s->frag4_mem);
3214 else if (strcmp(id, "FRAG6:") == 0)
3215 sscanf(rem, "%*s%d%*s%d", &s->frag6, &s->frag6_mem);
3216 else if (strcmp(id, "TCP:") == 0)
3217 sscanf(rem, "%*s%d%*s%d%*s%d%*s%d%*s%d",
3218 &s->tcp4_hashed,
3219 &s->tcp_orphans, &s->tcp_tws, &s->tcp_total, &s->tcp_mem);
3220}
3221
055840f2 3222static int get_sockstat(struct ssummary *s)
aba5acdf
SH
3223{
3224 char buf[256];
3225 FILE *fp;
3226
3227 memset(s, 0, sizeof(*s));
3228
ab01dbbb 3229 if ((fp = net_sockstat_open()) == NULL)
aba5acdf
SH
3230 return -1;
3231 while(fgets(buf, sizeof(buf), fp) != NULL)
3232 get_sockstat_line(buf, s);
3233 fclose(fp);
3234
ab01dbbb 3235 if ((fp = net_sockstat6_open()) == NULL)
aba5acdf
SH
3236 return 0;
3237 while(fgets(buf, sizeof(buf), fp) != NULL)
3238 get_sockstat_line(buf, s);
3239 fclose(fp);
3240
3241 return 0;
3242}
3243
d1f28cf1 3244static int print_summary(void)
aba5acdf 3245{
055840f2 3246 struct ssummary s;
aba5acdf
SH
3247 struct snmpstat sn;
3248
3249 if (get_sockstat(&s) < 0)
3250 perror("ss: get_sockstat");
3251 if (get_snmp_int("Tcp:", "CurrEstab", &sn.tcp_estab) < 0)
3252 perror("ss: get_snmpstat");
3253
a221d621
BL
3254 get_slabstat(&slabstat);
3255
aba5acdf
SH
3256 printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks);
3257
3258 printf("TCP: %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
3259 s.tcp_total + slabstat.tcp_syns + s.tcp_tws,
3260 sn.tcp_estab,
3261 s.tcp_total - (s.tcp4_hashed+s.tcp6_hashed-s.tcp_tws),
3262 s.tcp_orphans,
3263 slabstat.tcp_syns,
3264 s.tcp_tws, slabstat.tcp_tws,
3265 slabstat.tcp_ports
3266 );
3267
3268 printf("\n");
3269 printf("Transport Total IP IPv6\n");
3270 printf("* %-9d %-9s %-9s\n", slabstat.socks, "-", "-");
3271 printf("RAW %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
3272 printf("UDP %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
3273 printf("TCP %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
ae665a52 3274 printf("INET %-9d %-9d %-9d\n",
aba5acdf
SH
3275 s.raw4+s.udp4+s.tcp4_hashed+
3276 s.raw6+s.udp6+s.tcp6_hashed,
3277 s.raw4+s.udp4+s.tcp4_hashed,
3278 s.raw6+s.udp6+s.tcp6_hashed);
3279 printf("FRAG %-9d %-9d %-9d\n", s.frag4+s.frag6, s.frag4, s.frag6);
3280
3281 printf("\n");
3282
3283 return 0;
3284}
3285
7a96e199 3286static void _usage(FILE *dest)
aba5acdf 3287{
7a96e199 3288 fprintf(dest,
aba5acdf
SH
3289"Usage: ss [ OPTIONS ]\n"
3290" ss [ OPTIONS ] [ FILTER ]\n"
ff041f16
VK
3291" -h, --help this message\n"
3292" -V, --version output version information\n"
3293" -n, --numeric don't resolve service names\n"
ab61159a 3294" -r, --resolve resolve host names\n"
ff041f16
VK
3295" -a, --all display all sockets\n"
3296" -l, --listening display listening sockets\n"
ab61159a
SH
3297" -o, --options show timer information\n"
3298" -e, --extended show detailed socket information\n"
3299" -m, --memory show socket memory usage\n"
ff041f16
VK
3300" -p, --processes show process using socket\n"
3301" -i, --info show internal TCP information\n"
3302" -s, --summary show socket usage summary\n"
b0f01cf6 3303" -b, --bpf show bpf filter socket information\n"
ff041f16
VK
3304" -Z, --context display process SELinux security contexts\n"
3305" -z, --contexts display process and socket SELinux security contexts\n"
95ce04bc 3306" -N, --net switch to the specified network namespace name\n"
ab61159a
SH
3307"\n"
3308" -4, --ipv4 display only IP version 4 sockets\n"
3309" -6, --ipv6 display only IP version 6 sockets\n"
ff041f16
VK
3310" -0, --packet display PACKET sockets\n"
3311" -t, --tcp display only TCP sockets\n"
3312" -u, --udp display only UDP sockets\n"
3313" -d, --dccp display only DCCP sockets\n"
3314" -w, --raw display only RAW sockets\n"
3315" -x, --unix display only Unix domain sockets\n"
ab61159a
SH
3316" -f, --family=FAMILY display sockets of type FAMILY\n"
3317"\n"
583de149 3318" -A, --query=QUERY, --socket=QUERY\n"
56dee73e 3319" QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]\n"
ab61159a 3320"\n"
583de149 3321" -D, --diag=FILE Dump raw information about TCP sockets to FILE\n"
ab61159a 3322" -F, --filter=FILE read filter information from FILE\n"
ff041f16
VK
3323" FILTER := [ state STATE-FILTER ] [ EXPRESSION ]\n"
3324" STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}\n"
3325" TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listen|closing}\n"
3326" connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
3327" synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
3328" bucket := {syn-recv|time-wait}\n"
3329" big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listen|closing}\n"
ab61159a 3330 );
7a96e199
AH
3331}
3332
3333static void help(void) __attribute__((noreturn));
3334static void help(void)
3335{
3336 _usage(stdout);
3337 exit(0);
3338}
3339
3340static void usage(void) __attribute__((noreturn));
3341static void usage(void)
3342{
3343 _usage(stderr);
aba5acdf
SH
3344 exit(-1);
3345}
3346
3347
d1f28cf1 3348static int scan_state(const char *state)
aba5acdf
SH
3349{
3350 int i;
3351 if (strcasecmp(state, "close") == 0 ||
3352 strcasecmp(state, "closed") == 0)
3353 return (1<<SS_CLOSE);
3354 if (strcasecmp(state, "syn-rcv") == 0)
3355 return (1<<SS_SYN_RECV);
1a5bad5a 3356 if (strcasecmp(state, "established") == 0)
aba5acdf
SH
3357 return (1<<SS_ESTABLISHED);
3358 if (strcasecmp(state, "all") == 0)
3359 return SS_ALL;
3360 if (strcasecmp(state, "connected") == 0)
3361 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN));
1a5bad5a 3362 if (strcasecmp(state, "synchronized") == 0)
aba5acdf
SH
3363 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN)|(1<<SS_SYN_SENT));
3364 if (strcasecmp(state, "bucket") == 0)
3365 return (1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT);
3366 if (strcasecmp(state, "big") == 0)
3367 return SS_ALL & ~((1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT));
3368 for (i=0; i<SS_MAX; i++) {
1a5bad5a 3369 if (strcasecmp(state, sstate_namel[i]) == 0)
aba5acdf
SH
3370 return (1<<i);
3371 }
9db7bf15
VK
3372
3373 fprintf(stderr, "ss: wrong state name: %s\n", state);
3374 exit(-1);
aba5acdf
SH
3375}
3376
ab61159a
SH
3377static const struct option long_opts[] = {
3378 { "numeric", 0, 0, 'n' },
3379 { "resolve", 0, 0, 'r' },
3380 { "options", 0, 0, 'o' },
3381 { "extended", 0, 0, 'e' },
3382 { "memory", 0, 0, 'm' },
3383 { "info", 0, 0, 'i' },
3384 { "processes", 0, 0, 'p' },
372c30d2 3385 { "bpf", 0, 0, 'b' },
351efcde 3386 { "dccp", 0, 0, 'd' },
ab61159a
SH
3387 { "tcp", 0, 0, 't' },
3388 { "udp", 0, 0, 'u' },
3389 { "raw", 0, 0, 'w' },
3390 { "unix", 0, 0, 'x' },
3391 { "all", 0, 0, 'a' },
3392 { "listening", 0, 0, 'l' },
3393 { "ipv4", 0, 0, '4' },
3394 { "ipv6", 0, 0, '6' },
3395 { "packet", 0, 0, '0' },
3396 { "family", 1, 0, 'f' },
3397 { "socket", 1, 0, 'A' },
583de149 3398 { "query", 1, 0, 'A' },
c3f346b0 3399 { "summary", 0, 0, 's' },
583de149 3400 { "diag", 1, 0, 'D' },
ab61159a
SH
3401 { "filter", 1, 0, 'F' },
3402 { "version", 0, 0, 'V' },
3403 { "help", 0, 0, 'h' },
116ac927
RH
3404 { "context", 0, 0, 'Z' },
3405 { "contexts", 0, 0, 'z' },
95ce04bc 3406 { "net", 1, 0, 'N' },
ab61159a 3407 { 0 }
ae665a52 3408
ab61159a
SH
3409};
3410
aba5acdf
SH
3411int main(int argc, char *argv[])
3412{
aba5acdf
SH
3413 int saw_states = 0;
3414 int saw_query = 0;
3415 int do_summary = 0;
7d105b56 3416 const char *dump_tcpdiag = NULL;
aba5acdf
SH
3417 FILE *filter_fp = NULL;
3418 int ch;
9db7bf15
VK
3419 struct filter dbs_filter = {};
3420 int state_filter = 0;
aba5acdf 3421
95ce04bc 3422 while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vVzZN:",
ab61159a 3423 long_opts, NULL)) != EOF) {
aba5acdf
SH
3424 switch(ch) {
3425 case 'n':
3426 resolve_services = 0;
3427 break;
3428 case 'r':
3429 resolve_hosts = 1;
3430 break;
3431 case 'o':
3432 show_options = 1;
3433 break;
3434 case 'e':
3435 show_options = 1;
3436 show_details++;
3437 break;
3438 case 'm':
3439 show_mem = 1;
3440 break;
3441 case 'i':
3442 show_tcpinfo = 1;
3443 break;
3444 case 'p':
3445 show_users++;
fbc0f876 3446 user_ent_hash_build();
aba5acdf 3447 break;
372c30d2
ND
3448 case 'b':
3449 show_options = 1;
3450 show_bpf++;
3451 break;
351efcde 3452 case 'd':
9db7bf15 3453 filter_db_set(&dbs_filter, DCCP_DB);
351efcde 3454 break;
aba5acdf 3455 case 't':
9db7bf15 3456 filter_db_set(&dbs_filter, TCP_DB);
aba5acdf
SH
3457 break;
3458 case 'u':
9db7bf15 3459 filter_db_set(&dbs_filter, UDP_DB);
aba5acdf
SH
3460 break;
3461 case 'w':
9db7bf15 3462 filter_db_set(&dbs_filter, RAW_DB);
aba5acdf
SH
3463 break;
3464 case 'x':
9db7bf15 3465 filter_af_set(&current_filter, AF_UNIX);
aba5acdf
SH
3466 break;
3467 case 'a':
9db7bf15 3468 state_filter = SS_ALL;
aba5acdf
SH
3469 break;
3470 case 'l':
9db7bf15 3471 state_filter = (1 << SS_LISTEN) | (1 << SS_CLOSE);
aba5acdf
SH
3472 break;
3473 case '4':
9db7bf15 3474 filter_af_set(&current_filter, AF_INET);
aba5acdf
SH
3475 break;
3476 case '6':
9db7bf15 3477 filter_af_set(&current_filter, AF_INET6);
aba5acdf
SH
3478 break;
3479 case '0':
9db7bf15 3480 filter_af_set(&current_filter, AF_PACKET);
aba5acdf
SH
3481 break;
3482 case 'f':
3483 if (strcmp(optarg, "inet") == 0)
9db7bf15 3484 filter_af_set(&current_filter, AF_INET);
aba5acdf 3485 else if (strcmp(optarg, "inet6") == 0)
9db7bf15 3486 filter_af_set(&current_filter, AF_INET6);
aba5acdf 3487 else if (strcmp(optarg, "link") == 0)
9db7bf15 3488 filter_af_set(&current_filter, AF_PACKET);
aba5acdf 3489 else if (strcmp(optarg, "unix") == 0)
9db7bf15 3490 filter_af_set(&current_filter, AF_UNIX);
aba5acdf 3491 else if (strcmp(optarg, "netlink") == 0)
9db7bf15 3492 filter_af_set(&current_filter, AF_NETLINK);
aba5acdf 3493 else if (strcmp(optarg, "help") == 0)
7a96e199 3494 help();
aba5acdf 3495 else {
9db7bf15
VK
3496 fprintf(stderr, "ss: \"%s\" is invalid family\n",
3497 optarg);
aba5acdf
SH
3498 usage();
3499 }
3500 break;
3501 case 'A':
3502 {
3503 char *p, *p1;
3504 if (!saw_query) {
3505 current_filter.dbs = 0;
3506 saw_query = 1;
3507 do_default = 0;
3508 }
3509 p = p1 = optarg;
3510 do {
3511 if ((p1 = strchr(p, ',')) != NULL)
ae665a52 3512 *p1 = 0;
aba5acdf 3513 if (strcmp(p, "all") == 0) {
9db7bf15 3514 filter_default_dbs(&dbs_filter);
aba5acdf 3515 } else if (strcmp(p, "inet") == 0) {
9db7bf15
VK
3516 filter_db_set(&dbs_filter, UDP_DB);
3517 filter_db_set(&dbs_filter, DCCP_DB);
3518 filter_db_set(&dbs_filter, TCP_DB);
3519 filter_db_set(&dbs_filter, RAW_DB);
aba5acdf 3520 } else if (strcmp(p, "udp") == 0) {
9db7bf15 3521 filter_db_set(&dbs_filter, UDP_DB);
351efcde 3522 } else if (strcmp(p, "dccp") == 0) {
9db7bf15 3523 filter_db_set(&dbs_filter, DCCP_DB);
aba5acdf 3524 } else if (strcmp(p, "tcp") == 0) {
9db7bf15 3525 filter_db_set(&dbs_filter, TCP_DB);
aba5acdf 3526 } else if (strcmp(p, "raw") == 0) {
9db7bf15 3527 filter_db_set(&dbs_filter, RAW_DB);
aba5acdf 3528 } else if (strcmp(p, "unix") == 0) {
9db7bf15
VK
3529 filter_db_set(&dbs_filter, UNIX_ST_DB);
3530 filter_db_set(&dbs_filter, UNIX_DG_DB);
3531 filter_db_set(&dbs_filter, UNIX_SQ_DB);
1a5bad5a 3532 } else if (strcasecmp(p, "unix_stream") == 0 ||
aba5acdf 3533 strcmp(p, "u_str") == 0) {
9db7bf15 3534 filter_db_set(&dbs_filter, UNIX_ST_DB);
1a5bad5a 3535 } else if (strcasecmp(p, "unix_dgram") == 0 ||
aba5acdf 3536 strcmp(p, "u_dgr") == 0) {
9db7bf15 3537 filter_db_set(&dbs_filter, UNIX_DG_DB);
30b669d7
MY
3538 } else if (strcasecmp(p, "unix_seqpacket") == 0 ||
3539 strcmp(p, "u_seq") == 0) {
9db7bf15 3540 filter_db_set(&dbs_filter, UNIX_SQ_DB);
aba5acdf 3541 } else if (strcmp(p, "packet") == 0) {
9db7bf15
VK
3542 filter_db_set(&dbs_filter, PACKET_R_DB);
3543 filter_db_set(&dbs_filter, PACKET_DG_DB);
aba5acdf
SH
3544 } else if (strcmp(p, "packet_raw") == 0 ||
3545 strcmp(p, "p_raw") == 0) {
9db7bf15 3546 filter_db_set(&dbs_filter, PACKET_R_DB);
aba5acdf
SH
3547 } else if (strcmp(p, "packet_dgram") == 0 ||
3548 strcmp(p, "p_dgr") == 0) {
9db7bf15 3549 filter_db_set(&dbs_filter, PACKET_DG_DB);
aba5acdf 3550 } else if (strcmp(p, "netlink") == 0) {
9db7bf15 3551 filter_db_set(&dbs_filter, NETLINK_DB);
aba5acdf
SH
3552 } else {
3553 fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p);
3554 usage();
3555 }
3556 p = p1 + 1;
3557 } while (p1);
3558 break;
3559 }
3560 case 's':
3561 do_summary = 1;
3562 break;
3563 case 'D':
3564 dump_tcpdiag = optarg;
3565 break;
3566 case 'F':
3567 if (filter_fp) {
3568 fprintf(stderr, "More than one filter file\n");
3569 exit(-1);
3570 }
3571 if (optarg[0] == '-')
3572 filter_fp = stdin;
3573 else
3574 filter_fp = fopen(optarg, "r");
3575 if (!filter_fp) {
3576 perror("fopen filter file");
3577 exit(-1);
3578 }
3579 break;
3580 case 'v':
3581 case 'V':
3582 printf("ss utility, iproute2-ss%s\n", SNAPSHOT);
3583 exit(0);
116ac927
RH
3584 case 'z':
3585 show_sock_ctx++;
3586 case 'Z':
3587 if (is_selinux_enabled() <= 0) {
3588 fprintf(stderr, "ss: SELinux is not enabled.\n");
3589 exit(1);
3590 }
3591 show_proc_ctx++;
3592 user_ent_hash_build();
3593 break;
95ce04bc
VK
3594 case 'N':
3595 if (netns_switch(optarg))
3596 exit(1);
3597 break;
aba5acdf
SH
3598 case 'h':
3599 case '?':
7a96e199 3600 help();
aba5acdf
SH
3601 default:
3602 usage();
3603 }
3604 }
3605
3606 argc -= optind;
3607 argv += optind;
3608
aba5acdf
SH
3609 if (do_summary) {
3610 print_summary();
3611 if (do_default && argc == 0)
3612 exit(0);
3613 }
3614
aba5acdf
SH
3615 /* Now parse filter... */
3616 if (argc == 0 && filter_fp) {
3617 if (ssfilter_parse(&current_filter.f, 0, NULL, filter_fp))
3618 usage();
3619 }
3620
3621 while (argc > 0) {
3622 if (strcmp(*argv, "state") == 0) {
3623 NEXT_ARG();
3624 if (!saw_states)
9db7bf15
VK
3625 state_filter = 0;
3626 state_filter |= scan_state(*argv);
aba5acdf
SH
3627 saw_states = 1;
3628 } else if (strcmp(*argv, "exclude") == 0 ||
3629 strcmp(*argv, "excl") == 0) {
3630 NEXT_ARG();
3631 if (!saw_states)
9db7bf15
VK
3632 state_filter = SS_ALL;
3633 state_filter &= ~scan_state(*argv);
aba5acdf
SH
3634 saw_states = 1;
3635 } else {
aba5acdf
SH
3636 break;
3637 }
3638 argc--; argv++;
3639 }
3640
9db7bf15
VK
3641 if (do_default) {
3642 state_filter = state_filter ? state_filter : SS_CONN;
3643 filter_default_dbs(&current_filter);
3644 filter_merge(&current_filter, &current_filter, state_filter);
3645 } else {
3646 filter_merge(&current_filter, &dbs_filter, state_filter);
3647 }
3648
3649 if (resolve_services && resolve_hosts &&
3650 (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
3651 init_service_resolver();
3652
3653
3654 if (current_filter.dbs == 0) {
3655 fprintf(stderr, "ss: no socket tables to show with such filter.\n");
3656 exit(0);
3657 }
3658 if (current_filter.families == 0) {
3659 fprintf(stderr, "ss: no families to show with such filter.\n");
3660 exit(0);
3661 }
aba5acdf
SH
3662 if (current_filter.states == 0) {
3663 fprintf(stderr, "ss: no socket states to show with such filter.\n");
3664 exit(0);
3665 }
3666
3667 if (dump_tcpdiag) {
3668 FILE *dump_fp = stdout;
3669 if (!(current_filter.dbs & (1<<TCP_DB))) {
3670 fprintf(stderr, "ss: tcpdiag dump requested and no tcp in filter.\n");
3671 exit(0);
3672 }
3673 if (dump_tcpdiag[0] != '-') {
3674 dump_fp = fopen(dump_tcpdiag, "w");
3675 if (!dump_tcpdiag) {
3676 perror("fopen dump file");
3677 exit(-1);
3678 }
3679 }
3fe5b534 3680 inet_show_netlink(&current_filter, dump_fp, IPPROTO_TCP);
aba5acdf
SH
3681 fflush(dump_fp);
3682 exit(0);
3683 }
3684
1527a17e
VK
3685 if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
3686 usage();
3687
aba5acdf
SH
3688 netid_width = 0;
3689 if (current_filter.dbs&(current_filter.dbs-1))
3690 netid_width = 5;
3691
3692 state_width = 0;
3693 if (current_filter.states&(current_filter.states-1))
3694 state_width = 10;
3695
3696 screen_width = 80;
3697 if (isatty(STDOUT_FILENO)) {
3698 struct winsize w;
3699
3700 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
3701 if (w.ws_col > 0)
3702 screen_width = w.ws_col;
3703 }
3704 }
3705
3706 addrp_width = screen_width;
3707 addrp_width -= netid_width+1;
3708 addrp_width -= state_width+1;
3709 addrp_width -= 14;
3710
3711 if (addrp_width&1) {
3712 if (netid_width)
3713 netid_width++;
3714 else if (state_width)
3715 state_width++;
3716 }
3717
3718 addrp_width /= 2;
3719 addrp_width--;
3720
3721 serv_width = resolve_services ? 7 : 5;
3722
3723 if (addrp_width < 15+serv_width+1)
3724 addrp_width = 15+serv_width+1;
3725
ae665a52 3726 addr_width = addrp_width - serv_width - 1;
aba5acdf
SH
3727
3728 if (netid_width)
3729 printf("%-*s ", netid_width, "Netid");
3730 if (state_width)
3731 printf("%-*s ", state_width, "State");
3732 printf("%-6s %-6s ", "Recv-Q", "Send-Q");
3733
d68e00f7 3734 /* Make enough space for the local/remote port field */
3735 addr_width -= 13;
3736 serv_width += 13;
2dc85485 3737
aba5acdf
SH
3738 printf("%*s:%-*s %*s:%-*s\n",
3739 addr_width, "Local Address", serv_width, "Port",
d68e00f7 3740 addr_width, "Peer Address", serv_width, "Port");
aba5acdf 3741
aba5acdf
SH
3742 fflush(stdout);
3743
3744 if (current_filter.dbs & (1<<NETLINK_DB))
3745 netlink_show(&current_filter);
3746 if (current_filter.dbs & PACKET_DBM)
3747 packet_show(&current_filter);
3748 if (current_filter.dbs & UNIX_DBM)
3749 unix_show(&current_filter);
3750 if (current_filter.dbs & (1<<RAW_DB))
3751 raw_show(&current_filter);
3752 if (current_filter.dbs & (1<<UDP_DB))
3753 udp_show(&current_filter);
3754 if (current_filter.dbs & (1<<TCP_DB))
3fe5b534 3755 tcp_show(&current_filter, IPPROTO_TCP);
351efcde 3756 if (current_filter.dbs & (1<<DCCP_DB))
3fe5b534 3757 tcp_show(&current_filter, IPPROTO_DCCP);
116ac927
RH
3758
3759 if (show_users || show_proc_ctx || show_sock_ctx)
3760 user_ent_destroy();
3761
aba5acdf
SH
3762 return 0;
3763}