This blog has been languishing - I’ve been busy. I’ve got some drafts that I need to finish up and post…
I’ve finally jumped onto the local only DSL bandwagon. If you haven’t done it yet, it’s a great way to save some bucks. The idea is that you get a local only account like this, which costs a fraction per GiB compared to normal account. Then you get your router to connect to both simultaneously, and route intelligently between them.
Most ADSL routers won’t let you connect 2 concurrent ADSL connections on the same ATM circuit. The solution is to use a separate modem and router. I’m using a basic Billion modem, in bridged mode, and a WRT54GL, running OpenWRT/kamikaze, as the router.
OpenWRT doesn’t support 2 PPPoE connections out of the box, but I’ve found the problems, and got a few changes committed upstream, that solve them:
The firewall needs to be modified with “WAN=ppp+” somewhere near the top, so that it masquerades all the ppp connections. This was a hack, apparently the firewall is being re-written soon.
There is also a bug that resets existing PPPoE connections on a ethernet interface when you fire up a new connection. This will apparently be fixed by the future interface aliasing support. For now, I just hacked around it in /lib/network/config.sh:
prepare_interface() {
local iface="$1"
local config="$2"
#SR: We don't want to reset any pppoe connections
config_get proto "$config" proto
[ "$proto" = "pppoe" ] && return 0
and /sbin/ifdown:
config_get ifname "$cfg" ifname
config_get device "$cfg" device
[ ."${proto%oe}" == ."ppp" ] && device=
[ ."$device" != ."$ifname" ] || device=
for dev in $ifname $device; do
ifconfig "$dev" 0.0.0.0 down >/dev/null 2>/dev/null
I got my local routes list from alm.za.net, saved it as a list in CDIR format. OpenWRT already has a static routing configuration system, but it’s very verbose. So I wrote my own, adding the new configuration option routefile. I used these hotplug scripts to set up routing and source routing, with the help of iproute2:
$ ipkg install ip
$ mkdir /etc/localroutes
$ wget http://alm.za.net/ip/localroutes4.txt -O - | awk '{print $4}' > /etc/routes/localroutes
$ cat /etc/config/network
# ...local interfaces...
#### WAN configuration
config interface wan
option ifname "eth0.1"
option proto pppoe
option username "xxxxx@international.co.za"
option password "xxxxxx"
option routefile "/etc/routes/exceptions"
option defaultroute 1
config interface localdsl
option ifname "eth0.1"
option proto pppoe
option username "xxxxx@local.co.za"
option password "xxxxxx"
option routefile "/etc/routes/zaroutes"
option defaultroute 0
$ cat /etc/iproute2/rt_tables
#
# reserved values
#
255 local
254 main
253 default
0 unspec
#
# local
#
1 wan
2 localdsl
$ cat /etc/hotplug.d/iface/20-split-routes
case "$ACTION" in
ifup)
. /etc/functions.sh
include /lib/network
scan_interfaces
config_get routefile "$INTERFACE" routefile
# Does this interface have custom routes?
if [ -e "$routefile" ]; then
# Add routes for this interface
cat "$routefile" | while read route; do
ip route add "$route" dev "$DEVICE"
done
# Set up source routing
peer=`ip addr show dev $DEVICE | sed -n '/inet/ s#.* peer \([0-9.]*\)/.*#\1# p'`
address=`ip addr show dev $DEVICE | sed -n '/inet/ s/.* inet \([0-9.]*\) .*/\1/ p'`
ip route add "$peer" dev "$DEVICE" src "$address" table "$INTERFACE"
ip route add default via "$peer" table "$INTERFACE"
ip rule add from "$address" table "$INTERFACE"
fi
# Make sure this interface is present in all the custom routing tables:
route=`ip route show dev "$DEVICE" | awk '/scope link src/ {print $1}'`
awk '/^[0-9]/ {if ($1 > 0 && $1 < 250) print $2}' /etc/iproute2/rt_tables | while read table; do
ip route add "$route" dev "$DEVICE" table "$table"
done
;;
esac
$ cat /etc/hotplug.d/net/20-split-routes
case "$ACTION" in
register)
. /etc/functions.sh
include /lib/network
scan_interfaces
# If this interface doesn't have a link local route, we don't need to bother
route=`ip route show dev "$INTERFACE" | awk '/scope link src/ {print $1}'`
[ ."$route" = ."" ] && return 0
# Add this interface's route to all custom routing tables
awk '/^[0-9]/ {if ($1 > 0 && $1 < 250) print $2}' /etc/iproute2/rt_tables | while read table; do
ip route add "$route" dev "$INTERFACE" table "$table"
done
;;
esac
Now, lastly, it won’t bring up both interfaces by default. That will be fixed by aliasing in the future, but for now:
$ cat /etc/init.d/network-multiwan
#!/bin/sh
ifup wan
ifup localdsl
$ chmod 755 /etc/init.d/network-multiwan
$ ln -s ../init.d/network-multiwan /etc/rc.d/S49network-multiwan
That’s it, and it’s working beautifully :-)
What is source routing, people ask? The problem is that your router now has 2 WAN IP addresses. IP1 is used for local traffic, and IP2 for international. So if somebody in ZA tries to connect to IP2, the reply (local destination) will go out of Interface 1. The ISP on the other end of Interface 1 will drop this reply, because it’s not coming from IP1.
Source routing tells the router that replies must go out of the same interface that the request came in on. I’m doing it by creating separate routing tables for traffic origionating from each WAN interface.