diff --git a/usr.sbin/tcpdrop/tcpdrop.8 b/usr.sbin/tcpdrop/tcpdrop.8 index 61c3f372c76..3f3fa0c9cc8 100644 --- a/usr.sbin/tcpdrop/tcpdrop.8 +++ b/usr.sbin/tcpdrop/tcpdrop.8 @@ -17,7 +17,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 30, 2013 +.Dd September 12, 2017 .Dt TCPDROP 8 .Os .Sh NAME @@ -32,6 +32,16 @@ .Nm tcpdrop .Op Fl l .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 The .Nm @@ -41,15 +51,49 @@ If .Fl a is specified then .Nm -will attempt to drop all active connections. -The -.Fl l -flag may be given to list the tcpdrop invocation to drop all active -connections one at a time. +will attempt to drop all TCP connections. .Pp If -.Fl a -is not specified then only the connection between the given local +.Fl S Ar stack +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 .Ar local-address , port @@ -89,6 +133,23 @@ port 22, the port used by .Bd -literal -offset indent # tcpdrop -l -a | grep -vw 22 | sh .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 .Xr netstat 1 , .Xr sockstat 1 diff --git a/usr.sbin/tcpdrop/tcpdrop.c b/usr.sbin/tcpdrop/tcpdrop.c index 721129f6898..ee2c8a96e3c 100644 --- a/usr.sbin/tcpdrop/tcpdrop.c +++ b/usr.sbin/tcpdrop/tcpdrop.c @@ -54,7 +54,7 @@ static char *findport(const char *); static struct xinpgen *getxpcblist(const char *); static void sockinfo(const struct sockaddr *, struct host_service *); 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 *, const char *); static bool tcpdropconn(const struct in_conninfo *); @@ -66,13 +66,17 @@ static void usage(void); int main(int argc, char *argv[]) { + char stack[TCP_FUNCTION_NAME_LEN_MAX]; char *lport, *fport; - bool dropall; - int ch; + bool dropall, dropallstack; + int ch, state; 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) { case 'a': dropall = true; @@ -80,6 +84,17 @@ main(int argc, char *argv[]) case 'l': tcpdrop_list_commands = true; 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: usage(); } @@ -87,10 +102,16 @@ main(int argc, char *argv[]) argc -= 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) usage(); - if (!tcpdropall()) + if (!tcpdropall(stack, state)) exit(1); exit(0); } @@ -202,7 +223,7 @@ tcpdrop(const struct sockaddr *lsa, const struct sockaddr *fsa) } static bool -tcpdropall(void) +tcpdropall(const char *stack, int state) { struct xinpgen *head, *xinp; struct xtcpcb *xtp; @@ -234,6 +255,15 @@ tcpdropall(void) if (xtp->t_state == TCPS_LISTEN) 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)) ok = false; } @@ -348,6 +378,9 @@ usage(void) "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 [-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); }