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:
- Use the OSX GUI to create a split tunnel VPN
- Add two bash scripts
- Add two supporting AppleScript scriptlets
- Modify sudo privileges (if desired)
- 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:
- The VPN allocates a private IPv4 address in the 10.0.0.0/24 range
- I have a publicly routable IPv4 address at 172.0.0.1/24 but its behind my VPN concentrator
- 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.