Re: [PATCH nf 2/2] netfilter: conntrack: re-init state for retransmitted syn-ack

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Florian,

On Sat, 29 Jan 2022, Florian Westphal wrote:

> TCP conntrack assumes that a syn-ack retransmit is identical to the
> previous syn-ack.  This isn't correct and causes stuck 3whs in some more
> esoteric scenarios.  tcpdump to illustrate the problem:
> 
>  client > server: Flags [S] seq 1365731894, win 29200, [mss 1460,sackOK,TS val 2083035583 ecr 0,wscale 7]
>  server > client: Flags [S.] seq 145824453, ack 643160523, win 65535, [mss 8952,wscale 5,TS val 3215367629 ecr 2082921663]
> 
> Note the invalid/outdated synack ack number.
> Conntrack marks this syn-ack as out-of-window/invalid, but it did
> initialize the reply direction parameters based on this packets content.
> 
>  client > server: Flags [S] seq 1365731894, win 29200, [mss 1460,sackOK,TS val 2083036623 ecr 0,wscale 7]
> 
> ... retransmit...
> 
>  server > client: Flags [S.], seq 145824453, ack 643160523, win 65535, [mss 8952,wscale 5,TS val 3215368644 ecr 2082921663]
> 
> and another bogus synack. This repeats, then client re-uses for a new
> attempt:
> 
> client > server: Flags [S], seq 2375731741, win 29200, [mss 1460,sackOK,TS val 2083100223 ecr 0,wscale 7]
> server > client: Flags [S.], seq 145824453, ack 643160523, win 65535, [mss 8952,wscale 5,TS val 3215430754 ecr 2082921663]
> 
> ... but still gets a invalid syn-ack.
> 
> This repeats until:
> 
>  server > client: Flags [S.], seq 145824453, ack 643160523, win 65535, [mss 8952,wscale 5,TS val 3215437785 ecr 2082921663]
>  server > client: Flags [R.], seq 145824454, ack 643160523, win 65535, [mss 8952,wscale 5,TS val 3215443451 ecr 2082921663]
>  client > server: Flags [S], seq 2375731741, win 29200, [mss 1460,sackOK,TS val 2083115583 ecr 0,wscale 7]
>  server > client: Flags [S.], seq 162602410, ack 2375731742, win 65535, [mss 8952,wscale 5,TS val 3215445754 ecr 2083115583]
> 
> This syn-ack has the correct ack number, but conntrack flags it as
> invalid: The internal state was created from the first syn-ack seen
> so the sequence number of the syn-ack is treated as being outside of
> the announced window.

I can only assume that the client is/are behind like a carrier-grade NAT
and the bogus SYN-ACK sent by the server is replying a connection attempt 
from another client. Yes, the best thing to do is to reinit the state.

> Don't assume that retransmitted syn-ack is identical to previous one.
> Treat it like the first syn-ack and reinit state.
> 
> Cc: Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxx>
> Signed-off-by: Florian Westphal <fw@xxxxxxxxx>

Acked-by: Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxx>

Best regards,
Jozsef

> ---
>  net/netfilter/nf_conntrack_proto_tcp.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
> index 88c89e97d8a2..d1582b888c0d 100644
> --- a/net/netfilter/nf_conntrack_proto_tcp.c
> +++ b/net/netfilter/nf_conntrack_proto_tcp.c
> @@ -571,6 +571,18 @@ static bool tcp_in_window(struct nf_conn *ct,
>  		sender->td_maxwin = (win == 0 ? 1 : win);
>  
>  		tcp_options(skb, dataoff, tcph, sender);
> +	} else if (tcph->syn && dir == IP_CT_DIR_REPLY &&
> +		   state->state == TCP_CONNTRACK_SYN_SENT) {
> +		/* Retransmitted syn-ack, or syn (simultaneous open).
> +		 *
> +		 * Re-init state for this direction, just like for the first
> +		 * syn(-ack) reply, it might differ in seq, ack or tcp options.
> +		 */
> +		tcp_init_sender(sender, receiver,
> +				skb, dataoff, tcph,
> +				end, win);
> +		if (!tcph->ack)
> +			return true;
>  	}
>  
>  	if (!(tcph->ack)) {
> -- 
> 2.34.1
> 
> 

-
E-mail  : kadlec@xxxxxxxxxxxxxxxxx, kadlecsik.jozsef@xxxxxxxxx
PGP key : https://wigner.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics
          H-1525 Budapest 114, POB. 49, Hungary



[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux