Blame iptables/iptables-apply

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