Native Cisco VPN on Mac OS X

Confirmed working on OSX 10.9 Mavericks

The proprietary CiscoVPN Mac client is somewhat buggy. It is possible to use the IPSec VPN software included with Mac OS X instead. This tutorial shows you how to migrate from CiscoVPN to the native OS X IPSec VPN by decrypting passwords saved in CiscoVPN PCF files.

Advertisment

Please visit these guys if their offer interests you - they make this site possible.

1. Open Network Prefrences

Open up your System Prefrences and select "Network". Click on the little + button at the bottom of the window to create a new connection.

2. Creating a New VPN Connection

Pick "VPN" for the Interface and set its type to "Cisco IPSec". It doesn't matter what you set as the service name.

3. Set Your Server Address and Account Name

Copy the "Host" setting from CiscoVPN...

to the "Server Address" setting in your System Prefrences" and enter your username under "Account Name". You probably don't want to enter your password unless you are OK with the system saving it.

4. Find Your PCF File

On Mac OS X, PCF files are usually found in /private/etc/CiscoSystemsVPNClient/Profiles. Open up /Applications/Terminal and type the following:

cd /private/etc/CiscoSystemsVPNClient/Profiles
cat *.pcf

You should get something like this:

5. Get Your Encrypted Group Password

Find that long list of letters and numbers after enc_GroupPwd= and copy it. Also make note of the GroupName - you'll need that in a bit as well.

6. Decrypt Your Group Password

Paste that sequence of characters into the fancy schmancy decoder ring below and click "Decode". (pops up a new window)

Fancy Schmancy Decoder Ring

As an example, this should return "letmein" as the password:

Thanks to HAL-9000 at evilscientists.de and Massar's work on cisco-decrypt.c for the magic here.

7. Enter your Shared Secret and Group Name

Click "Authentication Settings" back in the Network Prefrences screen. Enter the resulting decoded password into the "Shared Secret" section of the new VPN connection and set the GroupName from above as well.

8. Create a New VPN Connection

Click "OK", make sure "Show VPN status in menu bar" is checked and click "Apply".

9. Try Starting your VPN

At the top of your screen you should have a little VPN icon. Try connecting to your new VPN.

10. Bask in the Warm Glow of a Native VPN Connection

If everything goes as planned, you should see your connection time counting up at the top of your screen.

11. Visit our Sponsor if their Offer Interests You

The "Other Way Around"

How to get your VPN settings out of the built-in mac VPN client.

You don't need the Fancy Schmancy Decoder Ring to get your settings back out of the built-in Mac VPN client. Just head over to the Keychain Access application (under Applications -> Utilities) and search for "VPN". Double-click your IPSec Shared Secret to open up the window. Clicking "Show Password" will reveal the secret sauce after you authenticate.


Troubleshooting

If things seem to get hung-up and you are unable to reconnect your VPN without a reboot, Rick R mentions that you might try killing the "racoon" process.

Racoon is an IPsec key management daemon and is part of the KAME IPsec tools. Kill it by running "Activity Monitor" in the "Utilities" folder, finding it in the process list and clicking "Quit Process" at the upper left of the Activity Monitor window.

Look in your system.log by running the Console app for hints at what might be going wrong. Here's the system.log from a working VPN setup / take down.

Disconnects

