Hairpin NAT (LAN <-> DMZ)

after trying for countless hours, I’m about to give up.
coming from EdgeOS, I thought this would be easier…
I have everything else up and running: the webserver is
reachable from the internet, the VPN works and hosts on
the LAN subnet can’t be reached from DMZ but the other
way it’s possible. the only thing I seem to be unable to
get running is Hairpin NAT. it drives me crazy. I read
the docs, searched the forum for hours. no success so far.

any hints would be greatly appreciated, thnx!

regards,
michael

irrelevant stuff (DNS; VPN; DHCP; etc) left out.

192.168.1.1/24 LAN VyOS (eth0)

10.10.10.1/24 DMZ VyOS (eth2)
10.10.10.150/24 WWW server

X.X.X.X WAN VyOS (eth1)

set firewall all-ping 'enable'
set firewall broadcast-ping 'disable'
set firewall config-trap 'disable'
set firewall ipv6-receive-redirects 'disable'
set firewall ipv6-src-route 'disable'
set firewall ip-src-route 'disable'
set firewall log-martians 'enable'
set firewall name DMZ-ISOLATE default-action 'accept'
set firewall name DMZ-ISOLATE rule 1 action 'drop'
set firewall name DMZ-ISOLATE rule 1 description 'DROP DMZ to LAN'
set firewall name DMZ-ISOLATE rule 1 destination address '192.168.1.0/24'
set firewall name DMZ-ISOLATE rule 1 log 'disable'
set firewall name DMZ-ISOLATE rule 1 protocol 'all'
set firewall name DMZ-ISOLATE rule 1 state established 'disable'
set firewall name DMZ-ISOLATE rule 1 state invalid 'enable'
set firewall name DMZ-ISOLATE rule 1 state new 'enable'
set firewall name DMZ-ISOLATE rule 1 state related 'disable'
set firewall name WAN-IN default-action 'drop'
set firewall name WAN-IN rule 10 action 'accept'
set firewall name WAN-IN rule 10 state established 'enable'
set firewall name WAN-IN rule 10 state related 'enable'
set firewall name WAN-IN rule 20 action 'drop'
set firewall name WAN-IN rule 20 description 'Drop invalid state'
set firewall name WAN-IN rule 20 state invalid 'enable'
set firewall name WAN-IN rule 50 action 'accept'
set firewall name WAN-IN rule 50 destination address '10.10.10.150'
set firewall name WAN-IN rule 50 destination port '80'
set firewall name WAN-IN rule 50 protocol 'tcp'
set firewall name WAN-IN rule 50 state new 'enable'
set firewall name WAN-LOCAL default-action 'drop'
set firewall name WAN-LOCAL rule 20 action 'accept'
set firewall name WAN-LOCAL rule 20 icmp type-name 'echo-request'
set firewall name WAN-LOCAL rule 20 protocol 'icmp'
set firewall name WAN-LOCAL rule 20 state new 'enable'
set firewall name WAN-LOCAL rule 30 action 'drop'
set firewall name WAN-LOCAL rule 30 destination port '22'
set firewall name WAN-LOCAL rule 30 protocol 'tcp'
set firewall name WAN-LOCAL rule 30 recent count '4'
set firewall name WAN-LOCAL rule 30 recent time '60'
set firewall name WAN-LOCAL rule 30 state new 'enable'
set firewall name WAN-LOCAL rule 31 action 'accept'
set firewall name WAN-LOCAL rule 31 destination port '22'
set firewall name WAN-LOCAL rule 31 protocol 'tcp'
set firewall name WAN-LOCAL rule 31 state new 'enable'
set firewall name WAN-LOCAL rule 40 action 'accept'
set firewall name WAN-LOCAL rule 40 description 'Allow established/related'
set firewall name WAN-LOCAL rule 40 state established 'enable'
set firewall name WAN-LOCAL rule 40 state related 'enable'
set firewall name WAN-LOCAL rule 50 action 'drop'
set firewall name WAN-LOCAL rule 50 description 'Drop invalid state'
set firewall name WAN-LOCAL rule 50 state invalid 'enable'
set firewall receive-redirects 'disable'
set firewall send-redirects 'enable'
set firewall source-validation 'disable'
set firewall syn-cookies 'enable'
set firewall twa-hazards-protection 'disable'
set interfaces ethernet eth0 address '192.168.1.1/24'
set interfaces ethernet eth0 description 'LAN'
set interfaces ethernet eth0 ip 'enable-proxy-arp'
set interfaces ethernet eth1 address 'dhcp'
set interfaces ethernet eth1 description 'WAN'
set interfaces ethernet eth1 firewall in name 'WAN-IN'
set interfaces ethernet eth1 firewall local name 'WAN-LOCAL'
set interfaces ethernet eth2 address '10.10.10.1/24'
set interfaces ethernet eth2 description 'DMZ'
set interfaces ethernet eth2 firewall in name 'DMZ-ISOLATE'
set nat destination rule 100 description 'allow http -> webserver'
set nat destination rule 100 destination port '80'
set nat destination rule 100 inbound-interface 'eth1'
set nat destination rule 100 protocol 'tcp'
set nat destination rule 100 translation address '10.10.10.150'
set nat destination rule 110 description 'Hairpin NAT'
set nat destination rule 110 destination address 'IP_ADDRESS_WAN'
set nat destination rule 110 destination port '80'
set nat destination rule 110 inbound-interface 'eth1'
set nat destination rule 110 protocol 'tcp'
set nat destination rule 110 translation address '10.10.10.150'
set nat destination rule 110 translation port '80'
set nat source rule 100 outbound-interface 'eth1'
set nat source rule 100 source address '192.168.1.0/24'
set nat source rule 100 translation address 'masquerade'
set nat source rule 110 outbound-interface 'eth1'
set nat source rule 110 source address '10.10.10.0/24'
set nat source rule 110 translation address 'masquerade'
set nat source rule 120 description 'Hairpin NAT'
set nat source rule 120 destination address '10.10.10.150'
set nat source rule 120 destination port '80'
set nat source rule 120 outbound-interface 'eth1'
set nat source rule 120 protocol 'tcp'
set nat source rule 120 source address '192.168.1.0/24'
set nat source rule 120 source port '80'
set nat source rule 120 translation address 'masquerade'

