#!/bin/bash
#WARNING - remove the above before distribution!!!!!!!!!!
#A library of functions and subroutines for Mason
#Copyright 1999, William Stearns <wstearns@pobox.com>
#See the main Mason script for license and copyright information.

#Notes to myself:
#Safe to remove curly braces if char following variable is not letter, digit, or underscore.
#${ONENET%%/*} = stuff before /
#${ONENET##*/} = stuff after /
#ipchains -L -n -v -x: bytes 1-8 are the count, 10-19 are bytes, 66-75 is the mark.
#export BBB="bbb" ; export ADDCOUNTSCRIPT="-e s/aa/bbbb/ -e s/$BBB/z/" ; echo "aa" | sed $ADDCOUNTSCRIPT
# | sed -e 's/\^ [0-9]*//'
# ?		Expands to the status of the most recently executed foreground pipeline.
# -		Expands to the current option flags as specified upon invocation, by  the  set  builtin  command,  or
# those set by the shell itself (such as the -i flag).
# $		Expands  to  the process ID of the shell.  In a () subshell, it expands to the process ID of the cur-
# rent shell, not the subshell.
# !		Expands to the process ID of the most recently executed background (asynchronous) command.
#	For a single background task, this is the PID.
#	For a backgrounded pipe, this is the PID of the last object in the pipe.
#	For a ( X | Y | Z... ) &   , this is the pid of the encapsulating shell.  Killing $! kills that shell, but not inhabitants who get orphaned but keep running.
#FIXME - figure out how to add counts to NOINCOMING and BLOCKEDHOSTS rules?


#-------------------------------------------------------------------------
# addcounts procedure, adds the packet counts to the rules in a file.
#-------------------------------------------------------------------------
addcounts () {
#Params: $1 is the filespec for the files that need counts added.
	CKPTADDCOUNTS=" addcounts: Start $1" ; #ckpt $CKPTADDCOUNTS
	HEXMARKS="" ; DECMARKS=""
	for ONEMARK in `grep ' -m ' $1 | sed -e 's/.* -m \([^ ]*\) .*/\1/'` ; do
		case $ONEMARK in
		0x*)	HEXMARKS="YES"		;;
		[0-9]*)	DECMARKS="YES"		;;
		esac
	done

	CKPTADDCOUNTS=" addcounts: hexmarks $HEXMARKS decmarks $DECMARKS" ; #ckpt $CKPTADDCOUNTS
	if [ -n "$HEXMARKS$DECMARKS" ]; then	#Only do the work if some of the rules have mark values.
		ADDCOUNTSCRIPT="-e s/[[:space:]]*#\^[[:space:]][0-9]*//"	#Erase any old counts ( #^ 12345 )
		ADDCOUNTSCRIPT="$ADDCOUNTSCRIPT -e s/[[:space:]]*$//"		#Erase any trailing spaces
		for ONECOUNT in `ipchains -L -n -x -v | cut -b 1-9,66-75 - | sed -e 's@ 0x@/0x@' | grep '/0x'` ; do		#packetcount/markvalue pairs
			if [ "$HEXMARKS" = "YES" ]; then
				#In short: Add "  #^ packetcount" at the end of a line that has " -m 0xmarkvalue " in it.
				ADDCOUNTSCRIPT="$ADDCOUNTSCRIPT -e s@^\(.*[[:space:]]-m[[:space:]]${ONECOUNT##*/}[[:space:]].*\)@\1SpAcE#^SpAcE${ONECOUNT%%/*}SpAcE@"
			fi
			if [ "$DECMARKS" = "YES" ]; then
				#As above, but match the decimal version "$[0xmarkvalue]".
				ADDCOUNTSCRIPT="$ADDCOUNTSCRIPT -e s@^\(.*[[:space:]]-m[[:space:]]$[${ONECOUNT##*/}][[:space:]].*\)@\1SpAcE#^SpAcE${ONECOUNT%%/*}SpAcE@"
			fi
		done
		CKPTADDCOUNTS=" addcounts: script created, processing files" ; #ckpt $CKPTADDCOUNTS
		for ONEFILE in $1 ; do
			sed $ADDCOUNTSCRIPT -e 's/SpAcE/ /g' $ONEFILE >$ONEFILE.temp	#I couldn't figure out the quoting to allow actual spaces in the ADDCOUNTSCRIPT variable.
			cat $ONEFILE.temp >$ONEFILE
			rm -f $ONEFILE.temp
		done
	fi
	CKPTADDCOUNTS=""
} #End of addcounts


#-------------------------------------------------------------------------
# bits2mask function, returns the netmask for the number of bits parameter.
#-------------------------------------------------------------------------
bits2mask () {
	case $1 in
	32|*/32)			echo 255.255.255.255					;;
	31|*/31)			echo 255.255.255.254					;;
	30|*/30)			echo 255.255.255.252					;;
	29|*/29)			echo 255.255.255.248					;;
	28|*/28)			echo 255.255.255.240					;;
	27|*/27)			echo 255.255.255.224					;;
	26|*/26)			echo 255.255.255.192					;;
	25|*/25)			echo 255.255.255.128					;;

	24|*/24)			echo 255.255.255.0						;;
	23|*/23)			echo 255.255.254.0						;;
	22|*/22)			echo 255.255.252.0						;;
	21|*/21)			echo 255.255.248.0						;;
	20|*/20)			echo 255.255.240.0						;;
	19|*/19)			echo 255.255.224.0						;;
	18|*/18)			echo 255.255.192.0						;;
	17|*/17)			echo 255.255.128.0						;;

	16|*/16)			echo 255.255.0.0						;;
	15|*/15)			echo 255.254.0.0						;;
	14|*/14)			echo 255.252.0.0						;;
	13|*/13)			echo 255.248.0.0						;;
	12|*/12)			echo 255.240.0.0						;;
	11|*/11)			echo 255.224.0.0						;;
	10|*/10)			echo 255.192.0.0						;;
	9|*/9)				echo 255.128.0.0						;;

	8|*/8)				echo 255.0.0.0							;;
	7|*/7)				echo 254.0.0.0							;;
	6|*/6)				echo 252.0.0.0							;;
	5|*/5)				echo 248.0.0.0							;;
	4|*/4)				echo 240.0.0.0							;;
	3|*/3)				echo 224.0.0.0							;;
	2|*/2)				echo 192.0.0.0							;;
	1|*/1)				echo 128.0.0.0							;;
	0|*/0)				echo 0.0.0.0							;;
	*)					echo 255.255.255.255					;;
	esac
} #End of bits2mask


#-------------------------------------------------------------------------
# broadcastof function, returns the broadcast of the given network and netmask.
#-------------------------------------------------------------------------
broadcastof () {
#Basically, the broadcast is (network bitwise-or (255.255.255.255-netmask))
	CKPTBROADCASTOF=" broadcastof: Start $1 mask $2" ; #ckpt $CKPTBROADCASTOF
	SPLITIP=$1
	I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O4=$SPLITIP
	case $2 in
	[0-9]|[1-2][0-9]|3[0-2])	SPLITIP=`bits2mask $2`			;;
	*)							SPLITIP=$2						;;
	esac
	I2O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O4=$SPLITIP

	echo $[ $I1O1 | (255-$I2O1) ].$[ $I1O2 | (255-$I2O2) ].$[ $I1O3 | (255-$I2O3) ].$[ $I1O4 | (255-$I2O4) ]
	CKPTBROADCASTOF=""
} #End of broadcastof


#-------------------------------------------------------------------------
#After loading /etc/masonrc, this procedure puts sane values in for everything.
#-------------------------------------------------------------------------
checkconf () {
#FIXME - double check all vars have default values.
	CKPTCHECKCONF=" checkconf: Start" ; #ckpt $CKPTCHECKCONF
	echo -n "Check vars..." >/dev/stderr

	MASONDIR=${MASONDIR:-"/var/lib/mason/"} ;						if [ ! -d $MASONDIR ]; then mkdir --parents $MASONDIR ; chown root.root $MASONDIR ; chmod 700 $MASONDIR ; fi
	MASONCONF=${MASONCONF:-"/etc/masonrc"} ;						if [ ! -f $MASONCONF ]; then touch $MASONCONF ; fi
	#NAMECACHE support has been disabled
	#NAMECACHE=${NAMECACHE:-"${MASONDIR}morehosts"} ;				if [ ! -f $NAMECACHE ]; then touch $NAMECACHE ; fi
	#The NETCACHE file is no longer used; place any customized values in the NETWORKS variable.
	#NETCACHE=${NETCACHE:-"${MASONDIR}netconvert"} ;				if [ ! -f $NETCACHE ]; then touch $NETCACHE ; fi
	BASERULEFILE=${BASERULEFILE:-"${MASONDIR}baserules"} ;			if [ ! -f $BASERULEFILE ]; then touch $BASERULEFILE ; fi
	NEWRULEFILE=${NEWRULEFILE:-"${MASONDIR}newrules"} ;				if [ ! -f $NEWRULEFILE ]; then touch $NEWRULEFILE ; fi
	#SYSTEMRULEFILE=${SYSTEMRULEFILE:-"${MASONDIR}systemrules"} ;	if [ ! -f $SYSTEMRULEFILE ]; then touch $SYSTEMRULEFILE ; fi
	PACKETLOGFILE=${PACKETLOGFILE:-"/var/log/messages"}
	MASONEXE=${MASONEXE:-"/usr/bin/mason"}
	if [ -z "$SERVICES" ]; then
		SERVICES="/etc/services"
		#I used to add in the following 2 files.  I do not now because I got too many false matches from nmap-services.
		#if [ -f ${MASONDIR}moreservices ]; then SERVICES="$SERVICES ${MASONDIR}moreservices" ; fi
		#if [ -f ${MASONDIR}nmap-services ]; then SERVICES="$SERVICES ${MASONDIR}nmap-services" ; fi
	fi

	NOLOGSUFFIX=${NOLOGSUFFIX:-"N"}	#If you change this, change it in ruleshell too.
	DEBUG=${DEBUG:-"NO"}
	DYNIF=${DYNIF:-""}

	INCOMINGINTERFACES=${INCOMINGINTERFACES:-`/sbin/route -n | grep '^0\.0\.0\.0[ \t]' | awk '{print $8}' | sort | uniq`}

	CKPTCHECKCONF=" checkconf: Check policies" ; #ckpt $CKPTCHECKCONF
	case $NEWRULEPOLICY in			#Set LCPOLICY (lower case) and UCPOLICY...
	[Aa][Cc][Cc][Ee][Pp][Tt])					LCPOLICY="accept" ;	UCPOLICY="ACCEPT"	;;
	[Rr][Ee][Jj][Ee][Cc][Tt])					LCPOLICY="reject" ;	UCPOLICY="REJECT"	;;
	[Dd][Ee][Nn][Yy])							LCPOLICY="deny" ;	UCPOLICY="DENY"		;;
	*)	echo WARNING! NEWRULEPOLICY is neither accept, reject, nor deny >/dev/stderr
		echo in $MASONCONF.  >/dev/stderr
		while [ "$LCPOLICY" != "accept" ] && [ "$LCPOLICY" != "reject" ] && [ "$LCPOLICY" != "deny" ] ; do
			echo Please choose accept, reject, or deny: >/dev/stderr
			read NEWRULEPOLICY JUNK
			case "$NEWRULEPOLICY" in
			[Aa][Cc][Cc][Ee][Pp][Tt])			LCPOLICY="accept" ;	UCPOLICY="ACCEPT"	;;
			[Rr][Ee][Jj][Ee][Cc][Tt])			LCPOLICY="reject" ;	UCPOLICY="REJECT"	;;
			[Dd][Ee][Nn][Yy])					LCPOLICY="deny" ;	UCPOLICY="DENY"		;;
			esac
		done
		echo "NEWRULEPOLICY=$NEWRULEPOLICY" >>$MASONCONF
		echo NEWRULEPOLICY is being reset to \"$NEWRULEPOLICY\". >/dev/stderr
																;;
	esac

	case $DEFAULTPOLICY in
	[Aa][Cc][Cc][Ee][Pp][Tt])									DEFAULTPOLICY="accept"	;;
	[Rr][Ee][Jj][Ee][Cc][Tt])									DEFAULTPOLICY="reject"	;;
	[Dd][Ee][Nn][Yy])											DEFAULTPOLICY="deny"	;;
	*)	echo WARNING! DEFAULTPOLICY is neither accept, reject, nor deny. >/dev/stderr
		echo in $MASONCONF.  >/dev/stderr
		while [ "$DEFAULTPOLICY" != "accept" ] && [ "$DEFAULTPOLICY" != "reject" ] && [ "$DEFAULTPOLICY" != "deny" ] ; do
			echo Please choose accept, reject, or deny: >/dev/stderr
			read DEFAULTPOLICY JUNK
			case "$DEFAULTPOLICY" in
			[Aa][Cc][Cc][Ee][Pp][Tt])							DEFAULTPOLICY="accept"	;;
			[Rr][Ee][Jj][Ee][Cc][Tt])							DEFAULTPOLICY="reject"	;;
			[Dd][Ee][Nn][Yy])									DEFAULTPOLICY="deny"	;;
			esac
		done
		echo "DEFAULTPOLICY=$DEFAULTPOLICY" >>$MASONCONF
		echo DEFAULTPOLICY is being reset to \"$DEFAULTPOLICY\". >/dev/stderr			;;
	esac

	case $LOGGINGPOLICY in
	[Aa][Cc][Cc][Ee][Pp][Tt])									LOGGINGPOLICY="accept"	;;
	[Rr][Ee][Jj][Ee][Cc][Tt])									LOGGINGPOLICY="reject"	;;
	[Dd][Ee][Nn][Yy])											LOGGINGPOLICY="deny"	;;
	*)															LOGGINGPOLICY=$NEWRULEPOLICY	;;
	esac

	case $FLUSHEDPOLICY in
	[Aa][Cc][Cc][Ee][Pp][Tt])									FLUSHEDPOLICY="accept"	;;
	[Rr][Ee][Jj][Ee][Cc][Tt])									FLUSHEDPOLICY="reject"	;;
	[Dd][Ee][Nn][Yy])											FLUSHEDPOLICY="deny"	;;
	*)															FLUSHEDPOLICY="accept"	;;
	esac

	case $ECHOCOMMAND in
	[Ii][Pp][Ff][Ww][Aa][Dd][Mm])								ECHOCOMMAND="ipfwadm"	;;
	[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])							ECHOCOMMAND="ipchains"	;;
	[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss]-[Ss][Aa][Vv][Ee])			ECHOCOMMAND="ipchains-save"	;;
	[Cc][Ii][Ss][Cc][Oo])										ECHOCOMMAND="cisco"		;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee])									ECHOCOMMAND="none"		;;
	*)	if [ -f /proc/net/ip_fwchains ]; then					ECHOCOMMAND="ipchains"
		elif [ -f /proc/net/ip_input ]; then					ECHOCOMMAND="ipfwadm"
		else													ECHOCOMMAND="ipchains"			#Set default here
		fi																				;;
	esac

	case $DOCOMMAND in
	[Ii][Pp][Ff][Ww][Aa][Dd][Mm])
		DOCOMMAND="ipfwadm"
		if [ ! -f /proc/net/ip_input ]; then
			echo WARNING! User has requested ipfwadm, but it appears to be >/dev/stderr
			echo unavailable.  Proceeding, but this is not likely to work. >/dev/stderr
			sleep 10
		fi
		if [ ! -x /sbin/ipfwadm ]; then
			echo WARNING! User has requested ipfwadm, but /sbin/ipfwadm is not >/dev/stderr
			echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
			sleep 10
		fi																				;;
	[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])
		DOCOMMAND="ipchains"
		if [ ! -f /proc/net/ip_fwchains ]; then
			echo WARNING! User has requested ipchains, but it appears to be >/dev/stderr
			echo unavailable.  Proceeding, but this is not likely to work. >/dev/stderr
			sleep 10
		fi
		if [ ! -x /sbin/ipchains ]; then
			echo WARNING! User has requested ipchains, but /sbin/ipchains is not >/dev/stderr
			echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
			sleep 10
		fi																				;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee])	DOCOMMAND="none"										;;
	*)
		if [ -f /proc/net/ip_fwchains ]; then
			DOCOMMAND="ipchains"
			if [ ! -x /sbin/ipchains ]; then
				echo WARNING! This kernel uses ipchains, but /sbin/ipchains is not >/dev/stderr
				echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
				echo Please get a copy of the ipchains binary and place it in /sbin . >/dev/stderr
				sleep 10
			fi
		elif [ -f /proc/net/ip_input ]; then
			DOCOMMAND="ipfwadm"
			if [ ! -x /sbin/ipfwadm ]; then
				echo WARNING! This kernel uses ipfwadm, but /sbin/ipfwadm is not >/dev/stderr
				echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
				echo Please get a copy of the ipfwadm binary and place it in /sbin . >/dev/stderr
				sleep 10
			fi
		else
			DOCOMMAND="none"				#Well, we can't _do_ either!
			echo WARNING! Neither ipchains nor ipfwadm appears to be >/dev/stderr
			echo unavailable.  Proceeding anyways. >/dev/stderr
			sleep 10
		fi																				;;
	esac

	CKPTCHECKCONF=" checkconf: check heartbeat" ; #ckpt $CKPTCHECKCONF
	case $HEARTBEAT in
	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee])								HEARTBEAT="YES"			;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee]|[Ff][Aa][Ll][Ss][Ee])				HEARTBEAT="NO"			;;
	*)															HEARTBEAT="YES"			;;
	esac

	case $LOGBLOCKS in
	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|-[Ll]|-[Oo])					LOGBLOCKS="-l"			;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee]|[Ff][Aa][Ll][Ss][Ee])				LOGBLOCKS=""			;;
	*)															LOGBLOCKS=""			;;
	esac

	case $SORTMODE in
	[Pp][Rr][Oo][Tt][Oo][Cc][Oo][Ll])							SORTMODE="PROTOCOL"		;;
	[Pp][Aa][Cc][Kk][Ee][Tt][Cc][Oo][Uu][Nn][Tt][Ss])			SORTMODE="PACKETCOUNTS"	;;
	*)															SORTMODE="PROTOCOL"		;;
	esac

	case $IPCONV in
	[Hh][Oo][Ss][Tt][Nn][Aa][Mm][Ee]|[Hh][Oo][Ss][Tt])			IPCONV="HOST"			;;
	[Nn][Ee][Tt][Ww][Oo][Rr][Kk]|[Nn][Ee][Tt])					IPCONV="NETWORK"		;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee]|[Ff][Aa][Ll][Ss][Ee])				IPCONV="NONE"			;;
	#[Cc][Uu][Ss][Tt][Oo][Mm])									IPCONV="CUSTOM"			;;
	*)															IPCONV="NETWORK"		;;
	esac

	case $HOSTLOOKUP in
	[Nn][Oo]|[Nn][Oo][Nn][Ee]|[Ff][Aa][Ll][Ss][Ee])				HOSTLOOKUP="NONE"		;;
	[Ff][Ii][Ll][Ee][Ss]|[Ff][Ii][Ll][Ee][Ss][Oo][Nn][Ll][Yy])	HOSTLOOKUP="FILESONLY"	;;
	[Ff][Uu][Ll][Ll]|[Yy][Ee][Ss])								HOSTLOOKUP="FULL"		;;
	*)															HOSTLOOKUP="FULL"		;;
	esac

	case $GENERALIZETCPACK in
	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee])								GENERALIZETCPACK="YES"	;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee]|[Ff][Aa][Ll][Ss][Ee])				GENERALIZETCPACK="NO"	;;
	*)															GENERALIZETCPACK="NO"	;;
	esac


	CKPTCHECKCONF=" checkconf: Check networks" ; #ckpt $CKPTCHECKCONF
	#Class A 0-127, Class B 128-191, Class C 192-223, Class D 224-254.
	#A long time ago that would have been a good way to calculate the netmask automatically.  Unfortunately, CIDR makes that useless now.
	TEMPNETWORKS="$NETWORKS"
	NETWORKS=""
#FIXME - sort with the most specific up top?  Ugh.
	for ONENET in $TEMPNETWORKS ; do
		case $ONENET in		#convert /m netmasks over to /n.n.n.n
		*/[0-9]|*/[1-2][0-9]|*/3[0-2])	ONENET="${ONENET%%/*}/`bits2mask ${ONENET##*/}`"		;;
		esac
		case $ONENET in
		RUNTIME.NETWORKS)
			for RUNTIMENET in `route -n | grep -v '^127\.' | grep -v '^0\.0\.0\.0' | grep '^[0-9]' | awk '{print $1 "/" $3}'` ; do
				case $RUNTIMENET in
				*/255.255.255.255|*/255.255.255.254|*/255.255.255.252|*/0.0.0.0)	:							;;
				*)	NETWORKS="$NETWORKS ${RUNTIMENET%%/*}-`broadcastof ${RUNTIMENET%%/*} ${RUNTIMENET##*/}`/${RUNTIMENET##*/}"	;;
				esac
			done																		;;
		*/0.0.0.0|*/0)	echo $ONENET is not a valid network for generalization. >/dev/stderr	;;
		*-*/*)		NETWORKS="$NETWORKS $ONENET"										;;
		*/*)		NETWORKS="$NETWORKS ${ONENET%%/*}-`broadcastof ${ONENET%%/*} ${ONENET##*/}`/${ONENET##*/}"	;;
		0|0.*)		NETWORKS="$NETWORKS 0.0.0.0-0.255.255.255/255.0.0.0"				;;
		127|127.*)	NETWORKS="$NETWORKS 127.0.0.0-127.255.255.255/255.0.0.0"			;;
		*)			ROUTEMASK=`route -n | grep "^$ONENET[[:space:]]" | awk '{print $3}' | uniq`
					if [ `echo "$ROUTEMASK" | wc -l` -eq 1 ]; then
						NETWORKS="$NETWORKS $ONENET-`broadcastof $ONENET $ROUTEMASK`/$ROUTEMASK"
					else
						echo Unable to determine the netmask for $ONENET.  Please >/dev/stderr
						echo put an entry in the form network-broadcast/netmask in >/dev/stderr
						echo the NETWORKS variable in $MASONCONF . >/dev/stderr
					fi																	;;
		esac
	done
	unset TEMPNETWORKS
	if [ -z "$NETWORKS" ]; then		#load the NETWORKS variable with all non-trivial networks in the routing table.
		for RUNTIMENET in `route -n | grep -v '^127\.' | grep -v '^0\.0\.0\.0' | grep '^[0-9]' | awk '{print $1 "/" $3}'` ; do
			case $RUNTIMENET in
			*/255.255.255.255|*/255.255.255.254|*/255.255.255.252|*/0.0.0.0)	:							;;
			*)	NETWORKS="$NETWORKS ${RUNTIMENET%%/*}-`broadcastof ${RUNTIMENET%%/*} ${RUNTIMENET##*/}`/${RUNTIMENET##*/}"	;;	#network-broadcast/netmask
			esac
		done
	fi


	CKPTCHECKCONF=" checkconf: Check beep" ; #ckpt $CKPTCHECKCONF
	DOBEEP=${DOBEEP:-"YES"}	# "YES" = beep at user with new rule, "NO" = dont

	PORT_MASQ_BEGIN=${PORT_MASQ_BEGIN:-61000} ;		PORT_MASQ_END=${PORT_MASQ_END:-65096}
	TRACEROUTE_BEGIN=${TRACEROUTE_BEGIN:-33434} ;	TRACEROUTE_END=${TRACEROUTE_END:-33524}
	IRC_BEGIN=${IRC_BEGIN:-6666} ;					IRC_END=${IRC_END:-6671}

	MAXDISPLAYS=${MAXDISPLAYS:-6}
	X_BEGIN=${X_BEGIN:-6000} ;						X_END=${X_END:-$[ $X_BEGIN + $MAXDISPLAYS -1 ]}
	OPENWIN_BEGIN=${OPENWIN_BEGIN:-2000} ;			OPENWIN_END=${OPENWIN_END:-$[ $OPENWIN_BEGIN + $MAXDISPLAYS -1 ]}
	VNCJAVA_BEGIN=${VNCJAVA_BEGIN:-5800} ;			VNCJAVA_END=${VNCJAVA_END:-$[ $VNCJAVA_BEGIN + $MAXDISPLAYS -1 ]}
	VNC_BEGIN=${VNC_BEGIN:-5900} ;					VNC_END=${VNC_END:-$[ $VNC_BEGIN + $MAXDISPLAYS -1 ]}

	CKPTCHECKCONF=" checkconf: Check minmark" ; #ckpt $CKPTCHECKCONF
	if [ -n "$MINMARK" ]; then
		MINMARK=$[ $MINMARK ]			#Or should we use `echo $MINMARK | tr -d -c '[0-9]\n'` ?
		for ONEMARK in `ipchains -L -n -x -v | cut -b 66-75 - | grep '0x'` ; do
			if [ $MINMARK -le $[ $ONEMARK ] ]; then MINMARK=$[ $ONEMARK + 1 ] ; fi
		done
	fi
#Remove duplicates
	CKPTCHECKCONF=" checkconf: Remove dups" ; #ckpt $CKPTCHECKCONF
	if [ -n "$SSP" ]; then 				SSP=`echo "$SSP" | tr ' ' '\012' | sort | uniq` ;							fi
	if [ -n "$SCP" ]; then				SCP=`echo "$SCP" | tr ' ' '\012' | sort | uniq` ;							fi
	if [ -n "$BLOCKEDHOSTS" ]; then 	BLOCKEDHOSTS=`echo "$BLOCKEDHOSTS" | tr ' ' '\012' | sort | uniq` ;			fi
	if [ -n "$NOINCOMING" ]; then		NOINCOMING=`echo "$NOINCOMING" | tr ' ' '\012' | sort | uniq` ;				fi
	if [ -n "$POISONPROTOCOLS" ]; then	POISONPROTOCOLS=`echo "$POISONPROTOCOLS" | tr ' ' '\012' | sort | uniq` ;	fi
	#We can't dedupe this because we need the most specific nets first; a "sort" may destroy this order.
	#if [ -n "$NETWORKS" ]; then			NETWORKS=`echo "$NETWORKS" | tr ' ' '\012' | sort | uniq` ;					fi

	LOWSSHPORT=${LOWSSHPORT:-"1010"}

	CKPTCHECKCONF=" checkconf: Check editor" ; #ckpt $CKPTCHECKCONF
	if [ -z "$EDITOR" ]; then
		for TRYEDITOR in `type -path mcedit` `type -path pico` `type -path vi` `type -path jove` `type -path nedit` `type -path emacs`; do
			if [ -z "$EDITOR" ]; then
				EDITOR=$TRYEDITOR
				echo Editor default of $EDITOR taken. >/dev/stderr
			fi
		done
		unset TRYEDITOR || true
		if [ -z "$EDITOR" ]; then
			echo No editor was specified by the EDITOR= variable and >/dev/stderr
			echo this script was unable to find mcedit, pico, vi, jove, nedit or emacs >/dev/stderr
			echo on your system.  Please set EDITOR=the_name_of_an_editor >/dev/stderr
			echo in $MASONCONF or your environment and re-start. >/dev/stderr
			sleep 15
		fi #no suitable editor found
	fi
	if [ "$ECHOCOMMAND" = "cisco" ]; then
		SINGLEMACHSPEC=" 0.0.0.0" ; 		CMNT='!'
	else
		SINGLEMACHSPEC="/32" ;				CMNT="#"
	fi
	CKPTCHECKCONF=""
} #End of checkconf


