Can't get NAT Loopback to work with two NAT networks

Hi there, my current configuration is as follows:

LAN static ip + dhcp (Computers are connected here) (Allowed forward to: DMZ + WAN)
WAN: DHCP client to ISP
DMZ: static ip (Servers are connected here) (Allowed forward to: LAN + WAN)

SSH: Incoming from WAN port 22 > Forward > DMZ port 22 (Enable NAT Loopback enabled)

The problem that I am having is that the NAT loopback rules are only created for the DMZ network.

iptables -t nat -A zone_wan_prerouting -p tcp -m tcp --dport 22 -m comment --comment "!fw3: SSH" -j DNAT --to-destination
iptables -t nat -D zone_DMZ_prerouting -p tcp -s -d 214.***.**.***/ -m tcp --dport 22 -m comment --comment "!fw3: SSH (reflection)" -j DNAT --to-destination
iptables -t nat -A zone_DMZ_prerouting -p tcp -s -d 214.***.**.***/ -m tcp --dport 22 -m comment --comment "!fw3: SSH (reflection)" -j DNAT --to-destination
iptables -t nat -D zone_DMZ_postrouting -p tcp -s -d -m tcp --dport 22 -m comment --comment "!fw3: SSH (reflection)" -j SNAT --to-source
iptables -t nat -A zone_DMZ_postrouting -p tcp -s -d -m tcp --dport 22 -m comment --comment "!fw3: SSH (reflection)" -j SNAT --to-source


I tried adding to the Custom Rules, connection from the LAN network worked, but public addresses trying to connect to my public ip were blocked.

iptables -t nat -A zone_lan_prerouting -p tcp -s -d 214.***.**.***/ -m tcp --dport 22 -m comment --comment "!fw3: SSH (reflection)" -j DNAT --to-destination
iptables -t nat -A zone_lan_postrouting -p tcp -s -d -m tcp --dport 22 -m comment --comment "!fw3: SSH (reflection)" -j SNAT --to-source

Please let me know if you know anything that might help. I am here to give more information if needed.

tldr: One NAT loopback only works for DMZ network, not for LAN.

1 Like

@electrogamez, welcome to the community!

"NAT Loopback" as noted in OpenWrt works on the specific IP in question. I believe this term has other definitions on different router distros (i.e. DD-WRT).

If you're trying to reach a host by WAN IP/port from another network:

  • Use its local IP/port instead
  • Setup a local DNS entry for the LAN IP
  • You'll have to make an explicit redirect/port forward - that fixes the DST IP and drops it back in the SRC network for forwarding with the local IP

The latter suggestion is not recommended by regulars in the forum (it takes the most CPUs out of the three options).



Thanks for your response. I did end up using my local DNS server to change the DNS entry for my domains.


Record registered by my DNS service: > 214.**.**.***
My local DNS: >

And this does work just as you would expect. I was planning to only use that as a workaround, but after reading you message I came to understand that that is the better solution as it eliminates the need for CPU heavy routes?

If you could be so kind to confirm my current understanding on this matter, that would be awesome. regards to what?

Yes, your example is according to my suggestion:

...yep, a firewall rule (including a "NAT Loopback" rule) would mean that the CPU is handling it.


Thanks, I wanted to make sure that this setup is the most ideal for my configuration. Thank you so much!

The problem with the local DNS entry approach is that it only works for clients that are using the local DNS server, and you still have to add firewall rules to allow the relevant traffic between zones.

I hit the same problem, where loopback to machines in my lan zone would work for clients in my lan zone, but not for clients in my guest zone. This seems to be by design, but it seems like a slightly odd design to me - it means that everyone in the entire world can access these forwarded external ports except for people on my guest network...

I ended up writing a script which identifies port forwarding rules for a specific zone/subnet and adds new rules to allow loopback from all my local zones:


# Zone and subnet for original port forward rules

# Subnet from which port forwarding loopback connections will be allowed

echo "Configuring port forwarding loopback rules for guest network..."

# Get the port forwarding loopback rules from the original zone
original_rules=`iptables -t nat -S zone_${original_zone}_prerouting | grep "!fw3:.*(reflection)" ; \
                iptables -t nat -S zone_${original_zone}_postrouting | grep "!fw3:.*(reflection)"`

# Prepend "iptables -t nat" command
# Replace the original subnet with the new subnet
# Specify the generic "prerouting_rule" chain for DNAT rules
# Specify the generic "postrouting_rule" chain for SNAT rules
# Edit the comment
new_rules=`echo "$original_rules" | sed -e 's|^|iptables -t nat |g'                                  \
                                        -e "s|${original_subnet}|${new_subnet}|g"                    \
                                        -e "s|zone_${original_zone}_prerouting|prerouting_rule|g"    \
                                        -e "s|zone_${original_zone}_postrouting|postrouting_rule|g"  \
                                        -e 's|!fw3: |ALL ZONES: |g'`

# Create a script containing the new rules, and run it
# (We could just run the commands here directly, but it's nice to have a record of what we did)
echo "$new_rules" >/tmp/
chmod 755 /tmp/

echo "    Added `echo "$new_rules" | wc -l` rules"

I added a line to my custom firewall rules script to call the script above, but there's one additional wrinkle - the generic pre/postrouting chains get cleared when the firewall gets reloaded, and the custom firewall script does not get executed, so you lose these rules. So I modified /etc/config/firewall so that the custom firewall script does get executed on firewall reload:

config include
        option path '/etc/firewall.user'
        option reload '1'    <---------------

You just stated why:

It's also noted above:

I think you simply confuse other router distro's firewall designs with OpenWrt's.

I assure you when some of your zones are public subnets, it makes a lot of sense. I don't want my router to [incorrectly] guess that I want traffic to cross zones (and possibly routing policies, etc).

Because other routers magically add rules you never see (or more specifically, probably don't use zone-based firewalling), may make it convenient; but probably less safe.


This looks like overkill.
You should just create a separate redirect for each source zone:


You can easily adapt my script to do that - just change the new_subnet value. In fact I originally wrote it to target my guest zone/subnet specifically, but in my particular use case I don't see any reason not to allow all my internal zones to access my lan forwarded ports (given that I'm already exposing them to the world), so I modified the script to open them up to so I don't have to come back and change this if I add more zones in future.

Basically I wrote the script because I'm just lazy and I don't want to have to worry about manually adding rules every time I add or modify a port forward. Laziness is the driver behind most of my scripts :grinning:

1 Like

Hi, I tried out your script but it does not seem to work, it makes the rules and everything but traffic is still not allowed.

Do you have any additional forwarding rules setup?


The rules were working just fine, I was still using my local DNS so I tried conencting to the wrong ip.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.