summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/tcp_input.c10
-rw-r--r--sys/netinet/tcp_reass.c10
-rw-r--r--sys/netinet/tcp_var.h1
3 files changed, 21 insertions, 0 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 90cda71389bb..d0c1f9b29468 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1532,6 +1532,12 @@ trimthenstep6:
* echo of our outgoing acknowlegement numbers, but some hosts
* send a reset with the sequence number at the rightmost edge
* of our receive window, and we have to handle this case.
+ * Note 2: Paul Watson's paper "Slipping in the Window" has shown
+ * that brute force RST attacks are possible. To combat this,
+ * we use a much stricter check while in the ESTABLISHED state,
+ * only accepting RSTs where the sequence number is equal to
+ * last_ack_sent. In all other states (the states in which a
+ * RST is more likely), the more permissive check is used.
* If we have multiple segments in flight, the intial reset
* segment sequence numbers will be to the left of last_ack_sent,
* but they will eventually catch up.
@@ -1570,6 +1576,10 @@ trimthenstep6:
goto close;
case TCPS_ESTABLISHED:
+ if (tp->last_ack_sent != th->th_seq) {
+ tcpstat.tcps_badrst++;
+ goto drop;
+ }
case TCPS_FIN_WAIT_1:
case TCPS_FIN_WAIT_2:
case TCPS_CLOSE_WAIT:
diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c
index 90cda71389bb..d0c1f9b29468 100644
--- a/sys/netinet/tcp_reass.c
+++ b/sys/netinet/tcp_reass.c
@@ -1532,6 +1532,12 @@ trimthenstep6:
* echo of our outgoing acknowlegement numbers, but some hosts
* send a reset with the sequence number at the rightmost edge
* of our receive window, and we have to handle this case.
+ * Note 2: Paul Watson's paper "Slipping in the Window" has shown
+ * that brute force RST attacks are possible. To combat this,
+ * we use a much stricter check while in the ESTABLISHED state,
+ * only accepting RSTs where the sequence number is equal to
+ * last_ack_sent. In all other states (the states in which a
+ * RST is more likely), the more permissive check is used.
* If we have multiple segments in flight, the intial reset
* segment sequence numbers will be to the left of last_ack_sent,
* but they will eventually catch up.
@@ -1570,6 +1576,10 @@ trimthenstep6:
goto close;
case TCPS_ESTABLISHED:
+ if (tp->last_ack_sent != th->th_seq) {
+ tcpstat.tcps_badrst++;
+ goto drop;
+ }
case TCPS_FIN_WAIT_1:
case TCPS_FIN_WAIT_2:
case TCPS_CLOSE_WAIT:
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 86e27f051cc3..8c42b4dec427 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -414,6 +414,7 @@ struct tcpstat {
u_long tcps_badsyn; /* bogus SYN, e.g. premature ACK */
u_long tcps_mturesent; /* resends due to MTU discovery */
u_long tcps_listendrop; /* listen queue overflows */
+ u_long tcps_badrst; /* ignored RSTs in the window */
u_long tcps_sc_added; /* entry added to syncache */
u_long tcps_sc_retransmitted; /* syncache entry was retransmitted */