Best practice for NAT loopback/reflection/hairpinning behind router/fritzbox/etc?

The wiki page on Port Forward

https://wiki.ipfire.org/configuration/firewall/rules/port-forwarding#notes

says that the description given is the same as HairPin NAT or Loopback NAT

I believe that this is when you have defined ANY for the source and not just RED. Then it should also work for when you use the IP from green. At least that is my interpretation.

1 Like

Your argument makes sense, but I know that it works as well just using red. This is my WUI firewall rule NATting port 443 to my server in orange network.

Regardless whether I connect from work, or from the blue or green network, the traffic always reaches the server. No split DNS configured as well. I use the same DNS record pointing to the public IP for my home server.

I observed the same myself. With my web server, option 3 works, but for VPN it does not. Probably it is necessary an explicit NAT rule to redirect the traffic to IPFire itself when trying to connect on UDP port 1194 from green or blue. Or just RED, as it is directed to the public IP?

Hi Adolf,
there are advantages and disadvantages for both methods. The disadvantage for a NAT loopback is the amount of resources involved: packages are first transferred to the router and then back to the network. With split-DNS the packages are transfered directly between the two nodes on an network.

The advantage of the NAT loopback is, that itā€™s a solution on a lower layer (which - imho - is, where it should be :wink: ) This means that no adjustments on the client side is necessary - the client does not even notice the change. I ran in trouble with devices which switch network access very often. That could be a smartphone/tablet I carry with me and jumps between cellular network and Wifi while moving in the house or garden or a notebook/desktop with needs to connect & disconnect to VPN networks. Every network change requires to clear the DNS cache of the device and the application to resolve the DNS name again. Some versions of OpenVPN do a DNS-flush, some donā€™t (maybe itā€™s a bug or just a compile-optionā€¦) For Android devices you recommended to use the airplane mode, see: Clear DNS cache before each connection - #7 by bonnietwin
:wink: ) On Windows/Linux the command-line helps.

Other problems occur, if e.g. a smartphone app only does a dns lookup at start and will loose connection, when the network changes (some Synology apps in certain versions did this) It drives you nuts, if the audio player in the garden is fetching music from your NAS and crashes every time someone opens or closes the French window to the backyard :wink:

I ran in several issues over time until I switched to NAT loopback. This worked flawless for the last years. Consequently my preferred way was/is NAT loopback. (For heavy SMB file transfers to the NAS I use the local IP and therefore bypass the downside.)

1 Like

Iā€™m not sure, if I got it rightā€¦ but I understand a NAT-loopback as a loopback in the same subnet. The special feature of a NAT loopback is (imho) that the source has to be altered. So it is a combination of at least three rules: a DNAT, a FORWARD and a SNAT/masquerading rule (all three chains are involved)

Lets assume the following setup:

  • router with red & green network
  • red has public IP 11.22.33.44
  • green IP is 192.168.0.1 and subnet is 192.168.0.0/24
  • webserver in green network with IP 192.168.0.2, listening on port 80
  • client pc with IP 192.168.0.3 in green network with gateway set to 192.168.0.1

Iā€™m using uif ( Ubuntu Manpage: uif.conf ā€” Tool for generating optimized packet filter rules ) which makes iptable/netfilter rules more human readable but I will try to provide the corresponding iptable commands, as well. But those are not tested, the uif configuration lines are testet.

Just as a reminder: packages pass the kernel in this sequence: Prerouting (DNAT) ā†’ Filter (FORWARD) ā†’ Postrouting (SNAT/MASQ)

Goal:

  • external access from the internet to the public IP 11.22.33.44 Port 80 should be routed to 192.168.0.2:80
  • access from the green network 192.168.0.0/24 (e.g. the client pc with IP 192.168.0.3) to 11.22.33.44:80 should be routed back to 192.168.0.2:80

