diff options
Diffstat (limited to 'iptables-apply')
-rwxr-xr-x | iptables-apply | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/iptables-apply b/iptables-apply new file mode 100755 index 0000000..5fec76b --- /dev/null +++ b/iptables-apply @@ -0,0 +1,174 @@ +#!/bin/bash +# +# iptables-apply -- a safer way to update iptables remotely +# +# Copyright © Martin F. Krafft <madduck@madduck.net> +# Released under the terms of the Artistic Licence 2.0 +# +set -eu + +PROGNAME="${0##*/}"; +VERSION=1.0 + +TIMEOUT=10 +DEFAULT_FILE=/etc/network/iptables + +function blurb() +{ + cat <<-_eof + $PROGNAME $VERSION -- a safer way to update iptables remotely + _eof +} + +function copyright() +{ + cat <<-_eof + $PROGNAME is C Martin F. Krafft <madduck@madduck.net>. + + The program has been published under the terms of the Artistic Licence 2.0 + _eof +} + +function about() +{ + blurb + echo + copyright +} + +function usage() +{ + cat <<-_eof + Usage: $PROGNAME [options] ruleset + + The script will try to apply a new ruleset (as output by iptables-save/read + by iptables-restore) to iptables, then prompt the user whether the changes + are okay. If the new ruleset cut the existing connection, the user will not + be able to answer affirmatively. In this case, the script rolls back to the + previous ruleset. + + The following options may be specified, using standard conventions: + + -t | --timeout Specify the timeout in seconds (default: $TIMEOUT) + -V | --version Display version information + -h | --help Display this help text + _eof +} + +SHORTOPTS="t:Vh"; +LONGOPTS="timeout:,version,help"; + +OPTS=$(getopt -s bash -o "$SHORTOPTS" -l "$LONGOPTS" -n "$PROGNAME" -- "$@") || exit $? +for opt in $OPTS; do + case "$opt" in + (-*) unset OPT_STATE;; + (*) + case "${OPT_STATE:-}" in + (SET_TIMEOUT) + eval TIMEOUT=$opt + case "$TIMEOUT" in + ([0-9]*) :;; + (*) + echo "E: non-numeric timeout value." >&2 + exit 1 + ;; + esac + ;; + esac + ;; + esac + + case "$opt" in + (-h|--help) usage >&2; exit 0;; + (-V|--version) about >&2; exit 0;; + (-t|--timeout) OPT_STATE=SET_TIMEOUT;; + (--) break;; + esac + shift +done + +FILE="${1:-$DEFAULT_FILE}"; + +if [[ -z "$FILE" ]]; then + echo "E: missing file argument." >&2 + exit 1 +fi + +if [[ ! -r "$FILE" ]]; then + echo "E: cannot read $FILE" >&2 + exit 2 +fi + +case "${0##*/}" in + (*6*) + SAVE=ip6tables-save + RESTORE=ip6tables-restore + ;; + (*) + SAVE=iptables-save + RESTORE=iptables-restore + ;; +esac + +COMMANDS=(tempfile "$SAVE" "$RESTORE") + +for cmd in "${COMMANDS[@]}"; do + if ! command -v $cmd >/dev/null; then + echo "E: command not found: $cmd" >&2 + exit 127 + fi +done + +umask 0700 + +TMPFILE=$(tempfile -p iptap) +trap "rm -f $TMPFILE" EXIT 1 2 3 4 5 6 7 8 10 11 12 13 14 15 + +if ! "$SAVE" >"$TMPFILE"; then + if ! grep -q ipt /proc/modules 2>/dev/null; then + echo "E: iptables support lacking from the kernel." >&2 + exit 3 + else + echo "E: unknown error saving current iptables ruleset." >&2 + exit 4 + fi +fi + +[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban stop + +echo -n "Applying new ruleset... " +if ! "$RESTORE" <"$FILE"; then + echo "failed." + echo "E: unknown error applying new iptables ruleset." >&2 + exit 5 +else + echo done. +fi + +echo -n "Can you establish NEW connections to the machine? (y/N) " + +read -n1 -t "${TIMEOUT:-15}" ret 2>&1 || : +case "${ret:-}" in + (y*|Y*) + echo + echo ... then my job is done. See you next time. + ;; + (*) + if [[ -z "${ret:-}" ]]; then + echo "apparently not..." + else + echo + fi + echo "Timeout. Something happened (or did not). Better play it safe..." + echo -n "Reverting to old ruleset... " + "$RESTORE" <"$TMPFILE"; + echo done. + exit 255 + ;; +esac + +[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban start + +exit 0 + +# vim:noet:sw=8 |