blob: 887152ad0269d44b991563021acc4635ef6a806a [file] [log] [blame]
osdl.net!shemmingerb9de3ec2005-01-19 00:23:53 +00001/*
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002 * ss.c "sockstat", socket statistics
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <syslog.h>
16#include <fcntl.h>
17#include <sys/ioctl.h>
18#include <sys/socket.h>
19#include <sys/uio.h>
20#include <netinet/in.h>
21#include <string.h>
22#include <errno.h>
23#include <netdb.h>
24#include <arpa/inet.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000025#include <dirent.h>
26#include <fnmatch.h>
osdl.org!shemmingerab611592004-06-09 21:30:13 +000027#include <getopt.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000028
29#include "utils.h"
30#include "rt_names.h"
31#include "ll_map.h"
32#include "libnetlink.h"
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000033#include "SNAPSHOT.h"
34
Eric Dumazet9cb1ecc2013-05-03 20:48:00 -070035#include <linux/tcp.h>
Stephen Hemmingerf6062362012-01-20 12:48:00 -080036#include <linux/sock_diag.h>
shemminger351efcd2005-09-01 19:21:50 +000037#include <linux/inet_diag.h>
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +000038#include <linux/unix_diag.h>
Nicolas Dichtel372c30d2013-05-17 08:42:34 -070039#include <linux/netdevice.h> /* for MAX_ADDR_LEN */
40#include <linux/filter.h>
41#include <linux/packet_diag.h>
Andrey Vaginecb928c2013-06-05 12:42:01 +040042#include <linux/netlink_diag.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000043
44int resolve_hosts = 0;
45int resolve_services = 1;
46int preferred_family = AF_UNSPEC;
47int show_options = 0;
48int show_details = 0;
49int show_users = 0;
50int show_mem = 0;
51int show_tcpinfo = 0;
Nicolas Dichtel372c30d2013-05-17 08:42:34 -070052int show_bpf = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000053
54int netid_width;
55int state_width;
56int addrp_width;
57int addr_width;
58int serv_width;
59int screen_width;
60
61static const char *TCP_PROTO = "tcp";
62static const char *UDP_PROTO = "udp";
63static const char *RAW_PROTO = "raw";
64static const char *dg_proto = NULL;
65
66enum
67{
68 TCP_DB,
shemminger351efcd2005-09-01 19:21:50 +000069 DCCP_DB,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000070 UDP_DB,
71 RAW_DB,
72 UNIX_DG_DB,
73 UNIX_ST_DB,
Masatake YAMATO30b669d2014-01-08 20:13:46 +090074 UNIX_SQ_DB,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000075 PACKET_DG_DB,
76 PACKET_R_DB,
77 NETLINK_DB,
78 MAX_DB
79};
80
81#define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB))
Masatake YAMATO30b669d2014-01-08 20:13:46 +090082#define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB)|(1<<UNIX_SQ_DB))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000083#define ALL_DB ((1<<MAX_DB)-1)
84
85enum {
osdl.org!shemminger7d105b52004-06-02 20:22:08 +000086 SS_UNKNOWN,
87 SS_ESTABLISHED,
88 SS_SYN_SENT,
89 SS_SYN_RECV,
90 SS_FIN_WAIT1,
91 SS_FIN_WAIT2,
92 SS_TIME_WAIT,
93 SS_CLOSE,
94 SS_CLOSE_WAIT,
95 SS_LAST_ACK,
96 SS_LISTEN,
97 SS_CLOSING,
98 SS_MAX
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000099};
100
101#define SS_ALL ((1<<SS_MAX)-1)
102
103#include "ssfilter.h"
104
105struct filter
106{
107 int dbs;
108 int states;
109 int families;
110 struct ssfilter *f;
111};
112
113struct filter default_filter = {
Petr Sabata7de7e592012-12-11 06:42:52 +0000114 .dbs = ~0,
Stephen Hemmingere7113c62007-07-10 18:26:54 -0700115 .states = SS_ALL & ~((1<<SS_LISTEN)|(1<<SS_CLOSE)|(1<<SS_TIME_WAIT)|(1<<SS_SYN_RECV)),
116 .families= (1<<AF_INET)|(1<<AF_INET6),
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000117};
118
119struct filter current_filter;
120
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100121static FILE *generic_proc_open(const char *env, const char *name)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000122{
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100123 const char *p = getenv(env);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000124 char store[128];
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100125
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000126 if (!p) {
127 p = getenv("PROC_ROOT") ? : "/proc";
128 snprintf(store, sizeof(store)-1, "%s/%s", p, name);
129 p = store;
130 }
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100131
132 return fopen(p, "r");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000133}
134
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100135static FILE *net_tcp_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000136{
137 return generic_proc_open("PROC_NET_TCP", "net/tcp");
138}
139
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100140static FILE *net_tcp6_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000141{
142 return generic_proc_open("PROC_NET_TCP6", "net/tcp6");
143}
144
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100145static FILE *net_udp_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000146{
147 return generic_proc_open("PROC_NET_UDP", "net/udp");
148}
149
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100150static FILE *net_udp6_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000151{
152 return generic_proc_open("PROC_NET_UDP6", "net/udp6");
153}
154
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100155static FILE *net_raw_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000156{
157 return generic_proc_open("PROC_NET_RAW", "net/raw");
158}
159
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100160static FILE *net_raw6_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000161{
162 return generic_proc_open("PROC_NET_RAW6", "net/raw6");
163}
164
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100165static FILE *net_unix_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000166{
167 return generic_proc_open("PROC_NET_UNIX", "net/unix");
168}
169
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100170static FILE *net_packet_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000171{
172 return generic_proc_open("PROC_NET_PACKET", "net/packet");
173}
174
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100175static FILE *net_netlink_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000176{
177 return generic_proc_open("PROC_NET_NETLINK", "net/netlink");
178}
179
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100180static FILE *slabinfo_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000181{
182 return generic_proc_open("PROC_SLABINFO", "slabinfo");
183}
184
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100185static FILE *net_sockstat_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000186{
187 return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat");
188}
189
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100190static FILE *net_sockstat6_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000191{
192 return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6");
193}
194
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100195static FILE *net_snmp_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000196{
197 return generic_proc_open("PROC_NET_SNMP", "net/snmp");
198}
199
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100200static FILE *ephemeral_ports_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000201{
202 return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
203}
204
Steve Finkfbc0f872010-06-09 11:42:38 -0700205struct user_ent {
206 struct user_ent *next;
207 unsigned int ino;
208 int pid;
209 int fd;
210 char process[0];
211};
212
213#define USER_ENT_HASH_SIZE 256
214struct user_ent *user_ent_hash[USER_ENT_HASH_SIZE];
215
216static int user_ent_hashfn(unsigned int ino)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000217{
Steve Finkfbc0f872010-06-09 11:42:38 -0700218 int val = (ino >> 24) ^ (ino >> 16) ^ (ino >> 8) ^ ino;
219
220 return val & (USER_ENT_HASH_SIZE - 1);
221}
222
223static void user_ent_add(unsigned int ino, const char *process, int pid, int fd)
224{
225 struct user_ent *p, **pp;
226 int str_len;
227
228 str_len = strlen(process) + 1;
229 p = malloc(sizeof(struct user_ent) + str_len);
230 if (!p)
231 abort();
232 p->next = NULL;
233 p->ino = ino;
234 p->pid = pid;
235 p->fd = fd;
236 strcpy(p->process, process);
237
238 pp = &user_ent_hash[user_ent_hashfn(ino)];
239 p->next = *pp;
240 *pp = p;
241}
242
243static void user_ent_hash_build(void)
244{
245 const char *root = getenv("PROC_ROOT") ? : "/proc/";
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000246 struct dirent *d;
Steve Finkfbc0f872010-06-09 11:42:38 -0700247 char name[1024];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000248 int nameoff;
Steve Finkfbc0f872010-06-09 11:42:38 -0700249 DIR *dir;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000250
Steve Finkfbc0f872010-06-09 11:42:38 -0700251 strcpy(name, root);
252 if (strlen(name) == 0 || name[strlen(name)-1] != '/')
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000253 strcat(name, "/");
Steve Finkfbc0f872010-06-09 11:42:38 -0700254
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000255 nameoff = strlen(name);
Steve Finkfbc0f872010-06-09 11:42:38 -0700256
257 dir = opendir(name);
258 if (!dir)
259 return;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000260
261 while ((d = readdir(dir)) != NULL) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000262 struct dirent *d1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000263 char process[16];
Steve Finkfbc0f872010-06-09 11:42:38 -0700264 int pid, pos;
265 DIR *dir1;
266 char crap;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000267
268 if (sscanf(d->d_name, "%d%c", &pid, &crap) != 1)
269 continue;
270
Steve Finkfbc0f872010-06-09 11:42:38 -0700271 sprintf(name + nameoff, "%d/fd/", pid);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000272 pos = strlen(name);
273 if ((dir1 = opendir(name)) == NULL)
274 continue;
275
Steve Finkfbc0f872010-06-09 11:42:38 -0700276 process[0] = '\0';
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000277
278 while ((d1 = readdir(dir1)) != NULL) {
Steve Finkfbc0f872010-06-09 11:42:38 -0700279 const char *pattern = "socket:[";
280 unsigned int ino;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000281 char lnk[64];
Stephen Hemminger18445b32011-06-29 15:58:37 -0700282 int fd;
Thomas Jarosch788731b2011-10-13 10:30:21 +0200283 ssize_t link_len;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000284
285 if (sscanf(d1->d_name, "%d%c", &fd, &crap) != 1)
286 continue;
287
288 sprintf(name+pos, "%d", fd);
Thomas Jarosch788731b2011-10-13 10:30:21 +0200289
290 link_len = readlink(name, lnk, sizeof(lnk)-1);
291 if (link_len == -1)
292 continue;
293 lnk[link_len] = '\0';
294
295 if (strncmp(lnk, pattern, strlen(pattern)))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000296 continue;
297
Steve Finkfbc0f872010-06-09 11:42:38 -0700298 sscanf(lnk, "socket:[%u]", &ino);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000299
Steve Finkfbc0f872010-06-09 11:42:38 -0700300 if (process[0] == '\0') {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000301 char tmp[1024];
302 FILE *fp;
Steve Finkfbc0f872010-06-09 11:42:38 -0700303
304 snprintf(tmp, sizeof(tmp), "%s/%d/stat", root, pid);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000305 if ((fp = fopen(tmp, "r")) != NULL) {
306 fscanf(fp, "%*d (%[^)])", process);
307 fclose(fp);
308 }
309 }
310
Steve Finkfbc0f872010-06-09 11:42:38 -0700311 user_ent_add(ino, process, pid, fd);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000312 }
313 closedir(dir1);
314 }
315 closedir(dir);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000316}
317
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800318static int find_users(unsigned ino, char *buf, int buflen)
Steve Finkfbc0f872010-06-09 11:42:38 -0700319{
320 struct user_ent *p;
321 int cnt = 0;
322 char *ptr;
323
324 if (!ino)
325 return 0;
326
327 p = user_ent_hash[user_ent_hashfn(ino)];
328 ptr = buf;
329 while (p) {
330 if (p->ino != ino)
331 goto next;
332
333 if (ptr - buf >= buflen - 1)
334 break;
335
336 snprintf(ptr, buflen - (ptr - buf),
337 "(\"%s\",%d,%d),",
338 p->process, p->pid, p->fd);
339 ptr += strlen(ptr);
340 cnt++;
341
342 next:
343 p = p->next;
344 }
345
346 if (ptr != buf)
347 ptr[-1] = '\0';
348
349 return cnt;
350}
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000351
352/* Get stats from slab */
353
354struct slabstat
355{
356 int socks;
357 int tcp_ports;
358 int tcp_tws;
359 int tcp_syns;
360 int skbs;
361};
362
363struct slabstat slabstat;
364
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800365static const char *slabstat_ids[] =
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000366{
367 "sock",
368 "tcp_bind_bucket",
369 "tcp_tw_bucket",
370 "tcp_open_request",
371 "skbuff_head_cache",
372};
373
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800374static int get_slabstat(struct slabstat *s)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000375{
376 char buf[256];
377 FILE *fp;
378 int cnt;
379
380 memset(s, 0, sizeof(*s));
381
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100382 fp = slabinfo_open();
383 if (!fp)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000384 return -1;
385
386 cnt = sizeof(*s)/sizeof(int);
387
388 fgets(buf, sizeof(buf), fp);
389 while(fgets(buf, sizeof(buf), fp) != NULL) {
390 int i;
391 for (i=0; i<sizeof(slabstat_ids)/sizeof(slabstat_ids[0]); i++) {
392 if (memcmp(buf, slabstat_ids[i], strlen(slabstat_ids[i])) == 0) {
393 sscanf(buf, "%*s%d", ((int *)s) + i);
394 cnt--;
395 break;
396 }
397 }
398 if (cnt <= 0)
399 break;
400 }
401
402 fclose(fp);
403 return 0;
404}
405
osdl.org!shemminger7d105b52004-06-02 20:22:08 +0000406static const char *sstate_name[] = {
407 "UNKNOWN",
Eric Dumazet9cb1ecc2013-05-03 20:48:00 -0700408 [SS_ESTABLISHED] = "ESTAB",
409 [SS_SYN_SENT] = "SYN-SENT",
410 [SS_SYN_RECV] = "SYN-RECV",
411 [SS_FIN_WAIT1] = "FIN-WAIT-1",
412 [SS_FIN_WAIT2] = "FIN-WAIT-2",
413 [SS_TIME_WAIT] = "TIME-WAIT",
414 [SS_CLOSE] = "UNCONN",
415 [SS_CLOSE_WAIT] = "CLOSE-WAIT",
416 [SS_LAST_ACK] = "LAST-ACK",
417 [SS_LISTEN] = "LISTEN",
418 [SS_CLOSING] = "CLOSING",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000419};
420
osdl.org!shemminger7d105b52004-06-02 20:22:08 +0000421static const char *sstate_namel[] = {
422 "UNKNOWN",
Eric Dumazet9cb1ecc2013-05-03 20:48:00 -0700423 [SS_ESTABLISHED] = "established",
424 [SS_SYN_SENT] = "syn-sent",
425 [SS_SYN_RECV] = "syn-recv",
426 [SS_FIN_WAIT1] = "fin-wait-1",
427 [SS_FIN_WAIT2] = "fin-wait-2",
428 [SS_TIME_WAIT] = "time-wait",
429 [SS_CLOSE] = "unconnected",
430 [SS_CLOSE_WAIT] = "close-wait",
431 [SS_LAST_ACK] = "last-ack",
432 [SS_LISTEN] = "listening",
433 [SS_CLOSING] = "closing",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000434};
435
436struct tcpstat
437{
438 inet_prefix local;
439 inet_prefix remote;
440 int lport;
441 int rport;
442 int state;
443 int rq, wq;
444 int timer;
445 int timeout;
446 int retrs;
Stephen Hemmingere7113c62007-07-10 18:26:54 -0700447 unsigned ino;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000448 int probes;
Stephen Hemmingere7113c62007-07-10 18:26:54 -0700449 unsigned uid;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000450 int refcnt;
451 unsigned long long sk;
452 int rto, ato, qack, cwnd, ssthresh;
453};
454
osdl.org!shemminger7d105b52004-06-02 20:22:08 +0000455static const char *tmr_name[] = {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000456 "off",
457 "on",
458 "keepalive",
459 "timewait",
460 "persist",
461 "unknown"
462};
463
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800464static const char *print_ms_timer(int timeout)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000465{
466 static char buf[64];
467 int secs, msecs, minutes;
468 if (timeout < 0)
469 timeout = 0;
470 secs = timeout/1000;
471 minutes = secs/60;
472 secs = secs%60;
473 msecs = timeout%1000;
474 buf[0] = 0;
475 if (minutes) {
476 msecs = 0;
477 snprintf(buf, sizeof(buf)-16, "%dmin", minutes);
478 if (minutes > 9)
479 secs = 0;
480 }
481 if (secs) {
482 if (secs > 9)
483 msecs = 0;
484 sprintf(buf+strlen(buf), "%d%s", secs, msecs ? "." : "sec");
485 }
486 if (msecs)
487 sprintf(buf+strlen(buf), "%03dms", msecs);
488 return buf;
Stephen Hemmingere7113c62007-07-10 18:26:54 -0700489}
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000490
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800491static const char *print_hz_timer(int timeout)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000492{
Stephen Hemminger2d44be12008-06-20 12:40:03 -0700493 int hz = get_user_hz();
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000494 return print_ms_timer(((timeout*1000) + hz-1)/hz);
Stephen Hemmingere7113c62007-07-10 18:26:54 -0700495}
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000496
497struct scache
498{
499 struct scache *next;
500 int port;
501 char *name;
502 const char *proto;
503};
504
505struct scache *rlist;
506
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800507static void init_service_resolver(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000508{
509 char buf[128];
510 FILE *fp = popen("/usr/sbin/rpcinfo -p 2>/dev/null", "r");
511 if (fp) {
512 fgets(buf, sizeof(buf), fp);
513 while (fgets(buf, sizeof(buf), fp) != NULL) {
514 unsigned int progn, port;
515 char proto[128], prog[128];
516 if (sscanf(buf, "%u %*d %s %u %s", &progn, proto,
517 &port, prog+4) == 4) {
518 struct scache *c = malloc(sizeof(*c));
519 if (c) {
520 c->port = port;
521 memcpy(prog, "rpc.", 4);
522 c->name = strdup(prog);
523 if (strcmp(proto, TCP_PROTO) == 0)
524 c->proto = TCP_PROTO;
525 else if (strcmp(proto, UDP_PROTO) == 0)
526 c->proto = UDP_PROTO;
527 else
528 c->proto = NULL;
529 c->next = rlist;
530 rlist = c;
531 }
532 }
533 }
Thomas Jarosch2bcc3c12011-10-03 05:22:27 +0000534 pclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000535 }
536}
537
osdl.org!shemmingerab611592004-06-09 21:30:13 +0000538static int ip_local_port_min, ip_local_port_max;
539
540/* Even do not try default linux ephemeral port ranges:
541 * default /etc/services contains so much of useless crap
542 * wouldbe "allocated" to this area that resolution
543 * is really harmful. I shrug each time when seeing
544 * "socks" or "cfinger" in dumps.
545 */
546static int is_ephemeral(int port)
547{
548 if (!ip_local_port_min) {
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100549 FILE *f = ephemeral_ports_open();
osdl.org!shemmingerab611592004-06-09 21:30:13 +0000550 if (f) {
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800551 fscanf(f, "%d %d",
osdl.org!shemmingerab611592004-06-09 21:30:13 +0000552 &ip_local_port_min, &ip_local_port_max);
553 fclose(f);
554 } else {
555 ip_local_port_min = 1024;
556 ip_local_port_max = 4999;
557 }
558 }
559
560 return (port >= ip_local_port_min && port<= ip_local_port_max);
561}
562
563
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800564static const char *__resolve_service(int port)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000565{
566 struct scache *c;
567
568 for (c = rlist; c; c = c->next) {
569 if (c->port == port && c->proto == dg_proto)
570 return c->name;
571 }
572
osdl.org!shemmingerab611592004-06-09 21:30:13 +0000573 if (!is_ephemeral(port)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000574 static int notfirst;
575 struct servent *se;
576 if (!notfirst) {
577 setservent(1);
578 notfirst = 1;
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800579 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000580 se = getservbyport(htons(port), dg_proto);
581 if (se)
582 return se->s_name;
583 }
584
585 return NULL;
586}
587
588
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800589static const char *resolve_service(int port)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000590{
591 static char buf[128];
592 static struct scache cache[256];
593
594 if (port == 0) {
595 buf[0] = '*';
596 buf[1] = 0;
597 return buf;
598 }
599
600 if (resolve_services) {
601 if (dg_proto == RAW_PROTO) {
602 return inet_proto_n2a(port, buf, sizeof(buf));
603 } else {
604 struct scache *c;
605 const char *res;
606 int hash = (port^(((unsigned long)dg_proto)>>2))&255;
607
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800608 for (c = &cache[hash]; c; c = c->next) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000609 if (c->port == port &&
610 c->proto == dg_proto) {
611 if (c->name)
612 return c->name;
613 goto do_numeric;
614 }
615 }
616
617 if ((res = __resolve_service(port)) != NULL) {
618 if ((c = malloc(sizeof(*c))) == NULL)
619 goto do_numeric;
620 } else {
621 c = &cache[hash];
622 if (c->name)
623 free(c->name);
624 }
625 c->port = port;
626 c->name = NULL;
627 c->proto = dg_proto;
628 if (res) {
629 c->name = strdup(res);
630 c->next = cache[hash].next;
631 cache[hash].next = c;
632 }
633 if (c->name)
634 return c->name;
635 }
636 }
637
638 do_numeric:
639 sprintf(buf, "%u", port);
640 return buf;
641}
642
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800643static void formatted_print(const inet_prefix *a, int port)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000644{
645 char buf[1024];
646 const char *ap = buf;
647 int est_len;
648
649 est_len = addr_width;
650
651 if (a->family == AF_INET) {
652 if (a->data[0] == 0) {
653 buf[0] = '*';
654 buf[1] = 0;
655 } else {
656 ap = format_host(AF_INET, 4, a->data, buf, sizeof(buf));
657 }
658 } else {
659 ap = format_host(a->family, 16, a->data, buf, sizeof(buf));
660 est_len = strlen(ap);
661 if (est_len <= addr_width)
662 est_len = addr_width;
663 else
664 est_len = addr_width + ((est_len-addr_width+3)/4)*4;
665 }
666 printf("%*s:%-*s ", est_len, ap, serv_width, resolve_service(port));
667}
668
669struct aafilter
670{
671 inet_prefix addr;
672 int port;
673 struct aafilter *next;
674};
675
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800676static int inet2_addr_match(const inet_prefix *a, const inet_prefix *p,
677 int plen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000678{
679 if (!inet_addr_match(a, p, plen))
680 return 0;
osdl.org!shemminger7d105b52004-06-02 20:22:08 +0000681
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000682 /* Cursed "v4 mapped" addresses: v4 mapped socket matches
683 * pure IPv4 rule, but v4-mapped rule selects only v4-mapped
684 * sockets. Fair? */
685 if (p->family == AF_INET && a->family == AF_INET6) {
686 if (a->data[0] == 0 && a->data[1] == 0 &&
687 a->data[2] == htonl(0xffff)) {
688 inet_prefix tmp = *a;
689 tmp.data[0] = a->data[3];
690 return inet_addr_match(&tmp, p, plen);
691 }
692 }
693 return 1;
694}
695
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800696static int unix_match(const inet_prefix *a, const inet_prefix *p)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000697{
698 char *addr, *pattern;
699 memcpy(&addr, a->data, sizeof(addr));
700 memcpy(&pattern, p->data, sizeof(pattern));
701 if (pattern == NULL)
702 return 1;
703 if (addr == NULL)
704 addr = "";
705 return !fnmatch(pattern, addr, 0);
706}
707
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800708static int run_ssfilter(struct ssfilter *f, struct tcpstat *s)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000709{
710 switch (f->type) {
711 case SSF_S_AUTO:
712 {
713 static int low, high=65535;
714
715 if (s->local.family == AF_UNIX) {
716 char *p;
717 memcpy(&p, s->local.data, sizeof(p));
718 return p == NULL || (p[0] == '@' && strlen(p) == 6 &&
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800719 strspn(p+1, "0123456789abcdef") == 5);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000720 }
721 if (s->local.family == AF_PACKET)
722 return s->lport == 0 && s->local.data == 0;
723 if (s->local.family == AF_NETLINK)
724 return s->lport < 0;
725
726 if (!low) {
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +0100727 FILE *fp = ephemeral_ports_open();
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000728 if (fp) {
729 fscanf(fp, "%d%d", &low, &high);
730 fclose(fp);
731 }
732 }
733 return s->lport >= low && s->lport <= high;
734 }
735 case SSF_DCOND:
736 {
737 struct aafilter *a = (void*)f->pred;
738 if (a->addr.family == AF_UNIX)
739 return unix_match(&s->remote, &a->addr);
740 if (a->port != -1 && a->port != s->rport)
741 return 0;
742 if (a->addr.bitlen) {
743 do {
744 if (!inet2_addr_match(&s->remote, &a->addr, a->addr.bitlen))
745 return 1;
746 } while ((a = a->next) != NULL);
747 return 0;
748 }
749 return 1;
750 }
751 case SSF_SCOND:
752 {
753 struct aafilter *a = (void*)f->pred;
754 if (a->addr.family == AF_UNIX)
755 return unix_match(&s->local, &a->addr);
756 if (a->port != -1 && a->port != s->lport)
757 return 0;
758 if (a->addr.bitlen) {
759 do {
760 if (!inet2_addr_match(&s->local, &a->addr, a->addr.bitlen))
761 return 1;
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800762 } while ((a = a->next) != NULL);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000763 return 0;
764 }
765 return 1;
766 }
767 case SSF_D_GE:
768 {
769 struct aafilter *a = (void*)f->pred;
770 return s->rport >= a->port;
771 }
772 case SSF_D_LE:
773 {
774 struct aafilter *a = (void*)f->pred;
775 return s->rport <= a->port;
776 }
777 case SSF_S_GE:
778 {
779 struct aafilter *a = (void*)f->pred;
780 return s->lport >= a->port;
781 }
782 case SSF_S_LE:
783 {
784 struct aafilter *a = (void*)f->pred;
785 return s->lport <= a->port;
786 }
787
788 /* Yup. It is recursion. Sorry. */
789 case SSF_AND:
790 return run_ssfilter(f->pred, s) && run_ssfilter(f->post, s);
791 case SSF_OR:
792 return run_ssfilter(f->pred, s) || run_ssfilter(f->post, s);
793 case SSF_NOT:
794 return !run_ssfilter(f->pred, s);
795 default:
796 abort();
797 }
798}
799
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800800/* Relocate external jumps by reloc. */
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +0000801static void ssfilter_patch(char *a, int len, int reloc)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000802{
803 while (len > 0) {
shemminger351efcd2005-09-01 19:21:50 +0000804 struct inet_diag_bc_op *op = (struct inet_diag_bc_op*)a;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000805 if (op->no == len+4)
806 op->no += reloc;
807 len -= op->yes;
808 a += op->yes;
809 }
810 if (len < 0)
811 abort();
812}
813
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +0000814static int ssfilter_bytecompile(struct ssfilter *f, char **bytecode)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000815{
816 switch (f->type) {
817 case SSF_S_AUTO:
818 {
819 if (!(*bytecode=malloc(4))) abort();
shemminger351efcd2005-09-01 19:21:50 +0000820 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_AUTO, 4, 8 };
Eric Dumazetdf39de82011-06-20 14:31:51 -0700821 return 4;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000822 }
823 case SSF_DCOND:
824 case SSF_SCOND:
825 {
826 struct aafilter *a = (void*)f->pred;
827 struct aafilter *b;
828 char *ptr;
shemminger351efcd2005-09-01 19:21:50 +0000829 int code = (f->type == SSF_DCOND ? INET_DIAG_BC_D_COND : INET_DIAG_BC_S_COND);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000830 int len = 0;
831
832 for (b=a; b; b=b->next) {
shemminger351efcd2005-09-01 19:21:50 +0000833 len += 4 + sizeof(struct inet_diag_hostcond);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000834 if (a->addr.family == AF_INET6)
835 len += 16;
836 else
837 len += 4;
838 if (b->next)
839 len += 4;
840 }
841 if (!(ptr = malloc(len))) abort();
842 *bytecode = ptr;
843 for (b=a; b; b=b->next) {
shemminger351efcd2005-09-01 19:21:50 +0000844 struct inet_diag_bc_op *op = (struct inet_diag_bc_op *)ptr;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000845 int alen = (a->addr.family == AF_INET6 ? 16 : 4);
shemminger351efcd2005-09-01 19:21:50 +0000846 int oplen = alen + 4 + sizeof(struct inet_diag_hostcond);
847 struct inet_diag_hostcond *cond = (struct inet_diag_hostcond*)(ptr+4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000848
shemminger351efcd2005-09-01 19:21:50 +0000849 *op = (struct inet_diag_bc_op){ code, oplen, oplen+4 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000850 cond->family = a->addr.family;
851 cond->port = a->port;
852 cond->prefix_len = a->addr.bitlen;
853 memcpy(cond->addr, a->addr.data, alen);
854 ptr += oplen;
855 if (b->next) {
shemminger351efcd2005-09-01 19:21:50 +0000856 op = (struct inet_diag_bc_op *)ptr;
857 *op = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, len - (ptr-*bytecode)};
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000858 ptr += 4;
859 }
860 }
861 return ptr - *bytecode;
862 }
863 case SSF_D_GE:
864 {
865 struct aafilter *x = (void*)f->pred;
866 if (!(*bytecode=malloc(8))) abort();
shemminger351efcd2005-09-01 19:21:50 +0000867 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_GE, 8, 12 };
868 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000869 return 8;
870 }
871 case SSF_D_LE:
872 {
873 struct aafilter *x = (void*)f->pred;
874 if (!(*bytecode=malloc(8))) abort();
shemminger351efcd2005-09-01 19:21:50 +0000875 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_D_LE, 8, 12 };
876 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000877 return 8;
878 }
879 case SSF_S_GE:
880 {
881 struct aafilter *x = (void*)f->pred;
882 if (!(*bytecode=malloc(8))) abort();
shemminger351efcd2005-09-01 19:21:50 +0000883 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_GE, 8, 12 };
884 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000885 return 8;
886 }
887 case SSF_S_LE:
888 {
889 struct aafilter *x = (void*)f->pred;
890 if (!(*bytecode=malloc(8))) abort();
shemminger351efcd2005-09-01 19:21:50 +0000891 ((struct inet_diag_bc_op*)*bytecode)[0] = (struct inet_diag_bc_op){ INET_DIAG_BC_S_LE, 8, 12 };
892 ((struct inet_diag_bc_op*)*bytecode)[1] = (struct inet_diag_bc_op){ 0, 0, x->port };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000893 return 8;
894 }
895
896 case SSF_AND:
897 {
Andreas Henriksson2a4fa1c2013-11-13 09:46:42 +0100898 char *a1, *a2, *a;
899 int l1, l2;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000900 l1 = ssfilter_bytecompile(f->pred, &a1);
901 l2 = ssfilter_bytecompile(f->post, &a2);
902 if (!(a = malloc(l1+l2))) abort();
903 memcpy(a, a1, l1);
904 memcpy(a+l1, a2, l2);
905 free(a1); free(a2);
906 ssfilter_patch(a, l1, l2);
907 *bytecode = a;
908 return l1+l2;
909 }
910 case SSF_OR:
911 {
Andreas Henriksson2a4fa1c2013-11-13 09:46:42 +0100912 char *a1, *a2, *a;
913 int l1, l2;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000914 l1 = ssfilter_bytecompile(f->pred, &a1);
915 l2 = ssfilter_bytecompile(f->post, &a2);
916 if (!(a = malloc(l1+l2+4))) abort();
917 memcpy(a, a1, l1);
918 memcpy(a+l1+4, a2, l2);
919 free(a1); free(a2);
shemminger351efcd2005-09-01 19:21:50 +0000920 *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, l2+4 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000921 *bytecode = a;
922 return l1+l2+4;
923 }
924 case SSF_NOT:
925 {
Andreas Henriksson2a4fa1c2013-11-13 09:46:42 +0100926 char *a1, *a;
927 int l1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000928 l1 = ssfilter_bytecompile(f->pred, &a1);
929 if (!(a = malloc(l1+4))) abort();
930 memcpy(a, a1, l1);
931 free(a1);
shemminger351efcd2005-09-01 19:21:50 +0000932 *(struct inet_diag_bc_op*)(a+l1) = (struct inet_diag_bc_op){ INET_DIAG_BC_JMP, 4, 8 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000933 *bytecode = a;
934 return l1+4;
935 }
936 default:
937 abort();
938 }
939}
940
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +0000941static int remember_he(struct aafilter *a, struct hostent *he)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000942{
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800943 char **ptr = he->h_addr_list;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000944 int cnt = 0;
945 int len;
946
947 if (he->h_addrtype == AF_INET)
948 len = 4;
949 else if (he->h_addrtype == AF_INET6)
950 len = 16;
951 else
952 return 0;
953
954 while (*ptr) {
955 struct aafilter *b = a;
956 if (a->addr.bitlen) {
957 if ((b = malloc(sizeof(*b))) == NULL)
958 return cnt;
959 *b = *a;
960 b->next = a->next;
961 a->next = b;
962 }
963 memcpy(b->addr.data, *ptr, len);
964 b->addr.bytelen = len;
965 b->addr.bitlen = len*8;
966 b->addr.family = he->h_addrtype;
967 ptr++;
968 cnt++;
969 }
970 return cnt;
971}
972
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +0000973static int get_dns_host(struct aafilter *a, const char *addr, int fam)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000974{
975 static int notfirst;
976 int cnt = 0;
977 struct hostent *he;
978
979 a->addr.bitlen = 0;
980 if (!notfirst) {
981 sethostent(1);
982 notfirst = 1;
983 }
984 he = gethostbyname2(addr, fam == AF_UNSPEC ? AF_INET : fam);
985 if (he)
986 cnt = remember_he(a, he);
987 if (fam == AF_UNSPEC) {
988 he = gethostbyname2(addr, AF_INET6);
989 if (he)
990 cnt += remember_he(a, he);
991 }
992 return !cnt;
993}
994
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +0000995static int xll_initted = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000996
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +0000997static void xll_init(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000998{
999 struct rtnl_handle rth;
Stephen Hemmingerd2468da2013-12-20 08:15:02 -08001000 if (rtnl_open(&rth, 0) < 0)
1001 exit(1);
1002
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001003 ll_init_map(&rth);
1004 rtnl_close(&rth);
1005 xll_initted = 1;
1006}
1007
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001008static const char *xll_index_to_name(int index)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001009{
1010 if (!xll_initted)
1011 xll_init();
1012 return ll_index_to_name(index);
1013}
1014
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001015static int xll_name_to_index(const char *dev)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001016{
1017 if (!xll_initted)
1018 xll_init();
1019 return ll_name_to_index(dev);
1020}
1021
1022void *parse_hostcond(char *addr)
1023{
1024 char *port = NULL;
1025 struct aafilter a;
1026 struct aafilter *res;
1027 int fam = preferred_family;
1028
1029 memset(&a, 0, sizeof(a));
1030 a.port = -1;
1031
1032 if (fam == AF_UNIX || strncmp(addr, "unix:", 5) == 0) {
1033 char *p;
1034 a.addr.family = AF_UNIX;
1035 if (strncmp(addr, "unix:", 5) == 0)
1036 addr+=5;
1037 p = strdup(addr);
1038 a.addr.bitlen = 8*strlen(p);
1039 memcpy(a.addr.data, &p, sizeof(p));
1040 goto out;
1041 }
1042
1043 if (fam == AF_PACKET || strncmp(addr, "link:", 5) == 0) {
1044 a.addr.family = AF_PACKET;
1045 a.addr.bitlen = 0;
1046 if (strncmp(addr, "link:", 5) == 0)
1047 addr+=5;
1048 port = strchr(addr, ':');
1049 if (port) {
1050 *port = 0;
1051 if (port[1] && strcmp(port+1, "*")) {
1052 if (get_integer(&a.port, port+1, 0)) {
1053 if ((a.port = xll_name_to_index(port+1)) <= 0)
1054 return NULL;
1055 }
1056 }
1057 }
1058 if (addr[0] && strcmp(addr, "*")) {
1059 unsigned short tmp;
1060 a.addr.bitlen = 32;
1061 if (ll_proto_a2n(&tmp, addr))
1062 return NULL;
1063 a.addr.data[0] = ntohs(tmp);
1064 }
1065 goto out;
1066 }
1067
1068 if (fam == AF_NETLINK || strncmp(addr, "netlink:", 8) == 0) {
1069 a.addr.family = AF_NETLINK;
1070 a.addr.bitlen = 0;
1071 if (strncmp(addr, "netlink:", 8) == 0)
1072 addr+=8;
1073 port = strchr(addr, ':');
1074 if (port) {
1075 *port = 0;
1076 if (port[1] && strcmp(port+1, "*")) {
1077 if (get_integer(&a.port, port+1, 0)) {
1078 if (strcmp(port+1, "kernel") == 0)
1079 a.port = 0;
1080 else
1081 return NULL;
1082 }
1083 }
1084 }
1085 if (addr[0] && strcmp(addr, "*")) {
1086 a.addr.bitlen = 32;
1087 if (get_u32(a.addr.data, addr, 0)) {
1088 if (strcmp(addr, "rtnl") == 0)
1089 a.addr.data[0] = 0;
1090 else if (strcmp(addr, "fw") == 0)
1091 a.addr.data[0] = 3;
1092 else if (strcmp(addr, "tcpdiag") == 0)
1093 a.addr.data[0] = 4;
1094 else
1095 return NULL;
1096 }
1097 }
1098 goto out;
1099 }
1100
1101 if (strncmp(addr, "inet:", 5) == 0) {
1102 addr += 5;
1103 fam = AF_INET;
1104 } else if (strncmp(addr, "inet6:", 6) == 0) {
1105 addr += 6;
1106 fam = AF_INET6;
1107 }
1108
1109 /* URL-like literal [] */
1110 if (addr[0] == '[') {
1111 addr++;
1112 if ((port = strchr(addr, ']')) == NULL)
1113 return NULL;
1114 *port++ = 0;
1115 } else if (addr[0] == '*') {
1116 port = addr+1;
1117 } else {
1118 port = strrchr(strchr(addr, '/') ? : addr, ':');
1119 }
1120 if (port && *port) {
1121 if (*port != ':')
1122 return NULL;
1123 *port++ = 0;
1124 if (*port && *port != '*') {
1125 if (get_integer(&a.port, port, 0)) {
1126 struct servent *se1 = NULL;
1127 struct servent *se2 = NULL;
1128 if (current_filter.dbs&(1<<UDP_DB))
1129 se1 = getservbyname(port, UDP_PROTO);
1130 if (current_filter.dbs&(1<<TCP_DB))
1131 se2 = getservbyname(port, TCP_PROTO);
1132 if (se1 && se2 && se1->s_port != se2->s_port) {
1133 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
1134 return NULL;
1135 }
1136 if (!se1)
1137 se1 = se2;
1138 if (se1) {
1139 a.port = ntohs(se1->s_port);
1140 } else {
1141 struct scache *s;
1142 for (s = rlist; s; s = s->next) {
1143 if ((s->proto == UDP_PROTO &&
1144 (current_filter.dbs&(1<<UDP_DB))) ||
1145 (s->proto == TCP_PROTO &&
1146 (current_filter.dbs&(1<<TCP_DB)))) {
1147 if (s->name && strcmp(s->name, port) == 0) {
1148 if (a.port > 0 && a.port != s->port) {
1149 fprintf(stderr, "Error: ambiguous port \"%s\".\n", port);
1150 return NULL;
1151 }
1152 a.port = s->port;
1153 }
1154 }
1155 }
1156 if (a.port <= 0) {
1157 fprintf(stderr, "Error: \"%s\" does not look like a port.\n", port);
1158 return NULL;
1159 }
1160 }
1161 }
1162 }
1163 }
1164 if (addr && *addr && *addr != '*') {
1165 if (get_prefix_1(&a.addr, addr, fam)) {
1166 if (get_dns_host(&a, addr, fam)) {
1167 fprintf(stderr, "Error: an inet prefix is expected rather than \"%s\".\n", addr);
1168 return NULL;
1169 }
1170 }
1171 }
1172
1173 out:
1174 res = malloc(sizeof(*res));
1175 if (res)
1176 memcpy(res, &a, sizeof(a));
1177 return res;
1178}
1179
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001180static int tcp_show_line(char *line, const struct filter *f, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001181{
1182 struct tcpstat s;
1183 char *loc, *rem, *data;
1184 char opt[256];
1185 int n;
1186 char *p;
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001187
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001188 if ((p = strchr(line, ':')) == NULL)
1189 return -1;
1190 loc = p+2;
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001191
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001192 if ((p = strchr(loc, ':')) == NULL)
1193 return -1;
1194 p[5] = 0;
1195 rem = p+6;
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001196
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001197 if ((p = strchr(rem, ':')) == NULL)
1198 return -1;
1199 p[5] = 0;
1200 data = p+6;
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001201
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001202 do {
1203 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
1204
1205 if (!(f->states & (1<<state)))
1206 return 0;
1207 } while (0);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001208
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001209 s.local.family = s.remote.family = family;
1210 if (family == AF_INET) {
1211 sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
1212 sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport);
1213 s.local.bytelen = s.remote.bytelen = 4;
1214 } else {
1215 sscanf(loc, "%08x%08x%08x%08x:%x",
1216 s.local.data,
1217 s.local.data+1,
1218 s.local.data+2,
1219 s.local.data+3,
1220 &s.lport);
1221 sscanf(rem, "%08x%08x%08x%08x:%x",
1222 s.remote.data,
1223 s.remote.data+1,
1224 s.remote.data+2,
1225 s.remote.data+3,
1226 &s.rport);
1227 s.local.bytelen = s.remote.bytelen = 16;
1228 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001229
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001230 if (f->f && run_ssfilter(f->f, &s) == 0)
1231 return 0;
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001232
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001233 opt[0] = 0;
Stephen Hemmingere7113c62007-07-10 18:26:54 -07001234 n = sscanf(data, "%x %x:%x %x:%x %x %d %d %u %d %llx %d %d %d %d %d %[^\n]\n",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001235 &s.state, &s.wq, &s.rq,
1236 &s.timer, &s.timeout, &s.retrs, &s.uid, &s.probes, &s.ino,
1237 &s.refcnt, &s.sk, &s.rto, &s.ato, &s.qack,
1238 &s.cwnd, &s.ssthresh, opt);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001239
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001240 if (n < 17)
1241 opt[0] = 0;
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001242
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001243 if (n < 12) {
1244 s.rto = 0;
1245 s.cwnd = 2;
1246 s.ssthresh = -1;
1247 s.ato = s.qack = 0;
1248 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001249
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001250 if (netid_width)
1251 printf("%-*s ", netid_width, "tcp");
1252 if (state_width)
1253 printf("%-*s ", state_width, sstate_name[s.state]);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001254
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001255 printf("%-6d %-6d ", s.rq, s.wq);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001256
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001257 formatted_print(&s.local, s.lport);
1258 formatted_print(&s.remote, s.rport);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001259
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001260 if (show_options) {
1261 if (s.timer) {
1262 if (s.timer > 4)
1263 s.timer = 5;
1264 printf(" timer:(%s,%s,%d)",
1265 tmr_name[s.timer],
1266 print_hz_timer(s.timeout),
1267 s.timer != 1 ? s.probes : s.retrs);
1268 }
1269 }
1270 if (show_tcpinfo) {
Stephen Hemminger4c1db132008-06-20 12:34:15 -07001271 int hz = get_user_hz();
1272 if (s.rto && s.rto != 3*hz)
1273 printf(" rto:%g", (double)s.rto/hz);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001274 if (s.ato)
Stephen Hemminger4c1db132008-06-20 12:34:15 -07001275 printf(" ato:%g", (double)s.ato/hz);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001276 if (s.cwnd != 2)
1277 printf(" cwnd:%d", s.cwnd);
1278 if (s.ssthresh != -1)
1279 printf(" ssthresh:%d", s.ssthresh);
1280 if (s.qack/2)
1281 printf(" qack:%d", s.qack/2);
1282 if (s.qack&1)
1283 printf(" bidir");
1284 }
1285 if (show_users) {
1286 char ubuf[4096];
1287 if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0)
1288 printf(" users:(%s)", ubuf);
1289 }
1290 if (show_details) {
1291 if (s.uid)
1292 printf(" uid:%u", (unsigned)s.uid);
Stephen Hemmingere7113c62007-07-10 18:26:54 -07001293 printf(" ino:%u", s.ino);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001294 printf(" sk:%llx", s.sk);
1295 if (opt[0])
1296 printf(" opt:\"%s\"", opt);
1297 }
1298 printf("\n");
1299
1300 return 0;
1301}
1302
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001303static int generic_record_read(FILE *fp,
1304 int (*worker)(char*, const struct filter *, int),
1305 const struct filter *f, int fam)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001306{
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001307 char line[256];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001308
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001309 /* skip header */
1310 if (fgets(line, sizeof(line), fp) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001311 goto outerr;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001312
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001313 while (fgets(line, sizeof(line), fp) != NULL) {
1314 int n = strlen(line);
1315 if (n == 0 || line[n-1] != '\n') {
1316 errno = -EINVAL;
1317 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001318 }
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001319 line[n-1] = 0;
1320
1321 if (worker(line, f, fam) < 0)
1322 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001323 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001324outerr:
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001325
1326 return ferror(fp) ? -1 : 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001327}
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001328
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001329static char *sprint_bw(char *buf, double bw)
1330{
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001331 if (bw > 1000000.)
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001332 sprintf(buf,"%.1fM", bw / 1000000.);
1333 else if (bw > 1000.)
1334 sprintf(buf,"%.1fK", bw / 1000.);
1335 else
1336 sprintf(buf, "%g", bw);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001337
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001338 return buf;
1339}
1340
Hannes Frederic Sowa51ff9f22013-02-22 15:28:18 +00001341static void print_skmeminfo(struct rtattr *tb[], int attrtype)
1342{
1343 const __u32 *skmeminfo;
1344 if (!tb[attrtype])
1345 return;
1346 skmeminfo = RTA_DATA(tb[attrtype]);
1347
1348 printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
1349 skmeminfo[SK_MEMINFO_RMEM_ALLOC],
1350 skmeminfo[SK_MEMINFO_RCVBUF],
1351 skmeminfo[SK_MEMINFO_WMEM_ALLOC],
1352 skmeminfo[SK_MEMINFO_SNDBUF],
1353 skmeminfo[SK_MEMINFO_FWD_ALLOC],
1354 skmeminfo[SK_MEMINFO_WMEM_QUEUED],
1355 skmeminfo[SK_MEMINFO_OPTMEM]);
1356
1357 if (RTA_PAYLOAD(tb[attrtype]) >=
1358 (SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
1359 printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
1360
1361 printf(")");
1362}
1363
Pavel Emelyanov5b816042013-05-17 08:02:14 -07001364static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
1365 struct rtattr *tb[])
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001366{
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001367 char b1[64];
1368 double rtt = 0;
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001369
Shan Wei910b0392012-05-03 16:39:52 +08001370 if (tb[INET_DIAG_SKMEMINFO]) {
Hannes Frederic Sowa51ff9f22013-02-22 15:28:18 +00001371 print_skmeminfo(tb, INET_DIAG_SKMEMINFO);
Eric Dumazetc6d6c922012-08-01 16:16:43 -07001372 } else if (tb[INET_DIAG_MEMINFO]) {
shemminger351efcd2005-09-01 19:21:50 +00001373 const struct inet_diag_meminfo *minfo
1374 = RTA_DATA(tb[INET_DIAG_MEMINFO]);
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001375 printf(" mem:(r%u,w%u,f%u,t%u)",
shemminger351efcd2005-09-01 19:21:50 +00001376 minfo->idiag_rmem,
1377 minfo->idiag_wmem,
1378 minfo->idiag_fmem,
1379 minfo->idiag_tmem);
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001380 }
1381
shemminger351efcd2005-09-01 19:21:50 +00001382 if (tb[INET_DIAG_INFO]) {
osdl.org!shemminger05e18112004-06-08 20:33:44 +00001383 struct tcp_info *info;
shemminger351efcd2005-09-01 19:21:50 +00001384 int len = RTA_PAYLOAD(tb[INET_DIAG_INFO]);
osdl.org!shemminger05e18112004-06-08 20:33:44 +00001385
1386 /* workaround for older kernels with less fields */
1387 if (len < sizeof(*info)) {
1388 info = alloca(sizeof(*info));
1389 memset(info, 0, sizeof(*info));
shemminger351efcd2005-09-01 19:21:50 +00001390 memcpy(info, RTA_DATA(tb[INET_DIAG_INFO]), len);
osdl.org!shemminger05e18112004-06-08 20:33:44 +00001391 } else
shemminger351efcd2005-09-01 19:21:50 +00001392 info = RTA_DATA(tb[INET_DIAG_INFO]);
osdl.org!shemminger05e18112004-06-08 20:33:44 +00001393
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001394 if (show_options) {
1395 if (info->tcpi_options & TCPI_OPT_TIMESTAMPS)
1396 printf(" ts");
1397 if (info->tcpi_options & TCPI_OPT_SACK)
1398 printf(" sack");
1399 if (info->tcpi_options & TCPI_OPT_ECN)
1400 printf(" ecn");
Eric Dumazet719b9582011-11-16 07:59:06 +00001401 if (info->tcpi_options & TCPI_OPT_ECN_SEEN)
1402 printf(" ecnseen");
Eric Dumazet9cb1ecc2013-05-03 20:48:00 -07001403 if (info->tcpi_options & TCPI_OPT_SYN_DATA)
1404 printf(" fastopen");
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001405 }
shemminger52d5ac32005-07-05 22:11:37 +00001406
shemminger351efcd2005-09-01 19:21:50 +00001407 if (tb[INET_DIAG_CONG])
Stephen Hemmingerff247462012-04-10 08:47:55 -07001408 printf(" %s", rta_getattr_str(tb[INET_DIAG_CONG]));
shemmingerea8fc102005-06-22 18:27:49 +00001409
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001410 if (info->tcpi_options & TCPI_OPT_WSCALE)
osdl.org!shemminger05e18112004-06-08 20:33:44 +00001411 printf(" wscale:%d,%d", info->tcpi_snd_wscale,
1412 info->tcpi_rcv_wscale);
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001413 if (info->tcpi_rto && info->tcpi_rto != 3000000)
1414 printf(" rto:%g", (double)info->tcpi_rto/1000);
1415 if (info->tcpi_rtt)
1416 printf(" rtt:%g/%g", (double)info->tcpi_rtt/1000,
1417 (double)info->tcpi_rttvar/1000);
1418 if (info->tcpi_ato)
1419 printf(" ato:%g", (double)info->tcpi_ato/1000);
Ben Hutchings4d354342012-07-30 20:51:07 +01001420 if (info->tcpi_snd_mss)
1421 printf(" mss:%d", info->tcpi_snd_mss);
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001422 if (info->tcpi_snd_cwnd != 2)
1423 printf(" cwnd:%d", info->tcpi_snd_cwnd);
1424 if (info->tcpi_snd_ssthresh < 0xFFFF)
1425 printf(" ssthresh:%d", info->tcpi_snd_ssthresh);
shemminger52d5ac32005-07-05 22:11:37 +00001426
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001427 rtt = (double) info->tcpi_rtt;
shemminger351efcd2005-09-01 19:21:50 +00001428 if (tb[INET_DIAG_VEGASINFO]) {
osdl.org!shemminger05e18112004-06-08 20:33:44 +00001429 const struct tcpvegas_info *vinfo
shemminger351efcd2005-09-01 19:21:50 +00001430 = RTA_DATA(tb[INET_DIAG_VEGASINFO]);
osdl.org!shemminger05e18112004-06-08 20:33:44 +00001431
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001432 if (vinfo->tcpv_enabled &&
shemmingerea8fc102005-06-22 18:27:49 +00001433 vinfo->tcpv_rtt && vinfo->tcpv_rtt != 0x7fffffff)
1434 rtt = vinfo->tcpv_rtt;
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001435 }
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001436
1437 if (rtt > 0 && info->tcpi_snd_mss && info->tcpi_snd_cwnd) {
1438 printf(" send %sbps",
1439 sprint_bw(b1, (double) info->tcpi_snd_cwnd *
1440 (double) info->tcpi_snd_mss * 8000000.
1441 / rtt));
1442 }
1443
Eric Dumazet260804f2013-06-25 13:29:17 -07001444 if (info->tcpi_unacked)
1445 printf(" unacked:%u", info->tcpi_unacked);
1446 if (info->tcpi_retrans || info->tcpi_total_retrans)
1447 printf(" retrans:%u/%u", info->tcpi_retrans,
1448 info->tcpi_total_retrans);
1449 if (info->tcpi_lost)
1450 printf(" lost:%u", info->tcpi_lost);
1451 if (info->tcpi_sacked && r->idiag_state != SS_LISTEN)
1452 printf(" sacked:%u", info->tcpi_sacked);
1453 if (info->tcpi_fackets)
1454 printf(" fackets:%u", info->tcpi_fackets);
1455 if (info->tcpi_reordering != 3)
1456 printf(" reordering:%d", info->tcpi_reordering);
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001457 if (info->tcpi_rcv_rtt)
1458 printf(" rcv_rtt:%g", (double) info->tcpi_rcv_rtt/1000);
1459 if (info->tcpi_rcv_space)
1460 printf(" rcv_space:%d", info->tcpi_rcv_space);
1461
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001462 }
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001463}
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001464
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00001465static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001466{
Pavel Emelyanov5b816042013-05-17 08:02:14 -07001467 struct rtattr * tb[INET_DIAG_MAX+1];
shemminger351efcd2005-09-01 19:21:50 +00001468 struct inet_diag_msg *r = NLMSG_DATA(nlh);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001469 struct tcpstat s;
1470
Pavel Emelyanov5b816042013-05-17 08:02:14 -07001471 parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr*)(r+1),
1472 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
1473
shemminger351efcd2005-09-01 19:21:50 +00001474 s.state = r->idiag_state;
1475 s.local.family = s.remote.family = r->idiag_family;
1476 s.lport = ntohs(r->id.idiag_sport);
1477 s.rport = ntohs(r->id.idiag_dport);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001478 if (s.local.family == AF_INET) {
1479 s.local.bytelen = s.remote.bytelen = 4;
1480 } else {
1481 s.local.bytelen = s.remote.bytelen = 16;
1482 }
shemminger351efcd2005-09-01 19:21:50 +00001483 memcpy(s.local.data, r->id.idiag_src, s.local.bytelen);
1484 memcpy(s.remote.data, r->id.idiag_dst, s.local.bytelen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001485
1486 if (f && f->f && run_ssfilter(f->f, &s) == 0)
1487 return 0;
1488
1489 if (netid_width)
1490 printf("%-*s ", netid_width, "tcp");
1491 if (state_width)
1492 printf("%-*s ", state_width, sstate_name[s.state]);
1493
shemminger351efcd2005-09-01 19:21:50 +00001494 printf("%-6d %-6d ", r->idiag_rqueue, r->idiag_wqueue);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001495
1496 formatted_print(&s.local, s.lport);
1497 formatted_print(&s.remote, s.rport);
1498
1499 if (show_options) {
shemminger351efcd2005-09-01 19:21:50 +00001500 if (r->idiag_timer) {
1501 if (r->idiag_timer > 4)
1502 r->idiag_timer = 5;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001503 printf(" timer:(%s,%s,%d)",
shemminger351efcd2005-09-01 19:21:50 +00001504 tmr_name[r->idiag_timer],
1505 print_ms_timer(r->idiag_expires),
1506 r->idiag_retrans);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001507 }
1508 }
1509 if (show_users) {
1510 char ubuf[4096];
shemminger351efcd2005-09-01 19:21:50 +00001511 if (find_users(r->idiag_inode, ubuf, sizeof(ubuf)) > 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001512 printf(" users:(%s)", ubuf);
1513 }
1514 if (show_details) {
shemminger351efcd2005-09-01 19:21:50 +00001515 if (r->idiag_uid)
1516 printf(" uid:%u", (unsigned)r->idiag_uid);
Stephen Hemmingere7113c62007-07-10 18:26:54 -07001517 printf(" ino:%u", r->idiag_inode);
Eric Dumazetbbe32052009-09-11 09:48:07 +02001518 printf(" sk:");
shemminger351efcd2005-09-01 19:21:50 +00001519 if (r->id.idiag_cookie[1] != 0)
1520 printf("%08x", r->id.idiag_cookie[1]);
Eric Dumazetbbe32052009-09-11 09:48:07 +02001521 printf("%08x", r->id.idiag_cookie[0]);
Pavel Emelyanov5b816042013-05-17 08:02:14 -07001522 if (tb[INET_DIAG_SHUTDOWN]) {
1523 unsigned char mask;
1524 mask = *(__u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
1525 printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
1526 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001527 }
1528 if (show_mem || show_tcpinfo) {
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001529 printf("\n\t");
Pavel Emelyanov5b816042013-05-17 08:02:14 -07001530 tcp_show_info(nlh, r, tb);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001531 }
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001532
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001533 printf("\n");
1534
1535 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001536}
1537
Pavel Emelyanov746a6952012-10-25 03:21:39 +00001538static int tcpdiag_send(int fd, int protocol, struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001539{
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001540 struct sockaddr_nl nladdr;
1541 struct {
1542 struct nlmsghdr nlh;
shemminger351efcd2005-09-01 19:21:50 +00001543 struct inet_diag_req r;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001544 } req;
1545 char *bc = NULL;
1546 int bclen;
1547 struct msghdr msg;
1548 struct rtattr rta;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001549 struct iovec iov[3];
1550
Pavel Emelyanov346f8ca2012-10-25 03:24:58 +00001551 if (protocol == IPPROTO_UDP)
1552 return -1;
1553
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001554 memset(&nladdr, 0, sizeof(nladdr));
1555 nladdr.nl_family = AF_NETLINK;
1556
1557 req.nlh.nlmsg_len = sizeof(req);
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00001558 if (protocol == IPPROTO_TCP)
1559 req.nlh.nlmsg_type = TCPDIAG_GETSOCK;
1560 else
1561 req.nlh.nlmsg_type = DCCPDIAG_GETSOCK;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001562 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
1563 req.nlh.nlmsg_pid = 0;
1564 req.nlh.nlmsg_seq = 123456;
1565 memset(&req.r, 0, sizeof(req.r));
shemminger351efcd2005-09-01 19:21:50 +00001566 req.r.idiag_family = AF_INET;
1567 req.r.idiag_states = f->states;
Shan Wei910b0392012-05-03 16:39:52 +08001568 if (show_mem) {
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001569 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
Shan Wei910b0392012-05-03 16:39:52 +08001570 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
1571 }
osdl.net!shemmingerb4b0b7d2004-09-28 18:14:03 +00001572
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001573 if (show_tcpinfo) {
shemminger351efcd2005-09-01 19:21:50 +00001574 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
1575 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
1576 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00001577 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001578
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001579 iov[0] = (struct iovec){
1580 .iov_base = &req,
1581 .iov_len = sizeof(req)
shemmingerea8fc102005-06-22 18:27:49 +00001582 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001583 if (f->f) {
1584 bclen = ssfilter_bytecompile(f->f, &bc);
shemminger351efcd2005-09-01 19:21:50 +00001585 rta.rta_type = INET_DIAG_REQ_BYTECODE;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001586 rta.rta_len = RTA_LENGTH(bclen);
1587 iov[1] = (struct iovec){ &rta, sizeof(rta) };
1588 iov[2] = (struct iovec){ bc, bclen };
1589 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
1590 }
1591
1592 msg = (struct msghdr) {
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001593 .msg_name = (void*)&nladdr,
shemmingerea8fc102005-06-22 18:27:49 +00001594 .msg_namelen = sizeof(nladdr),
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001595 .msg_iov = iov,
shemmingerea8fc102005-06-22 18:27:49 +00001596 .msg_iovlen = f->f ? 3 : 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001597 };
1598
Eric Dumazet930a75f2012-04-10 09:00:16 -07001599 if (sendmsg(fd, &msg, 0) < 0) {
1600 close(fd);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001601 return -1;
Eric Dumazet930a75f2012-04-10 09:00:16 -07001602 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001603
Pavel Emelyanov746a6952012-10-25 03:21:39 +00001604 return 0;
1605}
1606
Pavel Emelyanov886d19d2012-10-25 03:23:36 +00001607static int sockdiag_send(int family, int fd, int protocol, struct filter *f)
1608{
1609 struct sockaddr_nl nladdr;
1610 struct {
1611 struct nlmsghdr nlh;
1612 struct inet_diag_req_v2 r;
1613 } req;
1614 char *bc = NULL;
1615 int bclen;
1616 struct msghdr msg;
1617 struct rtattr rta;
1618 struct iovec iov[3];
1619
1620 if (family == PF_UNSPEC)
1621 return tcpdiag_send(fd, protocol, f);
1622
1623 memset(&nladdr, 0, sizeof(nladdr));
1624 nladdr.nl_family = AF_NETLINK;
1625
1626 req.nlh.nlmsg_len = sizeof(req);
1627 req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
1628 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
1629 req.nlh.nlmsg_pid = 0;
1630 req.nlh.nlmsg_seq = 123456;
1631 memset(&req.r, 0, sizeof(req.r));
1632 req.r.sdiag_family = family;
1633 req.r.sdiag_protocol = protocol;
1634 req.r.idiag_states = f->states;
1635 if (show_mem) {
1636 req.r.idiag_ext |= (1<<(INET_DIAG_MEMINFO-1));
1637 req.r.idiag_ext |= (1<<(INET_DIAG_SKMEMINFO-1));
1638 }
1639
1640 if (show_tcpinfo) {
1641 req.r.idiag_ext |= (1<<(INET_DIAG_INFO-1));
1642 req.r.idiag_ext |= (1<<(INET_DIAG_VEGASINFO-1));
1643 req.r.idiag_ext |= (1<<(INET_DIAG_CONG-1));
1644 }
1645
1646 iov[0] = (struct iovec){
1647 .iov_base = &req,
1648 .iov_len = sizeof(req)
1649 };
1650 if (f->f) {
1651 bclen = ssfilter_bytecompile(f->f, &bc);
1652 rta.rta_type = INET_DIAG_REQ_BYTECODE;
1653 rta.rta_len = RTA_LENGTH(bclen);
1654 iov[1] = (struct iovec){ &rta, sizeof(rta) };
1655 iov[2] = (struct iovec){ bc, bclen };
1656 req.nlh.nlmsg_len += RTA_LENGTH(bclen);
1657 }
1658
1659 msg = (struct msghdr) {
1660 .msg_name = (void*)&nladdr,
1661 .msg_namelen = sizeof(nladdr),
1662 .msg_iov = iov,
1663 .msg_iovlen = f->f ? 3 : 1,
1664 };
1665
1666 if (sendmsg(fd, &msg, 0) < 0) {
1667 close(fd);
1668 return -1;
1669 }
1670
1671 return 0;
1672}
1673
Pavel Emelyanov746a6952012-10-25 03:21:39 +00001674static int inet_show_netlink(struct filter *f, FILE *dump_fp, int protocol)
1675{
Pavel Emelyanov886d19d2012-10-25 03:23:36 +00001676 int fd, family;
Pavel Emelyanov746a6952012-10-25 03:21:39 +00001677 struct sockaddr_nl nladdr;
1678 struct msghdr msg;
1679 char buf[8192];
1680 struct iovec iov[3];
1681
1682 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
1683 return -1;
1684
Pavel Emelyanov886d19d2012-10-25 03:23:36 +00001685 family = PF_INET;
1686again:
1687 if (sockdiag_send(family, fd, protocol, f))
Pavel Emelyanov746a6952012-10-25 03:21:39 +00001688 return -1;
1689
1690 memset(&nladdr, 0, sizeof(nladdr));
1691 nladdr.nl_family = AF_NETLINK;
1692
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001693 iov[0] = (struct iovec){
1694 .iov_base = buf,
1695 .iov_len = sizeof(buf)
shemmingerea8fc102005-06-22 18:27:49 +00001696 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001697
1698 while (1) {
1699 int status;
1700 struct nlmsghdr *h;
1701
1702 msg = (struct msghdr) {
1703 (void*)&nladdr, sizeof(nladdr),
1704 iov, 1,
1705 NULL, 0,
1706 0
1707 };
1708
1709 status = recvmsg(fd, &msg, 0);
1710
1711 if (status < 0) {
1712 if (errno == EINTR)
1713 continue;
1714 perror("OVERRUN");
1715 continue;
1716 }
1717 if (status == 0) {
1718 fprintf(stderr, "EOF on netlink\n");
Matt Tierneyc51577c2012-02-15 18:20:38 -05001719 close(fd);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001720 return 0;
1721 }
1722
1723 if (dump_fp)
1724 fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
1725
1726 h = (struct nlmsghdr*)buf;
1727 while (NLMSG_OK(h, status)) {
1728 int err;
Li Yewanga37b01c2008-09-09 09:13:42 +08001729 struct inet_diag_msg *r = NLMSG_DATA(h);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001730
1731 if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
1732 h->nlmsg_seq != 123456)
1733 goto skip_it;
1734
Pavel Emelyanov886d19d2012-10-25 03:23:36 +00001735 if (h->nlmsg_type == NLMSG_DONE)
1736 goto done;
1737
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001738 if (h->nlmsg_type == NLMSG_ERROR) {
1739 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
1740 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
1741 fprintf(stderr, "ERROR truncated\n");
1742 } else {
Pavel Emelyanov886d19d2012-10-25 03:23:36 +00001743 if (family != PF_UNSPEC) {
1744 family = PF_UNSPEC;
1745 goto again;
1746 }
1747
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001748 errno = -err->error;
Eric Dumazet930a75f2012-04-10 09:00:16 -07001749 if (errno == EOPNOTSUPP) {
1750 close(fd);
1751 return -1;
1752 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001753 perror("TCPDIAG answers");
1754 }
Pavel Emelyanov886d19d2012-10-25 03:23:36 +00001755
1756 goto done;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001757 }
1758 if (!dump_fp) {
Li Yewanga37b01c2008-09-09 09:13:42 +08001759 if (!(f->families & (1<<r->idiag_family))) {
1760 h = NLMSG_NEXT(h, status);
1761 continue;
1762 }
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00001763 err = inet_show_sock(h, NULL);
Matt Tierneyc51577c2012-02-15 18:20:38 -05001764 if (err < 0) {
1765 close(fd);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001766 return err;
Matt Tierneyc51577c2012-02-15 18:20:38 -05001767 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001768 }
1769
1770skip_it:
1771 h = NLMSG_NEXT(h, status);
1772 }
1773 if (msg.msg_flags & MSG_TRUNC) {
1774 fprintf(stderr, "Message truncated\n");
1775 continue;
1776 }
1777 if (status) {
1778 fprintf(stderr, "!!!Remnant of size %d\n", status);
1779 exit(1);
1780 }
1781 }
Pavel Emelyanov886d19d2012-10-25 03:23:36 +00001782done:
1783 if (family == PF_INET) {
1784 family = PF_INET6;
1785 goto again;
1786 }
1787
Matt Tierneyc51577c2012-02-15 18:20:38 -05001788 close(fd);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001789 return 0;
1790}
1791
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001792static int tcp_show_netlink_file(struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001793{
1794 FILE *fp;
1795 char buf[8192];
1796
1797 if ((fp = fopen(getenv("TCPDIAG_FILE"), "r")) == NULL) {
1798 perror("fopen($TCPDIAG_FILE)");
1799 return -1;
1800 }
1801
1802 while (1) {
1803 int status, err;
1804 struct nlmsghdr *h = (struct nlmsghdr*)buf;
1805
1806 status = fread(buf, 1, sizeof(*h), fp);
1807 if (status < 0) {
1808 perror("Reading header from $TCPDIAG_FILE");
1809 return -1;
1810 }
1811 if (status != sizeof(*h)) {
1812 perror("Unexpected EOF reading $TCPDIAG_FILE");
1813 return -1;
1814 }
1815
1816 status = fread(h+1, 1, NLMSG_ALIGN(h->nlmsg_len-sizeof(*h)), fp);
1817
1818 if (status < 0) {
1819 perror("Reading $TCPDIAG_FILE");
1820 return -1;
1821 }
1822 if (status + sizeof(*h) < h->nlmsg_len) {
1823 perror("Unexpected EOF reading $TCPDIAG_FILE");
1824 return -1;
1825 }
1826
1827 /* The only legal exit point */
1828 if (h->nlmsg_type == NLMSG_DONE)
1829 return 0;
1830
1831 if (h->nlmsg_type == NLMSG_ERROR) {
1832 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
1833 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
1834 fprintf(stderr, "ERROR truncated\n");
1835 } else {
1836 errno = -err->error;
1837 perror("TCPDIAG answered");
1838 }
1839 return -1;
1840 }
1841
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00001842 err = inet_show_sock(h, f);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001843 if (err < 0)
1844 return err;
1845 }
1846}
1847
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001848static int tcp_show(struct filter *f, int socktype)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001849{
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001850 FILE *fp = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001851 char *buf = NULL;
1852 int bufsize = 64*1024;
1853
1854 dg_proto = TCP_PROTO;
1855
1856 if (getenv("TCPDIAG_FILE"))
1857 return tcp_show_netlink_file(f);
1858
1859 if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT")
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00001860 && inet_show_netlink(f, NULL, socktype) == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001861 return 0;
1862
1863 /* Sigh... We have to parse /proc/net/tcp... */
1864
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001865
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001866 /* Estimate amount of sockets and try to allocate
1867 * huge buffer to read all the table at one read.
1868 * Limit it by 16MB though. The assumption is: as soon as
1869 * kernel was able to hold information about N connections,
1870 * it is able to give us some memory for snapshot.
1871 */
1872 if (1) {
1873 int guess = slabstat.socks+slabstat.tcp_syns;
1874 if (f->states&(1<<SS_TIME_WAIT))
1875 guess += slabstat.tcp_tws;
1876 if (guess > (16*1024*1024)/128)
1877 guess = (16*1024*1024)/128;
1878 guess *= 128;
1879 if (guess > bufsize)
1880 bufsize = guess;
1881 }
1882 while (bufsize >= 64*1024) {
1883 if ((buf = malloc(bufsize)) != NULL)
1884 break;
1885 bufsize /= 2;
1886 }
1887 if (buf == NULL) {
1888 errno = ENOMEM;
1889 return -1;
1890 }
1891
1892 if (f->families & (1<<AF_INET)) {
Björn Steinbrink69cae642008-04-03 11:42:41 +02001893 if ((fp = net_tcp_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001894 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001895
1896 setbuffer(fp, buf, bufsize);
1897 if (generic_record_read(fp, tcp_show_line, f, AF_INET))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001898 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001899 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001900 }
1901
1902 if ((f->families & (1<<AF_INET6)) &&
Björn Steinbrink69cae642008-04-03 11:42:41 +02001903 (fp = net_tcp6_open()) != NULL) {
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001904 setbuffer(fp, buf, bufsize);
1905 if (generic_record_read(fp, tcp_show_line, f, AF_INET6))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001906 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001907 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001908 }
1909
1910 free(buf);
1911 return 0;
1912
1913outerr:
1914 do {
1915 int saved_errno = errno;
1916 if (buf)
1917 free(buf);
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01001918 if (fp)
1919 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001920 errno = saved_errno;
1921 return -1;
1922 } while (0);
1923}
1924
1925
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08001926static int dgram_show_line(char *line, const struct filter *f, int family)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001927{
1928 struct tcpstat s;
1929 char *loc, *rem, *data;
1930 char opt[256];
1931 int n;
1932 char *p;
1933
1934 if ((p = strchr(line, ':')) == NULL)
1935 return -1;
1936 loc = p+2;
1937
1938 if ((p = strchr(loc, ':')) == NULL)
1939 return -1;
1940 p[5] = 0;
1941 rem = p+6;
1942
1943 if ((p = strchr(rem, ':')) == NULL)
1944 return -1;
1945 p[5] = 0;
1946 data = p+6;
1947
1948 do {
1949 int state = (data[1] >= 'A') ? (data[1] - 'A' + 10) : (data[1] - '0');
1950
1951 if (!(f->states & (1<<state)))
1952 return 0;
1953 } while (0);
1954
1955 s.local.family = s.remote.family = family;
1956 if (family == AF_INET) {
1957 sscanf(loc, "%x:%x", s.local.data, (unsigned*)&s.lport);
1958 sscanf(rem, "%x:%x", s.remote.data, (unsigned*)&s.rport);
1959 s.local.bytelen = s.remote.bytelen = 4;
1960 } else {
1961 sscanf(loc, "%08x%08x%08x%08x:%x",
1962 s.local.data,
1963 s.local.data+1,
1964 s.local.data+2,
1965 s.local.data+3,
1966 &s.lport);
1967 sscanf(rem, "%08x%08x%08x%08x:%x",
1968 s.remote.data,
1969 s.remote.data+1,
1970 s.remote.data+2,
1971 s.remote.data+3,
1972 &s.rport);
1973 s.local.bytelen = s.remote.bytelen = 16;
1974 }
1975
1976 if (f->f && run_ssfilter(f->f, &s) == 0)
1977 return 0;
1978
1979 opt[0] = 0;
Stephen Hemmingere7113c62007-07-10 18:26:54 -07001980 n = sscanf(data, "%x %x:%x %*x:%*x %*x %d %*d %u %d %llx %[^\n]\n",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001981 &s.state, &s.wq, &s.rq,
1982 &s.uid, &s.ino,
1983 &s.refcnt, &s.sk, opt);
1984
1985 if (n < 9)
1986 opt[0] = 0;
1987
1988 if (netid_width)
1989 printf("%-*s ", netid_width, dg_proto);
1990 if (state_width)
1991 printf("%-*s ", state_width, sstate_name[s.state]);
1992
1993 printf("%-6d %-6d ", s.rq, s.wq);
1994
1995 formatted_print(&s.local, s.lport);
1996 formatted_print(&s.remote, s.rport);
1997
1998 if (show_users) {
1999 char ubuf[4096];
2000 if (find_users(s.ino, ubuf, sizeof(ubuf)) > 0)
2001 printf(" users:(%s)", ubuf);
2002 }
2003
2004 if (show_details) {
2005 if (s.uid)
2006 printf(" uid=%u", (unsigned)s.uid);
Stephen Hemmingere7113c62007-07-10 18:26:54 -07002007 printf(" ino=%u", s.ino);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002008 printf(" sk=%llx", s.sk);
2009 if (opt[0])
2010 printf(" opt:\"%s\"", opt);
2011 }
2012 printf("\n");
2013
2014 return 0;
2015}
2016
2017
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002018static int udp_show(struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002019{
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002020 FILE *fp = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002021
Pavel Emelyanov346f8ca2012-10-25 03:24:58 +00002022 if (!getenv("PROC_NET_UDP") && !getenv("PROC_ROOT")
2023 && inet_show_netlink(f, NULL, IPPROTO_UDP) == 0)
2024 return 0;
2025
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002026 dg_proto = UDP_PROTO;
2027
2028 if (f->families&(1<<AF_INET)) {
Björn Steinbrink69cae642008-04-03 11:42:41 +02002029 if ((fp = net_udp_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002030 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002031 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002032 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002033 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002034 }
2035
2036 if ((f->families&(1<<AF_INET6)) &&
Björn Steinbrink69cae642008-04-03 11:42:41 +02002037 (fp = net_udp6_open()) != NULL) {
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002038 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002039 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002040 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002041 }
2042 return 0;
2043
2044outerr:
2045 do {
2046 int saved_errno = errno;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002047 if (fp)
2048 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002049 errno = saved_errno;
2050 return -1;
2051 } while (0);
2052}
2053
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002054static int raw_show(struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002055{
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002056 FILE *fp = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002057
2058 dg_proto = RAW_PROTO;
2059
2060 if (f->families&(1<<AF_INET)) {
Björn Steinbrink69cae642008-04-03 11:42:41 +02002061 if ((fp = net_raw_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002062 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002063 if (generic_record_read(fp, dgram_show_line, f, AF_INET))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002064 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002065 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002066 }
2067
2068 if ((f->families&(1<<AF_INET6)) &&
Björn Steinbrink69cae642008-04-03 11:42:41 +02002069 (fp = net_raw6_open()) != NULL) {
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002070 if (generic_record_read(fp, dgram_show_line, f, AF_INET6))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002071 goto outerr;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002072 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002073 }
2074 return 0;
2075
2076outerr:
2077 do {
2078 int saved_errno = errno;
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002079 if (fp)
2080 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002081 errno = saved_errno;
2082 return -1;
2083 } while (0);
2084}
2085
2086
2087struct unixstat
2088{
2089 struct unixstat *next;
2090 int ino;
2091 int peer;
2092 int rq;
2093 int wq;
2094 int state;
2095 int type;
2096 char *name;
2097};
2098
2099
2100
2101int unix_state_map[] = { SS_CLOSE, SS_SYN_SENT,
2102 SS_ESTABLISHED, SS_CLOSING };
2103
2104
2105#define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct unixstat))
2106
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002107static void unix_list_free(struct unixstat *list)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002108{
2109 while (list) {
2110 struct unixstat *s = list;
2111 list = list->next;
2112 if (s->name)
2113 free(s->name);
2114 free(s);
2115 }
2116}
2117
Masatake YAMATO30b669d2014-01-08 20:13:46 +09002118static const char *unix_netid_name(int type)
2119{
2120 const char *netid;
2121
2122 switch (type) {
2123 case SOCK_STREAM:
2124 netid = "u_str";
2125 break;
2126 case SOCK_SEQPACKET:
2127 netid = "u_seq";
2128 break;
2129 case SOCK_DGRAM:
2130 default:
2131 netid = "u_dgr";
2132 break;
2133 }
2134 return netid;
2135}
2136
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002137static void unix_list_print(struct unixstat *list, struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002138{
2139 struct unixstat *s;
2140 char *peer;
2141
2142 for (s = list; s; s = s->next) {
2143 if (!(f->states & (1<<s->state)))
2144 continue;
2145 if (s->type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
2146 continue;
2147 if (s->type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
2148 continue;
Masatake YAMATO30b669d2014-01-08 20:13:46 +09002149 if (s->type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
2150 continue;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002151
2152 peer = "*";
2153 if (s->peer) {
2154 struct unixstat *p;
2155 for (p = list; p; p = p->next) {
2156 if (s->peer == p->ino)
2157 break;
2158 }
2159 if (!p) {
2160 peer = "?";
2161 } else {
2162 peer = p->name ? : "*";
2163 }
2164 }
2165
2166 if (f->f) {
2167 struct tcpstat tst;
2168 tst.local.family = AF_UNIX;
2169 tst.remote.family = AF_UNIX;
2170 memcpy(tst.local.data, &s->name, sizeof(s->name));
2171 if (strcmp(peer, "*") == 0)
2172 memset(tst.remote.data, 0, sizeof(peer));
2173 else
Stephen Hemmingerae665a52006-12-05 10:10:22 -08002174 memcpy(tst.remote.data, &peer, sizeof(peer));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002175 if (run_ssfilter(f->f, &tst) == 0)
2176 continue;
2177 }
2178
2179 if (netid_width)
Stephen Hemmingerae665a52006-12-05 10:10:22 -08002180 printf("%-*s ", netid_width,
Masatake YAMATO30b669d2014-01-08 20:13:46 +09002181 unix_netid_name(s->type));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002182 if (state_width)
2183 printf("%-*s ", state_width, sstate_name[s->state]);
2184 printf("%-6d %-6d ", s->rq, s->wq);
2185 printf("%*s %-*d %*s %-*d",
2186 addr_width, s->name ? : "*", serv_width, s->ino,
2187 addr_width, peer, serv_width, s->peer);
2188 if (show_users) {
2189 char ubuf[4096];
2190 if (find_users(s->ino, ubuf, sizeof(ubuf)) > 0)
2191 printf(" users:(%s)", ubuf);
2192 }
2193 printf("\n");
2194 }
2195}
2196
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002197static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f)
2198{
2199 struct unix_diag_msg *r = NLMSG_DATA(nlh);
2200 struct rtattr *tb[UNIX_DIAG_MAX+1];
2201 char name[128];
2202 int peer_ino;
Hannes Frederic Sowadefd61c2013-02-22 15:28:10 +00002203 __u32 rqlen, wqlen;
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002204
2205 parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
2206 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2207
Masatake YAMATO0d2e01c2014-01-08 20:13:47 +09002208 if (r->udiag_type == SOCK_STREAM && !(f->dbs&(1<<UNIX_ST_DB)))
2209 return 0;
2210 if (r->udiag_type == SOCK_DGRAM && !(f->dbs&(1<<UNIX_DG_DB)))
2211 return 0;
2212 if (r->udiag_type == SOCK_SEQPACKET && !(f->dbs&(1<<UNIX_SQ_DB)))
2213 return 0;
2214
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002215 if (netid_width)
2216 printf("%-*s ", netid_width,
Masatake YAMATO30b669d2014-01-08 20:13:46 +09002217 unix_netid_name(r->udiag_type));
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002218 if (state_width)
2219 printf("%-*s ", state_width, sstate_name[r->udiag_state]);
2220
Hannes Frederic Sowadefd61c2013-02-22 15:28:10 +00002221 if (tb[UNIX_DIAG_RQLEN]) {
2222 struct unix_diag_rqlen *rql = RTA_DATA(tb[UNIX_DIAG_RQLEN]);
2223 rqlen = rql->udiag_rqueue;
2224 wqlen = rql->udiag_wqueue;
2225 } else {
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002226 rqlen = 0;
Hannes Frederic Sowadefd61c2013-02-22 15:28:10 +00002227 wqlen = 0;
2228 }
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002229
Hannes Frederic Sowadefd61c2013-02-22 15:28:10 +00002230 printf("%-6u %-6u ", rqlen, wqlen);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002231
2232 if (tb[UNIX_DIAG_NAME]) {
2233 int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
2234
2235 memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
2236 name[len] = '\0';
2237 if (name[0] == '\0')
2238 name[0] = '@';
2239 } else
2240 sprintf(name, "*");
2241
2242 if (tb[UNIX_DIAG_PEER])
Stephen Hemminger5048f9a2013-02-26 17:32:58 -08002243 peer_ino = rta_getattr_u32(tb[UNIX_DIAG_PEER]);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002244 else
2245 peer_ino = 0;
2246
2247 printf("%*s %-*d %*s %-*d",
2248 addr_width, name,
2249 serv_width, r->udiag_ino,
2250 addr_width, "*", /* FIXME */
2251 serv_width, peer_ino);
2252
2253 if (show_users) {
2254 char ubuf[4096];
2255 if (find_users(r->udiag_ino, ubuf, sizeof(ubuf)) > 0)
2256 printf(" users:(%s)", ubuf);
2257 }
2258
Hannes Frederic Sowa51ff9f22013-02-22 15:28:18 +00002259 if (show_mem) {
2260 printf("\n\t");
2261 print_skmeminfo(tb, UNIX_DIAG_MEMINFO);
2262 }
2263
Pavel Emelyanov5b816042013-05-17 08:02:14 -07002264 if (show_details) {
2265 if (tb[UNIX_DIAG_SHUTDOWN]) {
2266 unsigned char mask;
2267 mask = *(__u8 *)RTA_DATA(tb[UNIX_DIAG_SHUTDOWN]);
2268 printf(" %c-%c", mask & 1 ? '-' : '<', mask & 2 ? '-' : '>');
2269 }
2270 }
2271
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002272 printf("\n");
2273
2274 return 0;
2275}
2276
Andrey Vagind8402b92013-06-05 12:41:58 +04002277static int handle_netlink_request(struct filter *f, FILE *dump_fp,
2278 struct nlmsghdr *req, size_t size,
2279 int (* show_one_sock)(struct nlmsghdr *nlh, struct filter *f))
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002280{
2281 int fd;
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002282 char buf[8192];
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002283
2284 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
2285 return -1;
2286
Andrey Vagind8402b92013-06-05 12:41:58 +04002287 if (send(fd, req, size, 0) < 0) {
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002288 close(fd);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002289 return -1;
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002290 }
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002291
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002292 while (1) {
Stephen Hemminger2728f592012-02-16 16:42:42 -08002293 ssize_t status;
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002294 struct nlmsghdr *h;
Stephen Hemminger2728f592012-02-16 16:42:42 -08002295 struct sockaddr_nl nladdr;
2296 socklen_t slen = sizeof(nladdr);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002297
Stephen Hemminger2728f592012-02-16 16:42:42 -08002298 status = recvfrom(fd, buf, sizeof(buf), 0,
2299 (struct sockaddr *) &nladdr, &slen);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002300 if (status < 0) {
2301 if (errno == EINTR)
2302 continue;
2303 perror("OVERRUN");
2304 continue;
2305 }
2306 if (status == 0) {
2307 fprintf(stderr, "EOF on netlink\n");
Stephen Hemminger2728f592012-02-16 16:42:42 -08002308 goto close_it;
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002309 }
2310
2311 if (dump_fp)
2312 fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
2313
2314 h = (struct nlmsghdr*)buf;
2315 while (NLMSG_OK(h, status)) {
2316 int err;
2317
2318 if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
2319 h->nlmsg_seq != 123456)
2320 goto skip_it;
2321
Stephen Hemminger2728f592012-02-16 16:42:42 -08002322 if (h->nlmsg_type == NLMSG_DONE)
2323 goto close_it;
2324
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002325 if (h->nlmsg_type == NLMSG_ERROR) {
2326 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
2327 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
2328 fprintf(stderr, "ERROR truncated\n");
2329 } else {
2330 errno = -err->error;
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002331 if (errno != ENOENT)
Andrey Vagind8402b92013-06-05 12:41:58 +04002332 fprintf(stderr, "DIAG answers %d\n", errno);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002333 }
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002334 close(fd);
2335 return -1;
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002336 }
2337 if (!dump_fp) {
Andrey Vagind8402b92013-06-05 12:41:58 +04002338 err = show_one_sock(h, f);
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002339 if (err < 0) {
2340 close(fd);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002341 return err;
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002342 }
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002343 }
2344
2345skip_it:
2346 h = NLMSG_NEXT(h, status);
2347 }
Stephen Hemminger2728f592012-02-16 16:42:42 -08002348
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002349 if (status) {
Stephen Hemminger2728f592012-02-16 16:42:42 -08002350 fprintf(stderr, "!!!Remnant of size %zd\n", status);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002351 exit(1);
2352 }
2353 }
Stephen Hemminger2728f592012-02-16 16:42:42 -08002354
2355close_it:
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002356 close(fd);
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002357 return 0;
2358}
2359
Andrey Vagind8402b92013-06-05 12:41:58 +04002360static int unix_show_netlink(struct filter *f, FILE *dump_fp)
2361{
2362 struct {
2363 struct nlmsghdr nlh;
2364 struct unix_diag_req r;
2365 } req;
2366
2367 memset(&req, 0, sizeof(req));
2368 req.nlh.nlmsg_len = sizeof(req);
2369 req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
2370 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
2371 req.nlh.nlmsg_seq = 123456;
2372
2373 req.r.sdiag_family = AF_UNIX;
2374 req.r.udiag_states = f->states;
2375 req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
2376 if (show_mem)
2377 req.r.udiag_show |= UDIAG_SHOW_MEMINFO;
2378
2379 return handle_netlink_request(f, dump_fp, &req.nlh,
2380 sizeof(req), unix_show_sock);
2381}
2382
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002383static int unix_show(struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002384{
2385 FILE *fp;
2386 char buf[256];
2387 char name[128];
2388 int newformat = 0;
2389 int cnt;
2390 struct unixstat *list = NULL;
2391
Pavel Emelyanovdfbaa902011-12-15 03:28:15 +00002392 if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
2393 && unix_show_netlink(f, NULL) == 0)
2394 return 0;
2395
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002396 if ((fp = net_unix_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002397 return -1;
2398 fgets(buf, sizeof(buf)-1, fp);
2399
Stephen Hemmingerae665a52006-12-05 10:10:22 -08002400 if (memcmp(buf, "Peer", 4) == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002401 newformat = 1;
2402 cnt = 0;
2403
2404 while (fgets(buf, sizeof(buf)-1, fp)) {
2405 struct unixstat *u, **insp;
2406 int flags;
2407
2408 if (!(u = malloc(sizeof(*u))))
2409 break;
2410 u->name = NULL;
2411
2412 if (sscanf(buf, "%x: %x %x %x %x %x %d %s",
2413 &u->peer, &u->rq, &u->wq, &flags, &u->type,
2414 &u->state, &u->ino, name) < 8)
2415 name[0] = 0;
2416
2417 if (flags&(1<<16)) {
2418 u->state = SS_LISTEN;
2419 } else {
2420 u->state = unix_state_map[u->state-1];
2421 if (u->type == SOCK_DGRAM &&
2422 u->state == SS_CLOSE &&
2423 u->peer)
2424 u->state = SS_ESTABLISHED;
2425 }
2426
2427 if (!newformat) {
2428 u->peer = 0;
2429 u->rq = 0;
2430 u->wq = 0;
2431 }
2432
2433 insp = &list;
2434 while (*insp) {
2435 if (u->type < (*insp)->type ||
2436 (u->type == (*insp)->type &&
2437 u->ino < (*insp)->ino))
2438 break;
2439 insp = &(*insp)->next;
2440 }
2441 u->next = *insp;
2442 *insp = u;
2443
2444 if (name[0]) {
2445 if ((u->name = malloc(strlen(name)+1)) == NULL)
2446 break;
2447 strcpy(u->name, name);
2448 }
2449 if (++cnt > MAX_UNIX_REMEMBER) {
2450 unix_list_print(list, f);
2451 unix_list_free(list);
2452 list = NULL;
2453 cnt = 0;
2454 }
2455 }
Eric Dumazeta3fd8e52012-01-30 17:05:45 +01002456 fclose(fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002457 if (list) {
2458 unix_list_print(list, f);
2459 unix_list_free(list);
2460 list = NULL;
2461 cnt = 0;
2462 }
2463
2464 return 0;
2465}
2466
Nicolas Dichtel372c30d2013-05-17 08:42:34 -07002467static int packet_show_sock(struct nlmsghdr *nlh, struct filter *f)
2468{
2469 struct packet_diag_msg *r = NLMSG_DATA(nlh);
2470 struct rtattr *tb[PACKET_DIAG_MAX+1];
2471 __u32 rq;
2472
2473 parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr*)(r+1),
2474 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2475
2476 /* use /proc/net/packet if all info are not available */
2477 if (!tb[PACKET_DIAG_MEMINFO])
2478 return -1;
2479
2480 if (netid_width)
2481 printf("%-*s ", netid_width,
2482 r->pdiag_type == SOCK_RAW ? "p_raw" : "p_dgr");
2483 if (state_width)
2484 printf("%-*s ", state_width, "UNCONN");
2485
2486 if (tb[PACKET_DIAG_MEMINFO]) {
2487 __u32 *skmeminfo = RTA_DATA(tb[PACKET_DIAG_MEMINFO]);
2488
2489 rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
2490 } else
2491 rq = 0;
2492 printf("%-6d %-6d ", rq, 0);
2493
2494 if (r->pdiag_num == 3) {
2495 printf("%*s:", addr_width, "*");
2496 } else {
2497 char tb2[16];
2498 printf("%*s:", addr_width,
2499 ll_proto_n2a(htons(r->pdiag_num), tb2, sizeof(tb2)));
2500 }
2501 if (tb[PACKET_DIAG_INFO]) {
2502 struct packet_diag_info *pinfo = RTA_DATA(tb[PACKET_DIAG_INFO]);
2503
2504 if (pinfo->pdi_index == 0)
2505 printf("%-*s ", serv_width, "*");
2506 else
2507 printf("%-*s ", serv_width, xll_index_to_name(pinfo->pdi_index));
2508 } else
2509 printf("%-*s ", serv_width, "*");
2510
2511 printf("%*s*%-*s",
2512 addr_width, "", serv_width, "");
2513
2514 if (show_users) {
2515 char ubuf[4096];
2516 if (find_users(r->pdiag_ino, ubuf, sizeof(ubuf)) > 0)
2517 printf(" users:(%s)", ubuf);
2518 }
2519 if (show_details) {
2520 __u32 uid = 0;
2521
2522 if (tb[PACKET_DIAG_UID])
2523 uid = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_UID]);
2524
2525 printf(" ino=%u uid=%u sk=", r->pdiag_ino, uid);
2526 if (r->pdiag_cookie[1] != 0)
2527 printf("%08x", r->pdiag_cookie[1]);
2528 printf("%08x", r->pdiag_cookie[0]);
2529 }
2530
2531 if (show_bpf && tb[PACKET_DIAG_FILTER]) {
2532 struct sock_filter *fil =
2533 RTA_DATA(tb[PACKET_DIAG_FILTER]);
2534 int num = RTA_PAYLOAD(tb[PACKET_DIAG_FILTER]) /
2535 sizeof(struct sock_filter);
2536
2537 printf("\n\tbpf filter (%d): ", num);
2538 while (num) {
2539 printf(" 0x%02x %u %u %u,",
2540 fil->code, fil->jt, fil->jf, fil->k);
2541 num--;
2542 fil++;
2543 }
2544 }
2545 printf("\n");
2546 return 0;
2547}
2548
2549static int packet_show_netlink(struct filter *f, FILE *dump_fp)
2550{
2551 int fd;
2552 struct {
2553 struct nlmsghdr nlh;
2554 struct packet_diag_req r;
2555 } req;
2556 char buf[8192];
2557
2558 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
2559 return -1;
2560
2561 memset(&req, 0, sizeof(req));
2562 req.nlh.nlmsg_len = sizeof(req);
2563 req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
2564 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
2565 req.nlh.nlmsg_seq = 123456;
2566
2567 req.r.sdiag_family = AF_PACKET;
2568 req.r.pdiag_show = PACKET_SHOW_INFO | PACKET_SHOW_MEMINFO | PACKET_SHOW_FILTER;
2569
2570 if (send(fd, &req, sizeof(req), 0) < 0) {
2571 close(fd);
2572 return -1;
2573 }
2574
2575 while (1) {
2576 ssize_t status;
2577 struct nlmsghdr *h;
2578 struct sockaddr_nl nladdr;
2579 socklen_t slen = sizeof(nladdr);
2580
2581 status = recvfrom(fd, buf, sizeof(buf), 0,
2582 (struct sockaddr *) &nladdr, &slen);
2583 if (status < 0) {
2584 if (errno == EINTR)
2585 continue;
2586 perror("OVERRUN");
2587 continue;
2588 }
2589 if (status == 0) {
2590 fprintf(stderr, "EOF on netlink\n");
2591 goto close_it;
2592 }
2593
2594 if (dump_fp)
2595 fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
2596
2597 h = (struct nlmsghdr*)buf;
2598 while (NLMSG_OK(h, status)) {
2599 int err;
2600
2601 if (h->nlmsg_seq != 123456)
2602 goto skip_it;
2603
2604 if (h->nlmsg_type == NLMSG_DONE)
2605 goto close_it;
2606
2607 if (h->nlmsg_type == NLMSG_ERROR) {
2608 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
2609 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
2610 fprintf(stderr, "ERROR truncated\n");
2611 } else {
2612 errno = -err->error;
2613 if (errno != ENOENT)
2614 fprintf(stderr, "UDIAG answers %d\n", errno);
2615 }
2616 close(fd);
2617 return -1;
2618 }
2619 if (!dump_fp) {
2620 err = packet_show_sock(h, f);
2621 if (err < 0) {
2622 close(fd);
2623 return err;
2624 }
2625 }
2626
2627skip_it:
2628 h = NLMSG_NEXT(h, status);
2629 }
2630
2631 if (status) {
2632 fprintf(stderr, "!!!Remnant of size %zd\n", status);
2633 exit(1);
2634 }
2635 }
2636
2637close_it:
2638 close(fd);
2639 return 0;
2640}
2641
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002642
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002643static int packet_show(struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002644{
2645 FILE *fp;
2646 char buf[256];
2647 int type;
2648 int prot;
2649 int iface;
2650 int state;
2651 int rq;
2652 int uid;
2653 int ino;
2654 unsigned long long sk;
2655
2656 if (!(f->states & (1<<SS_CLOSE)))
2657 return 0;
2658
Nicolas Dichtel372c30d2013-05-17 08:42:34 -07002659 if (packet_show_netlink(f, NULL) == 0)
2660 return 0;
2661
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002662 if ((fp = net_packet_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002663 return -1;
2664 fgets(buf, sizeof(buf)-1, fp);
2665
2666 while (fgets(buf, sizeof(buf)-1, fp)) {
2667 sscanf(buf, "%llx %*d %d %x %d %d %u %u %u",
2668 &sk,
2669 &type, &prot, &iface, &state,
2670 &rq, &uid, &ino);
2671
2672 if (type == SOCK_RAW && !(f->dbs&(1<<PACKET_R_DB)))
2673 continue;
2674 if (type == SOCK_DGRAM && !(f->dbs&(1<<PACKET_DG_DB)))
2675 continue;
2676 if (f->f) {
2677 struct tcpstat tst;
2678 tst.local.family = AF_PACKET;
2679 tst.remote.family = AF_PACKET;
2680 tst.rport = 0;
2681 tst.lport = iface;
2682 tst.local.data[0] = prot;
2683 tst.remote.data[0] = 0;
2684 if (run_ssfilter(f->f, &tst) == 0)
2685 continue;
2686 }
2687
2688 if (netid_width)
Stephen Hemmingerae665a52006-12-05 10:10:22 -08002689 printf("%-*s ", netid_width,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002690 type == SOCK_RAW ? "p_raw" : "p_dgr");
2691 if (state_width)
2692 printf("%-*s ", state_width, "UNCONN");
2693 printf("%-6d %-6d ", rq, 0);
2694 if (prot == 3) {
2695 printf("%*s:", addr_width, "*");
2696 } else {
2697 char tb[16];
Stephen Hemmingerae665a52006-12-05 10:10:22 -08002698 printf("%*s:", addr_width,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002699 ll_proto_n2a(htons(prot), tb, sizeof(tb)));
2700 }
2701 if (iface == 0) {
2702 printf("%-*s ", serv_width, "*");
2703 } else {
2704 printf("%-*s ", serv_width, xll_index_to_name(iface));
2705 }
2706 printf("%*s*%-*s",
2707 addr_width, "", serv_width, "");
2708
2709 if (show_users) {
2710 char ubuf[4096];
2711 if (find_users(ino, ubuf, sizeof(ubuf)) > 0)
2712 printf(" users:(%s)", ubuf);
2713 }
2714 if (show_details) {
2715 printf(" ino=%u uid=%u sk=%llx", ino, uid, sk);
2716 }
2717 printf("\n");
2718 }
2719
2720 return 0;
2721}
2722
Andrey Vagin129709a2013-06-05 12:41:59 +04002723static void netlink_show_one(struct filter *f,
2724 int prot, int pid, unsigned groups,
Andrey Vaginf271fe02013-06-05 12:42:00 +04002725 int state, int dst_pid, unsigned dst_group,
Andrey Vagin129709a2013-06-05 12:41:59 +04002726 int rq, int wq,
2727 unsigned long long sk, unsigned long long cb)
2728{
2729 if (f->f) {
2730 struct tcpstat tst;
2731 tst.local.family = AF_NETLINK;
2732 tst.remote.family = AF_NETLINK;
2733 tst.rport = -1;
2734 tst.lport = pid;
2735 tst.local.data[0] = prot;
2736 tst.remote.data[0] = 0;
2737 if (run_ssfilter(f->f, &tst) == 0)
2738 return;
2739 }
2740
2741 if (netid_width)
2742 printf("%-*s ", netid_width, "nl");
2743 if (state_width)
2744 printf("%-*s ", state_width, "UNCONN");
2745 printf("%-6d %-6d ", rq, wq);
2746 if (resolve_services && prot == 0)
2747 printf("%*s:", addr_width, "rtnl");
2748 else if (resolve_services && prot == 3)
2749 printf("%*s:", addr_width, "fw");
2750 else if (resolve_services && prot == 4)
2751 printf("%*s:", addr_width, "tcpdiag");
2752 else
2753 printf("%*d:", addr_width, prot);
2754 if (pid == -1) {
2755 printf("%-*s ", serv_width, "*");
2756 } else if (resolve_services) {
2757 int done = 0;
2758 if (!pid) {
2759 done = 1;
2760 printf("%-*s ", serv_width, "kernel");
2761 } else if (pid > 0) {
2762 char procname[64];
2763 FILE *fp;
2764 sprintf(procname, "%s/%d/stat",
2765 getenv("PROC_ROOT") ? : "/proc", pid);
2766 if ((fp = fopen(procname, "r")) != NULL) {
2767 if (fscanf(fp, "%*d (%[^)])", procname) == 1) {
2768 sprintf(procname+strlen(procname), "/%d", pid);
2769 printf("%-*s ", serv_width, procname);
2770 done = 1;
2771 }
2772 fclose(fp);
2773 }
2774 }
2775 if (!done)
2776 printf("%-*d ", serv_width, pid);
2777 } else {
2778 printf("%-*d ", serv_width, pid);
2779 }
Andrey Vaginf271fe02013-06-05 12:42:00 +04002780
2781 if (state == NETLINK_CONNECTED) {
2782 printf("%*d:%-*d",
2783 addr_width, dst_group, serv_width, dst_pid);
2784 } else {
2785 printf("%*s*%-*s",
2786 addr_width, "", serv_width, "");
2787 }
Andrey Vagin129709a2013-06-05 12:41:59 +04002788
2789 if (show_details) {
2790 printf(" sk=%llx cb=%llx groups=0x%08x", sk, cb, groups);
2791 }
2792 printf("\n");
2793
2794 return;
2795}
2796
Andrey Vaginecb928c2013-06-05 12:42:01 +04002797static int netlink_show_sock(struct nlmsghdr *nlh, struct filter *f)
2798{
2799 struct netlink_diag_msg *r = NLMSG_DATA(nlh);
2800 struct rtattr *tb[NETLINK_DIAG_MAX+1];
2801 int rq = 0, wq = 0;
2802 unsigned long groups = 0;
2803
2804 parse_rtattr(tb, NETLINK_DIAG_MAX, (struct rtattr*)(r+1),
2805 nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
2806
2807 if (tb[NETLINK_DIAG_GROUPS] && RTA_PAYLOAD(tb[NETLINK_DIAG_GROUPS]))
2808 groups = *(unsigned long *) RTA_DATA(tb[NETLINK_DIAG_GROUPS]);
2809
2810 if (tb[NETLINK_DIAG_MEMINFO]) {
2811 const __u32 *skmeminfo;
2812 skmeminfo = RTA_DATA(tb[NETLINK_DIAG_MEMINFO]);
2813
2814 rq = skmeminfo[SK_MEMINFO_RMEM_ALLOC];
2815 wq = skmeminfo[SK_MEMINFO_WMEM_ALLOC];
2816 }
2817
2818 netlink_show_one(f, r->ndiag_protocol, r->ndiag_portid, groups,
2819 r->ndiag_state, r->ndiag_dst_portid, r->ndiag_dst_group,
2820 rq, wq, 0, 0);
2821
2822 if (show_mem) {
2823 printf("\t");
2824 print_skmeminfo(tb, NETLINK_DIAG_MEMINFO);
2825 printf("\n");
2826 }
2827
2828 return 0;
2829}
2830
2831static int netlink_show_netlink(struct filter *f, FILE *dump_fp)
2832{
2833 struct {
2834 struct nlmsghdr nlh;
2835 struct netlink_diag_req r;
2836 } req;
2837
2838 memset(&req, 0, sizeof(req));
2839 req.nlh.nlmsg_len = sizeof(req);
2840 req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
2841 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
2842 req.nlh.nlmsg_seq = 123456;
2843
2844 req.r.sdiag_family = AF_NETLINK;
2845 req.r.sdiag_protocol = NDIAG_PROTO_ALL;
2846 req.r.ndiag_show = NDIAG_SHOW_GROUPS | NDIAG_SHOW_MEMINFO;
2847
2848 return handle_netlink_request(f, dump_fp, &req.nlh,
2849 sizeof(req), netlink_show_sock);
2850}
2851
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002852static int netlink_show(struct filter *f)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002853{
2854 FILE *fp;
2855 char buf[256];
2856 int prot, pid;
2857 unsigned groups;
2858 int rq, wq, rc;
2859 unsigned long long sk, cb;
2860
2861 if (!(f->states & (1<<SS_CLOSE)))
2862 return 0;
2863
Andrey Vagin129709a2013-06-05 12:41:59 +04002864 if (!getenv("PROC_NET_NETLINK") && !getenv("PROC_ROOT") &&
2865 netlink_show_netlink(f, NULL) == 0)
2866 return 0;
2867
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002868 if ((fp = net_netlink_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002869 return -1;
2870 fgets(buf, sizeof(buf)-1, fp);
2871
2872 while (fgets(buf, sizeof(buf)-1, fp)) {
2873 sscanf(buf, "%llx %d %d %x %d %d %llx %d",
2874 &sk,
2875 &prot, &pid, &groups, &rq, &wq, &cb, &rc);
2876
Andrey Vaginf271fe02013-06-05 12:42:00 +04002877 netlink_show_one(f, prot, pid, groups, 0, 0, 0, rq, wq, sk, cb);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002878 }
2879
2880 return 0;
2881}
2882
2883struct snmpstat
2884{
2885 int tcp_estab;
2886};
2887
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002888static int get_snmp_int(char *proto, char *key, int *result)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002889{
2890 char buf[1024];
2891 FILE *fp;
2892 int protolen = strlen(proto);
2893 int keylen = strlen(key);
2894
2895 *result = 0;
2896
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002897 if ((fp = net_snmp_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002898 return -1;
2899
2900 while (fgets(buf, sizeof(buf), fp) != NULL) {
2901 char *p = buf;
2902 int pos = 0;
2903 if (memcmp(buf, proto, protolen))
2904 continue;
2905 while ((p = strchr(p, ' ')) != NULL) {
2906 pos++;
2907 p++;
2908 if (memcmp(p, key, keylen) == 0 &&
2909 (p[keylen] == ' ' || p[keylen] == '\n'))
2910 break;
2911 }
2912 if (fgets(buf, sizeof(buf), fp) == NULL)
2913 break;
2914 if (memcmp(buf, proto, protolen))
2915 break;
2916 p = buf;
2917 while ((p = strchr(p, ' ')) != NULL) {
2918 p++;
2919 if (--pos == 0) {
2920 sscanf(p, "%d", result);
2921 fclose(fp);
2922 return 0;
2923 }
2924 }
2925 }
2926
2927 fclose(fp);
2928 errno = ESRCH;
2929 return -1;
2930}
2931
2932
2933/* Get stats from sockstat */
2934
2935struct sockstat
2936{
2937 int socks;
2938 int tcp_mem;
2939 int tcp_total;
2940 int tcp_orphans;
2941 int tcp_tws;
2942 int tcp4_hashed;
2943 int udp4;
2944 int raw4;
2945 int frag4;
2946 int frag4_mem;
2947 int tcp6_hashed;
2948 int udp6;
2949 int raw6;
2950 int frag6;
2951 int frag6_mem;
2952};
2953
2954static void get_sockstat_line(char *line, struct sockstat *s)
2955{
2956 char id[256], rem[256];
2957
2958 if (sscanf(line, "%[^ ] %[^\n]\n", id, rem) != 2)
2959 return;
2960
2961 if (strcmp(id, "sockets:") == 0)
2962 sscanf(rem, "%*s%d", &s->socks);
2963 else if (strcmp(id, "UDP:") == 0)
2964 sscanf(rem, "%*s%d", &s->udp4);
2965 else if (strcmp(id, "UDP6:") == 0)
2966 sscanf(rem, "%*s%d", &s->udp6);
2967 else if (strcmp(id, "RAW:") == 0)
2968 sscanf(rem, "%*s%d", &s->raw4);
2969 else if (strcmp(id, "RAW6:") == 0)
2970 sscanf(rem, "%*s%d", &s->raw6);
2971 else if (strcmp(id, "TCP6:") == 0)
2972 sscanf(rem, "%*s%d", &s->tcp6_hashed);
2973 else if (strcmp(id, "FRAG:") == 0)
2974 sscanf(rem, "%*s%d%*s%d", &s->frag4, &s->frag4_mem);
2975 else if (strcmp(id, "FRAG6:") == 0)
2976 sscanf(rem, "%*s%d%*s%d", &s->frag6, &s->frag6_mem);
2977 else if (strcmp(id, "TCP:") == 0)
2978 sscanf(rem, "%*s%d%*s%d%*s%d%*s%d%*s%d",
2979 &s->tcp4_hashed,
2980 &s->tcp_orphans, &s->tcp_tws, &s->tcp_total, &s->tcp_mem);
2981}
2982
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08002983static int get_sockstat(struct sockstat *s)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002984{
2985 char buf[256];
2986 FILE *fp;
2987
2988 memset(s, 0, sizeof(*s));
2989
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002990 if ((fp = net_sockstat_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002991 return -1;
2992 while(fgets(buf, sizeof(buf), fp) != NULL)
2993 get_sockstat_line(buf, s);
2994 fclose(fp);
2995
Stephen Hemmingerab01dbb2007-07-18 15:31:29 +01002996 if ((fp = net_sockstat6_open()) == NULL)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00002997 return 0;
2998 while(fgets(buf, sizeof(buf), fp) != NULL)
2999 get_sockstat_line(buf, s);
3000 fclose(fp);
3001
3002 return 0;
3003}
3004
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08003005static int print_summary(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003006{
3007 struct sockstat s;
3008 struct snmpstat sn;
3009
3010 if (get_sockstat(&s) < 0)
3011 perror("ss: get_sockstat");
3012 if (get_snmp_int("Tcp:", "CurrEstab", &sn.tcp_estab) < 0)
3013 perror("ss: get_snmpstat");
3014
3015 printf("Total: %d (kernel %d)\n", s.socks, slabstat.socks);
3016
3017 printf("TCP: %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
3018 s.tcp_total + slabstat.tcp_syns + s.tcp_tws,
3019 sn.tcp_estab,
3020 s.tcp_total - (s.tcp4_hashed+s.tcp6_hashed-s.tcp_tws),
3021 s.tcp_orphans,
3022 slabstat.tcp_syns,
3023 s.tcp_tws, slabstat.tcp_tws,
3024 slabstat.tcp_ports
3025 );
3026
3027 printf("\n");
3028 printf("Transport Total IP IPv6\n");
3029 printf("* %-9d %-9s %-9s\n", slabstat.socks, "-", "-");
3030 printf("RAW %-9d %-9d %-9d\n", s.raw4+s.raw6, s.raw4, s.raw6);
3031 printf("UDP %-9d %-9d %-9d\n", s.udp4+s.udp6, s.udp4, s.udp6);
3032 printf("TCP %-9d %-9d %-9d\n", s.tcp4_hashed+s.tcp6_hashed, s.tcp4_hashed, s.tcp6_hashed);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08003033 printf("INET %-9d %-9d %-9d\n",
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003034 s.raw4+s.udp4+s.tcp4_hashed+
3035 s.raw6+s.udp6+s.tcp6_hashed,
3036 s.raw4+s.udp4+s.tcp4_hashed,
3037 s.raw6+s.udp6+s.tcp6_hashed);
3038 printf("FRAG %-9d %-9d %-9d\n", s.frag4+s.frag6, s.frag4, s.frag6);
3039
3040 printf("\n");
3041
3042 return 0;
3043}
3044
Andreas Henriksson7a96e192009-12-07 13:12:36 +01003045static void _usage(FILE *dest)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003046{
Andreas Henriksson7a96e192009-12-07 13:12:36 +01003047 fprintf(dest,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003048"Usage: ss [ OPTIONS ]\n"
3049" ss [ OPTIONS ] [ FILTER ]\n"
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003050" -h, --help this message\n"
3051" -V, --version output version information\n"
3052" -n, --numeric don't resolve service names\n"
3053" -r, --resolve resolve host names\n"
3054" -a, --all display all sockets\n"
3055" -l, --listening display listening sockets\n"
3056" -o, --options show timer information\n"
3057" -e, --extended show detailed socket information\n"
3058" -m, --memory show socket memory usage\n"
3059" -p, --processes show process using socket\n"
3060" -i, --info show internal TCP information\n"
3061" -s, --summary show socket usage summary\n"
Rami Rosenb0f01cf2013-05-24 12:42:40 +03003062" -b, --bpf show bpf filter socket information\n"
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003063"\n"
3064" -4, --ipv4 display only IP version 4 sockets\n"
3065" -6, --ipv6 display only IP version 6 sockets\n"
3066" -0, --packet display PACKET sockets\n"
3067" -t, --tcp display only TCP sockets\n"
3068" -u, --udp display only UDP sockets\n"
shemminger351efcd2005-09-01 19:21:50 +00003069" -d, --dccp display only DCCP sockets\n"
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003070" -w, --raw display only RAW sockets\n"
3071" -x, --unix display only Unix domain sockets\n"
3072" -f, --family=FAMILY display sockets of type FAMILY\n"
3073"\n"
Petr Sabata583de142011-10-06 14:45:32 +02003074" -A, --query=QUERY, --socket=QUERY\n"
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003075" QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]\n"
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003076"\n"
Petr Sabata583de142011-10-06 14:45:32 +02003077" -D, --diag=FILE Dump raw information about TCP sockets to FILE\n"
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003078" -F, --filter=FILE read filter information from FILE\n"
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003079" FILTER := [ state TCP-STATE ] [ EXPRESSION ]\n"
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003080 );
Andreas Henriksson7a96e192009-12-07 13:12:36 +01003081}
3082
3083static void help(void) __attribute__((noreturn));
3084static void help(void)
3085{
3086 _usage(stdout);
3087 exit(0);
3088}
3089
3090static void usage(void) __attribute__((noreturn));
3091static void usage(void)
3092{
3093 _usage(stderr);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003094 exit(-1);
3095}
3096
3097
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -08003098static int scan_state(const char *state)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003099{
3100 int i;
3101 if (strcasecmp(state, "close") == 0 ||
3102 strcasecmp(state, "closed") == 0)
3103 return (1<<SS_CLOSE);
3104 if (strcasecmp(state, "syn-rcv") == 0)
3105 return (1<<SS_SYN_RECV);
osdl.net!shemminger1a5bad52004-07-07 17:06:35 +00003106 if (strcasecmp(state, "established") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003107 return (1<<SS_ESTABLISHED);
3108 if (strcasecmp(state, "all") == 0)
3109 return SS_ALL;
3110 if (strcasecmp(state, "connected") == 0)
3111 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN));
osdl.net!shemminger1a5bad52004-07-07 17:06:35 +00003112 if (strcasecmp(state, "synchronized") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003113 return SS_ALL & ~((1<<SS_CLOSE)|(1<<SS_LISTEN)|(1<<SS_SYN_SENT));
3114 if (strcasecmp(state, "bucket") == 0)
3115 return (1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT);
3116 if (strcasecmp(state, "big") == 0)
3117 return SS_ALL & ~((1<<SS_SYN_RECV)|(1<<SS_TIME_WAIT));
3118 for (i=0; i<SS_MAX; i++) {
osdl.net!shemminger1a5bad52004-07-07 17:06:35 +00003119 if (strcasecmp(state, sstate_namel[i]) == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003120 return (1<<i);
3121 }
3122 return 0;
3123}
3124
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003125static const struct option long_opts[] = {
3126 { "numeric", 0, 0, 'n' },
3127 { "resolve", 0, 0, 'r' },
3128 { "options", 0, 0, 'o' },
3129 { "extended", 0, 0, 'e' },
3130 { "memory", 0, 0, 'm' },
3131 { "info", 0, 0, 'i' },
3132 { "processes", 0, 0, 'p' },
Nicolas Dichtel372c30d2013-05-17 08:42:34 -07003133 { "bpf", 0, 0, 'b' },
shemminger351efcd2005-09-01 19:21:50 +00003134 { "dccp", 0, 0, 'd' },
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003135 { "tcp", 0, 0, 't' },
3136 { "udp", 0, 0, 'u' },
3137 { "raw", 0, 0, 'w' },
3138 { "unix", 0, 0, 'x' },
3139 { "all", 0, 0, 'a' },
3140 { "listening", 0, 0, 'l' },
3141 { "ipv4", 0, 0, '4' },
3142 { "ipv6", 0, 0, '6' },
3143 { "packet", 0, 0, '0' },
3144 { "family", 1, 0, 'f' },
3145 { "socket", 1, 0, 'A' },
Petr Sabata583de142011-10-06 14:45:32 +02003146 { "query", 1, 0, 'A' },
osdl.net!shemmingerc3f346b2005-01-18 22:31:42 +00003147 { "summary", 0, 0, 's' },
Petr Sabata583de142011-10-06 14:45:32 +02003148 { "diag", 1, 0, 'D' },
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003149 { "filter", 1, 0, 'F' },
3150 { "version", 0, 0, 'V' },
3151 { "help", 0, 0, 'h' },
3152 { 0 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -08003153
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003154};
3155
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003156int main(int argc, char *argv[])
3157{
3158 int do_default = 1;
3159 int saw_states = 0;
3160 int saw_query = 0;
3161 int do_summary = 0;
osdl.org!shemminger7d105b52004-06-02 20:22:08 +00003162 const char *dump_tcpdiag = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003163 FILE *filter_fp = NULL;
3164 int ch;
3165
3166 memset(&current_filter, 0, sizeof(current_filter));
3167
3168 current_filter.states = default_filter.states;
3169
Nicolas Dichtel372c30d2013-05-17 08:42:34 -07003170 while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vV",
osdl.org!shemmingerab611592004-06-09 21:30:13 +00003171 long_opts, NULL)) != EOF) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003172 switch(ch) {
3173 case 'n':
3174 resolve_services = 0;
3175 break;
3176 case 'r':
3177 resolve_hosts = 1;
3178 break;
3179 case 'o':
3180 show_options = 1;
3181 break;
3182 case 'e':
3183 show_options = 1;
3184 show_details++;
3185 break;
3186 case 'm':
3187 show_mem = 1;
3188 break;
3189 case 'i':
3190 show_tcpinfo = 1;
3191 break;
3192 case 'p':
3193 show_users++;
Steve Finkfbc0f872010-06-09 11:42:38 -07003194 user_ent_hash_build();
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003195 break;
Nicolas Dichtel372c30d2013-05-17 08:42:34 -07003196 case 'b':
3197 show_options = 1;
3198 show_bpf++;
3199 break;
shemminger351efcd2005-09-01 19:21:50 +00003200 case 'd':
3201 current_filter.dbs |= (1<<DCCP_DB);
3202 do_default = 0;
3203 break;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003204 case 't':
3205 current_filter.dbs |= (1<<TCP_DB);
3206 do_default = 0;
3207 break;
3208 case 'u':
3209 current_filter.dbs |= (1<<UDP_DB);
3210 do_default = 0;
3211 break;
3212 case 'w':
3213 current_filter.dbs |= (1<<RAW_DB);
3214 do_default = 0;
3215 break;
3216 case 'x':
3217 current_filter.dbs |= UNIX_DBM;
3218 do_default = 0;
3219 break;
3220 case 'a':
3221 current_filter.states = SS_ALL;
3222 break;
3223 case 'l':
Petr Å abata16963ce2011-11-16 09:32:20 -08003224 current_filter.states = (1<<SS_LISTEN) | (1<<SS_CLOSE);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003225 break;
3226 case '4':
3227 preferred_family = AF_INET;
3228 break;
3229 case '6':
3230 preferred_family = AF_INET6;
3231 break;
3232 case '0':
3233 preferred_family = AF_PACKET;
3234 break;
3235 case 'f':
3236 if (strcmp(optarg, "inet") == 0)
3237 preferred_family = AF_INET;
3238 else if (strcmp(optarg, "inet6") == 0)
3239 preferred_family = AF_INET6;
3240 else if (strcmp(optarg, "link") == 0)
3241 preferred_family = AF_PACKET;
3242 else if (strcmp(optarg, "unix") == 0)
3243 preferred_family = AF_UNIX;
3244 else if (strcmp(optarg, "netlink") == 0)
3245 preferred_family = AF_NETLINK;
3246 else if (strcmp(optarg, "help") == 0)
Andreas Henriksson7a96e192009-12-07 13:12:36 +01003247 help();
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003248 else {
3249 fprintf(stderr, "ss: \"%s\" is invalid family\n", optarg);
3250 usage();
3251 }
3252 break;
3253 case 'A':
3254 {
3255 char *p, *p1;
3256 if (!saw_query) {
3257 current_filter.dbs = 0;
3258 saw_query = 1;
3259 do_default = 0;
3260 }
3261 p = p1 = optarg;
3262 do {
3263 if ((p1 = strchr(p, ',')) != NULL)
Stephen Hemmingerae665a52006-12-05 10:10:22 -08003264 *p1 = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003265 if (strcmp(p, "all") == 0) {
3266 current_filter.dbs = ALL_DB;
3267 } else if (strcmp(p, "inet") == 0) {
shemminger351efcd2005-09-01 19:21:50 +00003268 current_filter.dbs |= (1<<TCP_DB)|(1<<DCCP_DB)|(1<<UDP_DB)|(1<<RAW_DB);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003269 } else if (strcmp(p, "udp") == 0) {
3270 current_filter.dbs |= (1<<UDP_DB);
shemminger351efcd2005-09-01 19:21:50 +00003271 } else if (strcmp(p, "dccp") == 0) {
3272 current_filter.dbs |= (1<<DCCP_DB);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003273 } else if (strcmp(p, "tcp") == 0) {
3274 current_filter.dbs |= (1<<TCP_DB);
3275 } else if (strcmp(p, "raw") == 0) {
3276 current_filter.dbs |= (1<<RAW_DB);
3277 } else if (strcmp(p, "unix") == 0) {
3278 current_filter.dbs |= UNIX_DBM;
osdl.net!shemminger1a5bad52004-07-07 17:06:35 +00003279 } else if (strcasecmp(p, "unix_stream") == 0 ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003280 strcmp(p, "u_str") == 0) {
3281 current_filter.dbs |= (1<<UNIX_ST_DB);
osdl.net!shemminger1a5bad52004-07-07 17:06:35 +00003282 } else if (strcasecmp(p, "unix_dgram") == 0 ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003283 strcmp(p, "u_dgr") == 0) {
3284 current_filter.dbs |= (1<<UNIX_DG_DB);
Masatake YAMATO30b669d2014-01-08 20:13:46 +09003285 } else if (strcasecmp(p, "unix_seqpacket") == 0 ||
3286 strcmp(p, "u_seq") == 0) {
3287 current_filter.dbs |= (1<<UNIX_SQ_DB);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003288 } else if (strcmp(p, "packet") == 0) {
3289 current_filter.dbs |= PACKET_DBM;
3290 } else if (strcmp(p, "packet_raw") == 0 ||
3291 strcmp(p, "p_raw") == 0) {
3292 current_filter.dbs |= (1<<PACKET_R_DB);
3293 } else if (strcmp(p, "packet_dgram") == 0 ||
3294 strcmp(p, "p_dgr") == 0) {
3295 current_filter.dbs |= (1<<PACKET_DG_DB);
3296 } else if (strcmp(p, "netlink") == 0) {
3297 current_filter.dbs |= (1<<NETLINK_DB);
3298 } else {
3299 fprintf(stderr, "ss: \"%s\" is illegal socket table id\n", p);
3300 usage();
3301 }
3302 p = p1 + 1;
3303 } while (p1);
3304 break;
3305 }
3306 case 's':
3307 do_summary = 1;
3308 break;
3309 case 'D':
3310 dump_tcpdiag = optarg;
3311 break;
3312 case 'F':
3313 if (filter_fp) {
3314 fprintf(stderr, "More than one filter file\n");
3315 exit(-1);
3316 }
3317 if (optarg[0] == '-')
3318 filter_fp = stdin;
3319 else
3320 filter_fp = fopen(optarg, "r");
3321 if (!filter_fp) {
3322 perror("fopen filter file");
3323 exit(-1);
3324 }
3325 break;
3326 case 'v':
3327 case 'V':
3328 printf("ss utility, iproute2-ss%s\n", SNAPSHOT);
3329 exit(0);
3330 case 'h':
3331 case '?':
Andreas Henriksson7a96e192009-12-07 13:12:36 +01003332 help();
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003333 default:
3334 usage();
3335 }
3336 }
3337
3338 argc -= optind;
3339 argv += optind;
3340
3341 get_slabstat(&slabstat);
3342
3343 if (do_summary) {
3344 print_summary();
3345 if (do_default && argc == 0)
3346 exit(0);
3347 }
3348
3349 if (do_default)
3350 current_filter.dbs = default_filter.dbs;
3351
3352 if (preferred_family == AF_UNSPEC) {
3353 if (!(current_filter.dbs&~UNIX_DBM))
3354 preferred_family = AF_UNIX;
3355 else if (!(current_filter.dbs&~PACKET_DBM))
3356 preferred_family = AF_PACKET;
3357 else if (!(current_filter.dbs&~(1<<NETLINK_DB)))
3358 preferred_family = AF_NETLINK;
3359 }
3360
3361 if (preferred_family != AF_UNSPEC) {
3362 int mask2;
3363 if (preferred_family == AF_INET ||
3364 preferred_family == AF_INET6) {
Li Yewangf70d96a2008-09-09 09:06:47 +08003365 mask2= current_filter.dbs;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003366 } else if (preferred_family == AF_PACKET) {
3367 mask2 = PACKET_DBM;
3368 } else if (preferred_family == AF_UNIX) {
3369 mask2 = UNIX_DBM;
3370 } else if (preferred_family == AF_NETLINK) {
3371 mask2 = (1<<NETLINK_DB);
3372 } else {
3373 mask2 = 0;
3374 }
3375
3376 if (do_default)
3377 current_filter.dbs = mask2;
3378 else
3379 current_filter.dbs &= mask2;
3380 current_filter.families = (1<<preferred_family);
3381 } else {
3382 if (!do_default)
3383 current_filter.families = ~0;
3384 else
3385 current_filter.families = default_filter.families;
3386 }
3387 if (current_filter.dbs == 0) {
3388 fprintf(stderr, "ss: no socket tables to show with such filter.\n");
3389 exit(0);
3390 }
3391 if (current_filter.families == 0) {
3392 fprintf(stderr, "ss: no families to show with such filter.\n");
3393 exit(0);
3394 }
3395
3396 if (resolve_services && resolve_hosts &&
shemminger351efcd2005-09-01 19:21:50 +00003397 (current_filter.dbs&(UNIX_DBM|(1<<TCP_DB)|(1<<UDP_DB)|(1<<DCCP_DB))))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003398 init_service_resolver();
3399
3400 /* Now parse filter... */
3401 if (argc == 0 && filter_fp) {
3402 if (ssfilter_parse(&current_filter.f, 0, NULL, filter_fp))
3403 usage();
3404 }
3405
3406 while (argc > 0) {
3407 if (strcmp(*argv, "state") == 0) {
3408 NEXT_ARG();
3409 if (!saw_states)
3410 current_filter.states = 0;
3411 current_filter.states |= scan_state(*argv);
3412 saw_states = 1;
3413 } else if (strcmp(*argv, "exclude") == 0 ||
3414 strcmp(*argv, "excl") == 0) {
3415 NEXT_ARG();
3416 if (!saw_states)
3417 current_filter.states = SS_ALL;
3418 current_filter.states &= ~scan_state(*argv);
3419 saw_states = 1;
3420 } else {
3421 if (ssfilter_parse(&current_filter.f, argc, argv, filter_fp))
3422 usage();
3423 break;
3424 }
3425 argc--; argv++;
3426 }
3427
3428 if (current_filter.states == 0) {
3429 fprintf(stderr, "ss: no socket states to show with such filter.\n");
3430 exit(0);
3431 }
3432
3433 if (dump_tcpdiag) {
3434 FILE *dump_fp = stdout;
3435 if (!(current_filter.dbs & (1<<TCP_DB))) {
3436 fprintf(stderr, "ss: tcpdiag dump requested and no tcp in filter.\n");
3437 exit(0);
3438 }
3439 if (dump_tcpdiag[0] != '-') {
3440 dump_fp = fopen(dump_tcpdiag, "w");
3441 if (!dump_tcpdiag) {
3442 perror("fopen dump file");
3443 exit(-1);
3444 }
3445 }
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00003446 inet_show_netlink(&current_filter, dump_fp, IPPROTO_TCP);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003447 fflush(dump_fp);
3448 exit(0);
3449 }
3450
3451 netid_width = 0;
3452 if (current_filter.dbs&(current_filter.dbs-1))
3453 netid_width = 5;
3454
3455 state_width = 0;
3456 if (current_filter.states&(current_filter.states-1))
3457 state_width = 10;
3458
3459 screen_width = 80;
3460 if (isatty(STDOUT_FILENO)) {
3461 struct winsize w;
3462
3463 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) {
3464 if (w.ws_col > 0)
3465 screen_width = w.ws_col;
3466 }
3467 }
3468
3469 addrp_width = screen_width;
3470 addrp_width -= netid_width+1;
3471 addrp_width -= state_width+1;
3472 addrp_width -= 14;
3473
3474 if (addrp_width&1) {
3475 if (netid_width)
3476 netid_width++;
3477 else if (state_width)
3478 state_width++;
3479 }
3480
3481 addrp_width /= 2;
3482 addrp_width--;
3483
3484 serv_width = resolve_services ? 7 : 5;
3485
3486 if (addrp_width < 15+serv_width+1)
3487 addrp_width = 15+serv_width+1;
3488
Stephen Hemmingerae665a52006-12-05 10:10:22 -08003489 addr_width = addrp_width - serv_width - 1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003490
3491 if (netid_width)
3492 printf("%-*s ", netid_width, "Netid");
3493 if (state_width)
3494 printf("%-*s ", state_width, "State");
3495 printf("%-6s %-6s ", "Recv-Q", "Send-Q");
3496
3497 printf("%*s:%-*s %*s:%-*s\n",
3498 addr_width, "Local Address", serv_width, "Port",
3499 addr_width, "Peer Address", serv_width, "Port");
3500
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003501 fflush(stdout);
3502
3503 if (current_filter.dbs & (1<<NETLINK_DB))
3504 netlink_show(&current_filter);
3505 if (current_filter.dbs & PACKET_DBM)
3506 packet_show(&current_filter);
3507 if (current_filter.dbs & UNIX_DBM)
3508 unix_show(&current_filter);
3509 if (current_filter.dbs & (1<<RAW_DB))
3510 raw_show(&current_filter);
3511 if (current_filter.dbs & (1<<UDP_DB))
3512 udp_show(&current_filter);
3513 if (current_filter.dbs & (1<<TCP_DB))
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00003514 tcp_show(&current_filter, IPPROTO_TCP);
shemminger351efcd2005-09-01 19:21:50 +00003515 if (current_filter.dbs & (1<<DCCP_DB))
Pavel Emelyanov3fe5b532012-10-25 03:18:31 +00003516 tcp_show(&current_filter, IPPROTO_DCCP);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00003517 return 0;
3518}