Problem:

  • 1st goal is straight forward:
    UIF:
    nat+ i=if_red p=tcp(/80) D=192.168.0.2
    fw+ i=if_red d=192.168.0.2 p=tcp(/80)

    IPTABLES:
    iptables -t nat -A PREROUTING -i if_red -p tcp --dport 80 -j DNAT --to-destination 192.168.0.2
    iptables -A FORWARD -i if_red -p tcp -d 192.168.0.2 --dport 80 -j ACCEPT

    all packets arriving at red interface with destination port 80 will get itā€™s destination address rewritten to 192.168.0.2 (port remains unaltered) and 2nd rule allows the packet to be forwarded to the subnet which holds 192.168.0.2 (which is green)

  • 2nd goal is NOT achieved by doing
    UIF:
    nat+ i=if_green s=192.168.0.0/24 d=11.22.33.44 p=tcp(/80) D=192.168.0.2
    fw+ i=if_green s=192.168.0.0/24 d=192.168.0.2 p=tcp(/80)

    IPTABLES:
    iptables -t nat -A PREROUTING -i if_green -p tcp -s 192.168.0.0/24 -d 11.22.33.44 --dport 80 -j DNAT --to-destination 192.168.0.2
    iptables -A FORWARD -i if_green -p tcp -s 192.168.0.0/24 -d 192.168.0.2 --dport 80 -j ACCEPT

    the nat line will rewrite the destination address to 192.168.0.2 for packages that enter via green interface with destination 11.22.33.44:80 (and the second allows all packages to be forwarded which arrive through green from green subnet and have the destination 192.168.0.2:80)
    This is not working, because the webserver will arrive an initial package from the router with a source address from the client (192.168.0.3). The answer from the webserver will go to the source address of the package (192.168.0.3) and since this is on the same subnet as the webserver itself, it will be delivered straight to the client without involving the gateway (here:the router). So the packages will go different routes (client ā†’ router ā†’ webserver) vs. (webserver ā†’ client). The firewall will log packages with invalid state. (Hint: imho an answer of a package has to take the same route, as the initial package. There are only very rare conditions, where this is not necessary - e.g. ā€œholepunchingā€)

Solution:

  • in addition to above you have to rewrite the source address of the package, so that the answer of the webserver will take the same way back (webserver ā†’ router ā†’ client)
    UIF:
    nat+ i=if_green s=192.168.0.0/24 d=11.22.33.44 p=tcp(/80) D=192.168.0.2
    fw+ i=if_green s=192.168.0.0/24 d=192.168.0.2 p=tcp(/80)
    masq+ o=if_green s=192.168.0.0/24 d=192.168.0.2 p=tcp(/80)

    IPTABLES:
    iptables -t nat -A PREROUTING -i if_green -p tcp -s 192.168.0.0/24 -d 11.22.33.44 --dport 80 -j DNAT --to-destination 192.168.0.2
    iptables -A FORWARD -i if_green -p tcp -s 192.168.0.0/24 -d 192.168.0.2 --dport 80 -j ACCEPT
    iptables -t nat -A POSTROUTING -o if_green -p tcp -s 192.168.0.0/24 -d 192.168.0.2 --dport 80 -j MASQUERADE

    instead of masquerading a snat should work as well (replace last line, not tested):
    UIF:
    nat+ o=if_green s=192.168.0.0/24 d=192.168.0.2 p=tcp(/80) S=192.168.0.1

    IPTABLES:
    iptables -t nat -A POSTROUTING -o if_green -p tcp -s 192.168.0.0/24 -d 192.168.0.2 --dport 80 -j SNAT --to-source 192.168.168.0.1

If your server you would like to reach from the green network is not in the green network but in a different subnet e.g. the orange subnet, then this is a simple NAT + PortForward and not a loopback (in my understanding of NAT loopback/relection/ā€¦) But you still need to know the public IP (which is easy, if you have a static one :wink: )

By the way: I donā€™t use a DMZ for the NAS because it is the most critical device in the network and provides several services like DHCP/DNS/RADIUS for the internal network. On the other hand, I donā€™t want to miss the conveniences of accessing it from outside. Hence I focus on securing this deviceā€¦ Itā€™s a tradeoff, of courseā€¦

I hope this provides clarification an does not cause even more confusion :wink:

Cheers,
Holger

1 Like

Jjust found this

Hi @hvacguy,

ā€¦yes, there are a few threads, that deal with nat loopback but not in combination with dynamic IPs on the public IPā€¦

