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 @@ tcp_input(m, off0) * 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 @@ tcp_input(m, off0) 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 @@ tcp_input(m, off0) * 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 @@ tcp_input(m, off0) 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 */