The FreeBSD Diary

The FreeBSD Diary (TM)

Providing practical examples since 1998

If you buy from Amazon USA, please support us by using this link.
Success Stories
 New Topic  |  Go to Top  |  Go to Topic  |  Search  |  Log In   Newer Topic  |  Older Topic 
 Switching default routing between two ISPs
Author: ongle 
Date:   14-09-05 01:28

I have both xDSL & a cable modem on my home network. Because the cable service often goes out for extended periods of time, I wanted to be able to switch my network's default route over to the xDSL service when the cable was down. I have many devices on the network including a FreeBSD 5.3 box that is used for local DNS, DHCP, mail, etc. I wasn't looking for load balancing or fail over, just a backup route that would keep me connected to the internet. I looked around on the 'net for ideas, but most of them seemed to need a multi-homed FreeBSD box with direct connections to the ISP's "modems". So, this is what I did. It may not be the best method (I'm not a BSD guru), but it works for me.

To make this work, I had to configure the FreeBSD box to act as the network gateway. I also had two cheap DSL/Cable routers, one each connected to the xDSL & Cable bridges, er, "modems". The FreeBSD box needs to have a network interface installed so it can ping both ISP routers, have routing enabled and have DNS installed locally (I used bind/named). Actually, you could have DNS running on another machine, but I won't go into that.

On my network, the DSL router has the address [] and the Cable router has the address []. You would obviously need to replace these references to the addresses used on your network.

I added the following entries to the /etc/rc.conf file:

static_routes="cable1 cable2 dsl1 dsl2"
route_dsl1=" -host"
route_dsl2=" -host"
route_cable1=" -host"
route_cable2=" -host"

The first line enables routing on the FreeBSD box. All other devices on the network will list the FreeBSD box as their default gateway (instead of one of the dsl/cable routers -- unless you *always* want a device to only use one ISP). The FreeBSD box will then forward the network packet to the correct router (xDSL or Cable).

The second line sets the default router of the FreeBSD box when it boots up. After that, the script below will change it as needed.

The third line defines a list of static routes for each ISP's DNS servers. I needed to do this so the FreeBSD box would always route DNS requests to the respective ISP's connection without using the box's default route.

The next four lines match the suffix listed in the "static_routes" line and define specific routes to specific DNS servers. This is ISP specific and be sure that each DNS server address is pointing to the correct dsl/cable router.

Once you have added these lines to your /etc/rc.conf file (remembering to substitute my sample addresses with yours), you need to update /var/named/etc/namedb/named.conf configuration file. All we are doing is adding “forwarders” to the configuration so bind will forward requests for hosts it does not know to one of the listed servers. If you already have bind running, then you likely already have a forwarders statement. If you don’t already have bind running, consult the FreeBSD Diary articles on the subject (,,, etc).

Add (or typically, replace) the following section to /var/named/etc/namedb/named.conf containing the DNS server addresses you added to the /etc/rc.conf file):

forwarders {;;;;

This will cause bind to forward requests to these servers, trying each one on the list until it gets a response (IIRC).

Now you are almost done. All you need to do is install and schedule the script that monitors the health of each connection and changes the FreeBSD box’s default route when needed. You can call the script anything you want, I call it monitor_isp.


set pgw = ""
set bgw = ""
set cgw = `netstat -rn | grep "^default" | awk '{print $2}'`

set out = "Current default gateway: $cgw"

set pl = `ping -n -c 5 -o -t 5 | grep " packet loss" | awk '{split($7, a, "%"); print a[1]}'`

if ($pl < 100) then
set out = "$out\nPrimary gateway is functional"

if ($cgw != $pgw) then
set out = "$out\nSwitching back to primary gateway"

set x = `route delete default`
set out = "$out\n$x"
set x = `route add default $pgw`
set out = "$out\n$x"

printf "$out\n"
set out = "$out\nPrimary gateway remains current"
set out = "$out\nPrimary gateway is not functional, checking backup gateway"

set pl = `ping -n -c 5 -o -t 5 | grep " 0% packet loss" | awk '{split($7, a, "%"); print a[1]}'`

if ($pl < 100) then
set out = "$out\nBackup gateway is functional"

if ($cgw != $bgw) then
set x = `route delete default`
set out = "$out\n$x"
set x = `route add default $bgw`
set out = "$out\n$x"
set out = "$out\nBackup gateway remains current"

printf "$out\n"

(formatting was lost by posting, sorry -- why no code tag?)

You'll need to update four lines in the code. Two at the very beginning to indicate the two DSL/Cable routers on your network (pgw=Primary Gateway, bgw=Backup Gateway). You'll also need to update the IP addresses in the two "ping" statements, the first one is a server on your primary ISP's network and the second one for your backup ISP's network. I use one of each ISP's DNS servers, but if your ISP's DNS servers won't respond to ping you may need to pick something else (e.g. mail server). It is important that you must have a static route defined to whatever server you end up using (see /etc/rc.conf above) and that the server being pinged is NOT reachable by the other ISP's connection. Failing all else, you could pick two servers on the net that you *never* visit but is always running. Define a static route to each using a different ISP for each, then use those servers in the "ping" statements.

Now that you have saved the script somewhere (I used /root/monitor_isp) and made it executable (chmod a+x monitor_isp), you just need to schedule it with cron. Edit the /etc/crontab file and add the following line (making any account or path changes you wish):

*/5 * * * * root /root/monitor_isp

This will cause the script to be executed every 5 minutes, which is good enough for my use. Your mileage may vary.

Now, just reboot the box to pick up all the changes and you are done. If the monitor_isp script changes the default route, cron will send an e-mail to the root account (by default) with the output. For example:

Current default gateway:
Primary gateway is not functional, checking backup gateway
Backup gateway is functional
delete net default
add net default: gateway

And when the primary ISP starts working again:

Current default gateway:
Primary gateway is functional
Switching back to primary gateway
delete net default
add net default: gateway

In summary, this method doesn't do load balancing or painless failover. If you are playing Everquest and your primary dies, you will get dropped and have to reconnect. But if you are just surfing the web, or need to have your mail or other server periodically connect to the internet, or are leaving a huge batch download running; this solution may work for you too.

P.S. Thanks for FreeBSD Diary; You've been a huge help to me!

Reply To This Message
 Forum List  |  Threaded View   Newer Topic  |  Older Topic 

 User Login
 User Name:
 Remember my login:
 Forgot Your Password?
Enter your email address or user name below and a new password will be sent to the email address associated with your profile.
How to get the most out of the forum