diff --git a/share/man/man4/blackhole.4 b/share/man/man4/blackhole.4 --- a/share/man/man4/blackhole.4 +++ b/share/man/man4/blackhole.4 @@ -12,7 +12,7 @@ .\" .\" .\" $FreeBSD$ -.Dd September 6, 2015 +.Dd November 3, 2021 .Dt BLACKHOLE 4 .Os .Sh NAME @@ -24,7 +24,9 @@ .Sh SYNOPSIS .Cd sysctl net.inet.sctp.blackhole Ns Op = Ns Brq "0 | 1 | 2" .Cd sysctl net.inet.tcp.blackhole Ns Op = Ns Brq "0 | 1 | 2" +.Cd sysctl net.inet.tcp.blackhole_local Ns Op = Ns Brq "0 | 1" .Cd sysctl net.inet.udp.blackhole Ns Op = Ns Brq "0 | 1" +.Cd sysctl net.inet.udp.blackhole_local Ns Op = Ns Brq "0 | 1" .Sh DESCRIPTION The .Nm @@ -35,6 +37,14 @@ The blackhole behaviour is useful to slow down an attacker who is port-scanning a system in an attempt to detect vulnerable services. It might also slow down an attempted denial of service attack. +.Pp +The blackhole behaviour is disabled by default. +If enabled, the locally originated packets would still be responded to, +unless also +.Va net.inet.tcp.blackhole_local +(for TCP) and/or +.Va net.inet.udp.blackhole_local +(for UDP) are enforced. .Ss SCTP Setting the SCTP blackhole MIB to a numeric value of one will prevent sending an ABORT packet in response to an incoming INIT. diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -144,6 +144,12 @@ &VNET_NAME(blackhole), 0, "Do not send RST on segments to closed ports"); +VNET_DEFINE(bool, blackhole_local) = false; +#define V_blackhole_local VNET(blackhole_local) +SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, blackhole_local, CTLFLAG_VNET | + CTLFLAG_RW, &VNET_NAME(blackhole_local), false, + "Enforce net.inet.tcp.blackhole for locally originated packets"); + VNET_DEFINE(int, tcp_delack_enabled) = 1; SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_delack_enabled), 0, @@ -935,8 +941,17 @@ * When blackholing do not respond with a RST but * completely ignore the segment and drop it. */ - if ((V_blackhole == 1 && (thflags & TH_SYN)) || - V_blackhole == 2) + if (((V_blackhole == 1 && (thflags & TH_SYN)) || + V_blackhole == 2) && (V_blackhole_local || +#ifdef INET6 + isipv6 ? !in6_localaddr(&ip6->ip6_src) : +#endif +#ifdef INET + !in_localip(ip->ip_src) +#else + true +#endif + )) goto dropunlock; rstreason = BANDLIM_RST_CLOSEDPORT; diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -127,6 +127,10 @@ SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(udp_blackhole), 0, "Do not send port unreachables for refused connects"); +VNET_DEFINE(bool, udp_blackhole_local) = false; +SYSCTL_BOOL(_net_inet_udp, OID_AUTO, blackhole_local, CTLFLAG_VNET | + CTLFLAG_RW, &VNET_NAME(udp_blackhole_local), false, + "Enforce net.inet.udp.blackhole for locally originated packets"); u_long udp_sendspace = 9216; /* really max datagram size */ SYSCTL_ULONG(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, @@ -701,7 +705,8 @@ UDPSTAT_INC(udps_noportbcast); goto badunlocked; } - if (V_udp_blackhole) + if (V_udp_blackhole && (V_udp_blackhole_local || + !in_localip(ip->ip_src))) goto badunlocked; if (badport_bandlim(BANDLIM_ICMP_UNREACH) < 0) goto badunlocked; diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -149,9 +149,11 @@ extern u_long udp_recvspace; VNET_DECLARE(int, udp_cksum); VNET_DECLARE(int, udp_blackhole); +VNET_DECLARE(bool, udp_blackhole_local); VNET_DECLARE(int, udp_log_in_vain); #define V_udp_cksum VNET(udp_cksum) #define V_udp_blackhole VNET(udp_blackhole) +#define V_udp_blackhole_local VNET(udp_blackhole_local) #define V_udp_log_in_vain VNET(udp_log_in_vain) VNET_DECLARE(int, zero_checksum_port); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -511,7 +511,8 @@ UDPSTAT_INC(udps_noportmcast); goto badunlocked; } - if (V_udp_blackhole) + if (V_udp_blackhole && (V_udp_blackhole_local || + !in6_localaddr(&ip6->ip6_src))) goto badunlocked; icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); *mp = NULL;