summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormaxim <maxim@FreeBSD.org>2005-02-14 07:37:51 +0000
committermaxim <maxim@FreeBSD.org>2005-02-14 07:37:51 +0000
commitd2ebfe4c1f1998f4bd2184a39cb19cc7ec023001 (patch)
treea6be9f7597e232f5e70091fea00613f0423dc377
parent70bda33804e254c8add665f1fd0a4cd42750423d (diff)
downloadFreeBSD-src-d2ebfe4c1f1998f4bd2184a39cb19cc7ec023001.zip
FreeBSD-src-d2ebfe4c1f1998f4bd2184a39cb19cc7ec023001.tar.gz
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
-rw-r--r--sys/netinet/tcp_subr.c98
-rw-r--r--sys/netinet/tcp_timewait.c98
-rw-r--r--sys/netinet/tcp_usrreq.c87
-rw-r--r--sys/netinet/tcp_var.h5
-rw-r--r--usr.sbin/tcpdrop/tcpdrop.c9
5 files changed, 201 insertions, 96 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index c8a4438..fa4489b 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 c8a4438..fa4489b 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 a2e3d3c..d6824dd 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 fa98508..f647346 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 cfa8c2a..68ef0ef 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
OpenPOWER on IntegriCloud