#!/bin/bash


# Enables the firewall and alters its settings.
# 
# Toggles between two sets of ipfw-firewall rules (loose and tight),
# with automatic determination of the interface used (fw0, en0, etc) and
# the host IP-number.
# 
# The two firewall-rule sets are files containing a list of ipfw
# rules.  The rules may contain the following placeholders, which will
# be substituted when the script is run:
#	
#	oif	outside interface 	(ie, fw0, en0, etc)
#	ipno	DNS-assigned IP number
#	dns	IP number of DNS server
#
#     eg: 00600 add deny log ip from 34.56.78.90/12 to any in recv oif
#         00800 add allow log udp from ipno to dns

	
# Credit for the oif/dns/... detection should be made, but the source
# was never recorded.
#
#  v1	H.A.Trujillo,  Apr 06
#
#  v2.0	   Jun 08   - Sanity checks for ipfw-rule owner and permissions
#  		    - "ping" feature
#
#   2.1	   1oct11   - "echo -n" replaced w/ printf, due to changes w/ OS10.5 sh



trap abort SIGINT

function abort () {
    if [ -e ${TMPFILE:-dummyfilename} ] ; then  rm $TMPFILE ; fi
    sudo -k
    exit 1
    }


function rulechange () {

    TMPFILE=`mktemp /tmp/SetFireWall.XXXXXX`

    if [ ! -f $rulefile ] ; then
	printf "\n${rulefile} not found.   Aborting.\n\n"
	abort
	fi

    # Verify that rule-set is owned by root and has 600 permissions.
    set - `ls -l $rulefile`
    if [ $1 != -rw------- ] || [ $3 != root ] ; then
	printf "\n${rulefile} is not owned by root with 600 permission.    Aborting.\n\n"
	abort
    fi
	

    # Determine interface, IP address and DNS server
    /sbin/ifconfig fw0 | grep -w active > /dev/null && oif=fw0
    /sbin/ifconfig en1 | grep -w active > /dev/null && oif=en1
    /sbin/ifconfig en0 | grep -w active > /dev/null && oif=en0
    iipn=`/sbin/ifconfig ${oif}| grep -w inet | awk '{ print $2 }'`;
    ipno="${iipn:=123.45.68.89}"
    dns=`/usr/sbin/ipconfig getpacket $oif 2>/dev/null \
	| grep server_identifier  | cut -f2 -d:` 

    echo "oif  = ${oif:=en0}"
    echo "ipno = $ipno"
    echo "dns  = ${dns:=123.45.0.0}"
    echo ""

    # Read in firewall rules
    echo "Flushing firewall rules and reading new ones..."
    printf "      "
    sudo cat $rulefile | \
	sed "s/oif/$oif/g ; s/ipno/$ipno/g ; s/dns/$dns/g" > $TMPFILE
    sudo ipfw -q $TMPFILE  <<< "y" \
	&&  logger -s "Installing $ruletype firewall rules"  \
	||  logger -s "Firewall rule change failed" 
    rm $TMPFILE
    }



case "${1}" in
    -l)	rulefile=/Path/To/Startup/Rules
	ruletype=loose
	;;

    -t)	rulefile=/Path/To/Tighter/Rules
	ruletype=tight
	;;

    -s)		# print status  (rather flaky)
	cat /var/log/system.log | grep -i firewall | tail -1
        echo ""
	exit 0
	;;

    -p) 	# ping a stalled connection by dropping to loose then retightening
	sudo -v -p "su password: "
	echo ""

    	rulefile=/Path/To/Startup/Rules
	ruletype=loose
	rulechange
	printf "\n    Install tight rules?     Y/n  "
	read -t 15
	case $(REPLY:-y) in
	    n|N)
		printf "\n   Exiting with loose rules\n"
		sudo -k
		exit 0
		;;
	    *)
		echo ""
		rulefile=/Path/To/Tighter/Rules
		ruletype=tight
		rulechange
		sudo -k
		exit 0
		;;
	    esac
	;;

    *)	cat << END_OF_HELP_TXT

    A script to set the firewall ruleset and enable firewall logging.
    The rules can be set to "loose" (ie the default Apple ruleset, with
    the addition of logging) or to "tight".  

	    use: SetFireWall   -l | -t | -s | -h | -p

		   l)oose      t)ight      s)how status       h)elp
		   p)ing:  briefly install loose rules, then switch back to tight

    Associated files:
	    /Path/To/Tighter/Rules		the default Apple ruleset
	    /Path/To/Tighter/Rules		a user-defined tight ruleset
	These must be owned by root with 600 permissions.

END_OF_HELP_TXT
	exit 0
	;;
    esac



# Get SU password, but don't retain it anywhere.  (rely on timeout)
sudo -v -p "su password:"
echo ""



### Turn on firewall and logging ###

# Make sure logging is enabled (disabled by default)
if [ `/usr/sbin/sysctl -n net.inet.ip.fw.verbose` == 0 ] ; then
    echo "Turning on Firewall Logging"
    sudo /usr/sbin/sysctl -w net.inet.ip.fw.verbose=2
    sudo /usr/sbin/sysctl -w net.inet6.ip6.fw.verbose=2
#			0 = off;    1,2,4 = progressively more detailed logging
    echo ""
fi

rulechange

sudo -k




exit 0


#							   vim: tw=0
