0401-580941-iptables_apply_update.patch 13.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
From dafbc722de7bf7445a7650e5fe0778ac798dcd18 Mon Sep 17 00:00:00 2001
From: Laurence J. Lane <ljlane@debian.org>
Subject: [PATCH] iptables: update iptables-apply to v1.1
Bug: http://bugs.debian.org/580941

This is GW's update to iptables-apply. It does a code
cleanup and adds two options: one runs a command and
the other writes the sucessful rules file.

I modified the script to use mktemp instead of tempfile. I also
fixed a couple of hyphens in the man page addition.

Signed-off-by: Laurence J. Lane <ljlane@debian.org>
---
15
16
17
 iptables-apply      |  310 ++++++++++++++++++++++++++++++++++++----------------
 iptables-apply.8.in |   48 +++++---
 2 files changed, 247 insertions(+), 111 deletions(-)
18
19
20

--- a/iptables/iptables-apply
+++ b/iptables/iptables-apply
21
@@ -1,174 +1,294 @@
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 #!/bin/bash
-#
 # iptables-apply -- a safer way to update iptables remotely
 #
-# Copyright © Martin F. Krafft <madduck@madduck.net>
+# Usage:
+#   iptables-apply [-hV] [-t timeout] [-w savefile] {[rulesfile]|-c [runcmd]}
+#
+# Versions:
+#   * 1.0 Copyright 2006 Martin F. Krafft <madduck@madduck.net>
+#         Original version
+#   * 1.1 Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>
+#         Added parameter -c (run command)
+#         Added parameter -w (save successfully applied rules to file)
+#         Major code cleanup
+#
 # Released under the terms of the Artistic Licence 2.0
 #
 set -eu
 
-PROGNAME="${0##*/}";
-VERSION=1.0
+PROGNAME="${0##*/}"
+VERSION=1.1
+
+
+### Default settings
+
+DEF_TIMEOUT=10
+
+MODE=0  # apply rulesfile mode
+# MODE=1  # run command mode
+
+case "$PROGNAME" in
+	(*6*)
+		SAVE=ip6tables-save
+		RESTORE=ip6tables-restore
+		DEF_RULESFILE="/etc/network/ip6tables.up.rules"
+		DEF_SAVEFILE="$DEF_RULESFILE"
+		DEF_RUNCMD="/etc/network/ip6tables.up.run"
+		;;
+	(*)
+		SAVE=iptables-save
+		RESTORE=iptables-restore
+		DEF_RULESFILE="/etc/network/iptables.up.rules"
+		DEF_SAVEFILE="$DEF_RULESFILE"
+		DEF_RUNCMD="/etc/network/iptables.up.run"
+		;;
+esac
71
+
72
73
 
-TIMEOUT=10
74
+### Functions
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
 
