int show_sock_ctx = 0;
/* If show_users & show_proc_ctx only do user_ent_hash_build() once */
int user_ent_hash_build_init = 0;
+int follow_events = 0;
int netid_width;
int state_width;
if (f && f->f && run_ssfilter(f->f, &s) == 0)
return 0;
+ if (tb[INET_DIAG_PROTOCOL])
+ protocol = *(__u8 *)RTA_DATA(tb[INET_DIAG_PROTOCOL]);
+
inet_stats_print(&s, protocol);
if (show_options) {
if (!(diag_arg->f->families & (1 << r->idiag_family)))
return 0;
- if ((err = inet_show_sock(h, NULL, diag_arg->protocol)) < 0)
+ if ((err = inet_show_sock(h, diag_arg->f, diag_arg->protocol)) < 0)
return err;
return 0;
return 0;
}
+struct sock_diag_msg {
+ __u8 sdiag_family;
+};
+
+static int generic_show_sock(const struct sockaddr_nl *addr,
+ struct nlmsghdr *nlh, void *arg)
+{
+ struct sock_diag_msg *r = NLMSG_DATA(nlh);
+ struct inet_diag_arg inet_arg = { .f = arg, .protocol = IPPROTO_MAX };
+
+ switch (r->sdiag_family) {
+ case AF_INET:
+ case AF_INET6:
+ return show_one_inet_sock(addr, nlh, &inet_arg);
+ case AF_UNIX:
+ return unix_show_sock(addr, nlh, arg);
+ case AF_PACKET:
+ return packet_show_sock(addr, nlh, arg);
+ case AF_NETLINK:
+ return netlink_show_sock(addr, nlh, arg);
+ default:
+ return -1;
+ }
+}
+
+static int handle_follow_request(struct filter *f)
+{
+ int ret = -1;
+ int groups = 0;
+ struct rtnl_handle rth;
+
+ if (f->families & (1 << AF_INET) && f->dbs & (1 << TCP_DB))
+ groups |= 1 << (SKNLGRP_INET_TCP_DESTROY - 1);
+ if (f->families & (1 << AF_INET) && f->dbs & (1 << UDP_DB))
+ groups |= 1 << (SKNLGRP_INET_UDP_DESTROY - 1);
+ if (f->families & (1 << AF_INET6) && f->dbs & (1 << TCP_DB))
+ groups |= 1 << (SKNLGRP_INET6_TCP_DESTROY - 1);
+ if (f->families & (1 << AF_INET6) && f->dbs & (1 << UDP_DB))
+ groups |= 1 << (SKNLGRP_INET6_UDP_DESTROY - 1);
+
+ if (groups == 0)
+ return -1;
+
+ if (rtnl_open_byproto(&rth, groups, NETLINK_SOCK_DIAG))
+ return -1;
+
+ rth.dump = 0;
+ rth.local.nl_pid = 0;
+
+ if (rtnl_dump_filter(&rth, generic_show_sock, f))
+ goto Exit;
+
+ ret = 0;
+Exit:
+ rtnl_close(&rth);
+ return ret;
+}
+
struct snmpstat
{
int tcp_estab;
" -i, --info show internal TCP information\n"
" -s, --summary show socket usage summary\n"
" -b, --bpf show bpf filter socket information\n"
+" -E, --events continually display sockets as they are destroyed\n"
" -Z, --context display process SELinux security contexts\n"
" -z, --contexts display process and socket SELinux security contexts\n"
" -N, --net switch to the specified network namespace name\n"
{ "info", 0, 0, 'i' },
{ "processes", 0, 0, 'p' },
{ "bpf", 0, 0, 'b' },
+ { "events", 0, 0, 'E' },
{ "dccp", 0, 0, 'd' },
{ "tcp", 0, 0, 't' },
{ "udp", 0, 0, 'u' },
int ch;
int state_filter = 0;
- while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbf:miA:D:F:vVzZN:",
+ while ((ch = getopt_long(argc, argv, "dhaletuwxnro460spbEf:miA:D:F:vVzZN:",
long_opts, NULL)) != EOF) {
switch(ch) {
case 'n':
show_options = 1;
show_bpf++;
break;
+ case 'E':
+ follow_events = 1;
+ break;
case 'd':
filter_db_set(¤t_filter, DCCP_DB);
break;
fflush(stdout);
+ if (follow_events)
+ exit(handle_follow_request(¤t_filter));
+
if (current_filter.dbs & (1<<NETLINK_DB))
netlink_show(¤t_filter);
if (current_filter.dbs & PACKET_DBM)