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