#!/bin/sh
#
# pfsense-ifc-check
#
# This script addresses a peculiar problem of pfSense 1.0.1 - 1.2RC3 and the
# Telstraclear ISP in New Zealand when using cable modems. Intermittently,
# data transfer between pfSense and the ISP stop, although transfers between
# pfSense and the cable modem remain functional. Faulty pfSense hardware or
# cable modems, or network cards, have been ruled out. The only possible fix is
# to reboot pfSense, or take the WAN interface down and bring it up again.
# See the pfsense-support mailing list May to Oct 2007.
#
# This script pings the WAN gateway, if that fails, the ping is repeated a short
# while later. If that fails too, the WAN interface is taken down and brought up
# again. This script is designed to be called from cron.
#
# Problems:
# If the WAN gateway is legitimately unreachable (cable modem unplugged, ISP
# network problems), the WAN interface turns into a yo-yo.
#
# Installation:
# Copy this script to /usr/local/bin
# Make it executable: chmod 700 /usr/local/bin/pfsense-ifc-check
# Check the script's configuration variables, edit if desirable.
# Call it regularly from cron. For current versions of pfSense (1.2), insert
# this into /conf/config.xml before the and reboot (or back up, edit,
# and restore the config file):
# -
# */5
# *
# *
# *
# *
# root
# /usr/local/bin/pfsense-ifc-check
#
#
# Copyright (C) by Volker Kuhlmann, http://volker.top.geek.nz/contact.html
# All rights reserved.
# Released under the terms of the GNU General Public License (GPL) Version 2,
# or at your option, under the same terms as the pfSense firewall
# (http://pfsense.org/).
#
# Version 1.0 13 Oct 2007 VK
# Version 1.1 08 Nov 2007 VK
# Version 1.2 17 Nov 2007 VK
# Version 1.3 15 Nov 2018 VK
# Update for newer pfsense.
#
### Constants / Configuration
# Location of pfSense configuration file.
config=/cf/conf/config.xml
# If the fault still exists after this time, action is taken. In seconds.
# Make sure not to call this script more often than this (plus e.g. 5s margin)!
fault_delay=20
# Syslog facility to use for logging problems.
# (pfSense only seems to send local0 to remote.)
facility="local0"
# Local logfile to use for logging problems. (Nothing written if empty.)
logfile=""
logfile="/var/log/pfsense-ifc-check-`date +%Y%m`"
### Functions
# Read the WAN interface name and gateway IP address.
# The values are written to stdout as variable assignment "IF=xyz GW=1.2.3.4".
# Warning: this parser relies on a neatly formatted XML file!
read_config() {
nawk < "$config" '
// { wan=1; }
!wan { next; }
wan==1 && // {
gsub("^.*", "")
gsub(".*$", "")
ifc=$0
}
wan==1 && // {
gsub("^.*", "")
gsub(".*$", "")
gw=$0
}
/<\/wan>/ && gw!="WAN_GW" { exit; }
/<\/wan>/ { wan=2 }
wan==2 && // { wan=3; }
wan==3 && // {
gsub("^.*", "")
gsub(".*$", "")
gwitem=$0
}
wan==3 && /WAN_GW { foundwangw=1; }
wan==3 && /<\/gateway_item>/ {
if (foundwangw) {
gw=gwitem
wan=4
} else {
foundwangw=0
gwitem=""
}
}
/<\/gateways>/ { exit; }
END {
if ( gw == "WAN_GW")
gw=""
printf "IF=%s GW=%s\n", ifc, gw;
}
'
}
# Return true if the gateway is currently not reachable.
gateway_dead() {
ping -c1 -t2 "$GW" >/dev/null
test $? -eq 2
}
# Log the message given in $1, to the syslog facility.level $2.
log_msg() {
local stamp="`date +%Y%m%d_%T` `hostname -s` `id -un`"
echo 1>&2 "$stamp: $1"
logger -p "${2:-$facility.notice}" "$1"
if [ -n "$logfile" ]; then
echo >>"$logfile" "$stamp: $1"
fi
}
### Main
eval `read_config`
case "$1" in
-t|--test)
echo "Interface='$IF' Gateway='$GW'"
if gateway_dead; then
echo "Gateway $GW down."
else
echo "Gateway $GW up."
fi
exit
;;
esac
if [ -n "$IF" -a -n "$GW" ]; then
if gateway_dead; then
log_msg "Gateway $GW down." "$facility.warning"
sleep $fault_delay
if gateway_dead; then
log_msg "Gateway $GW still down. Kicking interface $IF." \
"$facility.err"
ifconfig "$IF" down
sleep 1
ifconfig "$IF" up
fi
else
true
fi
else
echo 1>&2 "Error: could not determine WAN interface or WAN gateway!"
false
fi