From 9945c0e21f69eb22f3a73def4c6a14f5b88b5de2 Mon Sep 17 00:00:00 2001 From: Maxim Konovalov Date: Mon, 14 Feb 2005 07:37:51 +0000 Subject: [PATCH] o Add handling of an IPv4-mapped IPv6 address. o Use SYSCTL_IN() macro instead of direct call of copyin(9). Submitted by: ume o Move sysctl_drop() implementation to sys/netinet/tcp_subr.c where most of tcp sysctls live. o There are net.inet[6].tcp[6].getcred sysctls already, no needs in a separate struct tcp_ident_mapping. Suggested by: ume --- sys/netinet/tcp_subr.c | 98 ++++++++++++++++++++++++++++++++++++++ sys/netinet/tcp_timewait.c | 98 ++++++++++++++++++++++++++++++++++++++ sys/netinet/tcp_usrreq.c | 87 --------------------------------- sys/netinet/tcp_var.h | 5 -- usr.sbin/tcpdrop/tcpdrop.c | 9 ++-- 5 files changed, 201 insertions(+), 96 deletions(-) diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index c8a443893e32..fa4489b575c6 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -2119,3 +2119,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_timewait.c b/sys/netinet/tcp_timewait.c index c8a443893e32..fa4489b575c6 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -2119,3 +2119,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_usrreq.c b/sys/netinet/tcp_usrreq.c index a2e3d3c0aae7..d6824dd9151a 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1272,90 +1272,3 @@ 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 fa98508be59a..f6473467c812 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -451,11 +451,6 @@ struct xtcpcb { }; #endif -struct tcp_ident_mapping { - struct sockaddr_storage faddr, laddr; - uid_t euid, ruid; -}; - /* * Names for TCP sysctl objects */ diff --git a/usr.sbin/tcpdrop/tcpdrop.c b/usr.sbin/tcpdrop/tcpdrop.c index cfa8c2adf367..68ef0ef1604b 100644 --- a/usr.sbin/tcpdrop/tcpdrop.c +++ b/usr.sbin/tcpdrop/tcpdrop.c @@ -38,7 +38,8 @@ int main(int argc, char *argv[]) { struct addrinfo hints, *ail, *aif, *laddr, *faddr; - struct tcp_ident_mapping tir; + /* addrs[0] is a foreign socket, addrs[1] is a local one. */ + struct sockaddr_storage addrs[2]; int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_DROP }; int gaierr, rval = 0; char fhbuf[NI_MAXHOST], fsbuf[NI_MAXSERV], lhbuf[NI_MAXHOST], @@ -61,8 +62,8 @@ main(int argc, char *argv[]) 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); + memcpy(&addrs[0], aif->ai_addr, aif->ai_addrlen); + memcpy(&addrs[1], ail->ai_addr, ail->ai_addrlen); if (getnameinfo(aif->ai_addr, aif->ai_addrlen, fhbuf, sizeof(fhbuf), fsbuf, sizeof(fsbuf), @@ -74,7 +75,7 @@ main(int argc, char *argv[]) NI_NUMERICHOST | NI_NUMERICSERV) == -1) err(1, "getnameinfo"); if (sysctl(mib, sizeof (mib) / sizeof (int), NULL, - NULL, &tir, sizeof(tir)) == -1) { + NULL, &addrs, sizeof(addrs)) == -1) { rval = 1; warn("%s %s %s %s", lhbuf, lsbuf, fhbuf, fsbuf); } else