Here's a rough explanation of what can go wrong.
Before the iptables rules:
X (X=2 in OP's starting example) source IP addresses with 2^16 possible source ports and 1 destination address and port:
X * 2^16 possible connections.
After the iptables rules: X sources got squashed into one source
1 * 2^16 possible connections.
X * 2^16 connections can't be made to fit into only 2^16 connections. Source port collision will start happening more and more often, and be resolved by changing the source port, but finding a free source port not clashing with an other flow will become increasingly harder: performance degradation starts increasing, dropped packets can even start happening.
Would this happen differently if iptables were replaced with nftables? No. In both cases, they are not the parts resolving the collision. This resolution is done in the same common Netfilter backend: the nf_nat
kernel module, possibly iterating multiple times if needed and even giving up (ie: dropping the new conntrack entry and the packet having triggered its tentative creation).
The cause is the source NAT done when there's a single possible destination (the server): it should be avoided.
Possible workarounds:
don't use source NAT. An adequate routing (even if this requires multi-homing or a tunnel) put in place so 10.10.10.10 doesn't have to see a single 50.50.50.50 source should be done instead. The question doesn't explain why this SNAT is required, so it's not possible to detail further.
have multiple sources addresses to load balance with and spread the source port pressure. This can be achieved with iptables using the statistic
module to load balance to multiple SNAT
targets.
Switching to nftables is usually an improvement, but for this case, this doesn't appear to be the solution.