diff options
author | Guillaume Nault <gnault@redhat.com> | 2023-12-19 14:18:13 +0100 |
---|---|---|
committer | David Ahern <dsahern@kernel.org> | 2023-12-20 16:15:49 +0000 |
commit | ae447da64975ad02e40a93ccbc440a6477af96c0 (patch) | |
tree | 08d685089ba3901bde41fe9597620fa2b10b0db8 | |
parent | b6df01d17752d746cdca6383db21d34279f0d1f4 (diff) | |
download | iproute2-ae447da64975ad02e40a93ccbc440a6477af96c0.tar.gz |
ss: Add support for dumping TCP bound-inactive sockets.
Make ss aware of the new "bound-inactive" pseudo-state for TCP (see
Linux commit 91051f003948 ("tcp: Dump bound-only sockets in inet_diag.")).
These are TCP sockets that have been bound, but are neither listening nor
connecting.
With this patch, these sockets can now be dumped with:
* the existing -a (--all) option, to dump all sockets, including
bound-inactive ones,
* the new -B (--bound-inactive) option, to dump them exclusively,
* the new "bound-inactive" state, to be used in a STATE-FILTER.
Note that the SS_BOUND_INACTIVE state is a pseudo-state used for queries
only. The kernel returns them as SS_CLOSE.
The SS_NEW_SYN_RECV pseudo-state is added in this patch only because we
have to set its entry in the sstate_namel array (in scan_state()). Care
is taken not to make it visible by users.
Signed-off-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
-rw-r--r-- | man/man8/ss.8 | 7 | ||||
-rw-r--r-- | misc/ss.c | 20 |
2 files changed, 26 insertions, 1 deletions
diff --git a/man/man8/ss.8 b/man/man8/ss.8 index 073e9f039..4ece41fa6 100644 --- a/man/man8/ss.8 +++ b/man/man8/ss.8 @@ -40,6 +40,10 @@ established connections) sockets. .B \-l, \-\-listening Display only listening sockets (these are omitted by default). .TP +.B \-B, \-\-bound-inactive +Display only TCP bound but inactive (not listening, connecting, etc.) sockets +(these are omitted by default). +.TP .B \-o, \-\-options Show timer information. For TCP protocol, the output format is: .RS @@ -456,6 +460,9 @@ states except for - opposite to .B bucket +.B bound-inactive +- bound but otherwise inactive sockets (not listening, connecting, etc.) + .SH EXPRESSION .B EXPRESSION @@ -210,6 +210,8 @@ enum { SS_LAST_ACK, SS_LISTEN, SS_CLOSING, + SS_NEW_SYN_RECV, /* Kernel only value, not for use in user space */ + SS_BOUND_INACTIVE, SS_MAX }; @@ -1382,6 +1384,8 @@ static void sock_state_print(struct sockstat *s) [SS_LAST_ACK] = "LAST-ACK", [SS_LISTEN] = "LISTEN", [SS_CLOSING] = "CLOSING", + [SS_NEW_SYN_RECV] = "UNDEF", /* Never returned by kernel */ + [SS_BOUND_INACTIVE] = "UNDEF", /* Never returned by kernel */ }; switch (s->local.family) { @@ -5339,6 +5343,7 @@ static void _usage(FILE *dest) " -r, --resolve resolve host names\n" " -a, --all display all sockets\n" " -l, --listening display listening sockets\n" +" -B, --bound-inactive display TCP bound but inactive sockets\n" " -o, --options show timer information\n" " -e, --extended show detailed socket information\n" " -m, --memory show socket memory usage\n" @@ -5421,9 +5426,17 @@ static int scan_state(const char *state) [SS_LAST_ACK] = "last-ack", [SS_LISTEN] = "listening", [SS_CLOSING] = "closing", + [SS_NEW_SYN_RECV] = "new-syn-recv", + [SS_BOUND_INACTIVE] = "bound-inactive", }; int i; + /* NEW_SYN_RECV is a kernel implementation detail. It shouldn't be used + * or even be visible by users. + */ + if (strcasecmp(state, "new-syn-recv") == 0) + goto wrong_state; + if (strcasecmp(state, "close") == 0 || strcasecmp(state, "closed") == 0) return (1<<SS_CLOSE); @@ -5446,6 +5459,7 @@ static int scan_state(const char *state) return (1<<i); } +wrong_state: fprintf(stderr, "ss: wrong state name: %s\n", state); exit(-1); } @@ -5487,6 +5501,7 @@ static const struct option long_opts[] = { { "vsock", 0, 0, OPT_VSOCK }, { "all", 0, 0, 'a' }, { "listening", 0, 0, 'l' }, + { "bound-inactive", 0, 0, 'B' }, { "ipv4", 0, 0, '4' }, { "ipv6", 0, 0, '6' }, { "packet", 0, 0, '0' }, @@ -5525,7 +5540,7 @@ int main(int argc, char *argv[]) int state_filter = 0; while ((ch = getopt_long(argc, argv, - "dhaletuwxnro460spTbEf:mMiA:D:F:vVzZN:KHSO", + "dhalBetuwxnro460spTbEf:mMiA:D:F:vVzZN:KHSO", long_opts, NULL)) != EOF) { switch (ch) { case 'n': @@ -5590,6 +5605,9 @@ int main(int argc, char *argv[]) case 'l': state_filter = (1 << SS_LISTEN) | (1 << SS_CLOSE); break; + case 'B': + state_filter = 1 << SS_BOUND_INACTIVE; + break; case '4': filter_af_set(¤t_filter, AF_INET); break; |