Innovative Technology

This is a short description of how to add a backup internet route to a Linux box using a 3G mobile broadband modem.

3G Modem Internet Backup

I've had trouble recently with our office internet connection, and also with my home ADSL. This prompted me to finish a little project I started a while ago.

About a year ago, I got a 3G dongle to give me mobile broadband. I signed up to a contract with Vodafone, and was very pleased that I was able to use the Huawei USB 3G dongle with all my Linux devices. I did make a bit of a mistake in not opting for a pay-as-you-go plan, and the sense that I was often paying my monthly fee for nothing (yes, I hardly use the thing!) got me thinking about alternative uses.

I decided to use the 3G modem as a backup for my internet connection. The idea was not to use it in tandem with the ADSL modem (possible, but for me, not really necessary) but to use it as a backup route, in case the ADSL were to fail (unusual, my provider "Freedom2surf-on-a-BT-line" is very reliable). The idea was to be able to plug the 3G modem into a Linux box in my attic and for the routing to automatically switch over to the modem, so that all the devices in the house/office would route through the Linux box via the 3G modem, rather than through the Linux box via the ADSL router.

Regular Network Setup

In order to be able to switch seamlessly between your normal DSL router and the 3G modem, you'll need a network setup using a Linux machine as the "network manager". In a normal home or small office setup, you'd use the DSL modem-router as the "network manager" - you'd most likely use its DHCP server feature, and your client machines would all route to the internet through the DSL modem-router.

To be able to use the 3G modem as a backup, you need your Linux network manager. Your clients will obtain an IP address from this machine, use it for DNS requests and route to the internet via the machine. This way, when you plug the 3G modem into the network manager box, it can update its default route to the internet, but none of the clients have to change their configuration.

Time, I think, for a badly drawn network diagram!


Ignoring the 3G modem to begin with, here's how my network is configured:

The Netgear ADSL router has 4 wired sockets and a 802.11b/g wireless antenna. We have an Ubuntu PC, an Ubuntu netbook and a small Debian box (the hardware is one of the Sumo thin client devices as sold by us via this site). All these devices have IP addresses in the 192.168.0.0/24 range.

Some important points:

  • The Netgear does NOT provide DHCP services, that is handled by the Debian box.
  • The client devices - the PC and netbook - obtain their IP address from the Debian box AND use the Debian box as a DNS server, so...
  • The Debian box has dhcpd and bind9 installed and configured.
  • All the client devices use the Debian box as a default router - they don't use the Netgear for their default route. They route through the Debian box, and the Debian box then routes through the Netgear to the outside world.

DHCP

Although the Netgear can hand out IP addresses using DHCP (in fact, it does this by default) it is unable to hand out a default gateway address that is not itself. For this reason, I have to use a DHCP server running on the Debian box. I'm not going to go into the ins and outs of setting up the ISCD dhcpd (package dhcp3-server in Debian). Here is the config I'm running. Note that I set "option domain-name-servers" and "option routers" both to be 192.168.0.7, which is the Debian box itself (that is, its eth0 address).

ddns-update-style       ad-hoc;
default-lease-time       21600;
max-lease-time            21600;
option subnet-mask    255.255.255.0;
option broadcast-address         192.168.0.255;
option routers                               192.168.0.7;
option domain-name-servers   192.168.0.7;
option domain-name                   "mylan";
option log-servers                       192.168.0.7;
shared-network ADSLSTATIONS
    option subnet-mask                       255.255.255.0;
    option broadcast-address           192.168.0.255;
    option routers                                 192.168.0.7;
    option domain-name-servers     192.168.0.7;
    option domain-name                     "mylan";
    option log-servers                         192.168.0.7;
}

Routing

The clients receive the information via DHCP that they should route via the Debian box.

The routing on the Debian box for eth0 is configured simply using the standard network setup for the box, specified in Debian in /etc/network/interfaces. Here is the stanza, it's quite a standard setup:

auto eth0
iface eth0 inet static
     address 192.168.0.7
     gateway 192.168.0.100
     netmask 255.255.255.0

The gateway is specified as the DSL modem-router (192.168.0.100 on this network).

The only other thing that has to be done is to ensure that "1" is placed into /proc/sys/net/ipv4/ip_forward. You can do it manually using this command:

echo "1" > /proc/sys/net/ipv4/ip_forward

To ensure this is done on every boot of the machine, you can put the line "ip_forward=yes" into a file called /etc/network/options on Debian.

DNS (bind)

Again, I'm not going to try to give a full account of the setup of bind9 on Debian. The main thing we want is for bind9 to be a forwarder - that is when I make a DNS query to the Debian box, it will (unless its a LAN address) pass the request on to my DSL router, which itself passes the request on to the DNS servers provided by my ISP. This forwarding behaviour is achieved by editing /etc/bind/named.conf.options. My named.conf.options file contains (I've stripped out most of the comments):

 

 options {

        directory "/var/cache/bind" ;

        # 192.168.0.100 is the Netgear router.

        # 10.206.65.68 is the Vodafone DNS server for 3G modems.

        forwarders {192.168.0.100; 10.206.65.68;};

        auth-nxdomain no; # conform to RFC1035 listen-on-v6 { any; };

};

 

The key thing here is that I've listed in the forwarders field both the DSL modem AND the DNS server used when I plug in my dongle.

Adding the 3G Dongle

