Reconnectivity

So this is a script — really a series of scripts — I bashed (heh) together in a few minutes last night to check when my VPN connection goes down, with a tiny pinhole in the firewall just enough to send an email, and then send another one when it comes back up. Obviously this is useless if the whole internet connection is down, but that isn’t the use case as I don’t have a backup internet connection anyway (although two ISPs with multihomed BGP and my own /24 on each would be damn sweet). I’m using Ubuntu 16.10, by the way.

This first thing to do was putting an entry at the bottom of /etc/network/interfaces like this:

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
up vpnup

The “up vpnup” might not be strictly necessary, but some guides suggested it was and it works, so I’m leaving it. This kicks off a script in /etc/network/if-up.d called vpnup that deletes a file present in /var/run. I’ll explain why later. (If you don’t know, the contents of /var/run are deleted on each reboot.)

Do sudo chmod +x /etc/network/if-up.d/vpnup

That script looks like this:

#!/bin/sh

if [ "$IFACE" = tun0 ]; then
rm /var/run/vpnup
fi

The tun0 is my VPN connection.

Then in crontab I have an entry that runs every minute that does some things and kicks off some other bits in a script depending on what events occur. That crontab entry looks like this:

*/1 * * * * /usr/local/bin/vpndrop.sh >> /dev/null 2>&1

That script “vpndrop.sh” is below, but first I’ll explain it.

The first bit is a ping of four packets that attempts to ping a VPN gateway. If it can’t be pinged, then (after a function declaration and some other crap I should really move), it echoes to a log file and then sends an email (if the base internet connection still works). No leaks — only port 587 is open, and only to a specific address range.

Then it sleeps for three seconds and restarts the Network Manager service. This is because there are a few bugs in Network Manager (actually loads of bugs, but two I care about) that requires restarting it when VPN drops. One is that DNS resolution doesn’t work when VPN drops and then reconnects — at least with certain providers. Hmm, the other bug I seem to have forgotten but there is a second one, not as major. Will add if I recall it.

Then it sleeps again to allow the network connection to fully recover, and then attempts to reconnect to the VPN.

Another five second sleep to allow that to happen, and then it looks for the file in /var/run. If it does find that file (meaning that tun0 and thus the VPN did not come back up), it does nothing in this bit. It just exits. Then it sleeps for 10 and always attempts to write the file I am looking for when the VPN comes up.

There is probably a better way to to do this, but I care the most about knowing for sure when the VPN comes up again so I want that file to be destroyed when it is definitely up so I get an email.

I won’t even go through the nightmare it is configuring an MTA in Linux to relay mail to an outside server. I’m using exim4, and for being an “easy” MTA it took me a long time to get anything to work and many painful steps. Explaining all that would require another tutorial five times as long as this one, so you are on your own there.

Do sudo chmod +x /usr/local/bin/vpndrop.sh

But here’s the script:

#!/bin/bash
if ! ping -c 4 10.15.20.2; then
timestamp()
{
date +"%Y-%m-%d %T"
}

FLAGFILE=/var/run/vpnup
echo "$(timestamp): Damn! That sumbitch disconnected." >> /home/myusername/vpndisconnect.log
echo "VPN disconnected at $(timestamp)" | mail -s "VPN disconnection notice" -r "VPN Alert" myemaile@myemail2.com
sleep 3
sudo systemctl restart NetworkManager.service
sleep 3
nmcli con up id YourVPNConnectionHere
fi
sleep 5
if [ -e $FLAGFILE ]; then
exit 0
else
echo "VPN reconnected at $(timestamp)" | mail -s "VPN reconnection notice" -r "VPN Alert" myemaile@myemail2.com
fi
sleep 10
if [ ! -e $FLAGFILE ]; then
touch $FLAGFILE
fi

Note that I’ve replaced all my private info — including IP addresses — with dummies and aliases.

Yes, I could replace the “sleep” statements with better checking, but the script works for me and I don’t really need (or want) that complexity. I’m not launching rockets here.

Any questions, put on your own rocket and send them my way. I’ll answer with as much as I know.