Blame iptables/iptables-apply

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