One of my clients has recently moved to AnyConnect VPN and I’ve been having routing problems with the official Mac client. As my colleagues on Linux on the project have not had these issues, I investigated and installed the OpenConnect client.
These are my notes after scouring the Internet to set it up how I want it.
Contents
Installation
I used Homebrew:
$ brew install openconnect
OpenConnect is a CLI tool. If you want a GUI in your menu bar, then also install openconnect-gui. I an not using the GUI as command line works for me.
Starting and stopping
To start the VPN:
$ sudo openconnect –user={username} {VPN URL}
(Replace {username} & {VPN URL} with the relevant details, of course.)
You can then use ctrl+C to stop it.
To avoid having to type your password for the sudo call each time, we can add a new file to /etc/sudoers.d/ to allow no password for openconnect binary.
This one-liner will do it:
$ sudo sh -c ‘echo “%admin ALL=(ALL) NOPASSWD: /usr/local/bin/openconnect” > /etc/sudoers.d/openconnect’
This creates /etc/sudoers.d/openconnect with the relevant config.
Run in the background
Alternatively, you can put openconnect into the background with the –background flag. To stop the VPN, we need to find the pid so that we can kill the process:
$ sudo kill -2 `pgrep openconnect`
This will be useful for scripting it.
Avoiding typing the password
The –passwd-on-stdin flag allows us to pipe the password to openconnect like this:
$ echo “mypassword” | sudo openconnect –passwd-on-stdin –user={username} {VPN URL}
Clearly we don’t want the password in our history or in our scripts, so we put it in a file such as ~/.vpn_password.
This file needs to contain the plain text password and be readable only by the current user:
$ echo “mypassword > ~/.vpn_password
$ chmod 600 ~/.vpn_password
We can now pipe the output of this file:
$ echo $(cat ~/.vpn_password) | sudo openconnect –passwd-on-stdin –user={username} {VPN URL}
We now have a working connection.
Scripting to make it easier
At this point we have enough to write a couple of functions to start and stop the VPN connection.
Place the following into ~/.bashrc:
function vpn-up() {
local VPN_HOST={VPN URL}
local VPN_USER={username}
if [ ! -f ~/.vpn_password ]; then
echo “Error: missing ~/.vpn_password”
return
fi
echo “Starting the vpn …”
echo $(cat ~/.vpn_password) | sudo openconnect –background –passwd-on-stdin –user=$VPN_USER $VPN_HOST
}
function vpn-down() {
sudo kill -2 `pgrep openconnect`
}
Replace {VPN URL} with the correct URL for your VPN and {username} with your VPN username.
We can now start the VPN:
$ vpn-up
and then stop it:
$ vpn-down
Nice and simple to remember!
DNS resolution
On Big Sur, I found that the VPN’s DNS server wasn’t registered, so I had add scripts to do that. OpenConnect will any script in /etc/vpnc/post-connect.d when the VPN connects and any script in /etc/vpnc/post-disconnect.d when the VPN disconnects, so we can create two files to handle DNS. The directories don’t exist do you’ll need to create them:
$ sudo sh -c ‘mkdir -p /etc/vpnc/post-connect.d’
$ sudo sh -c ‘mkdir -p /etc/vpnc/post-disconnect.d’
This is the “on connect” script:
/etc/vpnc/post-connect.d/use-vpn-dns:
networksetup -setdnsservers Ethernet {VPN DNS IP1} {VPN DNS IP2} {Usual DNS IP1} {Usual DNS IP2}
networksetup -setdnsservers Wi-Fi {VPN DNS IP1} {VPN DNS IP2} {Usual DNS IP1} {Usual DNS IP2}
killall -HUP mDNSResponder
Replace {VPN DNS IP1}, {VPN DNS IP2}, {Usual DNS IP1} and {Usual DNS IP2} with the correct IP addresses for your setup.
When the VPN is disconnected, we need to reset. I use DHCP, so this worked for me:
/etc/vpnc/post-disconnect.d/use-default-dns:
networksetup -setdnsservers Ethernet Empty
networksetup -setdnsservers Wi-Fi Empty
killall -HUP mDNSResponder
This clears the DNS entries and the DHCP defaults are then used. Be aware that if you use multiple VPNs, you will probably need more complicated logic.
DNS for a specific domain
If you need to use a particular DNS server for a specific domain you can use this in use-vpn-dns:
scutil
1.2.3.4 and 5.6.7.8 are the DNS servers and specific-searchdomain.com is the domain in question.
and to remove:
scutil
That’s it
With this in place, I can now connect and disconnect from my client’s VPN with minimal fuss and, so far, everything works as I expect.
Permanent link to this post here
