OSX Split L2TP VPN

I recently had to configure a L2TP VPN into my office network that, for a simple network, is trivial in OSX as there is a GUI in the Network pane of System Preferences. However, we run a mix of both publicly routable and private IPv4 subnets and I really wanted to run with split tunnelling through my relatively fast HFC home network connection. There are certainly references from Google, e.g. [1, 2], on how to set this up, as well as some debate [3] as whether it is possible to accomplish this server side. Irrespective: I have no control of the VPN concentrator so this is all done client side and, as I spend most of my life in a terminal, this seemed the way to go.

The general process is:

  1. Use the OSX GUI to create a split tunnel VPN
  2. Add two bash scripts
  3. Add two supporting AppleScript scriptlets
  4. Modify sudo privileges (if desired)
  5. Test and relax

The key really here is that the bash scripts act as controllers to execute the AppleScripts, which start and stop the VPN respectively, and then modify the routing table.

IP Ranges

For this example assume the following:

  1. The VPN allocates a private IPv4 address in the 10.0.0.0/24 range
  2. I have a publicly routable IPv4 address at 172.0.0.1/24 but its behind my VPN concentrator
  3. I have a private 192.168.240.0/24 subnet also behind my VPN concentrator

GUI Install

There’s really good online guides for this so I’m not going to go through this again.

Bash Scripts

For ease of execution, these two bash scripts should be installed somewhere on your path.  I use ~/bin, which is in my path.

launch-vpn:

#!/bin/bash
# set -o noexec
# set -o verbose
# set -o xtrace
set -o nounset

# Simple script to launch the VPN.
# It is better to do this as the L2TP does not allow for split tunnelling,
# easily that is, so I can execute the commands here.  This does assume that
# there is no overlap in the IP ranges, for example if you are at home on
# 192.168.1.0/24 then work cannot be the same.
#
# See also: disconnect-vpn
#
# Need to ad to sudo via: sudo visudo
# username ALL= NOPASSWD: /sbin/route
#
# Dr Peter Brady <peter.brady@openfluids.engineer>
# 2017-05-07

# Step 1: AppleScript VPN
/usr/bin/osascript /Users/pbrady/esi/esi-connect.scpt

# Step 2: Adjust Routes
sudo /sbin/route -nq add 172.0.0.1/24 -interface ppp0
sudo /sbin/route -nq add 192.168.240.0/24 -interface ppp0

disconnect-vpn:

#!/bin/bash
# set -o noexec
# set -o verbose
# set -o xtrace
set -o nounset

# Simple script to close the VPN.
# It is better to do this as the L2TP does not allow for split tunnelling,
# easily that is, so I can execute the commands here.  This does assume that
# there is no overlap in the IP ranges, for example if you are at home on
# 192.168.1.0/24 then work cannot be the same.
#
# See also: esi-disconnect
#
# Need to ad to sudo via: sudo visudo
# username ALL= NOPASSWD: /sbin/route
#
# Dr Peter Brady <peter.brady@openfluids.engineer>
# 2017-05-07

# Step 1: Adjust Routes
sudo /sbin/route -nq delete 172.0.0.1/24 -interface ppp0
sudo /sbin/route -nq delete 192.168.240.0/24 -interface ppp0

# Step 2: AppleScript VPN
/usr/bin/osascript /Users/pbrady/esi/esi-disconnect.scpt

AppleScript

These scripts were inspired by a discussion and example over on superuser.com where I could adapt the bash functions described to the following.

esi-connect.scpt:

-- Inspired by:
-- https://superuser.com/questions/358513/start-configured-vpn-from-command-line-osx
tell application "System Events"
	tell current location of network preferences
		set VPN to service "MyVPN"
		if exists VPN then connect VPN
		repeat while (current configuration of VPN is not connected)
			delay 1
		end repeat
	end tell
end tell

esi-disconnect.scpt:

-- Inspired by:
-- https://superuser.com/questions/358513/start-configured-vpn-from-command-line-osx
tell application "System Events"
	tell current location of network preferences
		set VPN to service "Pacific ESI"
		if exists VPN then disconnect VPN
	end tell
end tell
return

Modify sudo Permissions

Finally, because I’m lazy and this is my personal laptop, I modified my sudo file via

speleo:~ pbrady$ sudo visudo

to add to add to the bottom

username ALL= NOPASSWD: /sbin/route

This allows me to run the route commands without adding a password for the sudo.

Finally, thanks for reading this article and please leave a comment below. If you are interested in being updated when similar items are posted then either subscribe via RSS or sign up to my mailing list below.

Site Footer