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