#-------------------------------------------------------------------------
# checksys procedure.  Perform some basic checks on the system.
#-------------------------------------------------------------------------
checksys () {
	CKPTCHECKSYS=" checksys: Start" ; #ckpt $CKPTCHECKSYS
	if [ ! -d /proc/1 ]; then
		echo WARNING! Proc filesystem not supported or not mounted.  Please fix and restart.
		exit
	fi

	if [ ! -f /proc/net/ip_fwchains ] && [ ! -f /proc/net/ip_input ]; then
		echo This kernel supports neither ipchains nor ipfwadm! >/dev/stderr
		#DOCOMMAND="none"		#Should we force to none?
	fi

	#Are we allowed to quietly ignore the fact that a misconstructed path will probably make the following pipeline fail? *grin*
	for ONEPATH in `set | grep '^PATH=' | sed -e 's/^PATH=/ /' -e 's/:/ /g'` ; do		#check path for big 4.
		if [ "$ONEPATH" = "/bin" ]; then		BINOK="YES" ;		fi
		if [ "$ONEPATH" = "/sbin" ]; then		SBINOK="YES" ;		fi
		if [ "$ONEPATH" = "/usr/bin" ]; then	USRBINOK="YES" ;	fi
		if [ "$ONEPATH" = "/usr/sbin" ]; then	USRSBINOK="YES" ;	fi
	done
	if [ "$USRBINOK" != "YES" ]; then	export PATH="/usr/bin:$PATH" ;	fi
	if [ "$BINOK" != "YES" ]; then 		export PATH="/bin:$PATH" ;		fi
	if [ "$USRSBINOK" != "YES" ]; then	export PATH="/usr/sbin:$PATH" ;	fi
	if [ "$SBINOK" != "YES" ]; then		export PATH="/sbin:$PATH" ;		fi

	MISSINGUTILS=""
	#I don't test for rm (it's an alias on rh), shell builtins, or ipfwadm/ipchains (we test for them later).
	for ONEUTIL in awk bash cat chmod cut grep head host ifconfig mkdir route sed seq sleep sort tail touch tr true uniq wc ; do
		if [ -z "`type -path $ONEUTIL`" ]; then
			MISSINGUTILS="$MISSINGUTILS $ONEUTIL"
		fi
	done
	if [ -n "$MISSINGUTILS" ]; then
		echo The following tool/tools do not appear to be available on this system: >/dev/stderr
		echo $MISSINGUTILS >/dev/stderr
		echo You should make try to get these before continuing. >/dev/stderr
		echo This may be an indication that your path does not include >/dev/stderr
		echo at least /sbin, /bin, /usr/sbin, and /usr/bin. >/dev/stderr
		echo Press Ctrl-C to fix this, or wait 30 seconds if you want to >/dev/stderr
		echo try continuing anyways - cross your fingers. >/dev/stderr
		sleep 30
	fi
	
	CKPTCHECKSYS=" checksys: Create logchains" ; #ckpt $CKPTCHECKSYS
	if [ "$DOCOMMAND" = "ipchains" ]; then
		if [ -n "$NOLOGSUFFIX" ]; then
			for ONECHAIN in `/sbin/ipchains -L -n | grep '^Chain ' | awk '{print $2}'` ; do		#Could this just be input output forward ?
				case $ONECHAIN in
				*$NOLOGSUFFIX)	:								;;
				*)	# For each chain (except for the nolog chains themselves) check that a corresponding nolog chain exists.
					#Do not use -n - it does not work for this.
					if ! /sbin/ipchains -L $ONECHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null ; then  #If nolog chain does not exist
						LOGCHAINSEXIST="no"
						echo The $ONECHAIN chain exists without a corresponding $ONECHAIN$NOLOGSUFFIX >/dev/stderr
						echo chain.  For the moment, the "nolog" feature will revert to sticking the rules >/dev/stderr
						echo at the top of the original chain. >/dev/stderr
					fi												;;
				esac
			done
			if [ "$LOGCHAINSEXIST" = "no" ]; then $NOLOGSUFFIX = "" ; fi
		fi
	fi
	CKPTCHECKSYS=""
} #End of checksys


#-------------------------------------------------------------------------
# ckpt (checkpoint) procedure.  Logs where we are in Mason in case bash
# kills us so we can know where to look for a command with a non-zero
# return value.  I had hoped to use 
#trap "echo $LINENO" 0
# but this seems to return the line on which the trap command is placed, 
# not the line being executed when we exit.
# This is only intended for use by developers.
#-------------------------------------------------------------------------
ckpt () {
	if [ -f ${MASONDIR}ckpt ]; then echo $* >>${MASONDIR}ckpt ; fi
	#echo $* >/dev/stderr
} #End of ckpt


#-------------------------------------------------------------------------
# clientportrange function, returns the individual port or range of 
# ports for the given client port, server port, and protocol parameters.
#-------------------------------------------------------------------------
clientportrange () {
	CLIENTPORT="$1" ; SERVERPORT="$2" ; PRPROTO="$3" ; ACKFLAG="$4"
	CPRRETVAL="1024:65535"
	CKPTCLIENTPORTRANGE=" clientportrange: client $1 server $2 proto $3 ack $4" ; #ckpt $CKPTCLIENTPORTRANGE

	if [ "$ACKFLAG" = "-k" ]; then ACKFLAG="! -y" ; fi
	if [ -n "$1" ] && isdigits "$1" ; then
		if [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "ACCEPT" ] && [ $CLIENTPORT -ge 0 ] && [ $CLIENTPORT -le 1023 ]; then
			CPRRETVAL="0:1023"
		elif [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "MASQ" ] && [ $CLIENTPORT -ge 0 ] && [ $CLIENTPORT -le 1023 ]; then
			CPRRETVAL="0:1023"
		elif [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "ACCEPT" ] && [ $CLIENTPORT -ge "$PORT_MASQ_BEGIN" ] && [ $CLIENTPORT -le "$PORT_MASQ_END" ]; then
			CPRRETVAL="$PORT_MASQ_BEGIN:$PORT_MASQ_END"
		elif [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "MASQ" ] && [ $CLIENTPORT -ge "$PORT_MASQ_BEGIN" ] && [ $CLIENTPORT -le "$PORT_MASQ_END" ]; then
			CPRRETVAL="$PORT_MASQ_BEGIN:$PORT_MASQ_END"
		elif [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "ACCEPT" ] && [ $CLIENTPORT -ge "1024" ] && [ $CLIENTPORT -le "65535" ]; then
			CPRRETVAL="1024:65535"
		elif [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "MASQ" ] && [ $CLIENTPORT -ge "1024" ] && [ $CLIENTPORT -le "65535" ]; then
			CPRRETVAL="1024:65535"
		elif [ $CLIENTPORT -ge $PORT_MASQ_BEGIN ] && [ $CLIENTPORT -le $PORT_MASQ_END ]; then
			CPRRETVAL="$PORT_MASQ_BEGIN:$PORT_MASQ_END"
		elif [ $CLIENTPORT -ge $TRACEROUTE_BEGIN ] && [ $CLIENTPORT -le $TRACEROUTE_END ] && [ "$PRPROTO" = "udp" ]; then
			CPRRETVAL="$TRACEROUTE_BEGIN:$TRACEROUTE_END"
		elif [ -n "$SERVERPORT" ] && isdigits "$SERVERPORT" && [ $SERVERPORT -ge $TRACEROUTE_BEGIN ] && [ $SERVERPORT -le $TRACEROUTE_END ] && [ "$PRPROTO" = "udp" ]; then
			if [ $CLIENTPORT -ge 32768 ]; then CPRRETVAL="32768:65535" ; fi
			#According to the traceroute 1.4a5 source, the source port for a udp traceroute is set to the pid
			#with the high bit set.  This translates into 32768-65535; remember, the pid could be 32768.
		elif [ -n "$SERVERPORT" ] && isdigits "$SERVERPORT" && [ "$PRPROTO" = "udp" ] && [ $SERVERPORT -ge 6770 ] && [ $SERVERPORT -le 7170 ]; then	#RealAudio
			if [ $CLIENTPORT -ge 6970 ] && [ $CLIENTPORT -le 7170 ]; then
				CPRRETVAL="6970:7170"
			elif [ $CLIENTPORT -ge 6770 ] && [ $CLIENTPORT -le 7170 ]; then
				CPRRETVAL="6770:7170"
			fi
		else
			case "$SERVERPORT/$PRPROTO" in
			"22/tcp"|"ssh/tcp")
				if [ $CLIENTPORT -le 1023 ]; then
					while [ "$CLIENTPORT" -lt "$LOWSSHPORT" ]; do
						LOWSSHPORT=$[ $LOWSSHPORT - 10 ]
					done
					CPRRETVAL="$LOWSSHPORT:1023"
				fi													;;
			"111/tcp"|"sunrpc/tcp"|"rpcbind/tcp"|"111/udp"|"sunrpc/udp"|"rpcbind/tcp"|"635/tcp"|"mount/tcp"|"635/udp"|"mount/udp"|"2049/udp"|"nfs/udp")
#sunrpc/tcp: 600-1014 viewed with rpcinfo client, sunrpc/udp: 600-1022 viewed with nfs mount and unmount
#mount/tcp: 605-1022 viewed with nfs mount and unmount, mount/udp: 601-1022 viewed with nfs mount and unmount
#nfs/udp: 610-1014 and nfs viewed
				if [ $CLIENTPORT -le 1023 ]; then
					if [ $CLIENTPORT -ge 600 ]; then
						CPRRETVAL="600:1023"
					else
						CPRRETVAL="$CLIENTPORT"
					fi
				fi													;;
			"2049/tcp"|"nfs/tcp")	#Starts at 800 and works its way down, may reuse ports?
#Probably do a min port like ssh.  For the moment, use 760 to 800
				if [ $CLIENTPORT -le 1023 ]; then
					if [ $CLIENTPORT -ge 760 ] && [ $CLIENTPORT -le 800 ]; then
						CPRRETVAL="760:800"
					else
						CPRRETVAL="$CLIENTPORT"
					fi
				fi													;;
			*)
				if [ $CLIENTPORT -le 1023 ]; then CPRRETVAL="$CLIENTPORT" ; fi
																	;;
			esac
		fi
	fi
	echo $CPRRETVAL
	CKPTCLIENTPORTRANGE=""
} #End of clientportrange


