diff options
| author | Maxim Konovalov <maxim@FreeBSD.org> | 2005-03-14 08:08:19 +0000 |
|---|---|---|
| committer | Maxim Konovalov <maxim@FreeBSD.org> | 2005-03-14 08:08:19 +0000 |
| commit | 032ea0a7e5e301a04424cbe508b2cadf22c0ba1c (patch) | |
| tree | 73b7f8b4359c86d4e2ed778d69560c60deee3b8a | |
| parent | bb0f63f69fb6c26d950302b38c68ce186a8bf63b (diff) | |
Notes
| -rw-r--r-- | sys/netinet/tcp_subr.c | 98 | ||||
| -rw-r--r-- | sys/netinet/tcp_var.h | 3 | ||||
| -rw-r--r-- | usr.sbin/Makefile | 1 |
3 files changed, 101 insertions, 1 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 43fa3e9dbd8c..2b759b277866 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -2155,3 +2155,101 @@ tcp_signature_compute(struct mbuf *m, int off0, int len, int optlen, return (0); } #endif /* TCP_SIGNATURE */ + +static int +sysctl_drop(SYSCTL_HANDLER_ARGS) +{ + /* addrs[0] is a foreign socket, addrs[1] is a local one. */ + struct sockaddr_storage addrs[2]; + 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(addrs)) + return (ENOMEM); + error = SYSCTL_IN(req, &addrs, sizeof(addrs)); + if (error) + return (error); + + switch (addrs[0].ss_family) { +#ifdef INET6 + case AF_INET6: + fin6 = (struct sockaddr_in6 *)&addrs[0]; + lin6 = (struct sockaddr_in6 *)&addrs[1]; + if (fin6->sin6_len != sizeof(struct sockaddr_in6) || + lin6->sin6_len != sizeof(struct sockaddr_in6)) + return (EINVAL); + if (IN6_IS_ADDR_V4MAPPED(&fin6->sin6_addr)) { + if (!IN6_IS_ADDR_V4MAPPED(&lin6->sin6_addr)) + return (EINVAL); + in6_sin6_2_sin_in_sock((struct sockaddr *)&addrs[0]); + in6_sin6_2_sin_in_sock((struct sockaddr *)&addrs[1]); + fin = (struct sockaddr_in *)&addrs[0]; + lin = (struct sockaddr_in *)&addrs[1]; + break; + } + 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 *)&addrs[0]; + lin = (struct sockaddr_in *)&addrs[1]; + 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 (addrs[0].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"); diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index a9b3121a2170..848faa23f3b4 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -499,7 +499,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 }, \ diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 96f6794077a7..5f71b3e4e764 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -159,6 +159,7 @@ SUBDIR= ac \ syslogd \ tcpdchk \ tcpdmatch \ + tcpdrop \ tcpdump \ timed \ traceroute \ |
