Hairpin NAT

Having an issue with hairpin NAT, can’t seem to get it to function. Have a webserver internally. These two rules don’t seem to work. Forwarding from outside is working fine.

eth0 - external public ip
eth1 - internal ip

rule 1000 {
outbound-interface eth0
source {
address 192.168.72.0/23
}
translation {
address masquerade
}
}
rule 1100 {
description “NAT Reflection: INSIDE”
destination {
address 192.168.72.0/23
}
outbound-interface eth1
source {
address 192.168.72.0/23
}
translation {
address masquerade
}
}

Did you ever get this working? I am having the same issue and I cannot figure out why it is not working.

I guess, you are missing DNAT rule like this:

inbound-interface: any
destination-address: Public-IP
translate address: Private-IP

Here is my setup replacing 8.8.8.8 with my external IP

vyos@HOSTNAME# show nat
destination {
rule 10 {
destination {
address 8.8.8.8
port 3389
}
inbound-interface any
protocol tcp
translation {
address 192.168.1.114
port 3389
}
}
rule 20 {
destination {
address 8.8.8.8
port 2299
}
inbound-interface any
protocol tcp
translation {
address 192.168.1.111
port 2299
}
}
}
source {
rule 10 {
outbound-interface eth1
source {
address 192.168.0.0/16
}
translation {
address masquerade
}
}
rule 998 {
destination {
address 192.168.1.0/24
}
outbound-interface br0
source {
address 192.168.1.0/24
}
translation {
address masquerade
}
}
}

[edit]
vyos@HOSTNAME#

So I do have the destination nat rules for port forwarding of an RDP and additional RDP port on internal network but from inside when I telnet to those ports from a machine on the LAN I get no response to the external interface for those.

Pretty sure the hairpin nat is supposed to fix this but possibly the rule order for allowing my machines to NAT the public IP first is the issue?


Oddly enough as well if I use tshark to check packets on br0 which is where the LAN traffic would be coming out of it works fine but once I stop tshark it again stops working properly.

Oh nevermind that is because it puts the interface in promiscuous mode and it then receives the traffic. I do not have any firewall rules besides established and connected so maybe I need to do some allows

Anyone?

Hi,

This configuration works fine to a mail server.

