Thursday, February 7, 2013

Backup multiple pfSense 2.x

Recently I've installed some pfSense firewalls and looked around how to backup their config.
I found this on pfsense.org, but I improved the idea because I would like to:
  • backup more than one firewall without changing the script
  • push something useful about config change to syslog
  • properly log out and do not leave the admin session alive
  • retain previous config files if something strange happens :)
I wrote pfsensecfgarch.sh:
#!/bin/bash
# Download the actual config.xml from pfSense firewall and archive it, if it has changed
# Read config file in following format
# host=host1;username;password
# host=host2;username;password
#
# ZsZs 2013

cfgfile=pfsensecfgarch.cfg
backupdirpfx=config
tmpdir=tmp

[ -d $tmpdir ] || mkdir -p $tmpdir
scr=${0##*/}
loginf() { logger -t "$scr" -p "info" "$@"; }
logerr() { logger -t "$scr" -p "error" "$@"; }
cleanup() { /bin/rm $curlerr 2>/dev/null; /bin/rm $cookiefile 2>/dev/null; }

[[ ! -f $cfgfile ]] && { logerr "Missing config file: $cfgfile"; exit 1; }
for cfgline in $(egrep "^host=" $cfgfile | cut -d= -f 2-)
do
  echo $cfgline | while IFS=';' read -r host user passwd rest
  do
    [ ! -z "$rest" ] && { echo "Invalid line in $cfgfile: $(grep "$cfgline" $cfgfile)"; exit 1; }
    # Login and store sessionid in cookie file
    cookiefile=$(mktemp)
    curlerr=$(mktemp)
    curl -s -S --data-ascii "login=Login&usernamefld=$user&passwordfld=$passwd" -k https://$host/diag_backup.php -o /dev/null -c $cookiefile 2>$curlerr \
      || { logerr "[$host]: login: $(cat $curlerr)"; cleanup; exit 1; }
    backupdir=$backupdirpfx/$host
    [ -d $backupdir ] || mkdir -p $backupdir
    # Download actual config
    curl -s -S --data-ascii 'Submit=download&donotbackuprrd=yes' -k https://$host/diag_backup.php -o $backupdir/config.xml.tmp -b $cookiefile 2>$curlerr \
      || { logerr "[$host]: download: $(cat $curlerr)"; cleanup; exit 1; }
    # Logout
    curl -s -S -k "https://$host/index.php?logout" -o /dev/null -b $cookiefile 2>$curlerr \
      || { logerr "[$host]: logout: $(cat $curlerr)"; cleanup; exit 1; }
    if [ "$?" == "0" ]; then
      # Check for change
      diff $backupdir/config.xml.tmp $backupdir/config.xml.latest 2>/dev/null >/dev/null
      # Archive previous config if the new one is different
      if [ "$?" != "0" ]; then
        if [ -f $backupdir/config.xml.latest ]; then
          mv $backupdir/config.xml.latest $backupdir/config.xml.$(date "+%Y%m%d-%H%M%S") 2>/dev/null
          mv $backupdir/config.xml.tmp $backupdir/config.xml.latest 2>/dev/null
        else
          mv $backupdir/config.xml.tmp $backupdir/config.xml.latest 2>/dev/null
        fi
        loginf "[$host]: updated"
      fi
      /bin/rm $backupdir/config.xml.tmp 2>/dev/null
    fi
    cleanup
  done
done 
This script should be run from cron approximately every hour.
Comments welcome!

No comments:

Post a Comment