diff options
author | Maxim Konovalov <maxim@FreeBSD.org> | 2005-02-06 10:47:12 +0000 |
---|---|---|
committer | Maxim Konovalov <maxim@FreeBSD.org> | 2005-02-06 10:47:12 +0000 |
commit | 212a79b0104bbd1a45b2dc5f60fc23e55a34aab5 (patch) | |
tree | 81a82bbce807e9b9f91a45a84bac02a9d5a74e61 /sys | |
parent | 3045c8af3f8032af548a3e30e5172b03a5b4685f (diff) | |
download | src-212a79b0104bbd1a45b2dc5f60fc23e55a34aab5.tar.gz src-212a79b0104bbd1a45b2dc5f60fc23e55a34aab5.zip |
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
Notes
Notes:
svn path=/head/; revision=141381
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 86 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 8 |
2 files changed, 93 insertions, 1 deletions
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 660dd5be4bc7..a2e3d3c0aae7 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -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"); diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index 4f87ef4c5645..fa98508be59a 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -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 }, \ |