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