destination {
    rule 10 {
        description "SSL & SMTP to Mail server from public"
        destination {
            address 18x.45.xx.xxx (public IP address of mail.xxxxxxxxxxxx.co.uk)
            port 25,443
        }
        inbound-interface eth0.4094
        protocol tcp
        translation {
            address 192.168.2.34 (IP address of mail server)
        }
    }
    rule 12 {
        description "Hairpin NAT mail.xxxxxxxxxxxx.co.uk to Exchange server for OWA"
        destination {
            address 18x.45.xx.xxx
            port 443
        }
        inbound-interface eth0.254
        protocol tcp
        translation {
            address 192.168.2.34
            port 443
        }
    }

source {
    rule 20 {
        description "Hairpin NAT mail.xxxxxxxxxxxx.co.uk to Exchange server for OWA"
        destination {
            address 192.168.2.34
            port 443
        }
        outbound-interface eth0.254
        protocol tcp
        translation {
            address masquerade
        }
    }

Hope it helps

2 Likes

Thanks for the update Steve. I feel dumb as I finally tried this from another machine on the LAN and I found it is working as expected just not from my machine I was testing it from since it is my main machine. Grrr so it works fine and I just have to see what is going on with that machine in regards to the traffic.

I appreciate all the replies and hope they help someone else out who has the same issue crop up. Be sure to test from other machines on the LAN.

Hello,
I have an issue similar, I’m working on this for hours but I was not able to solve.

Here is an extract of my configuration:

 destination {
     rule 4000 {
         description "Proxy"
         destination {
             address x.x.x.114
             port 80,443
         }
         inbound-interface bond1
         protocol tcp
         translation {
             address 10.0.0.190
         }
     }

 source {
     rule 1000 {
         description "NAT hairpin"
         destination {
             address 10.0.0.190
			 port 80, 443
         }
         outbound-interface bond0
		 protocol tcp
         translation {
             address masquerade
         }
     }

It’s working fine from outside, but insie my LAN I canno reach the external IP.

I’ve tried also with:

 source {
     rule 1000 {
         description "NAT hairpin"
         destination {
             address 10.0.0.0/24
         }
         outbound-interface bond0
         translation {
             address masquerade
         }
     }

I’ve found that configuraion somewhere searching with google, it seems that should create a NAT hairpin valid for all my LAN subnet. But also this is not working in my case.

Do you have any suggestion?
Am I missing something?

Thanks
Fabio

has anyone mastered this yet?
it works for me “kind of” the hairpin ability works, and the outside in works, but the issue i am having is anything that has a hairpin defined, all the connections show as coming from that IP, not the users external ip address, and network to network traffic (non-nat) translate to the public ip as well. which is rather frustrating when the PBX gets a tone of invalid requests from the outside and i try to login and it locks me out as well.

I am guessing additional filtering is needed on the hairpin to only translate on local subnet?

here is my code

nat { destination { rule 8001 { description "Hairpin - Terminal" destination { address 7X.XXX.XXX.10 } inbound-interface eth0 protocol ip translation { address 10.254.0.30 } } rule 8002 { description "Hairpin - TSGateway" destination { address 7X.XXX.XXX.11 } inbound-interface eth0 protocol ip translation { address 10.254.0.31 } } rule 8003 { description "Hairpin - WWW" destination { address 7X.XXX.XXX.13 } inbound-interface eth0 protocol ip translation { address 10.254.0.91 } } rule 8004 { description "Hairpin - Activation" destination { address 7X.XXX.XXX.14 } inbound-interface eth0 protocol ip translation { address 10.254.0.90 } } rule 8005 { description "Hairpin - Terminal2" destination { address 7X.XXX.XXX.15 } inbound-interface eth0 protocol ip translation { address 10.254.1.30 } } rule 8006 { description "Hairpin - PBX1" destination { address 7X.XXX.XXX.18 } inbound-interface eth0 protocol all translation { address 10.254.0.20 } } rule 8007 { description "Hairpin - EMAIL" destination { address 7X.XXX.XXX.12 } inbound-interface eth0 protocol all translation { address 10.254.0.50 } } rule 9001 { description "1to1 - Terminal" destination { address 7X.XXX.XXX.10 } inbound-interface eth1 protocol ip translation { address 10.254.0.30 } } rule 9002 { description "1to1 - TSGateway" destination { address 7X.XXX.XXX.11 } inbound-interface eth1 protocol ip translation { address 10.254.0.31 } } rule 9003 { description "1to1 - WWW" destination { address 7X.XXX.XXX.13 } inbound-interface eth1 protocol ip translation { address 10.254.0.91 } } rule 9004 { description "1to1 - Activation" destination { address 7X.XXX.XXX.14 } inbound-interface eth1 protocol ip translation { address 10.254.0.90 } } rule 9005 { description "1to1 - Terminal2" destination { address 7X.XXX.XXX.15 } inbound-interface eth1 protocol ip translation { address 10.254.1.30 } } rule 9006 { description "1to1 - PBX1" destination { address 7X.XXX.XXX.18 } inbound-interface eth1 protocol all translation { address 10.254.0.20 } } rule 9007 { description "1to1 - EMail" destination { address 7X.XXX.XXX.12 } inbound-interface eth1 protocol all translation { address 10.254.0.50 } } } source { rule 8001 { description "Hairpin - Terminal" destination { address 10.254.0.30 } outbound-interface eth0 protocol ip translation { address 7X.XXX.XXX.19 } } rule 8002 { description "Hairpin - TSGateway" destination { address 10.254.0.31 } outbound-interface eth0 protocol ip translation { address 7X.XXX.XXX.19 } } rule 8003 { description "Hairpin - WWW" destination { address 10.254.0.91 } outbound-interface eth0 protocol ip translation { address 7X.XXX.XXX.19 } } rule 8004 { description "Hairpin - Activation" destination { address 10.254.0.90 } outbound-interface eth0 protocol ip translation { address 7X.XXX.XXX.19 } } rule 8005 { description "Hairpin - Terminal2" destination { address 10.254.1.30 } outbound-interface eth0 protocol ip translation { address 7X.XXX.XXX.19 } } rule 8006 { description "Hairpin - PBX1" destination { address 10.254.0.20 } outbound-interface eth0 protocol ip translation { address 7X.XXX.XXX.19 } } rule 8007 { description "Hairpin - EMail" destination { address 10.254.0.50 } outbound-interface eth0 protocol ip translation { address 7X.XXX.XXX.19 } } rule 9001 { description "1to1 - Terminal" outbound-interface eth1 source { address 10.254.0.30 } translation { address 7X.XXX.XXX.10 } } rule 9002 { description "1to1 - TSGateway" outbound-interface eth1 source { address 10.254.0.31 } translation { address 7X.XXX.XXX.11 } } rule 9003 { description "1to1 - WWW" outbound-interface eth1 source { address 10.254.0.91 } translation { address 7X.XXX.XXX.13 } } rule 9004 { description "1to1 - Activation" outbound-interface eth1 source { address 10.254.0.90 } translation { address 7X.XXX.XXX.14 } } rule 9005 { description "1to1 - Terminal2" outbound-interface eth1 source { address 10.254.1.30 } translation { address 7X.XXX.XXX.15 } } rule 9006 { description "1to1 - PBX1" outbound-interface eth1 source { address 10.254.0.20 } translation { address 7X.XXX.XXX.18 } } rule 9007 { description "1to1 - EMail" outbound-interface eth1 source { address 10.254.0.50 } translation { address 7X.XXX.XXX.12 } } rule 9902 { outbound-interface eth1 source { address 10.254.0.0/18 } translation { address 7X.XXX.XXX.19 } } rule 9985 { outbound-interface eth1 source { address 10.254.64.0/18 } translation { address 7X.XXX.XXX.19 } } rule 9986 { outbound-interface eth1 source { address 10.254.128.0/18 } translation { address 7X.XXX.XXX.19 } } rule 9987 { outbound-interface eth1 source { address 10.254.192.0/18 } translation { address 7X.XXX.XXX.19 } } } }

You made my day with this clear example!!!

Thanks a lot, John

Trust me to Necro a thread, but I thought I might just follow this up for anyone else following along.

You have to be careful with Hairpinning because if you don’t properly do the “source” NAT, you end up translating ALL traffic if you’re doing pinholing, to your Internal IP. This means you can’t tell the real source IP of any traffic coming in, attacker or otherwise. You see this mentioned above by the post from @jesnofear.

So to do it properly:

[edit nat destination]
 rule 200 {
     description "Hairpin NAT for Home Assistant"
     destination {
         address <external IP/32>
         port 8123
     }
     inbound-interface eth1 [This is my LAN Interface]
     protocol tcp
     translation {
         address 192.168.0.7 [This is the Internal IP of my Home Assistant Instance]
     }
 }

[edit nat source]
 rule 200 {
     description "Hairpin NAT for Home Assistant"
     destination {
         address 192.168.0.7
         port 8123
     }
     outbound-interface eth1
     protocol tcp
     source {
         address 192.168.0.0/16 [THIS IS IMPORTANT!!!!]
     }
     translation {
         address masquerade
     }
 }

If you don’t match on the source range of your Internal Interface on the “nat source” rule, you’ll find that all traffic coming into your box from external hits this rule too and it all gets rewritten to appear from the masquerade address (the primary IP Address interface of eth1).
This is bad because you can’t tell the true external IP anymore, and any internal IP Access listing you’ve got going on on a server won’t work.

I hope this helps someone in the future.

1 Like