o Implement net.inet.tcp.drop sysctl and userland part, tcpdrop(8)

utility:

    The tcpdrop command drops the TCP connection specified by the
    local address laddr, port lport and the foreign address faddr,
    port fport.

Obtained from:	OpenBSD
Reviewed by:	rwatson (locking), ru (man page), -current
MFC after:	1 month
This commit is contained in:
Maxim Konovalov 2005-02-06 10:47:12 +00:00
parent 3045c8af3f
commit 212a79b010
6 changed files with 254 additions and 1 deletions

View File

@ -1273,3 +1273,89 @@ tcp_usrclosed(tp)
return (tp);
}
static int
sysctl_drop(SYSCTL_HANDLER_ARGS)
{
struct tcp_ident_mapping tir;
struct inpcb *inp;
struct tcpcb *tp;
struct sockaddr_in *fin, *lin;
#ifdef INET6
struct sockaddr_in6 *fin6, *lin6;
struct in6_addr f6, l6;
#endif
int error;
inp = NULL;
fin = lin = NULL;
#ifdef INET6
fin6 = lin6 = NULL;
#endif
error = 0;
if (req->oldptr != NULL || req->oldlen != 0)
return (EINVAL);
if (req->newptr == NULL)
return (EPERM);
if (req->newlen < sizeof(tir))
return (ENOMEM);
if ((error = copyin(req->newptr, &tir, sizeof(tir))) != 0)
return (error);
switch (tir.faddr.ss_family) {
#ifdef INET6
case AF_INET6:
fin6 = (struct sockaddr_in6 *)&tir.faddr;
lin6 = (struct sockaddr_in6 *)&tir.laddr;
if (fin6->sin6_len != sizeof(struct sockaddr_in6) ||
lin6->sin6_len != sizeof(struct sockaddr_in6))
return (EINVAL);
error = in6_embedscope(&f6, fin6, NULL, NULL);
if (error)
return (EINVAL);
error = in6_embedscope(&l6, lin6, NULL, NULL);
if (error)
return (EINVAL);
break;
#endif
case AF_INET:
fin = (struct sockaddr_in *)&tir.faddr;
lin = (struct sockaddr_in *)&tir.laddr;
if (fin->sin_len != sizeof(struct sockaddr_in) ||
lin->sin_len != sizeof(struct sockaddr_in))
return (EINVAL);
break;
default:
return (EINVAL);
}
INP_INFO_WLOCK(&tcbinfo);
switch (tir.faddr.ss_family) {
#ifdef INET6
case AF_INET6:
inp = in6_pcblookup_hash(&tcbinfo, &f6, fin6->sin6_port,
&l6, lin6->sin6_port, 0, NULL);
break;
#endif
case AF_INET:
inp = in_pcblookup_hash(&tcbinfo, fin->sin_addr, fin->sin_port,
lin->sin_addr, lin->sin_port, 0, NULL);
break;
}
if (inp != NULL) {
INP_LOCK(inp);
if ((tp = intotcpcb(inp)) &&
((inp->inp_socket->so_options & SO_ACCEPTCONN) == 0)) {
tp = tcp_drop(tp, ECONNABORTED);
if (tp != NULL)
INP_UNLOCK(inp);
} else
INP_UNLOCK(inp);
} else
error = ESRCH;
INP_INFO_WUNLOCK(&tcbinfo);
return (error);
}
SYSCTL_PROC(_net_inet_tcp, TCPCTL_DROP, drop,
CTLTYPE_STRUCT|CTLFLAG_WR|CTLFLAG_SKIP, NULL,
0, sysctl_drop, "", "Drop TCP connection");

View File

