1

I have a "client-server" setup composed of one Wireguard server computer and one client, both under their respective NAT. I want these to communicate without port forwarding on the client's router. Obviously, I still need port forwarding in the server's router.

According to this comment one can leverage stateful UDP firewall if server's replies come from the very same port the client used to reach it. To do that, I set ListenPort to 58120 on both ends:

[Interface]
ListenPort = 51820
...snip...

Now with tcpdump executed on client's router I can prove packets are going out with source port 51820 and destination port 51820. Same with tcpdump executed on server's router: outgoing packets with source and destination set to 51820.

In the incoming direction though, client's router shows that packets come from port 1025. It looks like server side NAT changed port 51820 to 1025. Is this because port 51820 is already occupied by the port forwarding? How can I have source and destination ports equal so that the client router detects a UDP "connection"?

Implementation detail: both firewalls and NATs are iptables-driven.

1 Answer 1

1

According to this comment one can leverage stateful UDP firewall if server's replies come from the very same port the client used to reach it.

That's not what the comment says. The ports don't have to be equal; they only need to be symmetric. That is, if packets go out with source port 51820 and destination port 28150, the NAT will expect inbound packets to be from port 28150 to 51820 instead.

(Take a look at e.g. DNS requests – you won't see packets with 53→53, you'll see [random]→53 and the firewall will just expect replies with 53→[random].)

In the incoming direction though, client's router shows that packets come from port 1025. It looks like server side NAT changed port 51820 to 1025. Is this because port 51820 is already occupied by the port forwarding?

More likely it's because the NAT is already tracking another UDP conversation with this destination that uses the same local port (but perhaps coming from a different internal IP address, or going to a different remote port).

The standard SNAT / MASQUERADE module in iptables doesn't look at what port-forwarding rules you have – it only has information about conntrack state (the currently tracked flows), but it will try to rewrite the local port to ensure uniqueness of the inbound host:port (see nf_nat_used_tuple).

Check conntrack -L -p udp on the gateway; you might want to flush old states if you're frequently editing the NAT rules for experiments.

Some NAT implementations in gateways use a custom iptables NAT module and always change the source port of all outbound connections. This usually goes together with the term "Symmetric NAT" (as opposed to the more lenient "Cone NAT" that standard iptables implements).

Relevant article (from developers of a WireGuard-based VPN app): https://tailscale.com/blog/how-nat-traversal-works/

2
  • OK, thank you, very informative post. Still this does not answer how I can make the NAT preserve the outbound port. (to ease reading allow me to repeat that the server computer wants to send a packet with the correct source port, but its gateway rewrites it to 1025). Commented Jul 22, 2022 at 22:15
  • Never mind, I solved it. The switch the server is connected to is unmanaged. The server still had the untagged LAN network interface active (eth0), along with the tagged one for the DMZ (eth0.3). As soon as I deactivated the eth0, ping started to work. Thank you again for your informative post, that allowed me not to fiddle with iptables too much. Commented Jul 22, 2022 at 22:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .