OS X automatic VPN connection

When I wander from place to place, I don’t want to have to remember to connect to the right VPN.

If I’m doing something for work, I need to be on the work VPN (IPSec), and if not, I should be on my personal VPN (OpenVPN, using Viscosity). Unfortunately, there is no easy way to check the box and have it all done automagically, particularly when work and personal VPNs are different software.

Scripting

A small amount of scripting will solve this problem. Because Apple is involved, we have some calls for AppleScript. Everything else is plain shell.

#!/bin/bash

set -e

PATH="/bin:/usr/bin:/usr/local/bin"

while getopts "i:t" COMMAND_LINE_ARGUMENT ; do
	case "${COMMAND_LINE_ARGUMENT}" in
		i) install="YES"
			;;
		t) test_mode="YES"
			;;
		\?) echo "-i and -t are optional"
			exit 1
			;;
	esac
done

cmd_pfx=""
if [ "${test_mode}" = "YES" ]; then
	echo "Test Mode"
	cmd_pfx="echo Would issue"
fi

# Get our current SSID
current_ssid=`networksetup -getairportnetwork en0 | cut -c 24-`
# Home VPN profile to execute
viscosity_connection="home"
# Work and home
whitelist=("<work ssid>" "<home ssid>")
# Work datacenter SSIDs
sites_need_work_vpn="<site1 ssid> <site2 ssid>"
# Start off untrusted
untrusted=true
 
install () {
	# Creating plist
	cat > ${HOME}/Library/LaunchAgents/local.network-change.plist < EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Enabled</key>
	<true/>
	<key>EnvironmentVariables</key>
	<dict>
		<key>PATH</key>
		<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin</string>
	</dict>
	<key>Label</key>
	<string>local.network-change</string>
	<key>LowPriorityIO</key>
	<true/>
	<key>ProgramArguments</key>
	<array>
		<string>${HOME}/.config/bin/connect_to_vpn.sh</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
	<key>WatchPaths</key>
	<array>
		<string>/Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist</string>
	</array>
</dict>
</plist>
EOF

	# Loading plist
	${cmd_pfx} launchctl load ${HOME}/Library/LaunchAgents/local.network-change.plist

}

if [ "${install}" == "YES" ] ; then
	install
	exit 0
fi

for ssid in "${whitelist[@]}" ; do
	# Check if SSID is trustworthy or not
	if [ "${current_ssid}" == "${ssid}" ] ; then
		untrusted=false
	fi
done
 
if [ ${untrusted} == true ] ; then
	if [ "${current_ssid}" == "`echo ${sites_need_work_vpn} | grep ${current_ssid}`" ] ; then
		# If we're at work, or a work-datacenter, use the work VPN
		${cmd_pfx} scutil --nc start "Work IPSEC VPN"
	else
		# Otherwise, use the home VPN
		${cmd_pfx} osascript -e "tell application \"Viscosity\" to connect \"$viscosity_connection\""
	fi
fi

You will need to put in the following bits:

  • whitelisted SSIDs
  • work vpn SSIDs
  • Viscosity connection name

Once you have all this defined, you can try running the script. If you’re on a whitelisted SSID or not on a work SSID, nothing should happen. If you’re not on a whitelisted SSID, your personal VPN connection should’ve started up. If you’re on a work-related SSID, your work VPN should’ve started up.

My Viscosity connection looks like this

My IPSec connection looks like this


Footnotes and References