#-------------------------------------------------------------------------
# convicmpcode procedure.  Take the icmp (code $1 and subcode $2) parameters
# and set COMMENT.  In the future, return a readable icmp code name?
#-------------------------------------------------------------------------
convicmpcode () {
#FIXME - add case for text versions of these numeric codes
	case "$1/$2" in
	0/*)		COMMENT="$CMNT Echo reply/icmp ($DIRLETTER)"					;;
	3/0)		COMMENT="$CMNT Net Unreach/icmp ($DIRLETTER)"					;;
	3/1)		COMMENT="$CMNT Host Unreach/icmp ($DIRLETTER)"					;;
	3/2)		COMMENT="$CMNT Protocol Unreach/icmp ($DIRLETTER)"				;;
	3/3)		COMMENT="$CMNT Port Unreach/icmp ($DIRLETTER)"					;;
	3/4)		COMMENT="$CMNT Frag Needed and DF Set/icmp ($DIRLETTER)"		;;
	3/5)		COMMENT="$CMNT Source Route Failed/icmp ($DIRLETTER)"			;;
	3/6)		COMMENT="$CMNT Dest Net Unknown/icmp ($DIRLETTER)"				;;
	3/7)		COMMENT="$CMNT Dest Host Unknown/icmp ($DIRLETTER)"				;;
	3/8)		COMMENT="$CMNT Source Host Isolated/icmp ($DIRLETTER)"			;;
	3/9)		COMMENT="$CMNT Comm with Dest Net Admin Prohib/icmp ($DIRLETTER)"	;;
	3/10)		COMMENT="$CMNT Comm with Dest Host Admin Prohib/icmp ($DIRLETTER)"	;;
	3/11)		COMMENT="$CMNT Dest Net Unreach for TOS/icmp ($DIRLETTER)"		;;
	3/12)		COMMENT="$CMNT Dest Host Unreach for TOS/icmp ($DIRLETTER)"		;;
	3/13)		COMMENT="$CMNT Comm Admin Prohib/icmp ($DIRLETTER)"				;;
	3/14)		COMMENT="$CMNT Host Precedence Violation/icmp ($DIRLETTER)"		;;
	3/15)		COMMENT="$CMNT Precedence cutoff in effect/icmp ($DIRLETTER)"	;;
	3/*)		COMMENT="$CMNT Dest Unreach/icmp ($DIRLETTER)"					;;
	4/*)		COMMENT="$CMNT Source Quench/icmp ($DIRLETTER)"					;;
	5/0)		COMMENT="$CMNT Redir Datagram for (sub)Net/icmp ($DIRLETTER)"	;;
	5/1)		COMMENT="$CMNT Redir Datagram for Host/icmp ($DIRLETTER)"		;;
	5/2)		COMMENT="$CMNT Redir Datagram for TOS and Net/icmp ($DIRLETTER)"	;;
	5/3)		COMMENT="$CMNT Redir Datagram for TOS and Host/icmp ($DIRLETTER)"	;;
	5/*)		COMMENT="$CMNT Redirect/icmp ($DIRLETTER)"						;;
	6/*)		COMMENT="$CMNT Alt host address/icmp ($DIRLETTER)"				;;
	8/*)		COMMENT="$CMNT Echo req/icmp ($DIRLETTER)"						;;
	9/*)		COMMENT="$CMNT Router Advertisement/icmp ($DIRLETTER)"			;;
	10/*)		COMMENT="$CMNT Router Selection/icmp ($DIRLETTER)"				;;
	11/0)		COMMENT="$CMNT TTL exceeded in Transit/icmp ($DIRLETTER)"		;;
	11/1)		COMMENT="$CMNT Frag Reassembly Time Exceeded/icmp ($DIRLETTER)"	;;
	11/*)		COMMENT="$CMNT Time exceeded/icmp ($DIRLETTER)"					;;
	12/0)		COMMENT="$CMNT Pointer indicates error/icmp ($DIRLETTER)"		;;
	12/1)		COMMENT="$CMNT Missing Required Option/icmp ($DIRLETTER)"		;;
	12/2)		COMMENT="$CMNT Bad Length/icmp ($DIRLETTER)"					;;
	12/*)		COMMENT="$CMNT Parameter prob/icmp ($DIRLETTER)"				;;
	13/*)		COMMENT="$CMNT Timestamp req/icmp ($DIRLETTER)"					;;
	14/*)		COMMENT="$CMNT Timestamp reply/icmp ($DIRLETTER)"				;;
	15/*)		COMMENT="$CMNT Info req/icmp ($DIRLETTER)"						;;
	16/*)		COMMENT="$CMNT Info reply/icmp ($DIRLETTER)"					;;
	17/*)		COMMENT="$CMNT Addr Mask req/icmp ($DIRLETTER)"					;;
	18/*)		COMMENT="$CMNT Addr Mask reply/icmp ($DIRLETTER)"				;;
	30/*)		COMMENT="$CMNT Traceroute/icmp ($DIRLETTER)"					;;
	31/*)		COMMENT="$CMNT Datagram Conv Err/icmp ($DIRLETTER)"				;;
	32/*)		COMMENT="$CMNT Mobile Host Redir/icmp ($DIRLETTER)"				;;
	33/*)		COMMENT="$CMNT IPv6 Where-Are-You/icmp ($DIRLETTER)"			;;
	34/*)		COMMENT="$CMNT IPv6 I-Am-Here/icmp ($DIRLETTER)"				;;
	35/*)		COMMENT="$CMNT Mobile Registration Req/icmp ($DIRLETTER)"		;;
	36/*)		COMMENT="$CMNT Mobile Registration Reply/icmp ($DIRLETTER)"		;;
	37/*)		COMMENT="$CMNT Domain Name Request/icmp ($DIRLETTER)"			;;
	38/*)		COMMENT="$CMNT Domain Name Reply/icmp ($DIRLETTER)"				;;
	39/*)		COMMENT="$CMNT SKIP/icmp ($DIRLETTER)"							;;
	40/1)		COMMENT="$CMNT Photuris unknown SPI/icmp ($DIRLETTER)"			;;
	40/2)		COMMENT="$CMNT Photuris auth fail/icmp ($DIRLETTER)"			;;
	40/3)		COMMENT="$CMNT Photuris decrypt fail/icmp ($DIRLETTER)"			;;
	40/*)		COMMENT="$CMNT Photuris/icmp ($DIRLETTER)"						;;
#FIXME - include source and dest IPs for the following?
	*)			COMMENT="$CMNT unknown-$SRCPORT/icmp ($DIRLETTER)"				;;
	esac
} #End of convicmpcode


#-------------------------------------------------------------------------
# delcounts procedure, deletes the packet counts from the rules in a file.
#-------------------------------------------------------------------------
delcounts () {
#Params: $1 is the filespec for the files that need counts removed.
	CKPTDELCOUNTS=" delcounts: Start $1" ; #ckpt $CKPTDELCOUNTS
	for ONEFILE in $1 ; do
		sed -e 's/[[:space:]]*#\^[[:space:]][0-9]*//' -e 's/[[:space:]]*$//' $ONEFILE >$ONEFILE.temp
		cat $ONEFILE.temp >$ONEFILE
		rm -f $ONEFILE.temp
	done
	CKPTDELCOUNTS=""
} #End of delcounts


#-------------------------------------------------------------------------
#Flush the existing rules so we start with a clean slate.
#-------------------------------------------------------------------------
flushfirewall () {
	CKPTFLUSHFIREWALL=" flushfirewall: Start" ; #ckpt $CKPTFLUSHFIREWALL
	if [ -f /proc/net/ip_fwchains ]; then
		echo -n Flushing... >/dev/stderr
		FLUSHEDPOLICY=`echo $FLUSHEDPOLICY | tr a-z A-Z`
		/sbin/ipchains -P output $FLUSHEDPOLICY ;	/sbin/ipchains -F output
		/sbin/ipchains -P forward $FLUSHEDPOLICY ;	/sbin/ipchains -F forward
		/sbin/ipchains -P input $FLUSHEDPOLICY ;	/sbin/ipchains -F input
#Flush the nolog chains if they exist, create them if not.
		CKPTFLUSHFIREWALL=" flushfirewall: Create or flush nolog chains." ; #ckpt $CKPTFLUSHFIREWALL
		if [ -n "$NOLOGSUFFIX" ]; then
			for ONECHAIN in output forward input ; do
				if [ `/sbin/ipchains -L -n | grep "^Chain $ONECHAIN$NOLOGSUFFIX" | wc -l` -gt 0 ]; then
					/sbin/ipchains -F $ONECHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null
				else
					/sbin/ipchains -N $ONECHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null
				fi
			done
		fi
		echo Done!
	elif [ -f /proc/net/ip_input ]; then
		echo -n Flushing... >/dev/stderr
		FLUSHEDPOLICY=`echo $FLUSHEDPOLICY | tr A-Z a-z`
		/sbin/ipfwadm -O -p $FLUSHEDPOLICY ;	/sbin/ipfwadm -O -f
		/sbin/ipfwadm -F -p $FLUSHEDPOLICY ;	/sbin/ipfwadm -F -f
		/sbin/ipfwadm -I -p $FLUSHEDPOLICY ;	/sbin/ipfwadm -I -f
		echo Done!
	else
		echo This kernel supports neither ipchains nor ipfwadm! >/dev/stderr
	fi
	CKPTFLUSHFIREWALL=""
} #End of flushfirewall


#-------------------------------------------------------------------------
# generalizeip function.  For the given ip address parameter, return one
# of the following:
# - $DYNIFADDR for interfaces with dynamic IP addresses.
# - the corresponding hostname
# - itself, if a local address, broadcast address, or special address.
# - its IP network 
# - as a last resort, 0/0
# User can select operation with IPCONV= in masonconf.
#-------------------------------------------------------------------------
generalizeip () {
	CKPTGENERALIZEIP=" generalizeip: address $1" ; #ckpt $CKPTGENERALIZEIP
	case $1 in
	anywhere|*/0|*/0.0.0.0)	GIRETVAL="0/0"						;;
	*/*)					GIRETVAL="$1"						;;
	*)
		GIRETVAL="$1$SINGLEMACHSPEC"
		ISASSIGNED="NO"
		for ONEIF in $DYNIF ; do
			if [ "$1" = "$(eval echo \${$(eval echo ${ONEIF}ADDR)})" ]; then	#The nested eval thing is the IP address of that interface.
				GIRETVAL="\${${ONEIF}ADDR}"		#Do not add /32 here - that shell variable _has_ /32 in it.
				ISASSIGNED="YES"
				#LINEHASDYNAMIC="YES"		#Not exported from a function - not currently used
			fi
		done

		if [ "$ISASSIGNED" = "NO" ]; then
			case $IPCONV in
			HOST)
				GIRETVAL="`nameof $1`$SINGLEMACHSPEC"								;;
			NETWORK)
#Handle special addresses
				case $1 in
				0.0.0.0|0.0.0.0/32)					GIRETVAL="0.0.0.0$SINGLEMACHSPEC" ;			ISASSIGNED="YES"	;;
				127.0.0.1|127.0.0.1/32)				GIRETVAL="localhost$SINGLEMACHSPEC" ;		ISASSIGNED="YES"	;;
				255.255.255.255|255.255.255.255/32)	GIRETVAL="255.255.255.255$SINGLEMACHSPEC" ;	ISASSIGNED="YES"	;;
				*[-A-Za-z]*)						GIRETVAL="$1" ;								ISASSIGNED="YES"	;;	#We should only be converting numeric addresses
				*)
					CKPTGENERALIZEIP=" generalizeip: all numeric" ; #ckpt $CKPTGENERALIZEIP
#Leave local IP addresses and broadcasts as they are.
#FIXME - pull broadcasts from /etc/hosts too?
					if [ "$ISASSIGNED" = "NO" ]; then
						for ONELOCALIP in $ALLIPS $ALLBCS ; do
							if [ "$1" = "$ONELOCALIP" ]; then 
								GIRETVAL="`nameof $1`$SINGLEMACHSPEC"
								ISASSIGNED="YES"
							fi
						done
					fi

#If IP is in a local netblock, generalize to that netblock.
					if [ "$ISASSIGNED" = "NO" ] && isnumericip $1 ; then
						#for ONENET in `cat $NETCACHE` ; do #Use NETWORKS now...
						for ONENET in $NETWORKS ; do
							if [ "$ISASSIGNED" = "NO" ]; then
								NETMASK=${ONENET##*/}	; ONENET=${ONENET%/*}
								BROADCAST=${ONENET##*-}	; ONENET=${ONENET%-*}
								if iple $ONENET $1 ; then
									if iple $1 $BROADCAST ; then
										GIHOLDHOSTLOOKUP="$HOSTLOOKUP"
										HOSTLOOKUP="FILESONLY"
										if [ "$ECHOCOMMAND" = "cisco" ]; then
											GIRETVAL="`nameof $ONENET` `mask2cisco $NETMASK`"
										else
											GIRETVAL="`nameof $ONENET`/`mask2bits $NETMASK`"
										fi
										HOSTLOOKUP="$GIHOLDHOSTLOOKUP"
										ISASSIGNED="YES"
									fi
								fi
							fi
						done
					fi
																;;
				esac

				if [ "$ISASSIGNED" = "NO" ]; then	GIRETVAL="0/0" ; ISASSIGNED="YES" ; fi
																	;;
			NONE)													;;
			#CUSTOM)												;;
			esac
		fi
																;;
	esac
	echo $GIRETVAL
	CKPTGENERALIZEIP=""
} #End of generalizeip



#-------------------------------------------------------------------------
# ipeq function, returns true/false: ip addresses are equal? 
#-------------------------------------------------------------------------
#Not currently used...
ipeq () {
	SPLITIP=$1
	I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O4=$SPLITIP
	SPLITIP=$2
	I2O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O4=$SPLITIP

	if [ $I1O1 -eq $I2O1 ] && [ $I1O2 -eq $I2O2 ] && [ $I1O3 -eq $I2O3 ] && [ $I1O4 -eq $I2O4 ]; then
		return 0 #True
	else
		return 1 #False
	fi
} #End of ipeq


#-------------------------------------------------------------------------
# iple function, returns true (0) if first IP <= second IP, else false(1)
#-------------------------------------------------------------------------
iple () {
#if iple 128.2.3.4 127.0.0.1 ; then echo less than or eq >/dev/stderr ; else echo ge >/dev/stderr ; fi
	CKPTIPLE=" iple: start, addresses $1 and $2" ; #ckpt $CKPTIPLE
	SPLITIP=$1
	I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O4=$SPLITIP
	SPLITIP=$2
	I2O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O4=$SPLITIP

	  if [ $I1O1 -lt $I2O1 ]; then	return 0
	elif [ $I1O1 -gt $I2O1 ]; then	return 1
	elif [ $I1O2 -lt $I2O2 ]; then	return 0
	elif [ $I1O2 -gt $I2O2 ]; then	return 1
	elif [ $I1O3 -lt $I2O3 ]; then	return 0
	elif [ $I1O3 -gt $I2O3 ]; then	return 1
	elif [ $I1O4 -lt $I2O4 ]; then	return 0
	elif [ $I1O4 -gt $I2O4 ]; then	return 1
	else							return 0
	fi
	CKPTIPLE=""
} #End of iple



#-------------------------------------------------------------------------
# isdigits function, returns true (0) if parameter is numeric and between 0 and 99999, else false(1)
#-------------------------------------------------------------------------
isdigits () {
	IDRETVAL=1
	case $1 in
	[0-9])	IDRETVAL=0											;;
	[0-9][0-9])	IDRETVAL=0										;;
	[0-9][0-9][0-9])	IDRETVAL=0								;;
	[0-9][0-9][0-9][0-9])	IDRETVAL=0							;;
	[0-9][0-9][0-9][0-9][0-9])	IDRETVAL=0						;;
	#[0-9]|[0-9][0-9]|[0-9][0-9][0-9]|[0-9][0-9][0-9][0-9]|[0-9][0-9][0-9][0-9][0-9])	IDRETVAL=0	;;
	esac
	return $IDRETVAL
}



#-------------------------------------------------------------------------
# isnumericip function, returns true (0) if IP is a numeric IP address, else false(1)
#-------------------------------------------------------------------------
isnumericip () {
	CKPTISNUMERICIP=" isnumericip: start $1" ; #ckpt $CKPTISNUMERICIP
	INIRETVAL=0

	SPLITIP=$1
	I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O4=$SPLITIP

	case $I1O1 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:			;;
	*)													INIRETVAL=1	;;
	esac
	case $I1O2 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:			;;
	*)													INIRETVAL=1	;;
	esac
	case $I1O3 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:			;;
	*)													INIRETVAL=1	;;
	esac
	case $I1O4 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:			;;
	*)													INIRETVAL=1	;;
	esac

	return $INIRETVAL
	CKPTISNUMERICIP=""
} #End of isnumericip



#-------------------------------------------------------------------------
# loadconf function, called at start and on receipt of SIGUSR1
#-------------------------------------------------------------------------
loadconf () {
	CKPTLOADCONF=" loadconf: start" ; #ckpt $CKPTLOADCONF
	if [ "$NEEDLF" = "YES" ]; then echo >/dev/stderr ; NEEDLF="NO" ; fi
	#This is the configuration file mason uses.  The parameters in it can be 
	#changed while Mason is running as long as the SIGUSR1 signal is sent to 
	#Mason afterwards.  This can be done by typing "killall -USR1 mason"
	if [ -f $MASONCONF ]; then
		echo -n "Loading options from $MASONCONF..." >/dev/stderr
		. $MASONCONF
	else
		touch $MASONCONF
		chmod 700 $MASONCONF
		echo Unable to load options, $MASONCONF does not exist. >/dev/stderr
	fi
	CKPTLOADCONF=" loadconf: post load $MASONCONF" ; #ckpt $CKPTLOADCONF

	checkconf

	echo -n "Load IPs, networks and nameservers..." >/dev/stderr				#set ALLIPS and ALLBCS (broadcasts)
	ALLIPS="`ifconfig | grep 'inet addr' | sed -e 's/.*addr://' -e 's/ .*//'` \
	`route -n | grep '^[0-9\.]* *[0-9\.]* *255\.255\.255\.255' | awk '{print $1}'`"
	ALLBCS=`ifconfig | grep 'Bcast' | sed -e 's/.*Bcast://' -e 's/ .*//'`
#FIXME: ALLBCS includes net addresses too?

#FIXME - if netcache and the current netlist (below) are identical, briefly warn then delete netcache.
	if [ -n "$NETCACHE" ] && [ -n "`grep -v '^$' $NETCACHE`" ]; then
		echo WARNING!  The $NETCACHE file is no longer used by Mason.  Please >/dev/stderr
		echo transfer all values from this file to the NETWORKS variable in $MASONCONF.  >/dev/stderr
	fi
	#rm -f $NETCACHE ; touch $NETCACHE ; chmod 700 $NETCACHE

	CKPTLOADCONF=" loadconf: about to load dnsservers" ; #ckpt $CKPTLOADCONF
	DNSSERVERS=`grep '^nameserver' /etc/resolv.conf | awk '{print $2}'`

	echo "Done." >/dev/stderr
	SIGGED="YES"	#We received a signal
#FIXME - put killall -SIGUSR1 mason in ip-up...
	CKPTLOADCONF=""
} #End of loadconf


