WAN Failover Script, Guide for DD-WRT and OpenWRT routers

A simplistic way to implement WAN fail-over on DD-WRT without altering your existing setup.

Script for Dual, Triple, Multiple WAN Failover

WAN Failover Script.

Use an old DDWRT router and convert it into a WAN failover gateway device using this Script.

Script To Add To Startup

Code To Add To Services > Additional Dnsmasq Options

Prerequisite for using this code

Necessary requirements before modifying your setup.

You have atleast 2 gateways that are on same subnet. For instance you can access internet from 2 gateways just by changing the gateway address of you device.

Additionally you should have a spare router running DDWRT.

Ofcourse you need to know some external IPs that are always online, for example Google DNS 8.8.8.8.

It is not possible to use iprule with following code, in case you need that functionality then use vlan approach.

Besides you need Notepad++ to edit the code and key in your script.

Accept the responsibility in case something goes wrong when using this script.

Startup Code For DDWRT

  • Add the following code to Startup in “Administration > Commands > Startup”.
  • Subsequently add static routes for the IP addresses that we will ping to check connectivity.
  • While DHCP server on every other device on the LAN should be disabled.
  • Similarly Enable DHCP on this router and disable WAN.
  • Additionally configure Additional DNSmasq options.

#!/bin/sh
echo "$(/bin/date +%H:%M:%S)" running startup script >> /tmp/var/log/messages

TIME=`/bin/date +%H:%M:%S`
RT=`uptime` 

# to reboot DDNS in case of WAN change
DDNSREBOOT='$(stopservice ddns;rm /tmp/ddns/inadyn_ip.cache;rm /tmp/ddns/inadyn_time.cache;nvram unset ddns_time;nvram unset ddns_cache;startservice ddns)'
eval echo $DDNSREBOOT

USINGWAN=FIRSTGW
echo "$(/bin/date +%H:%M:%S)" using WAN FIRST via "$( ip route | awk '/default via/')">> /tmp/var/log/messages

GW=br0
# you THIRD local gateway
THIRDGW=192.168.1.2
# you SECOND local gateway
SECONDGW=192.168.1.3
# you FIRST local gateway
FIRSTGW=192.168.1.4

#replace FIRSTIP with an external IP to check WAN FIRST , make sure to add that with a static route too in Advanced routing
TARGETFIRST1=`ping -c 3 -W 1 FIRSTIP 2>/dev/null | awk '/packets received/ {print $4}'`

#replace SECONDIP with an external IP to check WAN SECOND , make sure to add that with a static route too in Advanced routing
TARGETSECOND1=`ping -c 3 -W 1 SECONDIP 2>/dev/null | awk '/packets received/ {print $4}'`

#replace THIRDIP with an external IP to check WAN THIRD , make sure to add that with a static route too in Advanced routing
TARGETTHIRD1=`ping -c 3 -W 1 THIRDIP 2>/dev/null | awk '/packets received/ {print $4}'`

if [ "$TARGETFIRST1" -ge "1" ]; then
ip route delete default via $THIRDGW dev $GW
ip route delete default via $SECONDGW dev $GW
ip route add default via $FIRSTGW dev $GW
USINGWAN=FIRSTGW
echo "$(/bin/date +%H:%M:%S)" using WAN FIRST via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
if [ "$TARGETFIRST1" -lt "1" ] && [ "$TARGETTHIRD1" -ge "1" ] && [ "$TARGETSECOND1" -ge "1" ] ; then
ip route delete default via $FIRSTGW dev $GW
ip route delete default via $THIRDGW dev $GW
ip route add default via $SECONDGW dev $GW
USINGWAN=SECONDGW
echo "$(/bin/date +%H:%M:%S)" using WAN SECOND via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
if [ "$TARGETFIRST1" -lt "1" ] && [ "$TARGETTHIRD1" -lt "1" ] && [ "$TARGETSECOND1" -ge "1" ] ; then
ip route delete default via $THIRDGW dev $GW
ip route delete default via $FIRSTGW dev $GW
ip route add default via $SECONDGW dev $GW
USINGWAN=SECONDGW

echo "$(/bin/date +%H:%M:%S)" using WAN SECOND via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
if [ "$TARGETFIRST1" -lt "1" ] && [ "$TARGETTHIRD1" -ge "1" ] && [ "$TARGETSECOND1" -lt "1" ] ; then
ip route delete default via $FIRSTGW dev $GW
ip route delete default via $SECONDGW dev $GW
ip route add default via $THIRDGW dev $GW
USINGWAN=THIRDGW

