On Wed, Oct 1, 2014 at 8:10 AM, Jeff <[email protected]> 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 [email protected]
#
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