#-------------------------------------------------------------------------
# mask2bits function, returns the number of bits in the netmask parameter.
#-------------------------------------------------------------------------
mask2bits () {
	case $1 in
	255.255.255.255)	echo 32									;;
	255.255.255.254)	echo 31									;;
	255.255.255.252)	echo 30									;;
	255.255.255.248)	echo 29									;;
	255.255.255.240)	echo 28									;;
	255.255.255.224)	echo 27									;;
	255.255.255.192)	echo 26									;;
	255.255.255.128)	echo 25									;;
	255.255.255.0)		echo 24									;;
	255.255.254.0)		echo 23									;;
	255.255.252.0)		echo 22									;;
	255.255.248.0)		echo 21									;;
	255.255.240.0)		echo 20									;;
	255.255.224.0)		echo 19									;;
	255.255.192.0)		echo 18									;;
	255.255.128.0)		echo 17									;;
	255.255.0.0)		echo 16									;;
	255.254.0.0)		echo 15									;;
	255.252.0.0)		echo 14									;;
	255.248.0.0)		echo 13									;;
	255.240.0.0)		echo 12									;;
	255.224.0.0)		echo 11									;;
	255.192.0.0)		echo 10									;;
	255.128.0.0)		echo 9									;;
	255.0.0.0)			echo 8									;;
	254.0.0.0)			echo 7									;;
	252.0.0.0)			echo 6									;;
	248.0.0.0)			echo 5									;;
	240.0.0.0)			echo 4									;;
	224.0.0.0)			echo 3									;;
	192.0.0.0)			echo 2									;;
	128.0.0.0)			echo 1									;;
	0.0.0.0)			echo 0									;;
	*)					echo 32									;;
	esac
} #End of mask2bits


#-------------------------------------------------------------------------
# mask2cisco function, returns the cisco "reverse netmask" of the netmask parameter.
#-------------------------------------------------------------------------
mask2cisco () {
#This could be done in fewer lines by subtracting each octet from 255.
#I'm trying to avoid forking as it hurts performance.
	case $1 in
	255.255.255.255)	echo 0.0.0.0							;;
	255.255.255.254)	echo 0.0.0.1							;;
	255.255.255.252)	echo 0.0.0.3							;;
	255.255.255.248)	echo 0.0.0.7							;;
	255.255.255.240)	echo 0.0.0.15							;;
	255.255.255.224)	echo 0.0.0.31							;;
	255.255.255.192)	echo 0.0.0.63							;;
	255.255.255.128)	echo 0.0.0.127							;;
	255.255.255.0)		echo 0.0.0.255							;;
	255.255.254.0)		echo 0.0.1.255							;;
	255.255.252.0)		echo 0.0.3.255							;;
	255.255.248.0)		echo 0.0.7.255							;;
	255.255.240.0)		echo 0.0.15.255							;;
	255.255.224.0)		echo 0.0.31.255							;;
	255.255.192.0)		echo 0.0.63.255							;;
	255.255.128.0)		echo 0.0.127.255						;;
	255.255.0.0)		echo 0.0.255.255						;;
	255.254.0.0)		echo 0.1.255.255						;;
	255.252.0.0)		echo 0.3.255.255						;;
	255.248.0.0)		echo 0.7.255.255						;;
	255.240.0.0)		echo 0.15.255.255						;;
	255.224.0.0)		echo 0.31.255.255						;;
	255.192.0.0)		echo 0.63.255.255						;;
	255.128.0.0)		echo 0.127.255.255						;;
	255.0.0.0)			echo 0.255.255.255						;;
	254.0.0.0)			echo 1.255.255.255						;;
	252.0.0.0)			echo 3.255.255.255						;;
	248.0.0.0)			echo 7.255.255.255						;;
	240.0.0.0)			echo 15.255.255.255						;;
	224.0.0.0)			echo 31.255.255.255						;;
	192.0.0.0)			echo 63.255.255.255						;;
	128.0.0.0)			echo 127.255.255.255					;;
	0.0.0.0)			echo 255.255.255.255					;;
	*)					echo 0.0.0.0							;;
	esac
} #End of mask2cisco


#-------------------------------------------------------------------------
# nameof function, returns the hostname from the IP address parameter.
#-------------------------------------------------------------------------
nameof () {
#Use /etc/hosts and the "host" command to look up names for source and destination addresses.
	CKPTNAMEOF=" nameof: Start" ; #ckpt $CKPTNAMEOF
	NAMEOFRETVAL=""
#FIXME - Should we just drop everything after the /?
	NAMEOFINPUT=${1%%/32}

	CKPTNAMEOF=" nameof: check for dynifs" ; #ckpt $CKPTNAMEOF
	for ONEIF in $DYNIF ; do
		if [ "$NAMEOFINPUT" = "$(eval echo \${$(eval echo ${ONEIF}ADDR)})" ]; then	#The nested eval thing is the IP address of that interface.
			NAMEOFRETVAL="\${${ONEIF}ADDR}"		#Nameof is supposed to return something _without_ a /32, but the ppp0ADDR macros _have_ the /32.  It's OK because GI already does its own DYNIF checking, and the only other place that uses it is in mason/comment2.
			#LINEHASDYNAMIC="YES"		#Not exported from a function - not currently used
		fi
	done

	if [ -z "$NAMEOFRETVAL" ]; then
		if [ "$HOSTLOOKUP" = "FILESONLY" ] || [ "$HOSTLOOKUP" = "FULL" ]; then
			ONEHOSTNAME=`egrep "^$NAMEOFINPUT[^0-9]" /etc/hosts | tail --lines=1 | awk '{print $2}'`
			if [ -n "$ONEHOSTNAME" ]; then
				NAMEOFRETVAL="$ONEHOSTNAME"
			fi
		fi
	fi

	if [ -z "$NAMEOFRETVAL" ]; then
		case $NAMEOFINPUT in
		*/0|*/0.0.0.0)		NAMEOFRETVAL="0/0"					;;
		esac
	fi

	CKPTNAMEOF=" nameof: reverse host lookup" ; #ckpt $CKPTNAMEOF
	if [ "$HOSTLOOKUP" = "FULL" ] && [ -z "$NAMEOFRETVAL" ]; then
		if host -t ptr $NAMEOFINPUT >/dev/null 2>/dev/null ; then
			ONEHOSTNAME=`host -t ptr $NAMEOFINPUT 2>/dev/null | grep 'domain name pointer' | head --lines=1 | sed -e 's/.* //'`
			if [ -n "$ONEHOSTNAME" ]; then
				NAMEOFRETVAL="$ONEHOSTNAME"
			fi
		fi
	fi

	if [ -z "$NAMEOFRETVAL" ]; then NAMEOFRETVAL=$NAMEOFINPUT ; fi
	echo $NAMEOFRETVAL
	CKPTNAMEOF=""
} #End of nameof


#-------------------------------------------------------------------------
# port2ciscoport function, returns the individual port or range of 
# ports for the given port/port range and protocol parameters in cisco format.
#-------------------------------------------------------------------------
port2ciscoport () {			#$1 is the port number, $2 is the protocol
	CKPTPORT2CISCOPORT=" port2ciscoport: Start" ; #ckpt $CKPTPORT2CISCOPORT
	PCPRETVAL=""

	case "$1/$2" in
	0:1023/*)									PCPRETVAL=" lt 1024"								;;
	1024:65535/*)								PCPRETVAL=" gt 1023"								;;
#FIXME - this does not drop the protocol, I think.
	*:*/*)										PCPRETVAL=" range ${1%%:*} ${1##*:}"				;;
	179/tcp|bgp/tcp)							PCPRETVAL=" eq bgp"									;;
	19/tcp|chargen/tcp|ttyst/tcp|source/tcp)	PCPRETVAL=" eq chargen"								;;
	13/tcp|daytime/tcp)							PCPRETVAL=" eq daytime"								;;
	9/tcp|discard/tcp|sink/tcp|null/tcp)		PCPRETVAL=" eq discard"								;;
	53/tcp|domain/tcp|dns/tcp)					PCPRETVAL=" eq domain"								;;
	7/tcp|echo/tcp)								PCPRETVAL=" eq echo"								;;
	79/tcp|finger/tcp)							PCPRETVAL=" eq finger"								;;
	21/tcp|ftp/tcp)								PCPRETVAL=" eq ftp"									;;
	20/tcp|ftp-data/tcp)						PCPRETVAL=" eq ftp-data"							;;
	70/tcp|gopher/tcp)							PCPRETVAL=" eq gopher"								;;
	101/tcp|hostname/tcp|hostnames/tcp)			PCPRETVAL=" eq hostname"							;;
	194/tcp|irc/tcp)							PCPRETVAL=" eq irc"									;;
	543/tcp|klogin/tcp)							PCPRETVAL=" eq klogin"								;;
	544/tcp|kshell/tcp|krcmd/tcp)				PCPRETVAL=" eq kshell"								;;
	515/tcp|lpd/tcp|printer/tcp|spooler/tcp)	PCPRETVAL=" eq lpd"									;;
	109/tcp|pop-2/tcp|pop2/tcp|postoffice/tcp)	PCPRETVAL=" eq pop2"								;;
	110/tcp|pop-3/tcp|pop3/tcp)					PCPRETVAL=" eq pop3"								;;
	25/tcp|smtp/tcp)							PCPRETVAL=" eq smtp"								;;
	111/tcp|sunrpc/tcp|portmapper/tcp)			PCPRETVAL=" eq sunrpc"								;;
