A Poor Man’s Solution for Automatic ISP Failover

This file should be installed on your router. In my case, I was testing with a VyOS router so I was able to easily extend it with this script. Just paste this into a new file and chmod +x to make it executable. Update the IP information below – most importantly, your LAN information. Then add it to a cron job and have it run once per minute. That’s it!


#!/bin/bash
PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin

# LAN IPs of ISP Routers to Use as the Default Gateway
PREFERRED="10.1.10.1"
ALTERNATE="10.1.10.3"

# Public Internet Hosts to Ping
PUBLICHOST1="8.8.8.8"
PUBLICHOST2="8.8.4.4"


# Ping the first public Internet device first.  See if it fails.
RETURNED=`/bin/ping -c 5 $PUBLICHOST1 | grep 'transmitted' | cut -d',' -f2 | sed -e 's/^ *//' | cut -d' ' -f1`

# If the first pings fail, check the secondary Internet device.
if [ $RETURNED -eq 0 ]; then # Do a second check just to be sure, and to a different IP.  Less pings, since we are already pretty sure of an issue
        echo "Failed ping test to $PUBLICHOST1.   Trying against $PUBLICHOST2."
        RETURNED=`/bin/ping -c 2 $PUBLICHOST2 | grep 'transmitted' | cut -d',' -f2 | sed -e 's/^ *//' | cut -d' ' -f1`
fi

# If it still fails, assume that the Internet is down.
if [ $RETURNED -eq 0 ]; then
        echo "Everything is not ok.  Looks like the Internet connection is down.  Better switch ISPs."
        date +%s > /tmp/cutover-start.log
else
        echo "Everything is ok.  Checking if we are using the preferred connection."
        CURRENT=`route -n | grep "^0.0.0.0" | cut -d' ' -f2- | sed -e 's/^ *//' | cut -d' ' -f1`
        if [ -f /tmp/cutover-start.log ]; then
                LASTSWITCHTIME=`cat /tmp/cutover-start.log | sed -e 's/\n//'`
        fi
        NOW=`date +%s`
        TIMEDIFF=$((NOW - LASTSWITCHTIME))
        if [ "$CURRENT" == "$ALTERNATE" ] && [ $TIMEDIFF -gt 300 ]; then           
                date +%s > /tmp/cutover-start.log
                echo "Testing if the primary gateway is back online."
                route add -host $PUBLICHOST2 gw $PREFERRED
                RETURNED=`/bin/ping -c 5 $PUBLICHOST1 | grep 'transmitted' | cut -d',' -f2 | sed -e 's/^ *//' | cut -d' ' -f1`
                if [ $RETURNED -eq 5 ]; then
                        echo "Switching back now that primary ISP is back online."
                        route del -net 0.0.0.0/0
                        route add default gw $PREFERRED
                else
                        echo "The primary host is not back online yet."
                fi
                route del -host $PUBLICHOST2
        fi
        exit
fi

# If the script does not exit before it reaches this point, then assume the worst.  Time to cutover to the other ISP

CURRENT=`route -n | grep "^0.0.0.0" | cut -d' ' -f2- | sed -e 's/^ *//' | cut -d' ' -f1`

# Delete the existing default gateway
route del -net 0.0.0.0/0

if [ "$CURRENT" == "$PREFERRED" ]; then
        echo "Switcing to the alternate ISP $ALTERNATE"
        route add default gw $ALTERNATE
else
        echo "Switching to the default ISP $PREFERRED"
        route add default gw $PREFERRED
fi