0

I know this question exist in a dozen forms already but most were about commercial wifi routers etc.

I have an Ubuntu 20.04LTS box with a bunch of interfaces set up as a firewall/NAT box, one of the interfaces is a WAN interface.

I have a bunch of port forwards on the WAN interface (enp4s0f0) to different internal hosts, rules like these (btw all rules below are on the "nat" chain):

-A PREROUTING -i enp4s0f0 -p tcp -m tcp --dport 8181 -j DNAT --to-destination 10.0.0.50:22

(forwards incoming WAN connections at port 8181 to the host 10.0.0.50, ssh port)

But if I'm on an internal host I also want to be able to reach this port forward without going explicitly to the other internal host, for example I have a DNS that already points to the WAN IP. "Out of the box" this doesn't work (I guess because of the explicit interface specification of the WAN if), so I've tried adding stuff to iptables but neither of the two extra rules I added seem to work:

  1. -A PREROUTING -d -p tcp --dport 8181 -j DNAT --to-destination 10.0.0.50:22

  2. -A PREROUTING -i enp3s0f0 -p tcp --dport 8181 -j DNAT --to-destination 10.0.0.50:22

(enp3s0f0 is the LAN interface on the internal network)

I guess I'm missing some simple magic here.

Would be cool to have a "catch all" rule that would make all packets originating from the internal LAN destined for the WAN interface to end up there before the WAN=>LAN port forwarding rules take place, then I wouldn't have to worry to setup new matching extra rules whenever I add a WAN port forward.

UPDATE: maybe my original port forwarding rule should be changed, the one that now explicitly specifies the WAN eth interface name. I got this setup from numerous tutorials and it works fine for external clients.

2
  • Are the client and the server behind the same enp3s0f0 interface or are they on different LAN interfaces? In all those questions, the real cause is not exactly "LAN vs WAN" – more precisely it is "client & server are in the same subnet". Does that apply to your situation? Commented May 23, 2023 at 14:56
  • @user1686 They are on the same LAN, but I'm trying to get the LAN hosts to reach the server on the WAN IP, as that is the IP registred on DNS for the service I run. So for example, if example.com resolves to the WAN IP, I want to let all hosts reach the WAN=>LAN port forward iptables rule, regardless of if the client is coming from the internet or from the internal LAN (or from another of the internal LANs for that matter)
    – BjornW
    Commented May 23, 2023 at 15:48

1 Answer 1

2

The usual answer to this question is "You need NAT loopback / NAT hairpinning".

As mentioned in a few answers, the actual problem with loopback NAT is that the source IP address of such "loopback port-forwarded" connections – the client's LAN address – is seen as a local address for the destination server (being in the same LAN), which causes replies to the client to be sent directly and not via the router.

So what the "hairpinning" workaround does is NAT the source address as well. It's not just a modification to your DNAT rule – it's a completely separate SNAT rule that needs to apply to the same packets. (Though, yes, you do need to relax the -i match from your DNAT rules as well.)

-A POSTROUTING -o enp3s0f0 -s 10.0.0.0/24 -j MASQUERADE
[or]
-A POSTROUTING -o enp3s0f0 -m conntrack --ctstate DNAT -j MASQUERADE

(If I remember correctly, iptables does not allow -i matching in POSTROUTING, although that would be useful here.)

The SNAT workaround would be unnecessary if your clients and servers were in different LAN subnets (e.g. different VLANs or just different Ethernet interfaces on the external router), as then traffic between them would always go through the router no matter what.


In more detail:

  1. Client sends a request "client→WANip". The request goes towards the router's MAC.
  2. Router DNATs it to become "client→server" and forwards it towards the server.
  3. Server receives the "client→server" request, then sends a "server→client" reply back. This goes directly to the client's MAC, bypassing the router, so the DNAT is not undone.
  4. Client receives a reply "server→client", which doesn't match any known connection – the client was expecting to receive "WANip→client" instead – so the client discards the received reply.

With the SNAT workaround:

  1. Client sends a request "client→WANip". The request goes towards the router's MAC.
  2. Router DNATs it to become "client→server", then additionally SNATs it to look like "router→server", then forwards it towards the server.
  3. Server receives the "router→server" request and sends a "server→router" reply back. This goes to the router's MAC.
  4. Router receives the "server→router" reply, un-SNATs it to become "server→client", and un-DNATs it to become "WANip→client", then forwards it to the client.
  5. Client receives a reply "WANip→client" which matches the original request.
6
  • Hi, very interesting, so you mean the TCP connection probably succeeded in reaching the (internal) server, but it's reply packets aren't matched in the router's NAT connection table, because they are destined to a local IP (the client's local source IP)? I'll test this. Also, with "relaxing the -i match" do you suggest replacing the -i <wan if> with -d <wan ip> ?
    – BjornW
    Commented May 23, 2023 at 16:39
  • 1
    Yes, but it's not quite "aren't matched in the router", they don't even go through the router – the replies are getting sent directly to the client's MAC. (So even if they go through the physical "router" device, they still just take a shortcut through the hardware switch and back out; they aren't seen by the router's OS.) Commented May 23, 2023 at 16:41
  • Ah, yes of course... so with SNAT the packet going "back" to the server on the LAN, get the source rewritten to point back to the router's LAN interface instead of the original client's LAN IP
    – BjornW
    Commented May 23, 2023 at 18:06
  • Ok I've done some more tests. Unfortunately there are side-effects - now the port-forwards on incoming connections from the WAN, are SNATed to look like they come from the router's LAN interface. This is obviously dangerous as it makes it impossible to log the connections on the server and/or setup firewall rules on the server inside the LAN. I tried the second option, that only applied it to ctstate DNAT, however the port forwards from WAN are also in the DNAT state. Somehow I need to additionally discard the connections from SNAT, that originated from the physical WAN side!...
    – BjornW
    Commented May 23, 2023 at 20:21
  • Unfortunately, the "side effect" is precisely what makes the whole thing work. If you want to avoid it, split the network into two subnets so that hairpinning would no longer be an issue. Until then, make sure the SNAT/MASQ rule checks for -s, or use something like a fwmark to limit what the SNAT applies to. Commented May 23, 2023 at 20:23

You must log in to answer this question.

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