xref: /freebsd/share/examples/ipfw/change_rules.sh (revision 405c3050f102b8c74782f0366c8ead927bd07b68)
1#!/bin/sh
2#
3# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4#
5# Copyright (c) 2000 Alexandre Peixoto
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29# $FreeBSD$
30
31# Change ipfw(8) rules with safety guarantees for remote operation
32#
33# Invoke this script to edit ${firewall_script}. It will call ${EDITOR},
34# or vi(1) if the environment variable is not set, for you to edit
35# ${firewall_script}, ask for confirmation, and then run
36# ${firewall_script}. You can then examine the output of ipfw list and
37# confirm whether you want the new version or not.
38#
39# If no answer is received in 30 seconds, the previous
40# ${firewall_script} is run, restoring the old rules (this assumes ipfw
41# flush is present in it).
42#
43# If the new rules are confirmed, they'll replace ${firewall_script} and
44# the previous ones will be copied to ${firewall_script}.{date}. Mail
45# will also be sent to root with a unified diff of the rule change.
46#
47# Unapproved rules are kept in ${firewall_script}.new, and you are
48# offered the option of changing them instead of the present rules when
49# you call this script.
50#
51# This script could be improved by using version control
52# software.
53
54if [ -r /etc/defaults/rc.conf ]; then
55	. /etc/defaults/rc.conf
56	source_rc_confs
57elif [ -r /etc/rc.conf ]; then
58	. /etc/rc.conf
59fi
60
61EDITOR=${EDITOR:-/usr/bin/vi}
62PAGER=${PAGER:-/usr/bin/more}
63
64tempfoo=`basename $0`
65TMPFILE=`mktemp -t ${tempfoo}` || exit 1
66
67get_yes_no() {
68	while true
69	do
70		echo -n "$1 (Y/N) ? "
71		read -t 30 a
72		if [ $? != 0 ]; then
73			a="No";
74		        return;
75		fi
76		case $a in
77			[Yy]) a="Yes";
78			      return;;
79			[Nn]) a="No";
80			      return;;
81			*);;
82		esac
83	done
84}
85
86restore_rules() {
87	nohup sh ${firewall_script} </dev/null >/dev/null 2>&1
88	rm ${TMPFILE}
89	exit 1
90}
91
92case "${firewall_type}" in
93[Cc][Ll][Ii][Ee][Nn][Tt]|\
94[Cc][Ll][Oo][Ss][Ee][Dd]|\
95[Oo][Pp][Ee][Nn]|\
96[Ss][Ii][Mm][Pp][Ll][Ee]|\
97[Uu][Nn][Kk][Nn][Oo][Ww][Nn])
98	edit_file="${firewall_script}"
99	rules_edit=no
100	;;
101*)
102	if [ -r "${firewall_type}" ]; then
103		edit_file="${firewall_type}"
104		rules_edit=yes
105	fi
106	;;
107esac
108
109if [ -f ${edit_file}.new ]; then
110	get_yes_no "A new rules file already exists, do you want to use it"
111	[ $a = 'No' ] && cp ${edit_file} ${edit_file}.new
112else
113	cp ${edit_file} ${edit_file}.new
114fi
115
116trap restore_rules SIGHUP
117
118${EDITOR} ${edit_file}.new
119
120get_yes_no "Do you want to install the new rules"
121
122[ $a = 'No' ] && exit 1
123
124cat <<!
125The rules will be changed now. If the message 'Type y to keep the new
126rules' does not appear on the screen or the y key is not pressed in 30
127seconds, the original rules will be restored.
128The TCP/IP connections might be broken during the change. If so, restore
129the ssh/telnet connection being used.
130!
131
132if [ ${rules_edit} = yes ]; then
133	nohup sh ${firewall_script} ${firewall_type}.new \
134	    < /dev/null > ${TMPFILE} 2>&1
135else
136	nohup sh ${firewall_script}.new \
137	    < /dev/null > ${TMPFILE} 2>&1
138fi
139sleep 2;
140get_yes_no "Would you like to see the resulting new rules"
141[ $a = 'Yes' ] && ${PAGER} ${TMPFILE}
142get_yes_no "Type y to keep the new rules"
143[ $a != 'Yes' ] && restore_rules
144
145DATE=`date "+%Y%m%d%H%M"`
146cp ${edit_file} ${edit_file}.$DATE
147mv ${edit_file}.new ${edit_file}
148cat <<!
149The new rules are now installed. The previous rules have been preserved in
150the file ${edit_file}.$DATE
151!
152diff -F "^# .*[A-Za-z]" -u ${edit_file}.$DATE ${edit_file} \
153    | mail -s "`hostname` Firewall rule change" root
154rm ${TMPFILE}
155exit 0
156