Cisco ASA hairpinning

Cisco Pix/ASA hairpinning

The term hairpinning comes from the fact that the traffic comes from one source into a router or similar devices, makes a U-turn and goes back the same way it came.
Visualize this and you see something that looks like a hairpin.

Hairpinning is only relevant when the firewall is in routed mode since the “turnaround” of traffic is a routing decision. Also there needs to be another router
involved. If the firewall is setup to only pass traffic between interfaces no hairpinning will be taking place. Typical hairpinning is done when there is a router
inside of the firewall beyond which there is another network that needs to be reached to/from the inside network. See picture:

Another fundament for hairpinning taking place is that not all network equipment has full knowledge of the network topology. Typically these are computers with only
a default route (“default gateway”) to something but not aware of the fact that the remote network is reachable directly via the other router without taking the path
via the firewall (see picture above). If the computer had that knowledge it would never involve the firewall.
A workaround like this could be in a windows-host to add “route -p 192.168.2.0 mask 255.255.255.0 192.168.1.2” from the command prompt. However this is in most cases
not very flexible since it is a manual work at each host.

ver 6.x and prior

No hairpinning was possible. The historic reason for this was that the fact that interfaces with the same security-level was not allowed to exchange traffic was a
security fature. If you needed to isolate two interfaces from each other (but allow each of them to talk to other interfaces) you could give them the same security-
level and by design there was no traffic allowed between these interfaces no matter of access-list, nat or conduit-configuration. Unfortunately this also meant that
since traffic in an out thru the same interface was per definition “same security-level”, no hair-pinning was possible.

ver 7.0

The command “same-security” was introuduced with this version. The purpose with this command was to override the isolation between interfaces with the same
security-level. The command has 2 parameters: “permit-inter-interface” that allows traffic between different interfaces with same security-level and “permit-intra-
interface” that allows traffic thru the same interface, aka hairpinning. However, with this version the intra-interface-parameter was only functional for vpn-
traffic, for example traffic from an outside vpn-client destined to internet (full tunneling).

ver 7.2

Beginning with v7.2 the “same-security permit-intra-interface”-command becomes useful and can be used for other traffic than vpn-initiated. Now we can do hair-
pinning. So, what is needed? First of all, the “same-security permit -intra-interface”. Also we need to allow inbound traffic if we have an access-list applied
inbound on the interface. Let´s have another look at our example:

In this example we have one host at 192.168.1.100 using the firewall .1 as default gateway. The firewall has a route for the 192.168.2.0/24-network via 192.168.1.2
and the route is directly connected to both networks. Because of this configuration the traffic from 192.168.1.100 is hair-pinned back, to the router.


interface Vlan1
nameif inside
security-level 100
ip address 192.168.1.1 255.255.255.0
!
route inside 192.168.2.0 255.255.255.0 192.168.1.2 1
!
same-security-traffic permit intra-interface
!
no nat-control

All magic lies in the “same-security-traffic”-command. In the example above we have no access-list applied. If we have we must also open for that traffic:


access-list acl_inside extended permit ip 192.168.2.0 255.255.255.0 192.168.1.0 255.255.255.0
access-list acl_inside extended permit ip 192.168.1.0 255.255.255.0 192.168.2.0 255.255.255.0
access-list acl_inside extended deny ip any any
!
access-group acl_inside in interface inside

We most likely has a NAT/global configured for the inside network to be able to reach internet. If we add this to our example we kill our hair-pinning:


nat (inside) 1 0.0.0.0 0.0.0.0
global (outside) 1 interface

Now, when we try to ping from 192.168.1.100 to 192.168.2.200 we get this log output of the firewall:


