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