Vyatta 6.2 Policy Based Routing

What is Policy Based Routing?

Normal ip packet routing only looks at the destination ip (v4 or v6) address to decide which outbound interface should send that packet. Policy based routing allows that interface selection process to use information other than the destination ip address. For example, you might want all TCP packets with destination port number 80 to exit via a particular interface.

In this particular case, we have two interfaces running a full BGP (IPv4) feed from a provider, and we also have a higher-speed consumer grade DSL line configured via DHCP. As long as the DSL link is up, we can use it for web browsing. If the link is down, we want to automatically fall back to the main data links.

Vyatta 6.2

We add a second routing table, add a default route in that routing table thru our DSL link, use the firewall to add firewall marks to some packets, and add an "ip rule" to select that second routing table for those marked packets.

Since the DSL link is configured via DHCP, we can place a bash script in /etc/dhcp3/dhclient-exit-hooks.d/bgp which will be run whenever the dhcp state of that link changes. If the DSL link is up, it will cause some packets to get sent via the DSL link. If the link is down, the firewall marking will be removed, and those packets will take the normal outbound route via one of the BGP configured links.

Note that this use of the PREROUTING chain in the mangle table conflicts with Vyatta's use for the wan load balancing feature.

#!/bin/bash

if [ -z "$reason" ]; then
    reason="NONE"
fi

case $reason in
    BOUND|RENEW|REBIND|REBOOT|NONE|EXPIRE|FAIL|RELEASE|STOP)

    fn=/etc/iproute2/rt_tables
    ta=510sg
    prior=20
    mark=20     # for routing table selection
    localdev=eth0
    dev=eth1

    # create our second routing table if it does not exist
    grep $ta $fn >/dev/null || echo "$prior $ta" >>$fn

    # flush all the custom entries
    iptables -t mangle -F PREROUTING
    iptables -t mangle -F OUTPUT
    ip route flush table $ta

    # do we have a default route? It must have come from dhcp on $dev
    # if we have a default route that link is up.
    cmd="show ip route 0.0.0.0/0; exit
    "
    gwip=$( (echo "$cmd" | ssh -t -t vyatta@localhost 2>/dev/null) | grep "via $dev" | rev | awk '{print $3}' | rev | cut -d, -f1 )
    if [ "$gwip" != "" ]; then
        # find our ip address on $dev
        ip=$(ip addr list $dev | grep 'inet ' | awk '{print $2}' | cut -d/ -f1)
        # find our local network on $localdev
        localnet=$(ip addr list $localdev | grep 'inet ' | awk '{print $2}')
        # local destinations that should not be routed out $dev
        iptables -t mangle -A PREROUTING                     -d 192.168.0.0/16 -j ACCEPT
        # anything from the local network to some fixed ports gets forced out $dev
        iptables -t mangle -A PREROUTING -p tcp --dport 143  -s $localnet      -j MARK --set-mark $mark
        iptables -t mangle -A PREROUTING -p tcp --dport 80   -s $localnet      -j MARK --set-mark $mark
        iptables -t mangle -A PREROUTING -p tcp --dport 443  -s $localnet      -j MARK --set-mark $mark
        iptables -t mangle -A PREROUTING -p tcp --dport 8000 -s $localnet      -j MARK --set-mark $mark
        # vyatta source $dev natted out $dev
        iptables -t mangle -A OUTPUT                         -s $ip/32         -j MARK --set-mark $mark
        # add a default route in our second routing table
        ip route add default via $gwip dev $dev table $ta
        # setup routing based on the firewall mark
        ip rule list | grep "lookup $ta" >/dev/null || ip rule add fwmark $mark priority $prior table $ta
    fi

    ip route flush cache

    d=$(date)
    echo ""
    echo "$d $reason is reason for running this bgp script"

    echo ""
    echo "$d rule list"
    ip rule list

    echo ""
    echo "$d mangle table"
    iptables -n -t mangle -L PREROUTING
    iptables -n -t mangle -L OUTPUT
    ;;

    PREINIT)
    ;;
esac