Allow TCP connections to be filtered by stack and state.

Choose the command line options to be consistent with the ones of
sockstat.

Sponsored by:	Netflix, Inc.
This commit is contained in:
Michael Tuexen 2017-09-12 13:39:44 +00:00
parent e5cccc35c3
commit e1418fa5ef
2 changed files with 110 additions and 16 deletions

View File

@ -17,7 +17,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd January 30, 2013 .Dd September 12, 2017
.Dt TCPDROP 8 .Dt TCPDROP 8
.Os .Os
.Sh NAME .Sh NAME
@ -32,6 +32,16 @@
.Nm tcpdrop .Nm tcpdrop
.Op Fl l .Op Fl l
.Fl a .Fl a
.Nm tcpdrop
.Op Fl l
.Fl S Ar stack
.Nm tcpdrop
.Op Fl l
.Fl s Ar state
.Nm tcpdrop
.Op Fl l
.Fl S Ar stack
.Fl s Ar state
.Sh DESCRIPTION .Sh DESCRIPTION
The The
.Nm .Nm
@ -41,15 +51,49 @@ If
.Fl a .Fl a
is specified then is specified then
.Nm .Nm
will attempt to drop all active connections. will attempt to drop all TCP connections.
The
.Fl l
flag may be given to list the tcpdrop invocation to drop all active
connections one at a time.
.Pp .Pp
If If
.Fl a .Fl S Ar stack
is not specified then only the connection between the given local is specified then
.Nm
will attempt to drop all connections using the TCP stack
.Ar stack .
.Pp
If
.Fl s Ar state
is specified then
.Nm
will attempt to drop all TCP connections being in the state
.Ar state .
.Ar state
is one of
.Dv SYN_SENT ,
.Dv SYN_RCVD ,
.Dv ESTABLISHED ,
.Dv CLOSE_WAIT ,
.Dv FIN_WAIT_1 ,
.Dv CLOSING ,
.Dv LAST_ACK ,
.Dv FIN_WAIT_2 , or
.Dv TIME_WAIT .
.Pp
The
.Fl l
flag may be given in addition to the
.Fl a ,
.Fl S ,
or
.Fl s
options to list the tcpdrop invocation to drop all corresponding TCP
connections one at a time.
.Pp
If none of the
.Fl a ,
.Fl S ,
or
.Fl s
options are specified then only the connection between the given local
address address
.Ar local-address , .Ar local-address ,
port port
@ -89,6 +133,23 @@ port 22, the port used by
.Bd -literal -offset indent .Bd -literal -offset indent
# tcpdrop -l -a | grep -vw 22 | sh # tcpdrop -l -a | grep -vw 22 | sh
.Ed .Ed
.Pp
The following command will drop all connections using the TCP stack
fastack:
.Bd -literal -offset indent
# tcpdrop -S fastack
.Ed
.Pp
To drop all TCP connections in the LAST_ACK state use:
.Bd -literal -offset indent
# tcpdrop -s LAST_ACK
.Ed
.Pp
To drop all TCP connections using the TCP stack fastack and being in the
LAST_ACK state use:
.Bd -literal -offset indent
# tcpdrop -S fastack -s LAST_ACK
.Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr netstat 1 , .Xr netstat 1 ,
.Xr sockstat 1 .Xr sockstat 1

View File

@ -54,7 +54,7 @@ static char *findport(const char *);
static struct xinpgen *getxpcblist(const char *); static struct xinpgen *getxpcblist(const char *);
static void sockinfo(const struct sockaddr *, struct host_service *); static void sockinfo(const struct sockaddr *, struct host_service *);
static bool tcpdrop(const struct sockaddr *, const struct sockaddr *); static bool tcpdrop(const struct sockaddr *, const struct sockaddr *);
static bool tcpdropall(void); static bool tcpdropall(const char *, int);
static bool tcpdropbyname(const char *, const char *, const char *, static bool tcpdropbyname(const char *, const char *, const char *,
const char *); const char *);
static bool tcpdropconn(const struct in_conninfo *); static bool tcpdropconn(const struct in_conninfo *);
@ -66,13 +66,17 @@ static void usage(void);
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
char stack[TCP_FUNCTION_NAME_LEN_MAX];
char *lport, *fport; char *lport, *fport;
bool dropall; bool dropall, dropallstack;
int ch; int ch, state;
dropall = false; dropall = false;
dropallstack = false;
memset(stack, 0, TCP_FUNCTION_NAME_LEN_MAX);
state = -1;
while ((ch = getopt(argc, argv, "al")) != -1) { while ((ch = getopt(argc, argv, "alS:s:")) != -1) {
switch (ch) { switch (ch) {
case 'a': case 'a':
dropall = true; dropall = true;
@ -80,6 +84,17 @@ main(int argc, char *argv[])
case 'l': case 'l':
tcpdrop_list_commands = true; tcpdrop_list_commands = true;
break; break;
case 'S':
dropallstack = true;
strncpy(stack, optarg, TCP_FUNCTION_NAME_LEN_MAX);
break;
case 's':
dropallstack = true;
for (state = 0; state < TCP_NSTATES; state++) {
if (strcmp(tcpstates[state], optarg) == 0)
break;
}
break;
default: default:
usage(); usage();
} }
@ -87,10 +102,16 @@ main(int argc, char *argv[])
argc -= optind; argc -= optind;
argv += optind; argv += optind;
if (dropall) { if (state == TCP_NSTATES ||
state == TCPS_CLOSED ||
state == TCPS_LISTEN)
usage();
if (dropall && dropallstack)
usage();
if (dropall || dropallstack) {
if (argc != 0) if (argc != 0)
usage(); usage();
if (!tcpdropall()) if (!tcpdropall(stack, state))
exit(1); exit(1);
exit(0); exit(0);
} }
@ -202,7 +223,7 @@ tcpdrop(const struct sockaddr *lsa, const struct sockaddr *fsa)
} }
static bool static bool
tcpdropall(void) tcpdropall(const char *stack, int state)
{ {
struct xinpgen *head, *xinp; struct xinpgen *head, *xinp;
struct xtcpcb *xtp; struct xtcpcb *xtp;
@ -234,6 +255,15 @@ tcpdropall(void)
if (xtp->t_state == TCPS_LISTEN) if (xtp->t_state == TCPS_LISTEN)
continue; continue;
/* If requested, skip sockets not having the requested state. */
if ((state != -1) && (xtp->t_state != state))
continue;
/* If requested, skip sockets not having the requested stack. */
if (strnlen(stack, TCP_FUNCTION_NAME_LEN_MAX) > 0 &&
strncmp(xtp->xt_stack, stack, TCP_FUNCTION_NAME_LEN_MAX))
continue;
if (!tcpdropconn(&xip->inp_inc)) if (!tcpdropconn(&xip->inp_inc))
ok = false; ok = false;
} }
@ -348,6 +378,9 @@ usage(void)
"usage: tcpdrop local-address local-port foreign-address foreign-port\n" "usage: tcpdrop local-address local-port foreign-address foreign-port\n"
" tcpdrop local-address:local-port foreign-address:foreign-port\n" " tcpdrop local-address:local-port foreign-address:foreign-port\n"
" tcpdrop local-address.local-port foreign-address.foreign-port\n" " tcpdrop local-address.local-port foreign-address.foreign-port\n"
" tcpdrop [-l] -a\n"); " tcpdrop [-l] -a\n"
" tcpdrop [-l] -S stack\n"
" tcpdrop [-l] -s state\n"
" tcpdrop [-l] -S stack -s state\n");
exit(1); exit(1);
} }