And as a note to this thread you mentioned: as I said, Iā€™m not familiar with IPFire but I guess you can configure nat loopback in the WGUI by setting up the three rules I wrote in my post above (maybe the forward rule is applied automatically when WGUI is usedā€¦)- as long as the public IP (red) does not change, this is totally fine. (The nat loopback in this post does not work, because he routed back all traffic on a specific port and forgot the forward-rule. I didnā€™t reply to this, because it was 3 years oldā€¦)

@holger This was a FANTASTIC explanation that thought me new things, in layers. Also clarified different issues I had for years with understanding the routing process in Linux.

Egoistically, It would be great for our community if you would permanently adopt in your bag of tools IPFire and stick around here, transferring now and then with post like this the knowledge you have acquired in these topics. Not suggesting what you should do, just wishing it out loud :grinning:

4 Likes

Just reading this thread and I totally agree with the last iptables rule here for NAT Loopback, but it seems impossible to apply through the Firewall menu? It gets rejected:
image

is this a bug?

No, itā€™s not a bug. Firewall rules works between networks/subnets, not into the same.

1 Like

Sorry, but not true in this case although it is generally true. The firewall is operating on the packet because the original destination of the packet is the external IP. The packet then gets DNATā€™d back to the internal IP. Because of this, when the returns to the source from the target it tries to take a short cut and bypass IPfire and go straight back to the originating machine as it is on the same LAN. It then gets rejected because the originating machine is expecting the packet back from the external IP rather than the internal IP of the target server. The way to get round the issue is to force the packet back through the router by SNATing it to the router LAN IP.

To give you an actual example I have the following setup:
External IP block: 62.30.63.88/29
Server external IP: 62.30.63ā€¦91
Internal server IP: 172.17.2.51
LAN machine IP: 172.17.2.41

The LAN machine can be any IP on the LAN, a PC, another server or anything which is not mapped to a public IPā€¦

in IPFire I then have a firewall rule to map external 62.30.63ā€¦91 to internal 172.17.2.51 for all ports and protocols and an alias set up for 62.30.63ā€¦91.

Here I am trying to connect to the server on its LAN IP:

root@hostd-test:~# curl ifconfig.co
62.30.63.90
root@hostd-test:~# ssh 62.30.63.91
ssh: connect to host 62.30.63.91 port 22: Connection timed out

I then add the loopback rule:

[root@gateway ~]# iptables -I NAT_SOURCE -t nat -s 172.17.2.0/24 -d 172.17.2.51 -j SNAT --to-source 172.17.2.254

And I can connect by ssh to 62.30.63.91:

root@hostd-test:~# ssh 62.30.63.91
Last login: Thu Feb 29 09:52:14 2024 from 172.17.2.116
[root@sia2 ~]#

Please try something similar and youā€™ll see. Donā€™t try with pings as they can work because because odd quirk.

Note you wonā€™t be able to connect by ssh to 62.30.63.91 as 172.17.2.51 only accepts ssh from my LAN and from 62.30.63.88/29.

This is the rule you can not make from the WUI.

You can do.
Source ā€œgreenā€
SNAT ā€œexternal ip in redā€
Destination ā€œGreen ipā€

Have not tried this myself.

Same error.

This part of documentation is not helpful?

Yes and no. It is using Any as a source which I am not used to using where I am coming fromā€¦ I am used to having Source = Red0, in which case you need the hairpin rule. I have tested a bit and it seems to work for both Port Forwards and for Forwarding secondary IPs.

I need to have a think about Source = Any vs Source = Red0 to work out what the pros and cons are. It may be more applicable to the MultiWAN environment that I have come from where you could easily have Red0 port 80 forwarded to one server and Red1 port 80 forwarded to another, but even then I am failing to see why setting Source explicitly is advantageous.

Source ā€œAnyā€ always freak me out.
Like accidentally redirect all port traffic to server and can no longer reach the Web.

Source ā€œAnyā€
SNAT ā€œGreen interfaceā€ (assuming your server is in the green zone.)
Destination ā€œGreen server ipā€

The WUI doesnā€™t flag that rule.
Never tried it though.

That seems to work, but it creates a faulty rule in that green0 does not appear in any of the resulting iptables rules so the rule will act on all traffic from anywhere (other LANs and WAN included) heading to the LAN server.

I think I prefer the earlier solution to make the forward from Any and not Red0.