Page MenuHomeFreeBSD

D45894.id140609.diff
No OneTemporary

D45894.id140609.diff

diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4
--- 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 November 30, 2023
+.Dd July 6, 2024
.Dt TCP 4
.Os
.Sh NAME
@@ -699,6 +699,9 @@
.It Va insecure_syn
Use criteria defined in RFC793 instead of RFC5961 for accepting SYN segments.
Default is false.
+.It Va insecure_ack
+Use criteria defined in RFC793 for validating SEG.ACK.
+Default is false.
.It Va isn_reseed_interval
The interval (in seconds) specifying how often the secret data used in
RFC 1948 initial sequence number calculations should be reseeded.
diff --git a/sys/netinet/in_kdtrace.h b/sys/netinet/in_kdtrace.h
--- a/sys/netinet/in_kdtrace.h
+++ b/sys/netinet/in_kdtrace.h
@@ -330,6 +330,9 @@
SDT_PROBE_DECLARE(mib, tcp, count, tcps_tlpresends);
SDT_PROBE_DECLARE(mib, tcp, count, tcps_tlpresend_bytes);
+
+SDT_PROBE_DECLARE(mib, tcp, count, tcps_rcvghostack);
+SDT_PROBE_DECLARE(mib, tcp, count, tcps_rcvacktooold);
#endif
SDT_PROBE_DECLARE(ip, , , receive);
diff --git a/sys/netinet/in_kdtrace.c b/sys/netinet/in_kdtrace.c
--- a/sys/netinet/in_kdtrace.c
+++ b/sys/netinet/in_kdtrace.c
@@ -339,6 +339,8 @@
MIB_PROBE_TCP(tcps_tlpresends);
MIB_PROBE_TCP(tcps_tlpresend_bytes);
+MIB_PROBE_TCP(tcps_rcvghostack);
+MIB_PROBE_TCP(tcps_rcvacktooold);
#endif
SDT_PROBE_DEFINE6_XLATE(ip, , , receive,
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
@@ -202,6 +202,11 @@
&VNET_NAME(tcp_insecure_rst), 0,
"Follow RFC793 instead of RFC5961 criteria for accepting RST packets");
+VNET_DEFINE(int, tcp_insecure_ack) = 0;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, insecure_ack, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(tcp_insecure_ack), 0,
+ "Follow RFC793 criteria for validating SEG.ACK");
+
VNET_DEFINE(int, tcp_recvspace) = 1024*64;
#define V_tcp_recvspace VNET(tcp_recvspace)
SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace, CTLFLAG_VNET | CTLFLAG_RW,
@@ -2438,6 +2443,32 @@
/*
* Ack processing.
*/
+ if (SEQ_LT(tp->snd_max, tp->iss))
+ /* At least 2**31 - 1 byte have been sent. */
+ tp->t_flags2 |= TF2_NO_ISS_CHECK;
+ if (!V_tcp_insecure_ack) {
+ /* Send a challenge ACK for ghost ACKs. */
+ if (((tp->t_flags2 & TF2_NO_ISS_CHECK) == 0) &&
+ SEQ_LEQ(th->th_ack, tp->iss)) {
+ TCPSTAT_INC(tcps_rcvghostack);
+ /* Send challenge ACK. */
+ tcp_respond(tp, mtod(m, void *), th, m,
+ tp->rcv_nxt, tp->snd_nxt, TH_ACK);
+ tp->last_ack_sent = tp->rcv_nxt;
+ m = NULL;
+ goto drop;
+ }
+ /* Send a challenge ACK for ACKs being too old (RFC 5961). */
+ if (SEQ_LT(th->th_ack, tp->snd_una - tp->max_sndwnd)) {
+ TCPSTAT_INC(tcps_rcvacktooold);
+ /* Send challenge ACK. */
+ tcp_respond(tp, mtod(m, void *), th, m,
+ tp->rcv_nxt, tp->snd_nxt, TH_ACK);
+ tp->last_ack_sent = tp->rcv_nxt;
+ m = NULL;
+ goto drop;
+ }
+ }
switch (tp->t_state) {
/*
* In SYN_RECEIVED state, the ack ACKs our SYN, so enter
diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c
--- a/sys/netinet/tcp_stacks/bbr.c
+++ b/sys/netinet/tcp_stacks/bbr.c
@@ -7711,6 +7711,28 @@
bbr = (struct tcp_bbr *)tp->t_fb_ptr;
lost = bbr->r_ctl.rc_lost;
nsegs = max(1, m->m_pkthdr.lro_nsegs);
+ if (SEQ_LT(tp->snd_max, tp->iss))
+ /* At least 2**31 - 1 byte have been sent. */
+ tp->t_flags2 |= TF2_NO_ISS_CHECK;
+ if (!V_tcp_insecure_ack) {
+ /* Send a challenge ACK for ghost ACKs. */
+ if (((tp->t_flags2 & TF2_NO_ISS_CHECK) == 0) &&
+ SEQ_LEQ(th->th_ack, tp->iss)) {
+ TCPSTAT_INC(tcps_rcvghostack);
+ /* Send challenge ACK. */
+ ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val);
+ bbr->r_wanted_output = 1;
+ return (1);
+ }
+ /* Send a challenge ACK for ACKs being too old (RFC 5961). */
+ if (SEQ_LT(th->th_ack, tp->snd_una - tp->max_sndwnd)) {
+ TCPSTAT_INC(tcps_rcvacktooold);
+ /* Send challenge ACK. */
+ ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val);
+ bbr->r_wanted_output = 1;
+ return (1);
+ }
+ }
if (SEQ_GT(th->th_ack, tp->snd_max)) {
ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val);
bbr->r_wanted_output = 1;
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -12472,6 +12472,32 @@
INP_WLOCK_ASSERT(tptoinpcb(tp));
rack = (struct tcp_rack *)tp->t_fb_ptr;
+ if (SEQ_LT(tp->snd_max, tp->iss))
+ /* At least 2**31 - 1 byte have been sent. */
+ tp->t_flags2 |= TF2_NO_ISS_CHECK;
+ if (!V_tcp_insecure_ack) {
+ /* Send a challenge ACK for ghost ACKs. */
+ if (((tp->t_flags2 & TF2_NO_ISS_CHECK) == 0) &&
+ SEQ_LEQ(th->th_ack, tp->iss)) {
+ TCPSTAT_INC(tcps_rcvghostack);
+ /* Send challenge ACK. */
+ __ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val,
+ &rack->r_ctl.challenge_ack_ts,
+ &rack->r_ctl.challenge_ack_cnt);
+ rack->r_wanted_output = 1;
+ return (1);
+ }
+ /* Send a challenge ACK for ACKs being too old (RFC 5961). */
+ if (SEQ_LT(th->th_ack, tp->snd_una - tp->max_sndwnd)) {
+ TCPSTAT_INC(tcps_rcvacktooold);
+ /* Send challenge ACK. */
+ __ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val,
+ &rack->r_ctl.challenge_ack_ts,
+ &rack->r_ctl.challenge_ack_cnt);
+ rack->r_wanted_output = 1;
+ return (1);
+ }
+ }
if (SEQ_GT(th->th_ack, tp->snd_max)) {
__ctf_do_dropafterack(m, tp, th, thflags, tlen, ret_val,
&rack->r_ctl.challenge_ack_ts,
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -843,7 +843,8 @@
#define TF2_MBUF_QUEUE_READY 0x00020000 /* Inputs can be queued */
#define TF2_DONT_SACK_QUEUE 0x00040000 /* Don't wake on sack */
#define TF2_CANNOT_DO_ECN 0x00080000 /* The stack does not do ECN */
-#define TF2_PROC_SACK_PROHIBIT 0x00100000 /* Due to small MSS size do not process sack's */
+#define TF2_PROC_SACK_PROHIBIT 0x00100000 /* Due to small MSS size do not process sack's */
+#define TF2_NO_ISS_CHECK 0x00200000 /* Don't check SEG.ACK against ISS */
/*
* Structure to hold TCP options that are only used during segment
@@ -1085,8 +1086,11 @@
uint64_t tcps_tlpresends; /* number of tlp resends */
uint64_t tcps_tlpresend_bytes; /* number of bytes resent by tlp */
+ /* SEG.ACK validation failures */
+ uint64_t tcps_rcvghostack; /* received ACK for data never sent */
+ uint64_t tcps_rcvacktooold; /* received ACK for data too long ago */
- uint64_t _pad[3]; /* 3 TBD placeholder for STABLE */
+ uint64_t _pad[1]; /* 1 TBD placeholder for STABLE */
};
#define tcps_rcvmemdrop tcps_rcvreassfull /* compat */
@@ -1276,6 +1280,7 @@
VNET_DECLARE(int, tcp_initcwnd_segments);
VNET_DECLARE(int, tcp_insecure_rst);
VNET_DECLARE(int, tcp_insecure_syn);
+VNET_DECLARE(int, tcp_insecure_ack);
VNET_DECLARE(uint32_t, tcp_map_entries_limit);
VNET_DECLARE(uint32_t, tcp_map_split_limit);
VNET_DECLARE(int, tcp_minmss);
@@ -1323,6 +1328,7 @@
#define V_tcp_initcwnd_segments VNET(tcp_initcwnd_segments)
#define V_tcp_insecure_rst VNET(tcp_insecure_rst)
#define V_tcp_insecure_syn VNET(tcp_insecure_syn)
+#define V_tcp_insecure_ack VNET(tcp_insecure_ack)
#define V_tcp_map_entries_limit VNET(tcp_map_entries_limit)
#define V_tcp_map_split_limit VNET(tcp_map_split_limit)
#define V_tcp_minmss VNET(tcp_minmss)
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -695,6 +695,10 @@
"{N:/listen queue overflow%s}\n");
p(tcps_badrst, "\t{:ignored-in-window-resets/%ju} "
"{N:/ignored RSTs in the window%s}\n");
+ p(tcps_rcvghostack, "\t{:ack-for-never-sent-data/%ju} "
+ "{N:/ack%s for data never sent}\n");
+ p(tcps_rcvacktooold, "\t{:ack-for-too-old-data/%ju} "
+ "{N:/ack%s for too old data}\n");
p(tcps_connects, "\t{:connections-established/%ju} "
"{N:/connection%s established (including accepts)}\n");
p(tcps_usedrtt, "\t\t{:connections-hostcache-rtt/%ju} "

File Metadata

Mime Type
text/plain
Expires
Sat, May 16, 2:13 AM (12 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33094654
Default Alt Text
D45894.id140609.diff (7 KB)

Event Timeline