This article describes a Linux server set up with 2 interfaces (eth0) and (eth1). Each interface has a separate ISP, network details and default gateway. eth0 has two sets of network details on the same interface and so a virtual interface (eth0:0) must be created to handle the second IP.

By default, Linux only allows for one default gateway. Let’s see what happens if we try to use multiple uplinks with 1 default gateway. Assume eth0 is assigned 192.168.1.2/24 and eth1 is assigned 172.16.1.5/16. Let’s say our default gateway is 192.168.1.1 (which of course is found through eth0) but there’s also a 172.16.0.1 gateway on eth1 which we can’t enter as Linux only allows for the one.

Our routing table now looks like this:

root@www1:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
172.16.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth1

If a packet comes in to us, routed through the 172.16.0.1 gateway from say 8.8.8.8, our machine will receive it. When it tries to reply to 8.8.8.8 however, it runs down the routing table and sees that it’s not local to eth0 or eth1 and therefore will get routed out through the default gateway (192.168.1.1) – the problem is, this is the wrong gateway and so the target machine will ignore our response due to it being out of sequence and from the wrong IP.

Using iproute2, Linux can track multiple routing tables and therefore multiple default gateways. If the packet comes in through one interface and to one IP, it will go out via a specific default gateway. The script to achieve this is as follows:

IP1="192.168.1.10"   #interface IP
NM1="255.255.255.0"  #interface netmask
NW1="192.168.1.0"    #interface network address
PR1="24"	     #interface prefix (based on netmask)
GW1="192.168.1.1"    #interface gateway

IP2="10.4.50.4"
NM2="255.0.0.0"
NW2="10.0.0.0"
PR2="8"
GW2="10.0.0.1"

IP3="172.16.5.4"
NM3="255.255.0.0"
NW3="172.16.0.0"
PR3="16"
GW2="172.16.0.1"

#down the interfaces and wipe the existing config
ifconfig eth0 down
ifconfig eth1 down

#set ips
ifconfig eth0 up
ifconfig eth1 up
ifconfig eth0 $IP1 netmask $NM1
ifconfig eth0:0 $IP2 netmask $NM2
ifconfig eth1 $IP3 netmask $NM3

#add default gw
route add default gw $GW1 # set gw1 as system's default gw

#create tables
echo "103 WAN3" >> /etc/iproute2/rt_tables
echo "102 WAN2" >> /etc/iproute2/rt_tables
echo "101 WAN1" >> /etc/iproute2/rt_tables

#iproute2 routing
ip route add $NW1/$PR1 dev eth0 src $IP1 table WAN1
ip route add default via $GW1 table WAN1
ip route add $NW1/$PR1 dev eth0 src $IP1
ip rule add from $IP1 table WAN1
#--
ip route add $NW2/$PR2 dev eth0:0 src $IP2 table WAN2
ip route add default via $GW2 table WAN2
ip route add $NW2/$PR2 dev eth0:0 src $IP2
ip rule add from $IP2 table WAN2
#--
ip route add $NW3/$PR3 dev eth1 src $IP3 table WAN3
ip route add default via $GW3 table WAN3
ip route add $NW3/$PR3 eth1 src $IP3
ip rule add from $IP3 table WAN3

Rules and tables can also be shown and verified with:

ip route list table route2
ip rule show

Your Linux box can now correctly handle traffic coming in through any of the 3 IPs. iproute2 can in fact do a whole lot more than manage multiple default gateways, however this is one of it’s most common use cases.