1#!/bin/bash 2# 3# iptables-apply -- a safer way to update iptables remotely 4# 5# Copyright © Martin F. Krafft <madduck@madduck.net> 6# Released under the terms of the Artistic Licence 2.0 7# 8set -eu 9 10PROGNAME="${0##*/}"; 11VERSION=1.0 12 13TIMEOUT=10 14 15function blurb() 16{ 17 cat <<-_eof 18 $PROGNAME $VERSION -- a safer way to update iptables remotely 19 _eof 20} 21 22function copyright() 23{ 24 cat <<-_eof 25 $PROGNAME is C Martin F. Krafft <madduck@madduck.net>. 26 27 The program has been published under the terms of the Artistic Licence 2.0 28 _eof 29} 30 31function about() 32{ 33 blurb 34 echo 35 copyright 36} 37 38function usage() 39{ 40 cat <<-_eof 41 Usage: $PROGNAME [options] ruleset 42 43 The script will try to apply a new ruleset (as output by iptables-save/read 44 by iptables-restore) to iptables, then prompt the user whether the changes 45 are okay. If the new ruleset cut the existing connection, the user will not 46 be able to answer affirmatively. In this case, the script rolls back to the 47 previous ruleset. 48 49 The following options may be specified, using standard conventions: 50 51 -t | --timeout Specify the timeout in seconds (default: $TIMEOUT) 52 -V | --version Display version information 53 -h | --help Display this help text 54 _eof 55} 56 57SHORTOPTS="t:Vh"; 58LONGOPTS="timeout:,version,help"; 59 60OPTS=$(getopt -s bash -o "$SHORTOPTS" -l "$LONGOPTS" -n "$PROGNAME" -- "$@") || exit $? 61for opt in $OPTS; do 62 case "$opt" in 63 (-*) unset OPT_STATE;; 64 (*) 65 case "${OPT_STATE:-}" in 66 (SET_TIMEOUT) 67 eval TIMEOUT=$opt 68 case "$TIMEOUT" in 69 ([0-9]*) :;; 70 (*) 71 echo "E: non-numeric timeout value." >&2 72 exit 1 73 ;; 74 esac 75 ;; 76 esac 77 ;; 78 esac 79 80 case "$opt" in 81 (-h|--help) usage >&2; exit 0;; 82 (-V|--version) about >&2; exit 0;; 83 (-t|--timeout) OPT_STATE=SET_TIMEOUT;; 84 (--) break;; 85 esac 86 shift 87done 88 89case "$PROGNAME" in 90 (*6*) 91 SAVE=ip6tables-save 92 RESTORE=ip6tables-restore 93 DEFAULT_FILE=/etc/network/ip6tables 94 ;; 95 (*) 96 SAVE=iptables-save 97 RESTORE=iptables-restore 98 DEFAULT_FILE=/etc/network/iptables 99 ;; 100esac 101 102FILE="${1:-$DEFAULT_FILE}"; 103 104if [[ -z "$FILE" ]]; then 105 echo "E: missing file argument." >&2 106 exit 1 107fi 108 109if [[ ! -r "$FILE" ]]; then 110 echo "E: cannot read $FILE" >&2 111 exit 2 112fi 113 114COMMANDS=(tempfile "$SAVE" "$RESTORE") 115 116for cmd in "${COMMANDS[@]}"; do 117 if ! command -v $cmd >/dev/null; then 118 echo "E: command not found: $cmd" >&2 119 exit 127 120 fi 121done 122 123umask 0700 124 125TMPFILE=$(tempfile -p iptap) 126trap "rm -f $TMPFILE" EXIT 1 2 3 4 5 6 7 8 10 11 12 13 14 15 127 128if ! "$SAVE" >"$TMPFILE"; then 129 if ! grep -q ipt /proc/modules 2>/dev/null; then 130 echo "E: iptables support lacking from the kernel." >&2 131 exit 3 132 else 133 echo "E: unknown error saving current iptables ruleset." >&2 134 exit 4 135 fi 136fi 137 138[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban stop 139 140echo -n "Applying new ruleset... " 141if ! "$RESTORE" <"$FILE"; then 142 echo "failed." 143 echo "E: unknown error applying new iptables ruleset." >&2 144 exit 5 145else 146 echo done. 147fi 148 149echo -n "Can you establish NEW connections to the machine? (y/N) " 150 151read -n1 -t "${TIMEOUT:-15}" ret 2>&1 || : 152case "${ret:-}" in 153 (y*|Y*) 154 echo 155 echo ... then my job is done. See you next time. 156 ;; 157 (*) 158 if [[ -z "${ret:-}" ]]; then 159 echo "apparently not..." 160 else 161 echo 162 fi 163 echo "Timeout. Something happened (or did not). Better play it safe..." 164 echo -n "Reverting to old ruleset... " 165 "$RESTORE" <"$TMPFILE"; 166 echo done. 167 exit 255 168 ;; 169esac 170 171[ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban start 172 173exit 0 174 175# vim:noet:sw=8 176