Resilient High Availability VPN with Kill Switch in OpenWRT Routers





0/5 (0 vote)
An algorithm and a set of scripts which work in a closed loop on an OpenWRT router that enable resilient and high availability VPN (openvpn) connection for all connected router clients
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:
#!/bin/sh 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:
#!/bin/sh /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:
#!/bin/sh /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:
#!/bin/sh /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:
#!/bin/sh 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:
#!/bin/sh /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 # check pingcheck status for 40 seconds 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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 # Wait for some time to stop overloading /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:
#!/bin/sh 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.
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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:
#!/bin/sh 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.
#!/bin/sh 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