Hairpinning is a term used to describe traffic that goes into a device (usually an ASA, but could be a router), and exits through either the same interface or perhaps another internal interface.
There are several use cases for Hairpinning that can be described, but the one that I have ran into the most is as follows:
A network has an ASA, along with a subnet of Internet IP addresses.
They have a server on the internal network or DMZ which has a static NAT to one of their Internet IP addresses, and so is available from the outside (for example, it is running a website).
They want to be able to access the server using its external IP address from the inside network.
Let’s describe the network:
Inside subnet: 10.1.0.0/24
Inside ASA IP address: 10.1.0.1
Server internal hostname: web-01.inside.local
Server internal IP address: 10.1.0.21
Server outside hostname: www.domain.com
Server outside IP address: 50.1.2.21
In a default ASA configuration (without Hairpinning), if a user on the inside network entered www.domain.com in their browser, DNS would return the outside IP address. When the request reaches the ASA, it wouldn’t know how to translate the traffic properly, so the server is unreachable.
The user could just enter the internal hostname in their browser. The browser will connect to the relevant port as expected, but things may not work as desired.
For example, host headers will not function if the server is running multiple websites. Hyperlinks which are explicitly defined with the outside hostname will not work.
An easy solution (not using the ASA) would be adding entries to the local ‘hosts’ files, or even to define the outside domain on the local DNS server in the network. To do the DNS option, you would add a new Forward lookup zone named “www.domain.com”, then in here add a blank ‘A’ record with the internal IP address. This would resolve any internal request for this domain to the internal IP address.
The drawback is that when changing the outside DNS record for any reason, the inside will also need to be updated.
Hairpinning solves this issue by telling the ASA how to translate this request so that the inside server is available to inside hosts by its outside IP address.
First, enable traffic between hosts on the same interface:
same-security-traffic permit intra-interface
Then, add a NAT rule for the traffic:
nat (inside,inside) 1 source dynamic any interface destination static 50.1.2.21 10.1.0.21
The numeral before ‘source’ states which position in the NAT table to add the rule.
Through ASDM, this is configured as follows:
Configuration > Device Setup > Interfaces
Tick the box “Enable traffic between two or more hosts connected to the same interface”
Configuration > Firewall > NAT Rules
Add a new rule with the following settings:
Match Criteria: Original Packet
Source Interface: inside Destination Interface: inside
Source Address: any Destination Address: 50.1.2.21
Service: any
Action: Translated Packet
Source NAT Type: Dynamic PAT (Hide)
Source Address: inside Destination Address: 10.1.0.21
Service: — Original –
Once the rule is added, move it towards the top of the NAT table.
Why create this as a PAT and not a static NAT? In short, to prevent asymmetric routing.
If your source address (SA) is 10.1.0.101, and you try to access the server, this is what happens.
With PAT:
Your computer creates a packet with the following addresses:
SA: 10.1.0.101
DA: 50.1.2.21
At the ASA, this is translated to:
SA: 10.1.0.1
DA: 10.1.0.21
In the same way that PAT works for general Internet access, this ensures that the reverse path from the server back to the workstation is the same as the forward path.
With a static NAT:
Your computer creates a packet with the following addresses:
SA: 10.1.0.101
DA: 50.1.2.21
At the ASA, this is translated to:
SA: 10.1.0.101
DA: 10.1.0.21
Note: The Source address is not altered in the translated packet.
Here, the server tries to reply directly to the computer over the LAN. This will fail, as the computer is expecting traffic to come back from the original DA it opened the communication with.
The above also works when the server is on a different interface, such as a DMZ. In this instance, change the destination interface as appropriate, and change the translated packet to the appropriate destination address.