Split-Routing on Debian/Ubuntu
My post on split-routing on OpenWRT has been incredibly popular, and led to many people implementing split-routing, whether or not they had OpenWRT. While it's fun to have an exercise as a reader, it led to me having to help lots of newbies through porting that setup to a Debian / Ubuntu environment. To save myself some time, here's how I do it on Debian:
Background, especially for non-South Africa readers: Bandwidth in South Africa is ridiculously expensive, especially International bandwidth. The point of this exercise is that we can buy "local-only" DSL accounts which only connect to South African networks. E.g. I have an account that gives me 30GB of local traffic / month, for the same cost as 2.5GB of International traffic account. Normally you'd change your username and password on your router to switch account when you wanted to do something like an Debian apt-upgrade, but that's irritating. There's no reason why you can't have a Linux-based router concurrently connected to both accounts via the same ADSL line.
Firstly, we have a DSL modem. Doesn't matter what it is, it just has to support bridged mode. If it won't work without a DSL account, you can use the Telkom guest account. My recommendation for a modem is to buy a Telkom-branded Billion modem (because Telkom sells everything with really big chunky, well-surge-protected power supplies).
For the sake of this example, we have the modem (IP 10.0.0.2/24) plugged into eth0 on our server, which is running Debian or Ubuntu, doesn't really matter much - personal preference. The modem has DHCP turned off, and we have our PCs on the same ethernet segment as the modem. Obviously this is all trivial to change.
You need these packages installed:
# aptitude install iproute pppoe wget awk findutils
You need ppp interfaces for your providers. I created /etc/ppp/peers/intl-dsl
:
user intl-account@uber-isp.net unit 1 pty "/usr/sbin/pppoe -I eth0 -T 80 -m 1452" noipdefault defaultroute hide-password lcp-echo-interval 20 lcp-echo-failure 3 noauth persist maxfail 0 mtu 1492 noaccomp default-asyncmap
/etc/ppp/peer/local-dsl
:
user local-account@uber-isp.net unit 2 pty "/usr/sbin/pppoe -I eth0 -T 80 -m 1452" noipdefault hide-password lcp-echo-interval 20 lcp-echo-failure 3 connect /bin/true noauth persist maxfail 0 mtu 1492 noaccomp default-asyncmap
unit 1
makes a connection always bind to "ppp1". Everything else is pretty standard. Note that only the international connection forces a default route.
To /etc/ppp/pap-secrets
I added my username and password combinations:
# User Host Password intl-account@uber-isp.net * s3cr3t local-account@uber-isp.net * passw0rd
You need custom iproute2 routing tables for each interface, for the source routing. This will ensure that incoming connections get responded to out of the correct interface. As your provider only lets you send packets from your assigned IP address, you can't send packets with the international address out of the local interface. We get around that with multiple routing tables. Add these lines to /etc/iproute2/rt_tables
:
1 local-dsl 2 intl-dsl
Now for some magic. I create /etc/ppp/ip-up.d/20routing
to set up routes when a connection comes up:
That script loads routes from /etc/network/routes-intl-dsl
and /etc/network/routes-local-dsl
. It also sets up source routing so that incoming connections work as expected.
Now, we need those route files to exist and contain something useful. Create the script /etc/cron.daily/za-routes
(and make it executable):
It downloads the routes file from cocooncrash's site (he gets them from local-route-server.is.co.za
, aggregates them, and publishes every 6 hours). Run it now to seed that file.
Now some International-only routes. I use IS local DSL, so SAIX DNS queries should go through the SAIX connection even though the servers are local to ZA.
My /etc/network/routes-intl-dsl
contains SAIX DNS servers and proxies:
196.25.255.3 196.25.1.9 196.25.1.11 196.43.1.14 196.43.1.11 196.43.34.190 196.43.38.190 196.43.42.190 196.43.45.190 196.43.46.190 196.43.50.190 196.43.53.190 196.43.9.21
Now we can tell /etc/network/interfaces
about our connections so that they can get brought up automatically on bootup:
# This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). # The loopback network interface auto lo iface lo inet loopback # The primary network interface allow-hotplug eth0 iface eth0 inet static address 10.0.0.1 netmask 255.255.255.0 auto local-dsl iface local-dsl inet ppp provider local-dsl auto intl-dsl iface intl-dsl inet ppp provider intl-dsl
For DNS, I use dnsmasq, hardcoded to point to IS & SAIX upstreams. My machine's /etc/resolv.conf
just points to this dnsmasq.
So something like /etc/resolv.conf
:
nameserver 127.0.0.1
/etc/dnsmasq.conf
:
no-resolv # IS: server=168.210.2.2 server=196.14.239.2 # SAIX: server=196.43.34.190 server=196.43.46.190 server=196.25.1.11 domain=foobar.lan dhcp-range=10.0.0.128,10.0.0.254,12h dhcp-authoritative no-negcache
If you haven't already, you'll need to turn on ip_forward. Add the following to /etc/sysctl.conf
and then run sudo sysctl -p
:
net.ipv4.ip_forward=1
Finally, you'll need masquerading set up in your firewall. Here is a trivial example firewall, put it in /etc/network/if-up.d/firewall
and make it executable. You should probably change it to suit your needs or use something else, but this should work: