How to Configure VPN Split Tunnel on Mac
In this current world of remote work, we continue to see a growth in the use of VPNs in enterprises to support secure remote experiences for their users within their corporate network.
The norm in most institutions is that there will be an entire IT-support team dedicated to the provisioning of the required tools configured for use within the organization. Such are configured for accessing internal servers while accessing resources on internet and jumping into video calls. But then again this does not apply for every use case…
In certain cases you’ll need a device not configured for use within the corporate network or some institutions may not offer the support in setting up your devices for the same as well.
A VPN routes all the network connections through the VPN tunnel, this dramatically slows down connection to internet resources, at times refusing connection to others.
Split tunneling works by tunneling some of your traffic through a VPN and routing the rest via the open network. This way, you have both the benefits of a secure connection to your on-premise servers as well as a speedy connection to the open internet.
In this article we will set up split tunelling with Openconnect alongside vpn-slice(a vpnc-script
replacement) to set your own split tunnel on client side. vpn-slice
routes only traffic for specific hosts and/or subnets through the VPN by looking up named hosts, using the VPN's DNS servers, and adding these entries to the /etc/hosts
(which it cleans up after VPN disconnection).
- Install Openconnect via Homebrew.
brew update
brew install openconnect
2. Add password-less sudo ability for the openconnect
command.
sudo sh -c \
'echo "%admin ALL=(ALL) NOPASSWD: /usr/local/bin/openconnect" > /etc/sudoers.d/foo'
3. Test the vpn connection with:
sudo openconnect --user=<VPN username> <VPN host>
You will be prompted for your vpn password if any exists.
To exit use control + c(for mac).
Note: Newer versions of OpenConnect will use the utun
device on OS X which does not require the TUN/TAP driver or other additional kernel modules to be installed.
4. Now we install vpn-slice via Homebrew.
brew install vpn-slice
5. While it would be easy to initiate the connection with a single command as below;
sudo openconnect --user=<VPN username> <VPN host> \
--script 'vpn-slice <internal host> <internal CIDR range>'
At times this becomes cumbersome in a practical daily use basis. Just to put this into context, if my vpn is set up for VPN host vpn.example.com
with my internal host example.com
and internal CIDR range 192.168.1.0/24
for user johndoe
sudo openconnect --user=johndoe vpn.example.com \
--script 'vpn-slice example.com 192.168.1.0/24'
Any new internal host or CIDR range would require to be added to the list and the list may end up becoming too long. The easiset way out would be transforming this into shell functions and designing simpler commands that will be used for each new connection.
Scripting our shell functions
- Create a
vpn-slice-addresses
script in~/vpn-slice-addresses
with the following:
#!/bin/sh
# Script that starts vpn-slice with the hostnames/subnets
# that need to be accessed via the VPN.
vpn-slice \
<host 1> \
<host 2> \
<CIDR range A> \
<CIDR range B>
Note: This file can live in any location as long as it is correctly referenced in the following steps.
2. Set the right permissions for the script:
chmod a+x ~/vpn-slice-addresses
3. Create the following functions in your .zprofile
(or in a file that you source from your .zprofile
). By default .zprofile
located at ~/.zprofile
(I’ve found the .zprofile
to be a more permanent solution compared to the .zshrc
as in this article) :
export COMPANY_VPN_HOST=<VPN host>export VPN_USER=<VPN USER>function vpn-up() {
if [[ -z $COMPANY_VPN_HOST ]]
then
echo "Please set COMPANY_VPN_HOST env var"
return
fi
if [[ "$1" == "split" ]]
then
echo "Starting the vpn with split tunneling ..."
sudo openconnect --background --script='~/vpn-slice-addresses' --user=$VPN_USER $COMPANY_VPN_HOST
else
echo "Starting the vpn ..."
sudo openconnect --background --user=$VPN_USER $COMPANY_VPN_HOST
fi
}
function vpn-split() {
vpn-up split
}
function vpn-down() {
sudo kill -2 `pgrep openconnect`
}
For any help on the various tags used in the openconnect command, you can click here.
4. Reconfigure your .zprofile
. Note with .zprofile
, the next time you log in to your terminal, everything within the file will automatically be loaded.
source ~/.zprofile
5. Connect!
If you wand to send all the traffic through the VPN do:
vpn-up
If instead you want to do Split Tunneling, use:
vpn-split
6. Disconnect
Given OpenConnect
is started using the --background
flag, we can't use Ctrl-C
to close it, instead we need to run:
vpn-down