On Wed, Oct 1, 2014 at 8:10 AM, Jeff <j...@usedmoviefinder.com> wrote:
> I have a very unreliable ISP (approximately 97% uptime).  Many of the times 
> that they go
> down, I'm connected and can ping within their limited network, but can't get 
> to the
> "outside world".  In these cases, I have an alternate slow speed connection 
> that I use.
> Right now, I manually change the default route and use pfctl to invoke an 
> alternate
> pf.conf file.
>
> I'm thinking that OpenOSPF, BIRD or one of the other routing oriented daemons 
> might be a
> way to automate switching back and forth.
>
> Does anyone suggestions on effective ways to automate/manage this?
>

Hi Jeff,

I have been casually working on this for some time now. I also have
two isp's. One more reliable than the other. The additional wish is to
load balance, since my backup isp is not that slow, so you can ignore
a few bits in the pf.conf files.

I almost have it working. I use ifstated, which calls a script called
manage-routes to do the heavy lifting. Multiple pf.conf files are
managed by anchors.

<Excuse>Something is wrong with what I have so far. Some quiet time is
needed to read through and trace the process, but I keep getting
interrupted by higher priorities. Plus my primary isp is very
reliable.</Excuse> Actually I am just lazy about most things until
there's an emergency.

Here are my files:

# cat ifstated.conf

shaw_linkup     = "vr1.link.up"
telus_linkup    = "vr2.link.up"

shaw_gate_test  = "( \"ping -q -c1 -w1 -I 199.71.129.170
199.71.129.169 > /dev/null \" every 15 )"
telus_gate_test = "( \"ping -q -c1 -w1 -I 200.116.7.41 200.116.7.1 >
/dev/null \" every 15 )"

init-state both

state both {
        init {
                run "/usr/local/sbin/manage-routes ALL"
        }
        if ! $telus_linkup {
                set-state shaw
        }
        if ! $shaw_linkup {
                set-state telus
        }
        if ! $telus_gate_test {
                set-state shaw
        }
        if !$shaw_gate_test {
                set-state telus
        }
}
state shaw {
        init {
                run "/usr/local/sbin/manage-routes SHAW"
        }
        if !$shaw_linkup {
                set-state telus
        }
        if !$shaw_gate_test {
                set-state telus
        }
        if $telus_gate_test {
                set-state both
        }
}

state telus {
        init {
                run "/usr/local/sbin/manage-routes TELUS"
        }
        if ! $telus_linkup {
                set-state none
        }
        if ! $telus_gate_test {
                set-state none
        }
        if $shaw_gate_test {
                set-state both
        }
}

state none {
        init {
                run "/usr/local/sbin/manage-routes NONE"
        }
        if $shaw_gate_test {
                set-state shaw
        }
        if $telus_gate_test {
                set-state telus
        }
}


I had a bit of fun with the led's on the front of the box, so you can
ignore that. Here is my route script:

# cat /usr/local/sbin/manage-routes
#!/bin/sh
#
# with help from Justin Jereza on misc@openbsd.org
#

SCRIPT="$0";

function help {
    echo "Usage: $SCRIPT ALL | SHAW | TELUS | NONE";
}

function in_table {
    GW="$1";

    route -n show | grep '^default' | awk '{ print $2 }' | grep $GW
2>&1 > /dev/null;
}

function add_route {
    GW="$1";

    route add -mpath default $GW 2>&1 > /dev/null;
}

function delete_route {
    GW="$1";

    route delete default $GW 2>&1 > /dev/null;
}

function log_msg {
  SRV="$1";
  STATUS="$2";
  MSG="Unitow Network Status: $SRV is $STATUS";
  logger -p daemon.info -t ifstated $MSG ;
#  mail -s $MSG  -croot < "This is an automated message from gateway server";
}

function set_shaw_led {
        STATE="$1";
        gpioctl -q gpio0 shaw_led $STATE;
}
function set_telus_led {
        STATE="$1";
        gpioctl -q gpio0 telus_led $STATE;
}

function pf_all {
        pfctl -a isp_lan    -F rules;
        pfctl -a isp_egress -F rules;
        pfctl -a isp_lan    -f /etc/pf.all_lan.conf;
        pfctl -a isp_egress -f /etc/pf.all_egress.conf;
}
function pf_one {
        pfctl -a isp_lan    -F rules;
        pfctl -a isp_egress -F rules;
        pfctl -a isp_lan    -f /etc/pf.one_lan.conf;
        pfctl -a isp_egress -f /etc/pf.one_egress.conf;
}
function pf_none {
        pfctl -a isp_lan    -F rules;
        pfctl -a isp_egress -F rules;
}

