Using OpenVPN as fallback connection

This article is about how to setup a fallback connection to reach your network if your NAT fails (eg your primary router with NAT dies and your failover without NAT comes up).

A week ago, our internet provider (T-Online, Deutsche Telekom) in the office decided to cut our connection – or at least he could’nt keep it stable up anymore. Since then, we see the sync-LED of the VDSL modem going on and off and it really sucks a lot. Luckily we are in an office complex with multiple WAN uplinks (from other companies) and thus could obtain WLAN access from our neighbours. Of course, this is not a good solution (their uplink has a tenth of our bandwidth) especially because we run some services (eg Nagios, some SSH servers and so on) NATed from our office router/firewall. Hopping to the next best WLAN allows us to keep on working but does not allow us to access our office-server remotely (i could and would not congfigure “foreign” routers).

So we needed a solution and found one using OpenVPN. It’s quite simple and took me about an hour to setup (mostly due to up-and-downs of our VDSL).

The general idea is to etablish a connection via VPN to a remote machine of us and make then NATting from there into the office back again. The VPN connection is etablished either via our “real” uplink or via the failover. It should not matter, that’s the point.

Install and prepare OpenVPN (on debian):

First install via aptitude:

aptitude install openvpn

Now generate a static key (it’s far more simple to create a point-2-point connection, then a net-2-net connection, even with NATting into the office net later on.. thus we dont need a CA and stuff).

openvpn --genkey --secret office-to-remote.key

Setup OpenVPN on outside machine and office Server

Remote machine:

/etc/openvpn/from-office.conf

dev tun
ifconfig 10.20.21.1 10.20.21.2
secret office-to-remote.key

And on the office server (some VM):

/etc/openvpn/to-remote.conf

remote remote.hostname
dev tun
ifconfig 10.20.21.2 10.20.21.1
secret office-to-remote.key

I started off with up and down scripts in the config files, but the network didn’t come up fast enough and it felt more stable with a cron-job. Following this routing script, which sets up routes from the office server to the network behind the remote machine and (this is the whole point) vice versa on the remote to the net behind the office server. Also does some masquerading and enables ip-forwarding (if not yet).

Routing Script:

/etc/openvpn/start-stop-routing.sh

#!/bin/bash

ROUTE_FILE="/etc/openvpn/$2.routes"
if [ -f $ROUTE_FILE -a -x $ROUTE_FILE ]; then
	. $ROUTE_FILE
else
	echo "Cannot find or execute routing file '$ROUTE_FILE'"
	exit 1
fi

function start_routing {

	# check wheter UP
	ping -c 1 -t 2 $REMOTE_IP 1>/dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo "-> Link Up"

		for net in ${REMOTE_NET[@]}; do
			ip route | grep $net 1>/dev/null 2>&1
			if [ $? -gt 0 ]; then
				ip route add $net via $REMOTE_IP
			fi
		done
		echo "-> All routes set"

		iptables -t nat -L POSTROUTING -n | grep $REMOTE_IP 1>/dev/null 2>&1
		if [ $? -gt 0 ]; then
			iptables -t nat -A POSTROUTING -s $REMOTE_IP -j MASQUERADE  1>/dev/null 2>&1
		fi
		echo "-> Masquerading local net"

		FORWARD=`cat /proc/sys/net/ipv4/ip_forward`
		if [ $FORWARD -eq 0 ]; then
			echo 1 > /proc/sys/net/ipv4/ip_forward
		fi
		echo "-> Forwarding enabled"
		return 0
	else
		echo "** No route to $REMOTE_IP "
		return 1
	fi
}

function stop_routing {
	for net in ${REMOTE_NET[@]}; do
		ip route | grep $net 1>/dev/null 2>&1
		if [ $? -eq 0 ]; then
			ip route del $net via $REMOTE_IP
		fi
	done
	echo "-> All routes removed"

	iptables -t nat -L POSTROUTING -n | grep $REMOTE_IP 1>/dev/null 2>&1
	if [ $? -eq 0 ]; then
		iptables -t nat -D POSTROUTING -s $REMOTE_IP -j MASQUERADE  1>/dev/null 2>&1
	fi
	echo "-> Masquerading deactivated"
}

case $1 in
	start)
		start_routing
		if [ $? -eq 1 ]; then
			stop_routing
		fi
	;;
	stop)
		stop_routing
	;;
	*)
		echo "Usage: $0 start|stop"
	;;
esac

This script also needs a config file on each machine. It should be in /etc/openvpn/<configname>.routes and set to executable:

Routing config on remote:

/etc/openvpn/from-office.routes

# remote ip from p2p
REMOTE_IP=10.20.21.1

# local ip from p2p
LOCAL_IP=10.20.21.2

# remote networks
REMOTE_NET=(
	"10.00.0.0/16"
	"10.100.0.0/16"
)

Routing config on office:

/etc/openvpn/to-remote.routes

# remote ip from p2p
REMOTE_IP=10.20.21.2

# local ip from p2p
LOCAL_IP=10.20.21.1

# office network
REMOTE_NET=(
	"192.168.100.0/24"
)

And now the cron-jobs..

Cron-Job on remote:

/etc/cron.d/check-routings-from-office

# Check every 5 minutes wheter the route from office is etablished or not
*/5 *     * * *     root   [ $( ps aux | grep from-office | grep -v grep | wc -l ) -gt 0 ] && /etc/openvpn/start-stop-routing.sh start from-office

Cron-Job on office:

/etc/cron.d/check-routings-to-remote

# Check every 5 minutes wheter the route to remote is etablished or not
*/5 *     * * *     root   [ $( ps aux | grep to-remote | grep -v grep | wc -l ) -gt 0 ] && /etc/openvpn/start-stop-routing.sh start to-remote

Finish

Thats all, the connection should be stable. OpenVPN is per default set to re-connect always and keep the link up and running. To connect now to a service on the office server we could either do some NATtings on the remote machine or tunnel via SSH:

ssh -g -N -L 10099:192.168.100.123:22 remote-machine &
ssh localhost -p 10099

As always: Use, rewrite and re-distribute any part of the above as you want; but dont blame me, if anything goes wrong, doesnt work or destroys something. No warranties.

Leave a Reply

CAPTCHA image