-function blurb()
-{
-	cat <<-_eof
+function blurb() {
+	cat <<-__EOF__
 	$PROGNAME $VERSION -- a safer way to update iptables remotely
-	_eof
+	__EOF__
 }
 
-function copyright()
-{
-	cat <<-_eof
-	$PROGNAME is C Martin F. Krafft <madduck@madduck.net>.
-
-	The program has been published under the terms of the Artistic Licence 2.0
-	_eof
+function copyright() {
+	cat <<-__EOF__
+	$PROGNAME has been published under the terms of the Artistic Licence 2.0.
+
+	Original version - Copyright 2006 Martin F. Krafft <madduck@madduck.net>.
+	Version 1.1 - Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>.
+	__EOF__
 }
 
-function about()
-{
+function about() {
 	blurb
 	echo
 	copyright
 }
 
-function usage()
-{
-	cat <<-_eof
-	Usage: $PROGNAME [options] ruleset
-
-	The script will try to apply a new ruleset (as output by iptables-save/read
-	by iptables-restore) to iptables, then prompt the user whether the changes
-	are okay. If the new ruleset cut the existing connection, the user will not
-	be able to answer affirmatively. In this case, the script rolls back to the
-	previous ruleset.
-
-	The following options may be specified, using standard conventions:
-
-	-t | --timeout	Specify the timeout in seconds (default: $TIMEOUT)
-	-V | --version	Display version information
-	-h | --help	Display this help text
-	_eof
+function usage() {
+	blurb
+	echo
+	cat <<-__EOF__
+	Usage:
+	  $PROGNAME [-hV] [-t timeout] [-w savefile] {[rulesfile]|-c [runcmd]}
+
+	The script will try to apply a new rulesfile (as output by iptables-save,
+	read by iptables-restore) or run a command to configure iptables and then
+	prompt the user whether the changes are okay. If the new iptables rules cut
+	the existing connection, the user will not be able to answer affirmatively.
+	In this case, the script rolls back to the previous working iptables rules
+	after the timeout expires.
+
+	Successfully applied rules can also be written to savefile and later used
+	to roll back to this state. This can be used to implement a store last good
+	configuration mechanism when experimenting with an iptables setup script:
+	  $PROGNAME -w $DEF_SAVEFILE -c $DEF_RUNCMD
+
+	When called as ip6tables-apply, the script will use ip6tables-save/-restore
+	and IPv6 default values instead. Default value for rulesfile is
+	'$DEF_RULESFILE'.
+
+	Options:
+
+	-t seconds, --timeout seconds
+	  Specify the timeout in seconds (default: $DEF_TIMEOUT).
+	-w savefile, --write savefile
+	  Specify the savefile where successfully applied rules will be written to
+	  (default if empty string is given: $DEF_SAVEFILE).
+	-c runcmd, --command runcmd
+	  Run command runcmd to configure iptables instead of applying a rulesfile
+	  (default: $DEF_RUNCMD).
+	-h, --help
+	  Display this help text.
+	-V, --version
+	  Display version information.
+
+	__EOF__
166
167
+}
+
168
169
170
171
172
173
174
175
176
177
178
179
180
+function checkcommands() {
+	for cmd in "${COMMANDS[@]}"; do
+		if ! command -v "$cmd" >/dev/null; then
+			echo "Error: needed command not found: $cmd" >&2
+			exit 127
+		fi
+	done
+}
+
+function revertrules() {
+	echo -n "Reverting to old iptables rules... "
+	"$RESTORE" <"$TMPFILE"
+	echo "done."
181
182
183
184
 }
 
-SHORTOPTS="t:Vh";
-LONGOPTS="timeout:,version,help";
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
+
+### Parsing and checking parameters
+
+TIMEOUT="$DEF_TIMEOUT"
+SAVEFILE=""
+
+SHORTOPTS="t:w:chV";
+LONGOPTS="timeout:,write:,command,help,version";
 
 OPTS=$(getopt -s bash -o "$SHORTOPTS" -l "$LONGOPTS" -n "$PROGNAME" -- "$@") || exit $?
 for opt in $OPTS; do
 	case "$opt" in
-		(-*) unset OPT_STATE;;
+		(-*)
+			unset OPT_STATE
+			;;
 		(*)
 			case "${OPT_STATE:-}" in
-				(SET_TIMEOUT)
-					eval TIMEOUT=$opt
-					case "$TIMEOUT" in
-						([0-9]*) :;;
-						(*)
-							echo "E: non-numeric timeout value." >&2
-							exit 1
-							;;
-					esac
+				(SET_TIMEOUT) eval TIMEOUT=$opt;;
+				(SET_SAVEFILE)
+					eval SAVEFILE=$opt
+					[ -z "$SAVEFILE" ] && SAVEFILE="$DEF_SAVEFILE"
 					;;
 			esac
 			;;
 	esac
 
 	case "$opt" in
+		(-t|--timeout) OPT_STATE="SET_TIMEOUT";;
+		(-w|--write) OPT_STATE="SET_SAVEFILE";;
+		(-c|--command) MODE=1;;
 		(-h|--help) usage >&2; exit 0;;
 		(-V|--version) about >&2; exit 0;;
-		(-t|--timeout) OPT_STATE=SET_TIMEOUT;;
 		(--) break;;
 	esac
 	shift
 done
 
-case "$PROGNAME" in
-	(*6*)
-		SAVE=ip6tables-save
-		RESTORE=ip6tables-restore
-		DEFAULT_FILE=/etc/network/ip6tables
-		;;
-	(*)
-		SAVE=iptables-save
-		RESTORE=iptables-restore
-		DEFAULT_FILE=/etc/network/iptables
-		;;
-esac
-
-FILE="${1:-$DEFAULT_FILE}";
-
-if [[ -z "$FILE" ]]; then
-	echo "E: missing file argument." >&2
+# Validate parameters
+if [ "$TIMEOUT" -ge 0 ] 2>/dev/null; then
+	TIMEOUT=$(($TIMEOUT))
+else
+	echo "Error: timeout must be a positive number" >&2
 	exit 1
 fi
 
-if [[ ! -r "$FILE" ]]; then
-	echo "E: cannot read $FILE" >&2
-	exit 2
+if [ -n "$SAVEFILE" -a -e "$SAVEFILE" -a ! -w "$SAVEFILE" ]; then
+	echo "Error: savefile not writable: $SAVEFILE" >&2
+	exit 8
 fi
 
-COMMANDS=(tempfile "$SAVE" "$RESTORE")
+case "$MODE" in
+	(1)
+		# Treat parameter as runcmd (run command mode)
+		RUNCMD="${1:-$DEF_RUNCMD}"
+		if [ ! -x "$RUNCMD" ]; then
+			echo "Error: runcmd not executable: $RUNCMD" >&2
+			exit 6
+		fi
275
276
277
278
279
280
281
 
-for cmd in "${COMMANDS[@]}"; do
-	if ! command -v $cmd >/dev/null; then
-		echo "E: command not found: $cmd" >&2
-		exit 127
-	fi
-done
282
283
284
285
286
287
288
289
290
291
292
+		# Needed commands
+		COMMANDS=(mktemp "$SAVE" "$RESTORE" "$RUNCMD")
+		checkcommands
+		;;
+	(*)
+		# Treat parameter as rulesfile (apply rulesfile mode)
+		RULESFILE="${1:-$DEF_RULESFILE}";
+		if [ ! -r "$RULESFILE" ]; then
+			echo "Error: rulesfile not readable: $RULESFILE" >&2
+			exit 2
+		fi
293
294
 
-umask 0700
295
296
297
298
299
300
301
+		# Needed commands
+		COMMANDS=(mktemp "$SAVE" "$RESTORE")
+		checkcommands
+		;;
+esac
 
-TMPFILE=$(tempfile -p iptap)
302
303
304
+
+### Begin work
+
305
306
+# Store old iptables rules to temporary file
+TMPFILE=`mktemp /tmp/$PROGNAME-XXXXXXXX`
307
308
 trap "rm -f $TMPFILE" EXIT HUP INT QUIT ILL TRAP ABRT BUS \
 		      FPE USR1 SEGV USR2 PIPE ALRM TERM
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
 
 if ! "$SAVE" >"$TMPFILE"; then
+	# An error occured
 	if ! grep -q ipt /proc/modules 2>/dev/null; then
-		echo "E: iptables support lacking from the kernel." >&2
+		echo "Error: iptables support lacking from the kernel" >&2
 		exit 3
 	else
-		echo "E: unknown error saving current iptables ruleset." >&2
+		echo "Error: unknown error saving old iptables rules: $TMPFILE" >&2
 		exit 4
 	fi
 fi
 
+# Legacy to stop the fail2ban daemon if present
 [ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban stop
 
-echo -n "Applying new ruleset... "
-if ! "$RESTORE" <"$FILE"; then
-	echo "failed."
-	echo "E: unknown error applying new iptables ruleset." >&2
-	exit 5
-else
332
-	echo "done."
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
-fi
+# Configure iptables
+case "$MODE" in
+	(1)
+		# Run command in background and kill it if it times out
+		echo -n "Running command '$RUNCMD'... "
+		"$RUNCMD" &
+		CMD_PID=$!
+		( sleep "$TIMEOUT"; kill "$CMD_PID" 2>/dev/null; exit 0 ) &
+		CMDTIMEOUT_PID=$!
+		if ! wait "$CMD_PID"; then
+			echo "failed."
+			echo "Error: unknown error running command: $RUNCMD" >&2
+			revertrules
+			exit 7
+		else
+			echo "done."
+		fi
+		;;
+	(*)
+		# Apply iptables rulesfile
+		echo -n "Applying new iptables rules from '$RULESFILE'... "
+		if ! "$RESTORE" <"$RULESFILE"; then
+			echo "failed."
+			echo "Error: unknown error applying new iptables rules: $RULESFILE" >&2
+			revertrules
+			exit 5
+		else
+			echo "done."
+		fi
+		;;
+esac
 
+# Prompt user for confirmation
 echo -n "Can you establish NEW connections to the machine? (y/N) "
 
-read -n1 -t "${TIMEOUT:-15}" ret 2>&1 || :
+read -n1 -t "$TIMEOUT" ret 2>&1 || :
 case "${ret:-}" in
 	(y*|Y*)
+		# Success
 		echo
+
+		if [ ! -z "$SAVEFILE" ]; then
+			# Write successfully applied rules to the savefile
+			echo "Writing successfully applied rules to '$SAVEFILE'..."
+			if ! "$SAVE" >"$SAVEFILE"; then
+				echo "Error: unknown error writing successfully applied rules: $SAVEFILE" >&2
+				exit 9
+			fi
+		fi
+
385
 		echo "... then my job is done. See you next time."
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
 		;;
 	(*)
-		if [[ -z "${ret:-}" ]]; then
-			echo "apparently not..."
+		# Failed
+		echo
+		if [ -z "${ret:-}" ]; then
+			echo "Timeout! Something happened (or did not). Better play it safe..."
 		else
-			echo
+			echo "No affirmative response! Better play it safe..."
 		fi
-		echo "Timeout. Something happened (or did not). Better play it safe..."
-		echo -n "Reverting to old ruleset... "
-		"$RESTORE" <"$TMPFILE";
401
-		echo "done."
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
+		revertrules
 		exit 255
 		;;
 esac
 
+# Legacy to start the fail2ban daemon again
 [ -x /etc/init.d/fail2ban ] && /etc/init.d/fail2ban start
 
 exit 0
--- a/iptables/iptables-apply.8.in
+++ b/iptables/iptables-apply.8.in
@@ -1,6 +1,6 @@
 .\"     Title: iptables-apply
-.\"    Author: Martin F. Krafft
-.\"      Date: Jun 04, 2006
+.\"    Author: Martin F. Krafft, GW
+.\"      Date: May 10, 2010
 .\"
 .TH IPTABLES\-APPLY 8 "" "@PACKAGE_STRING@" "@PACKAGE_STRING@"
 .\" disable hyphenation
@@ -8,23 +8,37 @@
 .SH NAME
 iptables-apply \- a safer way to update iptables remotely
 .SH SYNOPSIS
-\fBiptables\-apply\fP [\-\fBhV\fP] [\fB-t\fP \fItimeout\fP] \fIruleset\-file\fP
+\fBiptables\-apply\fP [\-\fBhV\fP] [\fB-t\fP \fItimeout\fP] [\fB-w\fP \fIsavefile\fP] {[\fIrulesfile]|-c [runcmd]}\fP
 .SH "DESCRIPTION"
 .PP
-iptables\-apply will try to apply a new ruleset (as output by
-iptables\-save/read by iptables\-restore) to iptables, then prompt the
-user whether the changes are okay. If the new ruleset cut the existing
-connection, the user will not be able to answer affirmatively. In this
-case, the script rolls back to the previous ruleset after the timeout
-expired. The timeout can be set with \fB\-t\fP.
-.PP
-When called as \fBip6tables\-apply\fP, the script will use
-ip6tables\-save/\-restore instead.
+iptables\-apply will try to apply a new rulesfile (as output by
+iptables-save, read by iptables-restore) or run a command to configure
+iptables and then prompt the user whether the changes are okay. If the
+new iptables rules cut the existing connection, the user will not be
+able to answer affirmatively. In this case, the script rolls back to
+the previous working iptables rules after the timeout expires.
+.PP
+Successfully applied rules can also be written to savefile and later used
+to roll back to this state. This can be used to implement a store last good
+configuration mechanism when experimenting with an iptables setup script:
+iptables-apply \-w /etc/network/iptables.up.rules \-c /etc/network/iptables.up.run
+.PP
+When called as ip6tables\-apply, the script will use
+ip6tables\-save/\-restore and IPv6 default values instead. Default
+value for rulesfile is '/etc/network/iptables.up.rules'.
 .SH OPTIONS
 .TP
 \fB\-t\fP \fIseconds\fR, \fB\-\-timeout\fP \fIseconds\fR
-Sets the timeout after which the script will roll back to the previous
-ruleset.
+Sets the timeout in seconds after which the script will roll back
+to the previous ruleset (default: 10).
+.TP
+\fB\-w\fP \fIsavefile\fR, \fB\-\-write\fP \fIsavefile\fR
+Specify the savefile where successfully applied rules will be written to
+(default if empty string is given: /etc/network/iptables.up.rules).
+.TP
+\fB\-c\fP \fIruncmd\fR, \fB\-\-command\fP \fIruncmd\fR
+Run command runcmd to configure iptables instead of applying a rulesfile
+(default: /etc/network/iptables.up.run).
 .TP
 \fB\-h\fP, \fB\-\-help\fP
 Display usage information.
@@ -36,9 +50,11 @@
 \fBiptables-restore\fP(8), \fBiptables-save\fP(8), \fBiptables\fR(8).
 .SH LEGALESE
 .PP
-iptables\-apply is copyright by Martin F. Krafft.
+Original iptables-apply - Copyright 2006 Martin F. Krafft <madduck@madduck.net>.
+Version 1.1 - Copyright 2010 GW <gw.2010@tnode.com or http://gw.tnode.com/>.
 .PP
-This manual page was written by Martin F. Krafft <madduck@madduck.net>
+This manual page was written by Martin F. Krafft <madduck@madduck.net> and
+extended by GW <gw.2010@tnode.com or http://gw.tnode.com/>.
 .PP
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the Artistic License 2.0.