Re: [PATCH net] netfilter: nf_nat_masquerade: recalculate TCP TS offset when port is randomized
From: xietangxin
Date: Wed Jul 01 2026 - 10:15:24 EST
On 6/29/2026 11:23 PM, Florian Westphal wrote:
> xietangxin <xietangxin@xxxxxxxxxxxxxx> wrote:
>> Problem observed in Kubernetes environments where MASQUERADE target with
>> --random-fully is configured by default. after commit
>> 165573e41f2f ("tcp: secure_seq: add back ports to TS offset") TCP short
>> connection QPS dropped from ~20000 to ~10000. This added source and
>> destination ports into TS offset calculation.
>>
>> However, with MASQUERADE --random-fully, when multiple internal connections
>> (e.g sport 10000,20000) are mapped to the same external port (e.g 30000),
>> their TS offsets are calculated as ts_offset(10000) and ts_offset(20000).
>> If the server reuses the TIME_WAIT slot from the first connection, there is
>> a chance that ts_offset(20000) < ts_offset(10000), breaking TSval
>> monotonicity for the same 4-tuple and causing RST packets:
>> Client -> Server 24870 -> 80 [SYN] TSval=2294041168
>> Server -> Client 80 -> 24870 [ACK] TSecr=2846236456
>> Client -> Server 24870 -> 80 [RST] Seq=855605690
>>
>> After nf_nat_setup_info() successfully assigns a new randomized
>> source port, recalculate the TS offset using the new port and
>> update the SYN packet's TSval accordingly.
>
> I don't think this is related to masquerade but to snat (port address
> rewrite) in general.
>
> I think you could place your new helper in nf_nat_core.c and call it
> from nf_nat_l4proto_unique_tuple() once we've found a usable tuple:
>
> 668 another_round:
> 669 for (i = 0; i < attempts; i++, off++) {
> 670 *keyptr = htons(min + off % range_size);
> 671 if (!nf_nat_used_tuple_harder(tuple, ct, attempts - i))
>
> ... here.
> 672 return;
> 673 }
>
Hi Florian,
Thank you for the insightful feedback. You are absolutely right that
this issue is releated to SNAT with port rewrite, rather masquerade.
Shifting the helper down to nf_nat_l4proto_unique_tuple() as you suggested
encounters a structural roadblock. we don't have access to the skb there.
Adding skb to all intermediate callers (like nf_nat_setup_info, get_unique_tuple)
would severely pollute the core NAT APIs.
would it be acceptable to place this logic in nf_nat_inet_fn() before do_nat?
963 do_nat:
..here
964 return nf_nat_packet(ct, ctinfo, state->hook, skb);
965
966 oif_changed:
967 nf_ct_kill_acct(ct, ctinfo, skb);
968 return NF_DROP;
969 }
Best regards,
Tangxin Xie