What do you think? Discuss, post comments, or ask questions at the end of this article [More about me]

Problem

I needed to maintain a continuous (or near-continuous) VPN connection to a server (server 1) from another server (server 2) that was running a Tomcat web-app (on Ubuntu Server 16.04).  Server 1 was part of a network which provides secured VPN access to external connections via Cisco Anyconnect.

Solution

Users have reported that this approach does not work with newer version of openconnect etc.

Given I haven't attempted this approach (nor have need of it) I am just leaving this here for historical purposes (or something that did work previously).

For this, we're going to use the excellent OpenConnect to connect to server 1, and a bash script to continuously check the connection, and if disconnected, to reconnect.

Install OpenConnect

Let's first install OpenConnect.  Server 2 was running Ubuntu 16.04.  Let's do:

sudo apt-get install openconnect

Creating a script to reconnect when disconnected

Please note that the below approach stores a vpn password in clear text in the script file, and as such is a potential security risk. The script should be locked down to stop users without authorisation from viewing its contents. Hence, this approach may only be appropriate for a server/system that is strictly managed or not accessed by other users.

Let's create a script that will:

  1. connect to your VPN;
  2. check every x seconds whether it is still connected
  3. reconnect to the VPN if the connection is broken

In the below example we'll create a vpn.sh script.

sudo nano ~/vpn.sh

Copy the following into in your script:

#!/bin/bash

OPENCONNECT_PID=""
RUNNING=""

function checkOpenconnect {
    ps -p $OPENCONNECT_PID &> /dev/null
    RUNNING=$?

    #echo $RUNNING &>> reconnect.log
}

function startOpenConnect {
    # start here open connect with your params and grab its pid
    echo "<PASSWORD>" | sudo openconnect --no-cert-check -u <USER> --passwd-on-stdin <VPN.ADDRESS> & OPENCONNECT_PID=$!
}

startOpenConnect

while true
do
    # sleep a bit of time
    sleep 10
    checkOpenconnect
    [ $RUNNING -ne 0 ] && startOpenConnect
done

Let's at least lock this file down to be only readable by root:

sudo chown root:root vpn.sh
sudo chmod 711 vpn.sh

Running script in background

Once your happy with your script you can run said script as a background script:

cd ~/
sudo ./vpn.sh &

Stopping background script

To stop/disconnect the VPN and script, use ps to find the PID's of the VPN script and the openconnect process by:

sudo ps -aux | grep vpn

For example, on my system, running the above gives:

user:~$ sudo ps -aux | grep vpn
root     10524  0.0  0.1  51420  2108 ?        S    Mar05   0:00 sudo ./vpn.sh
root     10525  0.0  0.1  11524  2836 ?        S    Mar05   0:26 /bin/bash ./vpn.sh
root     28443  0.0  0.1  51420  3912 ?        S    21:15   0:00 sudo openconnect -u <USER> --passwd-on-stdin vpn.example.com
root     28445  0.0  0.6 101864 13148 ?        S    21:15   0:00 openconnect -u <USER> --passwd-on-stdin vpn.example.com
ubuntu   29396  0.0  0.0  12944  1084 pts/1    S+   22:14   0:00 grep --color=auto vpn

I would kill PID's 10525 and  28445, like this:

sudo kill 10525 28445

Split tunnelling with vpn-slice

Split tunnelling allows you to explicitly define the ip address(es) for which traffic will be routed to on the vpn server side.  This is useful for situations where you might want to route traffic to/from a specific ip, and want all other traffic to use normal (non-vpn) connections.

For this use case you can use vpn-slice.  Once installed (see here for requirements and install guide), you can then modify your the script above as follows (see line 15 for the vpn-slice script argument):

#!/bin/bash

OPENCONNECT_PID=""
RUNNING=""

function checkOpenconnect {
    ps -p $OPENCONNECT_PID &> /dev/null
    RUNNING=$?

    #echo $RUNNING &>> reconnect.log
}

function startOpenConnect {
    # start here open connect with your params and grab its pid
    echo "<PASSWORD>" | sudo openconnect --no-cert-check -u <USER> --passwd-on-stdin <VPN.ADDRESS> --script 'vpn-slice <IP-ADDRESS>' & OPENCONNECT_PID=$!
}

startOpenConnect

while true
do
    # sleep a bit of time
    sleep 10
    checkOpenconnect
    [ $RUNNING -ne 0 ] && startOpenConnect
done

where <IP-ADDRESS> is the ip address (or addresses, separated by a space) is what addresses you want tunnelled to the vpn.

NOTE: you should install vpn-slice with sudo to ensure it is available on the standard path (otherwise you'll need to give the full path to the vpn-slice script).

References

  1. https://discourse.osmc.tv/t/setting-openconnect-to-autoconnect-at-startup/8601/2
  2. https://askubuntu.com/questions/803021/how-to-automatically-connect-openconnect-vpn-when-the-connection-closes
  3. https://github.com/dlenski/vpn-slice