No Default Route

These scripts exist so that I can connect and disconnect from third party networks such as 3's UTMS network without worrying that data intended for their network will disappear up the internet pipe instead when disconnecting the mobile phone. We also avoid the idiosyncrasy of having overlapping routes in the routing tables.. I.e. a default route would overlap with everything, incuding localhost and routes back to the LAN.

Creating an Internet routes list

The routes are made by inverting an Internet drop list.

Drop lists can be obtained from the bogons reference page or the more thorough but more frequently changing DROP list. Go for the aggregated CIDR/bit notation format. Beware that sometimes a broken list is published, such as including overlapping prefixes. Inverse detects this and aborts. Then the old route table would be left in place.

Also by not having a default route, we can remove the multicast destinations except for those we generate locally. The system currently requires they are maintained by a system service process, and can have multiple output interfaces for a single input interface.

getroutes

This script combines drop entries from the Internet URL with your own routes to exclude to produce a list of desired external routes. Usage: getroutes <URL> <own excludes file> <file to write routes to>

It requires a program inverse that can be compiled as gcc -o inverse inverse.c

The file <own excludes file> is like this: (Only include entries that are not in the URL file)

010.000.000.000/08
127.000.000.000/08
172.016.000.000/12
192.168.000.000/16
224.000.000.000/04

It is padded as shown so the sort / comm utilities sort the entries correctly. Others can be added to block off certain IP's /32 or networks.

This example shows how to use inverse to obtain and format a route list

first parameter is URL of excludes

second is padded private excludes to drop in textfile, that arent in the excludes file i.e. 192.000.002.000/24

third is where to save the result, pad out addresses for correct sortability

#!/bin/sh
function presort () {
IFS=" "
tr -s "./" "  " | while read
do case "$REPLY" in
        \#*) ;;
        *) printf %03u.%03u.%03u.%03u/%03u\\n $REPLY ;;
        esac
done
}

# make list of current routes
wget -O - $1 | presort | sort -g - $2 | /usr/local/sbin/inverse | presort > $3
exit $?

routes

This program applies the difference between two files full of routes to the system routing table. Usage: routes <old routes file> <new routes file> [echo]

#!/bin/sh
# this example shows how to use inverse to apply routes

# compress addresses for route
function pack () {
sed -s 's/^0*\(.*[0-9]\)\.0*\(.*[0-9]\)\.0*\(.*[0-9]\)\.0*\(.*[0-9]\)\/0*\(.*[0-9]\)$/\1.\2.\3.\4\/\5/'
}

# generate commands to add or remove routes to match current
IFS="/"
comm -3 "$2" "$3" | cut -s -f2 | pack | while read IP BITS
do
        [ -n "$4" ] && echo "+"$IP/$BITS
        case $BITS in
        0)      route add default dev $1 ;;
        32)     route add -host $IP dev $1 ;;
        *)      route add -net $IP/$BITS dev $1 ;;
        esac
        if [ "$?" != "0" ]
        then
                exit -1
        fi
done

comm -3 "$2" "$3" | cut -f1 | cut -s -d"/" -f1-2 | pack | while read IP BITS
do
        [ -n "$4" ] && echo "-"$IP/$BITS
        case $BITS in
        0)      route -v del default dev $1 ;;
        32)     route -v del -host $IP dev $1 ;;
        *)      route -v del -net $IP/$BITS dev $1 ;;
        esac
        if [ "$?" != "0" ]
        then
                exit -1
        fi
done

[ -n "$4" ] && echo All done
logger "Routes All Done"

Example usage

A script can be made to get new routes and apply them to the system in one go. Just change the URL and create the mine-complete file.

#!/bin/sh

N=http://localhost/bogons.txt
M=/var/local/routes/mine-complete.txt

NE=/var/local/routes/new.txt
C=/var/local/routes/current.txt
O=/var/local/routes/old.txt

/usr/local/sbin/getroutes $N $M $NE
cp $C $O
mv $NE $C
/usr/local/sbin/routes w1ad $O $C echo

The sangoma S518 card needed to have the routes loaded after it brings up ppp. After having installed hotplug, do
echo WAN_ACTION=\"addroutes\" >> /etc/wanpipe/wanrouter.rc
ln --symbolic /etc/wanpipe/scripts/addroutes /etc/wanpipe/scripts/wanpipe1-addroutes
ln --symbolic /etc/wanpipe/scripts/addroutes /etc/wanpipe/scripts/wanpipe1-w1ad-addroutes

Now /etc/wanpipe/scripts/addroutes is invoked whenever wanpipe brings up the link. e.g. after the line has been re-connected.

#!/bin/sh

logger "ADDROUTES ON: $@"

/usr/local/sbin/routes w1ad /var/local/routes/null.txt /var/local/routes/current.txt >/dev/null 2>/dev/null &
pid=$!
disown $pid

#wondershaper w1ad 500 100

