diff options
| -rw-r--r-- | sys/netinet/tcp_subr.c | 98 | ||||
| -rw-r--r-- | sys/netinet/tcp_timewait.c | 98 | ||||
| -rw-r--r-- | sys/netinet/tcp_usrreq.c | 87 | ||||
| -rw-r--r-- | sys/netinet/tcp_var.h | 5 | ||||
| -rw-r--r-- | 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  | 