if [ $# -ne 1 ]; then
    help;
    exit 1;
fi

STATE="$1";
SHAW_GW="184.71.129.169";
TELUS_GW="206.116.7.1";

case "$STATE" in
    ALL)
        if ! in_table $SHAW_GW; then
            add_route $SHAW_GW;
        fi
        if ! in_table $TELUS_GW; then
            add_route $TELUS_GW;
        fi
        pf_all;
        log_msg "SHAW" "UP";
        log_msg "TELUS" "UP";
        set_shaw_led "on";
        set_telus_led "on";
        ;;
    SHAW)
        if ! in_table $SHAW_GW; then
            add_route $SHAW_GW;
        fi
        if in_table $TELUS_GW; then
            delete_route $TELUS_GW;
        fi
        pf_one;
        log_msg "TELUS" "DOWN";
        set_shaw_led "on";
        set_telus_led "off";
        ;;
    TELUS)
        if in_table $SHAW_GW; then
            delete_route $SHAW_GW;
        fi
        if ! in_table $TELUS_GW; then
            add_route $TELUS_GW;
        fi
        pf_one;
        log_msg "SHAW" "DOWN";
        set_shaw_led "off";
        set_telus_led "on";
        ;;
    NONE)
        if in_table $SHAW_GW; then
            delete_route $SHAW_GW;
        fi
        if in_table $TELUS_GW; then
            delete_route $TELUS_GW;
        fi
        log_msg "SHAW" "DOWN";
        log_msg "TELUS" "DOWN";
        set_shaw_led "off";
        set_telus_led "off";
        pf_none;
        ;;
    *)
        help;
        exit 1;
        ;;
esac

pf.conf rules are pretty simple right now. I deleted a few variable
definitions because I am paranoid, but I hope their names are
descriptive enough:

# cat pf.all_lan.conf
#
# Used by ifstated to load balance services between shaw and telus
# These are the rules if both Shaw and Telus are up
#

# load balance www, but keep https on single connection
#
logit           = "log (all)"
logit           = " "

telus_if        = "vr2"
shaw_if         = "vr1"

telus_gw        ="200.116.7.1"
shaw_gw         ="199.71.129.169"
smtpIP          ="192.168.100.4"
webproxyIP      ="192.168.100.3"

pass in $logit on lan inet proto tcp from $webproxyIP to port www \
         route-to { ($shaw_if $shaw_gw) ($telus_if $telus_gw) } round-robin
pass in $logit on lan inet proto tcp from $webproxyIP to port https \
        route-to ($shaw_if $shaw_gw)
#
#
# email coming through
pass in log on lan inet proto tcp from $smtpIP to any port smtp \
        route-to ($shaw_if $shaw_gw)



# cat pf.one_lan.conf
#
# Used by ifstated to load balance services between shaw and telus
# These are the rules if one isp is down
#
logit           = "log (all)"
logit           = " "
smtpIP          ="192.168.100.4"
webproxyIP      ="192.168.100.3"

pass in $logit on lan inet proto tcp from $webproxyIP to port www
pass in $logit on lan inet proto tcp from $webproxyIP to port https

pass in $logit on lan inet proto tcp to port www
pass in $logit on lan inet proto tcp to port https
#
#
# email coming through
pass in log on lan inet proto tcp from $smtpIP to port smtp


# cat pf.all_egress.conf
#
# Used by ifstated to manage to egress routes
# This file is for load balancing two isp's
#
# we log outgoing smtp for spamd
#
# notice match statements above for NAT processing
#
logit           = "log (all)"
logit           = " "

telus_gw        = "200.116.7.1"
shaw_gw         = "199.71.129.169"

webproxyIP      ="192.168.100.3"
smtpIP          ="192.168.100.4"

telus_if        = "vr2"
shaw_if         = "vr1"

match out on $telus_if  from lan:network nat-to ($telus_if)
match out on $shaw_if  from lan:network nat-to ($shaw_if)

pass out $logit on shaw  inet
pass out $logit on telus inet
pass out $logit on telus inet from shaw  route-to ($shaw_if $shaw_gw)
pass out $logit on shaw  inet from telus route-to ($telus_if $telus_gw)

# cat pf.one_egress.conf
#
# Used by ifstated to change pf rules for one isp
#

#
# we log outgoing smtp for spamd
#
logit           = "log (all)"
logit           = " "
smtpIP          ="192.168.100.4"
webproxyIP      ="192.168.100.3"

match out on egress from lan:network nat-to (egress)

#
# notice match statements above for NAT processing
#
#pass out $logit   on egress inet
pass out log (all) on egress inet proto   tcp       to any port smtp
pass out $logit    on egress inet proto { tcp udp } to any port {
domain ftp ntp }
pass out $logit    on egress inet proto { tcp udp } to any port { www https }
#pass out $logit    on egress inet proto { tcp udp } from $webproxyIP
to any port { www https }


I am particularly accustomed to scorn and derision, but any comments
appreciated. I would happily make this simpler if someone will point
the way.

Gerald

Reply via email to