#!/bin/bash
# Restore firewall state at boot, and store it at shutdown.
### BEGIN INIT INFO
# Provides:          firewall
# Required-Start:    $network
# Required-Stop:     $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Firewalls' state save/restore/flush
# Description:       Store the firewalls' state at shutdown, and restores it at boot.
#                    Aalso set the firewalls to a default state, and flush all rules.
### END INIT INFO

DEFAULT_V4="/etc/firewall/default_v4.rules"
DEFAULT_V6="/etc/firewall/default_v6.rules"
STATE_V4="/etc/firewall/state_v4.rules"
STATE_V6="/etc/firewall/state_v6.rules"

# Confirm the iptables utilities are available.
[[ ! -x "/usr/sbin/iptables" ]] || [[ ! -x "/usr/sbin/ip6tables" ]] || [[ ! -x "/usr/sbin/iptables-save" ]] || [[ ! -x "/usr/sbin/iptables-restore" ]] || [[ ! -x "/usr/sbin/ip6tables-save" ]] || [[ ! -x "/usr/sbin/ip6tables-restore" ]] && {
  printf "%s: %s\\n" "${0##*/}" "iptables package not installed!" >&2
  exit 1
}

firewall_states_restore() {
  local ERR=0

  # Restore the saved (or default) v4 firewall state.
  iptables-restore "$STATE_V4" 2>/dev/null || {
    printf "%s: %s" "${0##*/}" "failed to restore saved" >&2
    if iptables-restore "$DEFAULT_V4" 2>/dev/null; then
      printf "%s" ", only default" >&2
    else
      printf " %s" "and default" >&2
      ERR=1
    fi
    printf " %s\\n" "v4 firewall state" >&2
  }

  # Restore the saved (or default) v6 firewall state.
  ip6tables-restore "$STATE_V6" 2>/dev/null || {
    printf "%s: %s" "${0##*/}" "failed to restore saved" >&2
    if ip6tables-restore "$DEFAULT_V6" 2>/dev/null; then
      printf "%s" ", only default" >&2
    else
      printf " %s" "and default" >&2
      ERR=1
    fi
    printf " %s\\n" "v6 firewall state" >&2
  }

  return "$ERR"
}

firewall_states_save() {
  local ERR=0

  # Store the state of the v4 firewall.
  iptables-save >"$STATE_V4" 2>/dev/null || {
    printf "%s: %s\\n" "${0##*/}" "failed to save v4 firewall state" >&2
    ERR=1
  }

  # Store the state of the v6 firewall.
  ip6tables-save >"$STATE_V6" 2>/dev/null || {
    printf "%s: %s\\n" "${0##*/}" "failed to save v6 firewall state" >&2
    ERR=1
  }

  return "$ERR"
}

firewall_defaults_restore() {
  local ERR=0

  # Restore the default v4 firewall state.
  iptables-restore "$DEFAULT_V4" 2>/dev/null || {
    printf "%s: %s\\n" "${0##*/}" "failed to restore default v4 firewall state" >&2
    ERR=1
  }

  # Restore the default v6 firewall state.
  ip6tables-restore "$DEFAULT_V6" 2>/dev/null || {
    printf "%s: %s\\n" "${0##*/}" "failed to restore default v6 firewall state" >&2
    ERR=1
  }

  return "$ERR"
}

firewall_flush() {
  # Set the default policies to ACCEPT.
  iptables -P INPUT ACCEPT
  ip6tables -P INPUT ACCEPT
  iptables -P OUTPUT ACCEPT
  ip6tables -P OUTPUT ACCEPT
  iptables -P FORWARD ACCEPT
  ip6tables -P FORWARD ACCEPT

  # Flush all the rules in the tables.
  iptables -F INPUT
  ip6tables -F INPUT
  iptables -F OUTPUT
  ip6tables -F OUTPUT
  iptables -F FORWARD
  ip6tables -F FORWARD

  # Delete all user defined tables.
  iptables -X
  ip6tables -X

  # Reset packet counters to zero.
  iptables -Z
  ip6tables -Z

  return 0	# All the above commands should never fail.
}

case "$1" in
  start|restart|reload|force-reload)
    firewall_states_restore
    exit "$?"
    ;;
  stop)
    firewall_states_save
    exit "$?"
    ;;
  defaults)
    firewall_defaults_restore || {
      printf "%s: %s\\n" "${0##*/}" "failed to restore default firewall state" >&2
      exit 1
    }
    echo "$?"
    ;;
  flush)
    firewall_flush	# Should never fail.
    ;;
  *)
    printf "%s %s\\n" "${0##*/}" "<start|stop|restart|reload|force-reload|defaults|flush>"
    exit 2
    ;;
esac

exit 0
