aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Konovalov <maxim@FreeBSD.org>2005-03-14 08:08:19 +0000
committerMaxim Konovalov <maxim@FreeBSD.org>2005-03-14 08:08:19 +0000
commit032ea0a7e5e301a04424cbe508b2cadf22c0ba1c (patch)
tree73b7f8b4359c86d4e2ed778d69560c60deee3b8a
parentbb0f63f69fb6c26d950302b38c68ce186a8bf63b (diff)
Notes
-rw-r--r--sys/netinet/tcp_subr.c98
-rw-r--r--sys/netinet/tcp_var.h3
-rw-r--r--usr.sbin/Makefile1
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 \