This script produces a list of domains with IP addresses from an IPv6 squid access log

if [ ! -f /dev/shm/stage1 ]
then
cat /dev/shm/access.log | cut -c23- | cut -d" " -f1,5,7 | \
sed 's/^\([^ ]*\) \([^ ]*\) \([^ ]*\)$/\1 \3 \2/g' | \
cut -d"/" -f1-4 > /dev/shm/stage1
fi

if [ ! -f /dev/shm/stage2 ]
then
uniq /dev/shm/stage1 > /dev/shm/stage2
fi

if [ ! -f /dev/shm/stage3 ]
then
cat /dev/shm/stage2 | sed '
s/^\([^ ]* DIRECT\/::ffff:\)\([0-9]\{1\}\)\(\.\)/\100\2\3/g
s/^\([^ ]* DIRECT\/::ffff:\)\([0-9]\{2\}\)\(\.\)/\10\2\3/g
s/^\([^ ]* DIRECT\/::ffff:[^.]*\.\)\([0-9]\{1\}\)\(\.\)/\100\2\3/g
s/^\([^ ]* DIRECT\/::ffff:[^.]*\.\)\([0-9]\{2\}\)\(\.\)/\10\2\3/g
s/^\([^ ]* DIRECT\/::ffff:[^.]*\.[^.]*\.\)\([0-9]\{1\}\)\(\.\)/\100\2\3/g
s/^\([^ ]* DIRECT\/::ffff:[^.]*\.[^.]*\.\)\([0-9]\{2\}\)\(\.\)/\10\2\3/g
s/^\([^ ]* DIRECT\/::ffff:[^.]*\.[^.]*\.[^.]*\.\)\([0-9]\{1\}\)\( \)/\100\2\3/g
s/^\([^ ]* DIRECT\/::ffff:[^.]*\.[^.]*\.[^.]*\.\)\([0-9]\{2\}\)\( \)/\10\2\3/g
' > /dev/shm/stage3
fi

if [ ! -f /dev/shm/stage4 ]
then
        cat /dev/shm/stage3 | sort | uniq > /dev/shm/stage4
fi

Simple IPv6 excludes filter

I have not seen a complete IPv6 routes list yet. I use the following to have a complete IPv6 routing table after having dropped the default route that sit0 likes to setup. This allows the site and rfc 4193 local ranges to be unroutable and hence safe to use for local experiments.

If you are not on 6to4 you'll substitute ommission of 2002 for your own netblock.

#!/bin/sh

# wget http://www.iana.org/assignments/ipv6-unicast-address-assignments -O /var/local/routes/ipv6.txt
cat /var/local/routes/ipv6.txt | grep -v ^2002 | grep ^....\: | cut -f1 -d" " | while read
do
        route -A inet6 $1 $REPLY gw ::192.88.99.1 dev $2
done

Default Route Free DHCP

It is possible to provide a set of routes via a DHCP option, which gives the advantage of end-stations knowing immediately that certain private addresses are unreachable, and for an experiment one can load a new route in.

If using an operating system that recognises only a single instance of the route option, you can offer only a few routes (about 40 at most), so I have paired down the null “martian” list to the bare essentials. Of course, it is possible to have a more complete table elsewhere.

0.0.0.0/8
10.0.0.0/8
127.0.0.0/8
172.16.0.0/12
192.168.0.0/16
224.0.0.0/4
240.0.0.0/4

Inverted, it gives this table for dhcpd, replace 192,0,2,1 with the IP address of your router.

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
option rfc3442-classless-static-routes-microsoft code 249 = array of unsigned integer 8;

option rfc3442-classless-static-routes
8,1,192,0,2,1,
7,2,192,0,2,1,
6,4,192,0,2,1,
7,8,192,0,2,1,
8,11,192,0,2,1,
6,12,192,0,2,1,
4,16,192,0,2,1,
3,32,192,0,2,1,
3,64,192,0,2,1,
4,96,192,0,2,1,
5,112,192,0,2,1,
6,120,192,0,2,1,
7,124,192,0,2,1,
8,126,192,0,2,1,
3,128,192,0,2,1,
5,160,192,0,2,1,
6,168,192,0,2,1,
12,172,0,192,0,2,1,
11,172,32,192,0,2,1,
10,172,64,192,0,2,1,
9,172,128,192,0,2,1,
8,173,192,0,2,1,
7,174,192,0,2,1,
4,176,192,0,2,1,
9,192,0,192,0,2,1,
11,192,128,192,0,2,1,
13,192,160,192,0,2,1,
16,192,169,192,0,2,1,
15,192,170,192,0,2,1,
14,192,172,192,0,2,1,
12,192,176,192,0,2,1,
10,192,192,192,0,2,1,
8,193,192,0,2,1,
7,194,192,0,2,1,
6,196,192,0,2,1,
5,200,192,0,2,1,
4,208,192,0,2,1;