git: 4036380e0297 - main - tcp: vnetify sysctl variables ack_war_timewindow and ack_war_cnt

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Sun, 28 Jul 2024 20:40:22 UTC
The branch main has been updated by tuexen:

URL: https://cgit.FreeBSD.org/src/commit/?id=4036380e029708f5d6ad7aa599ce1bba9d7c067b

commit 4036380e029708f5d6ad7aa599ce1bba9d7c067b
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2024-07-28 20:36:34 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2024-07-28 20:36:34 +0000

    tcp: vnetify sysctl variables ack_war_timewindow and ack_war_cnt
    
    As suggested by glebius@. While there, improve the documentation.
    
    Reviewed by:            Peter Lei, cc
    MFC after:              1 week
    Sponsored by:           Netflix, Inc
    Differential Revision:  https://reviews.freebsd.org/D46140
---
 share/man/man4/tcp.4                     | 20 +++++++++++++++++++-
 sys/netinet/tcp_stacks/rack.c            |  2 +-
 sys/netinet/tcp_stacks/rack_bbr_common.c | 16 ++++++++--------
 sys/netinet/tcp_subr.c                   | 24 +++++++++++-------------
 sys/netinet/tcp_var.h                    |  4 ++++
 5 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4
index 3f5d87da0ffb..70356baa2145 100644
--- a/share/man/man4/tcp.4
+++ b/share/man/man4/tcp.4
@@ -31,7 +31,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 21, 2024
+.Dd July 28, 2024
 .Dt TCP 4
 .Os
 .Sh NAME
@@ -432,6 +432,17 @@ branch of the
 MIB, which can also be read or modified with
 .Xr sysctl 8 .
 .Bl -tag -width ".Va v6pmtud_blackhole_mss"
+.It Va ack_war_timewindow , ack_war_cnt
+The challenge ACK throttling algorithm defined in RFC 5961 limits
+the number of challenge ACKs sent per TCP connection to
+.Va ack_war_cnt
+during the time interval specified in milliseconds by
+.Va ack_war_timewindow .
+Setting
+.Va ack_war_timewindow
+or
+.Va ack_war_cnt
+to zero disables challenge ACK throttling.
 .It Va always_keepalive
 Assume that
 .Dv SO_KEEPALIVE
@@ -1078,6 +1089,13 @@ when trying to use a TCP function block that is not available;
 .%T "The Addition of Explicit Congestion Notification (ECN) to IP"
 .%O "RFC 3168"
 .Re
+.Rs
+.%A "A. Ramaiah"
+.%A "R. Stewart"
+.%A "M. Dalal"
+.%T "Improving TCP's Robustness to Blind In-Window Attacks"
+.%O "RFC 5961"
+.Re
 .Sh HISTORY
 The
 .Tn TCP
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 44ddfac2a6ca..ec0c6f500946 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -15547,7 +15547,7 @@ rack_init(struct tcpcb *tp, void **ptr)
 	rack->r_ctl.rc_lower_rtt_us_cts = us_cts;
 	rack->r_ctl.rc_time_of_last_probertt = us_cts;
 	rack->r_ctl.rc_went_idle_time = us_cts;
-	rack->r_ctl.challenge_ack_ts = tcp_ts_getticks() - (tcp_ack_war_time_window + 1);
+	rack->r_ctl.challenge_ack_ts = tcp_ts_getticks() - (V_tcp_ack_war_time_window + 1);
 	rack->r_ctl.rc_time_probertt_starts = 0;
 
 	rack->r_ctl.gp_rnd_thresh = rack_rnd_cnt_req & 0xff;
