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 -u ${edit_file}.$DATE ${edit_file} \ 153 | mail -s "`hostname` Firewall rule change" root 154rm ${TMPFILE} 155exit 0 156