Cisco IOS: U-Turn NAT, NAT Reflection, NAT Hairpinning

We all have come across this issue when one of our clients fails to connect to our web-server with its public IP address. And everyone else (external) on the internet successfully establishes a connection. The reason why this is happening is because the response is coming from a different source address (the internal address of the server). And thus the client will drop this packet because it’s expecting the public IP address as the source.

Let’s consider the following topology for our demo:

We have two networks, each on a separate VLAN. One is our DMZ (VLAN 100) and the other one is for our clients (VLAN 10). 192.168.0.236 is the public IP address which translates to 192.168.100.100 at port 80, just classic port forwarding so it’s nothing special.

Without NAT reflection, the packet would look like this:

Original packet -> Source: 192.168.10.200 (Client) & Destination: 192.168.0.236

Translated packet -> Source: 192.168.100.100 & Destination: 192.168.10.200

The client expects a packet originating from 192.168.0.236 (public address), which does not happen so it drops the packet.

With NAT reflection, the packet would look like this:

Original packet -> Source: 192.168.10.200 (Client) & Destination: 192.168.0.236

Translated packet -> Source: 192.168.0.236 & Destination: 192.168.10.200

The return packet originates from 192.168.0.236 and the client will not drop this packet.

Alternative method: Split DNS

This is the most simple and elegant solution and is usually advised, but it requires hosting your own DNS servers. This does not require any configuration on the router/firewall, hence the elegance of it.

There’ll be a public facing DNS zone (e.g. example.com), which lives at your domain registrar such as CloudFlare etc. So people on the internet will be hitting the public address (192.168.0.236).

Public DNS zone: example.com

A-record www.example.com -> 192.168.0.236

Internally, e.g. Active Directory DNS, there’ll be a DNS zone as well which contains the local address instead of the public address and thus you will not require NAT reflection because the response originates from the same address (192.168.100.100).

Private DNS zone: example.com

A-record www.example.com -> 192.168.100.100

Obviously, internal clients will use the local DNS server where as everyone else uses their own public DNS server (e.g. Google’s DNS 8.8.8.8).

NVI instead of domain-based NAT

For those who refuse to use the split-DNS method, using NVI is the way to go.

Before the release of NVI, it was done with domain-based NAT (inside/outside) utilizing policy-based routing through a loopback interface. That doesn’t seem to work anymore starting from a certain IOS version. Instead, NVI should be used and is significantly easier because it doesn’t require PBR or loopback interfaces.

NVI is newer, and does not work with the domain-based ‘ip nat outside’ & ‘ip nat inside’ commands. Instead, it uses the ‘ip nat enable‘ command. If you’re familiar with NVI, then you’ll notice there’s no special configuration required to make NAT reflection work.

interface Ethernet0/0
 ip address 192.168.0.236 255.255.255.0
 ip nat enable
!
interface Ethernet0/1
 no ip address
!
interface Ethernet0/1.10
 encapsulation dot1Q 10
 ip address 192.168.10.1 255.255.255.0
 ip nat enable
!
interface Ethernet0/1.100
 encapsulation dot1Q 100
 ip address 192.168.100.1 255.255.255.0
 ip nat enable
!
ip nat source static tcp 192.168.100.100 80 interface Ethernet0/0 80
ip nat source list 100 interface Ethernet0/0 overload
ip route 0.0.0.0 0.0.0.0 192.168.0.1
!
!
!
access-list 100 permit ip 192.168.0.0 0.0.255.255 any

Leave a Reply

Your email address will not be published. Required fields are marked *