In this example we have an ADSL modem on ppp0 and a CableModem on eth1. All
referenced scripts can be found in a contrib directory, http://rcf.mvlan.net/dist/contrib/adsl-cable-failover/.
The idea is to use the ADSL to host web servers, etc., and the CableModem for all outgoing
stuff (like browsing the web from LAN PCs, outgoing e-mail, etc.). If one
of the lines goes down, traffic should start using the other viable
internet connection. This can all be done with routing. There's no
monitoring of anything involved.
You need a process that runs in order to move incoming connections
from one line to the other though. In this case, we assume you're using a dynamic
DNS, this is fairly easy. Monitor the ADSL line, if it goes down,
update the dynamic DNS with the Cable's IP (using the cable's outgoing
connection). Start monitoring the ADSL line, and when it comes back,
update the DNS entries with the ADSL's IP.
What you need is a startup script called 'route' (created by Jean-Sébastien Morisset). It sits in
/etc/rc.d/init.d/route and is executed when the system starts-up and
shuts down. The start/stop parameters introduce some default routes. The
script also needs to be executed when an interface is started. I.e. the
/etc/rc.d/init.d/adsl script will call /etc/rc.d/init.d/route, using the
'adsl' parameter, after successfully bringing up the ppp0 interface. Same
goes for the cable modem script (/etc/rc.d/init.d/dhcpcd).
Here are the details of the routing...
# ip ro ls
10.1.1.60 dev eth0 scope link src 10.1.1.60
255.255.255.255 dev eth0 scope link
64.39.160.16 dev ppp0 proto kernel scope link src 64.39.178.10
10.1.1.10 dev eth0 scope link window 16384
10.1.1.50 dev eth0 scope link src 10.1.1.50
10.1.1.1 dev eth0 scope link src 10.1.1.1
24.200.98.0/24 dev eth1 proto kernel scope link src 24.200.98.99
10.1.1.0/24 dev eth0 proto kernel scope link src 10.1.1.10
127.0.0.0/8 dev lo scope link window 16384
default via 24.200.98.1 dev eth1 metric 1000
default via 64.39.160.16 dev ppp0 metric 2000
Everything is fairly standard, except for the last two default routes. In this example, the
preferred outgoing route is eth1 (metric 1000). If it fails, then traffic
will start to go out ppp0 instead (metric 2000).
Here are iproute2's rules:
# ip ru ls
0: from all lookup local
500: from all to 10.1.1.0/24 lookup main
1000: from 24.200.98.99 lookup cable
2000: from 64.39.178.10 lookup adsl
3000: from all to 10.1.1.0/24 lookup main
5000: from all to 216.162.64.9 lookup adsl
5000: from all to 216.162.64.65 lookup adsl
5000: from all to 216.162.64.130 lookup adsl
5000: from all to 216.162.64.71 lookup adsl
5000: from all to 216.162.65.26 lookup adsl
5000: from all to 205.237.233.50 lookup cable
5000: from all to 205.237.233.52 lookup cable
5000: from all to 209.171.35.194 lookup adsl
5000: from all to 209.171.38.37 lookup adsl
5000: from all to 209.171.38.40 lookup adsl
5000: from all to 209.171.38.104 lookup adsl
32766: from all lookup main
32767: from all lookup default
Pref 500 allows LAN IPs to communicate with the firewall's public interfaces.
Pref 1000 uses the cable table to route all traffic from the cablemodem's IP.
Pref 2000 uses the adsl table to route all traffic from the adsl's IP.
Here's the cable routing table:
# ip ro ls tab cable
default via 24.200.98.1 dev eth1
And the adsl routing table:
# ip ro ls tab adsl
default via 64.39.160.16 dev ppp0
Don't forget that the 'route' script must be called if/when one of your public IPs change. The
cablemodem uses a dhcp client which executes a script called dhcpcd-eth1.exe
(created by Jean-Sébastien Morisset) after it changes the ip. This script reloads the firewall rules for
eth1 (only) and calls the 'route' script to update the routing tables.
The only thing left was sending web traffic to the secondary link if the
primary went down. Since this example uses a dynamic DNS, just update the domain with
the currently valid IP address. You could do the same with a static DNS,
but the TTL should be fairly low (30 secs in this case). Run a script
called check-routes every minute (in a cronjob) which pings the
dynamic DNS provider (you could use any reliable ip like www.sun.com, or
whatever). If the ping fails, then it tries from the secondary interface.
If it fails also, then it checks the gateways. When the primary link comes
back up, the DNS is updated once again. You probably want to avoid running this script as you're loading
firewall rules, so the crontab would look like this:
# Don't make any route changes, etc. when rcf is running.
*/5 * * * * [ "`ps --no-heading -C rcf`" ] || { /root/bin/check-interfaces; /root/bin/check-routes-and-dyndns; }
If you get the following error:
# ip ru ls
RTNETLINK answers: Invalid argument
Dump terminated
This just means you don't have the right kernel options selected. Configure your kernel like this:
# CONFIG_IP_MULTICAST is not set
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y
CONFIG_IP_ROUTE_MULTIPATH=y
CONFIG_IP_ROUTE_TOS=y
CONFIG_IP_ROUTE_VERBOSE=y
# CONFIG_IP_ROUTE_LARGE_TABLES is not set
# CONFIG_IP_ROUTE_NAT is not set
# CONFIG_IP_PNP is not set
CONFIG_IP_FIREWALL=y
CONFIG_IP_FIREWALL_NETLINK=y
CONFIG_IP_ROUTE_FWMARK=y
CONFIG_IP_TRANSPARENT_PROXY=y
CONFIG_IP_MASQUERADE=y
CONFIG_IP_MASQUERADE_ICMP=y
CONFIG_IP_MASQUERADE_MOD=y
CONFIG_IP_MASQUERADE_IPAUTOFW=m
CONFIG_IP_MASQUERADE_IPPORTFW=m
CONFIG_IP_MASQUERADE_MFW=m
CONFIG_IP_ROUTER=y
CONFIG_IP_ALIAS=y
# CONFIG_IPV6 is not set
# CONFIG_IPX is not set