#!/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?
#A="`echo | tr '\012' '\001' `"	#Produces a Ctrl-A unlikely to exist in normal text
#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.
#FIXME - replace true with : .

MASONVER="0.13.0, final release 2, 8/12/99"

#-------------------------------------------------------------------------
# addcounts procedure, adds the packet counts to the rules in a file.
#-------------------------------------------------------------------------
addcounts () {
#Params: $* is/are the filespec(s) for the files that need counts added.
	CKPTADDCOUNTS=" addcounts: Start $*" ; #ckpt $CKPTADDCOUNTS
	if [ -f /proc/net/ip_fwchains ] && [ "$SORTMODE" = "PACKETCOUNTS" ]; then		#We can only match up counts to rules if we have mark values, i.e. ipchains.
		updatecounts
		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 `sed -e 's@ 0x@/0x@' $PACKETCOUNTFILE | 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.  The /../ at the beginning tells sed to only apply this substitution to lines matching this pattern.
					ADDCOUNTSCRIPT="$ADDCOUNTSCRIPT -e /-m[[:space:]]${ONECOUNT##*/}/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 /-m[[:space:]]$[${ONECOUNT##*/}]/s@^\(.*[[:space:]]-m[[:space:]]$[${ONECOUNT##*/}][[:space:]].*\)@\1SpAcE#^SpAcE${ONECOUNT%%/*}SpAcE@"
				fi
			done
			CKPTADDCOUNTS=" addcounts: script created, processing files" ; #ckpt $CKPTADDCOUNTS
			for ONEFILE in $* ; do
				DUPMARKS=`grep '[[:space:]]-m[[:space:]]' $ONEFILE | sed -e 's/^.*[[:space:]]-m[[:space:]]*\([x0-9]*\).*$/\1/' | uniq -d`
				if [ -n "$DUPMARKS" ]; then
					echo Warning - the following marks are used more than once in $ONEFILE: >/dev/stderr
					for ONEMARK in $DUPMARKS ; do
						case $ONEMARK in
						0x*)	echo -n "$ONEMARK = $[ $ONEMARK ]   " >/dev/stderr	;;
						*)		echo -n "$ONEMARK  " >/dev/stderr					;;
						esac
					done
					echo >/dev/stderr
					echo This will give incorrect packet counts. >/dev/stderr
				fi
				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
	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 ip and netmask.
#-------------------------------------------------------------------------
broadcastof () {
#The broadcast is (ip bitwise-or (255.255.255.255-netmask))
	CKPTBROADCASTOF=" broadcastof: Start $1 mask $2" ; #ckpt $CKPTBROADCASTOF

	case $2 in
	32|255.255.255.255)	echo $1									;;
	0|0.0.0.0)			echo 255.255.255.255					;;
	*)
		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) ]
																;;
	esac

	CKPTBROADCASTOF=""
} #End of broadcastof


#-------------------------------------------------------------------------
#After loading /etc/masonrc, this procedure puts sane values in for everything.
#-------------------------------------------------------------------------
checkconf () {
	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
	PACKETCOUNTFILE=${PACKETCOUNTFILE:-"${MASONDIR}packetcounts"} ;	if [ ! -f $PACKETCOUNTFILE ]; then touch $PACKETCOUNTFILE ; fi
	#SYSTEMRULEFILE=${SYSTEMRULEFILE:-"${MASONDIR}systemrules"} ;	if [ ! -f $SYSTEMRULEFILE ]; then touch $SYSTEMRULEFILE ; fi
	PACKETLOGFILE=${PACKETLOGFILE:-"/var/log/messages"}
	MASONEXE=${MASONEXE:-"/usr/bin/mason"}
	if [ ! -d /var/run ]; then mkdir --parents /var/run ; fi
	MASONPIDFILE=${MASONPIDFILE:-"/var/run/mason.pid"}
	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"}
	DEBUG=${DEBUG:-"NO"}
	BLOCKEDHOSTS=${BLOCKEDHOSTS:-""}
	DYNIF=${DYNIF:-""}
	AUTOMASQIF=${AUTOMASQIF:-""}
	SSP=${SSP:-""}
	SCP=${SCP:-""}
	NOINCOMING=${NOINCOMING:-""}
	NOOUTGOING=${NOOUTGOING:-""}
	VERBOSE=${VERBOSE:-"YES"}

	INCOMINGINTERFACES=${INCOMINGINTERFACES:-`/sbin/route -n | grep '^0\.0\.0\.0[ \t]' | awk '{print $8}' | sort | uniq`}
	OUTGOINGINTERFACES=${OUTGOINGINTERFACES:-`/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  || true
			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 || true
			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
	CKPTCHECKCONF=" checkconf: Post default policy" ; #ckpt $CKPTCHECKCONF

	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

	CKPTCHECKCONF=" checkconf: pre docommand" ; #ckpt $CKPTCHECKCONF
	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 $DOBEEP in
	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee])								DOBEEP="YES"			;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee]|[Ff][Aa][Ll][Ss][Ee])				DOBEEP="NO"				;;
	*)															DOBEEP="YES"			;;
	esac

	case $SPOOFBLOCKS in
	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee])
		SPOOFBLOCKS="YES"
		if routesoverlap ; then
			echo Warning! - Spoof blocking has been requested, but the following entries >/dev/stderr
			echo in your routing table overlap and point to different interfaces: >/dev/stderr
			echo $OVERLAPPINGROUTES >/dev/stderr
			echo Continuing, but communication from machines in the overlapping portion >/dev/stderr
			echo will be disrupted. >/dev/stderr
			sleep 20
		fi
																						;;
	[Nn][Oo]|[Nn][Oo][Nn][Ee]|[Ff][Aa][Ll][Ss][Ee])				SPOOFBLOCKS="NO"		;;
	*)
		if routesoverlap ; then
			SPOOFBLOCKS="NO"
		else
			SPOOFBLOCKS="YES"
		fi
																						;;
	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
	if ! type -path host >/dev/null 2>/dev/null ; then
		if [ "$HOSTLOOKUP" = "FULL" ]; then
			echo The \"host\" utility is not available for resolving IP addresses into >/dev/stderr
			echo hostnames.  Until this is available, Mason will only use /etc/hosts >/dev/stderr
			echo for resolution.  This warning can be disabled by setting >/dev/stderr
			echo HOSTLOOKUP=\"FILESONLY\"  in /etc/masonrc . >/dev/stderr
			HOSTLOOKUP="FILESONLY"
		fi
	fi

	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

	case $DYNIFMODE in
	[Aa][Nn][Yy][Aa][Dd][Dd][Rr][Ee][Ss][Ss])					DYNIFMODE="ANYADDRESS"	;;
	[Ss][Mm][Aa][Ll][Ll][Ee][Ss][Tt][Rr][Aa][Nn][Gg][Ee])		DYNIFMODE="SMALLESTRANGE"	;;
	[Ss][Pp][Ee][Cc][Ii][Ff][Ii][Cc][Ii][Pp])					DYNIFMODE="SPECIFICIP"	;;
	*)															DYNIFMODE="SMALLESTRANGE"	;;
	esac


	CKPTCHECKCONF=" checkconf: Check networks" ; #ckpt $CKPTCHECKCONF
	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 ports" ; #ckpt $CKPTCHECKCONF

	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 "$DYNIF" ]; then 			DYNIF=`echo "$DYNIF" | tr ' ' '\012' | sort | uniq` ;						fi
	if [ -n "$NOINCOMING" ]; then		NOINCOMING=`echo "$NOINCOMING" | tr ' ' '\012' | sort | uniq` ;				fi
	if [ -n "$NOOUTGOING" ]; then		NOOUTGOING=`echo "$NOOUTGOING" | 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

	#A misconstructed path will probably make the checks for basic utils and path fail; make sure the big 4 are in for these tests.
	PREMASONPATH=$PATH
	PATH="/sbin:/usr/sbin:/bin:/usr/bin:$PATH"

	MISSINGUTILS=""

	#I don't test for rm (it's an alias on rh), shell builtins, or ipfwadm, ipchains or host (we test for them later).
	#LSB compliant distributions provide all of the following except: bash(but sh is required), ifconfig, and route (ps?).
	for ONEUTIL in awk bash cat chmod cut grep head ifconfig mkdir ps route sed sleep sort tail touch tr true uniq wc ; do
		if ! type -path $ONEUTIL >/dev/null 2>/dev/null ; 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 try to get these before continuing. >/dev/stderr
		echo Press Ctrl-C to fix this, or wait 10 seconds if you want to >/dev/stderr
		echo try continuing anyways - cross your fingers. >/dev/stderr
		sleep 10
	fi

	#Now add in the main 4 bin/sbin path elements if missing.
	for ONEPATH in `set | grep '^PATH=' | sed -e 's/^PATH=/ /' -e 's/:/ /g'` ; do
		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
	PATH=$PREMASONPATH ; unset PREMASONPATH
	MISSINGPATH=""
	if [ "$USRBINOK" != "YES" ]; then	MISSINGPATH="/usr/bin:$MISSINGPATH" ;	fi
	if [ "$BINOK" != "YES" ]; then 		MISSINGPATH="/bin:$MISSINGPATH" ;		fi
	if [ "$USRSBINOK" != "YES" ]; then	MISSINGPATH="/usr/sbin:$MISSINGPATH" ;	fi
	if [ "$SBINOK" != "YES" ]; then		MISSINGPATH="/sbin:$MISSINGPATH" ;		fi
	if [ -n "$MISSINGPATH" ]; then
		export PATH="$MISSINGPATH$PATH"
		echo Note: The following directory/directories was/were not included >/dev/stderr
		echo in your PATH variable: \"$MISSINGPATH\" >/dev/stderr
	fi
	unset MISSINGPATH
	
	#Keep track of all IP's in use every time this is run.
	for ONEIF in `ifconfig | grep 'Link encap' | awk '{print $1}'` ; do
		NEWIP=`ifconfig $ONEIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`
		if [ ! -f $MASONDIR$ONEIF-ips ]; then touch $MASONDIR$ONEIF-ips ; fi
		if [ -z "`cat $MASONDIR$ONEIF-ips | grep ^$NEWIP\$`" ]; then
			echo $NEWIP >>$MASONDIR$ONEIF-ips
		fi
	done

	CKPTCHECKSYS=" checksys: Create logchains" ; #ckpt $CKPTCHECKSYS
	if [ "$DOCOMMAND" = "ipchains" ]; then
		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
		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 () {
	case "$1/$2" in
	0/*|echo-reply/*|pong/*)			COMMENT="$CMNT Echo reply/icmp ($DIRLETTER)"					;;
	3/0|network-unreachable/*)			COMMENT="$CMNT Net Unreach/icmp ($DIRLETTER)"					;;
	3/1|host-unreachable/*)				COMMENT="$CMNT Host Unreach/icmp ($DIRLETTER)"					;;
	3/2|protocol-unreachable/*)			COMMENT="$CMNT Protocol Unreach/icmp ($DIRLETTER)"				;;
	3/3|port-unreachable/*)				COMMENT="$CMNT Port Unreach/icmp ($DIRLETTER)"					;;
	3/4|fragmentation-needed/*)			COMMENT="$CMNT Frag Needed and DF Set/icmp ($DIRLETTER)"		;;
	3/5|source-route-failed/*)			COMMENT="$CMNT Source Route Failed/icmp ($DIRLETTER)"			;;
	3/6|network-unknown/*)				COMMENT="$CMNT Dest Net Unknown/icmp ($DIRLETTER)"				;;
	3/7|host-unknown/*)					COMMENT="$CMNT Dest Host Unknown/icmp ($DIRLETTER)"				;;
	3/8)								COMMENT="$CMNT Source Host Isolated/icmp ($DIRLETTER)"			;;
	3/9|network-prohibited/*)			COMMENT="$CMNT Comm with Dest Net Admin Prohib/icmp ($DIRLETTER)"	;;
	3/10|host-prohibited/*)				COMMENT="$CMNT Comm with Dest Host Admin Prohib/icmp ($DIRLETTER)"	;;
	3/11|TOS-network-unreachable/*)		COMMENT="$CMNT Dest Net Unreach for TOS/icmp ($DIRLETTER)"		;;
	3/12|TOS-host-unreachable/*)		COMMENT="$CMNT Dest Host Unreach for TOS/icmp ($DIRLETTER)"		;;
	3/13|communication-prohibited/*)	COMMENT="$CMNT Comm Admin Prohib/icmp ($DIRLETTER)"				;;
	3/14|host-precedence-violation/*)	COMMENT="$CMNT Host Precedence Violation/icmp ($DIRLETTER)"		;;
	3/15|precedence-cutoff/*)			COMMENT="$CMNT Precedence cutoff in effect/icmp ($DIRLETTER)"	;;
	3/*|destination-unreachable)		COMMENT="$CMNT Dest Unreach/icmp ($DIRLETTER)"					;;
	4/*|source-quench/*)				COMMENT="$CMNT Source Quench/icmp ($DIRLETTER)"					;;
	5/0|network-redirect/*)				COMMENT="$CMNT Redir Datagram for (sub)Net/icmp ($DIRLETTER)"	;;
	5/1|host-redirect/*)				COMMENT="$CMNT Redir Datagram for Host/icmp ($DIRLETTER)"		;;
	5/2|TOS-network-redirect/*)			COMMENT="$CMNT Redir Datagram for TOS and Net/icmp ($DIRLETTER)"	;;
	5/3|TOS-host-redirect/*)			COMMENT="$CMNT Redir Datagram for TOS and Host/icmp ($DIRLETTER)"	;;
	5/*|redirect/*)						COMMENT="$CMNT Redirect/icmp ($DIRLETTER)"						;;
	6/*)								COMMENT="$CMNT Alt host address/icmp ($DIRLETTER)"				;;
	8/*|echo-request/*|ping/*)			COMMENT="$CMNT Echo req/icmp ($DIRLETTER)"						;;
	9/*|router-advertisement/*)			COMMENT="$CMNT Router Advertisement/icmp ($DIRLETTER)"			;;
	10/*|router-solicitation/*)			COMMENT="$CMNT Router Selection/icmp ($DIRLETTER)"				;;
	11/0|ttl-zero-during-transit/*)		COMMENT="$CMNT TTL exceeded in Transit/icmp ($DIRLETTER)"		;;
	11/1|ttl-zero-during-reassembly/*)	COMMENT="$CMNT Frag Reassembly Time Exceeded/icmp ($DIRLETTER)"	;;
	11/*|time-exceeded/*|ttl-exceeded/*)	COMMENT="$CMNT Time exceeded/icmp ($DIRLETTER)"					;;
#FIXME is ip-header-bad a 12/0 (prob) or 12/2?
	12/0)								COMMENT="$CMNT Pointer indicates error/icmp ($DIRLETTER)"		;;
	12/1|required-option-missing/*)		COMMENT="$CMNT Missing Required Option/icmp ($DIRLETTER)"		;;
	12/2)								COMMENT="$CMNT Bad Length/icmp ($DIRLETTER)"					;;
	12/*|parameter-problem/*)			COMMENT="$CMNT Parameter prob/icmp ($DIRLETTER)"				;;
	13/*|timestamp-request/*)			COMMENT="$CMNT Timestamp req/icmp ($DIRLETTER)"					;;
	14/*|timestamp-reply/*)				COMMENT="$CMNT Timestamp reply/icmp ($DIRLETTER)"				;;
	15/*)								COMMENT="$CMNT Info req/icmp ($DIRLETTER)"						;;
	16/*)								COMMENT="$CMNT Info reply/icmp ($DIRLETTER)"					;;
	17/*|address-mask-request/*)		COMMENT="$CMNT Addr Mask req/icmp ($DIRLETTER)"					;;
	18/*|address-mask-reply/*)			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


#-------------------------------------------------------------------------
# encompassingnetworkof function, returns the smallest network that includes
# all of the given ip's.  There must be at least one parameter.
# Please hand in only straight IP's; to include a network in the calculation,
# hand in: `networkof $NET $NETMASK` `broadcastof $NET $NETMASK`
#-------------------------------------------------------------------------
encompassingnetworkof () {
	CKPTENCOMPASSINGNETWORKOF=" encompassingnetworkof: Start, ips: $*" ; #ckpt $CKPTENCOMPASSINGNETWORKOF

	case $# in
	0)	:														;;
	1)	echo "$1/32"											;;
	*)
		MINIP=$1	; MAXIP=$1
		shift
		for ONEIP in $* ; do
			if iplt $ONEIP $MINIP ; then MINIP=$ONEIP ; fi
			if iplt $MAXIP $ONEIP ; then MAXIP=$ONEIP ; fi
		done

		ENONUMBITS=32
		ENONETMASK=255.255.255.255
		ENONETWORK=$MINIP
		ENOBROADCAST=$MINIP

		while [ $ENONUMBITS -gt 0 ] && iplt $ENOBROADCAST $MAXIP ; do
			ENONUMBITS=$[ $ENONUMBITS - 1 ]
			ENONETMASK=`bits2mask $ENONUMBITS`
			ENONETWORK=`networkof $MINIP $ENONETMASK`
			ENOBROADCAST=`broadcastof $MINIP $ENONETMASK`
		done
		if [ "$ENONETWORK/$ENONUMBITS" = "0.0.0.0/0" ]; then ENONETWORK="0" ; fi
		echo "$ENONETWORK/$ENONUMBITS"
																;;
	esac
	CKPTENCOMPASSINGNETWORKOF=""
} #End of encompassingnetworkof


#-------------------------------------------------------------------------
#Flush the existing rules so we start with a clean slate.
#-------------------------------------------------------------------------
flushfirewall () {
	CKPTFLUSHFIREWALL=" flushfirewall: Start" ; #ckpt $CKPTFLUSHFIREWALL
	if [ -f /proc/net/ip_fwchains ]; then
		updatecounts
		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


#-------------------------------------------------------------------------
# generalportrange function, returns the masq/high/low port range of the given port.
#-------------------------------------------------------------------------
generalportrange () {
#We have already tested for isdigits
	if [ $1 -ge 0 ] && [ $1 -le 1023 ]; then								echo "0:1023"
	elif [ $1 -ge "$PORT_MASQ_BEGIN" ] && [ $1 -le "$PORT_MASQ_END" ]; then	echo "$PORT_MASQ_BEGIN:$PORT_MASQ_END"
	elif [ $1 -ge "1024" ] && [ $1 -le "65535" ]; then						echo "1024:65535"
	fi
} #End of generalportrange


#-------------------------------------------------------------------------
# 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"						;;
	22[4-9].*|23[0-9].*)	GIRETVAL="`nameof $1`$SINGLEMACHSPEC"		;;	#Multicast IP's should be left unique
	*)
		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 gt >/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	CKPTIPLE="" ; return 0
	elif [ $I1O1 -gt $I2O1 ]; then	CKPTIPLE="" ; return 1
	elif [ $I1O2 -lt $I2O2 ]; then	CKPTIPLE="" ; return 0
	elif [ $I1O2 -gt $I2O2 ]; then	CKPTIPLE="" ; return 1
	elif [ $I1O3 -lt $I2O3 ]; then	CKPTIPLE="" ; return 0
	elif [ $I1O3 -gt $I2O3 ]; then	CKPTIPLE="" ; return 1
	elif [ $I1O4 -lt $I2O4 ]; then	CKPTIPLE="" ; return 0
	elif [ $I1O4 -gt $I2O4 ]; then	CKPTIPLE="" ; return 1
	else							CKPTIPLE="" ; return 0
	fi
} #End of iple


#-------------------------------------------------------------------------
# iplt function, returns true (0) if first IP < second IP, else false(1)
#-------------------------------------------------------------------------
iplt () {
#if iplt 128.2.3.4 127.0.0.1 ; then echo less than >/dev/stderr ; else echo ge >/dev/stderr ; fi
	CKPTIPLT=" iplt: start, addresses $1 and $2" ; #ckpt $CKPTIPLT
	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	CKPTIPLT="" ; return 0
	elif [ $I1O1 -gt $I2O1 ]; then	CKPTIPLT="" ; return 1
	elif [ $I1O2 -lt $I2O2 ]; then	CKPTIPLT="" ; return 0
	elif [ $I1O2 -gt $I2O2 ]; then	CKPTIPLT="" ; return 1
	elif [ $I1O3 -lt $I2O3 ]; then	CKPTIPLT="" ; return 0
	elif [ $I1O3 -gt $I2O3 ]; then	CKPTIPLT="" ; return 1
	elif [ $I1O4 -lt $I2O4 ]; then	CKPTIPLT="" ; return 0
	elif [ $I1O4 -gt $I2O4 ]; then	CKPTIPLT="" ; return 1
	else							CKPTIPLT="" ; return 1
	fi
} #End of iplt


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



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

	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])	:								;;
	*)													CKPTISNUMERICIP="" ; return 1	;;
	esac
	case $I1O2 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:								;;
	*)													CKPTISNUMERICIP="" ; return 1	;;
	esac
	case $I1O3 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:								;;
	*)													CKPTISNUMERICIP="" ; return 1	;;
	esac
	case $I1O4 in
	[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])	:								;;
	*)													CKPTISNUMERICIP="" ; return 1	;;
	esac

	CKPTISNUMERICIP="" ; return 0
} #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
			#The () subshell below is the equivalent of: "tail --lines=1 | awk '{print $2}'"
			ONEHOSTNAME=`egrep "^$NAMEOFINPUT[^0-9]" /etc/hosts | ( while read F1 F2 FREST ; do LLF2=$F2 ; done ; if [ -n "$LLF2" ]; then echo $LLF2 ; fi )`
			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


#-------------------------------------------------------------------------
# networkof function, returns the network of the given ip and netmask.
#-------------------------------------------------------------------------
networkof () {
#Basically, the network is (ip bitwise-and netmask)
	CKPTNETWORKOF=" networkof: Start $1 mask $2" ; #ckpt $CKPTNETWORKOF

	case $2 in
	32|255.255.255.255)	echo $1									;;
	0|0.0.0.0)			echo 0.0.0.0							;;
	*)
		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 & $I2O1 ].$[ $I1O2 & $I2O2 ].$[ $I1O3 & $I2O3 ].$[ $I1O4 & $I2O4 ]
																;;
	esac
	CKPTNETWORKOF=""
} #End of networkof


#-------------------------------------------------------------------------
# networksoverlap function, returns true (0) if the two param networks overlap, false otherwise.
#-------------------------------------------------------------------------
networksoverlap () {
	N1NET=`networkof ${1%%/*} ${1##*/}` ;	N1BROAD=`broadcastof ${1%%/*} ${1##*/}`
	N2NET=`networkof ${2%%/*} ${2##*/}` ;	N2BROAD=`broadcastof ${2%%/*} ${2##*/}`

	  if iple $N2NET $N1NET &&		iple $N1NET $N2BROAD ; then		return 0	#N1NET inside N2?
	elif iple $N2NET $N1BROAD &&	iple $N1BROAD $N2BROAD ; then	return 0	#N1BROAD inside N2?
	elif iple $N1NET $N2NET &&		iple $N2NET $N1BROAD ; then		return 0	#N2NET inside N1?
	elif iple $N1NET $N2BROAD &&	iple $N2BROAD $N1BROAD ; then	return 0	#N2BROAD inside N1?
	fi
	return 1	#False
} #End of networksoverlap


#-------------------------------------------------------------------------
# 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 () {
	if [ -n "$CKPTMGT$CKPTMASON$CKPTCHECKSYS$CKPTCLIENTPORTRANGE$CKPTGENERALIZEIP$CKPTIPLE$CKPTIPLT$CKPTISNUMERICIP$CKPTLOADCONF$CKPTSERVERPORTRANGE$CKPTADDCOUNTS$CKPTNAMEOF$CKPTBROADCASTOF$CKPTCHECKCONF$CKPTDELCOUNTS$CKPTFLUSHFIREWALL$CKPTPORT2CISCOPORT$CKPTPROTONUM2NAME$CKPTRULETAG$CKPTRUNLEARNFIREWALL$CKPTRUNSTANDARDFIREWALL$CKPTSETTOS$CKPTSORTRULEFILE$CKPTUNIQRULEFILE$CKPTUPDATECOUNTS$CKPTNETWORKOF" ]; then
		if [ -z "$MASONDIR" ]; then MASONDIR="/var/lib/mason/" ; fi
		echo																	>/dev/stderr
		echo Abnormal exit from $0 $MASONVER.									>/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 $CKPTIPLT $CKPTISNUMERICIP $CKPTLOADCONF \
		 $CKPTSERVERPORTRANGE $CKPTADDCOUNTS $CKPTNAMEOF $CKPTBROADCASTOF \
		 $CKPTCHECKCONF $CKPTDELCOUNTS $CKPTFLUSHFIREWALL $CKPTPORT2CISCOPORT \
		 $CKPTPROTONUM2NAME $CKPTRULETAG $CKPTRUNLEARNFIREWALL \
		 $CKPTRUNSTANDARDFIREWALL $CKPTSETTOS $CKPTSORTRULEFILE \
		 $CKPTUNIQRULEFILE $CKPTUPDATECOUNTS $CKPTNETWORKOF						>/dev/stderr
		echo End of checkpoints.												>/dev/stderr
		echo																	>/dev/stderr
		echo This file was created as a result of a crash of $0 $MASONVER.		>>${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 $CKPTIPLT $CKPTISNUMERICIP $CKPTLOADCONF \
		 $CKPTSERVERPORTRANGE $CKPTADDCOUNTS $CKPTNAMEOF $CKPTBROADCASTOF \
		 $CKPTCHECKCONF $CKPTDELCOUNTS $CKPTFLUSHFIREWALL $CKPTPORT2CISCOPORT \
		 $CKPTPROTONUM2NAME $CKPTRULETAG $CKPTRUNLEARNFIREWALL \
		 $CKPTRUNSTANDARDFIREWALL $CKPTSETTOS $CKPTSORTRULEFILE \
		 $CKPTUNIQRULEFILE $CKPTUPDATECOUNTS $CKPTNETWORKOF						>>${MASONDIR}masoncrash
		echo End of checkpoints.												>>${MASONDIR}masoncrash
		echo																	>>${MASONDIR}masoncrash
		if [ -n "$MASONCONF" ]; then
			if [ -e "$MASONCONF" ]; then
				echo Masonconf:													>>${MASONDIR}masoncrash
				if type -path sed >/dev/null 2>/dev/null && type -path grep >/dev/null 2>/dev/null ; then
					cat $MASONCONF | sed -e 's/#.*//' | grep -v '^$'			>>${MASONDIR}masoncrash
				else
					cat $MASONCONF												>>${MASONDIR}masoncrash
				fi
				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
		echo System details:													>>${MASONDIR}masoncrash
		for ONESYSFILE in /sbin/ipchains /sbin/ipfwadm /proc/net/ip_input /proc/net/ip_fwchains ; do
			ls -ald $ONESYSFILE 												>>${MASONDIR}masoncrash 2>&1 || /bin/true
		done
		mount -t proc 															>>${MASONDIR}masoncrash 2>&1 || /bin/true
		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|[Ii][Pp])				PROTO="ip"		IGNOREPORT="YES"				;;
	1|[Ii][Cc][Mm][Pp])		PROTO="icmp"									;;
	2|[Ii][Gg][Mm][Pp])		PROTO="igmp"	IGNOREPORT="YES"				;;
	3|[Gg][Gg][Pp])			PROTO="ggp"		IGNOREPORT="YES"				;;
	4|[Ii][Pp][Ii][Pp])		PROTO="ipip"	IGNOREPORT="YES"				;;
	6|[Tt][Cc][Pp])			PROTO="tcp"										;;
	8|[Ee][Gg][Pp])			PROTO="egp"		IGNOREPORT="YES"				;;
	12|[Pp][Uu][Pp])		PROTO="pup"		IGNOREPORT="YES"				;;
	17|[Uu][Dd][Pp])		PROTO="udp"										;;
	22|[Ii][Dd][Pp])		PROTO="idp"		IGNOREPORT="YES"				;;
	41|[Ii][Pp][Vv]6)		PROTO="ipv6"	IGNOREPORT="YES"				;;
	46|[Rr][Ss][Vv][Pp])	PROTO="rsvp"	IGNOREPORT="YES"				;;
	47|[Gg][Rr][Ee])		PROTO="gre"		IGNOREPORT="YES"				;;
	50|[Ee][Ss][Pp])		PROTO="esp"		IGNOREPORT="YES"				;;
	103|[Pp][Ii][Mm])		PROTO="pim"		IGNOREPORT="YES"				;;
	255|[Rr][Aa][Ww])		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


#-------------------------------------------------------------------------
# routesoverlap function.  In short, if any two non-default routes in 
# the routing table overlap _and_ point at different interfaces, return true.
#-------------------------------------------------------------------------
routesoverlap () {
	ALLROUTES="`route -n | cut -b 1-16,33-48,73-80 | grep '^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*[[:space:]]' | \
	 grep -v '^0\.0\.0\.0[[:space:]]' | awk '{print $1 "/" $2 "-" $3}'`"		#network/netmask-interface

	OVERLAPS=1	#False
	OVERLAPPINGROUTES=""

	for NET1 in $ALLROUTES ; do
		for NET2 in $ALLROUTES ; do
			if [ "${NET1##*-}" != "${NET2##*-}" ]; then		#No need to check if they point to the same if
				if networksoverlap ${NET1%%-*} ${NET2%%-*} ; then
					OVERLAPS=0
					if [ -n "$OVERLAPPINGROUTES" ]; then OVERLAPPINGROUTES="$OVERLAPPINGROUTES, " ; fi
					OVERLAPPINGROUTES="$OVERLAPPINGROUTES${NET1%%-*} and ${NET2%%-*}"
				fi
			fi
		done
	done
	if [ -n "$OVERLAPPINGROUTES" ]; then OVERLAPPINGROUTES="$OVERLAPPINGROUTES." ; fi

	return $OVERLAPS
} #End of routesoverlap


#-------------------------------------------------------------------------
# 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 spoofblocks" ; #ckpt $CKPTRUNLEARNFIREWALL
		if [ "$SPOOFBLOCKS" = "YES" ]; then
			echo -n Spoof blocks...
			#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 ONEROUTE in `route -n | cut -b 1-16,33-48,73-80 | grep '^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*[[:space:]]' | \
			 grep -v '^0\.0\.0\.0[[:space:]]' | awk '{print $1 "/" $2 "-" $3}'` ; do
				/sbin/ipchains -I input  -s ${ONEROUTE%%-*}  -i ! ${ONEROUTE##*-} -j DENY $LOGBLOCKS
			done
		else echo -n Not blocking spoofed packets... ; 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)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.}
						/sbin/ipchains -I input -i $OUTSIDEIF -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS				;;
					*/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

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipchains nooutgoing" ; #ckpt $CKPTRUNLEARNFIREWALL
		if [ -n "$NOOUTGOING" ] && [ -n "$OUTGOINGINTERFACES" ]; then
			echo -n Outgoing blocks...
			for OUTSIDEIF in $OUTGOINGINTERFACES ; do
				for BLOCKPROTO in $NOOUTGOING ; do
					case $BLOCKPROTO in			#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
					*.*/icmp|*.*/ICMP)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.}
						/sbin/ipchains -I output -i $OUTSIDEIF -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS				;;
					*/icmp|*/ICMP)	/sbin/ipchains -I output -i $OUTSIDEIF -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS				;;
					#*/*)			/sbin/ipchains -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS ;;
					#*)				/sbin/ipchains -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS							;;
					esac
				done
			done
		else echo -n No outgoing 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

		echo -n Not blocking spoofed packets under ipfwadm...

		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)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.}	#Cannot do subcode on icmp.
						/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P icmp -S 0/0 ICMPCODE $LOGBLOCKS				;;
					*/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

		CKPTRUNLEARNFIREWALL=" runlearnfirewall: ipfwadm nooutgoing" ; #ckpt $CKPTRUNLEARNFIREWALL
		if [ -n "$NOOUTGOING" ] && [ -n "$OUTGOINGINTERFACES" ]; then
			echo -n Outgoing blocks...
			for OUTSIDEIF in $OUTGOINGINTERFACES ; do
				for BLOCKPROTO in $NOOUTGOING ; do
					case $BLOCKPROTO in
					*.*/icmp|*.*/ICMP)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.} #Cannot do subcode on ipfwadm
						/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 $ICMPCODE $LOGBLOCKS				;;
					*/icmp|*/ICMP)	/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS				;;
					#*/*)			/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS	;;
					#*)				/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} $LOGBLOCKS							;;
					esac
				done
			done
		else echo -n No outgoing 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 spoofblocks" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		if [ "$SPOOFBLOCKS" = "YES" ]; then
			echo -n Spoof blocks...
			#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 ONEROUTE in `route -n | cut -b 1-16,33-48,73-80 | grep '^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*[[:space:]]' | \
			 grep -v '^0\.0\.0\.0[[:space:]]' | awk '{print $1 "/" $2 "-" $3}'` ; do
				/sbin/ipchains -I input  -s ${ONEROUTE%%-*}  -i ! ${ONEROUTE##*-} -j DENY $LOGBLOCKS
			done
		else echo -n Not blocking spoofed packets... ; 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)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.}
						/sbin/ipchains -I input -i $OUTSIDEIF -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS				;;
					*/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

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipchains nooutgoing" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		if [ -n "$NOOUTGOING" ] && [ -n "$OUTGOINGINTERFACES" ]; then
			echo -n Outgoing blocks...
			for OUTSIDEIF in $OUTGOINGINTERFACES ; do
				for BLOCKPROTO in $NOOUTGOING ; do
					case $BLOCKPROTO in			#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
					*.*/icmp|*.*/ICMP)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.}
						/sbin/ipchains -I output -i $OUTSIDEIF -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS				;;
					*/icmp|*/ICMP)	/sbin/ipchains -I output -i $OUTSIDEIF -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS				;;
					#*/*)			/sbin/ipchains -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS	;;
					#*)				/sbin/ipchains -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS							;;
					esac
				done
			done
		else echo -n No outgoing 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

		echo -n Not blocking spoofed packets under ipfwadm...

		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)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.} # Cannot do subcode on ipfwadm.
						/sbin/ipfwadm -I -i deny -W $OUTSIDEIF -P icmp -S 0/0 $ICMPCODE $LOGBLOCKS				;;
					*/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

		CKPTRUNSTANDARDFIREWALL=" runstandardfirewall: ipfwadm nooutgoing" ; #ckpt $CKPTRUNSTANDARDFIREWALL
		if [ -n "$NOOUTGOING" ] && [ -n "$OUTGOINGINTERFACES" ]; then
			echo -n Outgoing blocks...
			for OUTSIDEIF in $OUTGOINGINTERFACES ; do
				for BLOCKPROTO in $NOOUTGOING ; do
					case $BLOCKPROTO in
					*.*/icmp|*.*/ICMP)
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPCODE##*.} # Cannot do subcode on ipfwadm.
						/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 $ICMPCODE $LOGBLOCKS				;;
					*/icmp|*/ICMP)	/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS				;;
					#*/*)			/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS	;;
					#*)				/sbin/ipfwadm -O -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} $LOGBLOCKS							;;
					esac
				done
			done
		else echo -n No outgoing 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


#-------------------------------------------------------------------------
# seqfunc function, creates a sequence of integers from $1 to $2
# Integers only!
#-------------------------------------------------------------------------
seqfunc () {
	case $# in
	0)	:														;;
	1)	echo $1													;;
	*)	
		if [ $[ $1 ] -eq $[ $2 ] ]; then
			echo $1
		elif [ $[ $1 ] -lt $[ $2 ] ]; then
			SEQCOUNT=$[ $1 ]
			while [ $SEQCOUNT -le $[ $2 ] ]; do
				echo $SEQCOUNT
				SEQCOUNT=$[ $SEQCOUNT + 1 ]
			done
		else #$1 > $2
			SEQCOUNT=$[ $1 ]
			while [ $SEQCOUNT -ge $[ $2 ] ]; do
				echo $SEQCOUNT
				SEQCOUNT=$[ $SEQCOUNT - 1 ]
			done
		fi
																;;
	esac

} #End of seqfunc


#-------------------------------------------------------------------------
# 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
		#The () subshell below is the equivalent of: "head -n 1 | awk '{print $1}'`"
		SERVICE="`grep "[[:space:]]$1/$2" $SERVICES | ( if read F1 FREST ; then echo $F1 ; fi )`"
		#Mason will not be manipulating /etc/services.
		#SERVICELINE="`grep "[[:space:]]$1/$2" $SERVICES | head -n 1`"
		#if [ `grep "[[:space:]]$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 () {
	trap - 0	#If we were asked to exit, no need to process a "crash"
	unset CKPTMGT CKPTMASON CKPTCHECKSYS CKPTCLIENTPORTRANGE \
	 CKPTGENERALIZEIP CKPTIPLE CKPTIPLT CKPTISNUMERICIP CKPTLOADCONF \
	 CKPTSERVERPORTRANGE CKPTADDCOUNTS CKPTNAMEOF CKPTBROADCASTOF \
	 CKPTCHECKCONF CKPTDELCOUNTS CKPTFLUSHFIREWALL CKPTPORT2CISCOPORT \
	 CKPTPROTONUM2NAME CKPTRULETAG CKPTRUNLEARNFIREWALL \
	 CKPTRUNSTANDARDFIREWALL CKPTSETTOS CKPTSORTRULEFILE \
	 CKPTUNIQRULEFILE CKPTUPDATECOUNTS CKPTNETWORKOF || /bin/true
	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 `seqfunc 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 +1 | \
	uniq -1 | \
	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


#-------------------------------------------------------------------------
# updatecounts procedure, keeps a copy of the current packet counts if 
# there are more packets in the running firewall than in the archived copy.
#-------------------------------------------------------------------------
updatecounts () {
#Params: none
	CKPTUPDATECOUNTS=" updatecounts: Start" ; #ckpt $CKPTUPDATECOUNTS
	if [ -f /proc/net/ip_fwchains ] && [ "$SORTMODE" = "PACKETCOUNTS" ]; then		#We can only match up counts to rules if we have mark values, i.e. ipchains.
		if [ -z "$LASTMINMARK" ] || [ "$LASTMINMARK" = "0" ]; then
			LASTMINARK=$MINMARK
		elif [ "$MINMARK" -ge "$LASTMINMARK" ]; then	#Erase old counts if we've made new rules.
			cat /dev/null >$PACKETCOUNTFILE
			CURRENTCOUNT=0
			LASTMINMARK=$MINMARK
		fi
		if [ -z "$CURRENTCOUNT" ] || [ "$CURRENTCOUNT" = "0" ]; then	#Add up number of packets in current cache.
			CURRENTCOUNT=0
			CKPTUPDATECOUNTS=" updatecounts: sum packetcountfile" ; #ckpt $CKPTUPDATECOUNTS
			for ONECOUNT in `awk '{print $1}' $PACKETCOUNTFILE` ; do
				CURRENTCOUNT=$[ $CURRENTCOUNT + $ONECOUNT ]
			done
		fi
		NEWCOUNT=0
		CKPTUPDATECOUNTS=" updatecounts: sum running firewall" ; #ckpt $CKPTUPDATECOUNTS
		for ONECOUNT in `ipchains -L -n -x -v | cut -b 1-9,66-75 - | grep '0x' | awk '{print $1}'` ; do
			NEWCOUNT=$[ $NEWCOUNT + $ONECOUNT ]
		done
		if [ $NEWCOUNT -gt $CURRENTCOUNT ]; then	#Are there more packets in the running firewall?
			CKPTUPDATECOUNTS=" updatecounts: replace packetcountfile" ; #ckpt $CKPTUPDATECOUNTS
			ipchains -L -n -x -v | cut -b 1-9,66-75 - | grep '0x' >$PACKETCOUNTFILE
			CURRENTCOUNT=$NEWCOUNT
		fi
		DUPMARKS=`ipchains -L -n -x -v | cut -b 1-9,66-75 - | grep '0x' | awk '{print $2}' | sort | uniq -d`
		if [ -n "$DUPMARKS" ]; then
			echo Warning - the following marks are used more than once in the >/dev/stderr
			echo currently running firewall: >/dev/stderr
			for ONEMARK in $DUPMARKS ; do
				case $ONEMARK in
				0x*)	echo -n "$ONEMARK = $[ $ONEMARK ]   " >/dev/stderr	;;
				*)		echo -n "$ONEMARK  " >/dev/stderr					;;
				esac
			done
			echo >/dev/stderr
			echo This will give incorrect packet counts in your rulefiles. >/dev/stderr
		fi
	fi
	CKPTUPDATECOUNTS=""
} #End of updatecounts