echo "$(/bin/date +%H:%M:%S)" using WAN THIRD via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
if [ "$TARGETFIRST1" -lt "1" ] && [ "$TARGETTHIRD1" -lt "1" ] && [ "$TARGETSECOND1" -lt "1" ] ; then
USINGWAN=DEAD
echo "$(/bin/date +%H:%M:%S)" using WAN NONE via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi

sleep 6

while sleep 2
do
# replace firstip, firstip2, secondip, secondip2, thirdip, thirdip2 with external IP which are forwarded through static routing.
TARGETFIRST=$((`ping -c 4 -W 1 firstip 2>/dev/null | awk '/packets received/ {print $4}'` + `ping -c 2 -W 1 firstip2 2>/dev/null | awk '/packets received/ {print $4}'`))
TARGETSECOND=$((`ping -c 2 -W 1 secondip 2>/dev/null | awk '/packets received/ {print $4}'` + `ping -c 2 -W 1 secondip2 2>/dev/null | awk '/packets received/ {print $4}'`))
TARGETTHIRD=$((`ping -c 2 -W 1 thirdip 2>/dev/null | awk '/packets received/ {print $4}'` + `ping -c 2 -W 1 thirdip2 2>/dev/null | awk '/packets received/ {print $4}'`))

DATE=`/bin/date +%H:%M:%S`

UT=`uptime`

if [ "$TARGETFIRST" -lt "1" ]; then
WAN1=$DOWN
gpio enable 30
WHD1=`tail -n 2 /tmp/var/log/messages | awk '// {count[$2]++} END {print count["WAN.FIRST.down"]}'`
if [ "$WHD1" = "" ]; then
echo -e ""$(/bin/date +%H:%M:%S)" WAN.FIRST.down"  >> /tmp/var/log/messages
fi
fi
if [ "$TARGETSECOND" -lt "1" ]; then
WAN2=$DOWN
gpio enable 29
WHD2=`tail -n 2 /tmp/var/log/messages | awk '// {count[$2]++} END {print count["WAN.SECOND.down"]}'`
if [ "$WHD2" = "" ]; then
echo -e ""$(/bin/date +%H:%M:%S)" WAN.SECOND.down"  >> /tmp/var/log/messages
fi
fi
if [ "$TARGETTHIRD" -lt "1" ]; then
WAN3=$DOWN
gpio enable 28
WHD3=`tail -n 2 /tmp/var/log/messages | awk '// {count[$2]++} END {print count["WAN.THIRD.down"]}'`
if [ "$WHD3" = "" ]; then
echo -e ""$(/bin/date +%H:%M:%S)" WAN.THIRD.down"  >> /tmp/var/log/messages
fi
fi

if [ "$TARGETFIRST" -ge "2" ]; then
WAN1=$UP
gpio disable 30
fi
if [ "$TARGETSECOND" -ge "2" ]; then
WAN2=$UP
gpio disable 29
fi
if [ "$TARGETTHIRD" -ge "2" ]; then
WAN3=$UP
gpio disable 28
fi

if [ "$USINGWAN" = "THIRDGW" ] || [ "$USINGWAN" = "DEAD" ]; then
if [ "$TARGETFIRST" -ge "2" ]; then
ip route delete default via $THIRDGW dev $GW
ip route delete default via $SECONDGW dev $GW
ip route add default via $FIRSTGW dev $GW
USINGWAN=FIRSTGW

eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN FIRST via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 

if [ "$TARGETFIRST" -lt "1" ] && [ "$TARGETTHIRD" -ge "2" ] && [ "$TARGETSECOND" -ge "2" ] ; then
ip route delete default via $FIRSTGW dev $GW
ip route delete default via $THIRDGW dev $GW
ip route add default via $SECONDGW dev $GW
USINGWAN=SECONDGW
eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN SECOND via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 

if [ "$TARGETFIRST" -lt "1" ] && [ "$TARGETTHIRD" -lt "1" ] && [ "$TARGETSECOND" -ge "2" ] ; then
ip route delete default via $THIRDGW dev $GW
ip route delete default via $FIRSTGW dev $GW
ip route add default via $SECONDGW dev $GW
USINGWAN=SECONDGW

eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN SECOND via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
fi

if [ "$USINGWAN" = "SECONDGW" ] || [ "$USINGWAN" = "DEAD" ]; then
if [ "$TARGETFIRST" -ge "2" ]; then
ip route delete default via $THIRDGW dev $GW
ip route delete default via $SECONDGW dev $GW
ip route add default via $FIRSTGW dev $GW
USINGWAN=FIRSTGW

eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN FIRST via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
if [ "$TARGETFIRST" -lt "1" ] && [ "$TARGETTHIRD" -ge "2" ] && [ "$TARGETSECOND" -lt "1" ] ; then
ip route delete default via $FIRSTGW dev $GW
ip route delete default via $SECONDGW dev $GW
ip route add default via $THIRDGW dev $GW
USINGWAN=THIRDGW

eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN THIRD via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
fi;

if [ "$USINGWAN" = "FIRSTGW" ] || [ "$USINGWAN" = "DEAD" ] ; then
if [ "$TARGETFIRST" -lt "1" ] && [ "$TARGETTHIRD" -ge "2" ] && [ "$TARGETSECOND" -ge "2" ] ; then
ip route delete default via $FIRSTGW dev $GW
ip route delete default via $THIRDGW dev $GW
ip route add default via $SECONDGW dev $GW
USINGWAN=SECONDGW

eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN SECOND via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 

if [ "$TARGETFIRST" -lt "1" ] && [ "$TARGETTHIRD" -lt "1" ] && [ "$TARGETSECOND" -ge "2" ] ; then
ip route delete default via $THIRDGW dev $GW
ip route delete default via $FIRSTGW dev $GW
ip route add default via $SECONDGW dev $GW
USINGWAN=SECONDGW

eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN SECOND via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 

if [ "$TARGETFIRST" -lt "1" ] && [ "$TARGETTHIRD" -ge "2" ] && [ "$TARGETSECOND" -lt "1" ] ; then
ip route delete default via $FIRSTGW dev $GW
ip route delete default via $SECONDGW dev $GW
ip route add default via $THIRDGW dev $GW
USINGWAN=THIRDGW

eval echo $DDNSREBOOT
echo "$(/bin/date +%H:%M:%S)" using WAN THIRD via "$( ip route | awk '/default via/')">> /tmp/var/log/messages
fi 
fi;

if [ "$TARGETFIRST" -lt "1" ] && [ "$TARGETTHIRD" -lt "1" ] && [ "$TARGETSECOND" -lt "1" ] ; then
USINGWAN=DEAD

echo "$(/bin/date +%H:%M:%S)" all WAN dead >> /tmp/var/log/messages

WANHTM=`echo -e WAN DETAILS "<br />\\n"$UT "<br />"$DATE "<br />"ALL LINKS DROPPED EMERGENCY!!! "<br />\\n"LAN DETAILS"<br />\\n"`
awk -v new="$WANHTM" '/WAN DETAILS/{print new} /WAN DETAILS/,/LAN DETAILS/{next} 1' /tmp/www/ps.htm > /tmp/tmpTARGETSECOND && mv /tmp/tmpTARGETSECOND /tmp/www/ps.htm

fi;

WANHTM=`echo -e WAN DETAILS "<br />\\n"$UT "<br />"$DATE "<br />"USING "<strong>" $USINGWAN "</strong>" via "$( ip route | awk '/default via/')" "<br />"WAN1 = $WAN1 "<br />"WAN2 = $WAN2 "<br />"WAN3 = $WAN3 "<br />"WAN4 = NOT ACTIVE"<br />\\n"LAN DETAILS"<br />\\n"`
awk -v new="$WANHTM" '/WAN DETAILS/{print new} /WAN DETAILS/,/LAN DETAILS/{next} 1' /tmp/www/ps.htm > /tmp/tmpTARGETSECOND && mv /tmp/tmpTARGETSECOND /tmp/www/ps.htm

DEAD=`tail -n 15 /tmp/var/log/messages | awk '// {count[$4]++} END {print count["dead"]}'`
if [ "$DEAD" -ge "1" ] && ([ "$TARGETFIRST" -ge "2" ] || [ "$TARGETSECOND" -ge "2" ] || [ "$TARGETTHIRD" -ge "2" ]); then
echo -e ""$(/bin/date +%H:%M:%S)" back to using WAN \\n15 \\n14 \\n13 \\n12 \\n11 \\n10 \\n9 \\n8 \\n7 \\n6 \\n5 \\n4 \\n3 \\n2 \\n1"  >> /tmp/var/log/messages
fi
done


WN failover settings
Static Routing.

Disable WAN and set preferred Gateway

Enable DHCP server

Add to Services > Additional Dnsmasq Options

dhcp-option=br0,3,192.168.1.1
strict-order
server=8.8.8.8
server=8.8.4.4
server=208.67.222.222

That is it, click Save and then reboot router.

This script essentially makes the router acts as a gateway or forwarding device within the subnet. Additionally it does not perform any NAT. As a result it can decide which gateway to forward the traffic to and act as a WAN failover router. Furthermore disabling DHCP on other routers make sure that all devices get a lease from this unit only.

Credits: Buy Guru

DDWRT Tutorial For Original Method With iprule Support And NAT.

Buy Latest Wi-Fi Routers on Amazon


This Post Has One Comment

  1. MikeD.

    spot on, job well done. finally it is amazing to be able to use a old router for wan failover and multiple WAN.

Leave a Reply