With previous commit https://github.com/torvalds/linux/commit/be0502a ("netfilter: conntrack: tcp: only close if RST matches exact sequence") to fight against TCP in-window reset attacks, current version of netfilter will keep the connection state in ESTABLISHED, but lower the timeout to that of CLOSE (10 seconds by default) for in-window TCP RSTs, and wait for the peer to send a challenge ack to restore the connection timeout (5 mins in tests). However, malicious attackers can prevent incurring challenge ACKs by manipulating the TTL value of RSTs. The attacker can probe the TTL value between the NAT device and itself and send in-window RST packets with a TTL value to be decreased to 0 after arriving at the NAT device. This causes the packet to be dropped rather than forwarded to the internal client, thus preventing a challenge ACK from being triggered. As the window of the sequence number is quite large (bigger than 60,000 in tests) and the sequence number is 16-bit, the attacker only needs to send nearly 60,000 RST packets with different sequence numbers (i.e., 1, 60001, 120001, and so on) and one of them will definitely fall within in the window. Therefore we can't simply lower the connection timeout to 10 seconds (rather short) upon receiving in-window RSTs. With this patch, netfilter will lower the connection timeout to that of CLOSE only when it receives RSTs with exact sequence numbers (i.e., old_state != new_state). Signed-off-by: yyxRoy <979093444@xxxxxx> --- net/netfilter/nf_conntrack_proto_tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index ae493599a..d06259407 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1280,7 +1280,8 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct, if (ct->proto.tcp.retrans >= tn->tcp_max_retrans && timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS]) timeout = timeouts[TCP_CONNTRACK_RETRANS]; - else if (unlikely(index == TCP_RST_SET)) + else if (unlikely(index == TCP_RST_SET) && + old_state != new_state) timeout = timeouts[TCP_CONNTRACK_CLOSE]; else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && -- 2.34.1