Dave Ma's VPN would disconnect after 45 minutes of uptime. Fotos Georgiadis on an Apple forum thread suggested changing the IPSec proposal lifetime within racoon to 24 hours instead of 3600 seconds. (3600 seconds is 1 hour - who knows why people are seeing drops at 45 minutes) Here's how that is done.

  1. Connect to the VPN (so OSX dynamically generates a racoon configuration file)

  2. Open Terminal on Mac (Applications --> Utilities--> Terminal)

  3. Copy the generated configuration file to /etc/racoon:

    sudo cp /var/run/racoon/XXXXXX.conf /etc/racoon

    **where: XXXXXX is the name or ip address of your VPN server**

  4. Edit the racoon configuration file with your favorite editor (pico):

    sudo pico /etc/racoon/racoon.conf
  5. At the bottom of the racoon.conf file, comment out the line:

    # include "/var/run/racoon/*.conf";

    (by added the "#" to the beginning of the line)

  6. And instead include the copied file (which we will edit):

    include "/etc/racoon/XXXXXX.conf" ;

    (don't forget to replace XXXXXX with the actual name of your file)

  7. Edit the generated configuration file with your favorite editor (pico):

    sudo pico /etc/racoon/XXXXXX.conf
  8. Disable dead peer detection:

    dpd_delay 0;
  9. Change proposal check to claim from obey:

    proposal_check claim;
  10. Change the proposed lifetime in each proposal (24 hours instead of 3600 seconds):

    lifetime time 24 hours;

    *note: make sure you change all the "proposed lifetime" sections and not just one.

  11. Disconnect and reconnect (this time racoon will use your custom configuration).

Now try using your VPN for more than 45 minutes and it shouldn't drop.

Routing Everything Through the VPN

So does all your traffic flow through the VPN when you are connected or just traffic to the protected networks? Cisco VPN servers normally send out a list of routes to private networks so you don't end up sending all of your traffic through the VPN server. The reasoning behind this is why protect it if the traffic is destined for an insecure network anyway? The native OS X Cisco VPN adds these routes automatically and removes them when you disconnect. That's one of the things that differentiates the Cisco VPN client from the standard IPSec client. Let's take a look at what gateway is used when sending traffic to apple.com from within the Terminal application:

route -n get apple.com
   route to: 17.149.160.49
destination: default
       mask: default
    gateway: 192.168.1.1
  interface: en0
      flags: 
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu
       0         0         0         0         0         0      1500

Notice the "gateway" line there? Traffic to apple.com is going out 192.168.1.1 which is my normal Internet gateway so it is skipping the VPN entirely.

Let's try an IP on a protected private network: (10.1.2.3)

route get 10.1.2.3
   route to: 10.1.2.3
destination: 10.1.2.3
    gateway: 172.131.25.12
  interface: utun0
      flags: 
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu
       0         0         0         0         0         0      1280

In this case, the gateway is 172.131.25.12 which is a fake IP on the far end of the VPN which will eventually route traffic to 10.1.2.3. So when sending data to 10.1.2.3, I am going through the VPN and that traffic is encrypted.

So how does it know what gateway to use for different IPs? Let's take a look at the routing table:

netstat -r -n
Routing tables

Internet:
Destination        Gateway            Flags        Refs      Use   Netif
default            192.168.1.1        UGSc          137        0     en0
default            utun0              UCSI            1        0   utun0
10.1/16            172.131.25.12      UGSc            0       11   utun0
...
1.2.3.4            192.168.1.1        UGHS            1        4     en0
...

I've lopped off a bunch of irrelevant lines but as you can see we have two "default" routes. If a destination isn't explicitly matched below, the traffic will flow through the first default route from the top. So in this case, if the destination isn't within 10.1/16 (which means 10.1.*.*) we will go through our default route of 192.168.1.1. If it is, we would go through 172.131.25.12 which is our VPN.

But what if you just wanted to send everything through your VPN connection? We could just delete the first default route and let everything go over the VPN, but this is presumably dangerous because the encrypted traffic probably uses the default route to get to the VPN server in the first place. Let's see:

route -n get vpn.example.com
   route to: 1.2.3.4
destination: default
       mask: default
    gateway: 192.168.1.1
  interface: en0
      flags: 
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu
       0         0         0         0         0         0      1500

Yep, it does. So if we are going to remove the default route to 192.168.1.1, we have to make sure we have an explicit route below to the VPN server. (1.2.3.4) You will notice above that my Cisco VPN server adds this route automatically, but if yours isn't configured that way you can add it like this:

sudo route add 1.2.3.4 192.168.1.1

It is safe to try this if you already have the route because the command will just fail.

The next thing we are going to do is a little dangerous and remove all your network access. A reboot should be your weapon of last resort to get your networking back but you might also want to print these instructions out so you have them. You have been warned!

Now let's do the dangerous bit and rip the first default route away:

sudo route delete default 192.168.1.1

Now let's check to see if we can still get to our VPN server:

route -n get 1.2.3.4
   route to: 1.2.3.4
destination: 1.2.3.4
    gateway: 192.168.1.1
  interface: en0
      flags: 
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu
       0         0         0         0         0         0      1500

Yep, looks good.

Now let's look at the wider Internet by seeing how we get to apple.com: (17.172.224.47 - we aren't using apple.com here because we don't want to depend on DNS working)

route -n get 17.172.224.47
route: writing to routing socket: not in table

Whoops, something is wrong! That's because that first route there is a little deceptive. It isn't a route to the IP of the gateway, just a route to the VPN tunnel device utun0. We'll need to say what IP to go to. Let's add a default route to the VPN's fakenet gateway address: (which we already have as the gateway in most other routes)

sudo route add default 172.131.25.12

OK, let's see which way packets go to get to apple.com: (17.172.224.47)

route -n get 17.172.224.47
   route to: 17.172.224.47
destination: default
       mask: default
  interface: utun0
      flags: 
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu
       0         0         0         0         0         0      1280

Yep, looks like the right way.

Now let's try pinging google.com: (apple.com doesn't respond to pings)

ping -c 1 google.com
PING google.com (74.125.226.229): 56 data bytes
64 bytes from 74.125.226.229: icmp_seq=0 ttl=252 time=10.662 ms

--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 10.662/10.662/10.662/0.000 ms

Looks like it works. If it doesn't work, your VPN server likely doesn't allow general Internet access through VPN connections. If this is the case, you are out of luck. Hopefully you know someone influential in the IT department that can change this for you.

Because we removed the normal default route, when we shut down our VPN we'll be stuck without a default route. To add that back in after the VPN goes down, do this:

sudo route add default 192.168.1.1

And we should be back to normal.

Ideally we do these things automatically when the VPN comes up. The easiest way to do this is to have your VPN administrator set that up as a policy for you. Alternatively, you can create scripts that run on VPN startup. Create /etc/ppp/ip-up and add whatever lines you came up with above to that and mark that file as executable with:

sudo chmod 755 /etc/ppp/ip-up

Similarly, /etc/ppp/ip-down will be run on VPN shutdown. Reverse your commands in that file and you should have a completely automated setup.

Happy tunneling!

-Anders Brownworth

Wednesday, September 17, 2014

About Me:


Name: Anders Brownworth
Home: Cambridge, MA, USA
Work: Mobile application and GSM research at Bandwidth.
Play: Technology, World Traveler and Helicopter Pilot
Follow: