]> git.proxmox.com Git - mirror_iproute2.git/blame - misc/ss.c
ss: Buffer raw fields first, then render them as a table
[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>
aba5acdf
SH
15#include <fcntl.h>
16#include <sys/ioctl.h>
17#include <sys/socket.h>
18#include <sys/uio.h>
19#include <netinet/in.h>
20#include <string.h>
21#include <errno.h>
22#include <netdb.h>
23#include <arpa/inet.h>
aba5acdf
SH
24#include <dirent.h>
25#include <fnmatch.h>
ab61159a 26#include <getopt.h>
bf4ceee6 27#include <stdbool.h>
6b376ebd 28#include <limits.h>
90351722 29#include <stdarg.h>
aba5acdf
SH
30
31#include "utils.h"
32#include "rt_names.h"
33#include "ll_map.h"
34#include "libnetlink.h"
95ce04bc 35#include "namespace.h"
aba5acdf
SH
36#include "SNAPSHOT.h"
37
9cb1eccf 38#include <linux/tcp.h>
f6062360 39#include <linux/sock_diag.h>
351efcde 40#include <linux/inet_diag.h>
dfbaa90d 41#include <linux/unix_diag.h>
372c30d2
ND
42#include <linux/netdevice.h> /* for MAX_ADDR_LEN */
43#include <linux/filter.h>
44#include <linux/packet_diag.h>
ecb928c8 45#include <linux/netlink_diag.h>
f89d46ad 46#include <linux/sctp.h>
c759116a 47#include <linux/vm_sockets_diag.h>
aba5acdf 48
8a4025f6 49#define MAGIC_SEQ 123456
691bd854
SB
50#define BUF_CHUNK (1024 * 1024)
51#define LEN_ALIGN(x) (((x) + 1) & ~1)
8a4025f6 52
5fb421d4 53#define DIAG_REQUEST(_req, _r) \
54 struct { \
55 struct nlmsghdr nlh; \
56 _r; \
57 } _req = { \
58 .nlh = { \
59 .nlmsg_type = SOCK_DIAG_BY_FAMILY, \
60 .nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST,\
8a4025f6 61 .nlmsg_seq = MAGIC_SEQ, \
5fb421d4 62 .nlmsg_len = sizeof(_req), \
63 }, \
64 }
65
116ac927
RH
66#if HAVE_SELINUX
67#include <selinux/selinux.h>
68#else
69/* Stubs for SELinux functions */
70static int is_selinux_enabled(void)
71{
72 return -1;
73}
74
75static int getpidcon(pid_t pid, char **context)
76{
77 *context = NULL;
78 return -1;
79}
80
81static int getfilecon(char *path, char **context)
82{
83 *context = NULL;
84 return -1;
85}
86
87static int security_get_initial_context(char *name, char **context)
88{
89 *context = NULL;
90 return -1;
91}
92#endif
93
aba5acdf
SH
94int resolve_services = 1;
95int preferred_family = AF_UNSPEC;
acd1e437
SH
96int show_options;
97int show_details;
98int show_users;
99int show_mem;
100int show_tcpinfo;
101int show_bpf;
102int show_proc_ctx;
103int show_sock_ctx;
7a4559f6 104int show_header = 1;
acd1e437 105int follow_events;
f89d46ad 106int sctp_ino;
aba5acdf 107
59f46b7b
SB
108enum col_id {
109 COL_NETID,
110 COL_STATE,
111 COL_RECVQ,
112 COL_SENDQ,
113 COL_ADDR,
114 COL_SERV,
115 COL_RADDR,
116 COL_RSERV,
117 COL_EXT,
118 COL_MAX
119};
120
121enum col_align {
122 ALIGN_LEFT,
123 ALIGN_CENTER,
124 ALIGN_RIGHT
125};
126
127struct column {
128 const enum col_align align;
129 const char *header;
130 const char *ldelim;
131 int width; /* Including delimiter. -1: fit to content, 0: hide */
59f46b7b
SB
132};
133
134static struct column columns[] = {
691bd854
SB
135 { ALIGN_LEFT, "Netid", "", 0 },
136 { ALIGN_LEFT, "State", " ", 0 },
137 { ALIGN_LEFT, "Recv-Q", " ", 7 },
138 { ALIGN_LEFT, "Send-Q", " ", 7 },
139 { ALIGN_RIGHT, "Local Address:", " ", 0 },
140 { ALIGN_LEFT, "Port", "", 0 },
141 { ALIGN_RIGHT, "Peer Address:", " ", 0 },
142 { ALIGN_LEFT, "Port", "", 0 },
143 { ALIGN_LEFT, "", "", -1 },
59f46b7b
SB
144};
145
146static struct column *current_field = columns;
691bd854
SB
147
148/* Output buffer: chained chunks of BUF_CHUNK bytes. Each field is written to
149 * the buffer as a variable size token. A token consists of a 16 bits length
150 * field, followed by a string which is not NULL-terminated.
151 *
152 * A new chunk is allocated and linked when the current chunk doesn't have
153 * enough room to store the current token as a whole.
154 */
155struct buf_chunk {
156 struct buf_chunk *next; /* Next chained chunk */
157 char *end; /* Current end of content */
158 char data[0];
159};
160
161struct buf_token {
162 uint16_t len; /* Data length, excluding length descriptor */
163 char data[0];
164};
165
166static struct {
167 struct buf_token *cur; /* Position of current token in chunk */
168 struct buf_chunk *head; /* First chunk */
169 struct buf_chunk *tail; /* Current chunk */
170} buffer;
aba5acdf
SH
171
172static const char *TCP_PROTO = "tcp";
f89d46ad 173static const char *SCTP_PROTO = "sctp";
aba5acdf
SH
174static const char *UDP_PROTO = "udp";
175static const char *RAW_PROTO = "raw";
acd1e437 176static const char *dg_proto;
aba5acdf 177
acd1e437 178enum {
aba5acdf 179 TCP_DB,
351efcde 180 DCCP_DB,
aba5acdf
SH
181 UDP_DB,
182 RAW_DB,
183 UNIX_DG_DB,
184 UNIX_ST_DB,
30b669d7 185 UNIX_SQ_DB,
aba5acdf
SH
186 PACKET_DG_DB,
187 PACKET_R_DB,
188 NETLINK_DB,
f89d46ad 189 SCTP_DB,
c759116a
SH
190 VSOCK_ST_DB,
191 VSOCK_DG_DB,
aba5acdf
SH
192 MAX_DB
193};
194
195#define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB))
30b669d7 196#define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)|(1<<UNIX_SQ_DB))
aba5acdf 197#define ALL_DB ((1<<MAX_DB)-1)
168d97f9
SH
198#define INET_L4_DBM ((1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB)|(1<<SCTP_DB))
199#define INET_DBM (INET_L4_DBM | (1<<RAW_DB))
c759116a 200#define VSOCK_DBM ((1<<VSOCK_ST_DB)|(1<<VSOCK_DG_DB))
aba5acdf
SH
201
202enum {
7d105b56
SH
203 SS_UNKNOWN,
204 SS_ESTABLISHED,
205 SS_SYN_SENT,
206 SS_SYN_RECV,
207 SS_FIN_WAIT1,
208 SS_FIN_WAIT2,
209 SS_TIME_WAIT,
210 SS_CLOSE,
211 SS_CLOSE_WAIT,
212 SS_LAST_ACK,
213 SS_LISTEN,
214 SS_CLOSING,
215 SS_MAX
aba5acdf
SH
216};
217
f89d46ad
PS
218enum {
219 SCTP_STATE_CLOSED = 0,
220 SCTP_STATE_COOKIE_WAIT = 1,
221 SCTP_STATE_COOKIE_ECHOED = 2,
222 SCTP_STATE_ESTABLISHED = 3,
223 SCTP_STATE_SHUTDOWN_PENDING = 4,
224 SCTP_STATE_SHUTDOWN_SENT = 5,
225 SCTP_STATE_SHUTDOWN_RECEIVED = 6,
226 SCTP_STATE_SHUTDOWN_ACK_SENT = 7,
227};
228
9db7bf15
VK
229#define SS_ALL ((1 << SS_MAX) - 1)
230#define SS_CONN (SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)))
aba5acdf
SH
231
232#include "ssfilter.h"
233
acd1e437 234struct filter {
aba5acdf
SH
235 int dbs;
236 int states;
b338a3e7 237 uint64_t families;
aba5acdf 238 struct ssfilter *f;
fb2594c1 239 bool kill;
aba5acdf
SH
240};
241
b338a3e7
SH
242#define FAMILY_MASK(family) ((uint64_t)1 << (family))
243
9db7bf15
VK
244static const struct filter default_dbs[MAX_DB] = {
245 [TCP_DB] = {
246 .states = SS_CONN,
b338a3e7 247 .families = FAMILY_MASK(AF_INET) | FAMILY_MASK(AF_INET6),
9db7bf15
VK
248 },
249 [DCCP_DB] = {
250 .states = SS_CONN,
b338a3e7 251 .families = FAMILY_MASK(AF_INET) | FAMILY_MASK(AF_INET6),
9db7bf15
VK
252 },
253 [UDP_DB] = {
f42a4574 254 .states = (1 << SS_ESTABLISHED),
b338a3e7 255 .families = FAMILY_MASK(AF_INET) | FAMILY_MASK(AF_INET6),
9db7bf15
VK
256 },
257 [RAW_DB] = {
f42a4574 258 .states = (1 << SS_ESTABLISHED),
b338a3e7 259 .families = FAMILY_MASK(AF_INET) | FAMILY_MASK(AF_INET6),
9db7bf15
VK
260 },
261 [UNIX_DG_DB] = {
262 .states = (1 << SS_CLOSE),
b338a3e7 263 .families = FAMILY_MASK(AF_UNIX),
9db7bf15
VK
264 },
265 [UNIX_ST_DB] = {
266 .states = SS_CONN,
b338a3e7 267 .families = FAMILY_MASK(AF_UNIX),
9db7bf15
VK
268 },
269 [UNIX_SQ_DB] = {
270 .states = SS_CONN,
b338a3e7 271 .families = FAMILY_MASK(AF_UNIX),
9db7bf15
VK
272 },
273 [PACKET_DG_DB] = {
274 .states = (1 << SS_CLOSE),
b338a3e7 275 .families = FAMILY_MASK(AF_PACKET),
9db7bf15
VK
276 },
277 [PACKET_R_DB] = {
278 .states = (1 << SS_CLOSE),
b338a3e7 279 .families = FAMILY_MASK(AF_PACKET),
9db7bf15
VK
280 },
281 [NETLINK_DB] = {
282 .states = (1 << SS_CLOSE),
b338a3e7 283 .families = FAMILY_MASK(AF_NETLINK),
9db7bf15 284 },
f89d46ad
PS
285 [SCTP_DB] = {
286 .states = SS_CONN,
b338a3e7 287 .families = FAMILY_MASK(AF_INET) | FAMILY_MASK(AF_INET6),
f89d46ad 288 },
c759116a
SH
289 [VSOCK_ST_DB] = {
290 .states = SS_CONN,
291 .families = FAMILY_MASK(AF_VSOCK),
292 },
293 [VSOCK_DG_DB] = {
294 .states = SS_CONN,
295 .families = FAMILY_MASK(AF_VSOCK),
296 },
aba5acdf
SH
297};
298
9db7bf15
VK
299static const struct filter default_afs[AF_MAX] = {
300 [AF_INET] = {
301 .dbs = INET_DBM,
302 .states = SS_CONN,
303 },
304 [AF_INET6] = {
305 .dbs = INET_DBM,
306 .states = SS_CONN,
307 },
308 [AF_UNIX] = {
309 .dbs = UNIX_DBM,
310 .states = SS_CONN,
311 },
312 [AF_PACKET] = {
313 .dbs = PACKET_DBM,
314 .states = (1 << SS_CLOSE),
315 },
316 [AF_NETLINK] = {
317 .dbs = (1 << NETLINK_DB),
318 .states = (1 << SS_CLOSE),
319 },
c759116a
SH
320 [AF_VSOCK] = {
321 .dbs = VSOCK_DBM,
322 .states = SS_CONN,
323 },
9db7bf15
VK
324};
325
326static int do_default = 1;
327static struct filter current_filter;
328
329static void filter_db_set(struct filter *f, int db)
330{
331 f->states |= default_dbs[db].states;
9db7bf15
VK
332 f->dbs |= 1 << db;
333 do_default = 0;
334}
335
336static void filter_af_set(struct filter *f, int af)
337{
1527a17e 338 f->states |= default_afs[af].states;
b338a3e7 339 f->families |= FAMILY_MASK(af);
1527a17e
VK
340 do_default = 0;
341 preferred_family = af;
9db7bf15
VK
342}
343
344static int filter_af_get(struct filter *f, int af)
345{
b338a3e7 346 return !!(f->families & FAMILY_MASK(af));
9db7bf15
VK
347}
348
349static void filter_default_dbs(struct filter *f)
350{
351 filter_db_set(f, UDP_DB);
352 filter_db_set(f, DCCP_DB);
353 filter_db_set(f, TCP_DB);
354 filter_db_set(f, RAW_DB);
355 filter_db_set(f, UNIX_ST_DB);
356 filter_db_set(f, UNIX_DG_DB);
357 filter_db_set(f, UNIX_SQ_DB);
358 filter_db_set(f, PACKET_R_DB);
359 filter_db_set(f, PACKET_DG_DB);
360 filter_db_set(f, NETLINK_DB);
f89d46ad 361 filter_db_set(f, SCTP_DB);
c759116a
SH
362 filter_db_set(f, VSOCK_ST_DB);
363 filter_db_set(f, VSOCK_DG_DB);
9db7bf15
VK
364}
365
57ff5a10 366static void filter_states_set(struct filter *f, int states)
9db7bf15 367{
57ff5a10 368 if (states)
9d320e1e 369 f->states = states;
57ff5a10 370}
9db7bf15 371
57ff5a10
VK
372static void filter_merge_defaults(struct filter *f)
373{
374 int db;
375 int af;
9db7bf15 376
57ff5a10
VK
377 for (db = 0; db < MAX_DB; db++) {
378 if (!(f->dbs & (1 << db)))
379 continue;
9db7bf15 380
57ff5a10
VK
381 if (!(default_dbs[db].families & f->families))
382 f->families |= default_dbs[db].families;
383 }
384 for (af = 0; af < AF_MAX; af++) {
b338a3e7 385 if (!(f->families & FAMILY_MASK(af)))
57ff5a10
VK
386 continue;
387
388 if (!(default_afs[af].dbs & f->dbs))
389 f->dbs |= default_afs[af].dbs;
390 }
9db7bf15 391}
aba5acdf 392
ab01dbbb 393static FILE *generic_proc_open(const char *env, const char *name)
aba5acdf 394{
ab01dbbb 395 const char *p = getenv(env);
aba5acdf 396 char store[128];
ab01dbbb 397
aba5acdf
SH
398 if (!p) {
399 p = getenv("PROC_ROOT") ? : "/proc";
400 snprintf(store, sizeof(store)-1, "%s/%s", p, name);
401 p = store;
402 }
ab01dbbb
SH
403
404 return fopen(p, "r");
aba5acdf 405}
0cb74a86
PS
406#define net_tcp_open() generic_proc_open("PROC_NET_TCP", "net/tcp")
407#define net_tcp6_open() generic_proc_open("PROC_NET_TCP6", "net/tcp6")
408#define net_udp_open() generic_proc_open("PROC_NET_UDP", "net/udp")
409#define net_udp6_open() generic_proc_open("PROC_NET_UDP6", "net/udp6")
410#define net_raw_open() generic_proc_open("PROC_NET_RAW", "net/raw")
411#define net_raw6_open() generic_proc_open("PROC_NET_RAW6", "net/raw6")
412#define net_unix_open() generic_proc_open("PROC_NET_UNIX", "net/unix")
413#define net_packet_open() generic_proc_open("PROC_NET_PACKET", \
414 "net/packet")
415#define net_netlink_open() generic_proc_open("PROC_NET_NETLINK", \
416 "net/netlink")
417#define slabinfo_open() generic_proc_open("PROC_SLABINFO", "slabinfo")
418#define net_sockstat_open() generic_proc_open("PROC_NET_SOCKSTAT", \
419 "net/sockstat")
420#define net_sockstat6_open() generic_proc_open("PROC_NET_SOCKSTAT6", \
421 "net/sockstat6")
422#define net_snmp_open() generic_proc_open("PROC_NET_SNMP", "net/snmp")
423#define ephemeral_ports_open() generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", \
424 "sys/net/ipv4/ip_local_port_range")
aba5acdf 425
fbc0f876
SF
426struct user_ent {
427 struct user_ent *next;
428 unsigned int ino;
429 int pid;
430 int fd;
116ac927
RH
431 char *process;
432 char *process_ctx;
433 char *socket_ctx;
fbc0f876
SF
434};
435
436#define USER_ENT_HASH_SIZE 256
437struct user_ent *user_ent_hash[USER_ENT_HASH_SIZE];
438
439static int user_ent_hashfn(unsigned int ino)
aba5acdf 440{
fbc0f876 441 int val = (ino >> 24) ^ (ino >> 16) ^ (ino >> 8) ^ ino;
aba5acdf 442
fbc0f876
SF
443 return val & (USER_ENT_HASH_SIZE - 1);
444}
445
116ac927
RH
446static void user_ent_add(unsigned int ino, char *process,
447 int pid, int fd,
448 char *proc_ctx,
449 char *sock_ctx)
fbc0f876
SF
450{
451 struct user_ent *p, **pp;
aba5acdf 452
116ac927
RH
453 p = malloc(sizeof(struct user_ent));
454 if (!p) {
455 fprintf(stderr, "ss: failed to malloc buffer\n");
fbc0f876 456 abort();
116ac927 457 }
fbc0f876
SF
458 p->next = NULL;
459 p->ino = ino;
460 p->pid = pid;
461 p->fd = fd;
116ac927
RH
462 p->process = strdup(process);
463 p->process_ctx = strdup(proc_ctx);
464 p->socket_ctx = strdup(sock_ctx);
fbc0f876
SF
465
466 pp = &user_ent_hash[user_ent_hashfn(ino)];
467 p->next = *pp;
468 *pp = p;
469}
aba5acdf 470
116ac927
RH
471static void user_ent_destroy(void)
472{
473 struct user_ent *p, *p_next;
474 int cnt = 0;
475
476 while (cnt != USER_ENT_HASH_SIZE) {
477 p = user_ent_hash[cnt];
478 while (p) {
479 free(p->process);
480 free(p->process_ctx);
481 free(p->socket_ctx);
482 p_next = p->next;
483 free(p);
484 p = p_next;
485 }
486 cnt++;
487 }
488}
489
fbc0f876
SF
490static void user_ent_hash_build(void)
491{
492 const char *root = getenv("PROC_ROOT") ? : "/proc/";
493 struct dirent *d;
494 char name[1024];
495 int nameoff;
496 DIR *dir;
116ac927
RH
497 char *pid_context;
498 char *sock_context;
499 const char *no_ctx = "unavailable";
b25bad2f 500 static int user_ent_hash_build_init;
116ac927
RH
501
502 /* If show_users & show_proc_ctx set only do this once */
503 if (user_ent_hash_build_init != 0)
504 return;
505
506 user_ent_hash_build_init = 1;
fbc0f876 507
18f156bf 508 strlcpy(name, root, sizeof(name));
0ee9052f 509
fbc0f876 510 if (strlen(name) == 0 || name[strlen(name)-1] != '/')
aba5acdf 511 strcat(name, "/");
fbc0f876 512
aba5acdf 513 nameoff = strlen(name);
fbc0f876
SF
514
515 dir = opendir(name);
516 if (!dir)
517 return;
aba5acdf
SH
518
519 while ((d = readdir(dir)) != NULL) {
aba5acdf 520 struct dirent *d1;
aba5acdf 521 char process[16];
116ac927 522 char *p;
fbc0f876
SF
523 int pid, pos;
524 DIR *dir1;
525 char crap;
aba5acdf
SH
526
527 if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
528 continue;
529
116ac927
RH
530 if (getpidcon(pid, &pid_context) != 0)
531 pid_context = strdup(no_ctx);
532
0ee9052f 533 snprintf(name + nameoff, sizeof(name) - nameoff, "%d/fd/", pid);
aba5acdf 534 pos = strlen(name);
a02371fb
PS
535 if ((dir1 = opendir(name)) == NULL) {
536 free(pid_context);
aba5acdf 537 continue;
a02371fb 538 }
aba5acdf 539
fbc0f876 540 process[0] = '\0';
116ac927 541 p = process;
aba5acdf
SH
542
543 while ((d1 = readdir(dir1)) != NULL) {
fbc0f876
SF
544 const char *pattern = "socket:[";
545 unsigned int ino;
aba5acdf 546 char lnk[64];
18445b3e 547 int fd;
788731b3 548 ssize_t link_len;
116ac927 549 char tmp[1024];
aba5acdf
SH
550
551 if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
552 continue;
553
0ee9052f 554 snprintf(name+pos, sizeof(name) - pos, "%d", fd);
788731b3
TJ
555
556 link_len = readlink(name, lnk, sizeof(lnk)-1);
557 if (link_len == -1)
558 continue;
559 lnk[link_len] = '\0';
560
561 if (strncmp(lnk, pattern, strlen(pattern)))
aba5acdf
SH
562 continue;
563
fbc0f876 564 sscanf(lnk, "socket:[%u]", &ino);
aba5acdf 565
116ac927
RH
566 snprintf(tmp, sizeof(tmp), "%s/%d/fd/%s",
567 root, pid, d1->d_name);
568
569 if (getfilecon(tmp, &sock_context) <= 0)
570 sock_context = strdup(no_ctx);
571
572 if (*p == '\0') {
aba5acdf 573 FILE *fp;
fbc0f876 574
116ac927
RH
575 snprintf(tmp, sizeof(tmp), "%s/%d/stat",
576 root, pid);
aba5acdf 577 if ((fp = fopen(tmp, "r")) != NULL) {
d572ed4d
PS
578 if (fscanf(fp, "%*d (%[^)])", p) < 1)
579 ; /* ignore */
aba5acdf
SH
580 fclose(fp);
581 }
582 }
116ac927
RH
583 user_ent_add(ino, p, pid, fd,
584 pid_context, sock_context);
585 free(sock_context);
aba5acdf 586 }
116ac927 587 free(pid_context);
aba5acdf
SH
588 closedir(dir1);
589 }
590 closedir(dir);
fbc0f876
SF
591}
592
116ac927
RH
593enum entry_types {
594 USERS,
595 PROC_CTX,
596 PROC_SOCK_CTX
597};
598
599#define ENTRY_BUF_SIZE 512
acd1e437 600static int find_entry(unsigned int ino, char **buf, int type)
fbc0f876
SF
601{
602 struct user_ent *p;
603 int cnt = 0;
604 char *ptr;
532ca40a 605 char *new_buf;
116ac927
RH
606 int len, new_buf_len;
607 int buf_used = 0;
608 int buf_len = 0;
fbc0f876
SF
609
610 if (!ino)
611 return 0;
612
613 p = user_ent_hash[user_ent_hashfn(ino)];
116ac927 614 ptr = *buf = NULL;
fbc0f876
SF
615 while (p) {
616 if (p->ino != ino)
617 goto next;
618
116ac927
RH
619 while (1) {
620 ptr = *buf + buf_used;
621 switch (type) {
622 case USERS:
623 len = snprintf(ptr, buf_len - buf_used,
624 "(\"%s\",pid=%d,fd=%d),",
625 p->process, p->pid, p->fd);
626 break;
627 case PROC_CTX:
628 len = snprintf(ptr, buf_len - buf_used,
629 "(\"%s\",pid=%d,proc_ctx=%s,fd=%d),",
630 p->process, p->pid,
631 p->process_ctx, p->fd);
632 break;
633 case PROC_SOCK_CTX:
634 len = snprintf(ptr, buf_len - buf_used,
635 "(\"%s\",pid=%d,proc_ctx=%s,fd=%d,sock_ctx=%s),",
636 p->process, p->pid,
637 p->process_ctx, p->fd,
638 p->socket_ctx);
639 break;
640 default:
641 fprintf(stderr, "ss: invalid type: %d\n", type);
642 abort();
643 }
fbc0f876 644
116ac927
RH
645 if (len < 0 || len >= buf_len - buf_used) {
646 new_buf_len = buf_len + ENTRY_BUF_SIZE;
532ca40a 647 new_buf = realloc(*buf, new_buf_len);
116ac927
RH
648 if (!new_buf) {
649 fprintf(stderr, "ss: failed to malloc buffer\n");
650 abort();
651 }
532ca40a 652 *buf = new_buf;
116ac927
RH
653 buf_len = new_buf_len;
654 continue;
655 } else {
656 buf_used += len;
657 break;
658 }
659 }
fbc0f876 660 cnt++;
116ac927 661next:
fbc0f876
SF
662 p = p->next;
663 }
116ac927
RH
664 if (buf_used) {
665 ptr = *buf + buf_used;
fbc0f876 666 ptr[-1] = '\0';
116ac927 667 }
aba5acdf
SH
668 return cnt;
669}
670
aba5acdf
SH
671/* Get stats from slab */
672
acd1e437 673struct slabstat {
aba5acdf
SH
674 int socks;
675 int tcp_ports;
676 int tcp_tws;
677 int tcp_syns;
678 int skbs;
679};
680
a221d621 681static struct slabstat slabstat;
aba5acdf 682
d1f28cf1 683static int get_slabstat(struct slabstat *s)
aba5acdf
SH
684{
685 char buf[256];
686 FILE *fp;
687 int cnt;
a221d621 688 static int slabstat_valid;
b3535dd6
PS
689 static const char * const slabstat_ids[] = {
690 "sock",
691 "tcp_bind_bucket",
692 "tcp_tw_bucket",
693 "tcp_open_request",
694 "skbuff_head_cache",
695 };
a221d621
BL
696
697 if (slabstat_valid)
698 return 0;
aba5acdf
SH
699
700 memset(s, 0, sizeof(*s));
701
ab01dbbb
SH
702 fp = slabinfo_open();
703 if (!fp)
aba5acdf
SH
704 return -1;
705
706 cnt = sizeof(*s)/sizeof(int);
707
d572ed4d
PS
708 if (!fgets(buf, sizeof(buf), fp)) {
709 fclose(fp);
710 return -1;
711 }
acd1e437 712 while (fgets(buf, sizeof(buf), fp) != NULL) {
aba5acdf 713 int i;
acd1e437 714
62000e51 715 for (i = 0; i < ARRAY_SIZE(slabstat_ids); i++) {
aba5acdf
SH
716 if (memcmp(buf, slabstat_ids[i], strlen(slabstat_ids[i])) == 0) {
717 sscanf(buf, "%*s%d", ((int *)s) + i);
718 cnt--;
719 break;
720 }
721 }
722 if (cnt <= 0)
723 break;
724 }
725
a221d621
BL
726 slabstat_valid = 1;
727
aba5acdf
SH
728 fclose(fp);
729 return 0;
730}
731
2e7e805d 732static unsigned long long cookie_sk_get(const uint32_t *cookie)
f1b39e1b 733{
2e7e805d 734 return (((unsigned long long)cookie[1] << 31) << 1) | cookie[0];
f1b39e1b
VK
735}
736
f89d46ad
PS
737static const char *sctp_sstate_name[] = {
738 [SCTP_STATE_CLOSED] = "CLOSED",
739 [SCTP_STATE_COOKIE_WAIT] = "COOKIE_WAIT",
740 [SCTP_STATE_COOKIE_ECHOED] = "COOKIE_ECHOED",
741 [SCTP_STATE_ESTABLISHED] = "ESTAB",
742 [SCTP_STATE_SHUTDOWN_PENDING] = "SHUTDOWN_PENDING",
743 [SCTP_STATE_SHUTDOWN_SENT] = "SHUTDOWN_SENT",
744 [SCTP_STATE_SHUTDOWN_RECEIVED] = "SHUTDOWN_RECEIVED",
745 [SCTP_STATE_SHUTDOWN_ACK_SENT] = "ACK_SENT",
746};
747
acd1e437 748struct sockstat {
ec4d0d8a
VK
749 struct sockstat *next;
750 unsigned int type;
89f634f9 751 uint16_t prot;
41fe6c34 752 uint16_t raw_prot;
8250bc9f
VK
753 inet_prefix local;
754 inet_prefix remote;
755 int lport;
756 int rport;
757 int state;
758 int rq, wq;
acd1e437
SH
759 unsigned int ino;
760 unsigned int uid;
8250bc9f
VK
761 int refcnt;
762 unsigned int iface;
763 unsigned long long sk;
99bb68ff
VK
764 char *name;
765 char *peer_name;
ec75249b 766 __u32 mark;
055840f2
VK
767};
768
acd1e437 769struct dctcpstat {
055840f2
VK
770 unsigned int ce_state;
771 unsigned int alpha;
772 unsigned int ab_ecn;
773 unsigned int ab_tot;
774 bool enabled;
775};
776
acd1e437 777struct tcpstat {
055840f2 778 struct sockstat ss;
4cbf5224
PS
779 unsigned int timer;
780 unsigned int timeout;
8250bc9f 781 int probes;
d2055ea5 782 char cong_alg[16];
8250bc9f 783 double rto, ato, rtt, rttvar;
d1f338b3 784 int qack, ssthresh, backoff;
8250bc9f
VK
785 double send_bps;
786 int snd_wscale;
787 int rcv_wscale;
788 int mss;
38e6dbc4
ED
789 int rcv_mss;
790 int advmss;
d1f338b3 791 unsigned int cwnd;
8250bc9f
VK
792 unsigned int lastsnd;
793 unsigned int lastrcv;
794 unsigned int lastack;
795 double pacing_rate;
796 double pacing_rate_max;
2f579872 797 double delivery_rate;
1a4dda71
ED
798 unsigned long long bytes_acked;
799 unsigned long long bytes_received;
ecb435ea
CG
800 unsigned int segs_out;
801 unsigned int segs_in;
414aeec9
MKL
802 unsigned int data_segs_out;
803 unsigned int data_segs_in;
8250bc9f
VK
804 unsigned int unacked;
805 unsigned int retrans;
806 unsigned int retrans_total;
807 unsigned int lost;
808 unsigned int sacked;
809 unsigned int fackets;
810 unsigned int reordering;
9e99e495 811 unsigned int not_sent;
8250bc9f 812 double rcv_rtt;
9e99e495 813 double min_rtt;
8250bc9f 814 int rcv_space;
00ac78d3 815 unsigned int rcv_ssthresh;
b6c7fc61
YC
816 unsigned long long busy_time;
817 unsigned long long rwnd_limited;
818 unsigned long long sndbuf_limited;
8250bc9f
VK
819 bool has_ts_opt;
820 bool has_sack_opt;
821 bool has_ecn_opt;
822 bool has_ecnseen_opt;
823 bool has_fastopen_opt;
824 bool has_wscale_opt;
2f579872 825 bool app_limited;
8250bc9f 826 struct dctcpstat *dctcp;
2f0f9aef 827 struct tcp_bbr_info *bbr_info;
aba5acdf
SH
828};
829
f89d46ad
PS
830/* SCTP assocs share the same inode number with their parent endpoint. So if we
831 * have seen the inode number before, it must be an assoc instead of the next
832 * endpoint. */
833static bool is_sctp_assoc(struct sockstat *s, const char *sock_name)
834{
835 if (strcmp(sock_name, "sctp"))
836 return false;
837 if (!sctp_ino || sctp_ino != s->ino)
838 return false;
839 return true;
840}
841
be7e4d20
PS
842static const char *unix_netid_name(int type)
843{
844 switch (type) {
845 case SOCK_STREAM:
846 return "u_str";
847 case SOCK_SEQPACKET:
848 return "u_seq";
849 case SOCK_DGRAM:
850 default:
851 return "u_dgr";
852 }
853}
854
855static const char *proto_name(int protocol)
2d791bc8 856{
be7e4d20
PS
857 switch (protocol) {
858 case 0:
859 return "raw";
860 case IPPROTO_UDP:
861 return "udp";
862 case IPPROTO_TCP:
863 return "tcp";
864 case IPPROTO_SCTP:
865 return "sctp";
866 case IPPROTO_DCCP:
867 return "dccp";
572e8936
PS
868 case IPPROTO_ICMPV6:
869 return "icmp6";
be7e4d20
PS
870 }
871
872 return "???";
873}
874
c759116a
SH
875static const char *vsock_netid_name(int type)
876{
877 switch (type) {
878 case SOCK_STREAM:
879 return "v_str";
880 case SOCK_DGRAM:
881 return "v_dgr";
882 default:
883 return "???";
884 }
885}
886
691bd854
SB
887/* Allocate and initialize a new buffer chunk */
888static struct buf_chunk *buf_chunk_new(void)
889{
890 struct buf_chunk *new = malloc(BUF_CHUNK);
891
892 if (!new)
893 abort();
894
895 new->next = NULL;
896
897 /* This is also the last block */
898 buffer.tail = new;
899
900 /* Next token will be stored at the beginning of chunk data area, and
901 * its initial length is zero.
902 */
903 buffer.cur = (struct buf_token *)new->data;
904 buffer.cur->len = 0;
905
906 new->end = buffer.cur->data;
907
908 return new;
909}
910
911/* Return available tail room in given chunk */
912static int buf_chunk_avail(struct buf_chunk *chunk)
913{
914 return BUF_CHUNK - offsetof(struct buf_chunk, data) -
915 (chunk->end - chunk->data);
916}
917
918/* Update end pointer and token length, link new chunk if we hit the end of the
919 * current one. Return -EAGAIN if we got a new chunk, caller has to print again.
920 */
921static int buf_update(int len)
922{
923 struct buf_chunk *chunk = buffer.tail;
924 struct buf_token *t = buffer.cur;
925
926 /* Claim success if new content fits in the current chunk, and anyway
927 * if this is the first token in the chunk: in the latter case,
928 * allocating a new chunk won't help, so we'll just cut the output.
929 */
930 if ((len < buf_chunk_avail(chunk) && len != -1 /* glibc < 2.0.6 */) ||
931 t == (struct buf_token *)chunk->data) {
932 len = min(len, buf_chunk_avail(chunk));
933
934 /* Total field length can't exceed 2^16 bytes, cut as needed */
935 len = min(len, USHRT_MAX - t->len);
936
937 chunk->end += len;
938 t->len += len;
939 return 0;
940 }
941
942 /* Content truncated, time to allocate more */
943 chunk->next = buf_chunk_new();
944
945 /* Copy current token over to new chunk, including length descriptor */
946 memcpy(chunk->next->data, t, sizeof(t->len) + t->len);
947 chunk->next->end += t->len;
948
949 /* Discard partially written field in old chunk */
950 chunk->end -= t->len + sizeof(t->len);
951
952 return -EAGAIN;
953}
954
955/* Append content to buffer as part of the current field */
90351722
SB
956static void out(const char *fmt, ...)
957{
59f46b7b 958 struct column *f = current_field;
90351722 959 va_list args;
691bd854
SB
960 char *pos;
961 int len;
962
963 if (!f->width)
964 return;
965
966 if (!buffer.head)
967 buffer.head = buf_chunk_new();
968
969again: /* Append to buffer: if we have a new chunk, print again */
90351722 970
691bd854 971 pos = buffer.cur->data + buffer.cur->len;
90351722 972 va_start(args, fmt);
691bd854
SB
973
974 /* Limit to tail room. If we hit the limit, buf_update() will tell us */
975 len = vsnprintf(pos, buf_chunk_avail(buffer.tail), fmt, args);
90351722 976 va_end(args);
691bd854
SB
977
978 if (buf_update(len))
979 goto again;
90351722
SB
980}
981
691bd854 982static int print_left_spacing(struct column *f, int stored, int printed)
59f46b7b
SB
983{
984 int s;
985
986 if (f->width < 0 || f->align == ALIGN_LEFT)
987 return 0;
988
691bd854 989 s = f->width - stored - printed;
59f46b7b
SB
990 if (f->align == ALIGN_CENTER)
991 /* If count of total spacing is odd, shift right by one */
992 s = (s + 1) / 2;
993
994 if (s > 0)
995 return printf("%*c", s, ' ');
996
997 return 0;
998}
999
691bd854 1000static void print_right_spacing(struct column *f, int printed)
59f46b7b
SB
1001{
1002 int s;
1003
1004 if (f->width < 0 || f->align == ALIGN_RIGHT)
1005 return;
1006
691bd854 1007 s = f->width - printed;
59f46b7b
SB
1008 if (f->align == ALIGN_CENTER)
1009 s /= 2;
1010
1011 if (s > 0)
1012 printf("%*c", s, ' ');
1013}
1014
691bd854 1015/* Done with field: update buffer pointer, start new token after current one */
59f46b7b
SB
1016static void field_flush(struct column *f)
1017{
691bd854
SB
1018 struct buf_chunk *chunk = buffer.tail;
1019 unsigned int pad = buffer.cur->len % 2;
1020
59f46b7b
SB
1021 if (!f->width)
1022 return;
1023
691bd854
SB
1024 /* We need a new chunk if we can't store the next length descriptor.
1025 * Mind the gap between end of previous token and next aligned position
1026 * for length descriptor.
1027 */
1028 if (buf_chunk_avail(chunk) - pad < sizeof(buffer.cur->len)) {
1029 chunk->end += pad;
1030 chunk->next = buf_chunk_new();
1031 return;
1032 }
59f46b7b 1033
691bd854
SB
1034 buffer.cur = (struct buf_token *)(buffer.cur->data +
1035 LEN_ALIGN(buffer.cur->len));
1036 buffer.cur->len = 0;
1037 buffer.tail->end = buffer.cur->data;
59f46b7b
SB
1038}
1039
1040static int field_is_last(struct column *f)
1041{
1042 return f - columns == COL_MAX - 1;
1043}
1044
1045static void field_next(void)
1046{
1047 field_flush(current_field);
1048
691bd854 1049 if (field_is_last(current_field))
59f46b7b 1050 current_field = columns;
691bd854 1051 else
59f46b7b 1052 current_field++;
59f46b7b
SB
1053}
1054
1055/* Walk through fields and flush them until we reach the desired one */
1056static void field_set(enum col_id id)
1057{
1058 while (id != current_field - columns)
1059 field_next();
1060}
1061
1062/* Print header for all non-empty columns */
1063static void print_header(void)
1064{
1065 while (!field_is_last(current_field)) {
1066 if (current_field->width)
1067 out(current_field->header);
1068 field_next();
1069 }
1070}
1071
691bd854
SB
1072/* Get the next available token in the buffer starting from the current token */
1073static struct buf_token *buf_token_next(struct buf_token *cur)
1074{
1075 struct buf_chunk *chunk = buffer.tail;
1076
1077 /* If we reached the end of chunk contents, get token from next chunk */
1078 if (cur->data + LEN_ALIGN(cur->len) == chunk->end) {
1079 buffer.tail = chunk = chunk->next;
1080 return chunk ? (struct buf_token *)chunk->data : NULL;
1081 }
1082
1083 return (struct buf_token *)(cur->data + LEN_ALIGN(cur->len));
1084}
1085
1086/* Free up all allocated buffer chunks */
1087static void buf_free_all(void)
1088{
1089 struct buf_chunk *tmp;
1090
1091 for (buffer.tail = buffer.head; buffer.tail; ) {
1092 tmp = buffer.tail;
1093 buffer.tail = buffer.tail->next;
1094 free(tmp);
1095 }
1096 buffer.head = NULL;
1097}
1098
1099/* Render buffered output with spacing and delimiters, then free up buffers */
1100static void render(void)
1101{
1102 struct buf_token *token = (struct buf_token *)buffer.head->data;
1103 int printed, line_started = 0, need_newline = 0;
1104 struct column *f;
1105
1106 /* Ensure end alignment of last token, it wasn't necessarily flushed */
1107 buffer.tail->end += buffer.cur->len % 2;
1108
1109 /* Rewind and replay */
1110 buffer.tail = buffer.head;
1111
1112 f = columns;
1113 while (!f->width)
1114 f++;
1115
1116 while (token) {
1117 /* Print left delimiter only if we already started a line */
1118 if (line_started++)
1119 printed = printf("%s", current_field->ldelim);
1120 else
1121 printed = 0;
1122
1123 /* Print field content from token data with spacing */
1124 printed += print_left_spacing(f, token->len, printed);
1125 printed += fwrite(token->data, 1, token->len, stdout);
1126 print_right_spacing(f, printed);
1127
1128 /* Variable field size or overflow, won't align to screen */
1129 if (printed > f->width)
1130 need_newline = 1;
1131
1132 /* Go to next non-empty field, deal with end-of-line */
1133 do {
1134 if (field_is_last(f)) {
1135 if (need_newline) {
1136 printf("\n");
1137 need_newline = 0;
1138 }
1139 f = columns;
1140 line_started = 0;
1141 } else {
1142 f++;
1143 }
1144 } while (!f->width);
1145
1146 token = buf_token_next(token);
1147 }
1148
1149 buf_free_all();
1150}
1151
be7e4d20
PS
1152static void sock_state_print(struct sockstat *s)
1153{
1154 const char *sock_name;
1882c0db
PS
1155 static const char * const sstate_name[] = {
1156 "UNKNOWN",
1157 [SS_ESTABLISHED] = "ESTAB",
1158 [SS_SYN_SENT] = "SYN-SENT",
1159 [SS_SYN_RECV] = "SYN-RECV",
1160 [SS_FIN_WAIT1] = "FIN-WAIT-1",
1161 [SS_FIN_WAIT2] = "FIN-WAIT-2",
1162 [SS_TIME_WAIT] = "TIME-WAIT",
1163 [SS_CLOSE] = "UNCONN",
1164 [SS_CLOSE_WAIT] = "CLOSE-WAIT",
1165 [SS_LAST_ACK] = "LAST-ACK",
1166 [SS_LISTEN] = "LISTEN",
1167 [SS_CLOSING] = "CLOSING",
1168 };
be7e4d20
PS
1169
1170 switch (s->local.family) {
1171 case AF_UNIX:
1172 sock_name = unix_netid_name(s->type);
1173 break;
1174 case AF_INET:
1175 case AF_INET6:
1176 sock_name = proto_name(s->type);
1177 break;
1178 case AF_PACKET:
1179 sock_name = s->type == SOCK_RAW ? "p_raw" : "p_dgr";
1180 break;
1181 case AF_NETLINK:
1182 sock_name = "nl";
1183 break;
c759116a
SH
1184 case AF_VSOCK:
1185 sock_name = vsock_netid_name(s->type);
1186 break;
be7e4d20
PS
1187 default:
1188 sock_name = "unknown";
1189 }
1190
59f46b7b
SB
1191 if (is_sctp_assoc(s, sock_name)) {
1192 field_set(COL_STATE); /* Empty Netid field */
1193 out("`- %s", sctp_sstate_name[s->state]);
1194 } else {
1195 field_set(COL_NETID);
1196 out("%s", sock_name);
1197 field_set(COL_STATE);
1198 out("%s", sstate_name[s->state]);
f89d46ad 1199 }
2d791bc8 1200
59f46b7b
SB
1201 field_set(COL_RECVQ);
1202 out("%-6d", s->rq);
1203 field_set(COL_SENDQ);
1204 out("%-6d", s->wq);
1205 field_set(COL_ADDR);
2d791bc8
VK
1206}
1207
f1b39e1b
VK
1208static void sock_details_print(struct sockstat *s)
1209{
1210 if (s->uid)
90351722 1211 out(" uid:%u", s->uid);
f1b39e1b 1212
90351722
SB
1213 out(" ino:%u", s->ino);
1214 out(" sk:%llx", s->sk);
ec75249b
LC
1215
1216 if (s->mark)
90351722 1217 out(" fwmark:0x%x", s->mark);
f1b39e1b
VK
1218}
1219
b217df10
VK
1220static void sock_addr_print(const char *addr, char *delim, const char *port,
1221 const char *ifname)
1222{
59f46b7b
SB
1223 if (ifname)
1224 out("%s" "%%" "%s%s", addr, ifname, delim);
1225 else
1226 out("%s%s", addr, delim);
1227
1228 field_next();
1229 out("%s", port);
1230 field_next();
b217df10
VK
1231}
1232
4cbf5224 1233static const char *print_ms_timer(unsigned int timeout)
aba5acdf
SH
1234{
1235 static char buf[64];
1236 int secs, msecs, minutes;
acd1e437 1237
aba5acdf
SH
1238 secs = timeout/1000;
1239 minutes = secs/60;
1240 secs = secs%60;
1241 msecs = timeout%1000;
1242 buf[0] = 0;
1243 if (minutes) {
1244 msecs = 0;
1245 snprintf(buf, sizeof(buf)-16, "%dmin", minutes);
1246 if (minutes > 9)
1247 secs = 0;
1248 }
1249 if (secs) {
1250 if (secs > 9)
1251 msecs = 0;
1252 sprintf(buf+strlen(buf), "%d%s", secs, msecs ? "." : "sec");
1253 }
1254 if (msecs)
1255 sprintf(buf+strlen(buf), "%03dms", msecs);
1256 return buf;
e7113c61 1257}
aba5acdf 1258
22588a0e 1259struct scache {
aba5acdf
SH
1260 struct scache *next;
1261 int port;
1262 char *name;
1263 const char *proto;
1264};
1265
1266struct scache *rlist;
1267
d1f28cf1 1268static void init_service_resolver(void)
aba5acdf
SH
1269{
1270 char buf[128];
1271 FILE *fp = popen("/usr/sbin/rpcinfo -p 2>/dev/null", "r");
596307ea
PS
1272
1273 if (!fp)
1274 return;
1275
1276 if (!fgets(buf, sizeof(buf), fp)) {
2bcc3c16 1277 pclose(fp);
596307ea
PS
1278 return;
1279 }
1280 while (fgets(buf, sizeof(buf), fp) != NULL) {
1281 unsigned int progn, port;
1282 char proto[128], prog[128] = "rpc.";
1283 struct scache *c;
1284
1285 if (sscanf(buf, "%u %*d %s %u %s",
acd1e437 1286 &progn, proto, &port, prog+4) != 4)
596307ea
PS
1287 continue;
1288
1289 if (!(c = malloc(sizeof(*c))))
1290 continue;
1291
1292 c->port = port;
1293 c->name = strdup(prog);
1294 if (strcmp(proto, TCP_PROTO) == 0)
1295 c->proto = TCP_PROTO;
1296 else if (strcmp(proto, UDP_PROTO) == 0)
1297 c->proto = UDP_PROTO;
f89d46ad
PS
1298 else if (strcmp(proto, SCTP_PROTO) == 0)
1299 c->proto = SCTP_PROTO;
596307ea
PS
1300 else
1301 c->proto = NULL;
1302 c->next = rlist;
1303 rlist = c;
aba5acdf 1304 }
596307ea 1305 pclose(fp);
aba5acdf
SH
1306}
1307
ab61159a
SH
1308/* Even do not try default linux ephemeral port ranges:
1309 * default /etc/services contains so much of useless crap
1310 * wouldbe "allocated" to this area that resolution
1311 * is really harmful. I shrug each time when seeing
1312 * "socks" or "cfinger" in dumps.
1313 */
1314static int is_ephemeral(int port)
1315{
acd1e437 1316 static int min = 0, max;
c29d3792
PS
1317
1318 if (!min) {
ab01dbbb 1319 FILE *f = ephemeral_ports_open();
acd1e437 1320
c29d3792
PS
1321 if (!f || fscanf(f, "%d %d", &min, &max) < 2) {
1322 min = 1024;
1323 max = 4999;
ab61159a 1324 }
c29d3792
PS
1325 if (f)
1326 fclose(f);
ab61159a 1327 }
c29d3792 1328 return port >= min && port <= max;
ab61159a
SH
1329}
1330
1331
d1f28cf1 1332static const char *__resolve_service(int port)
aba5acdf
SH
1333{
1334 struct scache *c;
1335
1336 for (c = rlist; c; c = c->next) {
1337 if (c->port == port && c->proto == dg_proto)
1338 return c->name;
1339 }
1340
ab61159a 1341 if (!is_ephemeral(port)) {
aba5acdf
SH
1342 static int notfirst;
1343 struct servent *se;
acd1e437 1344
aba5acdf
SH
1345 if (!notfirst) {
1346 setservent(1);
1347 notfirst = 1;
ae665a52 1348 }
aba5acdf
SH
1349 se = getservbyport(htons(port), dg_proto);
1350 if (se)
1351 return se->s_name;
1352 }
1353
1354 return NULL;
1355}
1356
22588a0e
ED
1357#define SCACHE_BUCKETS 1024
1358static struct scache *cache_htab[SCACHE_BUCKETS];
aba5acdf 1359
d1f28cf1 1360static const char *resolve_service(int port)
aba5acdf
SH
1361{
1362 static char buf[128];
22588a0e
ED
1363 struct scache *c;
1364 const char *res;
1365 int hash;
aba5acdf
SH
1366
1367 if (port == 0) {
1368 buf[0] = '*';
1369 buf[1] = 0;
1370 return buf;
1371 }
1372
22588a0e
ED
1373 if (!resolve_services)
1374 goto do_numeric;
aba5acdf 1375
22588a0e
ED
1376 if (dg_proto == RAW_PROTO)
1377 return inet_proto_n2a(port, buf, sizeof(buf));
1378
1379
1380 hash = (port^(((unsigned long)dg_proto)>>2)) % SCACHE_BUCKETS;
1381
1382 for (c = cache_htab[hash]; c; c = c->next) {
1383 if (c->port == port && c->proto == dg_proto)
1384 goto do_cache;
aba5acdf
SH
1385 }
1386
22588a0e
ED
1387 c = malloc(sizeof(*c));
1388 if (!c)
1389 goto do_numeric;
1390 res = __resolve_service(port);
1391 c->port = port;
1392 c->name = res ? strdup(res) : NULL;
1393 c->proto = dg_proto;
1394 c->next = cache_htab[hash];
1395 cache_htab[hash] = c;
1396
1397do_cache:
1398 if (c->name)
1399 return c->name;
1400
1401do_numeric:
aba5acdf
SH
1402 sprintf(buf, "%u", port);
1403 return buf;
1404}
1405
1267c0b9
PS
1406static void inet_addr_print(const inet_prefix *a, int port,
1407 unsigned int ifindex, bool v6only)
aba5acdf
SH
1408{
1409 char buf[1024];
1410 const char *ap = buf;
b217df10 1411 const char *ifname = NULL;
aba5acdf
SH
1412
1413 if (a->family == AF_INET) {
1267c0b9 1414 ap = format_host(AF_INET, 4, a->data);
aba5acdf 1415 } else {
1267c0b9
PS
1416 if (!v6only &&
1417 !memcmp(a->data, &in6addr_any, sizeof(in6addr_any))) {
aba9c23a
SH
1418 buf[0] = '*';
1419 buf[1] = 0;
1420 } else {
1421 ap = format_host(a->family, 16, a->data);
1422
1423 /* Numeric IPv6 addresses should be bracketed */
1424 if (strchr(ap, ':')) {
1425 snprintf(buf, sizeof(buf),
1426 "[%s]", ap);
1427 ap = buf;
1428 }
aba9c23a 1429 }
aba5acdf 1430 }
b217df10 1431
59f46b7b
SB
1432 if (ifindex)
1433 ifname = ll_index_to_name(ifindex);
7c8a3cfb 1434
59f46b7b 1435 sock_addr_print(ap, ":", resolve_service(port), ifname);
aba5acdf
SH
1436}
1437
acd1e437 1438struct aafilter {
aba5acdf
SH
1439 inet_prefix addr;
1440 int port;
2d293212 1441 unsigned int iface;
ec75249b
LC
1442 __u32 mark;
1443 __u32 mask;
aba5acdf
SH
1444 struct aafilter *next;
1445};
1446
d1f28cf1
SH
1447static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
1448 int plen)
aba5acdf
SH
1449{
1450 if (!inet_addr_match(a, p, plen))
1451 return 0;
7d105b56 1452
aba5acdf
SH
1453 /* Cursed "v4 mapped" addresses: v4 mapped socket matches
1454 * pure IPv4 rule, but v4-mapped rule selects only v4-mapped
1455 * sockets. Fair? */
1456 if (p->family == AF_INET && a->family == AF_INET6) {
1457 if (a->data[0] == 0 && a->data[1] == 0 &&
1458 a->data[2] == htonl(0xffff)) {
1459 inet_prefix tmp = *a;
acd1e437 1460
aba5acdf
SH
1461 tmp.data[0] = a->data[3];
1462 return inet_addr_match(&tmp, p, plen);
1463 }
1464 }
1465 return 1;
1466}
1467
d1f28cf1 1468static int unix_match(const inet_prefix *a, const inet_prefix *p)
aba5acdf 1469{
99bb68ff 1470 char *addr, *pattern;
acd1e437 1471
99bb68ff
VK
1472 memcpy(&addr, a->data, sizeof(addr));
1473 memcpy(&pattern, p->data, sizeof(pattern));
aba5acdf
SH
1474 if (pattern == NULL)
1475 return 1;
1476 if (addr == NULL)
1477 addr = "";
1478 return !fnmatch(pattern, addr, 0);
1479}
1480
055840f2 1481static int run_ssfilter(struct ssfilter *f, struct sockstat *s)
aba5acdf
SH
1482{
1483 switch (f->type) {
1484 case SSF_S_AUTO:
1485 {
aba5acdf 1486 if (s->local.family == AF_UNIX) {
99bb68ff 1487 char *p;
acd1e437 1488
99bb68ff 1489 memcpy(&p, s->local.data, sizeof(p));
aba5acdf 1490 return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
ae665a52 1491 strspn(p+1, "0123456789abcdef") == 5);
aba5acdf
SH
1492 }
1493 if (s->local.family == AF_PACKET)
bbd303d1 1494 return s->lport == 0 && s->local.data[0] == 0;
aba5acdf
SH
1495 if (s->local.family == AF_NETLINK)
1496 return s->lport < 0;
c759116a
SH
1497 if (s->local.family == AF_VSOCK)
1498 return s->lport > 1023;
aba5acdf 1499
c29d3792 1500 return is_ephemeral(s->lport);
aba5acdf
SH
1501 }
1502 case SSF_DCOND:
1503 {
acd1e437
SH
1504 struct aafilter *a = (void *)f->pred;
1505
aba5acdf
SH
1506 if (a->addr.family == AF_UNIX)
1507 return unix_match(&s->remote, &a->addr);
1508 if (a->port != -1 && a->port != s->rport)
1509 return 0;
1510 if (a->addr.bitlen) {
1511 do {
1512 if (!inet2_addr_match(&s->remote, &a->addr, a->addr.bitlen))
1513 return 1;
1514 } while ((a = a->next) != NULL);
1515 return 0;
1516 }
1517 return 1;
1518 }
1519 case SSF_SCOND:
1520 {
acd1e437
SH
1521 struct aafilter *a = (void *)f->pred;
1522
aba5acdf
SH
1523 if (a->addr.family == AF_UNIX)
1524 return unix_match(&s->local, &a->addr);
1525 if (a->port != -1 && a->port != s->lport)
1526 return 0;
1527 if (a->addr.bitlen) {
1528 do {
1529 if (!inet2_addr_match(&s->local, &a->addr, a->addr.bitlen))
1530 return 1;
ae665a52 1531 } while ((a = a->next) != NULL);
aba5acdf
SH
1532 return 0;
1533 }
1534 return 1;
1535 }
1536 case SSF_D_GE:
1537 {
acd1e437
SH
1538 struct aafilter *a = (void *)f->pred;
1539
aba5acdf
SH
1540 return s->rport >= a->port;
1541 }
1542 case SSF_D_LE:
1543 {
acd1e437
SH
1544 struct aafilter *a = (void *)f->pred;
1545
aba5acdf
SH
1546 return s->rport <= a->port;
1547 }
1548 case SSF_S_GE:
1549 {
acd1e437
SH
1550 struct aafilter *a = (void *)f->pred;
1551
aba5acdf
SH
1552 return s->lport >= a->port;
1553 }
1554 case SSF_S_LE:
1555 {
acd1e437
SH
1556 struct aafilter *a = (void *)f->pred;
1557
aba5acdf
SH
1558 return s->lport <= a->port;
1559 }
2d293212
DA
1560 case SSF_DEVCOND:
1561 {
1562 struct aafilter *a = (void *)f->pred;
aba5acdf 1563
2d293212 1564 return s->iface == a->iface;
ec75249b
LC
1565 }
1566 case SSF_MARKMASK:
1567 {
1568 struct aafilter *a = (void *)f->pred;
1569
1570 return (s->mark & a->mask) == a->mark;
2d293212 1571 }
aba5acdf
SH
1572 /* Yup. It is recursion. Sorry. */
1573 case SSF_AND:
1574 return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s);
1575 case SSF_OR:
1576 return run_ssfilter(f->pred, s) || run_ssfilter(f->post, s);
1577 case SSF_NOT:
1578 return !run_ssfilter(f->pred, s);
1579 default:
1580 abort();
1581 }
1582}
1583
ae665a52 1584/* Relocate external jumps by reloc. */
b4b0b7d5 1585static void ssfilter_patch(char *a, int len, int reloc)
aba5acdf
SH
1586{
1587 while (len > 0) {
acd1e437
SH
1588 struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)a;
1589
aba5acdf
SH
1590 if (op->no == len+4)
1591 op->no += reloc;
1592 len -= op->yes;
1593 a += op->yes;
1594 }
1595 if (len < 0)
1596 abort();
1597}
1598
b4b0b7d5 1599static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
aba5acdf
SH
1600{
1601 switch (f->type) {
1602 case SSF_S_AUTO:
1603 {
acd1e437
SH
1604 if (!(*bytecode = malloc(4))) abort();
1605 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 };
df39de8d 1606 return 4;
aba5acdf
SH
1607 }
1608 case SSF_DCOND:
1609 case SSF_SCOND:
1610 {
acd1e437 1611 struct aafilter *a = (void *)f->pred;
aba5acdf
SH
1612 struct aafilter *b;
1613 char *ptr;
351efcde 1614 int code = (f->type == SSF_DCOND ? INET_DIAG_BC_D_COND : INET_DIAG_BC_S_COND);
aba5acdf
SH
1615 int len = 0;
1616
acd1e437 1617 for (b = a; b; b = b->next) {
351efcde 1618 len += 4 + sizeof(struct inet_diag_hostcond);
aba5acdf
SH
1619 if (a->addr.family == AF_INET6)
1620 len += 16;
1621 else
1622 len += 4;
1623 if (b->next)
1624 len += 4;
1625 }
1626 if (!(ptr = malloc(len))) abort();
1627 *bytecode = ptr;
acd1e437 1628 for (b = a; b; b = b->next) {
351efcde 1629 struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)ptr;
aba5acdf 1630 int alen = (a->addr.family == AF_INET6 ? 16 : 4);
351efcde 1631 int oplen = alen + 4 + sizeof(struct inet_diag_hostcond);
acd1e437 1632 struct inet_diag_hostcond *cond = (struct inet_diag_hostcond *)(ptr+4);
aba5acdf 1633
351efcde 1634 *op = (struct inet_diag_bc_op){ code, oplen, oplen+4 };
aba5acdf
SH
1635 cond->family = a->addr.family;
1636 cond->port = a->port;
1637 cond->prefix_len = a->addr.bitlen;
1638 memcpy(cond->addr, a->addr.data, alen);
1639 ptr += oplen;
1640 if (b->next) {
351efcde
SH
1641 op = (struct inet_diag_bc_op *)ptr;
1642 *op = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, len - (ptr-*bytecode)};
aba5acdf
SH
1643 ptr += 4;
1644 }
1645 }
1646 return ptr - *bytecode;
1647 }
1648 case SSF_D_GE:
1649 {
acd1e437
SH
1650 struct aafilter *x = (void *)f->pred;
1651
1652 if (!(*bytecode = malloc(8))) abort();
1653 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 };
1654 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1655 return 8;
1656 }
1657 case SSF_D_LE:
1658 {
acd1e437
SH
1659 struct aafilter *x = (void *)f->pred;
1660
1661 if (!(*bytecode = malloc(8))) abort();
1662 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 };
1663 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1664 return 8;
1665 }
1666 case SSF_S_GE:
1667 {
acd1e437
SH
1668 struct aafilter *x = (void *)f->pred;
1669
1670 if (!(*bytecode = malloc(8))) abort();
1671 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 };
1672 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1673 return 8;
1674 }
1675 case SSF_S_LE:
1676 {
acd1e437
SH
1677 struct aafilter *x = (void *)f->pred;
1678
1679 if (!(*bytecode = malloc(8))) abort();
1680 ((struct inet_diag_bc_op *)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 };
1681 ((struct inet_diag_bc_op *)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
aba5acdf
SH
1682 return 8;
1683 }
1684
1685 case SSF_AND:
1686 {
376fb868 1687 char *a1 = NULL, *a2 = NULL, *a;
2a4fa1c3 1688 int l1, l2;
acd1e437 1689
aba5acdf
SH
1690 l1 = ssfilter_bytecompile(f->pred, &a1);
1691 l2 = ssfilter_bytecompile(f->post, &a2);
376fb868
DA
1692 if (!l1 || !l2) {
1693 free(a1);
1694 free(a2);
1695 return 0;
1696 }
aba5acdf
SH
1697 if (!(a = malloc(l1+l2))) abort();
1698 memcpy(a, a1, l1);
1699 memcpy(a+l1, a2, l2);
1700 free(a1); free(a2);
1701 ssfilter_patch(a, l1, l2);
1702 *bytecode = a;
1703 return l1+l2;
1704 }
1705 case SSF_OR:
1706 {
376fb868 1707 char *a1 = NULL, *a2 = NULL, *a;
2a4fa1c3 1708 int l1, l2;
acd1e437 1709
aba5acdf
SH
1710 l1 = ssfilter_bytecompile(f->pred, &a1);
1711 l2 = ssfilter_bytecompile(f->post, &a2);
376fb868
DA
1712 if (!l1 || !l2) {
1713 free(a1);
1714 free(a2);
1715 return 0;
1716 }
aba5acdf
SH
1717 if (!(a = malloc(l1+l2+4))) abort();
1718 memcpy(a, a1, l1);
1719 memcpy(a+l1+4, a2, l2);
1720 free(a1); free(a2);
acd1e437 1721 *(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 };
aba5acdf
SH
1722 *bytecode = a;
1723 return l1+l2+4;
1724 }
1725 case SSF_NOT:
1726 {
376fb868 1727 char *a1 = NULL, *a;
2a4fa1c3 1728 int l1;
acd1e437 1729
aba5acdf 1730 l1 = ssfilter_bytecompile(f->pred, &a1);
376fb868
DA
1731 if (!l1) {
1732 free(a1);
1733 return 0;
1734 }
aba5acdf
SH
1735 if (!(a = malloc(l1+4))) abort();
1736 memcpy(a, a1, l1);
1737 free(a1);
acd1e437 1738 *(struct inet_diag_bc_op *)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 };
aba5acdf
SH
1739 *bytecode = a;
1740 return l1+4;
2d293212
DA
1741 }
1742 case SSF_DEVCOND:
1743 {
1744 /* bytecompile for SSF_DEVCOND not supported yet */
1745 return 0;
ec75249b
LC
1746 }
1747 case SSF_MARKMASK:
1748 {
1749 struct aafilter *a = (void *)f->pred;
1750 struct instr {
1751 struct inet_diag_bc_op op;
1752 struct inet_diag_markcond cond;
1753 };
1754 int inslen = sizeof(struct instr);
1755
1756 if (!(*bytecode = malloc(inslen))) abort();
1757 ((struct instr *)*bytecode)[0] = (struct instr) {
1758 { INET_DIAG_BC_MARK_COND, inslen, inslen + 4 },
1759 { a->mark, a->mask},
1760 };
1761
1762 return inslen;
aba5acdf
SH
1763 }
1764 default:
1765 abort();
1766 }
1767}
1768
b4b0b7d5 1769static int remember_he(struct aafilter *a, struct hostent *he)
aba5acdf 1770{
ae665a52 1771 char **ptr = he->h_addr_list;
aba5acdf
SH
1772 int cnt = 0;
1773 int len;
1774
1775 if (he->h_addrtype == AF_INET)
1776 len = 4;
1777 else if (he->h_addrtype == AF_INET6)
1778 len = 16;
1779 else
1780 return 0;
1781
1782 while (*ptr) {
1783 struct aafilter *b = a;
acd1e437 1784
aba5acdf
SH
1785 if (a->addr.bitlen) {
1786 if ((b = malloc(sizeof(*b))) == NULL)
1787 return cnt;
1788 *b = *a;
aba5acdf
SH
1789 a->next = b;
1790 }
1791 memcpy(b->addr.data, *ptr, len);
1792 b->addr.bytelen = len;
1793 b->addr.bitlen = len*8;
1794 b->addr.family = he->h_addrtype;
1795 ptr++;
1796 cnt++;
1797 }
1798 return cnt;
1799}
1800
b4b0b7d5 1801static int get_dns_host(struct aafilter *a, const char *addr, int fam)
aba5acdf
SH
1802{
1803 static int notfirst;
1804 int cnt = 0;
1805 struct hostent *he;
1806
1807 a->addr.bitlen = 0;
1808 if (!notfirst) {
1809 sethostent(1);
1810 notfirst = 1;
1811 }
1812 he = gethostbyname2(addr, fam == AF_UNSPEC ? AF_INET : fam);
1813 if (he)
1814 cnt = remember_he(a, he);
1815 if (fam == AF_UNSPEC) {
1816 he = gethostbyname2(addr, AF_INET6);
1817 if (he)
1818 cnt += remember_he(a, he);
1819 }
1820 return !cnt;
1821}
1822
acd1e437 1823static int xll_initted;
aba5acdf 1824
b4b0b7d5 1825static void xll_init(void)
aba5acdf
SH
1826{
1827 struct rtnl_handle rth;
acd1e437 1828
d2468da0
SH
1829 if (rtnl_open(&rth, 0) < 0)
1830 exit(1);
1831
aba5acdf
SH
1832 ll_init_map(&rth);
1833 rtnl_close(&rth);
1834 xll_initted = 1;
1835}
1836
b4b0b7d5 1837static const char *xll_index_to_name(int index)
aba5acdf
SH
1838{
1839 if (!xll_initted)
1840 xll_init();
1841 return ll_index_to_name(index);
1842}
1843
b4b0b7d5 1844static int xll_name_to_index(const char *dev)
aba5acdf
SH
1845{
1846 if (!xll_initted)
1847 xll_init();
1848 return ll_name_to_index(dev);
1849}
1850
2d293212
DA
1851void *parse_devcond(char *name)
1852{
1853 struct aafilter a = { .iface = 0 };
1854 struct aafilter *res;
1855
1856 a.iface = xll_name_to_index(name);
1857 if (a.iface == 0) {
1858 char *end;
930d3f28 1859 unsigned long n;
2d293212 1860
930d3f28
DA
1861 n = strtoul(name, &end, 0);
1862 if (!end || end == name || *end || n > UINT_MAX)
2d293212 1863 return NULL;
930d3f28
DA
1864
1865 a.iface = n;
2d293212
DA
1866 }
1867
1868 res = malloc(sizeof(*res));
1869 *res = a;
1870
1871 return res;
1872}
1873
c759116a
SH
1874static void vsock_set_inet_prefix(inet_prefix *a, __u32 cid)
1875{
1876 *a = (inet_prefix){
1877 .bytelen = sizeof(cid),
1878 .family = AF_VSOCK,
1879 };
1880 memcpy(a->data, &cid, sizeof(cid));
1881}
1882
7871f7db 1883void *parse_hostcond(char *addr, bool is_port)
aba5acdf
SH
1884{
1885 char *port = NULL;
1527a17e 1886 struct aafilter a = { .port = -1 };
aba5acdf 1887 struct aafilter *res;
1527a17e 1888 int fam = preferred_family;
9db7bf15 1889 struct filter *f = &current_filter;
aba5acdf 1890
1527a17e 1891 if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) {
aba5acdf 1892 char *p;
acd1e437 1893
aba5acdf
SH
1894 a.addr.family = AF_UNIX;
1895 if (strncmp(addr, "unix:", 5) == 0)
acd1e437 1896 addr += 5;
aba5acdf
SH
1897 p = strdup(addr);
1898 a.addr.bitlen = 8*strlen(p);
99bb68ff 1899 memcpy(a.addr.data, &p, sizeof(p));
9db7bf15 1900 fam = AF_UNIX;
aba5acdf
SH
1901 goto out;
1902 }
1903
1527a17e 1904 if (fam == AF_PACKET || strncmp(addr, "link:", 5) == 0) {
aba5acdf
SH
1905 a.addr.family = AF_PACKET;
1906 a.addr.bitlen = 0;
1907 if (strncmp(addr, "link:", 5) == 0)
acd1e437 1908 addr += 5;
aba5acdf
SH
1909 port = strchr(addr, ':');
1910 if (port) {
1911 *port = 0;
1912 if (port[1] && strcmp(port+1, "*")) {
1913 if (get_integer(&a.port, port+1, 0)) {
1914 if ((a.port = xll_name_to_index(port+1)) <= 0)
1915 return NULL;
1916 }
1917 }
1918 }
1919 if (addr[0] && strcmp(addr, "*")) {
1920 unsigned short tmp;
acd1e437 1921
aba5acdf
SH
1922 a.addr.bitlen = 32;
1923 if (ll_proto_a2n(&tmp, addr))
1924 return NULL;
1925 a.addr.data[0] = ntohs(tmp);
1926 }
9db7bf15 1927 fam = AF_PACKET;
aba5acdf
SH
1928 goto out;
1929 }
1930
1527a17e 1931 if (fam == AF_NETLINK || strncmp(addr, "netlink:", 8) == 0) {
aba5acdf
SH
1932 a.addr.family = AF_NETLINK;
1933 a.addr.bitlen = 0;
1934 if (strncmp(addr, "netlink:", 8) == 0)
acd1e437 1935 addr += 8;
aba5acdf
SH
1936 port = strchr(addr, ':');
1937 if (port) {
1938 *port = 0;
1939 if (port[1] && strcmp(port+1, "*")) {
1940 if (get_integer(&a.port, port+1, 0)) {
1941 if (strcmp(port+1, "kernel") == 0)
1942 a.port = 0;
1943 else
1944 return NULL;
1945 }
1946 }
1947 }
1948 if (addr[0] && strcmp(addr, "*")) {
1949 a.addr.bitlen = 32;
b00daf6a 1950 if (nl_proto_a2n(&a.addr.data[0], addr) == -1)
1951 return NULL;
aba5acdf 1952 }
9db7bf15 1953 fam = AF_NETLINK;
aba5acdf
SH
1954 goto out;
1955 }
1956
c759116a
SH
1957 if (fam == AF_VSOCK || strncmp(addr, "vsock:", 6) == 0) {
1958 __u32 cid = ~(__u32)0;
1959
1960 a.addr.family = AF_VSOCK;
1961 if (strncmp(addr, "vsock:", 6) == 0)
1962 addr += 6;
1963
1964 if (is_port)
1965 port = addr;
1966 else {
1967 port = strchr(addr, ':');
1968 if (port) {
1969 *port = '\0';
1970 port++;
1971 }
1972 }
1973
1974 if (port && strcmp(port, "*") &&
1975 get_u32((__u32 *)&a.port, port, 0))
1976 return NULL;
1977
1978 if (addr[0] && strcmp(addr, "*")) {
1979 a.addr.bitlen = 32;
1980 if (get_u32(&cid, addr, 0))
1981 return NULL;
1982 }
1983 vsock_set_inet_prefix(&a.addr, cid);
1984 fam = AF_VSOCK;
1985 goto out;
1986 }
1987
1527a17e 1988 if (fam == AF_INET || !strncmp(addr, "inet:", 5)) {
aba5acdf 1989 fam = AF_INET;
1527a17e
VK
1990 if (!strncmp(addr, "inet:", 5))
1991 addr += 5;
1992 } else if (fam == AF_INET6 || !strncmp(addr, "inet6:", 6)) {
aba5acdf 1993 fam = AF_INET6;
1527a17e
VK
1994 if (!strncmp(addr, "inet6:", 6))
1995 addr += 6;
aba5acdf
SH
1996 }
1997
1998 /* URL-like literal [] */
1999 if (addr[0] == '[') {
2000 addr++;
2001 if ((port = strchr(addr, ']')) == NULL)
2002 return NULL;
2003 *port++ = 0;
2004 } else if (addr[0] == '*') {
2005 port = addr+1;
2006 } else {
2007 port = strrchr(strchr(addr, '/') ? : addr, ':');
2008 }
7871f7db
VK
2009
2010 if (is_port)
2011 port = addr;
2012
aba5acdf 2013 if (port && *port) {
7871f7db
VK
2014 if (*port == ':')
2015 *port++ = 0;
2016
aba5acdf
SH
2017 if (*port && *port != '*') {
2018 if (get_integer(&a.port, port, 0)) {
2019 struct servent *se1 = NULL;
2020 struct servent *se2 = NULL;
acd1e437 2021
aba5acdf
SH
2022 if (current_filter.dbs&(1<<UDP_DB))
2023 se1 = getservbyname(port, UDP_PROTO);
2024 if (current_filter.dbs&(1<<TCP_DB))
2025 se2 = getservbyname(port, TCP_PROTO);
2026 if (se1 && se2 && se1->s_port != se2->s_port) {
2027 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
2028 return NULL;
2029 }
2030 if (!se1)
2031 se1 = se2;
2032 if (se1) {
2033 a.port = ntohs(se1->s_port);
2034 } else {
2035 struct scache *s;
acd1e437 2036
aba5acdf
SH
2037 for (s = rlist; s; s = s->next) {
2038 if ((s->proto == UDP_PROTO &&
2039 (current_filter.dbs&(1<<UDP_DB))) ||
2040 (s->proto == TCP_PROTO &&
2041 (current_filter.dbs&(1<<TCP_DB)))) {
2042 if (s->name && strcmp(s->name, port) == 0) {
2043 if (a.port > 0 && a.port != s->port) {
2044 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
2045 return NULL;
2046 }
2047 a.port = s->port;
2048 }
2049 }
2050 }
2051 if (a.port <= 0) {
2052 fprintf(stderr, "Error: \"%s\" does not look like a port.\n", port);
2053 return NULL;
2054 }
2055 }
2056 }
2057 }
2058 }
44448a90 2059 if (!is_port && *addr && *addr != '*') {
aba5acdf
SH
2060 if (get_prefix_1(&a.addr, addr, fam)) {
2061 if (get_dns_host(&a, addr, fam)) {
2062 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", addr);
2063 return NULL;
2064 }
2065 }
2066 }
2067
9db7bf15 2068out:
1527a17e 2069 if (fam != AF_UNSPEC) {
e56a959e 2070 int states = f->states;
1527a17e 2071 f->families = 0;
9db7bf15 2072 filter_af_set(f, fam);
e56a959e 2073 filter_states_set(f, states);
1527a17e 2074 }
9db7bf15 2075
aba5acdf
SH
2076 res = malloc(sizeof(*res));
2077 if (res)
2078 memcpy(res, &a, sizeof(a));
2079 return res;
2080}
2081
ec75249b
LC
2082void *parse_markmask(const char *markmask)
2083{
2084 struct aafilter a, *res;
2085
2086 if (strchr(markmask, '/')) {
2087 if (sscanf(markmask, "%i/%i", &a.mark, &a.mask) != 2)
2088 return NULL;
2089 } else {
2090 a.mask = 0xffffffff;
2091 if (sscanf(markmask, "%i", &a.mark) != 1)
2092 return NULL;
2093 }
2094
2095 res = malloc(sizeof(*res));
2096 if (res)
2097 memcpy(res, &a, sizeof(a));
2098 return res;
2099}
2100
5f27ac1d 2101static void proc_ctx_print(struct sockstat *s)
8250bc9f 2102{
5f27ac1d 2103 char *buf;
8250bc9f 2104
8250bc9f
VK
2105 if (show_proc_ctx || show_sock_ctx) {
2106 if (find_entry(s->ino, &buf,
2107 (show_proc_ctx & show_sock_ctx) ?
2108 PROC_SOCK_CTX : PROC_CTX) > 0) {
90351722 2109 out(" users:(%s)", buf);
8250bc9f
VK
2110 free(buf);
2111 }
2112 } else if (show_users) {
2113 if (find_entry(s->ino, &buf, USERS) > 0) {
90351722 2114 out(" users:(%s)", buf);
8250bc9f
VK
2115 free(buf);
2116 }
2117 }
2118}
2119
1267c0b9 2120static void inet_stats_print(struct sockstat *s, bool v6only)
5f27ac1d
PS
2121{
2122 sock_state_print(s);
2123
1267c0b9
PS
2124 inet_addr_print(&s->local, s->lport, s->iface, v6only);
2125 inet_addr_print(&s->remote, s->rport, 0, v6only);
5f27ac1d
PS
2126
2127 proc_ctx_print(s);
2128}
2129
055840f2 2130static int proc_parse_inet_addr(char *loc, char *rem, int family, struct
acd1e437 2131 sockstat * s)
8250bc9f
VK
2132{
2133 s->local.family = s->remote.family = family;
2134 if (family == AF_INET) {
acd1e437
SH
2135 sscanf(loc, "%x:%x", s->local.data, (unsigned *)&s->lport);
2136 sscanf(rem, "%x:%x", s->remote.data, (unsigned *)&s->rport);
8250bc9f
VK
2137 s->local.bytelen = s->remote.bytelen = 4;
2138 return 0;
2139 } else {
2140 sscanf(loc, "%08x%08x%08x%08x:%x",
2141 s->local.data,
2142 s->local.data + 1,
2143 s->local.data + 2,
2144 s->local.data + 3,
2145 &s->lport);
2146 sscanf(rem, "%08x%08x%08x%08x:%x",
2147 s->remote.data,
2148 s->remote.data + 1,
2149 s->remote.data + 2,
2150 s->remote.data + 3,
2151 &s->rport);
2152 s->local.bytelen = s->remote.bytelen = 16;
2153 return 0;
2154 }
2155 return -1;
2156}
2157
2158static int proc_inet_split_line(char *line, char **loc, char **rem, char **data)
aba5acdf 2159{
aba5acdf 2160 char *p;
ae665a52 2161
aba5acdf
SH
2162 if ((p = strchr(line, ':')) == NULL)
2163 return -1;
ae665a52 2164
8250bc9f
VK
2165 *loc = p+2;
2166 if ((p = strchr(*loc, ':')) == NULL)
aba5acdf 2167 return -1;
ae665a52 2168
8250bc9f
VK
2169 p[5] = 0;
2170 *rem = p+6;
2171 if ((p = strchr(*rem, ':')) == NULL)
aba5acdf 2172 return -1;
8250bc9f 2173
aba5acdf 2174 p[5] = 0;
8250bc9f
VK
2175 *data = p+6;
2176 return 0;
2177}
ae665a52 2178
8250bc9f
VK
2179static char *sprint_bw(char *buf, double bw)
2180{
2181 if (bw > 1000000.)
acd1e437 2182 sprintf(buf, "%.1fM", bw / 1000000.);
8250bc9f 2183 else if (bw > 1000.)
acd1e437 2184 sprintf(buf, "%.1fK", bw / 1000.);
8250bc9f
VK
2185 else
2186 sprintf(buf, "%g", bw);
aba5acdf 2187
8250bc9f
VK
2188 return buf;
2189}
ae665a52 2190
f89d46ad
PS
2191static void sctp_stats_print(struct sctp_info *s)
2192{
2193 if (s->sctpi_tag)
90351722 2194 out(" tag:%x", s->sctpi_tag);
f89d46ad 2195 if (s->sctpi_state)
90351722 2196 out(" state:%s", sctp_sstate_name[s->sctpi_state]);
f89d46ad 2197 if (s->sctpi_rwnd)
90351722 2198 out(" rwnd:%d", s->sctpi_rwnd);
f89d46ad 2199 if (s->sctpi_unackdata)
90351722 2200 out(" unackdata:%d", s->sctpi_unackdata);
f89d46ad 2201 if (s->sctpi_penddata)
90351722 2202 out(" penddata:%d", s->sctpi_penddata);
f89d46ad 2203 if (s->sctpi_instrms)
90351722 2204 out(" instrms:%d", s->sctpi_instrms);
f89d46ad 2205 if (s->sctpi_outstrms)
90351722 2206 out(" outstrms:%d", s->sctpi_outstrms);
f89d46ad 2207 if (s->sctpi_inqueue)
90351722 2208 out(" inqueue:%d", s->sctpi_inqueue);
f89d46ad 2209 if (s->sctpi_outqueue)
90351722 2210 out(" outqueue:%d", s->sctpi_outqueue);
f89d46ad 2211 if (s->sctpi_overall_error)
90351722 2212 out(" overerr:%d", s->sctpi_overall_error);
f89d46ad 2213 if (s->sctpi_max_burst)
90351722 2214 out(" maxburst:%d", s->sctpi_max_burst);
f89d46ad 2215 if (s->sctpi_maxseg)
90351722 2216 out(" maxseg:%d", s->sctpi_maxseg);
f89d46ad 2217 if (s->sctpi_peer_rwnd)
90351722 2218 out(" prwnd:%d", s->sctpi_peer_rwnd);
f89d46ad 2219 if (s->sctpi_peer_tag)
90351722 2220 out(" ptag:%x", s->sctpi_peer_tag);
f89d46ad 2221 if (s->sctpi_peer_capable)
90351722 2222 out(" pcapable:%d", s->sctpi_peer_capable);
f89d46ad 2223 if (s->sctpi_peer_sack)
90351722 2224 out(" psack:%d", s->sctpi_peer_sack);
f89d46ad 2225 if (s->sctpi_s_autoclose)
90351722 2226 out(" autoclose:%d", s->sctpi_s_autoclose);
f89d46ad 2227 if (s->sctpi_s_adaptation_ind)
90351722 2228 out(" adapind:%d", s->sctpi_s_adaptation_ind);
f89d46ad 2229 if (s->sctpi_s_pd_point)
90351722 2230 out(" pdpoint:%d", s->sctpi_s_pd_point);
f89d46ad 2231 if (s->sctpi_s_nodelay)
90351722 2232 out(" nodealy:%d", s->sctpi_s_nodelay);
f89d46ad 2233 if (s->sctpi_s_disable_fragments)
90351722 2234 out(" nofrag:%d", s->sctpi_s_disable_fragments);
f89d46ad 2235 if (s->sctpi_s_v4mapped)
90351722 2236 out(" v4mapped:%d", s->sctpi_s_v4mapped);
f89d46ad 2237 if (s->sctpi_s_frag_interleave)
90351722 2238 out(" fraginl:%d", s->sctpi_s_frag_interleave);
f89d46ad
PS
2239}
2240
8250bc9f
VK
2241static void tcp_stats_print(struct tcpstat *s)
2242{
2243 char b1[64];
2244
2245 if (s->has_ts_opt)
90351722 2246 out(" ts");
8250bc9f 2247 if (s->has_sack_opt)
90351722 2248 out(" sack");
8250bc9f 2249 if (s->has_ecn_opt)
90351722 2250 out(" ecn");
8250bc9f 2251 if (s->has_ecnseen_opt)
90351722 2252 out(" ecnseen");
8250bc9f 2253 if (s->has_fastopen_opt)
90351722 2254 out(" fastopen");
d2055ea5 2255 if (s->cong_alg[0])
90351722 2256 out(" %s", s->cong_alg);
8250bc9f 2257 if (s->has_wscale_opt)
90351722 2258 out(" wscale:%d,%d", s->snd_wscale, s->rcv_wscale);
8250bc9f 2259 if (s->rto)
90351722 2260 out(" rto:%g", s->rto);
8250bc9f 2261 if (s->backoff)
90351722 2262 out(" backoff:%u", s->backoff);
8250bc9f 2263 if (s->rtt)
90351722 2264 out(" rtt:%g/%g", s->rtt, s->rttvar);
8250bc9f 2265 if (s->ato)
90351722 2266 out(" ato:%g", s->ato);
8250bc9f
VK
2267
2268 if (s->qack)
90351722 2269 out(" qack:%d", s->qack);
8250bc9f 2270 if (s->qack & 1)
90351722 2271 out(" bidir");
8250bc9f
VK
2272
2273 if (s->mss)
90351722 2274 out(" mss:%d", s->mss);
38e6dbc4 2275 if (s->rcv_mss)
90351722 2276 out(" rcvmss:%d", s->rcv_mss);
38e6dbc4 2277 if (s->advmss)
90351722 2278 out(" advmss:%d", s->advmss);
3bf5445c 2279 if (s->cwnd)
90351722 2280 out(" cwnd:%u", s->cwnd);
8250bc9f 2281 if (s->ssthresh)
90351722 2282 out(" ssthresh:%d", s->ssthresh);
8250bc9f 2283
1a4dda71 2284 if (s->bytes_acked)
90351722 2285 out(" bytes_acked:%llu", s->bytes_acked);
1a4dda71 2286 if (s->bytes_received)
90351722 2287 out(" bytes_received:%llu", s->bytes_received);
ecb435ea 2288 if (s->segs_out)
90351722 2289 out(" segs_out:%u", s->segs_out);
ecb435ea 2290 if (s->segs_in)
90351722 2291 out(" segs_in:%u", s->segs_in);
414aeec9 2292 if (s->data_segs_out)
90351722 2293 out(" data_segs_out:%u", s->data_segs_out);
414aeec9 2294 if (s->data_segs_in)
90351722 2295 out(" data_segs_in:%u", s->data_segs_in);
1a4dda71 2296
8250bc9f
VK
2297 if (s->dctcp && s->dctcp->enabled) {
2298 struct dctcpstat *dctcp = s->dctcp;
2299
90351722
SB
2300 out(" dctcp:(ce_state:%u,alpha:%u,ab_ecn:%u,ab_tot:%u)",
2301 dctcp->ce_state, dctcp->alpha, dctcp->ab_ecn,
2302 dctcp->ab_tot);
8250bc9f 2303 } else if (s->dctcp) {
90351722 2304 out(" dctcp:fallback_mode");
8250bc9f
VK
2305 }
2306
2f0f9aef
NC
2307 if (s->bbr_info) {
2308 __u64 bw;
2309
2310 bw = s->bbr_info->bbr_bw_hi;
2311 bw <<= 32;
2312 bw |= s->bbr_info->bbr_bw_lo;
2313
90351722
SB
2314 out(" bbr:(bw:%sbps,mrtt:%g",
2315 sprint_bw(b1, bw * 8.0),
2316 (double)s->bbr_info->bbr_min_rtt / 1000.0);
2f0f9aef 2317 if (s->bbr_info->bbr_pacing_gain)
90351722
SB
2318 out(",pacing_gain:%g",
2319 (double)s->bbr_info->bbr_pacing_gain / 256.0);
2f0f9aef 2320 if (s->bbr_info->bbr_cwnd_gain)
90351722
SB
2321 out(",cwnd_gain:%g",
2322 (double)s->bbr_info->bbr_cwnd_gain / 256.0);
2323 out(")");
2f0f9aef
NC
2324 }
2325
8250bc9f 2326 if (s->send_bps)
90351722 2327 out(" send %sbps", sprint_bw(b1, s->send_bps));
8250bc9f 2328 if (s->lastsnd)
90351722 2329 out(" lastsnd:%u", s->lastsnd);
8250bc9f 2330 if (s->lastrcv)
90351722 2331 out(" lastrcv:%u", s->lastrcv);
8250bc9f 2332 if (s->lastack)
90351722 2333 out(" lastack:%u", s->lastack);
8250bc9f
VK
2334
2335 if (s->pacing_rate) {
90351722 2336 out(" pacing_rate %sbps", sprint_bw(b1, s->pacing_rate));
8250bc9f 2337 if (s->pacing_rate_max)
90351722 2338 out("/%sbps", sprint_bw(b1, s->pacing_rate_max));
8250bc9f
VK
2339 }
2340
2f579872 2341 if (s->delivery_rate)
90351722 2342 out(" delivery_rate %sbps", sprint_bw(b1, s->delivery_rate));
2f579872 2343 if (s->app_limited)
90351722 2344 out(" app_limited");
2f579872 2345
b6c7fc61 2346 if (s->busy_time) {
90351722 2347 out(" busy:%llums", s->busy_time / 1000);
b6c7fc61 2348 if (s->rwnd_limited)
90351722
SB
2349 out(" rwnd_limited:%llums(%.1f%%)",
2350 s->rwnd_limited / 1000,
2351 100.0 * s->rwnd_limited / s->busy_time);
b6c7fc61 2352 if (s->sndbuf_limited)
90351722
SB
2353 out(" sndbuf_limited:%llums(%.1f%%)",
2354 s->sndbuf_limited / 1000,
2355 100.0 * s->sndbuf_limited / s->busy_time);
b6c7fc61
YC
2356 }
2357
8250bc9f 2358 if (s->unacked)
90351722 2359 out(" unacked:%u", s->unacked);
8250bc9f 2360 if (s->retrans || s->retrans_total)
90351722 2361 out(" retrans:%u/%u", s->retrans, s->retrans_total);
8250bc9f 2362 if (s->lost)
90351722 2363 out(" lost:%u", s->lost);
055840f2 2364 if (s->sacked && s->ss.state != SS_LISTEN)
90351722 2365 out(" sacked:%u", s->sacked);
8250bc9f 2366 if (s->fackets)
90351722 2367 out(" fackets:%u", s->fackets);
8250bc9f 2368 if (s->reordering != 3)
90351722 2369 out(" reordering:%d", s->reordering);
8250bc9f 2370 if (s->rcv_rtt)
90351722 2371 out(" rcv_rtt:%g", s->rcv_rtt);
8250bc9f 2372 if (s->rcv_space)
90351722 2373 out(" rcv_space:%d", s->rcv_space);
00ac78d3 2374 if (s->rcv_ssthresh)
90351722 2375 out(" rcv_ssthresh:%u", s->rcv_ssthresh);
9e99e495 2376 if (s->not_sent)
90351722 2377 out(" notsent:%u", s->not_sent);
9e99e495 2378 if (s->min_rtt)
90351722 2379 out(" minrtt:%g", s->min_rtt);
8250bc9f
VK
2380}
2381
055840f2
VK
2382static void tcp_timer_print(struct tcpstat *s)
2383{
86dfa1be
PS
2384 static const char * const tmr_name[] = {
2385 "off",
2386 "on",
2387 "keepalive",
2388 "timewait",
2389 "persist",
2390 "unknown"
2391 };
2392
055840f2
VK
2393 if (s->timer) {
2394 if (s->timer > 4)
2395 s->timer = 5;
90351722
SB
2396 out(" timer:(%s,%s,%d)",
2397 tmr_name[s->timer],
2398 print_ms_timer(s->timeout),
2399 s->retrans);
055840f2
VK
2400 }
2401}
2402
f89d46ad
PS
2403static void sctp_timer_print(struct tcpstat *s)
2404{
2405 if (s->timer)
90351722
SB
2406 out(" timer:(T3_RTX,%s,%d)",
2407 print_ms_timer(s->timeout), s->retrans);
f89d46ad
PS
2408}
2409
8250bc9f
VK
2410static int tcp_show_line(char *line, const struct filter *f, int family)
2411{
2412 int rto = 0, ato = 0;
2413 struct tcpstat s = {};
2414 char *loc, *rem, *data;
2415 char opt[256];
2416 int n;
2417 int hz = get_user_hz();
2418
2419 if (proc_inet_split_line(line, &loc, &rem, &data))
2420 return -1;
2421
2422 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
acd1e437 2423
8250bc9f
VK
2424 if (!(f->states & (1 << state)))
2425 return 0;
2426
055840f2 2427 proc_parse_inet_addr(loc, rem, family, &s.ss);
ae665a52 2428
055840f2 2429 if (f->f && run_ssfilter(f->f, &s.ss) == 0)
aba5acdf 2430 return 0;
ae665a52 2431
aba5acdf 2432 opt[0] = 0;
d1f338b3 2433 n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %u %d %[^\n]\n",
055840f2
VK
2434 &s.ss.state, &s.ss.wq, &s.ss.rq,
2435 &s.timer, &s.timeout, &s.retrans, &s.ss.uid, &s.probes,
2436 &s.ss.ino, &s.ss.refcnt, &s.ss.sk, &rto, &ato, &s.qack, &s.cwnd,
2437 &s.ssthresh, opt);
ae665a52 2438
aba5acdf
SH
2439 if (n < 17)
2440 opt[0] = 0;
ae665a52 2441
aba5acdf 2442 if (n < 12) {
8250bc9f 2443 rto = 0;
aba5acdf
SH
2444 s.cwnd = 2;
2445 s.ssthresh = -1;
8250bc9f 2446 ato = s.qack = 0;
aba5acdf 2447 }
ae665a52 2448
8250bc9f
VK
2449 s.retrans = s.timer != 1 ? s.probes : s.retrans;
2450 s.timeout = (s.timeout * 1000 + hz - 1) / hz;
2451 s.ato = (double)ato / hz;
2452 s.qack /= 2;
2453 s.rto = (double)rto;
2454 s.ssthresh = s.ssthresh == -1 ? 0 : s.ssthresh;
2455 s.rto = s.rto != 3 * hz ? s.rto / hz : 0;
be7e4d20 2456 s.ss.type = IPPROTO_TCP;
ae665a52 2457
1267c0b9 2458 inet_stats_print(&s.ss, false);
055840f2
VK
2459
2460 if (show_options)
2461 tcp_timer_print(&s);
116ac927 2462
aba5acdf 2463 if (show_details) {
f1b39e1b 2464 sock_details_print(&s.ss);
aba5acdf 2465 if (opt[0])
90351722 2466 out(" opt:\"%s\"", opt);
aba5acdf 2467 }
aba5acdf 2468
8250bc9f
VK
2469 if (show_tcpinfo)
2470 tcp_stats_print(&s);
2471
aba5acdf
SH
2472 return 0;
2473}
2474
ab01dbbb
SH
2475static int generic_record_read(FILE *fp,
2476 int (*worker)(char*, const struct filter *, int),
2477 const struct filter *f, int fam)
aba5acdf 2478{
ab01dbbb 2479 char line[256];
aba5acdf 2480
ab01dbbb
SH
2481 /* skip header */
2482 if (fgets(line, sizeof(line), fp) == NULL)
aba5acdf 2483 goto outerr;
ab01dbbb
SH
2484
2485 while (fgets(line, sizeof(line), fp) != NULL) {
2486 int n = strlen(line);
acd1e437 2487
ab01dbbb
SH
2488 if (n == 0 || line[n-1] != '\n') {
2489 errno = -EINVAL;
2490 return -1;
aba5acdf 2491 }
ab01dbbb 2492 line[n-1] = 0;
aba5acdf 2493
ab01dbbb
SH
2494 if (worker(line, f, fam) < 0)
2495 return 0;
2496 }
aba5acdf 2497outerr:
ab01dbbb
SH
2498
2499 return ferror(fp) ? -1 : 0;
aba5acdf 2500}
ae665a52 2501
51ff9f24
HFS
2502static void print_skmeminfo(struct rtattr *tb[], int attrtype)
2503{
2504 const __u32 *skmeminfo;
db08bdb8
VK
2505
2506 if (!tb[attrtype]) {
2507 if (attrtype == INET_DIAG_SKMEMINFO) {
2508 if (!tb[INET_DIAG_MEMINFO])
2509 return;
2510
2511 const struct inet_diag_meminfo *minfo =
2512 RTA_DATA(tb[INET_DIAG_MEMINFO]);
2513
90351722
SB
2514 out(" mem:(r%u,w%u,f%u,t%u)",
2515 minfo->idiag_rmem,
2516 minfo->idiag_wmem,
2517 minfo->idiag_fmem,
2518 minfo->idiag_tmem);
db08bdb8 2519 }
51ff9f24 2520 return;
db08bdb8
VK
2521 }
2522
51ff9f24
HFS
2523 skmeminfo = RTA_DATA(tb[attrtype]);
2524
90351722
SB
2525 out(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
2526 skmeminfo[SK_MEMINFO_RMEM_ALLOC],
2527 skmeminfo[SK_MEMINFO_RCVBUF],
2528 skmeminfo[SK_MEMINFO_WMEM_ALLOC],
2529 skmeminfo[SK_MEMINFO_SNDBUF],
2530 skmeminfo[SK_MEMINFO_FWD_ALLOC],
2531 skmeminfo[SK_MEMINFO_WMEM_QUEUED],
2532 skmeminfo[SK_MEMINFO_OPTMEM]);
51ff9f24
HFS
2533
2534 if (RTA_PAYLOAD(tb[attrtype]) >=
2535 (SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
90351722 2536 out(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
51ff9f24 2537
6df9c7a0
ED
2538 if (RTA_PAYLOAD(tb[attrtype]) >=
2539 (SK_MEMINFO_DROPS + 1) * sizeof(__u32))
90351722 2540 out(",d%u", skmeminfo[SK_MEMINFO_DROPS]);
6df9c7a0 2541
90351722 2542 out(")");
51ff9f24
HFS
2543}
2544
da9cc6ab
ID
2545static void print_md5sig(struct tcp_diag_md5sig *sig)
2546{
90351722
SB
2547 out("%s/%d=",
2548 format_host(sig->tcpm_family,
2549 sig->tcpm_family == AF_INET6 ? 16 : 4,
2550 &sig->tcpm_addr),
2551 sig->tcpm_prefixlen);
da9cc6ab
ID
2552 print_escape_buf(sig->tcpm_key, sig->tcpm_keylen, " ,");
2553}
2554
8250bc9f
VK
2555#define TCPI_HAS_OPT(info, opt) !!(info->tcpi_options & (opt))
2556
5b816047
PE
2557static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
2558 struct rtattr *tb[])
7d105b56 2559{
b4b0b7d5 2560 double rtt = 0;
8250bc9f 2561 struct tcpstat s = {};
7d105b56 2562
055840f2
VK
2563 s.ss.state = r->idiag_state;
2564
db08bdb8 2565 print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
7d105b56 2566
351efcde 2567 if (tb[INET_DIAG_INFO]) {
05e18118 2568 struct tcp_info *info;
351efcde 2569 int len = RTA_PAYLOAD(tb[INET_DIAG_INFO]);
05e18118
SH
2570
2571 /* workaround for older kernels with less fields */
2572 if (len < sizeof(*info)) {
2573 info = alloca(sizeof(*info));
351efcde 2574 memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len);
656e8fdd 2575 memset((char *)info + len, 0, sizeof(*info) - len);
05e18118 2576 } else
351efcde 2577 info = RTA_DATA(tb[INET_DIAG_INFO]);
05e18118 2578
b4b0b7d5 2579 if (show_options) {
8250bc9f
VK
2580 s.has_ts_opt = TCPI_HAS_OPT(info, TCPI_OPT_TIMESTAMPS);
2581 s.has_sack_opt = TCPI_HAS_OPT(info, TCPI_OPT_SACK);
2582 s.has_ecn_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN);
2583 s.has_ecnseen_opt = TCPI_HAS_OPT(info, TCPI_OPT_ECN_SEEN);
2584 s.has_fastopen_opt = TCPI_HAS_OPT(info, TCPI_OPT_SYN_DATA);
b4b0b7d5 2585 }
52d5ac3f 2586
d2055ea5
ED
2587 if (tb[INET_DIAG_CONG])
2588 strncpy(s.cong_alg,
2589 rta_getattr_str(tb[INET_DIAG_CONG]),
2590 sizeof(s.cong_alg) - 1);
8250bc9f
VK
2591
2592 if (TCPI_HAS_OPT(info, TCPI_OPT_WSCALE)) {
2593 s.has_wscale_opt = true;
2594 s.snd_wscale = info->tcpi_snd_wscale;
2595 s.rcv_wscale = info->tcpi_rcv_wscale;
2596 }
ea8fc104 2597
7d105b56 2598 if (info->tcpi_rto && info->tcpi_rto != 3000000)
8250bc9f
VK
2599 s.rto = (double)info->tcpi_rto / 1000;
2600
2601 s.backoff = info->tcpi_backoff;
2602 s.rtt = (double)info->tcpi_rtt / 1000;
2603 s.rttvar = (double)info->tcpi_rttvar / 1000;
11ba90fc 2604 s.ato = (double)info->tcpi_ato / 1000;
8250bc9f 2605 s.mss = info->tcpi_snd_mss;
38e6dbc4
ED
2606 s.rcv_mss = info->tcpi_rcv_mss;
2607 s.advmss = info->tcpi_advmss;
8250bc9f
VK
2608 s.rcv_space = info->tcpi_rcv_space;
2609 s.rcv_rtt = (double)info->tcpi_rcv_rtt / 1000;
2610 s.lastsnd = info->tcpi_last_data_sent;
2611 s.lastrcv = info->tcpi_last_data_recv;
2612 s.lastack = info->tcpi_last_ack_recv;
2613 s.unacked = info->tcpi_unacked;
2614 s.retrans = info->tcpi_retrans;
2615 s.retrans_total = info->tcpi_total_retrans;
2616 s.lost = info->tcpi_lost;
2617 s.sacked = info->tcpi_sacked;
c4be5feb 2618 s.fackets = info->tcpi_fackets;
8250bc9f 2619 s.reordering = info->tcpi_reordering;
00ac78d3 2620 s.rcv_ssthresh = info->tcpi_rcv_ssthresh;
8250bc9f
VK
2621 s.cwnd = info->tcpi_snd_cwnd;
2622
7d105b56 2623 if (info->tcpi_snd_ssthresh < 0xFFFF)
8250bc9f 2624 s.ssthresh = info->tcpi_snd_ssthresh;
52d5ac3f 2625
b4b0b7d5 2626 rtt = (double) info->tcpi_rtt;
351efcde 2627 if (tb[INET_DIAG_VEGASINFO]) {
05e18118 2628 const struct tcpvegas_info *vinfo
351efcde 2629 = RTA_DATA(tb[INET_DIAG_VEGASINFO]);
7d105b56 2630
ae665a52 2631 if (vinfo->tcpv_enabled &&
8250bc9f 2632 vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
ea8fc104 2633 rtt = vinfo->tcpv_rtt;
b4b0b7d5
SH
2634 }
2635
907e1aca 2636 if (tb[INET_DIAG_DCTCPINFO]) {
8250bc9f
VK
2637 struct dctcpstat *dctcp = malloc(sizeof(struct
2638 dctcpstat));
2639
907e1aca
DB
2640 const struct tcp_dctcp_info *dinfo
2641 = RTA_DATA(tb[INET_DIAG_DCTCPINFO]);
2642
8250bc9f
VK
2643 dctcp->enabled = !!dinfo->dctcp_enabled;
2644 dctcp->ce_state = dinfo->dctcp_ce_state;
2645 dctcp->alpha = dinfo->dctcp_alpha;
2646 dctcp->ab_ecn = dinfo->dctcp_ab_ecn;
2647 dctcp->ab_tot = dinfo->dctcp_ab_tot;
2648 s.dctcp = dctcp;
907e1aca
DB
2649 }
2650
2f0f9aef
NC
2651 if (tb[INET_DIAG_BBRINFO]) {
2652 const void *bbr_info = RTA_DATA(tb[INET_DIAG_BBRINFO]);
2653 int len = min(RTA_PAYLOAD(tb[INET_DIAG_BBRINFO]),
2654 sizeof(*s.bbr_info));
2655
2656 s.bbr_info = calloc(1, sizeof(*s.bbr_info));
2657 if (s.bbr_info && bbr_info)
2658 memcpy(s.bbr_info, bbr_info, len);
2659 }
2660
b4b0b7d5 2661 if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
8250bc9f
VK
2662 s.send_bps = (double) info->tcpi_snd_cwnd *
2663 (double)info->tcpi_snd_mss * 8000000. / rtt;
7d105b56 2664 }
b4b0b7d5 2665
eb6028b2 2666 if (info->tcpi_pacing_rate &&
8250bc9f
VK
2667 info->tcpi_pacing_rate != ~0ULL) {
2668 s.pacing_rate = info->tcpi_pacing_rate * 8.;
eb6028b2
ED
2669
2670 if (info->tcpi_max_pacing_rate &&
8250bc9f
VK
2671 info->tcpi_max_pacing_rate != ~0ULL)
2672 s.pacing_rate_max = info->tcpi_max_pacing_rate * 8.;
eb6028b2 2673 }
1a4dda71
ED
2674 s.bytes_acked = info->tcpi_bytes_acked;
2675 s.bytes_received = info->tcpi_bytes_received;
ecb435ea
CG
2676 s.segs_out = info->tcpi_segs_out;
2677 s.segs_in = info->tcpi_segs_in;
414aeec9
MKL
2678 s.data_segs_out = info->tcpi_data_segs_out;
2679 s.data_segs_in = info->tcpi_data_segs_in;
9e99e495 2680 s.not_sent = info->tcpi_notsent_bytes;
d9ba887e
ED
2681 if (info->tcpi_min_rtt && info->tcpi_min_rtt != ~0U)
2682 s.min_rtt = (double) info->tcpi_min_rtt / 1000;
2f579872
NC
2683 s.delivery_rate = info->tcpi_delivery_rate * 8.;
2684 s.app_limited = info->tcpi_delivery_rate_app_limited;
b6c7fc61
YC
2685 s.busy_time = info->tcpi_busy_time;
2686 s.rwnd_limited = info->tcpi_rwnd_limited;
2687 s.sndbuf_limited = info->tcpi_sndbuf_limited;
8250bc9f 2688 tcp_stats_print(&s);
92de1c2c 2689 free(s.dctcp);
2f0f9aef 2690 free(s.bbr_info);
77a8ca81 2691 }
da9cc6ab
ID
2692 if (tb[INET_DIAG_MD5SIG]) {
2693 struct tcp_diag_md5sig *sig = RTA_DATA(tb[INET_DIAG_MD5SIG]);
2694 int len = RTA_PAYLOAD(tb[INET_DIAG_MD5SIG]);
2695
90351722 2696 out(" md5keys:");
da9cc6ab
ID
2697 print_md5sig(sig++);
2698 for (len -= sizeof(*sig); len > 0; len -= sizeof(*sig)) {
90351722 2699 out(",");
da9cc6ab
ID
2700 print_md5sig(sig++);
2701 }
2702 }
77a8ca81
PE
2703}
2704
f89d46ad
PS
2705static const char *format_host_sa(struct sockaddr_storage *sa)
2706{
2707 union {
2708 struct sockaddr_in sin;
2709 struct sockaddr_in6 sin6;
2710 } *saddr = (void *)sa;
2711
2712 switch (sa->ss_family) {
2713 case AF_INET:
2714 return format_host(AF_INET, 4, &saddr->sin.sin_addr);
2715 case AF_INET6:
2716 return format_host(AF_INET6, 16, &saddr->sin6.sin6_addr);
2717 default:
2718 return "";
2719 }
2720}
2721
2722static void sctp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
2723 struct rtattr *tb[])
2724{
2725 struct sockaddr_storage *sa;
2726 int len;
2727
2728 print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
2729
2730 if (tb[INET_DIAG_LOCALS]) {
2731 len = RTA_PAYLOAD(tb[INET_DIAG_LOCALS]);
2732 sa = RTA_DATA(tb[INET_DIAG_LOCALS]);
2733
90351722 2734 out("locals:%s", format_host_sa(sa));
f89d46ad 2735 for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa))
90351722 2736 out(",%s", format_host_sa(sa));
f89d46ad
PS
2737
2738 }
2739 if (tb[INET_DIAG_PEERS]) {
2740 len = RTA_PAYLOAD(tb[INET_DIAG_PEERS]);
2741 sa = RTA_DATA(tb[INET_DIAG_PEERS]);
2742
90351722 2743 out(" peers:%s", format_host_sa(sa));
f89d46ad 2744 for (sa++, len -= sizeof(*sa); len > 0; sa++, len -= sizeof(*sa))
90351722 2745 out(",%s", format_host_sa(sa));
f89d46ad
PS
2746 }
2747 if (tb[INET_DIAG_INFO]) {
2748 struct sctp_info *info;
2749 len = RTA_PAYLOAD(tb[INET_DIAG_INFO]);
2750
2751 /* workaround for older kernels with less fields */
2752 if (len < sizeof(*info)) {
2753 info = alloca(sizeof(*info));
2754 memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len);
2755 memset((char *)info + len, 0, sizeof(*info) - len);
2756 } else
2757 info = RTA_DATA(tb[INET_DIAG_INFO]);
2758
2759 sctp_stats_print(info);
2760 }
2761}
2762
82d73ea0 2763static void parse_diag_msg(struct nlmsghdr *nlh, struct sockstat *s)
aba5acdf 2764{
acd1e437 2765 struct rtattr *tb[INET_DIAG_MAX+1];
351efcde 2766 struct inet_diag_msg *r = NLMSG_DATA(nlh);
aba5acdf 2767
acd1e437 2768 parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1),
5b816047
PE
2769 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2770
82d73ea0
DA
2771 s->state = r->idiag_state;
2772 s->local.family = s->remote.family = r->idiag_family;
2773 s->lport = ntohs(r->id.idiag_sport);
2774 s->rport = ntohs(r->id.idiag_dport);
2775 s->wq = r->idiag_wqueue;
2776 s->rq = r->idiag_rqueue;
2777 s->ino = r->idiag_inode;
2778 s->uid = r->idiag_uid;
2779 s->iface = r->id.idiag_if;
2780 s->sk = cookie_sk_get(&r->id.idiag_cookie[0]);
2781
ec75249b
LC
2782 s->mark = 0;
2783 if (tb[INET_DIAG_MARK])
9f1370c0 2784 s->mark = rta_getattr_u32(tb[INET_DIAG_MARK]);
41fe6c34 2785 if (tb[INET_DIAG_PROTOCOL])
9f1370c0 2786 s->raw_prot = rta_getattr_u8(tb[INET_DIAG_PROTOCOL]);
41fe6c34
CG
2787 else
2788 s->raw_prot = 0;
ec75249b 2789
82d73ea0
DA
2790 if (s->local.family == AF_INET)
2791 s->local.bytelen = s->remote.bytelen = 4;
2792 else
2793 s->local.bytelen = s->remote.bytelen = 16;
8250bc9f 2794
82d73ea0
DA
2795 memcpy(s->local.data, r->id.idiag_src, s->local.bytelen);
2796 memcpy(s->remote.data, r->id.idiag_dst, s->local.bytelen);
2797}
aba5acdf 2798
82d73ea0 2799static int inet_show_sock(struct nlmsghdr *nlh,
be7e4d20 2800 struct sockstat *s)
82d73ea0
DA
2801{
2802 struct rtattr *tb[INET_DIAG_MAX+1];
2803 struct inet_diag_msg *r = NLMSG_DATA(nlh);
1267c0b9 2804 unsigned char v6only = 0;
82d73ea0
DA
2805
2806 parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(r+1),
2807 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
aba5acdf 2808
6885e3bf 2809 if (tb[INET_DIAG_PROTOCOL])
9f1370c0 2810 s->type = rta_getattr_u8(tb[INET_DIAG_PROTOCOL]);
6885e3bf 2811
1267c0b9
PS
2812 if (s->local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY])
2813 v6only = rta_getattr_u8(tb[INET_DIAG_SKV6ONLY]);
2814
2815 inet_stats_print(s, v6only);
116ac927 2816
055840f2
VK
2817 if (show_options) {
2818 struct tcpstat t = {};
2819
2820 t.timer = r->idiag_timer;
2821 t.timeout = r->idiag_expires;
2822 t.retrans = r->idiag_retrans;
be7e4d20 2823 if (s->type == IPPROTO_SCTP)
f89d46ad
PS
2824 sctp_timer_print(&t);
2825 else
2826 tcp_timer_print(&t);
055840f2
VK
2827 }
2828
aba5acdf 2829 if (show_details) {
82d73ea0 2830 sock_details_print(s);
1267c0b9 2831 if (s->local.family == AF_INET6 && tb[INET_DIAG_SKV6ONLY])
90351722 2832 out(" v6only:%u", v6only);
1267c0b9 2833
5b816047
PE
2834 if (tb[INET_DIAG_SHUTDOWN]) {
2835 unsigned char mask;
acd1e437 2836
9f1370c0 2837 mask = rta_getattr_u8(tb[INET_DIAG_SHUTDOWN]);
90351722
SB
2838 out(" %c-%c",
2839 mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
5b816047 2840 }
aba5acdf 2841 }
8250bc9f 2842
be7e4d20 2843 if (show_mem || (show_tcpinfo && s->type != IPPROTO_UDP)) {
90351722 2844 out("\n\t");
be7e4d20 2845 if (s->type == IPPROTO_SCTP)
f89d46ad
PS
2846 sctp_show_info(nlh, r, tb);
2847 else
2848 tcp_show_info(nlh, r, tb);
aba5acdf 2849 }
f89d46ad 2850 sctp_ino = s->ino;
7d105b56 2851
aba5acdf 2852 return 0;
aba5acdf
SH
2853}
2854
746a695f 2855static int tcpdiag_send(int fd, int protocol, struct filter *f)
aba5acdf 2856{
d17b136f 2857 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
aba5acdf
SH
2858 struct {
2859 struct nlmsghdr nlh;
351efcde 2860 struct inet_diag_req r;
d17b136f
PS
2861 } req = {
2862 .nlh.nlmsg_len = sizeof(req),
2863 .nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST,
2864 .nlh.nlmsg_seq = MAGIC_SEQ,
2865 .r.idiag_family = AF_INET,
2866 .r.idiag_states = f->states,
2867 };
aba5acdf
SH
2868 char *bc = NULL;
2869 int bclen;
2870 struct msghdr msg;
2871 struct rtattr rta;
aba5acdf 2872 struct iovec iov[3];
376fb868 2873 int iovlen = 1;
aba5acdf 2874
346f8ca8
PE
2875 if (protocol == IPPROTO_UDP)
2876 return -1;
2877
3fe5b534
PE
2878 if (protocol == IPPROTO_TCP)
2879 req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
2880 else
2881 req.nlh.nlmsg_type = DCCPDIAG_GETSOCK;
910b0397 2882 if (show_mem) {
ae665a52 2883 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
910b0397
SW
2884 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
2885 }
b4b0b7d5 2886
7d105b56 2887 if (show_tcpinfo) {
351efcde
SH
2888 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
2889 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
2890 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
7d105b56 2891 }
aba5acdf 2892
ae665a52
SH
2893 iov[0] = (struct iovec){
2894 .iov_base = &req,
2895 .iov_len = sizeof(req)
ea8fc104 2896 };
aba5acdf
SH
2897 if (f->f) {
2898 bclen = ssfilter_bytecompile(f->f, &bc);
376fb868
DA
2899 if (bclen) {
2900 rta.rta_type = INET_DIAG_REQ_BYTECODE;
2901 rta.rta_len = RTA_LENGTH(bclen);
2902 iov[1] = (struct iovec){ &rta, sizeof(rta) };
2903 iov[2] = (struct iovec){ bc, bclen };
2904 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
2905 iovlen = 3;
2906 }
aba5acdf
SH
2907 }
2908
2909 msg = (struct msghdr) {
acd1e437 2910 .msg_name = (void *)&nladdr,
ea8fc104 2911 .msg_namelen = sizeof(nladdr),
ae665a52 2912 .msg_iov = iov,
376fb868 2913 .msg_iovlen = iovlen,
aba5acdf
SH
2914 };
2915
930a75f9
ED
2916 if (sendmsg(fd, &msg, 0) < 0) {
2917 close(fd);
aba5acdf 2918 return -1;
930a75f9 2919 }
aba5acdf 2920
746a695f
PE
2921 return 0;
2922}
2923
886d19d6
PE
2924static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
2925{
d17b136f 2926 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
5fb421d4 2927 DIAG_REQUEST(req, struct inet_diag_req_v2 r);
886d19d6
PE
2928 char *bc = NULL;
2929 int bclen;
2930 struct msghdr msg;
2931 struct rtattr rta;
2932 struct iovec iov[3];
376fb868 2933 int iovlen = 1;
886d19d6
PE
2934
2935 if (family == PF_UNSPEC)
2936 return tcpdiag_send(fd, protocol, f);
2937
886d19d6
PE
2938 memset(&req.r, 0, sizeof(req.r));
2939 req.r.sdiag_family = family;
2940 req.r.sdiag_protocol = protocol;
2941 req.r.idiag_states = f->states;
2942 if (show_mem) {
2943 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
2944 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
2945 }
2946
2947 if (show_tcpinfo) {
2948 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
2949 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
2950 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
2951 }
2952
2953 iov[0] = (struct iovec){
2954 .iov_base = &req,
2955 .iov_len = sizeof(req)
2956 };
2957 if (f->f) {
2958 bclen = ssfilter_bytecompile(f->f, &bc);
376fb868
DA
2959 if (bclen) {
2960 rta.rta_type = INET_DIAG_REQ_BYTECODE;
2961 rta.rta_len = RTA_LENGTH(bclen);
2962 iov[1] = (struct iovec){ &rta, sizeof(rta) };
2963 iov[2] = (struct iovec){ bc, bclen };
2964 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
2965 iovlen = 3;
2966 }
886d19d6
PE
2967 }
2968
2969 msg = (struct msghdr) {
acd1e437 2970 .msg_name = (void *)&nladdr,
886d19d6
PE
2971 .msg_namelen = sizeof(nladdr),
2972 .msg_iov = iov,
376fb868 2973 .msg_iovlen = iovlen,
886d19d6
PE
2974 };
2975
2976 if (sendmsg(fd, &msg, 0) < 0) {
2977 close(fd);
2978 return -1;
2979 }
2980
2981 return 0;
2982}
2983
486ccd99
VK
2984struct inet_diag_arg {
2985 struct filter *f;
2986 int protocol;
fb2594c1 2987 struct rtnl_handle *rth;
486ccd99 2988};
aba5acdf 2989
41fe6c34 2990static int kill_inet_sock(struct nlmsghdr *h, void *arg, struct sockstat *s)
fb2594c1
LC
2991{
2992 struct inet_diag_msg *d = NLMSG_DATA(h);
2993 struct inet_diag_arg *diag_arg = arg;
2994 struct rtnl_handle *rth = diag_arg->rth;
acd1e437 2995
fb2594c1
LC
2996 DIAG_REQUEST(req, struct inet_diag_req_v2 r);
2997
2998 req.nlh.nlmsg_type = SOCK_DESTROY;
2999 req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
3000 req.nlh.nlmsg_seq = ++rth->seq;
3001 req.r.sdiag_family = d->idiag_family;
3002 req.r.sdiag_protocol = diag_arg->protocol;
3003 req.r.id = d->id;
3004
41fe6c34
CG
3005 if (diag_arg->protocol == IPPROTO_RAW) {
3006 struct inet_diag_req_raw *raw = (void *)&req.r;
3007
3008 BUILD_BUG_ON(sizeof(req.r) != sizeof(*raw));
3009 raw->sdiag_raw_protocol = s->raw_prot;
3010 }
3011
86bf43c7 3012 return rtnl_talk(rth, &req.nlh, NULL);
fb2594c1
LC
3013}
3014
486ccd99
VK
3015static int show_one_inet_sock(const struct sockaddr_nl *addr,
3016 struct nlmsghdr *h, void *arg)
3017{
3018 int err;
3019 struct inet_diag_arg *diag_arg = arg;
3020 struct inet_diag_msg *r = NLMSG_DATA(h);
82d73ea0 3021 struct sockstat s = {};
aba5acdf 3022
b338a3e7 3023 if (!(diag_arg->f->families & FAMILY_MASK(r->idiag_family)))
486ccd99 3024 return 0;
82d73ea0
DA
3025
3026 parse_diag_msg(h, &s);
be7e4d20 3027 s.type = diag_arg->protocol;
82d73ea0
DA
3028
3029 if (diag_arg->f->f && run_ssfilter(diag_arg->f->f, &s) == 0)
3030 return 0;
3031
41fe6c34 3032 if (diag_arg->f->kill && kill_inet_sock(h, arg, &s) != 0) {
fb2594c1
LC
3033 if (errno == EOPNOTSUPP || errno == ENOENT) {
3034 /* Socket can't be closed, or is already closed. */
3035 return 0;
3036 } else {
3037 perror("SOCK_DESTROY answers");
3038 return -1;
3039 }
3040 }
82d73ea0 3041
be7e4d20 3042 err = inet_show_sock(h, &s);
82d73ea0 3043 if (err < 0)
486ccd99 3044 return err;
aba5acdf 3045
486ccd99
VK
3046 return 0;
3047}
886d19d6 3048
486ccd99
VK
3049static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)
3050{
3051 int err = 0;
fb2594c1 3052 struct rtnl_handle rth, rth2;
486ccd99
VK
3053 int family = PF_INET;
3054 struct inet_diag_arg arg = { .f = f, .protocol = protocol };
886d19d6 3055
486ccd99
VK
3056 if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
3057 return -1;
fb2594c1
LC
3058
3059 if (f->kill) {
3060 if (rtnl_open_byproto(&rth2, 0, NETLINK_SOCK_DIAG)) {
3061 rtnl_close(&rth);
3062 return -1;
3063 }
3064 arg.rth = &rth2;
3065 }
3066
486ccd99
VK
3067 rth.dump = MAGIC_SEQ;
3068 rth.dump_fp = dump_fp;
518af1e0
ED
3069 if (preferred_family == PF_INET6)
3070 family = PF_INET6;
886d19d6 3071
486ccd99
VK
3072again:
3073 if ((err = sockdiag_send(family, rth.fd, protocol, f)))
3074 goto Exit;
aba5acdf 3075
486ccd99
VK
3076 if ((err = rtnl_dump_filter(&rth, show_one_inet_sock, &arg))) {
3077 if (family != PF_UNSPEC) {
3078 family = PF_UNSPEC;
3079 goto again;
aba5acdf 3080 }
486ccd99 3081 goto Exit;
aba5acdf 3082 }
518af1e0 3083 if (family == PF_INET && preferred_family != PF_INET) {
886d19d6
PE
3084 family = PF_INET6;
3085 goto again;
3086 }
3087
486ccd99
VK
3088Exit:
3089 rtnl_close(&rth);
fb2594c1
LC
3090 if (arg.rth)
3091 rtnl_close(arg.rth);
486ccd99 3092 return err;
aba5acdf
SH
3093}
3094
ab01dbbb 3095static int tcp_show_netlink_file(struct filter *f)
aba5acdf
SH
3096{
3097 FILE *fp;
e557212e 3098 char buf[16384];
4b45ae22 3099 int err = -1;
aba5acdf
SH
3100
3101 if ((fp = fopen(getenv("TCPDIAG_FILE"), "r")) == NULL) {
3102 perror("fopen($TCPDIAG_FILE)");
4b45ae22 3103 return err;
aba5acdf
SH
3104 }
3105
3106 while (1) {
4b45ae22 3107 int status, err2;
acd1e437 3108 struct nlmsghdr *h = (struct nlmsghdr *)buf;
82d73ea0 3109 struct sockstat s = {};
aba5acdf
SH
3110
3111 status = fread(buf, 1, sizeof(*h), fp);
3112 if (status < 0) {
3113 perror("Reading header from $TCPDIAG_FILE");
4b45ae22 3114 break;
aba5acdf
SH
3115 }
3116 if (status != sizeof(*h)) {
3117 perror("Unexpected EOF reading $TCPDIAG_FILE");
4b45ae22 3118 break;
aba5acdf
SH
3119 }
3120
3121 status = fread(h+1, 1, NLMSG_ALIGN(h->nlmsg_len-sizeof(*h)), fp);
3122
3123 if (status < 0) {
3124 perror("Reading $TCPDIAG_FILE");
4b45ae22 3125 break;
aba5acdf
SH
3126 }
3127 if (status + sizeof(*h) < h->nlmsg_len) {
3128 perror("Unexpected EOF reading $TCPDIAG_FILE");
4b45ae22 3129 break;
aba5acdf
SH
3130 }
3131
3132 /* The only legal exit point */
4b45ae22
PS
3133 if (h->nlmsg_type == NLMSG_DONE) {
3134 err = 0;
3135 break;
3136 }
aba5acdf
SH
3137
3138 if (h->nlmsg_type == NLMSG_ERROR) {
acd1e437
SH
3139 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
3140
aba5acdf
SH
3141 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
3142 fprintf(stderr, "ERROR truncated\n");
3143 } else {
3144 errno = -err->error;
3145 perror("TCPDIAG answered");
3146 }
4b45ae22 3147 break;
aba5acdf
SH
3148 }
3149
82d73ea0 3150 parse_diag_msg(h, &s);
be7e4d20 3151 s.type = IPPROTO_TCP;
82d73ea0
DA
3152
3153 if (f && f->f && run_ssfilter(f->f, &s) == 0)
3154 continue;
3155
4b45ae22
PS
3156 err2 = inet_show_sock(h, &s);
3157 if (err2 < 0) {
3158 err = err2;
3159 break;
3160 }
aba5acdf 3161 }
4b45ae22
PS
3162
3163 fclose(fp);
3164 return err;
aba5acdf
SH
3165}
3166
6c6bbc30 3167static int tcp_show(struct filter *f)
aba5acdf 3168{
ab01dbbb 3169 FILE *fp = NULL;
aba5acdf
SH
3170 char *buf = NULL;
3171 int bufsize = 64*1024;
3172
1527a17e
VK
3173 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
3174 return 0;
3175
aba5acdf
SH
3176 dg_proto = TCP_PROTO;
3177
3178 if (getenv("TCPDIAG_FILE"))
3179 return tcp_show_netlink_file(f);
3180
3181 if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT")
6c6bbc30 3182 && inet_show_netlink(f, NULL, IPPROTO_TCP) == 0)
aba5acdf
SH
3183 return 0;
3184
3185 /* Sigh... We have to parse /proc/net/tcp... */
3186
ab01dbbb 3187
aba5acdf
SH
3188 /* Estimate amount of sockets and try to allocate
3189 * huge buffer to read all the table at one read.
3190 * Limit it by 16MB though. The assumption is: as soon as
3191 * kernel was able to hold information about N connections,
3192 * it is able to give us some memory for snapshot.
3193 */
3194 if (1) {
a221d621
BL
3195 get_slabstat(&slabstat);
3196
aba5acdf 3197 int guess = slabstat.socks+slabstat.tcp_syns;
acd1e437 3198
aba5acdf
SH
3199 if (f->states&(1<<SS_TIME_WAIT))
3200 guess += slabstat.tcp_tws;
3201 if (guess > (16*1024*1024)/128)
3202 guess = (16*1024*1024)/128;
3203 guess *= 128;
3204 if (guess > bufsize)
3205 bufsize = guess;
3206 }
3207 while (bufsize >= 64*1024) {
3208 if ((buf = malloc(bufsize)) != NULL)
3209 break;
3210 bufsize /= 2;
3211 }
3212 if (buf == NULL) {
3213 errno = ENOMEM;
3214 return -1;
3215 }
3216
b338a3e7 3217 if (f->families & FAMILY_MASK(AF_INET)) {
69cae645 3218 if ((fp = net_tcp_open()) == NULL)
aba5acdf 3219 goto outerr;
ab01dbbb
SH
3220
3221 setbuffer(fp, buf, bufsize);
3222 if (generic_record_read(fp, tcp_show_line, f, AF_INET))
aba5acdf 3223 goto outerr;
ab01dbbb 3224 fclose(fp);
aba5acdf
SH
3225 }
3226
b338a3e7 3227 if ((f->families & FAMILY_MASK(AF_INET6)) &&
69cae645 3228 (fp = net_tcp6_open()) != NULL) {
ab01dbbb
SH
3229 setbuffer(fp, buf, bufsize);
3230 if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
aba5acdf 3231 goto outerr;
ab01dbbb 3232 fclose(fp);
aba5acdf
SH
3233 }
3234
3235 free(buf);
3236 return 0;
3237
3238outerr:
3239 do {
3240 int saved_errno = errno;
acd1e437 3241
92de1c2c 3242 free(buf);
ab01dbbb
SH
3243 if (fp)
3244 fclose(fp);
aba5acdf
SH
3245 errno = saved_errno;
3246 return -1;
3247 } while (0);
3248}
3249
6c6bbc30
PS
3250static int dccp_show(struct filter *f)
3251{
3252 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
3253 return 0;
3254
3255 if (!getenv("PROC_NET_DCCP") && !getenv("PROC_ROOT")
3256 && inet_show_netlink(f, NULL, IPPROTO_DCCP) == 0)
3257 return 0;
3258
3259 return 0;
3260}
3261
f89d46ad
PS
3262static int sctp_show(struct filter *f)
3263{
3264 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
3265 return 0;
3266
3267 if (!getenv("PROC_NET_SCTP") && !getenv("PROC_ROOT")
3268 && inet_show_netlink(f, NULL, IPPROTO_SCTP) == 0)
3269 return 0;
3270
3271 return 0;
3272}
aba5acdf 3273
d1f28cf1 3274static int dgram_show_line(char *line, const struct filter *f, int family)
aba5acdf 3275{
055840f2 3276 struct sockstat s = {};
aba5acdf
SH
3277 char *loc, *rem, *data;
3278 char opt[256];
3279 int n;
aba5acdf 3280
8250bc9f 3281 if (proc_inet_split_line(line, &loc, &rem, &data))
aba5acdf 3282 return -1;
aba5acdf 3283
8250bc9f 3284 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
acd1e437 3285
8250bc9f
VK
3286 if (!(f->states & (1 << state)))
3287 return 0;
aba5acdf 3288
8250bc9f 3289 proc_parse_inet_addr(loc, rem, family, &s);
aba5acdf
SH
3290
3291 if (f->f && run_ssfilter(f->f, &s) == 0)
3292 return 0;
3293
3294 opt[0] = 0;
e7113c61 3295 n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
aba5acdf
SH
3296 &s.state, &s.wq, &s.rq,
3297 &s.uid, &s.ino,
3298 &s.refcnt, &s.sk, opt);
3299
3300 if (n < 9)
3301 opt[0] = 0;
3302
be7e4d20 3303 s.type = dg_proto == UDP_PROTO ? IPPROTO_UDP : 0;
1267c0b9 3304 inet_stats_print(&s, false);
aba5acdf 3305
f1b39e1b 3306 if (show_details && opt[0])
90351722 3307 out(" opt:\"%s\"", opt);
aba5acdf
SH
3308
3309 return 0;
3310}
3311
d1f28cf1 3312static int udp_show(struct filter *f)
aba5acdf 3313{
ab01dbbb 3314 FILE *fp = NULL;
aba5acdf 3315
1527a17e
VK
3316 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
3317 return 0;
3318
ace5cb31
VK
3319 dg_proto = UDP_PROTO;
3320
346f8ca8
PE
3321 if (!getenv("PROC_NET_UDP") && !getenv("PROC_ROOT")
3322 && inet_show_netlink(f, NULL, IPPROTO_UDP) == 0)
3323 return 0;
3324
b338a3e7 3325 if (f->families&FAMILY_MASK(AF_INET)) {
69cae645 3326 if ((fp = net_udp_open()) == NULL)
aba5acdf 3327 goto outerr;
ab01dbbb 3328 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
aba5acdf 3329 goto outerr;
ab01dbbb 3330 fclose(fp);
aba5acdf
SH
3331 }
3332
b338a3e7 3333 if ((f->families&FAMILY_MASK(AF_INET6)) &&
69cae645 3334 (fp = net_udp6_open()) != NULL) {
ab01dbbb 3335 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
aba5acdf 3336 goto outerr;
ab01dbbb 3337 fclose(fp);
aba5acdf
SH
3338 }
3339 return 0;
3340
3341outerr:
3342 do {
3343 int saved_errno = errno;
acd1e437 3344
ab01dbbb
SH
3345 if (fp)
3346 fclose(fp);
aba5acdf
SH
3347 errno = saved_errno;
3348 return -1;
3349 } while (0);
3350}
3351
d1f28cf1 3352static int raw_show(struct filter *f)
aba5acdf 3353{
ab01dbbb 3354 FILE *fp = NULL;
aba5acdf 3355
1527a17e
VK
3356 if (!filter_af_get(f, AF_INET) && !filter_af_get(f, AF_INET6))
3357 return 0;
3358
aba5acdf
SH
3359 dg_proto = RAW_PROTO;
3360
41fe6c34
CG
3361 if (!getenv("PROC_NET_RAW") && !getenv("PROC_ROOT") &&
3362 inet_show_netlink(f, NULL, IPPROTO_RAW) == 0)
3363 return 0;
3364
b338a3e7 3365 if (f->families&FAMILY_MASK(AF_INET)) {
69cae645 3366 if ((fp = net_raw_open()) == NULL)
aba5acdf 3367 goto outerr;
ab01dbbb 3368 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
aba5acdf 3369 goto outerr;
ab01dbbb 3370 fclose(fp);
aba5acdf
SH
3371 }
3372
b338a3e7 3373 if ((f->families&FAMILY_MASK(AF_INET6)) &&
69cae645 3374 (fp = net_raw6_open()) != NULL) {
ab01dbbb 3375 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
aba5acdf 3376 goto outerr;
ab01dbbb 3377 fclose(fp);
aba5acdf
SH
3378 }
3379 return 0;
3380
3381outerr:
3382 do {
3383 int saved_errno = errno;
acd1e437 3384
ab01dbbb
SH
3385 if (fp)
3386 fclose(fp);
aba5acdf
SH
3387 errno = saved_errno;
3388 return -1;
3389 } while (0);
3390}
3391
ec4d0d8a 3392#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct sockstat))
aba5acdf 3393
2d0e538f 3394static void unix_list_drop_first(struct sockstat **list)
aba5acdf 3395{
2d0e538f 3396 struct sockstat *s = *list;
ec4d0d8a 3397
2d0e538f
PS
3398 (*list) = (*list)->next;
3399 free(s->name);
3400 free(s);
aba5acdf
SH
3401}
3402
ec4d0d8a 3403static bool unix_type_skip(struct sockstat *s, struct filter *f)
bf4ceee6
VK
3404{
3405 if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
3406 return true;
3407 if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
3408 return true;
3409 if (s->type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
3410 return true;
3411 return false;
3412}
3413
2d0e538f 3414static void unix_stats_print(struct sockstat *s, struct filter *f)
aba5acdf 3415{
b217df10 3416 char port_name[30] = {};
aba5acdf 3417
2d0e538f 3418 sock_state_print(s);
2d791bc8 3419
2d0e538f
PS
3420 sock_addr_print(s->name ?: "*", " ",
3421 int_to_str(s->lport, port_name), NULL);
3422 sock_addr_print(s->peer_name ?: "*", " ",
3423 int_to_str(s->rport, port_name), NULL);
116ac927 3424
2d0e538f 3425 proc_ctx_print(s);
aba5acdf
SH
3426}
3427
8a4025f6 3428static int unix_show_sock(const struct sockaddr_nl *addr, struct nlmsghdr *nlh,
3429 void *arg)
dfbaa90d 3430{
8a4025f6 3431 struct filter *f = (struct filter *)arg;
dfbaa90d
PE
3432 struct unix_diag_msg *r = NLMSG_DATA(nlh);
3433 struct rtattr *tb[UNIX_DIAG_MAX+1];
99bb68ff
VK
3434 char name[128];
3435 struct sockstat stat = { .name = "*", .peer_name = "*" };
dfbaa90d 3436
acd1e437 3437 parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr *)(r+1),
dfbaa90d
PE
3438 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
3439
bf4ceee6
VK
3440 stat.type = r->udiag_type;
3441 stat.state = r->udiag_state;
ec4d0d8a
VK
3442 stat.ino = stat.lport = r->udiag_ino;
3443 stat.local.family = stat.remote.family = AF_UNIX;
0d2e01c5 3444
bf4ceee6
VK
3445 if (unix_type_skip(&stat, f))
3446 return 0;
dfbaa90d 3447
defd61ca
HFS
3448 if (tb[UNIX_DIAG_RQLEN]) {
3449 struct unix_diag_rqlen *rql = RTA_DATA(tb[UNIX_DIAG_RQLEN]);
acd1e437 3450
bf4ceee6
VK
3451 stat.rq = rql->udiag_rqueue;
3452 stat.wq = rql->udiag_wqueue;
defd61ca 3453 }
dfbaa90d
PE
3454 if (tb[UNIX_DIAG_NAME]) {
3455 int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
3456
3457 memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
3458 name[len] = '\0';
1dd0cca7
SH
3459 if (name[0] == '\0') {
3460 int i;
3461 for (i = 0; i < len; i++)
878dadc7
IB
3462 if (name[i] == '\0')
3463 name[i] = '@';
1dd0cca7 3464 }
99bb68ff
VK
3465 stat.name = &name[0];
3466 memcpy(stat.local.data, &stat.name, sizeof(stat.name));
bf4ceee6 3467 }
dfbaa90d 3468 if (tb[UNIX_DIAG_PEER])
ec4d0d8a 3469 stat.rport = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
dfbaa90d 3470
29999b0f
VK
3471 if (f->f && run_ssfilter(f->f, &stat) == 0)
3472 return 0;
3473
bf4ceee6 3474 unix_stats_print(&stat, f);
dfbaa90d 3475
45199997 3476 if (show_mem)
51ff9f24 3477 print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
5b816047
PE
3478 if (show_details) {
3479 if (tb[UNIX_DIAG_SHUTDOWN]) {
3480 unsigned char mask;
acd1e437 3481
9f1370c0 3482 mask = rta_getattr_u8(tb[UNIX_DIAG_SHUTDOWN]);
90351722
SB
3483 out(" %c-%c",
3484 mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
5b816047
PE
3485 }
3486 }
ec4d0d8a 3487
dfbaa90d
PE
3488 return 0;
3489}
3490
8a4025f6 3491static int handle_netlink_request(struct filter *f, struct nlmsghdr *req,
3492 size_t size, rtnl_filter_t show_one_sock)
dfbaa90d 3493{
8a4025f6 3494 int ret = -1;
3495 struct rtnl_handle rth;
dfbaa90d 3496
8a4025f6 3497 if (rtnl_open_byproto(&rth, 0, NETLINK_SOCK_DIAG))
dfbaa90d
PE
3498 return -1;
3499
8a4025f6 3500 rth.dump = MAGIC_SEQ;
dfbaa90d 3501
8a4025f6 3502 if (rtnl_send(&rth, req, size) < 0)
3503 goto Exit;
dfbaa90d 3504
8a4025f6 3505 if (rtnl_dump_filter(&rth, show_one_sock, f))
3506 goto Exit;
dfbaa90d 3507
8a4025f6 3508 ret = 0;
3509Exit:
3510 rtnl_close(&rth);
3511 return ret;
dfbaa90d
PE
3512}
3513
8a4025f6 3514static int unix_show_netlink(struct filter *f)
d8402b96 3515{
5fb421d4 3516 DIAG_REQUEST(req, struct unix_diag_req r);
d8402b96
AV
3517
3518 req.r.sdiag_family = AF_UNIX;
3519 req.r.udiag_states = f->states;
3520 req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
3521 if (show_mem)
3522 req.r.udiag_show |= UDIAG_SHOW_MEMINFO;
3523
8a4025f6 3524 return handle_netlink_request(f, &req.nlh, sizeof(req), unix_show_sock);
d8402b96
AV
3525}
3526
d1f28cf1 3527static int unix_show(struct filter *f)
aba5acdf
SH
3528{
3529 FILE *fp;
3530 char buf[256];
3531 char name[128];
3532 int newformat = 0;
3533 int cnt;
ec4d0d8a 3534 struct sockstat *list = NULL;
96d45daa
PS
3535 const int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
3536 SS_ESTABLISHED, SS_CLOSING };
aba5acdf 3537
9db7bf15
VK
3538 if (!filter_af_get(f, AF_UNIX))
3539 return 0;
3540
f25062e9
PS
3541 if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
3542 && unix_show_netlink(f) == 0)
dfbaa90d
PE
3543 return 0;
3544
ab01dbbb 3545 if ((fp = net_unix_open()) == NULL)
aba5acdf 3546 return -1;
61170fd8 3547 if (!fgets(buf, sizeof(buf), fp)) {
d572ed4d
PS
3548 fclose(fp);
3549 return -1;
3550 }
aba5acdf 3551
ae665a52 3552 if (memcmp(buf, "Peer", 4) == 0)
aba5acdf
SH
3553 newformat = 1;
3554 cnt = 0;
3555
61170fd8 3556 while (fgets(buf, sizeof(buf), fp)) {
ec4d0d8a 3557 struct sockstat *u, **insp;
aba5acdf
SH
3558 int flags;
3559
0ee9052f 3560 if (!(u = calloc(1, sizeof(*u))))
aba5acdf 3561 break;
aba5acdf
SH
3562
3563 if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
ec4d0d8a 3564 &u->rport, &u->rq, &u->wq, &flags, &u->type,
aba5acdf
SH
3565 &u->state, &u->ino, name) < 8)
3566 name[0] = 0;
3567
ec4d0d8a
VK
3568 u->lport = u->ino;
3569 u->local.family = u->remote.family = AF_UNIX;
3570
3571 if (flags & (1 << 16)) {
aba5acdf 3572 u->state = SS_LISTEN;
0aa03350
PS
3573 } else if (u->state > 0 &&
3574 u->state <= ARRAY_SIZE(unix_state_map)) {
aba5acdf 3575 u->state = unix_state_map[u->state-1];
ec4d0d8a 3576 if (u->type == SOCK_DGRAM && u->state == SS_CLOSE && u->rport)
aba5acdf
SH
3577 u->state = SS_ESTABLISHED;
3578 }
2d0e538f
PS
3579 if (unix_type_skip(u, f) ||
3580 !(f->states & (1 << u->state))) {
3581 free(u);
3582 continue;
3583 }
aba5acdf
SH
3584
3585 if (!newformat) {
ec4d0d8a 3586 u->rport = 0;
aba5acdf
SH
3587 u->rq = 0;
3588 u->wq = 0;
3589 }
3590
2d0e538f
PS
3591 if (name[0]) {
3592 u->name = strdup(name);
46131577
PS
3593 if (!u->name) {
3594 free(u);
2d0e538f 3595 break;
46131577 3596 }
2d0e538f
PS
3597 }
3598
3599 if (u->rport) {
3600 struct sockstat *p;
3601
3602 for (p = list; p; p = p->next) {
3603 if (u->rport == p->lport)
3604 break;
3605 }
3606 if (!p)
3607 u->peer_name = "?";
3608 else
3609 u->peer_name = p->name ? : "*";
3610 }
3611
3612 if (f->f) {
3613 struct sockstat st = {
3614 .local.family = AF_UNIX,
3615 .remote.family = AF_UNIX,
3616 };
3617
3618 memcpy(st.local.data, &u->name, sizeof(u->name));
3619 if (strcmp(u->peer_name, "*"))
3620 memcpy(st.remote.data, &u->peer_name,
3621 sizeof(u->peer_name));
3622 if (run_ssfilter(f->f, &st) == 0) {
3623 free(u->name);
3624 free(u);
3625 continue;
3626 }
3627 }
3628
aba5acdf
SH
3629 insp = &list;
3630 while (*insp) {
3631 if (u->type < (*insp)->type ||
3632 (u->type == (*insp)->type &&
3633 u->ino < (*insp)->ino))
3634 break;
3635 insp = &(*insp)->next;
3636 }
3637 u->next = *insp;
3638 *insp = u;
3639
aba5acdf 3640 if (++cnt > MAX_UNIX_REMEMBER) {
2d0e538f
PS
3641 while (list) {
3642 unix_stats_print(list, f);
2d0e538f
PS
3643 unix_list_drop_first(&list);
3644 }
aba5acdf
SH
3645 cnt = 0;
3646 }
3647 }
a3fd8e58 3648 fclose(fp);
2d0e538f 3649 while (list) {
bf4ceee6 3650 unix_stats_print(list, f);
2d0e538f 3651 unix_list_drop_first(&list);
aba5acdf
SH
3652 }
3653
3654 return 0;
3655}
3656
89f634f9 3657static int packet_stats_print(struct sockstat *s, const struct filter *f)
4a0053b6 3658{
b217df10
VK
3659 const char *addr, *port;
3660 char ll_name[16];
372c30d2 3661
be7e4d20
PS
3662 s->local.family = s->remote.family = AF_PACKET;
3663
4a0053b6 3664 if (f->f) {
89f634f9 3665 s->local.data[0] = s->prot;
89f634f9 3666 if (run_ssfilter(f->f, s) == 0)
4a0053b6
VK
3667 return 1;
3668 }
372c30d2 3669
be7e4d20 3670 sock_state_print(s);
372c30d2 3671
b217df10
VK
3672 if (s->prot == 3)
3673 addr = "*";
3674 else
3675 addr = ll_proto_n2a(htons(s->prot), ll_name, sizeof(ll_name));
3676
3677 if (s->iface == 0)
3678 port = "*";
3679 else
3680 port = xll_index_to_name(s->iface);
372c30d2 3681
b217df10
VK
3682 sock_addr_print(addr, ":", port, NULL);
3683 sock_addr_print("", "*", "", NULL);
116ac927 3684
5f27ac1d 3685 proc_ctx_print(s);
116ac927 3686
f1b39e1b
VK
3687 if (show_details)
3688 sock_details_print(s);
3689
4a0053b6
VK
3690 return 0;
3691}
3692
2631b856
VK
3693static void packet_show_ring(struct packet_diag_ring *ring)
3694{
90351722
SB
3695 out("blk_size:%d", ring->pdr_block_size);
3696 out(",blk_nr:%d", ring->pdr_block_nr);
3697 out(",frm_size:%d", ring->pdr_frame_size);
3698 out(",frm_nr:%d", ring->pdr_frame_nr);
3699 out(",tmo:%d", ring->pdr_retire_tmo);
3700 out(",features:0x%x", ring->pdr_features);
2631b856
VK
3701}
3702
4a0053b6
VK
3703static int packet_show_sock(const struct sockaddr_nl *addr,
3704 struct nlmsghdr *nlh, void *arg)
3705{
3706 const struct filter *f = arg;
3707 struct packet_diag_msg *r = NLMSG_DATA(nlh);
2631b856
VK
3708 struct packet_diag_info *pinfo = NULL;
3709 struct packet_diag_ring *ring_rx = NULL, *ring_tx = NULL;
4a0053b6 3710 struct rtattr *tb[PACKET_DIAG_MAX+1];
89f634f9 3711 struct sockstat stat = {};
2631b856
VK
3712 uint32_t fanout = 0;
3713 bool has_fanout = false;
4a0053b6 3714
acd1e437 3715 parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(r+1),
4a0053b6
VK
3716 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
3717
3718 /* use /proc/net/packet if all info are not available */
3719 if (!tb[PACKET_DIAG_MEMINFO])
3720 return -1;
3721
2d791bc8
VK
3722 stat.type = r->pdiag_type;
3723 stat.prot = r->pdiag_num;
3724 stat.ino = r->pdiag_ino;
3725 stat.state = SS_CLOSE;
f1b39e1b 3726 stat.sk = cookie_sk_get(&r->pdiag_cookie[0]);
4a0053b6
VK
3727
3728 if (tb[PACKET_DIAG_MEMINFO]) {
3729 __u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
acd1e437 3730
4a0053b6
VK
3731 stat.rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
3732 }
3733
3734 if (tb[PACKET_DIAG_INFO]) {
2631b856 3735 pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
2d791bc8 3736 stat.lport = stat.iface = pinfo->pdi_index;
4a0053b6
VK
3737 }
3738
f1b39e1b 3739 if (tb[PACKET_DIAG_UID])
9f1370c0 3740 stat.uid = rta_getattr_u32(tb[PACKET_DIAG_UID]);
f1b39e1b 3741
2631b856
VK
3742 if (tb[PACKET_DIAG_RX_RING])
3743 ring_rx = RTA_DATA(tb[PACKET_DIAG_RX_RING]);
3744
3745 if (tb[PACKET_DIAG_TX_RING])
3746 ring_tx = RTA_DATA(tb[PACKET_DIAG_TX_RING]);
3747
3748 if (tb[PACKET_DIAG_FANOUT]) {
3749 has_fanout = true;
9f1370c0 3750 fanout = rta_getattr_u32(tb[PACKET_DIAG_FANOUT]);
2631b856
VK
3751 }
3752
4a0053b6
VK
3753 if (packet_stats_print(&stat, f))
3754 return 0;
3755
2631b856
VK
3756 if (show_details) {
3757 if (pinfo) {
90351722
SB
3758 out("\n\tver:%d", pinfo->pdi_version);
3759 out(" cpy_thresh:%d", pinfo->pdi_copy_thresh);
3760 out(" flags( ");
2631b856 3761 if (pinfo->pdi_flags & PDI_RUNNING)
90351722 3762 out("running");
2631b856 3763 if (pinfo->pdi_flags & PDI_AUXDATA)
90351722 3764 out(" auxdata");
2631b856 3765 if (pinfo->pdi_flags & PDI_ORIGDEV)
90351722 3766 out(" origdev");
2631b856 3767 if (pinfo->pdi_flags & PDI_VNETHDR)
90351722 3768 out(" vnethdr");
2631b856 3769 if (pinfo->pdi_flags & PDI_LOSS)
90351722 3770 out(" loss");
2631b856 3771 if (!pinfo->pdi_flags)
90351722
SB
3772 out("0");
3773 out(" )");
2631b856
VK
3774 }
3775 if (ring_rx) {
90351722 3776 out("\n\tring_rx(");
2631b856 3777 packet_show_ring(ring_rx);
90351722 3778 out(")");
2631b856
VK
3779 }
3780 if (ring_tx) {
90351722 3781 out("\n\tring_tx(");
2631b856 3782 packet_show_ring(ring_tx);
90351722 3783 out(")");
2631b856
VK
3784 }
3785 if (has_fanout) {
3786 uint16_t type = (fanout >> 16) & 0xffff;
3787
90351722
SB
3788 out("\n\tfanout(");
3789 out("id:%d,", fanout & 0xffff);
3790 out("type:");
2631b856
VK
3791
3792 if (type == 0)
90351722 3793 out("hash");
2631b856 3794 else if (type == 1)
90351722 3795 out("lb");
2631b856 3796 else if (type == 2)
90351722 3797 out("cpu");
2631b856 3798 else if (type == 3)
90351722 3799 out("roll");
2631b856 3800 else if (type == 4)
90351722 3801 out("random");
2631b856 3802 else if (type == 5)
90351722 3803 out("qm");
2631b856 3804 else
90351722 3805 out("0x%x", type);
2631b856 3806
90351722 3807 out(")");
2631b856
VK
3808 }
3809 }
3810
372c30d2
ND
3811 if (show_bpf && tb[PACKET_DIAG_FILTER]) {
3812 struct sock_filter *fil =
3813 RTA_DATA(tb[PACKET_DIAG_FILTER]);
3814 int num = RTA_PAYLOAD(tb[PACKET_DIAG_FILTER]) /
3815 sizeof(struct sock_filter);
3816
90351722 3817 out("\n\tbpf filter (%d): ", num);
372c30d2 3818 while (num) {
90351722
SB
3819 out(" 0x%02x %u %u %u,",
3820 fil->code, fil->jt, fil->jf, fil->k);
372c30d2
ND
3821 num--;
3822 fil++;
3823 }
3824 }
372c30d2
ND
3825 return 0;
3826}
3827
8a4025f6 3828static int packet_show_netlink(struct filter *f)
372c30d2 3829{
5fb421d4 3830 DIAG_REQUEST(req, struct packet_diag_req r);
372c30d2 3831
372c30d2 3832 req.r.sdiag_family = AF_PACKET;
2631b856
VK
3833 req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO |
3834 PACKET_SHOW_FILTER | PACKET_SHOW_RING_CFG | PACKET_SHOW_FANOUT;
372c30d2 3835
8a4025f6 3836 return handle_netlink_request(f, &req.nlh, sizeof(req), packet_show_sock);
372c30d2
ND
3837}
3838
4a0053b6
VK
3839static int packet_show_line(char *buf, const struct filter *f, int fam)
3840{
3841 unsigned long long sk;
89f634f9 3842 struct sockstat stat = {};
4a0053b6
VK
3843 int type, prot, iface, state, rq, uid, ino;
3844
3845 sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
3846 &sk,
3847 &type, &prot, &iface, &state,
3848 &rq, &uid, &ino);
3849
3850 if (stat.type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
3851 return 0;
3852 if (stat.type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
3853 return 0;
3854
3855 stat.type = type;
3856 stat.prot = prot;
2d791bc8 3857 stat.lport = stat.iface = iface;
4a0053b6
VK
3858 stat.state = state;
3859 stat.rq = rq;
3860 stat.uid = uid;
3861 stat.ino = ino;
2d791bc8
VK
3862 stat.state = SS_CLOSE;
3863
4a0053b6
VK
3864 if (packet_stats_print(&stat, f))
3865 return 0;
3866
4a0053b6
VK
3867 return 0;
3868}
aba5acdf 3869
d1f28cf1 3870static int packet_show(struct filter *f)
aba5acdf
SH
3871{
3872 FILE *fp;
b95d28c3 3873 int rc = 0;
3d0b7439 3874
9db7bf15 3875 if (!filter_af_get(f, AF_PACKET) || !(f->states & (1 << SS_CLOSE)))
b9ea445d 3876 return 0;
aba5acdf 3877
4a0053b6
VK
3878 if (!getenv("PROC_NET_PACKET") && !getenv("PROC_ROOT") &&
3879 packet_show_netlink(f) == 0)
372c30d2
ND
3880 return 0;
3881
ab01dbbb 3882 if ((fp = net_packet_open()) == NULL)
aba5acdf 3883 return -1;
4a0053b6 3884 if (generic_record_read(fp, packet_show_line, f, AF_PACKET))
b95d28c3 3885 rc = -1;
aba5acdf 3886
b95d28c3
PS
3887 fclose(fp);
3888 return rc;
aba5acdf
SH
3889}
3890
5f24ec0e 3891static int netlink_show_one(struct filter *f,
acd1e437
SH
3892 int prot, int pid, unsigned int groups,
3893 int state, int dst_pid, unsigned int dst_group,
129709ae
AV
3894 int rq, int wq,
3895 unsigned long long sk, unsigned long long cb)
3896{
301826be
PS
3897 struct sockstat st = {
3898 .state = SS_CLOSE,
3899 .rq = rq,
3900 .wq = wq,
3901 .local.family = AF_NETLINK,
3902 .remote.family = AF_NETLINK,
3903 };
acd1e437 3904
b217df10
VK
3905 SPRINT_BUF(prot_buf) = {};
3906 const char *prot_name;
3907 char procname[64] = {};
eef43b50 3908
129709ae 3909 if (f->f) {
055840f2
VK
3910 st.rport = -1;
3911 st.lport = pid;
3912 st.local.data[0] = prot;
055840f2 3913 if (run_ssfilter(f->f, &st) == 0)
5f24ec0e 3914 return 1;
129709ae
AV
3915 }
3916
be7e4d20 3917 sock_state_print(&st);
eef43b50 3918
b217df10
VK
3919 if (resolve_services)
3920 prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf));
3921 else
3922 prot_name = int_to_str(prot, prot_buf);
eef43b50 3923
129709ae 3924 if (pid == -1) {
b217df10 3925 procname[0] = '*';
129709ae
AV
3926 } else if (resolve_services) {
3927 int done = 0;
acd1e437 3928
129709ae
AV
3929 if (!pid) {
3930 done = 1;
b217df10 3931 strncpy(procname, "kernel", 6);
129709ae 3932 } else if (pid > 0) {
129709ae 3933 FILE *fp;
acd1e437 3934
0ee9052f 3935 snprintf(procname, sizeof(procname), "%s/%d/stat",
129709ae
AV
3936 getenv("PROC_ROOT") ? : "/proc", pid);
3937 if ((fp = fopen(procname, "r")) != NULL) {
3938 if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
0ee9052f 3939 snprintf(procname+strlen(procname),
3940 sizeof(procname)-strlen(procname),
3941 "/%d", pid);
129709ae
AV
3942 done = 1;
3943 }
3944 fclose(fp);
3945 }
3946 }
3947 if (!done)
b217df10 3948 int_to_str(pid, procname);
129709ae 3949 } else {
b217df10 3950 int_to_str(pid, procname);
129709ae 3951 }
f271fe01 3952
b217df10
VK
3953 sock_addr_print(prot_name, ":", procname, NULL);
3954
f271fe01 3955 if (state == NETLINK_CONNECTED) {
b217df10
VK
3956 char dst_group_buf[30];
3957 char dst_pid_buf[30];
acd1e437 3958
b217df10
VK
3959 sock_addr_print(int_to_str(dst_group, dst_group_buf), ":",
3960 int_to_str(dst_pid, dst_pid_buf), NULL);
f271fe01 3961 } else {
b217df10 3962 sock_addr_print("", "*", "", NULL);
f271fe01 3963 }
129709ae 3964
116ac927 3965 char *pid_context = NULL;
acd1e437 3966
116ac927
RH
3967 if (show_proc_ctx) {
3968 /* The pid value will either be:
3969 * 0 if destination kernel - show kernel initial context.
3970 * A valid process pid - use getpidcon.
3971 * A unique value allocated by the kernel or netlink user
3972 * to the process - show context as "not available".
3973 */
3974 if (!pid)
3975 security_get_initial_context("kernel", &pid_context);
3976 else if (pid > 0)
3977 getpidcon(pid, &pid_context);
3978
90351722 3979 out(" proc_ctx=%s", pid_context ? : "unavailable");
22658ff5 3980 free(pid_context);
116ac927
RH
3981 }
3982
129709ae 3983 if (show_details) {
90351722 3984 out(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
129709ae 3985 }
129709ae 3986
5f24ec0e 3987 return 0;
129709ae
AV
3988}
3989
8a4025f6 3990static int netlink_show_sock(const struct sockaddr_nl *addr,
3991 struct nlmsghdr *nlh, void *arg)
ecb928c8 3992{
8a4025f6 3993 struct filter *f = (struct filter *)arg;
ecb928c8
AV
3994 struct netlink_diag_msg *r = NLMSG_DATA(nlh);
3995 struct rtattr *tb[NETLINK_DIAG_MAX+1];
3996 int rq = 0, wq = 0;
3997 unsigned long groups = 0;
3998
acd1e437 3999 parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr *)(r+1),
ecb928c8
AV
4000 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
4001
4002 if (tb[NETLINK_DIAG_GROUPS] && RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS]))
4003 groups = *(unsigned long *) RTA_DATA(tb[NETLINK_DIAG_GROUPS]);
4004
4005 if (tb[NETLINK_DIAG_MEMINFO]) {
4006 const __u32 *skmeminfo;
acd1e437 4007
ecb928c8
AV
4008 skmeminfo = RTA_DATA(tb[NETLINK_DIAG_MEMINFO]);
4009
4010 rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
4011 wq = skmeminfo[SK_MEMINFO_WMEM_ALLOC];
4012 }
4013
5f24ec0e 4014 if (netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
ecb928c8 4015 r->ndiag_state, r->ndiag_dst_portid, r->ndiag_dst_group,
5f24ec0e
VK
4016 rq, wq, 0, 0)) {
4017 return 0;
4018 }
ecb928c8
AV
4019
4020 if (show_mem) {
90351722 4021 out("\t");
ecb928c8 4022 print_skmeminfo(tb, NETLINK_DIAG_MEMINFO);
ecb928c8
AV
4023 }
4024
4025 return 0;
4026}
4027
8a4025f6 4028static int netlink_show_netlink(struct filter *f)
ecb928c8 4029{
5fb421d4 4030 DIAG_REQUEST(req, struct netlink_diag_req r);
ecb928c8
AV
4031
4032 req.r.sdiag_family = AF_NETLINK;
4033 req.r.sdiag_protocol = NDIAG_PROTO_ALL;
4034 req.r.ndiag_show = NDIAG_SHOW_GROUPS | NDIAG_SHOW_MEMINFO;
4035
8a4025f6 4036 return handle_netlink_request(f, &req.nlh, sizeof(req), netlink_show_sock);
ecb928c8
AV
4037}
4038
d1f28cf1 4039static int netlink_show(struct filter *f)
aba5acdf
SH
4040{
4041 FILE *fp;
4042 char buf[256];
4043 int prot, pid;
acd1e437 4044 unsigned int groups;
aba5acdf
SH
4045 int rq, wq, rc;
4046 unsigned long long sk, cb;
4047
9db7bf15 4048 if (!filter_af_get(f, AF_NETLINK) || !(f->states & (1 << SS_CLOSE)))
b9ea445d
VK
4049 return 0;
4050
129709ae 4051 if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") &&
8a4025f6 4052 netlink_show_netlink(f) == 0)
129709ae
AV
4053 return 0;
4054
ab01dbbb 4055 if ((fp = net_netlink_open()) == NULL)
aba5acdf 4056 return -1;
61170fd8 4057 if (!fgets(buf, sizeof(buf), fp)) {
d572ed4d
PS
4058 fclose(fp);
4059 return -1;
4060 }
aba5acdf 4061
61170fd8 4062 while (fgets(buf, sizeof(buf), fp)) {
aba5acdf
SH
4063 sscanf(buf, "%llx %d %d %x %d %d %llx %d",
4064 &sk,
4065 &prot, &pid, &groups, &rq, &wq, &cb, &rc);
4066
f271fe01 4067 netlink_show_one(f, prot, pid, groups, 0, 0, 0, rq, wq, sk, cb);
aba5acdf
SH
4068 }
4069
b95d28c3 4070 fclose(fp);
aba5acdf
SH
4071 return 0;
4072}
4073
c759116a
SH
4074static bool vsock_type_skip(struct sockstat *s, struct filter *f)
4075{
4076 if (s->type == SOCK_STREAM && !(f->dbs & (1 << VSOCK_ST_DB)))
4077 return true;
4078 if (s->type == SOCK_DGRAM && !(f->dbs & (1 << VSOCK_DG_DB)))
4079 return true;
4080 return false;
4081}
4082
4083static void vsock_addr_print(inet_prefix *a, __u32 port)
4084{
4085 char cid_str[sizeof("4294967295")];
4086 char port_str[sizeof("4294967295")];
4087 __u32 cid;
4088
4089 memcpy(&cid, a->data, sizeof(cid));
4090
4091 if (cid == ~(__u32)0)
4092 snprintf(cid_str, sizeof(cid_str), "*");
4093 else
4094 snprintf(cid_str, sizeof(cid_str), "%u", cid);
4095
4096 if (port == ~(__u32)0)
4097 snprintf(port_str, sizeof(port_str), "*");
4098 else
4099 snprintf(port_str, sizeof(port_str), "%u", port);
4100
4101 sock_addr_print(cid_str, ":", port_str, NULL);
4102}
4103
4104static void vsock_stats_print(struct sockstat *s, struct filter *f)
4105{
4106 sock_state_print(s);
4107
4108 vsock_addr_print(&s->local, s->lport);
4109 vsock_addr_print(&s->remote, s->rport);
4110
4111 proc_ctx_print(s);
c759116a
SH
4112}
4113
4114static int vsock_show_sock(const struct sockaddr_nl *addr,
4115 struct nlmsghdr *nlh, void *arg)
4116{
4117 struct filter *f = (struct filter *)arg;
4118 struct vsock_diag_msg *r = NLMSG_DATA(nlh);
4119 struct sockstat stat = {
4120 .type = r->vdiag_type,
4121 .lport = r->vdiag_src_port,
4122 .rport = r->vdiag_dst_port,
4123 .state = r->vdiag_state,
4124 .ino = r->vdiag_ino,
4125 };
4126
4127 vsock_set_inet_prefix(&stat.local, r->vdiag_src_cid);
4128 vsock_set_inet_prefix(&stat.remote, r->vdiag_dst_cid);
4129
4130 if (vsock_type_skip(&stat, f))
4131 return 0;
4132
4133 if (f->f && run_ssfilter(f->f, &stat) == 0)
4134 return 0;
4135
4136 vsock_stats_print(&stat, f);
4137
4138 return 0;
4139}
4140
4141static int vsock_show(struct filter *f)
4142{
4143 DIAG_REQUEST(req, struct vsock_diag_req r);
4144
4145 if (!filter_af_get(f, AF_VSOCK))
4146 return 0;
4147
4148 req.r.sdiag_family = AF_VSOCK;
4149 req.r.vdiag_states = f->states;
4150
4151 return handle_netlink_request(f, &req.nlh, sizeof(req), vsock_show_sock);
4152}
4153
6885e3bf
CG
4154struct sock_diag_msg {
4155 __u8 sdiag_family;
4156};
4157
4158static int generic_show_sock(const struct sockaddr_nl *addr,
4159 struct nlmsghdr *nlh, void *arg)
4160{
4161 struct sock_diag_msg *r = NLMSG_DATA(nlh);
4162 struct inet_diag_arg inet_arg = { .f = arg, .protocol = IPPROTO_MAX };
4163
4164 switch (r->sdiag_family) {
4165 case AF_INET:
4166 case AF_INET6:
4167 return show_one_inet_sock(addr, nlh, &inet_arg);
4168 case AF_UNIX:
4169 return unix_show_sock(addr, nlh, arg);
4170 case AF_PACKET:
4171 return packet_show_sock(addr, nlh, arg);
4172 case AF_NETLINK:
4173 return netlink_show_sock(addr, nlh, arg);
c759116a
SH
4174 case AF_VSOCK:
4175 return vsock_show_sock(addr, nlh, arg);
6885e3bf
CG
4176 default:
4177 return -1;
4178 }
4179}
4180
4181static int handle_follow_request(struct filter *f)
4182{
6b224dad 4183 int ret = 0;
6885e3bf
CG
4184 int groups = 0;
4185 struct rtnl_handle rth;
4186
b338a3e7 4187 if (f->families & FAMILY_MASK(AF_INET) && f->dbs & (1 << TCP_DB))
6885e3bf 4188 groups |= 1 << (SKNLGRP_INET_TCP_DESTROY - 1);
b338a3e7 4189 if (f->families & FAMILY_MASK(AF_INET) && f->dbs & (1 << UDP_DB))
6885e3bf 4190 groups |= 1 << (SKNLGRP_INET_UDP_DESTROY - 1);
b338a3e7 4191 if (f->families & FAMILY_MASK(AF_INET6) && f->dbs & (1 << TCP_DB))
6885e3bf 4192 groups |= 1 << (SKNLGRP_INET6_TCP_DESTROY - 1);
b338a3e7 4193 if (f->families & FAMILY_MASK(AF_INET6) && f->dbs & (1 << UDP_DB))
6885e3bf
CG
4194 groups |= 1 << (SKNLGRP_INET6_UDP_DESTROY - 1);
4195
4196 if (groups == 0)
4197 return -1;
4198
4199 if (rtnl_open_byproto(&rth, groups, NETLINK_SOCK_DIAG))
4200 return -1;
4201
4202 rth.dump = 0;
4203 rth.local.nl_pid = 0;
4204
4205 if (rtnl_dump_filter(&rth, generic_show_sock, f))
6b224dad 4206 ret = -1;
6885e3bf 4207
6885e3bf
CG
4208 rtnl_close(&rth);
4209 return ret;
4210}
4211
d1f28cf1 4212static int get_snmp_int(char *proto, char *key, int *result)
aba5acdf
SH
4213{
4214 char buf[1024];
4215 FILE *fp;
4216 int protolen = strlen(proto);
4217 int keylen = strlen(key);
4218
4219 *result = 0;
4220
ab01dbbb 4221 if ((fp = net_snmp_open()) == NULL)
aba5acdf
SH
4222 return -1;
4223
4224 while (fgets(buf, sizeof(buf), fp) != NULL) {
4225 char *p = buf;
4226 int pos = 0;
acd1e437 4227
aba5acdf
SH
4228 if (memcmp(buf, proto, protolen))
4229 continue;
4230 while ((p = strchr(p, ' ')) != NULL) {
4231 pos++;
4232 p++;
4233 if (memcmp(p, key, keylen) == 0 &&
4234 (p[keylen] == ' ' || p[keylen] == '\n'))
4235 break;
4236 }
4237 if (fgets(buf, sizeof(buf), fp) == NULL)
4238 break;
4239 if (memcmp(buf, proto, protolen))
4240 break;
4241 p = buf;
4242 while ((p = strchr(p, ' ')) != NULL) {
4243 p++;
4244 if (--pos == 0) {
4245 sscanf(p, "%d", result);
4246 fclose(fp);
4247 return 0;
4248 }
4249 }
4250 }
4251
4252 fclose(fp);
4253 errno = ESRCH;
4254 return -1;
4255}
4256
4257
4258/* Get stats from sockstat */
4259
acd1e437 4260struct ssummary {
aba5acdf
SH
4261 int socks;
4262 int tcp_mem;
4263 int tcp_total;
4264 int tcp_orphans;
4265 int tcp_tws;
4266 int tcp4_hashed;
4267 int udp4;
4268 int raw4;
4269 int frag4;
4270 int frag4_mem;
4271 int tcp6_hashed;
4272 int udp6;
4273 int raw6;
4274 int frag6;
4275 int frag6_mem;
4276};
4277
055840f2 4278static void get_sockstat_line(char *line, struct ssummary *s)
aba5acdf
SH
4279{
4280 char id[256], rem[256];
4281
4282 if (sscanf(line, "%[^ ] %[^\n]\n", id, rem) != 2)
4283 return;
4284
4285 if (strcmp(id, "sockets:") == 0)
4286 sscanf(rem, "%*s%d", &s->socks);
4287 else if (strcmp(id, "UDP:") == 0)
4288 sscanf(rem, "%*s%d", &s->udp4);
4289 else if (strcmp(id, "UDP6:") == 0)
4290 sscanf(rem, "%*s%d", &s->udp6);
4291 else if (strcmp(id, "RAW:") == 0)
4292 sscanf(rem, "%*s%d", &s->raw4);
4293 else if (strcmp(id, "RAW6:") == 0)
4294 sscanf(rem, "%*s%d", &s->raw6);
4295 else if (strcmp(id, "TCP6:") == 0)
4296 sscanf(rem, "%*s%d", &s->tcp6_hashed);
4297 else if (strcmp(id, "FRAG:") == 0)
4298 sscanf(rem, "%*s%d%*s%d", &s->frag4, &s->frag4_mem);
4299 else if (strcmp(id, "FRAG6:") == 0)
4300 sscanf(rem, "%*s%d%*s%d", &s->frag6, &s->frag6_mem);
4301 else if (strcmp(id, "TCP:") == 0)
4302 sscanf(rem, "%*s%d%*s%d%*s%d%*s%d%*s%d",
4303 &s->tcp4_hashed,
4304 &s->tcp_orphans, &s->tcp_tws, &s->tcp_total, &s->tcp_mem);
4305}
4306
055840f2 4307static int get_sockstat(struct ssummary *s)
aba5acdf
SH
4308{
4309 char buf[256];
4310 FILE *fp;
4311
4312 memset(s, 0, sizeof(*s));
4313
ab01dbbb 4314 if ((fp = net_sockstat_open()) == NULL)
aba5acdf 4315 return -1;
acd1e437 4316 while (fgets(buf, sizeof(buf), fp) != NULL)
aba5acdf
SH
4317 get_sockstat_line(buf, s);
4318 fclose(fp);
4319
ab01dbbb 4320 if ((fp = net_sockstat6_open()) == NULL)
aba5acdf 4321 return 0;
acd1e437 4322 while (fgets(buf, sizeof(buf), fp) != NULL)
aba5acdf
SH
4323 get_sockstat_line(buf, s);
4324 fclose(fp);
4325
4326 return 0;
4327}
4328
d1f28cf1 4329static int print_summary(void)
aba5acdf 4330{
055840f2 4331 struct ssummary s;
2f938ce1 4332 int tcp_estab;
aba5acdf
SH
4333
4334 if (get_sockstat(&s) < 0)
4335 perror("ss: get_sockstat");
2f938ce1 4336 if (get_snmp_int("Tcp:", "CurrEstab", &tcp_estab) < 0)
aba5acdf
SH
4337 perror("ss: get_snmpstat");
4338
a221d621
BL
4339 get_slabstat(&slabstat);
4340
aba5acdf
SH
4341 printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks);
4342
4343 printf("TCP: %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
4344 s.tcp_total + slabstat.tcp_syns + s.tcp_tws,
2f938ce1 4345 tcp_estab,
aba5acdf
SH
4346 s.tcp_total - (s.tcp4_hashed+s.tcp6_hashed-s.tcp_tws),
4347 s.tcp_orphans,
4348 slabstat.tcp_syns,
4349 s.tcp_tws, slabstat.tcp_tws,
4350 slabstat.tcp_ports
4351 );
4352
4353 printf("\n");
4354 printf("Transport Total IP IPv6\n");
4355 printf("* %-9d %-9s %-9s\n", slabstat.socks, "-", "-");
4356 printf("RAW %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
4357 printf("UDP %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
4358 printf("TCP %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
ae665a52 4359 printf("INET %-9d %-9d %-9d\n",
aba5acdf
SH
4360 s.raw4+s.udp4+s.tcp4_hashed+
4361 s.raw6+s.udp6+s.tcp6_hashed,
4362 s.raw4+s.udp4+s.tcp4_hashed,
4363 s.raw6+s.udp6+s.tcp6_hashed);
4364 printf("FRAG %-9d %-9d %-9d\n", s.frag4+s.frag6, s.frag4, s.frag6);
4365
4366 printf("\n");
4367
4368 return 0;
4369}
4370
7a96e199 4371static void _usage(FILE *dest)
aba5acdf 4372{
7a96e199 4373 fprintf(dest,
aba5acdf
SH
4374"Usage: ss [ OPTIONS ]\n"
4375" ss [ OPTIONS ] [ FILTER ]\n"
ff041f16
VK
4376" -h, --help this message\n"
4377" -V, --version output version information\n"
4378" -n, --numeric don't resolve service names\n"
ab61159a 4379" -r, --resolve resolve host names\n"
ff041f16
VK
4380" -a, --all display all sockets\n"
4381" -l, --listening display listening sockets\n"
ab61159a
SH
4382" -o, --options show timer information\n"
4383" -e, --extended show detailed socket information\n"
4384" -m, --memory show socket memory usage\n"
ff041f16
VK
4385" -p, --processes show process using socket\n"
4386" -i, --info show internal TCP information\n"
4387" -s, --summary show socket usage summary\n"
b0f01cf6 4388" -b, --bpf show bpf filter socket information\n"
6885e3bf 4389" -E, --events continually display sockets as they are destroyed\n"
ff041f16
VK
4390" -Z, --context display process SELinux security contexts\n"
4391" -z, --contexts display process and socket SELinux security contexts\n"
95ce04bc 4392" -N, --net switch to the specified network namespace name\n"
ab61159a
SH
4393"\n"
4394" -4, --ipv4 display only IP version 4 sockets\n"
4395" -6, --ipv6 display only IP version 6 sockets\n"
ff041f16
VK
4396" -0, --packet display PACKET sockets\n"
4397" -t, --tcp display only TCP sockets\n"
f89d46ad 4398" -S, --sctp display only SCTP sockets\n"
ff041f16
VK
4399" -u, --udp display only UDP sockets\n"
4400" -d, --dccp display only DCCP sockets\n"
4401" -w, --raw display only RAW sockets\n"
4402" -x, --unix display only Unix domain sockets\n"
c759116a 4403" --vsock display only vsock sockets\n"
ab61159a 4404" -f, --family=FAMILY display sockets of type FAMILY\n"
c759116a 4405" FAMILY := {inet|inet6|link|unix|netlink|vsock|help}\n"
ab61159a 4406"\n"
fb2594c1 4407" -K, --kill forcibly close sockets, display what was closed\n"
7a4559f6 4408" -H, --no-header Suppress header line\n"
fb2594c1 4409"\n"
583de149 4410" -A, --query=QUERY, --socket=QUERY\n"
c759116a 4411" QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink|vsock_stream|vsock_dgram}[,QUERY]\n"
ab61159a 4412"\n"
583de149 4413" -D, --diag=FILE Dump raw information about TCP sockets to FILE\n"
ab61159a 4414" -F, --filter=FILE read filter information from FILE\n"
ff041f16
VK
4415" FILTER := [ state STATE-FILTER ] [ EXPRESSION ]\n"
4416" STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}\n"
ae4e21c9 4417" TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listening|closing}\n"
ff041f16
VK
4418" connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
4419" synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}\n"
4420" bucket := {syn-recv|time-wait}\n"
ae4e21c9 4421" big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listening|closing}\n"
ab61159a 4422 );
7a96e199
AH
4423}
4424
4425static void help(void) __attribute__((noreturn));
4426static void help(void)
4427{
4428 _usage(stdout);
4429 exit(0);
4430}
4431
4432static void usage(void) __attribute__((noreturn));
4433static void usage(void)
4434{
4435 _usage(stderr);
aba5acdf
SH
4436 exit(-1);
4437}
4438
4439
d1f28cf1 4440static int scan_state(const char *state)
aba5acdf 4441{
b710a722
PS
4442 static const char * const sstate_namel[] = {
4443 "UNKNOWN",
4444 [SS_ESTABLISHED] = "established",
4445 [SS_SYN_SENT] = "syn-sent",
4446 [SS_SYN_RECV] = "syn-recv",
4447 [SS_FIN_WAIT1] = "fin-wait-1",
4448 [SS_FIN_WAIT2] = "fin-wait-2",
4449 [SS_TIME_WAIT] = "time-wait",
4450 [SS_CLOSE] = "unconnected",
4451 [SS_CLOSE_WAIT] = "close-wait",
4452 [SS_LAST_ACK] = "last-ack",
4453 [SS_LISTEN] = "listening",
4454 [SS_CLOSING] = "closing",
4455 };
aba5acdf 4456 int i;
acd1e437 4457
aba5acdf
SH
4458 if (strcasecmp(state, "close") == 0 ||
4459 strcasecmp(state, "closed") == 0)
4460 return (1<<SS_CLOSE);
4461 if (strcasecmp(state, "syn-rcv") == 0)
4462 return (1<<SS_SYN_RECV);
1a5bad5a 4463 if (strcasecmp(state, "established") == 0)
aba5acdf
SH
4464 return (1<<SS_ESTABLISHED);
4465 if (strcasecmp(state, "all") == 0)
4466 return SS_ALL;
4467 if (strcasecmp(state, "connected") == 0)
4468 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN));
1a5bad5a 4469 if (strcasecmp(state, "synchronized") == 0)
aba5acdf
SH
4470 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN)|(1<<SS_SYN_SENT));
4471 if (strcasecmp(state, "bucket") == 0)
4472 return (1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT);
4473 if (strcasecmp(state, "big") == 0)
4474 return SS_ALL & ~((1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT));
acd1e437 4475 for (i = 0; i < SS_MAX; i++) {
1a5bad5a 4476 if (strcasecmp(state, sstate_namel[i]) == 0)
aba5acdf
SH
4477 return (1<<i);
4478 }
9db7bf15
VK
4479
4480 fprintf(stderr, "ss: wrong state name: %s\n", state);
4481 exit(-1);
aba5acdf
SH
4482}
4483
c759116a
SH
4484/* Values 'v' and 'V' are already used so a non-character is used */
4485#define OPT_VSOCK 256
4486
ab61159a
SH
4487static const struct option long_opts[] = {
4488 { "numeric", 0, 0, 'n' },
4489 { "resolve", 0, 0, 'r' },
4490 { "options", 0, 0, 'o' },
4491 { "extended", 0, 0, 'e' },
4492 { "memory", 0, 0, 'm' },
4493 { "info", 0, 0, 'i' },
4494 { "processes", 0, 0, 'p' },
372c30d2 4495 { "bpf", 0, 0, 'b' },
6885e3bf 4496 { "events", 0, 0, 'E' },
351efcde 4497 { "dccp", 0, 0, 'd' },
ab61159a 4498 { "tcp", 0, 0, 't' },
f89d46ad 4499 { "sctp", 0, 0, 'S' },
ab61159a
SH
4500 { "udp", 0, 0, 'u' },
4501 { "raw", 0, 0, 'w' },
4502 { "unix", 0, 0, 'x' },
c759116a 4503 { "vsock", 0, 0, OPT_VSOCK },
ab61159a
SH
4504 { "all", 0, 0, 'a' },
4505 { "listening", 0, 0, 'l' },
4506 { "ipv4", 0, 0, '4' },
4507 { "ipv6", 0, 0, '6' },
4508 { "packet", 0, 0, '0' },
4509 { "family", 1, 0, 'f' },
4510 { "socket", 1, 0, 'A' },
583de149 4511 { "query", 1, 0, 'A' },
c3f346b0 4512 { "summary", 0, 0, 's' },
583de149 4513 { "diag", 1, 0, 'D' },
ab61159a
SH
4514 { "filter", 1, 0, 'F' },
4515 { "version", 0, 0, 'V' },
4516 { "help", 0, 0, 'h' },
116ac927
RH
4517 { "context", 0, 0, 'Z' },
4518 { "contexts", 0, 0, 'z' },
95ce04bc 4519 { "net", 1, 0, 'N' },
fb2594c1 4520 { "kill", 0, 0, 'K' },
7a4559f6 4521 { "no-header", 0, 0, 'H' },
ab61159a 4522 { 0 }
ae665a52 4523
ab61159a
SH
4524};
4525
aba5acdf
SH
4526int main(int argc, char *argv[])
4527{
aba5acdf
SH
4528 int saw_states = 0;
4529 int saw_query = 0;
4530 int do_summary = 0;
7d105b56 4531 const char *dump_tcpdiag = NULL;
aba5acdf
SH
4532 FILE *filter_fp = NULL;
4533 int ch;
9db7bf15 4534 int state_filter = 0;
95eafe43 4535 int addrp_width, screen_width = 80;
aba5acdf 4536
168d97f9
SH
4537 while ((ch = getopt_long(argc, argv,
4538 "dhaletuwxnro460spbEf:miA:D:F:vVzZN:KHS",
ab61159a 4539 long_opts, NULL)) != EOF) {
acd1e437 4540 switch (ch) {
aba5acdf
SH
4541 case 'n':
4542 resolve_services = 0;
4543 break;
4544 case 'r':
4545 resolve_hosts = 1;
4546 break;
4547 case 'o':
4548 show_options = 1;
4549 break;
4550 case 'e':
4551 show_options = 1;
4552 show_details++;
4553 break;
4554 case 'm':
4555 show_mem = 1;
4556 break;
4557 case 'i':
4558 show_tcpinfo = 1;
4559 break;
4560 case 'p':
4561 show_users++;
fbc0f876 4562 user_ent_hash_build();
aba5acdf 4563 break;
372c30d2
ND
4564 case 'b':
4565 show_options = 1;
4566 show_bpf++;
4567 break;
6885e3bf
CG
4568 case 'E':
4569 follow_events = 1;
4570 break;
351efcde 4571 case 'd':
57ff5a10 4572 filter_db_set(&current_filter, DCCP_DB);
351efcde 4573 break;
aba5acdf 4574 case 't':
57ff5a10 4575 filter_db_set(&current_filter, TCP_DB);
aba5acdf 4576 break;
f89d46ad
PS
4577 case 'S':
4578 filter_db_set(&current_filter, SCTP_DB);
4579 break;
aba5acdf 4580 case 'u':
57ff5a10 4581 filter_db_set(&current_filter, UDP_DB);
aba5acdf
SH
4582 break;
4583 case 'w':
57ff5a10 4584 filter_db_set(&current_filter, RAW_DB);
aba5acdf
SH
4585 break;
4586 case 'x':
9db7bf15 4587 filter_af_set(&current_filter, AF_UNIX);
aba5acdf 4588 break;
c759116a
SH
4589 case OPT_VSOCK:
4590 filter_af_set(&current_filter, AF_VSOCK);
4591 break;
aba5acdf 4592 case 'a':
9db7bf15 4593 state_filter = SS_ALL;
aba5acdf
SH
4594 break;
4595 case 'l':
9db7bf15 4596 state_filter = (1 << SS_LISTEN) | (1 << SS_CLOSE);
aba5acdf
SH
4597 break;
4598 case '4':
9db7bf15 4599 filter_af_set(&current_filter, AF_INET);
aba5acdf
SH
4600 break;
4601 case '6':
9db7bf15 4602 filter_af_set(&current_filter, AF_INET6);
aba5acdf
SH
4603 break;
4604 case '0':
9db7bf15 4605 filter_af_set(&current_filter, AF_PACKET);
aba5acdf
SH
4606 break;
4607 case 'f':
4608 if (strcmp(optarg, "inet") == 0)
9db7bf15 4609 filter_af_set(&current_filter, AF_INET);
aba5acdf 4610 else if (strcmp(optarg, "inet6") == 0)
9db7bf15 4611 filter_af_set(&current_filter, AF_INET6);
aba5acdf 4612 else if (strcmp(optarg, "link") == 0)
9db7bf15 4613 filter_af_set(&current_filter, AF_PACKET);
aba5acdf 4614 else if (strcmp(optarg, "unix") == 0)
9db7bf15 4615 filter_af_set(&current_filter, AF_UNIX);
aba5acdf 4616 else if (strcmp(optarg, "netlink") == 0)
9db7bf15 4617 filter_af_set(&current_filter, AF_NETLINK);
c759116a
SH
4618 else if (strcmp(optarg, "vsock") == 0)
4619 filter_af_set(&current_filter, AF_VSOCK);
aba5acdf 4620 else if (strcmp(optarg, "help") == 0)
7a96e199 4621 help();
aba5acdf 4622 else {
9db7bf15
VK
4623 fprintf(stderr, "ss: \"%s\" is invalid family\n",
4624 optarg);
aba5acdf
SH
4625 usage();
4626 }
4627 break;
4628 case 'A':
4629 {
4630 char *p, *p1;
acd1e437 4631
aba5acdf
SH
4632 if (!saw_query) {
4633 current_filter.dbs = 0;
7f9dddbe 4634 state_filter = state_filter ?
acd1e437 4635 state_filter : SS_CONN;
aba5acdf
SH
4636 saw_query = 1;
4637 do_default = 0;
4638 }
4639 p = p1 = optarg;
4640 do {
4641 if ((p1 = strchr(p, ',')) != NULL)
ae665a52 4642 *p1 = 0;
aba5acdf 4643 if (strcmp(p, "all") == 0) {
57ff5a10 4644 filter_default_dbs(&current_filter);
aba5acdf 4645 } else if (strcmp(p, "inet") == 0) {
57ff5a10
VK
4646 filter_db_set(&current_filter, UDP_DB);
4647 filter_db_set(&current_filter, DCCP_DB);
4648 filter_db_set(&current_filter, TCP_DB);
f89d46ad 4649 filter_db_set(&current_filter, SCTP_DB);
57ff5a10 4650 filter_db_set(&current_filter, RAW_DB);
aba5acdf 4651 } else if (strcmp(p, "udp") == 0) {
57ff5a10 4652 filter_db_set(&current_filter, UDP_DB);
351efcde 4653 } else if (strcmp(p, "dccp") == 0) {
57ff5a10 4654 filter_db_set(&current_filter, DCCP_DB);
aba5acdf 4655 } else if (strcmp(p, "tcp") == 0) {
57ff5a10 4656 filter_db_set(&current_filter, TCP_DB);
f89d46ad
PS
4657 } else if (strcmp(p, "sctp") == 0) {
4658 filter_db_set(&current_filter, SCTP_DB);
aba5acdf 4659 } else if (strcmp(p, "raw") == 0) {
57ff5a10 4660 filter_db_set(&current_filter, RAW_DB);
aba5acdf 4661 } else if (strcmp(p, "unix") == 0) {
57ff5a10
VK
4662 filter_db_set(&current_filter, UNIX_ST_DB);
4663 filter_db_set(&current_filter, UNIX_DG_DB);
4664 filter_db_set(&current_filter, UNIX_SQ_DB);
1a5bad5a 4665 } else if (strcasecmp(p, "unix_stream") == 0 ||
aba5acdf 4666 strcmp(p, "u_str") == 0) {
57ff5a10 4667 filter_db_set(&current_filter, UNIX_ST_DB);
1a5bad5a 4668 } else if (strcasecmp(p, "unix_dgram") == 0 ||
aba5acdf 4669 strcmp(p, "u_dgr") == 0) {
57ff5a10 4670 filter_db_set(&current_filter, UNIX_DG_DB);
30b669d7
MY
4671 } else if (strcasecmp(p, "unix_seqpacket") == 0 ||
4672 strcmp(p, "u_seq") == 0) {
57ff5a10 4673 filter_db_set(&current_filter, UNIX_SQ_DB);
aba5acdf 4674 } else if (strcmp(p, "packet") == 0) {
57ff5a10
VK
4675 filter_db_set(&current_filter, PACKET_R_DB);
4676 filter_db_set(&current_filter, PACKET_DG_DB);
aba5acdf
SH
4677 } else if (strcmp(p, "packet_raw") == 0 ||
4678 strcmp(p, "p_raw") == 0) {
57ff5a10 4679 filter_db_set(&current_filter, PACKET_R_DB);
aba5acdf
SH
4680 } else if (strcmp(p, "packet_dgram") == 0 ||
4681 strcmp(p, "p_dgr") == 0) {
57ff5a10 4682 filter_db_set(&current_filter, PACKET_DG_DB);
aba5acdf 4683 } else if (strcmp(p, "netlink") == 0) {
57ff5a10 4684 filter_db_set(&current_filter, NETLINK_DB);
c759116a
SH
4685 } else if (strcmp(p, "vsock") == 0) {
4686 filter_db_set(&current_filter, VSOCK_ST_DB);
4687 filter_db_set(&current_filter, VSOCK_DG_DB);
4688 } else if (strcmp(p, "vsock_stream") == 0 ||
4689 strcmp(p, "v_str") == 0) {
4690 filter_db_set(&current_filter, VSOCK_ST_DB);
4691 } else if (strcmp(p, "vsock_dgram") == 0 ||
4692 strcmp(p, "v_dgr") == 0) {
4693 filter_db_set(&current_filter, VSOCK_DG_DB);
aba5acdf
SH
4694 } else {
4695 fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p);
4696 usage();
4697 }
4698 p = p1 + 1;
4699 } while (p1);
4700 break;
4701 }
4702 case 's':
4703 do_summary = 1;
4704 break;
4705 case 'D':
4706 dump_tcpdiag = optarg;
4707 break;
4708 case 'F':
4709 if (filter_fp) {
4710 fprintf(stderr, "More than one filter file\n");
4711 exit(-1);
4712 }
4713 if (optarg[0] == '-')
4714 filter_fp = stdin;
4715 else
4716 filter_fp = fopen(optarg, "r");
4717 if (!filter_fp) {
4718 perror("fopen filter file");
4719 exit(-1);
4720 }
4721 break;
4722 case 'v':
4723 case 'V':
4724 printf("ss utility, iproute2-ss%s\n", SNAPSHOT);
4725 exit(0);
116ac927
RH
4726 case 'z':
4727 show_sock_ctx++;
36df1a6e 4728 /* fall through */
116ac927
RH
4729 case 'Z':
4730 if (is_selinux_enabled() <= 0) {
4731 fprintf(stderr, "ss: SELinux is not enabled.\n");
4732 exit(1);
4733 }
4734 show_proc_ctx++;
4735 user_ent_hash_build();
4736 break;
95ce04bc
VK
4737 case 'N':
4738 if (netns_switch(optarg))
4739 exit(1);
4740 break;
fb2594c1
LC
4741 case 'K':
4742 current_filter.kill = 1;
4743 break;
7a4559f6
DA
4744 case 'H':
4745 show_header = 0;
4746 break;
aba5acdf 4747 case 'h':
7a96e199 4748 help();
f73105ab 4749 case '?':
aba5acdf
SH
4750 default:
4751 usage();
4752 }
4753 }
4754
4755 argc -= optind;
4756 argv += optind;
4757
aba5acdf
SH
4758 if (do_summary) {
4759 print_summary();
4760 if (do_default && argc == 0)
4761 exit(0);
4762 }
4763
aba5acdf
SH
4764 while (argc > 0) {
4765 if (strcmp(*argv, "state") == 0) {
4766 NEXT_ARG();
4767 if (!saw_states)
9db7bf15
VK
4768 state_filter = 0;
4769 state_filter |= scan_state(*argv);
aba5acdf
SH
4770 saw_states = 1;
4771 } else if (strcmp(*argv, "exclude") == 0 ||
4772 strcmp(*argv, "excl") == 0) {
4773 NEXT_ARG();
4774 if (!saw_states)
9db7bf15
VK
4775 state_filter = SS_ALL;
4776 state_filter &= ~scan_state(*argv);
aba5acdf
SH
4777 saw_states = 1;
4778 } else {
aba5acdf
SH
4779 break;
4780 }
4781 argc--; argv++;
4782 }
4783
9db7bf15
VK
4784 if (do_default) {
4785 state_filter = state_filter ? state_filter : SS_CONN;
4786 filter_default_dbs(&current_filter);
9db7bf15
VK
4787 }
4788
57ff5a10
VK
4789 filter_states_set(&current_filter, state_filter);
4790 filter_merge_defaults(&current_filter);
4791
9db7bf15 4792 if (resolve_services && resolve_hosts &&
168d97f9 4793 (current_filter.dbs & (UNIX_DBM|INET_L4_DBM)))
9db7bf15
VK
4794 init_service_resolver();
4795
9db7bf15
VK
4796 if (current_filter.dbs == 0) {
4797 fprintf(stderr, "ss: no socket tables to show with such filter.\n");
4798 exit(0);
4799 }
4800 if (current_filter.families == 0) {
4801 fprintf(stderr, "ss: no families to show with such filter.\n");
4802 exit(0);
4803 }
aba5acdf
SH
4804 if (current_filter.states == 0) {
4805 fprintf(stderr, "ss: no socket states to show with such filter.\n");
4806 exit(0);
4807 }
4808
4809 if (dump_tcpdiag) {
4810 FILE *dump_fp = stdout;
acd1e437 4811
aba5acdf
SH
4812 if (!(current_filter.dbs & (1<<TCP_DB))) {
4813 fprintf(stderr, "ss: tcpdiag dump requested and no tcp in filter.\n");
4814 exit(0);
4815 }
4816 if (dump_tcpdiag[0] != '-') {
4817 dump_fp = fopen(dump_tcpdiag, "w");
4818 if (!dump_tcpdiag) {
4819 perror("fopen dump file");
4820 exit(-1);
4821 }
4822 }
3fe5b534 4823 inet_show_netlink(&current_filter, dump_fp, IPPROTO_TCP);
aba5acdf
SH
4824 fflush(dump_fp);
4825 exit(0);
4826 }
4827
1527a17e
VK
4828 if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
4829 usage();
4830
aba5acdf 4831 if (current_filter.dbs&(current_filter.dbs-1))
59f46b7b 4832 columns[COL_NETID].width = 6;
aba5acdf 4833
aba5acdf 4834 if (current_filter.states&(current_filter.states-1))
59f46b7b
SB
4835 columns[COL_STATE].width = 10;
4836
4837 /* If Netid or State are hidden, no delimiter before next column */
4838 if (!columns[COL_NETID].width)
4839 columns[COL_STATE].width--;
4840 else if (!columns[COL_STATE].width)
4841 columns[COL_RECVQ].width--;
aba5acdf 4842
aba5acdf
SH
4843 if (isatty(STDOUT_FILENO)) {
4844 struct winsize w;
4845
4846 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
4847 if (w.ws_col > 0)
4848 screen_width = w.ws_col;
4849 }
4850 }
4851
59f46b7b
SB
4852 addrp_width = screen_width -
4853 columns[COL_NETID].width -
4854 columns[COL_STATE].width -
4855 columns[COL_RECVQ].width -
4856 columns[COL_SENDQ].width;
aba5acdf
SH
4857
4858 if (addrp_width&1) {
59f46b7b
SB
4859 if (columns[COL_NETID].width)
4860 columns[COL_NETID].width++;
4861 else if (columns[COL_STATE].width)
4862 columns[COL_STATE].width++;
4357f5c3 4863 else
59f46b7b 4864 columns[COL_SENDQ].width++;
aba5acdf
SH
4865 }
4866
4867 addrp_width /= 2;
aba5acdf 4868
59f46b7b
SB
4869 columns[COL_SERV].width = resolve_services ? 8 : 6;
4870 if (addrp_width < 15 + columns[COL_SERV].width)
4871 addrp_width = 15 + columns[COL_SERV].width;
aba5acdf 4872
59f46b7b 4873 columns[COL_ADDR].width = addrp_width - columns[COL_SERV].width;
aba5acdf 4874
d68e00f7 4875 /* Make enough space for the local/remote port field */
59f46b7b
SB
4876 columns[COL_ADDR].width -= 13;
4877 columns[COL_SERV].width += 13;
2dc85485 4878
59f46b7b
SB
4879 columns[COL_RADDR].width = columns[COL_ADDR].width;
4880 columns[COL_RSERV].width = columns[COL_SERV].width;
4881
4882 if (show_header)
4883 print_header();
aba5acdf 4884
aba5acdf
SH
4885 fflush(stdout);
4886
6885e3bf
CG
4887 if (follow_events)
4888 exit(handle_follow_request(&current_filter));
4889
aba5acdf
SH
4890 if (current_filter.dbs & (1<<NETLINK_DB))
4891 netlink_show(&current_filter);
4892 if (current_filter.dbs & PACKET_DBM)
4893 packet_show(&current_filter);
4894 if (current_filter.dbs & UNIX_DBM)
4895 unix_show(&current_filter);
4896 if (current_filter.dbs & (1<<RAW_DB))
4897 raw_show(&current_filter);
4898 if (current_filter.dbs & (1<<UDP_DB))
4899 udp_show(&current_filter);
4900 if (current_filter.dbs & (1<<TCP_DB))
6c6bbc30 4901 tcp_show(&current_filter);
351efcde 4902 if (current_filter.dbs & (1<<DCCP_DB))
6c6bbc30 4903 dccp_show(&current_filter);
f89d46ad
PS
4904 if (current_filter.dbs & (1<<SCTP_DB))
4905 sctp_show(&current_filter);
c759116a
SH
4906 if (current_filter.dbs & VSOCK_DBM)
4907 vsock_show(&current_filter);
116ac927
RH
4908
4909 if (show_users || show_proc_ctx || show_sock_ctx)
4910 user_ent_destroy();
4911
691bd854 4912 render();
59f46b7b 4913
aba5acdf
SH
4914 return 0;
4915}