Full tunnel AnyConnect with Internet hairpin

As a matter of personal preference, I was never a HUGE fan of the ASA as a firewall appliance.  For VPN termination, it’s pretty slick but still has some issues.  Either way, I have a 5505 at home that I use for firewall and VPN.  Being bored some time ago (wish I had free time now) I decided to upgrade the device from 8.2 to 9.1 code.  Along with this change came the dreaded ASA 8.3 NAT configuration change.  I’d argue that NAT on the ASA never made true sense, but once you knew how it worked, you could make it do what you wanted it to do.  Not knowing how to configure the new mode of NAT in the CLI, I decided to try it through ASDM (this of course breaking my ‘ASDM is awful never use it’ rule (and yes, I know you have to use ASDM for some of the AnyConnect XML stuff)).  The ASDM configuration lead to the automagic creation of NAT groups I didn’t need, object groups I didn’t need, and ACLs I didn’t need.  Somehow I managed to click enough buttons that it worked, but I wasn’t happy with the end state of the config. 

Fast forward to now.  Now I want to be able to connect to VPN at my house, access local resources, as well as access the internet through my local Comcast connection (internet hairpin).  Thinking this would be straight forward, I pulled down a copy of my ASA config into notepad and realized that it was full of random stuff I didn’t need.  After some clean up, I came to some realizations about NAT on the newer ASA code.  Namely, the fact that you don’t HAVE to use the NAT configuration under the objects themselves.  This, at least for me, was a HUGE help.  Let’s take a quick look at my config so you can see what I’ve setup…

image

So the real goal here is to be able to access a hosting container I use out on the internets from my laptop.  The hosting container only allows certain IP addresses (my home IP) to access it.  So if I could VPN to my house and use my home internet connection to access the hosting space from my laptop, I’d be all set!

In order to accomplish this, you need to do some ‘weird’ NAT configuration. I’m not going to run through my whole ASA config, but here are the important pieces…

hostname ASA
!
ip local pool vpn 10.20.30.249-10.20.30.253 mask 255.255.255.0
!
interface Ethernet0/0
switchport access vlan 2
!
interface Ethernet0/1
!
interface Ethernet0/2
!
interface Ethernet0/3
!
interface Ethernet0/4
!
interface Ethernet0/5
switchport access vlan 3
!
interface Ethernet0/6
!
interface Ethernet0/7
switchport access vlan 3
!
interface Vlan1
nameif inside
security-level 100
ip address 10.20.30.1 255.255.255.0
!
interface Vlan2
nameif outside
security-level 0
ip address <removed> 255.255.255.248
!
interface Vlan3
no forward interface Vlan1
nameif guest
security-level 50
ip address 192.168.127.1 255.255.255.248
!
boot system disk0:/asa911-k8.bin
!
same-security-traffic permit intra-interface
object network guest
subnet 192.168.127.0 255.255.255.248
object network locallan
subnet 10.20.30.0 255.255.255.0
object-group network VPNPOOL
network-object 10.20.30.248 255.255.255.248
!
nat (outside,inside) source static VPNPOOL VPNPOOL
nat (outside,outside) source dynamic VPNPOOL interface
nat (inside,outside) source dynamic locallan interface
nat (guest,outside) source dynamic guest interface
!
route outside 0.0.0.0 0.0.0.0 <removed> 1
route inside 10.0.0.0 255.255.255.0 10.20.30.117 1
!
telnet 10.20.30.0 255.255.255.0 inside
telnet timeout 1440
ssh timeout 5
console timeout 0
management-access inside
!
dhcpd address 10.20.30.100-10.20.30.200 inside
dhcpd dns 4.2.2.2 8.8.8.8 interface inside
dhcpd enable inside
!
dhcpd address 192.168.127.2-192.168.127.6 guest
dhcpd dns 4.2.2.2 8.8.8.8 interface guest
dhcpd enable guest
!
webvpn
enable outside
anyconnect image disk0:/anyconnect-macosx-i386-2.5.2017-k9.pkg 1
anyconnect image disk0:/anyconnect-win-2.5.3055-k9.pkg 2
anyconnect profiles vpn disk0:/vpn.xml
anyconnect enable
group-policy DfltGrpPolicy attributes
vpn-idle-timeout none
vpn-tunnel-protocol ikev1 l2tp-ipsec ssl-client ssl-clientless
group-policy gp_anyconnect internal
group-policy gp_anyconnect attributes
dns-server value 4.2.2.2 8.8.8.8
vpn-tunnel-protocol ikev2 ssl-client
split-tunnel-policy tunnelall
split-tunnel-network-list value splitvpn
webvpn
  anyconnect profiles value vpn type user
  anyconnect ask none default anyconnect
