NAT - LAN to LAN IP Rewrite


My ISP router don't support Hairpin NAT and to overcome this issue I'm redireting all the traffic src from LAN with DST to my public IP to my NGINX Server on 443 port.
With this NAT I can access all the services behind my NGINX Server without any problem but the client IP that NGINX Server are seeing is the IP from my OpenWRT router, not the IP from the device where I make the request.
I already tried to active Enable NAT Loopback but the behaviour remains.
Important to note that on other NAT from WAN to LAN the NGINX see the correct client IP instead of OpenWRT router.
Anyone can help with this?

My Setup
ISP Router -> OpenWRT Router -> NGINX Server -> Services x/y/z

Version: OpenWrt 19.07.4
Firewall Rule - NAT LAN to LAN:

config redirect
	option src 'lan'
	option src_dport '443'
	option target 'DNAT'
	list proto 'tcp'
	option dest_ip ''
	option dest 'lan'
	option dest_port '443'
	option name 'internal NAT 443'
	option src_dip 'MYPUBLICIP'

Firewall Rule - NAT WAN to LAN:

config redirect
	option name 'https'
	option src 'wan'
	option proto 'tcp'
	option src_dport '443'
	option dest_port '443'
	option target 'DNAT'
	option dest 'lan'
	option ipset ''
	option dest_ip ''

This is expected behavior, because otherwise you would encounter the NAT loopback triangle routing problem. If the the DNATed request comes from the LAN, your NGINX machine will try to reply directly to the initiator and that would brake the connection.


That's why fw3 creates for you the necessary iptables rule(s) to SNAT the requests to the router's LAN IP address.


You can see the created SNAT rules running the following command:

iptables -t nat -nvL zone_lan_postrouting

BTW, the Firewall Rule - NAT LAN to LAN is redundant. All the necessary reflection rules should be created by the Firewall Rule - NAT WAN to LAN.

As a possible workaround, you can try an individual iptables rule for a specific LAN client to SNAT the request to the client's IP address.

An example:

iptables -t nat -A postrouting_lan_rule -p tcp -s --dport 443 -d -j SNAT --to-source
1 Like

Thanks for your explanation, it was very enlightening!
I believe reflection rule will not work on my scenario since I have a ISP router upstream of openwrt router, and that one owns the public ip address. Any traffic that hits openwrt with my public ip as DST will be forward to my ISP router. Right?

I took other approach by splitting DNS, any request inside my lan will hit the NGINX server directly and outside requests will be managed by Firewall Rule - NAT WAN to LAN.

No, it's NAT twice so the first NAT (in your OpenWrt router) will reflect off of its WAN address, which is a LAN address on the ISP router.

When someone on the Internet has several PCs behind NAT, your web server shows their house's public IP-- it can't tell which PC in the house made the request. Likewise if you're doing NAT reflection, everything inside your house is converted to one IP then reflected back.

So setting up your DNS so the PCs in your house use the server's LAN IP when they look up the public name is actually a more elegant solution.