#!/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/ { 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