18d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft#!/bin/bash
28d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft#
38d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft# iptables-apply -- a safer way to update iptables remotely
48d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft#
58d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft# Copyright © Martin F. Krafft <madduck@madduck.net>
68d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft# Released under the terms of the Artistic Licence 2.0
78d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft#
88d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftset -eu
98d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
108d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftPROGNAME="${0##*/}";
118d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftVERSION=1.0
128d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
138d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftTIMEOUT=10
148d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftDEFAULT_FILE=/etc/network/iptables
158d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
168d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfunction blurb()
178d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft{
188d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	cat <<-_eof
198d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	$PROGNAME $VERSION -- a safer way to update iptables remotely
208d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	_eof
218d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft}
228d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
238d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfunction copyright()
248d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft{
258d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	cat <<-_eof
268d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	$PROGNAME is C Martin F. Krafft <madduck@madduck.net>.
278d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
288d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	The program has been published under the terms of the Artistic Licence 2.0
298d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	_eof
308d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft}
318d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
328d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfunction about()
338d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft{
348d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	blurb
358d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	echo
368d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	copyright
378d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft}
388d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
398d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfunction usage()
408d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft{
418d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	cat <<-_eof
428d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	Usage: $PROGNAME [options] ruleset
438d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
448d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	The script will try to apply a new ruleset (as output by iptables-save/read
458d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	by iptables-restore) to iptables, then prompt the user whether the changes
468d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	are okay. If the new ruleset cut the existing connection, the user will not
478d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	be able to answer affirmatively. In this case, the script rolls back to the
488d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	previous ruleset.
498d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
508d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	The following options may be specified, using standard conventions:
518d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
528d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	-t | --timeout	Specify the timeout in seconds (default: $TIMEOUT)
538d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	-V | --version	Display version information
548d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	-h | --help	Display this help text
558d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	_eof
568d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft}
578d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
588d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftSHORTOPTS="t:Vh";
598d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftLONGOPTS="timeout:,version,help";
608d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
618d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftOPTS=$(getopt -s bash -o "$SHORTOPTS" -l "$LONGOPTS" -n "$PROGNAME" -- "$@") || exit $?
628d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfor opt in $OPTS; do
638d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	case "$opt" in
648d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		(-*) unset OPT_STATE;;
658d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		(*)
668d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft			case "${OPT_STATE:-}" in
678d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft				(SET_TIMEOUT)
688d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft					eval TIMEOUT=$opt
698d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft					case "$TIMEOUT" in
708d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft						([0-9]*) :;;
718d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft						(*)
728d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft							echo "E: non-numeric timeout value." >&2
738d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft							exit 1
748d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft							;;
758d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft					esac
768d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft					;;
778d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft			esac
788d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft			;;
798d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	esac
808d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
818d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	case "$opt" in
828d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		(-h|--help) usage >&2; exit 0;;
838d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		(-V|--version) about >&2; exit 0;;
848d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		(-t|--timeout) OPT_STATE=SET_TIMEOUT;;
858d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		(--) break;;
868d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	esac
878d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	shift
888d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftdone
898d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
908d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftFILE="${1:-$DEFAULT_FILE}";
918d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
928d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftif [[ -z "$FILE" ]]; then
938d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	echo "E: missing file argument." >&2
948d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	exit 1
958d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfi
968d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
978d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftif [[ ! -r "$FILE" ]]; then
988d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	echo "E: cannot read $FILE" >&2
998d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	exit 2
1008d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfi
1018d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1028d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftcase "${0##*/}" in
1038d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	(*6*)
1048d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		SAVE=ip6tables-save
1058d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		RESTORE=ip6tables-restore
1068d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		;;
1078d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	(*)
1088d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		SAVE=iptables-save
1098d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		RESTORE=iptables-restore
1108d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		;;
1118d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftesac
1128d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1138d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftCOMMANDS=(tempfile "$SAVE" "$RESTORE")
1148d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1158d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfor cmd in "${COMMANDS[@]}"; do
1168d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	if ! command -v $cmd >/dev/null; then
1178d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo "E: command not found: $cmd" >&2
1188d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		exit 127
1198d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	fi
1208d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftdone
1218d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1228d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftumask 0700
1238d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1248d458beec463e0b16467ee4649d4575377854fd7Martin F. KrafftTMPFILE=$(tempfile -p iptap)
1258d458beec463e0b16467ee4649d4575377854fd7Martin F. Kraffttrap "rm -f $TMPFILE" EXIT 1 2 3 4 5 6 7 8 10 11 12 13 14 15
1268d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1278d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftif ! "$SAVE" >"$TMPFILE"; then
1288d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	if ! grep -q ipt /proc/modules 2>/dev/null; then
1298d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo "E: iptables support lacking from the kernel." >&2
1308d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		exit 3
1318d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	else
1328d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo "E: unknown error saving current iptables ruleset." >&2
1338d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		exit 4
1348d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	fi
1358d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfi
1368d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1378d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban stop
1388d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1398d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftecho -n "Applying new ruleset... "
1408d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftif ! "$RESTORE" <"$FILE"; then
1418d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	echo "failed."
1428d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	echo "E: unknown error applying new iptables ruleset." >&2
1438d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	exit 5
1448d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftelse
1458d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	echo done.
1468d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftfi
1478d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1488d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftecho -n "Can you establish NEW connections to the machine? (y/N) "
1498d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1508d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftread -n1 -t "${TIMEOUT:-15}" ret 2>&1 || :
1518d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftcase "${ret:-}" in
1528d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	(y*|Y*)
1538d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo
1548d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo ... then my job is done. See you next time.
1558d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		;;
1568d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft	(*)
1578d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		if [[ -z "${ret:-}" ]]; then
1588d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft			echo "apparently not..."
1598d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		else
1608d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft			echo
1618d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		fi
1628d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo "Timeout. Something happened (or did not). Better play it safe..."
1638d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo -n "Reverting to old ruleset... "
1648d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		"$RESTORE" <"$TMPFILE";
1658d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		echo done.
1668d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		exit 255
1678d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft		;;
1688d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftesac
1698d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1708d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban start
1718d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1728d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafftexit 0
1738d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft
1748d458beec463e0b16467ee4649d4575377854fd7Martin F. Krafft# vim:noet:sw=8
175