I believe your problem is the destination address on the source hairpin nat rule. You would want that to be your actual public WAN address (whatever the DNS is resolving to externally).

Just glancing at it quickly while I’m mobile but that’s what stood out.

thnx, kroy! I’m pretty sure that I alreay tried this…

edited the NAT rules like shown below. still no luck.

set nat destination rule 100 description 'http -> webserver'
set nat destination rule 100 destination port '80'
set nat destination rule 100 inbound-interface 'eth1'
set nat destination rule 100 protocol 'tcp'
set nat destination rule 100 translation address '10.10.10.150'
set nat destination rule 110 description 'Hairpin NAT'
set nat destination rule 110 destination address 'IP_ADDRESS_WAN'
set nat destination rule 110 destination port '80'
set nat destination rule 110 inbound-interface 'eth1'
set nat destination rule 110 protocol 'tcp'
set nat destination rule 110 translation address '10.10.10.150'
set nat destination rule 110 translation port '80'
set nat source rule 100 outbound-interface 'eth1'
set nat source rule 100 source address '192.168.1.0/24'
set nat source rule 100 translation address 'masquerade'
set nat source rule 110 outbound-interface 'eth1'
set nat source rule 110 source address '10.10.10.0/24'
set nat source rule 110 translation address 'masquerade'
set nat source rule 120 description 'Hairpin NAT'
set nat source rule 120 destination address 'IP_ADDRESS_WAN'
set nat source rule 120 destination port '80'
set nat source rule 120 outbound-interface 'eth1'
set nat source rule 120 protocol 'tcp'
set nat source rule 120 source address '192.168.1.0/24'
set nat source rule 120 source port '80'
set nat source rule 120 translation address 'masquerade'

Okay, so I hacked this out in my lab. In the example, eth0.10 is the LAN interface

Here is a working example:

 admin@edge# show nat source rule 103
 destination {
     address 10.22.22.67
     port 32400
 }
 outbound-interface eth0.10
 protocol tcp
 source {
     address 10.22.22.0/24
 }
 translation {
     address masquerade
 }
 
admin@edge# show nat destination rule 103
 description Plex
 destination {
     address WAN_IP
     port 32400
 }
 inbound-interface eth0.10
 protocol tcp
 translation {
     address 10.22.22.67
 }

And a request from inside the network:

$ curl http://WAN_IP:32400
<html><head><script>window.location = window.location.href.match(/(^.+\/)[^\/]*$/)[1] + 'web/index.html';</script><title>Unauthorized</title></head><body><h1>401 Unauthorized</h1></body></html>#

thnx! will try tomorrow…

regards,
michael

I have it up and running! even though the www server is in the DMZ (eth2) and the WAN interface is on eth1, the inbound-interface of the NAT destination rule needs to be set to eth0 (LAN). I’m not sure if I can follow the logic :wink:

set nat destination rule 100 description 'http -> webserver'
set nat destination rule 100 destination port '80'
set nat destination rule 100 inbound-interface 'eth1'
set nat destination rule 100 protocol 'tcp'
set nat destination rule 100 translation address '10.10.10.150'
set nat destination rule 110 description 'Hairpin NAT'
set nat destination rule 110 destination address 'WAN_IP'
set nat destination rule 110 destination port '80'
set nat destination rule 110 inbound-interface 'eth0'
set nat destination rule 110 protocol 'tcp'
set nat destination rule 110 translation address '10.10.10.150'
set nat source rule 100 outbound-interface 'eth1'
set nat source rule 100 source address '192.168.1.0/24'
set nat source rule 100 translation address 'masquerade'
set nat source rule 110 outbound-interface 'eth1'
set nat source rule 110 source address '10.10.10.0/24'
set nat source rule 110 translation address 'masquerade'
set nat source rule 120 description 'Hairpin NAT'
set nat source rule 120 destination address '10.10.10.150'
set nat source rule 120 destination port '80'
set nat source rule 120 outbound-interface 'eth0'
set nat source rule 120 protocol 'tcp'
set nat source rule 120 source address '192.168.1.0/24'
set nat source rule 120 translation address 'masquerade'

Hi Michael,

Noticed this post and just to clarify that the following change was needed.

You are doing hairpin nat for devices from LAN to DMZ so they can access the webserver with the WAN_IP.
This traffic flows from eth0 to eth2, you only use the IP address of eth1 (WAN) but traffic does not use this interface.
Inbound-interface is where the traffic for that rules originates.

1 Like