@ -451,6 +451,11 @@ struct xtcpcb {
};
#endif
struct tcp_ident_mapping {
struct sockaddr_storage faddr, laddr;
uid_t euid, ruid;
};
/*
* Names for TCP sysctl objects
*/
@ -467,7 +472,8 @@ struct xtcpcb {
#define TCPCTL_DELACKTIME 12 /* time before sending delayed ACK */
#define TCPCTL_V6MSSDFLT 13 /* MSS default for IPv6 */
#define TCPCTL_SACK 14 /* Selective Acknowledgement,rfc 2018 */
#define TCPCTL_MAXID 15
#define TCPCTL_DROP 15 /* drop tcp connection */
#define TCPCTL_MAXID 16
#define TCPCTL_NAMES { \
{ 0, 0 }, \

View File

@ -159,6 +159,7 @@ SUBDIR= ac \
syslogd \
tcpdchk \
tcpdmatch \
tcpdrop \
tcpdump \
timed \
traceroute \

View File

@ -0,0 +1,8 @@
# $OpenBSD: Makefile,v 1.1 2004/04/26 19:51:20 markus Exp $
# $FreeBSD$
PROG= tcpdrop
MAN= tcpdrop.8
WARNS?= 6
.include <bsd.prog.mk>

View File

@ -0,0 +1,64 @@
.\" $OpenBSD: tcpdrop.8,v 1.5 2004/05/24 13:57:31 jmc Exp $
.\"
.\" Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.\" $FreeBSD$
.\"
.Dd March 21, 2004
.Dt TCPDROP 8
.Os
.Sh NAME
.Nm tcpdrop
.Nd drop a TCP connection
.Sh SYNOPSIS
.Nm tcpdrop
.Ar laddr
.Ar lport
.Ar faddr
.Ar fport
.Sh DESCRIPTION
The
.Nm
command drops the TCP connection specified by the local address
.Ar laddr ,
port
.Ar lport
and the foreign address
.Ar faddr ,
port
.Ar fport .
Addresses and ports can be specified by name or numeric value.
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
If a connection to
.Xr httpd 8
is causing congestion on a network link, one can drop the TCP session
in charge:
.Bd -literal -offset indent
# fstat | egrep 'httpd.*internet.*<--'
www httpd 21307 3* internet stream tcp \e
0xd1007ca8 192.168.5.41:80 <-- 192.168.5.1:26747
.Ed
.Pp
The following command will drop the connection:
.Bd -literal -offset indent
# tcpdrop 192.168.5.41 80 192.168.5.1 26747
.Ed
.Sh SEE ALSO
.Xr fstat 1 ,
.Xr netstat 1
.Sh AUTHORS
.An Markus Friedl Aq markus@openbsd.org

View File

@ -0,0 +1,88 @@
/* $OpenBSD: tcpdrop.c,v 1.4 2004/05/22 23:55:22 deraadt Exp $ */
/*-
* Copyright (c) 2004 Markus Friedl <markus@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <netinet/tcp_var.h>
#include <err.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Drop a tcp connection.
*/
int
main(int argc, char *argv[])
{
struct addrinfo hints, *ail, *aif, *laddr, *faddr;
struct tcp_ident_mapping tir;
int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_DROP };
int gaierr, rval = 0;
char fhbuf[NI_MAXHOST], fsbuf[NI_MAXSERV], lhbuf[NI_MAXHOST],
lsbuf[NI_MAXSERV];
if (argc != 5)
errx(1, "usage: tcpdrop laddr lport faddr fport\n");
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((gaierr = getaddrinfo(argv[1], argv[2], &hints, &laddr)) != 0)
errx(1, "%s port %s: %s", argv[1], argv[2],
gai_strerror(gaierr));
if ((gaierr = getaddrinfo(argv[3], argv[4], &hints, &faddr)) != 0) {
freeaddrinfo(laddr);
errx(1, "%s port %s: %s", argv[3], argv[4],
gai_strerror(gaierr));
}
for (ail = laddr; ail; ail = ail->ai_next) {
for (aif = faddr; aif; aif = aif->ai_next) {
if (ail->ai_family != aif->ai_family)
continue;
memcpy(&tir.faddr, aif->ai_addr, aif->ai_addrlen);
memcpy(&tir.laddr, ail->ai_addr, ail->ai_addrlen);
if (getnameinfo(aif->ai_addr, aif->ai_addrlen,
fhbuf, sizeof(fhbuf),
fsbuf, sizeof(fsbuf),
NI_NUMERICHOST | NI_NUMERICSERV) == -1)
err(1, "getnameinfo");
if (getnameinfo(ail->ai_addr, ail->ai_addrlen,
lhbuf, sizeof(lhbuf),
lsbuf, sizeof(lsbuf),
NI_NUMERICHOST | NI_NUMERICSERV) == -1)
err(1, "getnameinfo");
if (sysctl(mib, sizeof (mib) / sizeof (int), NULL,
NULL, &tir, sizeof(tir)) == -1) {
rval = 1;
warn("%s %s %s %s", lhbuf, lsbuf, fhbuf, fsbuf);
} else
printf("%s %s %s %s: dropped\n",
lhbuf, lsbuf, fhbuf, fsbuf);
}
}
freeaddrinfo(laddr);
freeaddrinfo(faddr);
exit(rval);
}