git: 3ea9a7cf7b09 - main - blackhole(4): disable for locally originated TCP/UDP packets

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Wed, 03 Nov 2021 20:03:19 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=3ea9a7cf7b09a355cde3a76824809402b99d0892

commit 3ea9a7cf7b09a355cde3a76824809402b99d0892
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2021-10-28 15:11:45 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2021-11-03 20:02:44 +0000

    blackhole(4): disable for locally originated TCP/UDP packets
    
    In most cases blackholing for locally originated packets is undesired,
    leads to different kind of lags and delays. Provide sysctls to enforce
    it, e.g. for debugging purposes.
    
    Reviewed by:            rrs
    Differential revision:  https://reviews.freebsd.org/D32718
---
 share/man/man4/blackhole.4 | 12 +++++++++++-
 sys/netinet/tcp_input.c    | 19 +++++++++++++++++--
 sys/netinet/udp_usrreq.c   |  7 ++++++-
 sys/netinet/udp_var.h      |  2 ++
 sys/netinet6/udp6_usrreq.c |  3 ++-
 5 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/share/man/man4/blackhole.4 b/share/man/man4/blackhole.4
index 0bd7d03bcb50..17d1286525e4 100644
--- 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 @@ attempts
 .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 @@ are received on SCTP, TCP, or UDP ports where there is no socket listening.
 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
index a8fe6d9817d0..3ebac68c7c48 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -144,6 +144,12 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, blackhole, CTLFLAG_VNET | CTLFLAG_RW,
     &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 @@ findpcb:
 		 * 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
index 7c5a642da040..a9d534fbc8c0 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -127,6 +127,10 @@ VNET_DEFINE(int, udp_blackhole) = 0;
 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 @@ udp_input(struct mbuf **mp, int *offp, int proto)
 			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
index 37bc0c846d99..eaafdb299233 100644
--- a/sys/netinet/udp_var.h
+++ b/sys/netinet/udp_var.h
@@ -149,9 +149,11 @@ extern u_long			udp_sendspace;
 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
index 6ee2abc4ea1b..5939b631a1ab 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -511,7 +511,8 @@ skip_checksum:
 			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;