Pi and More

Willkommen

Herzlich willkommen auf meiner Homepage. Mögest du interessante Artikel und Informationen finden!

Welcome to my homepage! While some texts are written in German, the most interesting articles are available in English.

05.12.14

How to Route Selectively by Domain Name

linuxiproutevpnIts a seemingly harmless task: You have multiple internet connections (e.g., your default DSL line and a VPN connection), and you want to route some of your traffic over the VPN (e.g., to access contents blocked in your country, or to access the company LAN) but not all traffic (e.g., because the VPN is slower than the default connection). In particular, you want to redirect traffic by its target domain, i.e., you want to specify a list of domains that should be accessed over the VPN. As it turns out, this is actually non-trivial.

Here I present one solution for this problem. Probably there are others, but I have not found this particular solution documented online. Also, I write this blog post as a reminder to myself :-)

My setup is a DSL router at 192.168.2.1, a gateway for the rest of the LAN at 192.168.2.5, and some other computers using this gateway for their internet conneciton.

My solution is based on three mechanisms:
  • First, there is a cronjob that takes a list of domains as input, queries the DNS server for the IP addresses of these domains, and adds these addresses to a so-called ipset
  • Second, iptables is told to mark any traffic to any of the IP addresses in this ipset with a specific identifier.
  • Third, using rule-based routing, any traffic with that identifier is routed through the VPN.
Now for the three components:

1. Sets of IP addresses

I created two sets of IP addresses with the following commands: ipset create vpnlist_usa hash:ip hashsize 4096
ipset create vpnlist_usa_tmp hash:ip hashsize 4096
Why two sets? This way, the cronjob can work with the "_tmp" list and only when it was successful, the two lists are swapped.

2. Cronjob

The cron job is a simple bash file with the following content:

#!/bin/bash
 
if [ "$1" == "" ]
then
    echo "Usage: $0 configfile"
    exit -1
fi
 
set -e
 
source "$1" 
 
if [ "$HOSTS" == "" ]
then
    echo "No HOSTS given!"
    exit -1
fi
 
if [ "$LIST" == "" ]
then
    echo "No LIST given!"
    exit -1
fi
 
TMPLIST="$LIST"_tmp
 
/sbin/ipset flush $TMPLIST
 
for host in ${HOSTS[@]}
do
    echo "Host: $host"
    IPS=`dig -t A $host +noall +answer +short 
      | grep "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"`
    echo "IPs: $IPS"
    for addr in $IPS
    do 
    /sbin/ipset add $TMPLIST "$addr" || echo "Already in the list: $addr"
    done
done
 
/sbin/ipset swap $TMPLIST $LIST
It takes the names of config files as input, which have to be in the following format:
HOSTS=( "netflix.com" "www.netflix.com" )
LIST=vpnlist_usa
This cron job is called every five minutes.

3. Rule-based Routing

First, a new routing table is created by adding the following entry to /etc/iproute2/rt_tables: 400   vpn_usa_redir This creates a new routing table with the name vpn_usa_redir. Now we have to tell the system when to use it: ip rule add from all fwmark 120 lookup vpn_usa_redir And finally, we have to give it some contents: ip r add default dev tun0 src 192.168.20.2 table vpn_usa_redir Where tun0 is the VPN device and 192.168.20.2 is the VPN local IP address.

Now we can instruct iptables to add the matching firmware mark for us: iptables -A PREROUTING -t mangle -m set --match-set vpnlist_usa dst -i br0 -p TCP -j MARK --set-mark 120

Downsides of this solution

First, if multiple domains are hosted on one IP address, all these domains will be redirected over the VPN. In my case, I'm fine with that. Second, if the cronjob gets a different DNS response than the computer that actually accesses the domain, this solution doesn't work. To keep the probability of that happening low, I set up the same DNS server for both machines.

Alle Blogbeiträge ansehen

Neueste Artikel

Advanced Geocaching Tool for Android

02.08.12

AGTL was ported to Android.

Advanced Geocaching Tool for Android

Advanced Geocaching Tool for Meego/N9

23.01.12

AGTL, developed originally for the Openmoko Freerunner and now in active development on the Nokia N9, is the all-in-one solution for on- and offline geocaching and makes geocaching paperless!

Advanced Geocaching Tool for Meego/N9