Score:0

How to prevent netfilter to automatically change the source ports

jp flag

I observed that netfilter changes the source port when a connection is established in the conntrack module. I need to prevent this behavior.

Here is what I have done to reproduce my problem:

  1. I create a netfilter rule that will perform DNAT from port 2002 to 2003

sudo iptables -w -t nat -A OUTPUT -s 192.168.30.3 -d 192.168.30.1 -p udp --sport 2001 --dport 2002 -j DNAT --to-destination :2003

  1. I then create a conntrack entry to simulate a connection from 192.168.30.1:2001 (My computer) to 192.168.30.1:2003

sudo /sbin/conntrack -I -s 192.168.30.1 -d 192.168.30.3 -p udp --sport 2003 --dport 2001 --timeout 100000

  1. Eventually, I perform a connection to 192.168.30.1:2002 from my computer with source port 2001:

sudo nc -u -p 2001 192.168.30.1 2002

Due to the netfilter DNAT rule, I expected an output packet with destination port 2003 and source port 2001. However, on wireshark I observed the source port changed to a random number. I guess this is because my computer considers that there is an existing connection on port 2001 (due to the conntrack entry) and then prevents the source port to be 2001 (right?). But I don't want this behavior? How can I force the use of the port number 2001?

Tom Yan avatar
in flag
I don't think this has anything to do with DNAT or netfilter. Rather it's just the behavior of `nc`.
sebastien dontneedtoknowthat avatar
jp flag
I am pretty sure it is not the behavior of `nc` (at least because my packet reaches my DNAT rule with the original source port. )
Score:0
in flag

For the DNAT to work (in the sense that, for the program on to be able to recognize the replies), "reverse NAT" that changes the source port of the replying traffics from 192.168.30.1 (to 192.168.30.3:2001) from 2003 to 2002 will need to be performed.

However, when there are traffics coming from 192.168.30.1:2003 to 192.168.30.3:2001 that from conntrack's point of view are not a consequence of the DNAT (because as per conntrack entry created, the host is not the one that initiated the connection), the reverse NAT will be inappropriate.

Therefore, netfilter is "forced" to also perform SNAT for the traffics match with the DNAT rule, so that it can differentiate the replying traffics (that is also from 192.168.30.1:2003) by the destination 192.168.30.3:$random.

I assume netfilter will either perform reverse NAT for DNAT (which is an SNAT) before reverse NAT for SNAT (which is a DNAT), or manage to use the destination before the reverse NAT for SNAT (i.e. 192.168.30.3:$random) as matching for the reverse NAT for DNAT, otherwise the forced SNAT will be pointless. (In the non-reversal case, however, neither of these is true AFAIK: DNAT will be performed in PREROUTING before SNAT in INPUT, and destination matching in the SNAT rule, if any, will use the value resulted in the DNAT)


The thing is, the story above / the "problem" in your question hardly make any sense in reality. Take a two-host wireguard VPN as example: suppose you want to have Endpoint= set on both hosts (so that either of them can initiate the communication) and do not want the values to be "updated" unexpectedly because of the forced SNAT (assuming that could actually be triggered), what you should do is simply an "always-on" SNAT that "complements" DNAT / is equivalent to the reserve NAT:

iptables -t nat -A INPUT -s 192.168.30.1 -d 192.168.30.3 -p udp --sport 2003 --dport 2001 -j SNAT --to-source :2002

which is normally not necessary in the client-server model because of the automatic reverse NAT for the DNAT.

P.S. You are still not supposed to reach 192.168.30.1:2003 by 192.168.30.1:2003 though, otherwise the forced source NAT will also occur if you reach it again by 192.168.30.1:2002 before the conntrack entry of the former is dropped. The additional SNAT rule in INPUT should not cause you extra trouble either.

Score:0
in flag

NAT changes source port to reduce the risk of a port conflict, what should happen if that sport 2002 is already busy on the NAT machine?

If you have specific requirements for specific ports then you could add specific SNAT rules for that, but again, what if multiple internal clients try to use the same source port?

Here we should go back and acknowledge that NAT is a hack that was created to reduce the issue of lack of public IP-addresses. The real fix here is for everyone to have non NAT public IPs.

When talking about NAT these days we most often mean private IP-addresses behind one IP, In these cases it is actually NAPT a Similar question related to that, I was thinking about MASQUERADE target and not DNAT

Tom Yan avatar
in flag
There's no way DNAT would cause the source port to change (not for the *original* traffic) as that would mean it implied SNAT. Say if it did so, it would mean SNAT suggested by you / requested by the user to be a "second-time" SNAT, which makes no sense at all (to *one* "NAT machine"). Don't forget that for every SNAT needs "reverse DNAT" for the replies. The story you are telling here is about SNAT, yet you suggests SNAT as the solution (or workaround; whatever).
in flag
If you do NAT, mangling is done of the full packets as needed, even if you only intend for DNAT or SNAT.
Score:0
cl flag
A.B

You can set two flows that would normally collide in the conntrack lookup table (thus usually triggering a source port rewrite on the new flow to avoid the collision) to be in different conntrack zones. This additional zone property makes conntrack not match/collide with an existing flow in a different conntrack zone: no source port rewriting will happen.

For your specific example, here's a specific rule that will prevent the collision and thus prevent source port rewriting:

iptables -t raw -A OUTPUT -s 192.168.30.3 -d 192.168.30.1 -p udp --sport 2001  --dport 2002 -j CT --zone-orig 1

Normally depending on the use case, a more sensible selector is used. It's often used in the PREROUTING chain with an incoming interface as selector when routing, and often associated with a mark value so routing can be affected too.


The original use case that made this option appear is when conntrack on the same network stack (no additional network namespace) with a complex routing setup (eg: routing between 4 different private LANs using same IP addresses. eg between 192.168.1.0/24 eth0 <-> eth1 10.1.0.0/24, and again 192.168.1.0/24 eth2 <-> 10.1.0.0/24 eth3) can see two unrelated flows with same addresses/ports. As Netfilter and conntrack know nothing about routing (the conntrack lookup table includes only addresses) they must be taught to consider these flows separately by adding a zone property manually tied to the routing topology in the conntrack lookup table.

(Here's an LWN link when the feature was originally proposed.)

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.