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