git: 4401d7b362b1 - stable/14 - tcp: vnetify sysctl variables ack_war_timewindow and ack_war_cnt

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Sat, 03 Aug 2024 23:21:23 UTC
The branch stable/14 has been updated by tuexen:

URL: https://cgit.FreeBSD.org/src/commit/?id=4401d7b362b18d867b50eefe1b6258760c8c9870

commit 4401d7b362b18d867b50eefe1b6258760c8c9870
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2024-07-28 20:36:34 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2024-08-03 23:19:29 +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
    Sponsored by:           Netflix, Inc
    Differential Revision:  https://reviews.freebsd.org/D46140
    
    (cherry picked from commit 4036380e029708f5d6ad7aa599ce1bba9d7c067b)
---
 share/man/man4/tcp.4                     | 20 +++++++++++++++++++-
 sys/netinet/tcp_stacks/rack_bbr_common.c | 16 ++++++++--------
 sys/netinet/tcp_subr.c                   | 24 +++++++++++-------------
 sys/netinet/tcp_var.h                    |  4 ++++
 4 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4
index 1f5cc7734bbf..da88a30bf86a 100644
--- a/share/man/man4/tcp.4
+++ b/share/man/man4/tcp.4
@@ -33,7 +33,7 @@
 .\"
 .\"     From: @(#)tcp.4	8.1 (Berkeley) 6/5/93
 .\"
-.Dd July 21, 2024
+.Dd July 28, 2024
 .Dt TCP 4
 .Os
 .Sh NAME
@@ -434,6 +434,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
@@ -1080,6 +1091,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_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 e2b120223bc0..a2424f2ab4d6 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -193,16 +193,14 @@ SYSCTL_INT(_net_inet_tcp_sack_attack, OID_AUTO, sad_low_pps,
     &tcp_sad_low_pps, 100,
     "What is the input pps that below which we do not decay?");
 #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;
 
@@ -2224,7 +2222,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)
@@ -2232,7 +2230,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 {
@@ -2241,13 +2239,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 f41fdaca13ac..9ba13b779616 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -1278,6 +1278,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);
@@ -1328,6 +1330,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)