#I think the following was a mistake.  Cisco's docs show a TCP syslog - I dont think there is one.
	syslog/tcp)									PCPRETVAL=" eq syslog"								;;
	65/tcp|tacacs-ds/tcp)						PCPRETVAL=" eq tacacs-ds"							;;
	517/tcp|talk/tcp)							PCPRETVAL=" eq talk"								;;
	23/tcp|telnet/tcp)							PCPRETVAL=" eq telnet"								;;
	37/tcp|time/tcp|timserver/tcp)				PCPRETVAL=" eq time"								;;
	540/tcp|uucp/tcp|uucpd/tcp)					PCPRETVAL=" eq uucp"								;;
	43/tcp|whois/tcp|nicname/tcp)				PCPRETVAL=" eq whois"								;;
	80/tcp|www/tcp|http/tcp)					PCPRETVAL=" eq www"									;;
	512/udp|biff/udp|comsat/udp)				PCPRETVAL=" eq biff"								;;
	68/udp|bootpc/udp)							PCPRETVAL=" eq bootpc"								;;
	67/udp|bootps/udp)							PCPRETVAL=" eq bootps"								;;
	9/udp|discard/udp|sink/udp|null/udp)		PCPRETVAL=" eq discard"								;;
	53/udp|dns/udp|domain/udp)					PCPRETVAL=" eq dns"									;;
	90/udp|dnsix/udp)							PCPRETVAL=" eq dnsix"								;;
	7/udp|echo/udp)								PCPRETVAL=" eq echo"								;;
	434/udp|mobile-ip/udp|mobileip-agent/udp)	PCPRETVAL=" eq mobile-ip"							;;
	42/udp|nameserver/udp|name/udp)				PCPRETVAL=" eq nameserver"							;;
	138/udp|netbios-dgm/udp)					PCPRETVAL=" eq netbios-dgm"							;;
	137/udp|netbios-ns/udp)						PCPRETVAL=" eq netbios-ns"							;;
	123/udp|ntp/udp)							PCPRETVAL=" eq ntp"									;;
	520/udp|rip/udp|route/udp|router/udp|routed/udp)	PCPRETVAL=" eq rip"							;;
	161/udp|snmp/udp)							PCPRETVAL=" eq snmp"								;;
	162/udp|snmptrap/udp|snmp-trap/udp)			PCPRETVAL=" eq snmptrap"							;;
	111/udp|sunrpc/udp|portmapper/udp)			PCPRETVAL=" eq sunrpc"								;;
	514/udp|syslog/udp)							PCPRETVAL=" eq syslog"								;;
	65/udp|tacacs-ds/udp)						PCPRETVAL=" eq tacacs-ds"							;;
	517/udp|talk/udp)							PCPRETVAL=" eq talk"								;;
	69/udp|tftp/udp)							PCPRETVAL=" eq tftp"								;;
	37/udp|time/udp)							PCPRETVAL=" eq time"								;;
	513/udp|who/udp|whod/udp)					PCPRETVAL=" eq who"									;;
	177/udp|xdmcp/udp)							PCPRETVAL=" eq xdmcp"								;;
	*)
		if isdigits $1 ; then
			PCPRETVAL=" eq $1"
		else
#FIXME - convert alpha port name ("telnet") back to the port number ("23") for Cisco.
			PCPRETVAL=" eq $1"
		fi
																									;;
	esac
	echo "$PCPRETVAL"
	CKPTPORT2CISCOPORT=""
} #End of port2ciscoport


#-------------------------------------------------------------------------
# preexit procedure.  Called on receipt of signal 0 (exiting) from bash
#-------------------------------------------------------------------------
#We check to see if any of the checkpoint variables are still set; if so, 
#the script probably crashed before finishing that module.  Bitch to the user.
#Be careful of system variables; they may not be loaded yet.
preexit () {
#FIXME - include Mason version as well.
	if [ -n "$CKPTMGT$CKPTMASON$CKPTCHECKSYS$CKPTCLIENTPORTRANGE$CKPTGENERALIZEIP$CKPTIPLE$CKPTISNUMERICIP$CKPTLOADCONF$CKPTSERVERPORTRANGE$CKPTADDCOUNTS$CKPTNAMEOF$CKPTBROADCASTOF$CKPTCHECKCONF$CKPTDELCOUNTS$CKPTFLUSHFIREWALL$CKPTPORT2CISCOPORT$CKPTPROTONUM2NAME$CKPTRULETAG$CKPTRUNLEARNFIREWALL$CKPTRUNSTANDARDFIREWALL$CKPTSETTOS$CKPTSORTRULEFILE$CKPTUNIQRULEFILE" ]; then
		if [ -z "$MASONDIR" ]; then MASONDIR="/var/lib/mason/" ; fi
		echo																	>/dev/stderr
		echo Abnormal exit from $0.												>/dev/stderr
		echo The author, William Stearns, would be very grateful if you would	>/dev/stderr
		echo email the following information to wstearns@pobox.com, as well as	>/dev/stderr
		echo anything else that you think might be relevant.  It would help 	>/dev/stderr
		echo make future versions of mason more stable.  The easiest way to		>/dev/stderr
		echo do this is to attach ${MASONDIR}masoncrash to a message to 		>/dev/stderr
		echo wstearns@pobox.com .												>/dev/stderr
		echo																	>/dev/stderr
		date																	>/dev/stderr
		echo Most recent checkpoints:											>/dev/stderr
		echo $CKPTMGT $CKPTMASON $CKPTCHECKSYS $CKPTCLIENTPORTRANGE \
		 $CKPTGENERALIZEIP $CKPTIPLE $CKPTISNUMERICIP $CKPTLOADCONF \
		 $CKPTSERVERPORTRANGE $CKPTADDCOUNTS $CKPTNAMEOF $CKPTBROADCASTOF \
		 $CKPTCHECKCONF $CKPTDELCOUNTS $CKPTFLUSHFIREWALL $CKPTPORT2CISCOPORT \
		 $CKPTPROTONUM2NAME $CKPTRULETAG $CKPTRUNLEARNFIREWALL \
		 $CKPTRUNSTANDARDFIREWALL $CKPTSETTOS $CKPTSORTRULEFILE \
		 $CKPTUNIQRULEFILE														>/dev/stderr
		echo End of checkpoints.												>/dev/stderr
		echo																	>/dev/stderr
		echo This file was created as a result of a crash of $0 .				>>${MASONDIR}masoncrash
		echo It was created automatically. Please mail it to wstearns@pobox.com >>${MASONDIR}masoncrash
		date																	>>${MASONDIR}masoncrash
		echo Most recent checkpoints:											>>${MASONDIR}masoncrash
		echo $CKPTMGT $CKPTMASON $CKPTCHECKSYS $CKPTCLIENTPORTRANGE \
		 $CKPTGENERALIZEIP $CKPTIPLE $CKPTISNUMERICIP $CKPTLOADCONF \
		 $CKPTSERVERPORTRANGE $CKPTADDCOUNTS $CKPTNAMEOF $CKPTBROADCASTOF \
		 $CKPTCHECKCONF $CKPTDELCOUNTS $CKPTFLUSHFIREWALL $CKPTPORT2CISCOPORT \
		 $CKPTPROTONUM2NAME $CKPTRULETAG $CKPTRUNLEARNFIREWALL \
		 $CKPTRUNSTANDARDFIREWALL $CKPTSETTOS $CKPTSORTRULEFILE \
		 $CKPTUNIQRULEFILE														>>${MASONDIR}masoncrash
		echo End of checkpoints.												>>${MASONDIR}masoncrash
		echo																	>>${MASONDIR}masoncrash
		if [ -n "$MASONCONF" ]; then
			if [ -e "$MASONCONF" ]; then
				echo Masonconf:													>>${MASONDIR}masoncrash
				cat $MASONCONF | sed -e 's/#.*//' | grep -v '^$'				>>${MASONDIR}masoncrash
				echo End of Masonconf.											>>${MASONDIR}masoncrash
			else
				echo No Masonconf found.										>>${MASONDIR}masoncrash
			fi
		else
			echo Masonconf environment variable not set.						>>${MASONDIR}masoncrash
		fi
		echo																	>>${MASONDIR}masoncrash
	fi
} #End of preexit


#-------------------------------------------------------------------------
# protonum2name procedure, sets PROTO to the readable protocol name from protocol number and sets IGNOREPORT.
#-------------------------------------------------------------------------
protonum2name () {
	CKPTPROTONUM2NAME=" protonum2name: Start" ; #ckpt $CKPTPROTONUM2NAME
	unset IGNOREPORT || true
	case $1 in
	0)		PROTO="ip"		IGNOREPORT="YES"				;;
	1)		PROTO="icmp"									;;
	2)		PROTO="igmp"	IGNOREPORT="YES"				;;
	3)		PROTO="ggp"		IGNOREPORT="YES"				;;
	4)		PROTO="ipip"	IGNOREPORT="YES"				;;
	6)		PROTO="tcp"										;;
	8)		PROTO="egp"		IGNOREPORT="YES"				;;
	12)		PROTO="pup"		IGNOREPORT="YES"				;;
	17)		PROTO="udp"										;;
	22)		PROTO="idp"		IGNOREPORT="YES"				;;
	41)		PROTO="ipv6"	IGNOREPORT="YES"				;;
	46)		PROTO="rsvp"	IGNOREPORT="YES"				;;
	47)		PROTO="gre"		IGNOREPORT="YES"				;;
	50)		PROTO="esp"		IGNOREPORT="YES"				;;
	103)	PROTO="pim"		IGNOREPORT="YES"				;;
	255)	PROTO="raw"		IGNOREPORT="YES"				;;
	*)
		PROTONAME=`grep "^[a-zA-Z]*\W*$1 *" /etc/protocols | awk '{print $1}'`
		if [ -n "$PROTONAME" ]; then PROTO=$PROTONAME ; else PROTO=$1 ; fi
		unset PROTONAME
		IGNOREPORT="YES"
															;;
	esac
	CKPTPROTONUM2NAME=""
} #End of protonum2name


#-------------------------------------------------------------------------
# reservedip function, returns true/false: ip address is reserved (rfc1918)?
#-------------------------------------------------------------------------
#OK, technically a hostname _could_ correspond to a reserved address, but come on!
#If we're being handed a hostname, we probably don't need to autoset masq anyways.
reservedip () {
	case $1 in
	*[-A-Za-z]*)	return 1			;;
	*)
		SPLITIP=$1
		I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
		I1O2=${SPLITIP%%.*}

		if [ $I1O1 -eq 10 ]; then												return 0 #True
		elif [ $I1O1 -eq 172 ] && [ $I1O2 -ge 16 ] && [ $I1O2 -le 31 ]; then	return 0 #True
		elif [ $I1O1 -eq 192 ] && [ $I1O2 -eq 168 ]; then						return 0 #True
		else																	return 1 #False
		fi
										;;
	esac
} #End of reservedip


#-------------------------------------------------------------------------
# ruletag function, returns a kind of hash of the rule to identify equivalence.
#-------------------------------------------------------------------------
ruletag () {
#Params: $* is an ipchains command.
#This function returns a tag.  This tag is used to determine if two rules can
#be safely swapped; they can if their tags are identical.
#Tag: first object/target(w/redirect port)/-l/#^
#This tag could also include the mark value. Hmmm, should it?
	CKPTRULETAG=" ruletag: Start" ; #ckpt $CKPTRULETAG
	RTRETVAL=$1
	TARGET="" ; LOG="" ; COUNTTAG=""
	while [ -n "$1" ]; do
		case $1 in
		-j|--jump)
			NEXT="TARGET" ; TARGET="-j" ; shift										;;
		-l|--log)
			NEXT="" ; LOG="-l" ; shift												;;
		-A|--append|-D|--delete|-R|--replace|-I|--insert|-L|--list|-F|--flush|-Z|--zero|-N|--new-chain|-X|--delete-chain|-P|--policy|-M|--masquerading|-S|--set|-C|--check|-h|-p|--protocol|-s|--source|--source-port|-d|--destination|--destination-port|--icmp-type|-i|--interface|!|-f|--fragment|-b|--bidirectional|-v|--verbose|-n|--numeric|-o|--output|-m|--mark|-t|--TOS|-x|--exact|-y|--syn)
			NEXT="" ; shift															;;
		\#^)
			NEW="" ; COUNTTAG="#^" ; shift											;;
		\#*)
			NEXT="" ; shift $#														;;	#Drop everything following a "#"
		*)
			case $NEXT in
			TARGET)	TARGET="${TARGET}$1" ; shift	;;
			*)		shift							;;
			esac
																					;;
		esac
	done
	echo "$RTRETVAL/$TARGET/$LOG/$COUNTTAG"
	CKPTRULETAG=""
} #End of ruletag