diff --git a/sys/netinet/tcp_stacks/rack_bbr_common.c b/sys/netinet/tcp_stacks/rack_bbr_common.c
index 4a4a8af2bd78..b218f449475f 100644
--- a/sys/netinet/tcp_stacks/rack_bbr_common.c
+++ b/sys/netinet/tcp_stacks/rack_bbr_common.c
@@ -535,8 +535,8 @@ void
 ctf_ack_war_checks(struct tcpcb *tp, uint32_t *ts, uint32_t *cnt)
 {
 	if ((ts != NULL) && (cnt != NULL) &&
-	    (tcp_ack_war_time_window > 0) &&
-	    (tcp_ack_war_cnt > 0)) {
+	    (V_tcp_ack_war_time_window > 0) &&
+	    (V_tcp_ack_war_cnt > 0)) {
 		/* We are possibly doing ack war prevention */
 		uint32_t cts;
 
@@ -550,9 +550,9 @@ ctf_ack_war_checks(struct tcpcb *tp, uint32_t *ts, uint32_t *cnt)
 		if (TSTMP_LT((*ts), cts)) {
 			/* Timestamp is in the past */
 			*cnt = 0;
-			*ts = (cts + tcp_ack_war_time_window);
+			*ts = (cts + V_tcp_ack_war_time_window);
 		}
-		if (*cnt < tcp_ack_war_cnt) {
+		if (*cnt < V_tcp_ack_war_cnt) {
 			*cnt = (*cnt + 1);
 			tp->t_flags |= TF_ACKNOW;
 		} else
@@ -772,8 +772,8 @@ __ctf_process_rst(struct mbuf *m, struct tcphdr *th, struct socket *so,
 
 			KMOD_TCPSTAT_INC(tcps_badrst);
 			if ((ts != NULL) && (cnt != NULL) &&
-			    (tcp_ack_war_time_window > 0) &&
-			    (tcp_ack_war_cnt > 0)) {
+			    (V_tcp_ack_war_time_window > 0) &&
+			    (V_tcp_ack_war_cnt > 0)) {
 				/* We are possibly preventing an  ack-rst  war prevention */
 				uint32_t cts;
 
@@ -787,9 +787,9 @@ __ctf_process_rst(struct mbuf *m, struct tcphdr *th, struct socket *so,
 				if (TSTMP_LT((*ts), cts)) {
 					/* Timestamp is in the past */
 					*cnt = 0;
-					*ts = (cts + tcp_ack_war_time_window);
+					*ts = (cts + V_tcp_ack_war_time_window);
 				}
-				if (*cnt < tcp_ack_war_cnt) {
+				if (*cnt < V_tcp_ack_war_cnt) {
 					*cnt = (*cnt + 1);
 					send_challenge = 1;
 				} else
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index cc9020f89a3a..145496afa098 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -139,16 +139,14 @@ VNET_DEFINE(int, tcp_mssdflt) = TCP_MSS;
 VNET_DEFINE(int, tcp_v6mssdflt) = TCP6_MSS;
 #endif
 
-uint32_t tcp_ack_war_time_window = 1000;
+VNET_DEFINE(uint32_t, tcp_ack_war_time_window) = 1000;
 SYSCTL_UINT(_net_inet_tcp, OID_AUTO, ack_war_timewindow,
-    CTLFLAG_RW,
-    &tcp_ack_war_time_window, 1000,
-   "If the tcp_stack does ack-war prevention how many milliseconds are in its time window?");
-uint32_t tcp_ack_war_cnt = 5;
-SYSCTL_UINT(_net_inet_tcp, OID_AUTO, ack_war_cnt,
-    CTLFLAG_RW,
-    &tcp_ack_war_cnt, 5,
-   "If the tcp_stack does ack-war prevention how many acks can be sent in its time window?");
+    CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(tcp_ack_war_time_window), 0,
+   "Time interval in ms used to limit the number (ack_war_cnt) of challenge ACKs sent per TCP connection");
+VNET_DEFINE(uint32_t, tcp_ack_war_cnt) = 5;
+SYSCTL_UINT(_net_inet_tcp, OID_AUTO, ack_war_cnt, CTLFLAG_VNET | CTLFLAG_RW,
+    &VNET_NAME(tcp_ack_war_cnt), 0,
+   "Maximum number of challenge ACKs sent per TCP connection during the time interval (ack_war_timewindow)");
 
 struct rwlock tcp_function_lock;
 
@@ -2183,7 +2181,7 @@ tcp_respond(struct tcpcb *tp, void *ipgen, struct tcphdr *th, struct mbuf *m,
 
 /*
  * Send a challenge ack (no data, no SACK option), but not more than
- * tcp_ack_war_cnt per tcp_ack_war_time_window (per TCP connection).
+ * V_tcp_ack_war_cnt per V_tcp_ack_war_time_window (per TCP connection).
  */
 void
 tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
@@ -2191,7 +2189,7 @@ tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
 	sbintime_t now;
 	bool send_challenge_ack;
 
-	if (tcp_ack_war_time_window == 0 || tcp_ack_war_cnt == 0) {
+	if (V_tcp_ack_war_time_window == 0 || V_tcp_ack_war_cnt == 0) {
 		/* ACK war protection is disabled. */
 		send_challenge_ack = true;
 	} else {
@@ -2200,13 +2198,13 @@ tcp_send_challenge_ack(struct tcpcb *tp, struct tcphdr *th, struct mbuf *m)
 		if (tp->t_challenge_ack_end < now) {
 			tp->t_challenge_ack_cnt = 0;
 			tp->t_challenge_ack_end = now +
-			    tcp_ack_war_time_window * SBT_1MS;
+			    V_tcp_ack_war_time_window * SBT_1MS;
 		}
 		/*
 		 * Send a challenge ACK, if less than tcp_ack_war_cnt have been
 		 * sent in the current epoch.
 		 */
-		if (tp->t_challenge_ack_cnt < tcp_ack_war_cnt) {
+		if (tp->t_challenge_ack_cnt < V_tcp_ack_war_cnt) {
 			send_challenge_ack = true;
 			tp->t_challenge_ack_cnt++;
 		} else {
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index af82d0bfeaaa..cc982e321709 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1268,6 +1268,8 @@ VNET_DECLARE(int, tcp_log_in_vain);
 VNET_DECLARE(int, drop_synfin);
 VNET_DECLARE(int, path_mtu_discovery);
 VNET_DECLARE(int, tcp_abc_l_var);
+VNET_DECLARE(uint32_t, tcp_ack_war_cnt);
+VNET_DECLARE(uint32_t, tcp_ack_war_time_window);
 VNET_DECLARE(int, tcp_autorcvbuf_max);
 VNET_DECLARE(int, tcp_autosndbuf_inc);
 VNET_DECLARE(int, tcp_autosndbuf_max);
@@ -1319,6 +1321,8 @@ VNET_DECLARE(struct inpcbinfo, tcbinfo);
 #define	V_path_mtu_discovery		VNET(path_mtu_discovery)
 #define	V_tcbinfo			VNET(tcbinfo)
 #define	V_tcp_abc_l_var			VNET(tcp_abc_l_var)
+#define	V_tcp_ack_war_cnt		VNET(tcp_ack_war_cnt)
+#define	V_tcp_ack_war_time_window	VNET(tcp_ack_war_time_window)
 #define	V_tcp_autorcvbuf_max		VNET(tcp_autorcvbuf_max)
 #define	V_tcp_autosndbuf_inc		VNET(tcp_autosndbuf_inc)
 #define	V_tcp_autosndbuf_max		VNET(tcp_autosndbuf_max)