This article describes a script based algorithm and implementation for creating a kill switch enabled VPN connection that is resilient to VPN disconnections and non responding VPN servers on OpenWRT routers. This will result in high availability VPN connection to all router clients, and will avoid data leaks to regular network during the automatic reconnect attempts.
Introduction
This article is my conclusion of findings in search for configuration for OpenWRT routers that will enable VPN for all devices connected to it. I have written two other articles before on the same topic, but described in this article is the ultimate solution that enables kill switch when VPN is connecting or disabled, and also ensures VPN tunnel is auto restored when interrupted or inactive, using ping checks to any host of choice. Below is the algorithm diagram of what the scripts described in this article accomplish.
Resilient VPN Algorithm Flow Chart
As shown in the above diagram, the scripts run in a closed loop, trying to keep the VPN tunnel alive and running, so that router clients will have a highly available VPN connection, without intervention requiring manual re-connection or reboot. Script file names are given in the diagram blocks for easy reference.
Kill Switch Flow Chart
The kill switch flow chart is given above, and it ensures kill switch remains active even when interfaces are reconfigured or restarted.
Perquisite - Setting Up Router
First thing you need is a freshly flashed or re-setted OpenWRT router with OpenWRT version at or above 19.xx. You need to setup LAN and WIFI interfaces using configuration below. If you are not familiar with initial setup of OpenWRT routers, please refer to 'Setting up OpenWRT' section in this article.
Network Configuration
Make sure the network configuration file at /etc/config/network contains the following entries. Bolded lines are new.
config interface 'lan'
option device 'br-lan'
option proto 'static'
option netmask '255.255.255.0'
option ipaddr '192.168.3.1'
list dns '208.67.222.222'
list dns '208.67.220.220'
config interface 'wan'
option device 'wan'
option proto 'dhcp'
option peerdns '0'
config interface 'ovpn'
option proto 'none'
option device 'tun0'
option peerdns '0'
config interface 'wifi24'
option proto 'static'
option netmask '255.255.255.0'
list dns '208.67.222.222'
list dns '208.67.220.220'
option device 'wlan1'
option ipaddr '192.168.10.1'
config interface 'wifi50'
option proto 'static'
option netmask '255.255.255.0'
option device 'wlan0'
list dns '8.8.8.8'
list dns '8.8.4.4'
option ipaddr '192.168.11.1'
Make sure the DHCP configuration file at /etc/config/dhcp contains the following entries. Bolded lines are new.
config dhcp 'lan'
option interface 'lan'
option start '100'
option limit '150'
option leasetime '12h'
option dhcpv4 'server'
list dhcp_option '6,208.67.222.222,208.67.220.220'
config dhcp 'wifi24'
option interface 'wifi24'
option start '100'
option limit '150'
option leasetime '12h'
list dhcp_option '6,208.67.222.222,208.67.220.220'
config dhcp 'wifi50'
option interface 'wifi50'
option start '100'
option limit '150'
option leasetime '12h'
list dhcp_option '6,208.67.222.222,208.67.220.220'
Make sure the firewall configuration file at /etc/config/firewall contains the following entries. Bolded lines are new.
config zone
option name 'lan'
option input 'ACCEPT'
option output 'ACCEPT'
option forward 'ACCEPT'
list network 'lan'
list network 'wifi24'
list network 'wifi50'
config zone
option name 'wan'
option input 'REJECT'
option output 'ACCEPT'
option forward 'REJECT'
option masq '1'
option mtu_fix '1'
list network 'wan'
list network 'ovpn'
Enable WiFi
Steps to enable WiFi are given here.
After this initial step, reboot the router and test the internet connectivity on LAN and WiFi clients of the router for sanity. Interface IP address (example: 192.168.11.1) in configuration files above are arbitrary, but are used again in the kill switch scripts, hence make appropriate changes to addresses there as well if needed. This article also assumes three client interfaces lan
, wlan0
and wlan1
, omissions or additions can be made accordingly.
Install Packages
Two packages are needed for the scripts to work, run the below commands to install those.
opkg update
opkg install openvpn-openssl pingcheck
After the above commands are complete, remove all lines from /etc/config/pingcheck configuration file to avoid accidental script calls. This configuration file will be populated again in later steps.
Folder Structure of all Scripts
Below is the folder structure for all the files to be created on the router. Each file content is described in sections below. Make sure all these files are set as executable after creation.
Step 1: Kill Switch Scripts Setup
A single hot plug script described in this section will activate kill switch for all configured client interfaces. The method used to achieve this is to use a separate custom routing table for each interface on which routes will be added or deleted dynamically by scripts described in later sections. This ensures traffic from the interfaces flows only through a working VPN tunnel.
Add New Routing Tables
Add the following lines to add three new routing tables, at /etc/iproute2/rt_tables. Bolded lines are new. This created three new routing tables which will be associated with the three client interfaces.
#
# reserved values
#
128 prelocal
255 local
254 main
253 default
40 custom_lan
39 custom_wlan0
38 custom_wlan1
0 unspec
#
# local
#
Add Kill Switch Helper Scripts
Below is the folder structure for the kill switch helper scripts and contents of the scripts. Create them in the same locations and set them as executable.
activate-kill-switch-for-interface.sh
Create file /etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh with the following content:
interface_cidr=$1
interface_name=$2
interface_gateway=$3
table_name=$4
ip route flush $interface_cidr
ip rule add from $interface_cidr lookup $table_name
ip rule add from all to $interface_cidr lookup $table_name
ip route add $interface_cidr dev $interface_name scope link src $interface_gateway table $table_name
ip route add default via $interface_gateway table $table_name
ip route flush cache
kill-switch-setup-lan.sh
Create file /etc/openvpn/kill-switch/kill-switch-setup-lan.sh with the following content:
/etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh 192.168.3.0/24 br-lan 192.168.3.1 custom_lan
kill-switch-setup-wlan0.sh
Create file /etc/openvpn/kill-switch/kill-switch-setup-wlan0.sh with the following content:
/etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh 192.168.11.0/24 wlan0 192.168.11.1 custom_wlan0
kill-switch-setup-wlan1.sh
Create file /etc/openvpn/kill-switch/kill-switch-setup-wlan1.sh with the following content:
/etc/openvpn/kill-switch/activate-kill-switch-for-interface.sh 192.168.10.0/24 wlan1 192.168.10.1 custom_wlan1
Add Hot-Plug Script
A hot-plug script will watch interfaces and modify routes in routing tables with the help of the scripts above, to ensure the interfaces do not use the main routing table and the regular internet. You can read about OpenWRT hot-plug scripts here.
99-ifup-wan-interfaces
Create file /etc/hotplug.d/iface/99-wan-interfaces
with the following content:
wanstateret=`cat /tmp/wanstate`
lanstateret=`cat /tmp/lanstate`
wlan0stateret=`cat /tmp/wlan0state`
wlan1stateret=`cat /tmp/wlan1state`
wanstarted=`echo "$wanstateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
lanstarted=`echo "$lanstateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
wlan0started=`echo "$wlan0stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
wlan1started=`echo "$wlan1stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
killswitchlanstateret=`cat /tmp/killswitchlanstate`
killswitchwlan0stateret=`cat /tmp/killswitchwlan0state`
killswitchwlan1stateret=`cat /tmp/killswitchwlan1state`
killswitchlanstarted=`echo "$killswitchlanstateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
killswitchwlan0started=`echo "$killswitchwlan0stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
killswitchwlan1started=`echo "$killswitchwlan1stateret" started | awk '{ print ($1 == $2) ? 1 : 0 }'`
activatelankillswitch=0
activatewlan0killswitch=0
activatewlan1killswitch=0
if [ "${ACTION}" == "ifdown" ] && [ "${INTERFACE}" = "lan" ]
then
rm /tmp/killswitchlanstate
fi
if [ "${ACTION}" == "ifdown" ] && [ "${INTERFACE}" = "wifi50" ]
then
rm /tmp/killswitchwlan0state
fi
if [ "${ACTION}" == "ifdown" ] && [ "${INTERFACE}" = "wifi24" ]
then
rm /tmp/killswitchwlan1state
fi
if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "wan" ]
then
echo started > /tmp/wanstate
if [ $lanstarted -eq 1 ] && [ $killswitchlanstarted -eq 0 ]
then
activatelankillswitch=1
fi
if [ $wlan0started -eq 1 ] && [ $killswitchwlan0started -eq 0 ]
then
activatewlan0killswitch=1
fi
if [ $wlan1started -eq 1 ] && [ $killswitchwlan1started -eq 0 ]
then
activatewlan1killswitch=1
fi
fi
if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "br-lan" ]
then
echo started > /tmp/lanstate
if [ $wanstarted -eq 1 ] && [ $killswitchlanstarted -eq 0 ]
then
activatelankillswitch=1
fi
fi
if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "wlan0" ]
then
echo started > /tmp/wlan0state
if [ $wanstarted -eq 1 ] && [ $killswitchwlan0started -eq 0 ]
then
activatewlan0killswitch=1
fi
fi
if [ "${ACTION}" == "ifup" ] && [ "${DEVICE}" = "wlan1" ]
then
echo started > /tmp/wlan1state
if [ $wanstarted -eq 1 ] && [ $killswitchwlan1started -eq 0 ]
then
activatewlan1killswitch=1
fi
fi
if [ $activatelankillswitch -eq 1 ]
then
echo started > /tmp/killswitchlanstate
/etc/openvpn/kill-switch/kill-switch-setup-lan.sh
fi
if [ $activatewlan0killswitch -eq 1 ]
then
echo started > /tmp/killswitchwlan0state
/etc/openvpn/kill-switch/kill-switch-setup-wlan0.sh
fi
if [ $activatewlan1killswitch -eq 1 ]
then
echo started > /tmp/killswitchwlan1state
/etc/openvpn/kill-switch/kill-switch-setup-wlan1.sh
fi
exit 0
After creating this hot-plug script, internet for connected clients will be disabled on reboot and interface restarts, so do not panic. Internet will start working when rest of the setup is done and VPN connection is successful.
Step 2: Resilient VPN Scripts Setup
Add Resilient Folder Scripts
Below is the folder structure for the resilient VPN scripts and contents of the scripts. Create them in the same locations and set them as executable.
check-vpn-connection.sh
Create file /etc/openvpn/resilient/check-vpn-connection.sh
with the following content:
/etc/openvpn/leds/init-complete-led.sh off
/etc/openvpn/leds/connecting-led.sh on
connectedstatus=0
ovpnconnectedstatus=0
i=0
while [ $i -le 30 ]
do
sleep 1
i=`expr $i + 1`
if grep "Initialization Sequence Completed" /tmp/openvpn-main-log; then
connectedstatus=1
break;
fi
done
/etc/openvpn/leds/connecting-led.sh off
if [ $connectedstatus -eq 1 ]
then
/etc/openvpn/leds/init-complete-led.sh on
i=0
while [ $i -le 40 ]
do
sleep 1
i=`expr $i + 1
ovpnstateret=`cat /tmp/pingcheck-ovpnstate`
ovpnonline=`echo "$ovpnstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
if [ $ovpnonline -eq 1 ]
then
ovpnconnectedstatus=1
break;
fi
done
fi
if [ $connectedstatus -eq 0 ] || [ $ovpnconnectedstatus -eq 0 ]
then
sh /etc/openvpn/resilient/kill-vpn.sh
fi
kill-vpn.sh
Create file /etc/openvpn/resilient/kill-vpn.sh
with the following content:
openvpnpid=$(pidof openvpn)
kill $openvpnpid
echo "Killed openvpn"
resilient-vpn-pingcheck-controller.sh
Create file /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh
with the following content:
wanstateret=`cat /tmp/pingcheck-wanstate`
ovpnstateret=`cat /tmp/pingcheck-ovpnstate`
wanonline=`echo "$wanstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
ovpnonline=`echo "$ovpnstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
resilientrunningret=`cat /tmp/resilientrunningstatus`
resilientrunningstatus=`echo "$resilientrunningret" running | awk '{ print ($1 == $2) ? 1 : 0 }'`
if [ $wanonline -eq 1 ]
then
if [ $ovpnonline -eq 0 ]
then
/etc/openvpn/leds/connected-led.sh off
if [ $resilientrunningstatus -eq 0 ]
then
(sh /etc/openvpn/resilient/start-resilient-vpn.sh >/dev/null 2>&1 )&
echo running > /tmp/resilientrunningstatus
fi
if [ $resilientrunningstatus -eq 1 ]
then
sh /etc/openvpn/resilient/kill-vpn.sh
fi
fi
if [ $ovpnonline -eq 1 ]
then
/etc/openvpn/leds/init-complete-led.sh off
/etc/openvpn/leds/connected-led.sh on
fi
fi
if [ $wanonline -eq 0 ]
then
if [ $ovpnonline -eq 1 ]
then
/etc/openvpn/leds/init-complete-led.sh off
/etc/openvpn/leds/connected-led.sh on
fi
if [ $ovpnonline -eq 0 ]
then
sh /etc/openvpn/resilient/stop-resilient-vpn.sh
echo stopped > /tmp/resilientrunningstatus
fi
fi
start-openvpn-client.sh
Create file /etc/openvpn/resilient/start-openvpn-client.sh
with the following content:
dir='/etc/openvpn/configs'
n_files=`/bin/ls -1 "$dir" | wc -l | cut -f1`
rand_num=`awk "BEGIN{srand();print int($n_files * rand()) + 1;}"`
file=`/bin/ls -1 "$dir" | sed -ne "${rand_num}p"`
path=`cd $dir && echo "$PWD/$file"` # Converts to full path.
echo "Chosen file ${path}"
echo "${path}" > /tmp/openvpn-server.log
rm /tmp/openvpn-main-log
openvpn --config ${path} --log /tmp/openvpn-main-log
--auth-user-pass /etc/openvpn/credentials --up /etc/openvpn/up.sh
--down-pre --down /etc/openvpn/down.sh --route-noexec --dev tun0
--persist-local-ip --script-security 2
start-resilient-vpn.sh
Create file /etc/openvpn/resilient/start-resilient-vpn.sh
with the following content:
rm /tmp/openvpn-main-log
(sh /etc/openvpn/resilient/check-vpn-connection.sh >/dev/null 2>&1 )&
sh /etc/openvpn/resilient/start-openvpn-client.sh
checkscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/check-vpn-connection.sh")
kill $checkscriptpid
/etc/openvpn/leds/connecting-led.sh off
if grep "AUTH_FAILED" /tmp/openvpn-main-log; then
/etc/openvpn/leds/auth-failed-led.sh on
pause_connect_seconds=60
sleep $pause_connect_seconds
/etc/openvpn/leds/auth-failed-led.sh off
fi
exec sh /etc/openvpn/resilient/start-resilient-vpn.sh
stop-resilient-vpn.sh
Create file /etc/openvpn/resilient/stop-resilient-vpn.sh
with the following content:
resilientscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/start-resilient-vpn.sh")
kill $resilientscriptpid
checkscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/check-vpn-connection.sh")
kill $checkscriptpid
sh /etc/openvpn/resilient/kill-vpn.sh
openvpnscriptpid=$(pgrep -f "sh /etc/openvpn/resilient/start-openvpn-client.sh")
kill $openvpnscriptpid
rm /tmp/openvpn-main-log
sh /etc/openvpn/resilient/kill-vpn.sh
/etc/openvpn/leds/connected-led.sh off
/etc/openvpn/leds/connecting-led.sh off
/etc/openvpn/leds/init-complete-led.sh off
Add Route Creating Scripts
These scripts are called by the openvpn
command and up.sh create routes in the custom routing tables to enable VPN internet access to interfaces when running. down.sh removes the routes.
up.sh
Create file /etc/openvpn/up.sh
with the following content.
wanstrifconfig=$(ip -4 -o addr show wan)
wan_cidr=$(echo $wanstrifconfig | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\/[0-9]\{1,\}')
wan_interface_name=wan
vpn_gateway=$route_vpn_gateway
vpn_local=$ifconfig_local
vpn_mask=$ifconfig_netmask
remote_ip=$trusted_ip
device_name=$dev
router_gateway=$route_net_gateway
vpn_interface_cidr=`awk -v val="$vpn_gateway|$vpn_mask" '
function count1s(N){
c = 0
for(i=0; i<8; ++i) if(and(2**i, N)) ++c
return c
}
function subnetmaskToPrefix(input) {
split(input, inputParts, "|")
split(inputParts[2], subnetParts, ".")
split(inputParts[1], mainParts, ".")
if (subnetParts[1] == 0 ) {
mainParts[1] = 0
}
if (subnetParts[2] == 0 ) {
mainParts[2] = 0
}
if (subnetParts[3] == 0 ) {
mainParts[3] = 0
}
if (subnetParts[4] == 0 ) {
mainParts[4] = 0
}
printf "%d.%d.%d.%d/%d", mainParts[1], mainParts[2],
mainParts[3], mainParts[4], count1s(subnetParts[1]) + count1s
}
BEGIN {
subnetmaskToPrefix(val)
}'`
for vpn_table_name in custom_lan custom_wlan0 custom_wlan1 ; do
ip route add 0.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
ip route add 128.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
ip route add $vpn_interface_cidr dev $device_name scope link src
$vpn_local table $vpn_table_name
ip route add $remote_ip via $router_gateway dev wan table $vpn_table_name
ip route add $wan_cidr dev $wan_interface_name table $vpn_table_name
done
ip route flush cache
down.sh
Create file /etc/openvpn/down.sh
with the following content:
wanstrifconfig=$(ip -4 -o addr show wan)
wan_cidr=$(echo $wanstrifconfig | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\/[0-9]\{1,\}')
wan_interface_name=wan
vpn_gateway=$route_vpn_gateway
vpn_local=$ifconfig_local
vpn_mask=$ifconfig_netmask
remote_ip=$trusted_ip
device_name=$dev
router_gateway=$route_net_gateway
vpn_interface_cidr=`awk -v val="$vpn_gateway|$vpn_mask" '
function count1s(N){
c = 0
for(i=0; i<8; ++i) if(and(2**i, N)) ++c
return c
}
function subnetmaskToPrefix(input) {
split(input, inputParts, "|")
split(inputParts[2], subnetParts, ".")
split(inputParts[1], mainParts, ".")
if (subnetParts[1] == 0 ) {
mainParts[1] = 0
}
if (subnetParts[2] == 0 ) {
mainParts[2] = 0
}
if (subnetParts[3] == 0 ) {
mainParts[3] = 0
}
if (subnetParts[4] == 0 ) {
mainParts[4] = 0
}
printf "%d.%d.%d.%d/%d", mainParts[1], mainParts[2],
mainParts[3], mainParts[4], count1s(subnetParts[1]) + count1s
}
BEGIN {
subnetmaskToPrefix(val)
}'`
for vpn_table_name in custom_lan custom_wlan0 custom_wlan1 ; do
ip route flush 0.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
ip route flush 128.0.0.0/1 via $vpn_gateway dev $device_name table $vpn_table_name
ip route flush $vpn_interface_cidr dev $device_name scope link
src $vpn_local table $vpn_table_name
ip route flush $remote_ip via $router_gateway dev wan table $vpn_table_name
ip route flush $wan_cidr dev $wan_interface_name table $vpn_table_name
done
ip route flush cache
Add LED Control Helper Scripts
Tunnel status and connection status of the scripts can displayed on hardware LEDs which are usually available on OpenWRT
routers so that a quick feedback of the tunnel status can be obtained without needing to access the terminal. The following helper scripts are used by other scripts and should be modified according to LEDs available on the router model. You can read about LED control on OpenWRT routers here. You can see the LEDs available on your router using the below command:
ls /sys/class/leds/
Below is the folder structure for the led control scripts and contents of the scripts. Create them in the same locations and set them as executable.
auth-failed-led.sh
Create file /etc/openvpn/leds/auth-failed-led.sh with the following content:
status=$1
if [ "${status}" == "on" ]
then
echo timer > /sys/class/leds/{your_custom_auth_failed_led}/trigger
fi
if [ "${status}" == "off" ]
then
echo none > /sys/class/leds/{your_custom_auth_failed_led}/trigger
fi
connected-led.sh
Create file /etc/openvpn/leds/connected-led.sh with the following content:
status=$1
if [ "${status}" == "on" ]
then
echo default-on > /sys/class/leds/{your_custom_connected_led}/trigger
fi
if [ "${status}" == "off" ]
then
echo none > /sys/class/leds/{your_custom_connected_led}/trigger
fi
connecting-led.sh
Create file /etc/openvpn/leds/connecting-led.sh with the following content:
status=$1
if [ "${status}" == "on" ]
then
echo timer > /sys/class/leds/{your_custom_connecting_led}/trigger
fi
if [ "${status}" == "off" ]
then
echo none > /sys/class/leds/{your_custom_connecting_led}/trigger
fi
inactive-waiting-led.sh
Create file /etc/openvpn/leds/inactive-waiting-led.sh with the following content:
status=$1
if [ "${status}" == "on" ]
then
echo timer > /sys/class/leds/{your_custom_inactive_led}/trigger
fi
if [ "${status}" == "off" ]
then
echo none > /sys/class/leds/{your_custom_inactive_led}/trigger
fi
init-complete-led.sh
Create file /etc/openvpn/leds/init-complete-led.sh with the following content:
status=$1
if [ "${status}" == "on" ]
then
echo default-on > /sys/class/leds/{your_custom_complete_led}/trigger
fi
if [ "${status}" == "off" ]
then
echo none > /sys/class/leds/{your_custom_complete_led}/trigger
fi
Step 3: VPN Provider Files Setup
The configs folder needs to be populated with *.ovpn configuration files from VPN provider and the credentials file with the authentication details, example given below.
credentials
Create file /etc/openvpn/credentials with the following contents:
{your_vpn_username}
{your_vpn_password}
Testing VPN Provider
You can run the following command manually in terminal to test your VPN config files and credentials.
sh /etc/openvpn/resilient/start-openvpn-client.sh
In a different terminal, you can check the logs from the above script using the command below:
cat /etc/tmp/openvpn-main-log
If the VPN provider is working with the given ovpn configuration file and credentials, it will show up in the logs.
Step 4: Ping Checker Scripts Setup
If you have going through resilient controller script, it controls the VPN connection based on statuses which are setup by ping checker scripts. Read about pingcheck in the link here. The ping check scripts invoke the controller which controls the VPN connection.
Below is the folder structure for the ping check scripts and contents of the scripts. Create them in the same locations and set them as executable.
pingcheck-online.sh
Create file /etc/pingcheck/online.d/pingcheck-online.sh with the following content:
if [ "${INTERFACE}" == "wan" ]
then
echo online > /tmp/pingcheck-wanstate
fi
if [ "${INTERFACE}" == "ovpn" ]
then
echo online > /tmp/pingcheck-ovpnstate
fi
sh /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh
pingcheck-offline.sh
Create file /etc/pingcheck/offline.d/pingcheck-offline.sh with the following content:
if [ "${INTERFACE}" == "wan" ]
then
echo offline > /tmp/pingcheck-wanstate
fi
if [ "${INTERFACE}" == "ovpn" ]
then
echo offline > /tmp/pingcheck-ovpnstate
fi
sh /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh
pingcheck-panic.sh
Create file /etc/pingcheck/panic.d/pingcheck-panic.sh with the following content:
echo online > /tmp/pingcheck-panicstate
sh /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh
Final Step: Ping Checker Configuration
Add the following content to ping checker configuration file at /etc/config/pingcheck:
config default
option host 208.67.222.222
option interval 10
option timeout 120
option panic 4
config interface
option name wan
config interface
option name ovpn
option host 208.67.222.222
option interval 10
option timeout 40
The timeouts can be modified according to user preference, just remember that WAN timeout must be greater than VPN timeout. Reboot the router and check for internet access in clients and VPN connectivity.
(Optional) - Alternate Resilient Controller Mode
For folks with intermittent internet connectivity, the above algorithm will result in reconnection every time the internet goes out for more than timeout seconds parameter described in /etc/config/pingcheck configuration file, which will be inefficient reconnects for a few minutes of blackout. If the connection is to be preserved for at least a few minutes in the hopes that the internet comes back meanwhile, below is the alternate script for resilient connection. This mode is not recommended if internet is usually stable.
Update the following content in ping checker configuration file at /etc/config/pingcheck.
config default
option host 208.67.222.222
option interval 10
option timeout 30
option panic 4
config interface
option name wan
config interface
option name ovpn
option host 208.67.222.222
option interval 10
option timeout 50
Note that WAN timeout is lower than VPN timeout in this mode. Bolded lines are changed. Note that panic 4
means connection will be preserved for four minutes.
resilient-vpn-pingcheck-controller.sh
Replace /etc/openvpn/resilient/resilient-vpn-pingcheck-controller.sh
with the following content for alternate mode of operation.
wanstateret=`cat /tmp/pingcheck-wanstate`
ovpnstateret=`cat /tmp/pingcheck-ovpnstate`
wanonline=`echo "$wanstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
ovpnonline=`echo "$ovpnstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
resilientrunningret=`cat /tmp/resilientrunningstatus`
resilientrunningstatus=`echo "$resilientrunningret" running |
awk '{ print ($1 == $2) ? 1 : 0 }'`
panicstateret=`cat /tmp/pingcheck-panicstate`
panicstate=`echo "$panicstateret" online | awk '{ print ($1 == $2) ? 1 : 0 }'`
wanoutfirstret=`cat /tmp/resilient-wanoutfirst`
wanoutfirststatus=`echo "$wanoutfirstret" yes | awk '{ print ($1 == $2) ? 1 : 0 }'`
if [ $wanonline -eq 1 ]
then
if [ $ovpnonline -eq 0 ] && [ $wanoutfirststatus -eq 1 ]
then
rm /tmp/resilient-wanoutfirst
(sh /etc/openvpn/resilient/check-vpn-connection.sh >/dev/null 2>&1 )&
fi
if [ $ovpnonline -eq 0 ] && [ $wanoutfirststatus -eq 0 ]
then
/etc/openvpn/leds/connected-led.sh off
if [ $resilientrunningstatus -eq 0 ]
then
(sh /etc/openvpn/resilient/start-resilient-vpn.sh >/dev/null 2>&1 )&
echo running > /tmp/resilientrunningstatus
fi
if [ $resilientrunningstatus -eq 1 ]
then
sh /etc/openvpn/resilient/kill-vpn.sh
fi
fi
if [ $ovpnonline -eq 1 ]
then
/etc/openvpn/leds/init-complete-led.sh off
/etc/openvpn/leds/connected-led.sh on
fi
fi
if [ $wanonline -eq 0 ]
then
if [ $ovpnonline -eq 0 ] && [ $panicstate -eq 1 ]
then
sh /etc/openvpn/resilient/stop-resilient-vpn.sh
echo stopped > /tmp/resilientrunningstatus
rm /tmp/pingcheck-panicstate
fi
if [ $ovpnonline -eq 1 ]
then
/etc/openvpn/leds/init-complete-led.sh on
/etc/openvpn/leds/connected-led.sh on
echo yes > /tmp/resilient-wanoutfirst
fi
fi
Diagnosis
If something is wrong, you can check the following steps:
- Check executable status of all scripts
- Check log file at: /tmp/openvpn-main-log
- Remove the hot-plug script and test internet access
- Run manually start-openvpn-client.sh and check log file at /tmp/openvpn-main-log
Epilogue
This will be my final article on this topic as I cannot see any improvements to be made from my end and the objective of a high availability randomized kill switch enabled VPN router is achieved. I hope my effort will make it easy for folks seeking the same. Contact me if you need any clarification or help setting up!
History
- 16th July, 2023: Initial version