%ASA-3-305006: portmap translation creation failed for icmp src inside:192.168.1.100 dst inside:192.168.2.200 (type 8, code 0)
%ASA-3-305006: portmap translation creation failed for icmp src inside:192.168.1.100 dst inside:192.168.2.200 (type 8, code 0)
%ASA-3-305006: portmap translation creation failed for icmp src inside:192.168.1.100 dst inside:192.168.2.200 (type 8, code 0)
%ASA-3-305006: portmap translation creation failed for icmp src inside:192.168.1.100 dst inside:192.168.2.200 (type 8, code 0)
%ASA-3-305006: portmap translation creation failed for icmp src inside:192.168.1.100 dst inside:192.168.2.200 (type 8, code 0)

As soon as we add ANY nat-configuration for an interface we must configure nat for all traffic from that interface, even hairpinned traffic. We do this with the static-command below. The purpose of this is to “static” translate traffic from interface “inside” to interface “inside” where the source is “192.168.1.0” (netmask 255.255.255.0 and translate the source to “192.168.1.0” (the same address). We also do the same for the 192.168.2.0-network to ensure that traffic can flow initiated in both directions.


static (inside,inside) 192.168.1.0 192.168.1.0 netmask 255.255.255.0
static (inside,inside) 192.168.2.0 192.168.2.0 netmask 255.255.255.0

The compilation of relevant configuration lines in the firewall to ackomplish this is shown here:


hostname fw
!
interface Vlan1
nameif inside
security-level 100
ip address 192.168.1.1 255.255.255.0
!
interface Vlan222
nameif outside
security-level 0
ip address dhcp setroute
!
boot system disk0:/asa725-k8.bin
!
same-security-traffic permit intra-interface
!
access-list acl_inside extended permit ip 192.168.2.0 255.255.255.0 192.168.1.0 255.255.255.0
access-list acl_inside extended permit ip 192.168.1.0 255.255.255.0 192.168.2.0 255.255.255.0
access-list acl_inside extended deny ip any any
!
nat-control
!
global (outside) 1 interface
nat (inside) 1 0.0.0.0 0.0.0.0
!
static (inside,inside) 192.168.1.0 192.168.1.0 netmask 255.255.255.0
static (inside,inside) 192.168.2.0 192.168.2.0 netmask 255.255.255.0
!
access-group acl_inside in interface inside
!
route inside 192.168.2.0 255.255.255.0 192.168.1.2 1

Ver 8.3

In this version the nat-concept is totally rewritten with a new command syntax. More about this can be read about elsewhere, but the technique is the same. This is the converted version of the configuration snippet above:


hostname fw
!
interface Vlan1
nameif inside
security-level 100
ip address 192.168.1.1 255.255.255.0
!
interface Vlan222
nameif outside
security-level 0
ip address dhcp setroute
boot system disk0:/asa831-k8.bin
!
same-security-traffic permit intra-interface
!
object network obj-192.168.1.0
subnet 192.168.1.0 255.255.255.0
object network obj-192.168.2.0
subnet 192.168.2.0 255.255.255.0
object network obj_any
subnet 0.0.0.0 0.0.0.0
object network obj_any-01
subnet 0.0.0.0 0.0.0.0
object network obj-0.0.0.0
host 0.0.0.0
!
access-list acl_inside extended permit ip 192.168.2.0 255.255.255.0 192.168.1.0 255.255.255.0
access-list acl_inside extended permit ip 192.168.1.0 255.255.255.0 192.168.2.0 255.255.255.0
access-list acl_inside extended deny ip any any
!
object network obj-192.168.1.0
nat (inside,inside) static 192.168.1.0
object network obj-192.168.2.0
nat (inside,inside) static 192.168.2.0
object network obj_any
nat (inside,outside) dynamic interface
object network obj_any-01
nat (inside,outside) dynamic obj-0.0.0.0
!
access-group acl_inside in interface inside
!
route inside 192.168.2.0 255.255.255.0 192.168.1.2 1

Assymetric routing

An issue with the configuration above is that since the firewall is stateful (which means that it keeps track of TCP-states) and the fact that traffic in one direction goes via the firewall (from 192.168.1.100 to 192.168.2.200) but the traffic in the other direction goes direct makes the firewall going bananas. If the traffic initiates from the 1-network all is fine since the firewall allowes the initial packet and never sees the return traffic. It might build a quite large list of incomplete sessions that eventually will time out, but it will work:

However, when the traffic is initiated from the 2-network the first packet that will be seen by the firewall is the second (SYN-ACK) which is not very appreciated.

Beginning with version 8.2 there is a solution for this in the “tcp state bypass”-functionality. By using this you can with MPF (modular policy framework) specify traffic that should not be handled stateful. Here is an example of doing that.
Genereally my solution to hairpinning- and/or assymetric routing-issues is to avoid it. If you have one or more routers in your topology it is probably a good idea to use that router as the default gateway instead and only direct traffic to the firewall that should pass it. The drawback from this is that internet-traffic needs to go via the router instead. However this seldom causes any trouble since the router is not stateful and has no issues with doing hairpinning.

Another solution if you need to pass WAN-traffic thru the firewall (for security reasons) can be to put the WAN-router(s) on a dedicated firewall interface.

Conclusion

Hairpinning of traffic in Cisco Pix/ASA and problems with assymetric routing can be a pain. There are workarounds but mostly assymetric issues are symptoms of bad network design rather than configuration issues.
There are more dimensions of hairpinning than just internal traffic turning around to a WAN-router. Such a common example is U-turning of VPN-traffic, for example traffic from an VPN-client going via the firewall out to internet or into another vpn-tunnel. Or spoke-hub-spoke VPN-traffic. This type of traffic seldom gives routing or assymetric issues but is more a matter of defining proxy ACL:s for vpn-traffic and not doing NAT on that traffic.

Tagged with: , ,
Posted in Cisco Security
10 comments on “Cisco ASA hairpinning
  1. Igorh says:

    Holy S…T! You ARE AWESOME! I had the same issue as Philip. Thank you! Igor

  2. Fran says:

    I have an ASA with version 8.3. This worked perfect for my TCP traffic. However, I can’t pass other kinds of traffic as there is only ‘TCP state-bypass’ functionality for the ASA. 

    When I ping, the replies are rejected because the ASA doesn’t see the incoming requests. It only sees the reply and drops the packet because there is no initial session.

    Any clue on how to bypass other non-TCP traffic?

  3. Jgilmour says:

    Wow. that explains why the NATs are weird as hell to me. Thanks for clearing this up. Coming from a 7.x environment to a 9.x environment had me scratching my head! 

  4. People like you is so usefull.
    Perfect explaning, even for a Consultant with many years with Cisco IOS. Thanks!

  5. Hello to all, since I am actually keen of reading this webpage’s post to be updated regularly.

    It carries pleasant information.

  6. click says:

    Supercomputer som en konsekvens pc gloves blevet værdifulde varer,
    plus de er også same . ømskindet .
    Som sådan de skal tilstøde tilførslerne under individuel form.
    Til dette perseverance, mange

  7. Seth says:

    Hello,
    Came across this….and this portion here at the end:
    Such a common example is U-turning of VPN-traffic, for example traffic from an VPN-client going via the firewall out to internet or into another vpn-tunnel. Or spoke-hub-spoke VPN-traffic. This type of traffic seldom gives routing or assymetric issues but is more a matter of defining proxy ACL:s for vpn-traffic and not doing NAT on that traffic

    Is what I am interested in.
    I have built a tunnel for my iPhone and I want Full Tunnel for it.
    So all traffic be sent to the ASA and then go to the outside world.
    If I browse via Safari or Chrome, nothing works.
    But certain apps do work fine, like iMessage, Facebook, WeChat
    Other apps like iTunes, App Store, Apple Weather App do not work.

    So it appears it may be DNS look up issues…>
    I tried using my internal DNS server, didn’t work.
    Then I tried setting up the VPN policy to use Google’s DNS Servers, didn’t work.

    So not sure what I can do to correct this.
    Any ideas would be appreciated.

  8. Seth says:

    Hey Jimmy,
    Here is my ASA Config (important stuff):

    : Saved
    : Written by enable_15 at 12:26:34.023 EDT Thu Oct 27 2016
    !
    ASA Version 8.2(3)
    !
    hostname CoxASA5510
    domain-name webd2ms2.com
    enable password ..Lyz3sh0DbVWcxP encrypted
    passwd 2KFQnbNIdI.2KYOU encrypted
    names
    name 10.78.0.0 Cox_Inside description Inside network behind ASA5510
    name 172.16.1.0 RemoteVPN description Remote Access Network
    name 192.168.1.0 VPNMobile description IP Pool for VPN Mobile
    dns server-group DefaultDNS
    domain-name webd2ms2.com
    same-security-traffic permit inter-interface
    same-security-traffic permit intra-interface
    object-group network Google_DNS
    network-object host 8.8.4.4
    network-object host 8.8.8.8
    object-group network DomainControllers
    network-object host 10.78.0.5
    network-object host 10.78.0.6
    access-list Inside_nat0_outbound extended permit ip Cox_Inside 255.255.255.0 VPNMobile 255.255.255.0
    access-list Outside_access_in extended permit ip VPNMobile 255.255.255.0 any
    access-list Outside_access_in extended permit ip any VPNMobile 255.255.255.0
    access-list Outside_cryptomap_5000 extended permit ip any VPNMobile 255.255.255.0
    access-list Inside_access_in extended permit ip any any
    ip local pool VPNDHCP2 172.16.1.100-172.16.1.200 mask 255.255.255.0
    ip local pool VPNMobile 192.168.1.100-192.168.1.105 mask 255.255.255.0
    global (Outside) 10 interface
    nat (Outside) 0 access-list Outside_nat0_outbound
    nat (Outside) 10 VPNMobile 255.255.255.0
    nat (Inside) 0 access-list Inside_nat0_outbound
    nat (Inside) 10 0.0.0.0 0.0.0.0
    access-group Outside_access_in in interface Outside
    access-group Inside_access_in in interface Inside
    route Outside 0.0.0.0 0.0.0.0 216.54.104.129 1
    crypto dynamic-map SYSTEM_DEFAULT_CRYPTO_MAP 65535 match address Outside_cryptomap_65535.65535
    crypto dynamic-map SYSTEM_DEFAULT_CRYPTO_MAP 65535 set transform-set ESP-AES-256-SHA
    crypto dynamic-map SYSTEM_DEFAULT_CRYPTO_MAP 65535 set reverse-route
    crypto dynamic-map iPhone 50000 match address Outside_cryptomap_5000
    crypto dynamic-map iPhone 50000 set transform-set ESP-3DES-SHA
    crypto dynamic-map iPhone 50000 set reverse-route
    crypto map Outside_map 50000 ipsec-isakmp dynamic iPhone
    crypto map Outside_map 65535 ipsec-isakmp dynamic SYSTEM_DEFAULT_CRYPTO_MAP
    crypto map Outside_map interface Outside
    webvpn
    group-policy iPhone internal
    group-policy iPhone attributes
    dns-server value 8.8.8.8 8.8.4.4
    vpn-tunnel-protocol IPSec
    default-domain value my_domain

    *****************************************************************
    Here is the config on my Test PIX that is working right:

    sh run

    : Saved

    :

    PIX Version 7.2(2)

    !

    hostname gbpix

    !
    interface Ethernet0
    speed 100
    duplex full
    nameif outside
    security-level 0
    ip address 10.81.1.80 255.255.255.0

    !

    ftp mode passive
    clock timezone EST -5
    clock summer-time EDT recurring
    dns server-group DefaultDNS
    domain-name my_domain
    same-security-traffic permit inter-interface
    same-security-traffic permit intra-interface
    object-group network DMZ_RDP
    description Connect to hosts via RDP that are in DMZ
    network-object 172.16.1.2 255.255.255.255
    network-object 172.16.1.3 255.255.255.255
    object-group service DNS_LookUp tcp-udp
    description Group for DNS Port number UDP/TCP
    port-object range domain domain
    access-list inside_outbound_nat0_acl remark Do not NAT Addresses when talking to PPTP Clients.
    access-list inside_nat0_outbound extended permit ip 10.10.0.0 255.255.255.0 192.168.1.96 255.255.255.240
    access-list outside_cryptomap_65535.40 extended permit ip any 192.168.1.0 255.255.255.0
    access-list outside_access_in extended permit ip 192.168.1.0 255.255.255.0 any
    access-list outside_access_in extended permit ip any 192.168.1.0 255.255.255.0
    pager lines 24
    logging enable
    logging trap notifications
    logging asdm informational
    logging facility 23
    logging queue 2048
    logging host inside 10.10.0.199
    mtu outside 1500
    mtu inside 1500
    mtu dmz 1500
    ip local pool VPNMobile 192.168.1.100-192.168.1.105 mask 255.255.255.0
    ip local pool VPNDesktop 172.16.1.100-172.16.1.200 mask 255.255.255.0
    ip verify reverse-path interface outside
    icmp unreachable rate-limit 1 burst-size 1
    asdm image flash:/asdm-522.bin
    asdm history enable
    arp timeout 14400
    nat-control
    global (outside) 10 interface
    global (outside) 68 x.x.x.x netmask 255.255.255.255
    global (outside) 2 x.x.x.x
    global (dmz) 17 interface
    global (dmz) 20 x.x.x.x
    nat (outside) 10 192.168.1.0 255.255.255.0
    nat (inside) 0 access-list inside_nat0_outbound
    nat (inside) 2 10.10.0.199 255.255.255.255 dns
    nat (inside) 10 0.0.0.0 0.0.0.0
    nat (dmz) 10 0.0.0.0 0.0.0.0
    static (dmz,outside) x.x.x.x 172.16.1.2 netmask 255.255.255.255
    static (dmz,outside) x.x.x.x 172.16.1.3 netmask 255.255.255.255
    static (outside,dmz) 172.16.1.2 x.x.x.x netmask 255.255.255.255
    access-group outside_access_in in interface outside
    route outside 0.0.0.0 0.0.0.0 10.81.1.1 1
    timeout xlate 3:00:00
    timeout conn 1:00:00 half-closed 0:10:00 udp 0:02:00 icmp 0:00:02
    timeout sunrpc 0:10:00 h323 0:05:00 h225 1:00:00 mgcp 0:05:00 mgcp-pat 0:05:00
    timeout sip 0:30:00 sip_media 0:02:00 sip-invite 0:03:00 sip-disconnect 0:02:00
    timeout uauth 0:05:00 absolute
    aaa-server TACACS+ protocol tacacs+
    aaa-server RADIUS protocol radius
    aaa-server RADIUS host 10.10.0.34
    timeout 30
    key my_psk
    aaa-server RADIUS host 10.10.0.9
    timeout 25
    key my_psk
    group-policy VPNDesktop internal
    group-policy VPNDesktop attributes
    wins-server value 10.78.0.6
    dns-server value 10.78.0.6 10.78.0.5
    vpn-tunnel-protocol IPSec
    default-domain value my_domain
    group-policy iPhone internal
    group-policy iPhone attributes
    dns-server value 8.8.8.8 8.8.4.4
    vpn-tunnel-protocol IPSec
    default-domain value my_domain
    username dunns password 5eV1j.Y6CHrne9RO encrypted privilege 15
    username replogled password gGQpsYvn1mD3wox8 encrypted privilege 5
    username xunhe password W8rA5wZqpj2lgRlE encrypted privilege 0
    aaa authentication ssh console LOCAL
    no snmp-server location
    no snmp-server contact
    snmp-server community public
    snmp-server enable traps snmp authentication linkup linkdown coldstart
    sysopt connection tcpmss 0
    auth-prompt prompt xxx Logon:
    auth-prompt accept Authenticated
    auth-prompt reject Too bad. Try again.
    crypto ipsec transform-set ESP-3DES-MD5 esp-3des esp-md5-hmac
    crypto ipsec transform-set ESP-DES-SHA esp-des esp-sha-hmac
    crypto ipsec transform-set ESP-DES-MD5 esp-des esp-md5-hmac
    crypto ipsec transform-set ESP-AES-128-MD5 esp-aes esp-md5-hmac
    crypto ipsec transform-set ESP-AES-128-SHA esp-aes esp-sha-hmac
    crypto ipsec transform-set ESP-AES-256-SHA esp-aes-256 esp-sha-hmac
    crypto ipsec transform-set ESP-3DES-SHA esp-3des esp-sha-hmac
    crypto dynamic-map outside_dyn_map 20 set pfs
    crypto dynamic-map outside_dyn_map 20 set transform-set ESP-AES-256-SHA
    crypto dynamic-map outside_dyn_map 40 match address outside_cryptomap_65535.40
    crypto dynamic-map outside_dyn_map 40 set transform-set ESP-3DES-SHA
    crypto map outside_map 140 set peer 216.54.104.130
    crypto map outside_map 140 set transform-set ESP-AES-256-SHA
    crypto map inside_map interface inside
    crypto map outside_map0 65535 ipsec-isakmp dynamic outside_dyn_map
    crypto map outside_map0 interface outside
    crypto isakmp identity hostname
    crypto isakmp enable outside
    crypto isakmp enable inside
    crypto isakmp enable dmz
    crypto isakmp nat-traversal 45
    tunnel-group DefaultL2LGroup ipsec-attributes
    trust-point d2msbk1
    tunnel-group DefaultRAGroup general-attributes
    authentication-server-group (outside) RADIUS
    authentication-server-group (inside) RADIUS
    tunnel-group DefaultRAGroup ipsec-attributes
    trust-point d2msbk1
    tunnel-group VPNDesktop type ipsec-ra
    tunnel-group VPNDesktop general-attributes
    address-pool VPNDesktop
    default-group-policy VPNDesktop
    tunnel-group VPNDesktop ipsec-attributes
    pre-shared-key *
    tunnel-group iPhone type ipsec-ra
    tunnel-group iPhone general-attributes
    address-pool VPNMobile
    default-group-policy iPhone
    tunnel-group iPhone ipsec-attributes
    pre-shared-key *
    telnet 10.10.0.40 255.255.255.255 inside
    telnet 10.10.0.23 255.255.255.255 inside
    telnet 10.10.0.47 255.255.255.255 inside
    telnet timeout 8
    ssh 10.10.0.40 255.255.255.255 inside
    ssh 10.10.0.47 255.255.255.255 inside
    ssh timeout 5
    ssh version 1
    console timeout 0
    management-access inside
    vpdn group PPTP-VPDN-GROUP ppp authentication mschap
    !
    !
    !
    policy-map type inspect dns migrated_dns_map_1
    parameters
    message-length maximum 512
    !
    ntp server 10.10.0.12 source inside
    ntp server 130.126.24.44 source outside prefer
    tftp-server inside 10.10.0.34 pix
    prompt hostname context
    Cryptochecksum:89f612e7474b2846886ec1fc0f9e91b2
    : end

  9. Lahoma Mathe says:

    Via my observation, shopping for gadgets online may be easily expensive, yet there are some tips and tricks that you can use to help you get the best bargains. There are continually ways to uncover discount offers that could make one to buy the best electronic devices products at the cheapest prices. Good blog post.

1 Pings/Trackbacks for "Cisco ASA hairpinning"
  1. […] słowa podziękowania dla Jimmiego Larssona z bloga nat0.net, który rozgryzł temat hairpinningu w dedykowanym wpisie. Jak zwykle, zachęcam Cię do podzielenia się swoimi przemyśleniami w […]

Leave a Reply

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

*

Signuppp

[mc4wp_form id="2457"]
Website Security Test