username <removed> password <removed>
tunnel-group tg_vpn type remote-access
tunnel-group tg_vpn general-attributes
address-pool vpn
default-group-policy gp_anyconnect
tunnel-group tg_vpn webvpn-attributes
group-url <removed> enable
without-csd

Lot’s of config there, but I want to focus on are the bolded lines.  The first bolded line is what tells the ASA to allow the ‘hairpin’ to occur.  Specifically, you are telling the ASA with this command that it’s ok for traffic to come in a interface with a certain security level (0) and leave through an interface with an identical security level (0).  This allows VPN traffic to come in the outside interface encrypted, and leave back out the outside interface to get to the internet. 

The next 4 bolded lines are the NAT configuration.  This is what I’m really interested in…

nat (outside,inside) source static VPNPOOL VPNPOOL
nat (outside,outside) source dynamic VPNPOOL interface
nat (inside,outside) source dynamic locallan interface
nat (guest,outside) source dynamic guest interface

Let’s line these statements up on our diagram to give you a visual of what’s actually going on…

image

The first NAT statement tells the ASA to allow the client space in from the outside interface to the inside interface and to not modify the addresses.  This allows my VPN pool (tail end of my 10.20.30.40/24) to talk to the Local LAN space. 

image

The second NAT statement tells the ASA to take the VPN client space in the outside interface, back out the outside interface, but to dynamically overload it to the outside interface IP.  This is the actual NAT hairpin configuration that allows a VPN client to come in the outside and then leave back out towards the internet with the NAT overload.  

image

image

The last two NATs are simple dynamic overloads for the Local LAN and the Guest LAN network.  This allows both RFC 1918 spaces to be hidden behind the outside interface of the ASA.

Not really a ton too it actually, but I did struggle initially with the NAT until I figured out I could do it without defining the NAT under the object group itself.

11 thoughts on “Full tunnel AnyConnect with Internet hairpin

  1. Kerry

    Thanks for this article, well written and love the drawings.
    It’s so much easier to configure the object NAT rules when someone’s got a good description of a working configuration.

    -Kerry

    Reply
  2. Mors

    I had this problem this morning and you’ve saved my bacon. Was working fine via the SSL portal but not the Anyconnect client. I was pushing down routes for specific website IP’s too via a splittunnel ACL.

    Reply
  3. Mike

    I am hoping someone can help me.

    I have an ASA 5505. I am attempting to setup a full tunnel VPN with anyconnect. Currently anyconnect users are not able to access the internet when connected.

    I am not able to get my IOS to take the NAT commands mentioned in this article.

    The IOS will not take – (inside,outside) together. Only one or the other.

    Reply
  4. -

    Is there a way to simply get the VPN clients to use a internal gateway present in the VPN LAN instead of messing around with NATs?

    Reply
  5. Aakanksha

    Thanks!
    Ive been struggling with application of NAT. I understand the theory..but the solution never comes easily to me..
    The diagrams are extremely helpful!
    I hope the next time Im in NAT ‘muddypool’ i can find my way out:)

    Reply
  6. mlan

    Thank you for posting this. It helped confirm that my overall config concept was correct, but I found I was being stung by a legacy “tunneled vpn route” config line. Since the tunneled config was no longer required, I removed it and the hairpin NAT started working correct for the vpn clients’ Internet access:

    # no route INSIDE 0.0.0.0 0.0.0.0 x.x.x.x tunneled

    Reply
  7. Seth

    Hey Jon,
    I am trying to do similar with a setup I have (on ASA 8.2(3))
    But for some reason the DNS lookup is messing up…..it is not being passed by to the VPN Client.

    My company has a ASA 5510 in place. I have created a VPN Full tunnel for my iPhone. Phone connects, traffic is passed. So hairpinning is working.
    As long as the app or website is being accessed using the IP address, things work.
    But if you use Chrome or Safari it will not work. The DNS lookup is just not happening.

    Now the weird thing is that I have a PIX 515E here next to me I use for testing and I can get it to work as it should. I try to migrate those commands from the PIX (7.2) to the ASA and it does not work at all.

    I have tried creating a DNS Inspect map, but that hasn’t helped…..
    Running out of ideas to try. It should work.
    It’s hard to really see what is happening in the log, since all the traffic is being passed on the outside interface, not to much shows up.

    Thank you for any thoughts or ideas you may have.

    Reply

Leave a Reply to mlan Cancel reply

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