Local only DSL
Update: Debian/Ubuntu version
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:
- Configurable default route: changeset 8569
- Allow specifying ppp unit numbers: changeset 8563+8564
- Support for multiple interfaces in UpdateDD (a DynDNS client): bug 2294
The firewall (/etc/init.d/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 done
I got my local routes list from cocooncrash's site (he gets them from local-route-server.is.co.za
, aggregates them, and publishes every 6 hours). 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/routes $ wget http://mene.za.net/za-routes/latest.txt -O /etc/routes/zaroutes
You'll probably want to update that route file regularly. I don't run cron on my WRT54GL, so I do it manually. Up to you.
/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
/etc/iproute2/rt_tables
:
# # reserved values # 255 local 254 main 253 default 0 unspec # # local # 1 wan 2 localdsl
/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
/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:
/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.
Gotchas
- If you are using 2 different ISPs (say SAIX international and IS local), you must make sure that DNS queries get routed out the right interface. SAIX won't accept queries on their servers from IS, and vice versa.
- SAIX Web proxies, Mail servers, and News servers don't accept traffic from local accounts. (especially from another ISP)