#-------------------------------------------------------------------------
#Start up a firewall from scratch.  Use both baserules and newrules.
#-------------------------------------------------------------------------
runlearnfirewall () {
	CKPTRUNLEARNFIREWALL=" runlearnfirewall: Start" ; #ckpt $CKPTRUNLEARNFIREWALL
	if [ -f /proc/net/ip_fwchains ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr a-z A-Z`
		if [ "$LOGBLOCKS" = "-o" ]; then LOGBLOCKS="-l" ; fi

		if [ -f /proc/sys/net/ipv4/ip_forward ]; then
			if [ "`cat /proc/sys/net/ipv4/ip_forward`" = "0" ]; then
				echo Please note that forwarding is disabled in the kernel. >/dev/stderr
				echo If this machine is expected to be a router, this should be fixed. >/dev/stderr
			fi
		fi

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains blockedhosts" ; #ckpt $CKPTRUNLEARNFIREWALL
		if [ -n "$BLOCKEDHOSTS" ]; then
			echo -n Blockedhost blocks...
			for BLOCKEDHOST in $BLOCKEDHOSTS ; do		#Add this in if we reinstate marks on system rules, check below too.  ${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
				/sbin/ipchains -I input  -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I input  -d $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -d $BLOCKEDHOST -j DENY $LOGBLOCKS
			done
		else
			echo -n No Blockedhost blocks...
		fi

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains noleakrfc1918" ; #ckpt $CKPTRUNLEARNFIREWALL
		#This is a construction issue only; if rfc1918 packets leak through as the firewall is being constructed, 
		#we deny them to tell the sending end to try again.  Once the forward/MASQ rules are in place, 
		#this won't be used again.
		if [ -n "$AUTOMASQIF" ]; then
			echo -n NoLeakRFC1918 blocks...
			for MASQIF in $AUTOMASQIF ; do		#Add this in if we reinstate marks on system rules, check below too.  ${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
				for RESNET in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 ; do
					/sbin/ipchains -I output -i $MASQIF -s $RESNET -j DENY
				done
			done
		else
			echo -n No NoLeakRFC1918 blocks...
		fi

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains noincoming" ; #ckpt $CKPTRUNLEARNFIREWALL
		if [ -n "$NOINCOMING" ] && [ -n "$INCOMINGINTERFACES" ]; then
			echo -n Incoming blocks...
			for OUTSIDEIF in $INCOMINGINTERFACES ; do
				for BLOCKPROTO in $NOINCOMING ; do
					case $BLOCKPROTO in			#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
					*/icmp|*/ICMP)	/sbin/ipchains -I input -i $OUTSIDEIF -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS				;;
					*/*)			/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS 	;;
					*)				/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS							;;
					esac
				done
			done
		else
			echo -n No incoming blocks...
		fi

		set +e		#Turn off failure checking; Mason has no control over the final contents of these files
		#echo -n System rules...
		#. $SYSTEMRULEFILE
		#
		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains baserules" ; #ckpt $CKPTRUNLEARNFIREWALL
		echo -n Fixed rules...
		. $BASERULEFILE

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains newrules" ; #ckpt $CKPTRUNLEARNFIREWALL
		echo -n New rules...
		. $NEWRULEFILE
		set -e

#Finally, create a "nolog' chain for each of the existing chains, have each existing 
#chain jump to it, then log everything else.
		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains logging rules" ; #ckpt $CKPTRUNLEARNFIREWALL
		echo -n Adding logging rules...
		for ACHAIN in input output forward ; do
			/sbin/ipchains -F $ACHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null				#Flush it as it might have existed before.
			if ! /sbin/ipchains -L $ACHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null ; then	#If nolog chain does not exist
				/sbin/ipchains -N $ACHAIN$NOLOGSUFFIX					#Create it
		  	fi
			#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
			/sbin/ipchains -A $ACHAIN -j $ACHAIN$NOLOGSUFFIX
			/sbin/ipchains -A $ACHAIN -l
			/sbin/ipchains -P $ACHAIN $DEFAULTPOLICY
		done
		echo Done!
	elif [ -f /proc/net/ip_input ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr A-Z a-z`
		if [ "$LOGBLOCKS" = "-l" ]; then LOGBLOCKS="-o" ; fi

		if [ -f /proc/sys/net/ipv4/ip_forward ]; then
			if [ "`cat /proc/sys/net/ipv4/ip_forward`" = "0" ]; then
				echo Please note that forwarding is disabled in the kernel. >/dev/stderr
				echo If this machine is expected to be a router, this should be fixed. >/dev/stderr
			fi
		fi

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipfwadm blockedhosts" ; #ckpt $CKPTRUNLEARNFIREWALL
		if [ -n "$BLOCKEDHOSTS" ]; then
			echo -n Blockedhost blocks...
			for BLOCKEDHOST in $BLOCKEDHOSTS ; do
				/sbin/ipfwadm -I -i deny -S $BLOCKEDHOST $LOGBLOCKS
				/sbin/ipfwadm -O -i deny -S $BLOCKEDHOST $LOGBLOCKS
				/sbin/ipfwadm -I -i deny -D $BLOCKEDHOST $LOGBLOCKS
				/sbin/ipfwadm -O -i deny -D $BLOCKEDHOST $LOGBLOCKS
			done
		else
			echo -n No Blockedhost blocks...
		fi

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipfwadm noleakrfc1918" ; #ckpt $CKPTRUNLEARNFIREWALL
		#This is a construction issue only; if rfc1918 packets leak through as the firewall is being constructed, 
		#we deny them to tell the sending end to try again.  Once the forward/MASQ rules are in place, 
		#this won't be used again.
		if [ -n "$AUTOMASQIF" ]; then
			echo -n NoLeakRFC1918 blocks...
			for MASQIF in $AUTOMASQIF ; do		#Add this in if we reinstate marks on system rules, check below too.  ${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
				for RESNET in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 ; do
					/sbin/ipfwadm -O -i deny -W $MASQIF -S $RESNET
				done
			done
		else
			echo -n No NoLeakRFC1918 blocks...
		fi

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipfwadm noincoming" ; #ckpt $CKPTRUNLEARNFIREWALL
		if [ -n "$NOINCOMING" ] && [ -n "$INCOMINGINTERFACES" ]; then
			echo -n Incoming blocks...
			for OUTSIDEIF in $INCOMINGINTERFACES ; do
				for BLOCKPROTO in $NOINCOMING ; do
					case $BLOCKPROTO in
					*/icmp|*/ICMP)	/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS				;;
					*/*)			/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS	;;
					*)				/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} $LOGBLOCKS							;;
					esac
				done
			done
		else
			echo -n No incoming blocks...
		fi

		set +e		#Turn off failure checking; Mason has no control over the final contents of these files
		#echo -n System rules...
		#. $SYSTEMRULEFILE
		#
		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipfwadm baserules" ; #ckpt $CKPTRUNLEARNFIREWALL
		echo -n Fixed rules...
		. $BASERULEFILE

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipfwadm newrules" ; #ckpt $CKPTRUNLEARNFIREWALL
		echo -n New rules...
		. $NEWRULEFILE
		set -e

#Finally, log everything else.
		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipfwadm logging" ; #ckpt $CKPTRUNLEARNFIREWALL
		echo -n Adding logging rules...
		for ACHAIN in I O F ; do
			/sbin/ipfwadm -$ACHAIN -a $LOGGINGPOLICY -o
			/sbin/ipfwadm -$ACHAIN -p $DEFAULTPOLICY
		done
		echo Done!
	else
		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains and ipfwadm not supported." ; #ckpt $CKPTRUNLEARNFIREWALL
		echo This kernel supports neither ipchains nor ipfwadm! >/dev/stderr
	fi
	CKPTRUNLEARNFIREWALL=""
} #End of runlearnfirewall


#-------------------------------------------------------------------------
#Start up a firewall from scratch.  Only use baserules.
#-------------------------------------------------------------------------
runstandardfirewall () {
	CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: Start" ; #ckpt $CKPTRUNSTANDARDFIREWALL
	if [ -f /proc/net/ip_fwchains ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr a-z A-Z`
		if [ "$LOGBLOCKS" = "-o" ]; then LOGBLOCKS="-l" ; fi

		if [ -f /proc/sys/net/ipv4/ip_forward ]; then
			if [ "`cat /proc/sys/net/ipv4/ip_forward`" = "0" ]; then
				echo Please note that forwarding is disabled in the kernel. >/dev/stderr
				echo If this machine is expected to be a router, this should be fixed. >/dev/stderr
			fi
		fi

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipchains blockedhosts" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		if [ -n "$BLOCKEDHOSTS" ]; then
			echo -n Blockedhost blocks...
			for BLOCKEDHOST in $BLOCKEDHOSTS ; do		#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
				/sbin/ipchains -I input  -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I input  -d $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -d $BLOCKEDHOST -j DENY $LOGBLOCKS
			done
		else
			echo -n No Blockedhost blocks...
		fi

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipchains noleakrfc1918" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		#This is a construction issue only; if rfc1918 packets leak through as the firewall is being constructed, 
		#we deny them to tell the sending end to try again.  Once the forward/MASQ rules are in place, 
		#this won't be used again.
		if [ -n "$AUTOMASQIF" ]; then
			echo -n NoLeakRFC1918 blocks...
			for MASQIF in $AUTOMASQIF ; do		#Add this in if we reinstate marks on system rules, check below too.  ${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
				for RESNET in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 ; do
					/sbin/ipchains -I output -i $MASQIF -s $RESNET -j DENY
				done
			done
		else
			echo -n No NoLeakRFC1918 blocks...
		fi

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipchains noincoming" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		if [ -n "$NOINCOMING" ] && [ -n "$INCOMINGINTERFACES" ]; then
			echo -n Incoming blocks...
			for OUTSIDEIF in $INCOMINGINTERFACES ; do
				for BLOCKPROTO in $NOINCOMING ; do
					case $BLOCKPROTO in			#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
					*/icmp|*/ICMP)	/sbin/ipchains -I input -i $OUTSIDEIF -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS				;;
					*/*)			/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS	;;
					*)				/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS							;;
					esac
				done
			done
		else
			echo -n No incoming blocks...
		fi

		set +e		#Turn off failure checking; Mason has no control over the final contents of these files.
		#echo -n System rules...
		#. $SYSTEMRULEFILE
		#
		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipchains baserules" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		echo -n Fixed rules...
		. $BASERULEFILE
		set -e

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipchains policy" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		for ACHAIN in input output forward ; do
			/sbin/ipchains -P $ACHAIN $DEFAULTPOLICY
		done
		echo Done!
	elif [ -f /proc/net/ip_input ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr A-Z a-z`
		if [ "$LOGBLOCKS" = "-l" ]; then LOGBLOCKS="-o" ; fi

		if [ -f /proc/sys/net/ipv4/ip_forward ]; then
			if [ "`cat /proc/sys/net/ipv4/ip_forward`" = "0" ]; then
				echo Please note that forwarding is disabled in the kernel. >/dev/stderr
				echo If this machine is expected to be a router, this should be fixed. >/dev/stderr
			fi
		fi

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipfwadm blockedhosts" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		if [ -n "$BLOCKEDHOSTS" ]; then
			echo -n Blockedhost blocks...
			for BLOCKEDHOST in $BLOCKEDHOSTS ; do
				/sbin/ipfwadm -I -i deny -S $BLOCKEDHOST $LOGBLOCKS
				/sbin/ipfwadm -O -i deny -S $BLOCKEDHOST $LOGBLOCKS
				/sbin/ipfwadm -I -i deny -D $BLOCKEDHOST $LOGBLOCKS
				/sbin/ipfwadm -O -i deny -D $BLOCKEDHOST $LOGBLOCKS
			done
		else
			echo -n No Blockedhost blocks...
		fi

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipfwadm noleakrfc1918" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		#This is a construction issue only; if rfc1918 packets leak through as the firewall is being constructed, 
		#we deny them to tell the sending end to try again.  Once the forward/MASQ rules are in place, 
		#this won't be used again.
		if [ -n "$AUTOMASQIF" ]; then
			echo -n NoLeakRFC1918 blocks...
			for MASQIF in $AUTOMASQIF ; do		#Add this in if we reinstate marks on system rules, check below too.  ${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
				for RESNET in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 ; do
					/sbin/ipfwadm -O -i deny -W $MASQIF -S $RESNET
				done
			done
		else
			echo -n No NoLeakRFC1918 blocks...
		fi

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipfwadm noincoming" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		if [ -n "$NOINCOMING" ] && [ -n "$INCOMINGINTERFACES" ]; then
			echo -n Incoming blocks...
			for OUTSIDEIF in $INCOMINGINTERFACES ; do
				for BLOCKPROTO in $NOINCOMING ; do
					case $BLOCKPROTO in
					*/icmp|*/ICMP)	/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS				;;
					*/*)			/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS	;;
					*)				/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} $LOGBLOCKS							;;
					esac
				done
			done
		else
			echo -n No incoming blocks...
		fi

		set +e		#Turn off failure checking; Mason has no control over the final contents of these files.
		#echo -n System rules...
		#. $SYSTEMRULEFILE
		#
		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipfwadm baserules" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		echo -n Fixed rules...
		. $BASERULEFILE
		set -e

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipfwadm policy" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		for ACHAIN in I O F ; do
			/sbin/ipfwadm -$ACHAIN -p $DEFAULTPOLICY
		done
		echo Done!
	else
		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: neither supported" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		echo This kernel supports neither ipchains nor ipfwadm! >/dev/stderr
	fi
	CKPTRUNSTANDARDFIREWALL=""
} #End of runstandardfirewall



#-------------------------------------------------------------------------
# serverportrange subroutine, tries to determine whether the given numeric
# port and protocol specify a server port.  If so, returns the appropriate
# readable representation for that server and sets the comment.
# If no corresponding server port is known, both are left blank.
#-------------------------------------------------------------------------
serverportrange () {
#Params: numeric port, proto
	CKPTSERVERPORTRANGE=" serverportrange: port $1 proto $2" ; #ckpt $CKPTSERVERPORTRANGE
	PARTIALCOMMENT="" ; READABLEPORT=""

	if isdigits "$1" ; then
		SERVICE="`grep "$1/$2" $SERVICES | head -n 1 | awk '{print $1}'`"
		#Mason will not be manipulating /etc/services.
		#SERVICELINE="`grep "$1/$2" $SERVICES | head -n 1`"
		#if [ `grep "$1/$2" /etc/services | wc -l` -eq 0 ]; then	#Merge line from additional services files to /etc/services if necessary
		#	if [ -n "$SERVICELINE" ]; then
		#		echo -e "$SERVICELINE ##(added by Mason)" >>/etc/services
		#	fi
		#fi

		#if #registered in sunrpc
			#process sunrpc port, change following to elif
		if [ "$2" = "udp" ] && [ $1 -ge $TRACEROUTE_BEGIN ] && [ $1 -le $TRACEROUTE_END ]; then
			READABLEPORT="$TRACEROUTE_BEGIN:$TRACEROUTE_END" ;		PARTIALCOMMENT="TRACEROUTE/$PROTO"
		elif [ "$2" = "udp" ] && [ $1 -ge 6970 ] && [ $1 -le 7170 ]; then
			READABLEPORT="6970:7170" ;								PARTIALCOMMENT="RADATA/$PROTO"
		elif [ "$2" = "udp" ] && [ $1 -ge 6770 ] && [ $1 -le 7170 ]; then
			READABLEPORT="6770:7170" ;								PARTIALCOMMENT="RA30DATA/$PROTO"
		elif [ "$2" = "tcp" ] && [ $1 -ge $X_BEGIN ] && [ $1 -le $X_END ]; then
			READABLEPORT="$X_BEGIN:$X_END" ;						PARTIALCOMMENT="X/$PROTO"
		elif [ "$2" = "tcp" ] && [ $1 -ge $OPENWIN_BEGIN ] && [ $1 -le $OPENWIN_END ]; then
			READABLEPORT="$OPENWIN_BEGIN:$OPENWIN_END" ;			PARTIALCOMMENT="OPENWIN/$PROTO"
		elif [ "$2" = "tcp" ] && [ $1 -ge $VNCJAVA_BEGIN ] && [ $1 -le $VNCJAVA_END ]; then
			READABLEPORT="$VNCJAVA_BEGIN:$VNCJAVA_END" ;			PARTIALCOMMENT="VNCJAVA/$PROTO"
		elif [ "$2" = "tcp" ] && [ $1 -ge $VNC_BEGIN ] && [ $1 -le $VNC_END ]; then
			READABLEPORT="$VNC_BEGIN:$VNC_END" ;					PARTIALCOMMENT="VNC/$PROTO"
		elif [ "$2" = "tcp" ] && [ $1 -ge $IRC_BEGIN ] && [ $1 -le $IRC_END ]; then
			READABLEPORT="$IRC_BEGIN:$IRC_END" ;					PARTIALCOMMENT="IRC/$PROTO"

		elif [ -n "$SERVICE" ]; then
			if [ "$ECHOCOMMAND" != "ipchains-save" ]; then
				READABLEPORT=$SERVICE ;								PARTIALCOMMENT="$SERVICE/$PROTO"
			else
				READABLEPORT=$1 ;									PARTIALCOMMENT="$SERVICE/$PROTO"
			fi
		fi
		CKPTSERVERPORTRANGE=" serverportrange: isdigits $READABLEPORT $PARTIALCOMMENT" ; #ckpt $CKPTSERVERPORTRANGE
	elif [ -n "`grep -E $1 /etc/services`" ]; then		# $1 is already converted to text and a server port
		#egrep "^$1[[:space:]]+[0-9]+/$2"
		READABLEPORT=$1											PARTIALCOMMENT="$1/$PROTO"
		CKPTSERVERPORTRANGE=" serverportrange: isname $READABLEPORT $PARTIALCOMMENT" ; #ckpt $CKPTSERVERPORTRANGE
#handle special server port ranges like the above
	elif [ "$2" = "udp" ] && [ "$1" = "$TRACEROUTE_BEGIN:$TRACEROUTE_END" ]; then
		READABLEPORT="$TRACEROUTE_BEGIN:$TRACEROUTE_END" ;		PARTIALCOMMENT="TRACEROUTE/$PROTO"
	elif [ "$2" = "udp" ] && [ "$1" = "6970:7170" ]; then
		READABLEPORT="6970:7170" ;								PARTIALCOMMENT="RADATA/$PROTO"
	elif [ "$2" = "udp" ] && [ "$1" = "6770:7170" ]; then
		READABLEPORT="6770:7170" ;								PARTIALCOMMENT="RA30DATA/$PROTO"
	elif [ "$2" = "tcp" ] && [ "$1" = "$X_BEGIN:$X_END" ]; then
		READABLEPORT="$X_BEGIN:$X_END" ;						PARTIALCOMMENT="X/$PROTO"
		CKPTSERVERPORTRANGE=" serverportrange: setting to X" ; #ckpt $CKPTSERVERPORTRANGE
	elif [ "$2" = "tcp" ] && [ "$1" = "$OPENWIN_BEGIN:$OPENWIN_END" ]; then
		READABLEPORT="$OPENWIN_BEGIN:$OPENWIN_END" ;			PARTIALCOMMENT="OPENWIN/$PROTO"
	elif [ "$2" = "tcp" ] && [ "$1" = "$VNCJAVA_BEGIN:$VNCJAVA_END" ]; then
		READABLEPORT="$VNCJAVA_BEGIN:$VNCJAVA_END" ;			PARTIALCOMMENT="VNCJAVA/$PROTO"
	elif [ "$2" = "tcp" ] && [ "$1" = "$VNC_BEGIN:$VNC_END" ]; then
		READABLEPORT="$VNC_BEGIN:$VNC_END" ;					PARTIALCOMMENT="VNC/$PROTO"
	elif [ "$2" = "tcp" ] && [ "$1" = "$IRC_BEGIN:$IRC_END" ]; then
		READABLEPORT="$IRC_BEGIN:$IRC_END" ;					PARTIALCOMMENT="IRC/$PROTO"
	elif [ "$2" = "tcp" ] && [ "$1" = "512:514" ]; then
		READABLEPORT="512:514" ;								PARTIALCOMMENT="R-COMMANDS/$PROTO"
	else
		CKPTSERVERPORTRANGE=" serverportrange: neither $1 $2" ; #ckpt $CKPTSERVERPORTRANGE
	fi
	#echo $READABLEPORT		#Can't do this because we need to return PARTIALCOMMENT as well.
	CKPTSERVERPORTRANGE=""
} #end of serverportrange


#-------------------------------------------------------------------------
# sigexitscript function, called on receipt of SIGHUP
#-------------------------------------------------------------------------
sigexitscript () {
	if [ "$NEEDLF" = "YES" ]; then echo >/dev/stderr ; NEEDLF="NO" ; fi
	echo Received HUP signal, exiting at next pass >/dev/stderr
	EXITMASON="YES"
} #End of sigexitscript


#-------------------------------------------------------------------------
# settos subroutine, sets the TOS variable for the given port, port range, and protocol.
#-------------------------------------------------------------------------
#params: port, port range, protocol
settos () {
	CKPTSETTOS=" settos: Start" ; #ckpt $CKPTSETTOS
	if [ "$INFORMAT" != "ipchains-lv" ]; then
		#http://www.cis.ohio-state.edu/htbin/rfc/rfc1349.html, esp. Appendix 2
		#I generally follow what's in the IPCHAINS-Howto and RFC 1349 (with the exception of SMTP), and 
		#chose to put pop3 and imap in the minimize cost category and web as maximize throughput.
		#I would truly welcome any dialog, public or private, on whether the following set of 
		#TOS settings is appropriate for a general purpose firewall.
		TOS=""
		#I specifically do _not_ test for what policy is being used.  Even if the policy is currently
		#reject or deny, the user might change it to accept later in the rule file, in which case the TOS flag should be set.
		case "$2/$3" in
		"$IRC_BEGIN:$IRC_END/tcp")		TOS=" -t 0x01 0x10"	;;	#IRC				Minimize delay
		esac
		case "$1/$3" in
		"21/tcp")						TOS=" -t 0x01 0x10"	;;	#FTP				Minimize delay
		"23/tcp"|"22/tcp"|"513/tcp")	TOS=" -t 0x01 0x10"	;;	#Telnet,SSH,rlogin	Minimize delay
		"53/udp")						TOS=" -t 0x01 0x10"	;;	#dns				Minimize delay
		"69/udp")						TOS=" -t 0x01 0x10"	;;	#tftp				Minimize delay
		"20/tcp"|"25/tcp")				TOS=" -t 0x01 0x08"	;;	#FTP-data,SMTP		Maximize throughput
		"53/tcp")						TOS=" -t 0x01 0x08"	;;	#DNS zone transfer	Maximize throughput
		"80/tcp"|"443/tcp"|"563/tcp")	TOS=" -t 0x01 0x08"	;;	#Web & secure web	Maximize throughput
		"8080/tcp"|"3128/tcp")			TOS=" -t 0x01 0x08"	;;	#Web Caches			Maximize throughput
		"161/udp")						TOS=" -t 0x01 0x04"	;;	#SNMP				Maximize reliability
		"119/tcp"|"110/tcp"|"143/tcp")	TOS=" -t 0x01 0x02"	;;	#NNTP,POP3,IMAP		Minimize cost
		esac
	fi

	if [ "$ECHOCOMMAND" = "cisco" ]; then
		case "$TOS" in
		" -t 0x01 0x02")	TOS=" min-monetary-cost"		;;
		" -t 0x01 0x04")	TOS=" max-reliability"			;;
		" -t 0x01 0x08")	TOS=" max-throughput"			;;
		" -t 0x01 0x10")	TOS=" min-delay"				;;
		esac
	elif [ "$ECHOCOMMAND" = "ipchains-save" ]; then
		case "$TOS" in
		" -t 0x01 0x02")	TOS=" -t 01 02"					;;
		" -t 0x01 0x04")	TOS=" -t 01 04"					;;
		" -t 0x01 0x08")	TOS=" -t 01 08"					;;
		" -t 0x01 0x10")	TOS=" -t 01 10"					;;
		esac
	fi
	CKPTSETTOS=""
} #End of settos


#-------------------------------------------------------------------------
# sortrulefile procedure, sorts a rulefile so that the rules that process the most packets are at the top.
#-------------------------------------------------------------------------
sortrulefile () {
#Params: $1 is the filespec for the files that need to be sorted by counts.
	CKPTSORTRULEFILE=" sortrulefile: Start" ; #ckpt $CKPTSORTRULEFILE
	for ONEFILE in $1 ; do
		echo -n Adding counts and sorting $ONEFILE...
		LASTRULETAG=""
		FILECOUNT="0" ; if [ -f $ONEFILE.0 ]; then rm -f $ONEFILE.0 ; fi
		CKPTSORTRULEFILE=" sortrulefile: addcounts" ; #ckpt $CKPTSORTRULEFILE
		addcounts $ONEFILE
#Break up input file into sections that can safely be sorted
		#Redirect stdin to work around an f^@&ing annoying limitation in the read command.
		CKPTSORTRULEFILE=" sortrulefile: split into equivalent sections." ; #ckpt $CKPTSORTRULEFILE
		exec 5<&0 < "$ONEFILE"
		while read ONELINE ; do
			NEWRULETAG="`ruletag $ONELINE`"
			if [ "$NEWRULETAG" != "$LASTRULETAG" ]; then
				FILECOUNT=$[ $FILECOUNT + 1 ]
				if [ -f $ONEFILE.$FILECOUNT ]; then rm -f $ONEFILE.$FILECOUNT ; fi
			fi
			echo "$ONELINE" >>$ONEFILE.$FILECOUNT
			LASTRULETAG="$NEWRULETAG"
		done
		exec 0<&5 5<&-
#Sort the sections that need it and re-assemble $ONEFILE
		CKPTSORTRULEFILE=" sortrulefile: reassemble" ; #ckpt $CKPTSORTRULEFILE
		rm -f $ONEFILE.new
		for SECTION in `seq 0 $FILECOUNT` ; do
			if [ -f "$ONEFILE.$SECTION" ]; then
				if [ `grep '#\^' $ONEFILE.$SECTION | wc -l` -gt 0 ]; then
					sort -t '^' +1 -n -r $ONEFILE.$SECTION >>$ONEFILE.new
				else
					cat $ONEFILE.$SECTION >>$ONEFILE.new
				fi
				rm -f $ONEFILE.$SECTION
			fi
		done
		cat $ONEFILE.new >$ONEFILE ; rm -f $ONEFILE.new
	done
	echo Done!
	CKPTSORTRULEFILE=""
} #End of sortrulefile


#-------------------------------------------------------------------------
# uniqrulefile subroutine, sorts the given file and removes duplicates.
#-------------------------------------------------------------------------
uniqrulefile () {
#params: $1: filename of file to sort
#	This one takes a little explanation.  I want to sort by the text after the first #, grouping similar rules
#next to each other so that uniq can remove duplicates.  Normally, sort -t '#' +1 $1 | uniq >$1.sorted 
#would do the trick.
#	Because we may have mark values on the lines, I have to convince uniq to ignore the mark values when 
#deciding whether adjacent lines are uniq.  The only way I see to do that is to:
#- add a fake field at the beginning of each line.  Make it !!! at first.  If the line has a mark value, 
#replace the !!! with the mark value and leave a placeholder ("ZzMaRkZz") in the mark value's place.
#- sort and uniq as above, but use "-1" to skip over the first field.
#- for each line with the placeholder, move the first field (the mark value) back to replace the placeholder.
#- for any remaining lines with the bogus "!!!", remove it.
#	Elegant?  no.  Functional?  Yes.

	CKPTUNIQRULEFILE=" uniqrulefile: delcounts" ; #ckpt $CKPTUNIQRULEFILE
	delcounts $1
	cp -pf $1 $1.bak
	#sort -t '#' +1 $1 | uniq >$1.sorted			#This worked until we had mark values.
	CKPTUNIQRULEFILE=" uniqrulefile: main pipeline" ; #ckpt $CKPTUNIQRULEFILE
	cat $1 | \
	sed -e 's/^/!!! /' \
		-e 's/^!!! \(.* -m \)\([0-9][0-9]*\)\( .*\)/\2 \1ZzMaRkZz\3/' | \
	sort -t '#' +1 | \
	uniq -1 | \
	sed -e 's/^\([0-9][0-9]*\) \(.* -m \)ZzMaRkZz\( .*\)/\2\1\3/' \
		-e 's/^!!! //' >$1.sorted
	cat $1.sorted >$1			#This preserves the permissions of fwrules
	rm -f $1.sorted
	if [ "$SORTMODE" = "PACKETCOUNTS" ]; then
		CKPTUNIQRULEFILE=" uniqrulefile: sortrulefile" ; #ckpt $CKPTUNIQRULEFILE
		sortrulefile $1
	fi
	CKPTUNIQRULEFILE=""
} #End of uniqrulefile