With the above network functioning correctly, we can move on to thinking about adding the 3G modem. My Huawei 3G dongle is supported in kernels from about 2.6.19/20ish. I'm running Debian Etch on this box, so I used make-kpkg to build a more recent kernel than the 2.6.18 kernel which comes with Etch. Using Debian Lenny, I'd not have had to do this. If you have to compile up a new kernel, don't forget to include the iptable_nat.ko feature, which will be necessary later on.

The dongle is dialled up using a program called wvdial in my setup, creating a new network interface called ppp0. Then we alter the routing table for the new interface, so that it becomes the default route, and add in (with the help of the iptables command) Source Network Address Translation (SNAT) so that the client devices can all route through the modem. Without SNAT, only the Debian box itself would be able to access the internet via the 3G dongle. We don't need SNAT when accessing via the Netgear as the Netgear itself applies SNAT (using the same code - it's based on Linux, too).

All of this is directed by udev - which reacts to the event of the 3G modem being plugged in to the Debian box, and runs scripts (which we have to add) to re-configure the system.

wvdial configuration

You may need to consult howtos specific to your 3G modem, but for my Huawei one, and my Vodafone 3G ISP, my /etc/wvdial.conf is:

# wvdial for Vodacom Data. Created by Tazz_tux
# Version 1.0

# Change Log:
#
# Added support for HSDPA.
# Added Headers and version control.

[Dialer Defaults]
Phone = *99***1#
Username = username
Password = password
Stupid Mode = 1
Dial Command = ATDT

[Dialer hsdpa]
Modem = /dev/ttyUSB0
Baud = 460800
Init2 = ATZ
Init3 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
ISDN = 0
Modem Type = Analog Modem
Audo DNS = off

Thanks to Tazz_tux for that one. With this config, I can connect the 3G modem with the command "wvdial hsdpa".

udev configuration

The really neat part of this system is the way that all the setup is executed when you plug the 3G dongle in, and then normal behaviour is restored when you remove the dongle. This is achieved with the help of udev.

Add a new rule for your dongle in /etc/udev. Add dongle.rules to /etc/udev/ and in /etc/udev/rules.d/ add a symlink to that file called something like z85_dongle.rules.

dongle.rules is:

# BUS=="usb", SYSFS=="12d1", SYSFS=="1003",
ACTION=="add", \
    KERNEL=="ttyUSB1" \
    RUN+="/usr/local/bin/fireup_dongle"
#BUS=="usb", SYSFS=="12d1", SYSFS=="1003",
ACTION=="remove", \
    KERNEL=="ttyUSB1" \
    RUN+="/usr/local/bin/bringdown_dongle"

ACTION=="add", SUBSYSTEM=="net", KERNEL=="ppp0", \
    RUN+="/usr/local/bin/ppp0_route_setup"
ACTION=="remove", SUBSYSTEM=="net", KERNEL=="ppp0", \
    RUN+="/usr/local/bin/ppp0_route_revert"

This causes udev to run a script called fireup_dongle.sh when the dongle is plugged in and ppp0_route_setup when the ppp0 network interface appears.

When the ppp0 interface disappears, ppp0_route_revert is run and when the USB device is removed, bringdown_dongle is executed.

udev scripts

fireup_dongle

Here's fireup_dongle, which creates a lock file, and then runs wvdial to connect the 3G modem.

#!/bin/sh

lock=/tmp/.dongle.lock
if [ ! -f $lock ]
then
    touch $lock
    sleep 6
    if [ -c /dev/ttyUSB0 ]
    then
        /usr/bin/wvdial hsdpa >>/var/log/dongle.log 2>&1 &
    else
        rm -f $lock
        echo "No ttyUSB0 device right now" >>/var/log/dongle.log
        exit 0
    fi
else
    echo "dongle is locked, no action" >>/var/log/dongle.log
fi

exit 0

bringdown_dongle

bringdown_dongle ends the connection by killing the wvdial process:

#!/bin/sh

lock=/tmp/.dongle.lock
if [ -f $lock ]
then
    sleep 1
    killall wvdial
    echo "bringdown_dongle: Sent kill signal to wvdial"
    rm -f $lock
else
    echo "bringdown_dongle: No dongle lock, not killing wvdial"
fi

exit 0

ppp0_route_setup

This deletes the normal default route through the DSL modem, and adds a default gw of 10.64.64.64 - the IP address which is always assigned to the partner address for my ppp0 modem interface (i.e. the ISP end). The line which adds the SNAT feature obtains the current IP address of my ppp0 network interface from an ifconfig command.

#!/bin/bash

# Set up the routes for the newly added dongle
sleep 15

route del default
route add default gw 10.64.64.64
# Need NAT for our box to be a router with the dongle:


iptables -t nat -A POSTROUTING -o ppp0 -j SNAT \
    --to-source `ifconfig ppp0 | grep inet\ addr | awk -F' ' '{ print $2; }'|awk -F':' '{print $2;}'`

echo "ppp0_route_setup: Changed default route to go via dongle." >> /var/log/dongle.log

ppp0_route_revert

The final script removes the SNAT rule, then reverts the default route back to the DSL modem.

#!/bin/bash

# Remove SNAT iptables rule
iptables -t nat -D POSTROUTING 1

# Change default route.
route del default
route add default gw 192.168.0.100

echo "ppp0_route_setup: Changed default route to go via Netgear." >> /var/log/dongle.log

Notes

The ppp0 connection is un-firewalled in this example. I will probably go on to implementing this in the office. There, I will add a pair of scripts ppp0_iptables_setup and ppp0_iptables_revert which, in addition to managing the NAT configuration, will also add packet filtering rules to ensure that it is difficult for someone on the 3G network to attempt to crack my machine via this route.

Don't forget to make the scripts executable!