]>
git.proxmox.com Git - mirror_iproute2.git/blob - misc/ss.c
2 * ss.c "sockstat", socket statistics
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
17 #include <sys/ioctl.h>
18 #include <sys/socket.h>
20 #include <netinet/in.h>
24 #include <arpa/inet.h>
33 #include "libnetlink.h"
36 #include <linux/inet_diag.h>
37 #include <linux/tcp.h>
38 #include <net/tcp_states.h>
40 int resolve_hosts
= 0;
41 int resolve_services
= 1;
42 int preferred_family
= AF_UNSPEC
;
56 static const char *TCP_PROTO
= "tcp";
57 static const char *UDP_PROTO
= "udp";
58 static const char *RAW_PROTO
= "raw";
59 static const char *dg_proto
= NULL
;
75 #define PACKET_DBM ((1<<PACKET_DG_DB)|(1<<PACKET_R_DB))
76 #define UNIX_DBM ((1<<UNIX_DG_DB)|(1<<UNIX_ST_DB))
77 #define ALL_DB ((1<<MAX_DB)-1)
95 #define SS_ALL ((1<<SS_MAX)-1)
107 struct filter default_filter
= {
109 states
: SS_ALL
& ~((1<<SS_LISTEN
)|(1<<SS_CLOSE
)|(1<<SS_TIME_WAIT
)|(1<<SS_SYN_RECV
)),
110 families
: (1<<AF_INET
)|(1<<AF_INET6
),
113 struct filter current_filter
;
115 int generic_proc_open(char *env
, char *name
)
118 char *p
= getenv(env
);
120 p
= getenv("PROC_ROOT") ? : "/proc";
121 snprintf(store
, sizeof(store
)-1, "%s/%s", p
, name
);
124 return open(store
, O_RDONLY
);
127 int net_tcp_open(void)
129 return generic_proc_open("PROC_NET_TCP", "net/tcp");
132 int net_tcp6_open(void)
134 return generic_proc_open("PROC_NET_TCP6", "net/tcp6");
137 int net_udp_open(void)
139 return generic_proc_open("PROC_NET_UDP", "net/udp");
142 int net_udp6_open(void)
144 return generic_proc_open("PROC_NET_UDP6", "net/udp6");
147 int net_raw_open(void)
149 return generic_proc_open("PROC_NET_RAW", "net/raw");
152 int net_raw6_open(void)
154 return generic_proc_open("PROC_NET_RAW6", "net/raw6");
157 int net_unix_open(void)
159 return generic_proc_open("PROC_NET_UNIX", "net/unix");
162 int net_packet_open(void)
164 return generic_proc_open("PROC_NET_PACKET", "net/packet");
167 int net_netlink_open(void)
169 return generic_proc_open("PROC_NET_NETLINK", "net/netlink");
172 int slabinfo_open(void)
174 return generic_proc_open("PROC_SLABINFO", "slabinfo");
177 int net_sockstat_open(void)
179 return generic_proc_open("PROC_NET_SOCKSTAT", "net/sockstat");
182 int net_sockstat6_open(void)
184 return generic_proc_open("PROC_NET_SOCKSTAT6", "net/sockstat6");
187 int net_snmp_open(void)
189 return generic_proc_open("PROC_NET_SNMP", "net/snmp");
192 int net_netstat_open(void)
194 return generic_proc_open("PROC_NET_NETSTAT", "net/netstat");
197 int ephemeral_ports_open(void)
199 return generic_proc_open("PROC_IP_LOCAL_PORT_RANGE", "sys/net/ipv4/ip_local_port_range");
202 int find_users(int ino
, char *buf
, int buflen
)
216 sprintf(pattern
, "socket:[%d]", ino
);
217 pattern_len
= strlen(pattern
);
219 strncpy(name
, getenv("PROC_ROOT") ? : "/proc/", sizeof(name
)/2);
220 name
[sizeof(name
)/2] = 0;
221 if (strlen(name
) == 0 ||
222 name
[strlen(name
)-1] != '/')
224 nameoff
= strlen(name
);
225 if ((dir
= opendir(name
)) == NULL
)
228 while ((d
= readdir(dir
)) != NULL
) {
236 if (sscanf(d
->d_name
, "%d%c", &pid
, &crap
) != 1)
239 sprintf(name
+nameoff
, "%d/fd/", pid
);
241 if ((dir1
= opendir(name
)) == NULL
)
246 while ((d1
= readdir(dir1
)) != NULL
) {
250 if (sscanf(d1
->d_name
, "%d%c", &fd
, &crap
) != 1)
253 sprintf(name
+pos
, "%d", fd
);
254 n
= readlink(name
, lnk
, sizeof(lnk
)-1);
255 if (n
!= pattern_len
||
256 memcmp(lnk
, pattern
, n
))
259 if (ptr
-buf
>= buflen
-1)
262 if (process
[0] == 0) {
265 snprintf(tmp
, sizeof(tmp
), "%s/%d/stat",
266 getenv("PROC_ROOT") ? : "/proc", pid
);
267 if ((fp
= fopen(tmp
, "r")) != NULL
) {
268 fscanf(fp
, "%*d (%[^)])", process
);
273 snprintf(ptr
, buflen
-(ptr
-buf
), "(\"%s\",%d,%d),", process
, pid
, fd
);
286 /* Get stats from slab */
297 struct slabstat slabstat
;
299 static const char *slabstat_ids
[] =
308 int get_slabstat(struct slabstat
*s
)
314 memset(s
, 0, sizeof(*s
));
316 if ((fp
= fdopen(slabinfo_open(), "r")) == NULL
)
319 cnt
= sizeof(*s
)/sizeof(int);
321 fgets(buf
, sizeof(buf
), fp
);
322 while(fgets(buf
, sizeof(buf
), fp
) != NULL
) {
324 for (i
=0; i
<sizeof(slabstat_ids
)/sizeof(slabstat_ids
[0]); i
++) {
325 if (memcmp(buf
, slabstat_ids
[i
], strlen(slabstat_ids
[i
])) == 0) {
326 sscanf(buf
, "%*s%d", ((int *)s
) + i
);
339 static const char *sstate_name
[] = {
341 [TCP_ESTABLISHED
] = "ESTAB",
342 [TCP_SYN_SENT
] = "SYN-SENT",
343 [TCP_SYN_RECV
] = "SYN-RECV",
344 [TCP_FIN_WAIT1
] = "FIN-WAIT-1",
345 [TCP_FIN_WAIT2
] = "FIN-WAIT-2",
346 [TCP_TIME_WAIT
] = "TIME-WAIT",
347 [TCP_CLOSE
] = "UNCONN",
348 [TCP_CLOSE_WAIT
] = "CLOSE-WAIT",
349 [TCP_LAST_ACK
] = "LAST-ACK",
350 [TCP_LISTEN
] = "LISTEN",
351 [TCP_CLOSING
] = "CLOSING",
354 static const char *sstate_namel
[] = {
356 [TCP_ESTABLISHED
] = "established",
357 [TCP_SYN_SENT
] = "syn-sent",
358 [TCP_SYN_RECV
] = "syn-recv",
359 [TCP_FIN_WAIT1
] = "fin-wait-1",
360 [TCP_FIN_WAIT2
] = "fin-wait-2",
361 [TCP_TIME_WAIT
] = "time-wait",
362 [TCP_CLOSE
] = "unconnected",
363 [TCP_CLOSE_WAIT
] = "close-wait",
364 [TCP_LAST_ACK
] = "last-ack",
365 [TCP_LISTEN
] = "listening",
366 [TCP_CLOSING
] = "closing",
384 unsigned long long sk
;
385 int rto
, ato
, qack
, cwnd
, ssthresh
;
388 static const char *tmr_name
[] = {
397 const char *print_ms_timer(int timeout
)
400 int secs
, msecs
, minutes
;
406 msecs
= timeout
%1000;
410 snprintf(buf
, sizeof(buf
)-16, "%dmin", minutes
);
417 sprintf(buf
+strlen(buf
), "%d%s", secs
, msecs
? "." : "sec");
420 sprintf(buf
+strlen(buf
), "%03dms", msecs
);
424 const char *print_hz_timer(int timeout
)
427 return print_ms_timer(((timeout
*1000) + hz
-1)/hz
);
438 struct scache
*rlist
;
440 void init_service_resolver(void)
443 FILE *fp
= popen("/usr/sbin/rpcinfo -p 2>/dev/null", "r");
445 fgets(buf
, sizeof(buf
), fp
);
446 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
447 unsigned int progn
, port
;
448 char proto
[128], prog
[128];
449 if (sscanf(buf
, "%u %*d %s %u %s", &progn
, proto
,
450 &port
, prog
+4) == 4) {
451 struct scache
*c
= malloc(sizeof(*c
));
454 memcpy(prog
, "rpc.", 4);
455 c
->name
= strdup(prog
);
456 if (strcmp(proto
, TCP_PROTO
) == 0)
457 c
->proto
= TCP_PROTO
;
458 else if (strcmp(proto
, UDP_PROTO
) == 0)
459 c
->proto
= UDP_PROTO
;
470 static int ip_local_port_min
, ip_local_port_max
;
472 /* Even do not try default linux ephemeral port ranges:
473 * default /etc/services contains so much of useless crap
474 * wouldbe "allocated" to this area that resolution
475 * is really harmful. I shrug each time when seeing
476 * "socks" or "cfinger" in dumps.
478 static int is_ephemeral(int port
)
480 if (!ip_local_port_min
) {
481 FILE *f
= fdopen(ephemeral_ports_open(), "r");
484 &ip_local_port_min
, &ip_local_port_max
);
487 ip_local_port_min
= 1024;
488 ip_local_port_max
= 4999;
492 return (port
>= ip_local_port_min
&& port
<= ip_local_port_max
);
496 const char *__resolve_service(int port
)
500 for (c
= rlist
; c
; c
= c
->next
) {
501 if (c
->port
== port
&& c
->proto
== dg_proto
)
505 if (!is_ephemeral(port
)) {
512 se
= getservbyport(htons(port
), dg_proto
);
521 const char *resolve_service(int port
)
523 static char buf
[128];
524 static struct scache cache
[256];
532 if (resolve_services
) {
533 if (dg_proto
== RAW_PROTO
) {
534 return inet_proto_n2a(port
, buf
, sizeof(buf
));
538 int hash
= (port
^(((unsigned long)dg_proto
)>>2))&255;
540 for (c
= &cache
[hash
]; c
; c
= c
->next
) {
541 if (c
->port
== port
&&
542 c
->proto
== dg_proto
) {
549 if ((res
= __resolve_service(port
)) != NULL
) {
550 if ((c
= malloc(sizeof(*c
))) == NULL
)
561 c
->name
= strdup(res
);
562 c
->next
= cache
[hash
].next
;
563 cache
[hash
].next
= c
;
571 sprintf(buf
, "%u", port
);
575 void formatted_print(const inet_prefix
*a
, int port
)
578 const char *ap
= buf
;
581 est_len
= addr_width
;
583 if (a
->family
== AF_INET
) {
584 if (a
->data
[0] == 0) {
588 ap
= format_host(AF_INET
, 4, a
->data
, buf
, sizeof(buf
));
591 ap
= format_host(a
->family
, 16, a
->data
, buf
, sizeof(buf
));
592 est_len
= strlen(ap
);
593 if (est_len
<= addr_width
)
594 est_len
= addr_width
;
596 est_len
= addr_width
+ ((est_len
-addr_width
+3)/4)*4;
598 printf("%*s:%-*s ", est_len
, ap
, serv_width
, resolve_service(port
));
605 struct aafilter
*next
;
608 int inet2_addr_match(const inet_prefix
*a
, const inet_prefix
*p
, int plen
)
610 if (!inet_addr_match(a
, p
, plen
))
613 /* Cursed "v4 mapped" addresses: v4 mapped socket matches
614 * pure IPv4 rule, but v4-mapped rule selects only v4-mapped
616 if (p
->family
== AF_INET
&& a
->family
== AF_INET6
) {
617 if (a
->data
[0] == 0 && a
->data
[1] == 0 &&
618 a
->data
[2] == htonl(0xffff)) {
619 inet_prefix tmp
= *a
;
620 tmp
.data
[0] = a
->data
[3];
621 return inet_addr_match(&tmp
, p
, plen
);
627 int unix_match(const inet_prefix
*a
, const inet_prefix
*p
)
629 char *addr
, *pattern
;
630 memcpy(&addr
, a
->data
, sizeof(addr
));
631 memcpy(&pattern
, p
->data
, sizeof(pattern
));
636 return !fnmatch(pattern
, addr
, 0);
639 int run_ssfilter(struct ssfilter
*f
, struct tcpstat
*s
)
644 static int low
, high
=65535;
646 if (s
->local
.family
== AF_UNIX
) {
648 memcpy(&p
, s
->local
.data
, sizeof(p
));
649 return p
== NULL
|| (p
[0] == '@' && strlen(p
) == 6 &&
650 strspn(p
+1, "0123456789abcdef") == 5);
652 if (s
->local
.family
== AF_PACKET
)
653 return s
->lport
== 0 && s
->local
.data
== 0;
654 if (s
->local
.family
== AF_NETLINK
)
658 FILE *fp
= fdopen(ephemeral_ports_open(), "r");
660 fscanf(fp
, "%d%d", &low
, &high
);
664 return s
->lport
>= low
&& s
->lport
<= high
;
668 struct aafilter
*a
= (void*)f
->pred
;
669 if (a
->addr
.family
== AF_UNIX
)
670 return unix_match(&s
->remote
, &a
->addr
);
671 if (a
->port
!= -1 && a
->port
!= s
->rport
)
673 if (a
->addr
.bitlen
) {
675 if (!inet2_addr_match(&s
->remote
, &a
->addr
, a
->addr
.bitlen
))
677 } while ((a
= a
->next
) != NULL
);
684 struct aafilter
*a
= (void*)f
->pred
;
685 if (a
->addr
.family
== AF_UNIX
)
686 return unix_match(&s
->local
, &a
->addr
);
687 if (a
->port
!= -1 && a
->port
!= s
->lport
)
689 if (a
->addr
.bitlen
) {
691 if (!inet2_addr_match(&s
->local
, &a
->addr
, a
->addr
.bitlen
))
693 } while ((a
= a
->next
) != NULL
);
700 struct aafilter
*a
= (void*)f
->pred
;
701 return s
->rport
>= a
->port
;
705 struct aafilter
*a
= (void*)f
->pred
;
706 return s
->rport
<= a
->port
;
710 struct aafilter
*a
= (void*)f
->pred
;
711 return s
->lport
>= a
->port
;
715 struct aafilter
*a
= (void*)f
->pred
;
716 return s
->lport
<= a
->port
;
719 /* Yup. It is recursion. Sorry. */
721 return run_ssfilter(f
->pred
, s
) && run_ssfilter(f
->post
, s
);
723 return run_ssfilter(f
->pred
, s
) || run_ssfilter(f
->post
, s
);
725 return !run_ssfilter(f
->pred
, s
);
731 /* Relocate external jumps by reloc. */
732 static void ssfilter_patch(char *a
, int len
, int reloc
)
735 struct inet_diag_bc_op
*op
= (struct inet_diag_bc_op
*)a
;
745 static int ssfilter_bytecompile(struct ssfilter
*f
, char **bytecode
)
750 if (!(*bytecode
=malloc(4))) abort();
751 ((struct inet_diag_bc_op
*)*bytecode
)[0] = (struct inet_diag_bc_op
){ INET_DIAG_BC_AUTO
, 4, 8 };
757 struct aafilter
*a
= (void*)f
->pred
;
760 int code
= (f
->type
== SSF_DCOND
? INET_DIAG_BC_D_COND
: INET_DIAG_BC_S_COND
);
763 for (b
=a
; b
; b
=b
->next
) {
764 len
+= 4 + sizeof(struct inet_diag_hostcond
);
765 if (a
->addr
.family
== AF_INET6
)
772 if (!(ptr
= malloc(len
))) abort();
774 for (b
=a
; b
; b
=b
->next
) {
775 struct inet_diag_bc_op
*op
= (struct inet_diag_bc_op
*)ptr
;
776 int alen
= (a
->addr
.family
== AF_INET6
? 16 : 4);
777 int oplen
= alen
+ 4 + sizeof(struct inet_diag_hostcond
);
778 struct inet_diag_hostcond
*cond
= (struct inet_diag_hostcond
*)(ptr
+4);
780 *op
= (struct inet_diag_bc_op
){ code
, oplen
, oplen
+4 };
781 cond
->family
= a
->addr
.family
;
782 cond
->port
= a
->port
;
783 cond
->prefix_len
= a
->addr
.bitlen
;
784 memcpy(cond
->addr
, a
->addr
.data
, alen
);
787 op
= (struct inet_diag_bc_op
*)ptr
;
788 *op
= (struct inet_diag_bc_op
){ INET_DIAG_BC_JMP
, 4, len
- (ptr
-*bytecode
)};
792 return ptr
- *bytecode
;
796 struct aafilter
*x
= (void*)f
->pred
;
797 if (!(*bytecode
=malloc(8))) abort();
798 ((struct inet_diag_bc_op
*)*bytecode
)[0] = (struct inet_diag_bc_op
){ INET_DIAG_BC_D_GE
, 8, 12 };
799 ((struct inet_diag_bc_op
*)*bytecode
)[1] = (struct inet_diag_bc_op
){ 0, 0, x
->port
};
804 struct aafilter
*x
= (void*)f
->pred
;
805 if (!(*bytecode
=malloc(8))) abort();
806 ((struct inet_diag_bc_op
*)*bytecode
)[0] = (struct inet_diag_bc_op
){ INET_DIAG_BC_D_LE
, 8, 12 };
807 ((struct inet_diag_bc_op
*)*bytecode
)[1] = (struct inet_diag_bc_op
){ 0, 0, x
->port
};
812 struct aafilter
*x
= (void*)f
->pred
;
813 if (!(*bytecode
=malloc(8))) abort();
814 ((struct inet_diag_bc_op
*)*bytecode
)[0] = (struct inet_diag_bc_op
){ INET_DIAG_BC_S_GE
, 8, 12 };
815 ((struct inet_diag_bc_op
*)*bytecode
)[1] = (struct inet_diag_bc_op
){ 0, 0, x
->port
};
820 struct aafilter
*x
= (void*)f
->pred
;
821 if (!(*bytecode
=malloc(8))) abort();
822 ((struct inet_diag_bc_op
*)*bytecode
)[0] = (struct inet_diag_bc_op
){ INET_DIAG_BC_S_LE
, 8, 12 };
823 ((struct inet_diag_bc_op
*)*bytecode
)[1] = (struct inet_diag_bc_op
){ 0, 0, x
->port
};
829 char *a1
, *a2
, *a
, l1
, l2
;
830 l1
= ssfilter_bytecompile(f
->pred
, &a1
);
831 l2
= ssfilter_bytecompile(f
->post
, &a2
);
832 if (!(a
= malloc(l1
+l2
))) abort();
834 memcpy(a
+l1
, a2
, l2
);
836 ssfilter_patch(a
, l1
, l2
);
842 char *a1
, *a2
, *a
, l1
, l2
;
843 l1
= ssfilter_bytecompile(f
->pred
, &a1
);
844 l2
= ssfilter_bytecompile(f
->post
, &a2
);
845 if (!(a
= malloc(l1
+l2
+4))) abort();
847 memcpy(a
+l1
+4, a2
, l2
);
849 *(struct inet_diag_bc_op
*)(a
+l1
) = (struct inet_diag_bc_op
){ INET_DIAG_BC_JMP
, 4, l2
+4 };
856 l1
= ssfilter_bytecompile(f
->pred
, &a1
);
857 if (!(a
= malloc(l1
+4))) abort();
860 *(struct inet_diag_bc_op
*)(a
+l1
) = (struct inet_diag_bc_op
){ INET_DIAG_BC_JMP
, 4, 8 };
869 static int remember_he(struct aafilter
*a
, struct hostent
*he
)
871 char **ptr
= he
->h_addr_list
;
875 if (he
->h_addrtype
== AF_INET
)
877 else if (he
->h_addrtype
== AF_INET6
)
883 struct aafilter
*b
= a
;
884 if (a
->addr
.bitlen
) {
885 if ((b
= malloc(sizeof(*b
))) == NULL
)
891 memcpy(b
->addr
.data
, *ptr
, len
);
892 b
->addr
.bytelen
= len
;
893 b
->addr
.bitlen
= len
*8;
894 b
->addr
.family
= he
->h_addrtype
;
901 static int get_dns_host(struct aafilter
*a
, const char *addr
, int fam
)
912 he
= gethostbyname2(addr
, fam
== AF_UNSPEC
? AF_INET
: fam
);
914 cnt
= remember_he(a
, he
);
915 if (fam
== AF_UNSPEC
) {
916 he
= gethostbyname2(addr
, AF_INET6
);
918 cnt
+= remember_he(a
, he
);
923 static int xll_initted
= 0;
925 static void xll_init(void)
927 struct rtnl_handle rth
;
934 static const char *xll_index_to_name(int index
)
938 return ll_index_to_name(index
);
941 static int xll_name_to_index(const char *dev
)
945 return ll_name_to_index(dev
);
948 void *parse_hostcond(char *addr
)
952 struct aafilter
*res
;
953 int fam
= preferred_family
;
955 memset(&a
, 0, sizeof(a
));
958 if (fam
== AF_UNIX
|| strncmp(addr
, "unix:", 5) == 0) {
960 a
.addr
.family
= AF_UNIX
;
961 if (strncmp(addr
, "unix:", 5) == 0)
964 a
.addr
.bitlen
= 8*strlen(p
);
965 memcpy(a
.addr
.data
, &p
, sizeof(p
));
969 if (fam
== AF_PACKET
|| strncmp(addr
, "link:", 5) == 0) {
970 a
.addr
.family
= AF_PACKET
;
972 if (strncmp(addr
, "link:", 5) == 0)
974 port
= strchr(addr
, ':');
977 if (port
[1] && strcmp(port
+1, "*")) {
978 if (get_integer(&a
.port
, port
+1, 0)) {
979 if ((a
.port
= xll_name_to_index(port
+1)) <= 0)
984 if (addr
[0] && strcmp(addr
, "*")) {
987 if (ll_proto_a2n(&tmp
, addr
))
989 a
.addr
.data
[0] = ntohs(tmp
);
994 if (fam
== AF_NETLINK
|| strncmp(addr
, "netlink:", 8) == 0) {
995 a
.addr
.family
= AF_NETLINK
;
997 if (strncmp(addr
, "netlink:", 8) == 0)
999 port
= strchr(addr
, ':');
1002 if (port
[1] && strcmp(port
+1, "*")) {
1003 if (get_integer(&a
.port
, port
+1, 0)) {
1004 if (strcmp(port
+1, "kernel") == 0)
1011 if (addr
[0] && strcmp(addr
, "*")) {
1013 if (get_u32(a
.addr
.data
, addr
, 0)) {
1014 if (strcmp(addr
, "rtnl") == 0)
1016 else if (strcmp(addr
, "fw") == 0)
1018 else if (strcmp(addr
, "tcpdiag") == 0)
1027 if (strncmp(addr
, "inet:", 5) == 0) {
1030 } else if (strncmp(addr
, "inet6:", 6) == 0) {
1035 /* URL-like literal [] */
1036 if (addr
[0] == '[') {
1038 if ((port
= strchr(addr
, ']')) == NULL
)
1041 } else if (addr
[0] == '*') {
1044 port
= strrchr(strchr(addr
, '/') ? : addr
, ':');
1046 if (port
&& *port
) {
1050 if (*port
&& *port
!= '*') {
1051 if (get_integer(&a
.port
, port
, 0)) {
1052 struct servent
*se1
= NULL
;
1053 struct servent
*se2
= NULL
;
1054 if (current_filter
.dbs
&(1<<UDP_DB
))
1055 se1
= getservbyname(port
, UDP_PROTO
);
1056 if (current_filter
.dbs
&(1<<TCP_DB
))
1057 se2
= getservbyname(port
, TCP_PROTO
);
1058 if (se1
&& se2
&& se1
->s_port
!= se2
->s_port
) {
1059 fprintf(stderr
, "Error: ambiguous port \"%s\".\n", port
);
1065 a
.port
= ntohs(se1
->s_port
);
1068 for (s
= rlist
; s
; s
= s
->next
) {
1069 if ((s
->proto
== UDP_PROTO
&&
1070 (current_filter
.dbs
&(1<<UDP_DB
))) ||
1071 (s
->proto
== TCP_PROTO
&&
1072 (current_filter
.dbs
&(1<<TCP_DB
)))) {
1073 if (s
->name
&& strcmp(s
->name
, port
) == 0) {
1074 if (a
.port
> 0 && a
.port
!= s
->port
) {
1075 fprintf(stderr
, "Error: ambiguous port \"%s\".\n", port
);
1083 fprintf(stderr
, "Error: \"%s\" does not look like a port.\n", port
);
1090 if (addr
&& *addr
&& *addr
!= '*') {
1091 if (get_prefix_1(&a
.addr
, addr
, fam
)) {
1092 if (get_dns_host(&a
, addr
, fam
)) {
1093 fprintf(stderr
, "Error: an inet prefix is expected rather than \"%s\".\n", addr
);
1100 res
= malloc(sizeof(*res
));
1102 memcpy(res
, &a
, sizeof(a
));
1106 static int tcp_show_line(char *line
, struct filter
*f
, int family
)
1109 char *loc
, *rem
, *data
;
1114 if ((p
= strchr(line
, ':')) == NULL
)
1118 if ((p
= strchr(loc
, ':')) == NULL
)
1123 if ((p
= strchr(rem
, ':')) == NULL
)
1129 int state
= (data
[1] >= 'A') ? (data
[1] - 'A' + 10) : (data
[1] - '0');
1131 if (!(f
->states
& (1<<state
)))
1135 s
.local
.family
= s
.remote
.family
= family
;
1136 if (family
== AF_INET
) {
1137 sscanf(loc
, "%x:%x", s
.local
.data
, (unsigned*)&s
.lport
);
1138 sscanf(rem
, "%x:%x", s
.remote
.data
, (unsigned*)&s
.rport
);
1139 s
.local
.bytelen
= s
.remote
.bytelen
= 4;
1141 sscanf(loc
, "%08x%08x%08x%08x:%x",
1147 sscanf(rem
, "%08x%08x%08x%08x:%x",
1153 s
.local
.bytelen
= s
.remote
.bytelen
= 16;
1156 if (f
->f
&& run_ssfilter(f
->f
, &s
) == 0)
1160 n
= sscanf(data
, "%x %x:%x %x:%x %x %d %d %d %d %llx %d %d %d %d %d %[^\n]\n",
1161 &s
.state
, &s
.wq
, &s
.rq
,
1162 &s
.timer
, &s
.timeout
, &s
.retrs
, &s
.uid
, &s
.probes
, &s
.ino
,
1163 &s
.refcnt
, &s
.sk
, &s
.rto
, &s
.ato
, &s
.qack
,
1164 &s
.cwnd
, &s
.ssthresh
, opt
);
1177 printf("%-*s ", netid_width
, "tcp");
1179 printf("%-*s ", state_width
, sstate_name
[s
.state
]);
1181 printf("%-6d %-6d ", s
.rq
, s
.wq
);
1183 formatted_print(&s
.local
, s
.lport
);
1184 formatted_print(&s
.remote
, s
.rport
);
1190 printf(" timer:(%s,%s,%d)",
1192 print_hz_timer(s
.timeout
),
1193 s
.timer
!= 1 ? s
.probes
: s
.retrs
);
1197 if (s
.rto
&& s
.rto
!= 3*get_hz())
1198 printf(" rto:%g", (double)s
.rto
/get_hz());
1200 printf(" ato:%g", (double)s
.ato
/get_hz());
1202 printf(" cwnd:%d", s
.cwnd
);
1203 if (s
.ssthresh
!= -1)
1204 printf(" ssthresh:%d", s
.ssthresh
);
1206 printf(" qack:%d", s
.qack
/2);
1212 if (find_users(s
.ino
, ubuf
, sizeof(ubuf
)) > 0)
1213 printf(" users:(%s)", ubuf
);
1217 printf(" uid:%u", (unsigned)s
.uid
);
1218 printf(" ino:%u", (unsigned)s
.ino
);
1219 printf(" sk:%llx", s
.sk
);
1221 printf(" opt:\"%s\"", opt
);
1228 static int generic_record_read(int fd
, char *buf
, int bufsize
,
1229 int (*worker
)(char*, struct filter
*, int),
1230 struct filter
*f
, int fam
)
1237 /* Load the first chunk and calculate record length from it. */
1238 n
= read(fd
, buf
, bufsize
);
1241 /* I _know_ that this is wrong, do not remind. :-)
1242 * But this works nowadays. */
1245 p
= memchr(buf
, '\n', n
);
1246 if (p
== NULL
|| (p
-buf
) >= n
)
1247 goto outwrongformat
;
1248 recsize
= (p
-buf
)+1;
1252 while ((p
+recsize
) - buf
<= n
) {
1253 if (p
[recsize
-1] != '\n')
1254 goto outwrongformat
;
1256 if (worker(p
, f
, fam
) < 0)
1261 int remains
= (buf
+bufsize
) - p
;
1262 memcpy(buf
, p
, remains
);
1264 n
= read(fd
, p
, (buf
+bufsize
) - p
);
1267 if (n
< (buf
+bufsize
) - p
) {
1271 goto outwrongformat
;
1279 goto outwrongformat
;
1292 static char *sprint_bw(char *buf
, double bw
)
1295 sprintf(buf
,"%.1fM", bw
/ 1000000.);
1296 else if (bw
> 1000.)
1297 sprintf(buf
,"%.1fK", bw
/ 1000.);
1299 sprintf(buf
, "%g", bw
);
1304 static void tcp_show_info(const struct nlmsghdr
*nlh
, struct inet_diag_msg
*r
)
1306 struct rtattr
* tb
[INET_DIAG_MAX
+1];
1310 parse_rtattr(tb
, INET_DIAG_MAX
, (struct rtattr
*)(r
+1),
1311 nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*r
)));
1313 if (tb
[INET_DIAG_MEMINFO
]) {
1314 const struct inet_diag_meminfo
*minfo
1315 = RTA_DATA(tb
[INET_DIAG_MEMINFO
]);
1316 printf(" mem:(r%u,w%u,f%u,t%u)",
1323 if (tb
[INET_DIAG_INFO
]) {
1324 struct tcp_info
*info
;
1325 int len
= RTA_PAYLOAD(tb
[INET_DIAG_INFO
]);
1327 /* workaround for older kernels with less fields */
1328 if (len
< sizeof(*info
)) {
1329 info
= alloca(sizeof(*info
));
1330 memset(info
, 0, sizeof(*info
));
1331 memcpy(info
, RTA_DATA(tb
[INET_DIAG_INFO
]), len
);
1333 info
= RTA_DATA(tb
[INET_DIAG_INFO
]);
1336 if (info
->tcpi_options
& TCPI_OPT_TIMESTAMPS
)
1338 if (info
->tcpi_options
& TCPI_OPT_SACK
)
1340 if (info
->tcpi_options
& TCPI_OPT_ECN
)
1344 if (tb
[INET_DIAG_CONG
])
1345 printf("%s", (char *) RTA_DATA(tb
[INET_DIAG_CONG
]));
1347 if (info
->tcpi_options
& TCPI_OPT_WSCALE
)
1348 printf(" wscale:%d,%d", info
->tcpi_snd_wscale
,
1349 info
->tcpi_rcv_wscale
);
1350 if (info
->tcpi_rto
&& info
->tcpi_rto
!= 3000000)
1351 printf(" rto:%g", (double)info
->tcpi_rto
/1000);
1353 printf(" rtt:%g/%g", (double)info
->tcpi_rtt
/1000,
1354 (double)info
->tcpi_rttvar
/1000);
1356 printf(" ato:%g", (double)info
->tcpi_ato
/1000);
1357 if (info
->tcpi_snd_cwnd
!= 2)
1358 printf(" cwnd:%d", info
->tcpi_snd_cwnd
);
1359 if (info
->tcpi_snd_ssthresh
< 0xFFFF)
1360 printf(" ssthresh:%d", info
->tcpi_snd_ssthresh
);
1362 rtt
= (double) info
->tcpi_rtt
;
1363 if (tb
[INET_DIAG_VEGASINFO
]) {
1364 const struct tcpvegas_info
*vinfo
1365 = RTA_DATA(tb
[INET_DIAG_VEGASINFO
]);
1367 if (vinfo
->tcpv_enabled
&&
1368 vinfo
->tcpv_rtt
&& vinfo
->tcpv_rtt
!= 0x7fffffff)
1369 rtt
= vinfo
->tcpv_rtt
;
1372 if (rtt
> 0 && info
->tcpi_snd_mss
&& info
->tcpi_snd_cwnd
) {
1373 printf(" send %sbps",
1374 sprint_bw(b1
, (double) info
->tcpi_snd_cwnd
*
1375 (double) info
->tcpi_snd_mss
* 8000000.
1379 if (info
->tcpi_rcv_rtt
)
1380 printf(" rcv_rtt:%g", (double) info
->tcpi_rcv_rtt
/1000);
1381 if (info
->tcpi_rcv_space
)
1382 printf(" rcv_space:%d", info
->tcpi_rcv_space
);
1387 int tcp_show_sock(struct nlmsghdr
*nlh
, struct filter
*f
)
1389 struct inet_diag_msg
*r
= NLMSG_DATA(nlh
);
1392 s
.state
= r
->idiag_state
;
1393 s
.local
.family
= s
.remote
.family
= r
->idiag_family
;
1394 s
.lport
= ntohs(r
->id
.idiag_sport
);
1395 s
.rport
= ntohs(r
->id
.idiag_dport
);
1396 if (s
.local
.family
== AF_INET
) {
1397 s
.local
.bytelen
= s
.remote
.bytelen
= 4;
1399 s
.local
.bytelen
= s
.remote
.bytelen
= 16;
1401 memcpy(s
.local
.data
, r
->id
.idiag_src
, s
.local
.bytelen
);
1402 memcpy(s
.remote
.data
, r
->id
.idiag_dst
, s
.local
.bytelen
);
1404 if (f
&& f
->f
&& run_ssfilter(f
->f
, &s
) == 0)
1408 printf("%-*s ", netid_width
, "tcp");
1410 printf("%-*s ", state_width
, sstate_name
[s
.state
]);
1412 printf("%-6d %-6d ", r
->idiag_rqueue
, r
->idiag_wqueue
);
1414 formatted_print(&s
.local
, s
.lport
);
1415 formatted_print(&s
.remote
, s
.rport
);
1418 if (r
->idiag_timer
) {
1419 if (r
->idiag_timer
> 4)
1421 printf(" timer:(%s,%s,%d)",
1422 tmr_name
[r
->idiag_timer
],
1423 print_ms_timer(r
->idiag_expires
),
1429 if (find_users(r
->idiag_inode
, ubuf
, sizeof(ubuf
)) > 0)
1430 printf(" users:(%s)", ubuf
);
1434 printf(" uid:%u", (unsigned)r
->idiag_uid
);
1435 printf(" ino:%u", (unsigned)r
->idiag_inode
);
1436 printf(" sk:%08x", r
->id
.idiag_cookie
[0]);
1437 if (r
->id
.idiag_cookie
[1] != 0)
1438 printf("%08x", r
->id
.idiag_cookie
[1]);
1440 if (show_mem
|| show_tcpinfo
) {
1442 tcp_show_info(nlh
, r
);
1450 int tcp_show_netlink(struct filter
*f
, FILE *dump_fp
, int socktype
)
1453 struct sockaddr_nl nladdr
;
1455 struct nlmsghdr nlh
;
1456 struct inet_diag_req r
;
1463 struct iovec iov
[3];
1465 if ((fd
= socket(AF_NETLINK
, SOCK_RAW
, NETLINK_INET_DIAG
)) < 0)
1468 memset(&nladdr
, 0, sizeof(nladdr
));
1469 nladdr
.nl_family
= AF_NETLINK
;
1471 req
.nlh
.nlmsg_len
= sizeof(req
);
1472 req
.nlh
.nlmsg_type
= socktype
;
1473 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
|NLM_F_MATCH
|NLM_F_REQUEST
;
1474 req
.nlh
.nlmsg_pid
= 0;
1475 req
.nlh
.nlmsg_seq
= 123456;
1476 memset(&req
.r
, 0, sizeof(req
.r
));
1477 req
.r
.idiag_family
= AF_INET
;
1478 req
.r
.idiag_states
= f
->states
;
1480 req
.r
.idiag_ext
|= (1<<(INET_DIAG_MEMINFO
-1));
1483 req
.r
.idiag_ext
|= (1<<(INET_DIAG_INFO
-1));
1484 req
.r
.idiag_ext
|= (1<<(INET_DIAG_VEGASINFO
-1));
1485 req
.r
.idiag_ext
|= (1<<(INET_DIAG_CONG
-1));
1488 iov
[0] = (struct iovec
){
1490 .iov_len
= sizeof(req
)
1493 bclen
= ssfilter_bytecompile(f
->f
, &bc
);
1494 rta
.rta_type
= INET_DIAG_REQ_BYTECODE
;
1495 rta
.rta_len
= RTA_LENGTH(bclen
);
1496 iov
[1] = (struct iovec
){ &rta
, sizeof(rta
) };
1497 iov
[2] = (struct iovec
){ bc
, bclen
};
1498 req
.nlh
.nlmsg_len
+= RTA_LENGTH(bclen
);
1501 msg
= (struct msghdr
) {
1502 .msg_name
= (void*)&nladdr
,
1503 .msg_namelen
= sizeof(nladdr
),
1505 .msg_iovlen
= f
->f
? 3 : 1,
1508 if (sendmsg(fd
, &msg
, 0) < 0)
1511 iov
[0] = (struct iovec
){
1513 .iov_len
= sizeof(buf
)
1520 msg
= (struct msghdr
) {
1521 (void*)&nladdr
, sizeof(nladdr
),
1527 status
= recvmsg(fd
, &msg
, 0);
1536 fprintf(stderr
, "EOF on netlink\n");
1541 fwrite(buf
, 1, NLMSG_ALIGN(status
), dump_fp
);
1543 h
= (struct nlmsghdr
*)buf
;
1544 while (NLMSG_OK(h
, status
)) {
1547 if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
1548 h
->nlmsg_seq
!= 123456)
1551 if (h
->nlmsg_type
== NLMSG_DONE
)
1553 if (h
->nlmsg_type
== NLMSG_ERROR
) {
1554 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
1555 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
1556 fprintf(stderr
, "ERROR truncated\n");
1558 errno
= -err
->error
;
1559 perror("TCPDIAG answers");
1564 err
= tcp_show_sock(h
, NULL
);
1570 h
= NLMSG_NEXT(h
, status
);
1572 if (msg
.msg_flags
& MSG_TRUNC
) {
1573 fprintf(stderr
, "Message truncated\n");
1577 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
1584 int tcp_show_netlink_file(struct filter
*f
)
1589 if ((fp
= fopen(getenv("TCPDIAG_FILE"), "r")) == NULL
) {
1590 perror("fopen($TCPDIAG_FILE)");
1596 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
1598 status
= fread(buf
, 1, sizeof(*h
), fp
);
1600 perror("Reading header from $TCPDIAG_FILE");
1603 if (status
!= sizeof(*h
)) {
1604 perror("Unexpected EOF reading $TCPDIAG_FILE");
1608 status
= fread(h
+1, 1, NLMSG_ALIGN(h
->nlmsg_len
-sizeof(*h
)), fp
);
1611 perror("Reading $TCPDIAG_FILE");
1614 if (status
+ sizeof(*h
) < h
->nlmsg_len
) {
1615 perror("Unexpected EOF reading $TCPDIAG_FILE");
1619 /* The only legal exit point */
1620 if (h
->nlmsg_type
== NLMSG_DONE
)
1623 if (h
->nlmsg_type
== NLMSG_ERROR
) {
1624 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
1625 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
1626 fprintf(stderr
, "ERROR truncated\n");
1628 errno
= -err
->error
;
1629 perror("TCPDIAG answered");
1634 err
= tcp_show_sock(h
, f
);
1640 int tcp_show(struct filter
*f
, int socktype
)
1644 int bufsize
= 64*1024;
1646 dg_proto
= TCP_PROTO
;
1648 if (getenv("TCPDIAG_FILE"))
1649 return tcp_show_netlink_file(f
);
1651 if (!getenv("PROC_NET_TCP") && !getenv("PROC_ROOT")
1652 && tcp_show_netlink(f
, NULL
, socktype
) == 0)
1655 /* Sigh... We have to parse /proc/net/tcp... */
1657 /* Estimate amount of sockets and try to allocate
1658 * huge buffer to read all the table at one read.
1659 * Limit it by 16MB though. The assumption is: as soon as
1660 * kernel was able to hold information about N connections,
1661 * it is able to give us some memory for snapshot.
1664 int guess
= slabstat
.socks
+slabstat
.tcp_syns
;
1665 if (f
->states
&(1<<SS_TIME_WAIT
))
1666 guess
+= slabstat
.tcp_tws
;
1667 if (guess
> (16*1024*1024)/128)
1668 guess
= (16*1024*1024)/128;
1670 if (guess
> bufsize
)
1673 while (bufsize
>= 64*1024) {
1674 if ((buf
= malloc(bufsize
)) != NULL
)
1683 if (f
->families
& (1<<AF_INET
)) {
1684 if ((fd
= net_tcp_open()) < 0)
1686 if (generic_record_read(fd
, buf
, bufsize
, tcp_show_line
, f
, AF_INET
))
1691 if ((f
->families
& (1<<AF_INET6
)) &&
1692 (fd
= net_tcp6_open()) >= 0) {
1693 if (generic_record_read(fd
, buf
, bufsize
, tcp_show_line
, f
, AF_INET6
))
1703 int saved_errno
= errno
;
1708 errno
= saved_errno
;
1714 int dgram_show_line(char *line
, struct filter
*f
, int family
)
1717 char *loc
, *rem
, *data
;
1722 if ((p
= strchr(line
, ':')) == NULL
)
1726 if ((p
= strchr(loc
, ':')) == NULL
)
1731 if ((p
= strchr(rem
, ':')) == NULL
)
1737 int state
= (data
[1] >= 'A') ? (data
[1] - 'A' + 10) : (data
[1] - '0');
1739 if (!(f
->states
& (1<<state
)))
1743 s
.local
.family
= s
.remote
.family
= family
;
1744 if (family
== AF_INET
) {
1745 sscanf(loc
, "%x:%x", s
.local
.data
, (unsigned*)&s
.lport
);
1746 sscanf(rem
, "%x:%x", s
.remote
.data
, (unsigned*)&s
.rport
);
1747 s
.local
.bytelen
= s
.remote
.bytelen
= 4;
1749 sscanf(loc
, "%08x%08x%08x%08x:%x",
1755 sscanf(rem
, "%08x%08x%08x%08x:%x",
1761 s
.local
.bytelen
= s
.remote
.bytelen
= 16;
1764 if (f
->f
&& run_ssfilter(f
->f
, &s
) == 0)
1768 n
= sscanf(data
, "%x %x:%x %*x:%*x %*x %d %*d %d %d %llx %[^\n]\n",
1769 &s
.state
, &s
.wq
, &s
.rq
,
1771 &s
.refcnt
, &s
.sk
, opt
);
1777 printf("%-*s ", netid_width
, dg_proto
);
1779 printf("%-*s ", state_width
, sstate_name
[s
.state
]);
1781 printf("%-6d %-6d ", s
.rq
, s
.wq
);
1783 formatted_print(&s
.local
, s
.lport
);
1784 formatted_print(&s
.remote
, s
.rport
);
1788 if (find_users(s
.ino
, ubuf
, sizeof(ubuf
)) > 0)
1789 printf(" users:(%s)", ubuf
);
1794 printf(" uid=%u", (unsigned)s
.uid
);
1795 printf(" ino=%u", (unsigned)s
.ino
);
1796 printf(" sk=%llx", s
.sk
);
1798 printf(" opt:\"%s\"", opt
);
1806 int udp_show(struct filter
*f
)
1810 int bufsize
= sizeof(buf
);
1812 dg_proto
= UDP_PROTO
;
1814 if (f
->families
&(1<<AF_INET
)) {
1815 if ((fd
= net_udp_open()) < 0)
1817 if (generic_record_read(fd
, buf
, bufsize
, dgram_show_line
, f
, AF_INET
))
1822 if ((f
->families
&(1<<AF_INET6
)) &&
1823 (fd
= net_udp6_open()) >= 0) {
1824 if (generic_record_read(fd
, buf
, bufsize
, dgram_show_line
, f
, AF_INET6
))
1832 int saved_errno
= errno
;
1835 errno
= saved_errno
;
1840 int raw_show(struct filter
*f
)
1844 int bufsize
= sizeof(buf
);
1846 dg_proto
= RAW_PROTO
;
1848 if (f
->families
&(1<<AF_INET
)) {
1849 if ((fd
= net_raw_open()) < 0)
1851 if (generic_record_read(fd
, buf
, bufsize
, dgram_show_line
, f
, AF_INET
))
1856 if ((f
->families
&(1<<AF_INET6
)) &&
1857 (fd
= net_raw6_open()) >= 0) {
1858 if (generic_record_read(fd
, buf
, bufsize
, dgram_show_line
, f
, AF_INET6
))
1866 int saved_errno
= errno
;
1869 errno
= saved_errno
;
1877 struct unixstat
*next
;
1889 int unix_state_map
[] = { SS_CLOSE
, SS_SYN_SENT
,
1890 SS_ESTABLISHED
, SS_CLOSING
};
1893 #define MAX_UNIX_REMEMBER (1024*1024/sizeof(struct unixstat))
1895 void unix_list_free(struct unixstat
*list
)
1898 struct unixstat
*s
= list
;
1906 void unix_list_print(struct unixstat
*list
, struct filter
*f
)
1911 for (s
= list
; s
; s
= s
->next
) {
1912 if (!(f
->states
& (1<<s
->state
)))
1914 if (s
->type
== SOCK_STREAM
&& !(f
->dbs
&(1<<UNIX_ST_DB
)))
1916 if (s
->type
== SOCK_DGRAM
&& !(f
->dbs
&(1<<UNIX_DG_DB
)))
1922 for (p
= list
; p
; p
= p
->next
) {
1923 if (s
->peer
== p
->ino
)
1929 peer
= p
->name
? : "*";
1935 tst
.local
.family
= AF_UNIX
;
1936 tst
.remote
.family
= AF_UNIX
;
1937 memcpy(tst
.local
.data
, &s
->name
, sizeof(s
->name
));
1938 if (strcmp(peer
, "*") == 0)
1939 memset(tst
.remote
.data
, 0, sizeof(peer
));
1941 memcpy(tst
.remote
.data
, &peer
, sizeof(peer
));
1942 if (run_ssfilter(f
->f
, &tst
) == 0)
1947 printf("%-*s ", netid_width
,
1948 s
->type
== SOCK_STREAM
? "u_str" : "u_dgr");
1950 printf("%-*s ", state_width
, sstate_name
[s
->state
]);
1951 printf("%-6d %-6d ", s
->rq
, s
->wq
);
1952 printf("%*s %-*d %*s %-*d",
1953 addr_width
, s
->name
? : "*", serv_width
, s
->ino
,
1954 addr_width
, peer
, serv_width
, s
->peer
);
1957 if (find_users(s
->ino
, ubuf
, sizeof(ubuf
)) > 0)
1958 printf(" users:(%s)", ubuf
);
1964 int unix_show(struct filter
*f
)
1971 struct unixstat
*list
= NULL
;
1973 if ((fp
= fdopen(net_unix_open(), "r")) == NULL
)
1975 fgets(buf
, sizeof(buf
)-1, fp
);
1977 if (memcmp(buf
, "Peer", 4) == 0)
1981 while (fgets(buf
, sizeof(buf
)-1, fp
)) {
1982 struct unixstat
*u
, **insp
;
1985 if (!(u
= malloc(sizeof(*u
))))
1989 if (sscanf(buf
, "%x: %x %x %x %x %x %d %s",
1990 &u
->peer
, &u
->rq
, &u
->wq
, &flags
, &u
->type
,
1991 &u
->state
, &u
->ino
, name
) < 8)
1994 if (flags
&(1<<16)) {
1995 u
->state
= SS_LISTEN
;
1997 u
->state
= unix_state_map
[u
->state
-1];
1998 if (u
->type
== SOCK_DGRAM
&&
1999 u
->state
== SS_CLOSE
&&
2001 u
->state
= SS_ESTABLISHED
;
2012 if (u
->type
< (*insp
)->type
||
2013 (u
->type
== (*insp
)->type
&&
2014 u
->ino
< (*insp
)->ino
))
2016 insp
= &(*insp
)->next
;
2022 if ((u
->name
= malloc(strlen(name
)+1)) == NULL
)
2024 strcpy(u
->name
, name
);
2026 if (++cnt
> MAX_UNIX_REMEMBER
) {
2027 unix_list_print(list
, f
);
2028 unix_list_free(list
);
2035 unix_list_print(list
, f
);
2036 unix_list_free(list
);
2045 int packet_show(struct filter
*f
)
2056 unsigned long long sk
;
2058 if (!(f
->states
& (1<<SS_CLOSE
)))
2061 if ((fp
= fdopen(net_packet_open(), "r")) == NULL
)
2063 fgets(buf
, sizeof(buf
)-1, fp
);
2065 while (fgets(buf
, sizeof(buf
)-1, fp
)) {
2066 sscanf(buf
, "%llx %*d %d %x %d %d %u %u %u",
2068 &type
, &prot
, &iface
, &state
,
2071 if (type
== SOCK_RAW
&& !(f
->dbs
&(1<<PACKET_R_DB
)))
2073 if (type
== SOCK_DGRAM
&& !(f
->dbs
&(1<<PACKET_DG_DB
)))
2077 tst
.local
.family
= AF_PACKET
;
2078 tst
.remote
.family
= AF_PACKET
;
2081 tst
.local
.data
[0] = prot
;
2082 tst
.remote
.data
[0] = 0;
2083 if (run_ssfilter(f
->f
, &tst
) == 0)
2088 printf("%-*s ", netid_width
,
2089 type
== SOCK_RAW
? "p_raw" : "p_dgr");
2091 printf("%-*s ", state_width
, "UNCONN");
2092 printf("%-6d %-6d ", rq
, 0);
2094 printf("%*s:", addr_width
, "*");
2097 printf("%*s:", addr_width
,
2098 ll_proto_n2a(htons(prot
), tb
, sizeof(tb
)));
2101 printf("%-*s ", serv_width
, "*");
2103 printf("%-*s ", serv_width
, xll_index_to_name(iface
));
2106 addr_width
, "", serv_width
, "");
2110 if (find_users(ino
, ubuf
, sizeof(ubuf
)) > 0)
2111 printf(" users:(%s)", ubuf
);
2114 printf(" ino=%u uid=%u sk=%llx", ino
, uid
, sk
);
2122 int netlink_show(struct filter
*f
)
2129 unsigned long long sk
, cb
;
2131 if (!(f
->states
& (1<<SS_CLOSE
)))
2134 if ((fp
= fdopen(net_netlink_open(), "r")) == NULL
)
2136 fgets(buf
, sizeof(buf
)-1, fp
);
2138 while (fgets(buf
, sizeof(buf
)-1, fp
)) {
2139 sscanf(buf
, "%llx %d %d %x %d %d %llx %d",
2141 &prot
, &pid
, &groups
, &rq
, &wq
, &cb
, &rc
);
2145 tst
.local
.family
= AF_NETLINK
;
2146 tst
.remote
.family
= AF_NETLINK
;
2149 tst
.local
.data
[0] = prot
;
2150 tst
.remote
.data
[0] = 0;
2151 if (run_ssfilter(f
->f
, &tst
) == 0)
2156 printf("%-*s ", netid_width
, "nl");
2158 printf("%-*s ", state_width
, "UNCONN");
2159 printf("%-6d %-6d ", rq
, wq
);
2160 if (resolve_services
&& prot
== 0)
2161 printf("%*s:", addr_width
, "rtnl");
2162 else if (resolve_services
&& prot
== 3)
2163 printf("%*s:", addr_width
, "fw");
2164 else if (resolve_services
&& prot
== 4)
2165 printf("%*s:", addr_width
, "tcpdiag");
2167 printf("%*d:", addr_width
, prot
);
2169 printf("%-*s ", serv_width
, "*");
2170 } else if (resolve_services
) {
2174 printf("%-*s ", serv_width
, "kernel");
2175 } else if (pid
> 0) {
2178 sprintf(procname
, "%s/%d/stat",
2179 getenv("PROC_ROOT") ? : "/proc", pid
);
2180 if ((fp
= fopen(procname
, "r")) != NULL
) {
2181 if (fscanf(fp
, "%*d (%[^)])", procname
) == 1) {
2182 sprintf(procname
+strlen(procname
), "/%d", pid
);
2183 printf("%-*s ", serv_width
, procname
);
2190 printf("%-*d ", serv_width
, pid
);
2192 printf("%-*d ", serv_width
, pid
);
2195 addr_width
, "", serv_width
, "");
2198 printf(" sk=%llx cb=%llx groups=0x%08x", sk
, cb
, groups
);
2211 int get_snmp_int(char *proto
, char *key
, int *result
)
2215 int protolen
= strlen(proto
);
2216 int keylen
= strlen(key
);
2220 if ((fp
= fdopen(net_snmp_open(), "r")) == NULL
)
2223 while (fgets(buf
, sizeof(buf
), fp
) != NULL
) {
2226 if (memcmp(buf
, proto
, protolen
))
2228 while ((p
= strchr(p
, ' ')) != NULL
) {
2231 if (memcmp(p
, key
, keylen
) == 0 &&
2232 (p
[keylen
] == ' ' || p
[keylen
] == '\n'))
2235 if (fgets(buf
, sizeof(buf
), fp
) == NULL
)
2237 if (memcmp(buf
, proto
, protolen
))
2240 while ((p
= strchr(p
, ' ')) != NULL
) {
2243 sscanf(p
, "%d", result
);
2256 /* Get stats from sockstat */
2277 static void get_sockstat_line(char *line
, struct sockstat
*s
)
2279 char id
[256], rem
[256];
2281 if (sscanf(line
, "%[^ ] %[^\n]\n", id
, rem
) != 2)
2284 if (strcmp(id
, "sockets:") == 0)
2285 sscanf(rem
, "%*s%d", &s
->socks
);
2286 else if (strcmp(id
, "UDP:") == 0)
2287 sscanf(rem
, "%*s%d", &s
->udp4
);
2288 else if (strcmp(id
, "UDP6:") == 0)
2289 sscanf(rem
, "%*s%d", &s
->udp6
);
2290 else if (strcmp(id
, "RAW:") == 0)
2291 sscanf(rem
, "%*s%d", &s
->raw4
);
2292 else if (strcmp(id
, "RAW6:") == 0)
2293 sscanf(rem
, "%*s%d", &s
->raw6
);
2294 else if (strcmp(id
, "TCP6:") == 0)
2295 sscanf(rem
, "%*s%d", &s
->tcp6_hashed
);
2296 else if (strcmp(id
, "FRAG:") == 0)
2297 sscanf(rem
, "%*s%d%*s%d", &s
->frag4
, &s
->frag4_mem
);
2298 else if (strcmp(id
, "FRAG6:") == 0)
2299 sscanf(rem
, "%*s%d%*s%d", &s
->frag6
, &s
->frag6_mem
);
2300 else if (strcmp(id
, "TCP:") == 0)
2301 sscanf(rem
, "%*s%d%*s%d%*s%d%*s%d%*s%d",
2303 &s
->tcp_orphans
, &s
->tcp_tws
, &s
->tcp_total
, &s
->tcp_mem
);
2306 int get_sockstat(struct sockstat
*s
)
2311 memset(s
, 0, sizeof(*s
));
2313 if ((fp
= fdopen(net_sockstat_open(), "r")) == NULL
)
2315 while(fgets(buf
, sizeof(buf
), fp
) != NULL
)
2316 get_sockstat_line(buf
, s
);
2319 if ((fp
= fdopen(net_sockstat6_open(), "r")) == NULL
)
2321 while(fgets(buf
, sizeof(buf
), fp
) != NULL
)
2322 get_sockstat_line(buf
, s
);
2328 int print_summary(void)
2333 if (get_sockstat(&s
) < 0)
2334 perror("ss: get_sockstat");
2335 if (get_snmp_int("Tcp:", "CurrEstab", &sn
.tcp_estab
) < 0)
2336 perror("ss: get_snmpstat");
2338 printf("Total: %d (kernel %d)\n", s
.socks
, slabstat
.socks
);
2340 printf("TCP: %d (estab %d, closed %d, orphaned %d, synrecv %d, timewait %d/%d), ports %d\n",
2341 s
.tcp_total
+ slabstat
.tcp_syns
+ s
.tcp_tws
,
2343 s
.tcp_total
- (s
.tcp4_hashed
+s
.tcp6_hashed
-s
.tcp_tws
),
2346 s
.tcp_tws
, slabstat
.tcp_tws
,
2351 printf("Transport Total IP IPv6\n");
2352 printf("* %-9d %-9s %-9s\n", slabstat
.socks
, "-", "-");
2353 printf("RAW %-9d %-9d %-9d\n", s
.raw4
+s
.raw6
, s
.raw4
, s
.raw6
);
2354 printf("UDP %-9d %-9d %-9d\n", s
.udp4
+s
.udp6
, s
.udp4
, s
.udp6
);
2355 printf("TCP %-9d %-9d %-9d\n", s
.tcp4_hashed
+s
.tcp6_hashed
, s
.tcp4_hashed
, s
.tcp6_hashed
);
2356 printf("INET %-9d %-9d %-9d\n",
2357 s
.raw4
+s
.udp4
+s
.tcp4_hashed
+
2358 s
.raw6
+s
.udp6
+s
.tcp6_hashed
,
2359 s
.raw4
+s
.udp4
+s
.tcp4_hashed
,
2360 s
.raw6
+s
.udp6
+s
.tcp6_hashed
);
2361 printf("FRAG %-9d %-9d %-9d\n", s
.frag4
+s
.frag6
, s
.frag4
, s
.frag6
);
2369 static void usage(void) __attribute__((noreturn
));
2371 static void usage(void)
2374 "Usage: ss [ OPTIONS ]\n"
2375 " ss [ OPTIONS ] [ FILTER ]\n"
2376 " -h, --help this message\n"
2377 " -V, --version output version information\n"
2378 " -n, --numeric don't resolve service names\n"
2379 " -r, --resolve resolve host names\n"
2380 " -a, --all display all sockets\n"
2381 " -l, --listening display listening sockets\n"
2382 " -o, --options show timer information\n"
2383 " -e, --extended show detailed socket information\n"
2384 " -m, --memory show socket memory usage\n"
2385 " -p, --processes show process using socket\n"
2386 " -i, --info show internal TCP information\n"
2387 " -s, --summary show socket usage summary\n"
2389 " -4, --ipv4 display only IP version 4 sockets\n"
2390 " -6, --ipv6 display only IP version 6 sockets\n"
2391 " -0, --packet display PACKET sockets\n"
2392 " -t, --tcp display only TCP sockets\n"
2393 " -u, --udp display only UDP sockets\n"
2394 " -d, --dccp display only DCCP sockets\n"
2395 " -w, --raw display only RAW sockets\n"
2396 " -x, --unix display only Unix domain sockets\n"
2397 " -f, --family=FAMILY display sockets of type FAMILY\n"
2399 " -A, --query=QUERY\n"
2400 " QUERY := {all|inet|tcp|udp|raw|unix|packet|netlink}[,QUERY]\n"
2402 " -F, --filter=FILE read filter information from FILE\n"
2403 " FILTER := [ state TCP-STATE ] [ EXPRESSION ]\n"
2409 int scan_state(const char *state
)
2412 if (strcasecmp(state
, "close") == 0 ||
2413 strcasecmp(state
, "closed") == 0)
2414 return (1<<SS_CLOSE
);
2415 if (strcasecmp(state
, "syn-rcv") == 0)
2416 return (1<<SS_SYN_RECV
);
2417 if (strcasecmp(state
, "established") == 0)
2418 return (1<<SS_ESTABLISHED
);
2419 if (strcasecmp(state
, "all") == 0)
2421 if (strcasecmp(state
, "connected") == 0)
2422 return SS_ALL
& ~((1<<SS_CLOSE
)|(1<<SS_LISTEN
));
2423 if (strcasecmp(state
, "synchronized") == 0)
2424 return SS_ALL
& ~((1<<SS_CLOSE
)|(1<<SS_LISTEN
)|(1<<SS_SYN_SENT
));
2425 if (strcasecmp(state
, "bucket") == 0)
2426 return (1<<SS_SYN_RECV
)|(1<<SS_TIME_WAIT
);
2427 if (strcasecmp(state
, "big") == 0)
2428 return SS_ALL
& ~((1<<SS_SYN_RECV
)|(1<<SS_TIME_WAIT
));
2429 for (i
=0; i
<SS_MAX
; i
++) {
2430 if (strcasecmp(state
, sstate_namel
[i
]) == 0)
2436 static const struct option long_opts
[] = {
2437 { "numeric", 0, 0, 'n' },
2438 { "resolve", 0, 0, 'r' },
2439 { "options", 0, 0, 'o' },
2440 { "extended", 0, 0, 'e' },
2441 { "memory", 0, 0, 'm' },
2442 { "info", 0, 0, 'i' },
2443 { "processes", 0, 0, 'p' },
2444 { "dccp", 0, 0, 'd' },
2445 { "tcp", 0, 0, 't' },
2446 { "udp", 0, 0, 'u' },
2447 { "raw", 0, 0, 'w' },
2448 { "unix", 0, 0, 'x' },
2449 { "all", 0, 0, 'a' },
2450 { "listening", 0, 0, 'l' },
2451 { "ipv4", 0, 0, '4' },
2452 { "ipv6", 0, 0, '6' },
2453 { "packet", 0, 0, '0' },
2454 { "family", 1, 0, 'f' },
2455 { "socket", 1, 0, 'A' },
2456 { "summary", 0, 0, 's' },
2457 { "diag", 0, 0, 'D' },
2458 { "filter", 1, 0, 'F' },
2459 { "version", 0, 0, 'V' },
2460 { "help", 0, 0, 'h' },
2465 int main(int argc
, char *argv
[])
2471 const char *dump_tcpdiag
= NULL
;
2472 FILE *filter_fp
= NULL
;
2475 memset(¤t_filter
, 0, sizeof(current_filter
));
2477 current_filter
.states
= default_filter
.states
;
2479 while ((ch
= getopt_long(argc
, argv
, "dhaletuwxnro460spf:miA:D:F:vV",
2480 long_opts
, NULL
)) != EOF
) {
2483 resolve_services
= 0;
2505 current_filter
.dbs
|= (1<<DCCP_DB
);
2509 current_filter
.dbs
|= (1<<TCP_DB
);
2513 current_filter
.dbs
|= (1<<UDP_DB
);
2517 current_filter
.dbs
|= (1<<RAW_DB
);
2521 current_filter
.dbs
|= UNIX_DBM
;
2525 current_filter
.states
= SS_ALL
;
2528 current_filter
.states
= (1<<SS_LISTEN
);
2531 preferred_family
= AF_INET
;
2534 preferred_family
= AF_INET6
;
2537 preferred_family
= AF_PACKET
;
2540 if (strcmp(optarg
, "inet") == 0)
2541 preferred_family
= AF_INET
;
2542 else if (strcmp(optarg
, "inet6") == 0)
2543 preferred_family
= AF_INET6
;
2544 else if (strcmp(optarg
, "link") == 0)
2545 preferred_family
= AF_PACKET
;
2546 else if (strcmp(optarg
, "unix") == 0)
2547 preferred_family
= AF_UNIX
;
2548 else if (strcmp(optarg
, "netlink") == 0)
2549 preferred_family
= AF_NETLINK
;
2550 else if (strcmp(optarg
, "help") == 0)
2553 fprintf(stderr
, "ss: \"%s\" is invalid family\n", optarg
);
2561 current_filter
.dbs
= 0;
2567 if ((p1
= strchr(p
, ',')) != NULL
)
2569 if (strcmp(p
, "all") == 0) {
2570 current_filter
.dbs
= ALL_DB
;
2571 } else if (strcmp(p
, "inet") == 0) {
2572 current_filter
.dbs
|= (1<<TCP_DB
)|(1<<DCCP_DB
)|(1<<UDP_DB
)|(1<<RAW_DB
);
2573 } else if (strcmp(p
, "udp") == 0) {
2574 current_filter
.dbs
|= (1<<UDP_DB
);
2575 } else if (strcmp(p
, "dccp") == 0) {
2576 current_filter
.dbs
|= (1<<DCCP_DB
);
2577 } else if (strcmp(p
, "tcp") == 0) {
2578 current_filter
.dbs
|= (1<<TCP_DB
);
2579 } else if (strcmp(p
, "raw") == 0) {
2580 current_filter
.dbs
|= (1<<RAW_DB
);
2581 } else if (strcmp(p
, "unix") == 0) {
2582 current_filter
.dbs
|= UNIX_DBM
;
2583 } else if (strcasecmp(p
, "unix_stream") == 0 ||
2584 strcmp(p
, "u_str") == 0) {
2585 current_filter
.dbs
|= (1<<UNIX_ST_DB
);
2586 } else if (strcasecmp(p
, "unix_dgram") == 0 ||
2587 strcmp(p
, "u_dgr") == 0) {
2588 current_filter
.dbs
|= (1<<UNIX_DG_DB
);
2589 } else if (strcmp(p
, "packet") == 0) {
2590 current_filter
.dbs
|= PACKET_DBM
;
2591 } else if (strcmp(p
, "packet_raw") == 0 ||
2592 strcmp(p
, "p_raw") == 0) {
2593 current_filter
.dbs
|= (1<<PACKET_R_DB
);
2594 } else if (strcmp(p
, "packet_dgram") == 0 ||
2595 strcmp(p
, "p_dgr") == 0) {
2596 current_filter
.dbs
|= (1<<PACKET_DG_DB
);
2597 } else if (strcmp(p
, "netlink") == 0) {
2598 current_filter
.dbs
|= (1<<NETLINK_DB
);
2600 fprintf(stderr
, "ss: \"%s\" is illegal socket table id\n", p
);
2611 dump_tcpdiag
= optarg
;
2615 fprintf(stderr
, "More than one filter file\n");
2618 if (optarg
[0] == '-')
2621 filter_fp
= fopen(optarg
, "r");
2623 perror("fopen filter file");
2629 printf("ss utility, iproute2-ss%s\n", SNAPSHOT
);
2641 get_slabstat(&slabstat
);
2645 if (do_default
&& argc
== 0)
2650 current_filter
.dbs
= default_filter
.dbs
;
2652 if (preferred_family
== AF_UNSPEC
) {
2653 if (!(current_filter
.dbs
&~UNIX_DBM
))
2654 preferred_family
= AF_UNIX
;
2655 else if (!(current_filter
.dbs
&~PACKET_DBM
))
2656 preferred_family
= AF_PACKET
;
2657 else if (!(current_filter
.dbs
&~(1<<NETLINK_DB
)))
2658 preferred_family
= AF_NETLINK
;
2661 if (preferred_family
!= AF_UNSPEC
) {
2663 if (preferred_family
== AF_INET
||
2664 preferred_family
== AF_INET6
) {
2667 mask2
= (1<<UDP_DB
)|(1<<RAW_DB
);
2668 } else if (preferred_family
== AF_PACKET
) {
2670 } else if (preferred_family
== AF_UNIX
) {
2672 } else if (preferred_family
== AF_NETLINK
) {
2673 mask2
= (1<<NETLINK_DB
);
2679 current_filter
.dbs
= mask2
;
2681 current_filter
.dbs
&= mask2
;
2682 current_filter
.families
= (1<<preferred_family
);
2685 current_filter
.families
= ~0;
2687 current_filter
.families
= default_filter
.families
;
2689 if (current_filter
.dbs
== 0) {
2690 fprintf(stderr
, "ss: no socket tables to show with such filter.\n");
2693 if (current_filter
.families
== 0) {
2694 fprintf(stderr
, "ss: no families to show with such filter.\n");
2698 if (resolve_services
&& resolve_hosts
&&
2699 (current_filter
.dbs
&(UNIX_DBM
|(1<<TCP_DB
)|(1<<UDP_DB
)|(1<<DCCP_DB
))))
2700 init_service_resolver();
2702 /* Now parse filter... */
2703 if (argc
== 0 && filter_fp
) {
2704 if (ssfilter_parse(¤t_filter
.f
, 0, NULL
, filter_fp
))
2709 if (strcmp(*argv
, "state") == 0) {
2712 current_filter
.states
= 0;
2713 current_filter
.states
|= scan_state(*argv
);
2715 } else if (strcmp(*argv
, "exclude") == 0 ||
2716 strcmp(*argv
, "excl") == 0) {
2719 current_filter
.states
= SS_ALL
;
2720 current_filter
.states
&= ~scan_state(*argv
);
2723 if (ssfilter_parse(¤t_filter
.f
, argc
, argv
, filter_fp
))
2730 if (current_filter
.states
== 0) {
2731 fprintf(stderr
, "ss: no socket states to show with such filter.\n");
2736 FILE *dump_fp
= stdout
;
2737 if (!(current_filter
.dbs
& (1<<TCP_DB
))) {
2738 fprintf(stderr
, "ss: tcpdiag dump requested and no tcp in filter.\n");
2741 if (dump_tcpdiag
[0] != '-') {
2742 dump_fp
= fopen(dump_tcpdiag
, "w");
2743 if (!dump_tcpdiag
) {
2744 perror("fopen dump file");
2748 tcp_show_netlink(¤t_filter
, dump_fp
, TCPDIAG_GETSOCK
);
2754 if (current_filter
.dbs
&(current_filter
.dbs
-1))
2758 if (current_filter
.states
&(current_filter
.states
-1))
2762 if (isatty(STDOUT_FILENO
)) {
2765 if (ioctl(STDOUT_FILENO
, TIOCGWINSZ
, &w
) != -1) {
2767 screen_width
= w
.ws_col
;
2771 addrp_width
= screen_width
;
2772 addrp_width
-= netid_width
+1;
2773 addrp_width
-= state_width
+1;
2776 if (addrp_width
&1) {
2779 else if (state_width
)
2786 serv_width
= resolve_services
? 7 : 5;
2788 if (addrp_width
< 15+serv_width
+1)
2789 addrp_width
= 15+serv_width
+1;
2791 addr_width
= addrp_width
- serv_width
- 1;
2794 printf("%-*s ", netid_width
, "Netid");
2796 printf("%-*s ", state_width
, "State");
2797 printf("%-6s %-6s ", "Recv-Q", "Send-Q");
2799 printf("%*s:%-*s %*s:%-*s\n",
2800 addr_width
, "Local Address", serv_width
, "Port",
2801 addr_width
, "Peer Address", serv_width
, "Port");
2803 //printf("%08x %08x %08x\n", current_filter.dbs, current_filter.states, current_filter.families);
2806 if (current_filter
.dbs
& (1<<NETLINK_DB
))
2807 netlink_show(¤t_filter
);
2808 if (current_filter
.dbs
& PACKET_DBM
)
2809 packet_show(¤t_filter
);
2810 if (current_filter
.dbs
& UNIX_DBM
)
2811 unix_show(¤t_filter
);
2812 if (current_filter
.dbs
& (1<<RAW_DB
))
2813 raw_show(¤t_filter
);
2814 if (current_filter
.dbs
& (1<<UDP_DB
))
2815 udp_show(¤t_filter
);
2816 if (current_filter
.dbs
& (1<<TCP_DB
))
2817 tcp_show(¤t_filter
, TCPDIAG_GETSOCK
);
2818 if (current_filter
.dbs
& (1<<DCCP_DB
))
2819 tcp_show(¤t_filter
, DCCPDIAG_GETSOCK
);