#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.
#		  || logfail $LINENO masonlib: YYYY #### the_command_that_was_supposed_to_run
#Last YYYY code used: 0134, use 0135 next

MASONVER="0.13.0.92, developers release, 9/26/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
	#FIXME - test for iptables
	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/' || logfail $LINENO masonlib: 0001 grep ' -m ' $1 pipe 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 || logfail $LINENO masonlib: YYYY 0002`
				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 || logfail $LINENO masonlib: YYYY 0003
				#I couldn't figure out the quoting to allow actual spaces in the ADDCOUNTSCRIPT variable.
				cat $ONEFILE.temp >$ONEFILE || logfail $LINENO masonlib: YYYY 0004
				rm -f $ONEFILE.temp || logfail $LINENO masonlib: YYYY 0005
			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 || logfail $LINENO masonlib: 0006 mkdir --parents $MASONDIR
		chown root.root $MASONDIR || logfail $LINENO masonlib: 0007 chown root.root $MASONDIR
		chmod 700 $MASONDIR || logfail $LINENO masonlib: 0008 chmod 700 $MASONDIR
	fi
	MASONCONF=${MASONCONF:-"/etc/masonrc"} ;						if [ ! -f $MASONCONF ]; then touch $MASONCONF || logfail $LINENO masonlib: 0009 touch $MASONCONF ; fi
	#NAMECACHE support has been disabled
	#NAMECACHE=${NAMECACHE:-"${MASONDIR}morehosts"} ;				if [ ! -f $NAMECACHE ]; then touch $NAMECACHE || logfail $LINENO masonlib: 0010 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 || logfail $LINENO masonlib: 0011 touch $NETCACHE ; fi
	BASERULEFILE=${BASERULEFILE:-"${MASONDIR}baserules"} ;			if [ ! -f $BASERULEFILE ]; then touch $BASERULEFILE || logfail $LINENO masonlib: 0012 touch $BASERULEFILE ; fi
	NEWRULEFILE=${NEWRULEFILE:-"${MASONDIR}newrules"} ;				if [ ! -f $NEWRULEFILE ]; then touch $NEWRULEFILE || logfail $LINENO masonlib: 0013 touch $NEWRULEFILE ; fi
	PACKETCOUNTFILE=${PACKETCOUNTFILE:-"${MASONDIR}packetcounts"} ;	if [ ! -f $PACKETCOUNTFILE ]; then touch $PACKETCOUNTFILE || logfail $LINENO masonlib: 0014 touch $PACKETCOUNTFILE ; fi
	#SYSTEMRULEFILE=${SYSTEMRULEFILE:-"${MASONDIR}systemrules"} ;	if [ ! -f $SYSTEMRULEFILE ]; then touch $SYSTEMRULEFILE || logfail $LINENO masonlib: 0015 touch $SYSTEMRULEFILE ; fi
	PACKETLOGFILE=${PACKETLOGFILE:-"/var/log/messages"}
	MASONEXE=${MASONEXE:-"/usr/bin/mason"}

	if [ -z "$IPNATCTLBIN" ]; then
		if type -path ipnatctl >/dev/null ; then		IPNATCTLBIN=`type -path ipnatctl | head -1`
		elif [ -x /sbin/ipnatctl ]; then				IPNATCTLBIN='/sbin/ipnatctl'
		elif [ -x /usr/local/bin/ipnatctl ]; then		IPNATCTLBIN='/usr/local/bin/ipnatctl'
		else
			IPNATCTLBIN='ipnatctl'
			#echo 'ipnatctl was not found in your path or in /usr/local/bin.  You may need' >/dev/stderr
			#echo 'to copy it or add an explicit path to it in the following commands.' >/dev/stderr
		fi
	fi
	if [ -z "$IPTABLESBIN" ]; then
		if type -path iptables >/dev/null ; then		IPTABLESBIN=`type -path iptables | head -1`
		elif [ -x /sbin/iptables ]; then				IPTABLESBIN='/sbin/iptables'
		elif [ -x /usr/local/bin/iptables ]; then		IPTABLESBIN='/usr/local/bin/iptables'
		else
			IPTABLESBIN='iptables'
			#echo 'iptables was not found in your path, in /usr/local/bin or in /sbin.  You may need' >/dev/stderr
			#echo 'to copy it or add an explicit path to it in the following commands.' >/dev/stderr
		fi
	fi
	if [ -z "$IPCHAINSBIN" ]; then
		if type -path ipchains >/dev/null ; then		IPCHAINSBIN=`type -path ipchains | head -1`
		elif [ -x /sbin/ipchains ]; then				IPCHAINSBIN='/sbin/ipchains'
		#elif [ -x /usr/local/bin/ipchains ]; then		IPCHAINSBIN='/usr/local/bin/ipchains'
		else
			IPCHAINSBIN='ipchains'
			#echo 'ipchains was not found in your path or in /sbin.  You may need' >/dev/stderr
			#echo 'to copy it or add an explicit path to it in the following commands.' >/dev/stderr
		fi
	fi
	if [ -z "$IPFWADMBIN" ]; then
		if type -path ipfwadm >/dev/null ; then			IPFWADMBIN=`type -path ipfwadm | head -1`
		elif [ -x /sbin/ipfwadm ]; then					IPFWADMBIN='/sbin/ipfwadm'
		#elif [ -x /usr/local/bin/ipfwadm ]; then		IPFWADMBIN='/usr/local/bin/ipfwadm'
		else
			IPFWADMBIN='ipfwadm'
			#echo 'ipfwadm was not found in your path or in /sbin.  You may need' >/dev/stderr
			#echo 'to copy it or add an explicit path to it in the following commands.' >/dev/stderr
		fi
	fi


	if [ ! -d /var/run ]; then mkdir --parents /var/run || logfail $LINENO masonlib: 0016 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 || logfail $LINENO masonlib: YYYY 0017`}
	OUTGOINGINTERFACES=${OUTGOINGINTERFACES:-`/sbin/route -n | grep '^0\.0\.0\.0[ \t]' | awk '{print $8}' | sort | uniq || logfail $LINENO masonlib: YYYY 0018`}

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

	case $DEFAULTPOLICY in
	[Aa][Cc][Cc][Ee][Pp][Tt])									DEFAULTPOLICY="accept"	;;
	[Rr][Ee][Jj][Ee][Cc][Tt])									DEFAULTPOLICY="reject"	;;
	[Dd][Ee][Nn][Yy])											DEFAULTPOLICY="deny"	;;
	*)	echo WARNING! DEFAULTPOLICY is neither accept, reject, nor deny. >/dev/stderr
		echo in $MASONCONF.  >/dev/stderr
		while [ "$DEFAULTPOLICY" != "accept" ] && [ "$DEFAULTPOLICY" != "reject" ] && [ "$DEFAULTPOLICY" != "deny" ] ; do
			echo Please choose accept, reject, or deny: >/dev/stderr
			read DEFAULTPOLICY JUNK || :
			case "$DEFAULTPOLICY" in
			[Aa][Cc][Cc][Ee][Pp][Tt])							DEFAULTPOLICY="accept"	;;
			[Rr][Ee][Jj][Ee][Cc][Tt])							DEFAULTPOLICY="reject"	;;
			[Dd][Ee][Nn][Yy])									DEFAULTPOLICY="deny"	;;
			esac
		done
		echo "DEFAULTPOLICY=$DEFAULTPOLICY" >>$MASONCONF
		echo DEFAULTPOLICY is being reset to \"$DEFAULTPOLICY\". >/dev/stderr			;;
	esac
	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"	;;
	[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])							ECHOCOMMAND="iptables"	;;
	[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"
		#FIXME - test for iptables
		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 "$IPFWADMBIN" ]; then
			echo WARNING! User has requested ipfwadm, but $IPFWADMBIN 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 "$IPCHAINSBIN" ]; then
			echo WARNING! User has requested ipchains, but $IPCHAINSBIN is not >/dev/stderr
			echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
			sleep 10
		fi																				;;
	[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])
		DOCOMMAND="iptables"
		#FIXME - how do we test for iptables?  Probably lsmod for the moment.
		#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 "$IPTABLESBIN" ]; then
			echo WARNING! User has requested iptables, but $IPTABLESBIN 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 "$IPCHAINSBIN" ]; then
				echo WARNING! This kernel uses ipchains, but $IPCHAINSBIN 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 "$IPFWADMBIN" ]; then
				echo WARNING! This kernel uses ipfwadm, but $IPFWADMBIN 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
		#FIXME - add a section for iptables once we know how to test for it.
		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])
		if [ "$DOCOMMAND" = "ipchains" ] || [ "$DOCOMMAND" = "iptables" ]; then
			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
		else
			echo Spoof blocking is only available under ipchains and iptables. >/dev/stderr
			SPOOFBLOCKS="YES"
		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}' || logfail $LINENO masonlib: YYYY 0019` ; 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 || logfail $LINENO masonlib: YYYY 0020`
					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}' || logfail $LINENO masonlib: YYYY 0021` ; 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
	#FIXME - do this for iptables too.
	if [ -n "$MINMARK" ] && [ -f /proc/net/ip_fwchains ]; 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	#Formerly YYYY 0022
			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 || logfail $LINENO masonlib: YYYY 0023` ;							fi
	if [ -n "$SCP" ]; then				SCP=`echo "$SCP" | tr ' ' '\012' | sort | uniq || logfail $LINENO masonlib: YYYY 0024` ;							fi
	if [ -n "$BLOCKEDHOSTS" ]; then 	BLOCKEDHOSTS=`echo "$BLOCKEDHOSTS" | tr ' ' '\012' | sort | uniq || logfail $LINENO masonlib: YYYY 0025` ;			fi
	if [ -n "$DYNIF" ]; then 			DYNIF=`echo "$DYNIF" | tr ' ' '\012' | sort | uniq || logfail $LINENO masonlib: YYYY 0026` ;						fi
	if [ -n "$NOINCOMING" ]; then		NOINCOMING=`echo "$NOINCOMING" | tr ' ' '\012' | sort | uniq || logfail $LINENO masonlib: YYYY 0027` ;				fi
	if [ -n "$NOOUTGOING" ]; then		NOOUTGOING=`echo "$NOOUTGOING" | tr ' ' '\012' | sort | uniq || logfail $LINENO masonlib: YYYY 0028` ;				fi
	if [ -n "$POISONPROTOCOLS" ]; then	POISONPROTOCOLS=`echo "$POISONPROTOCOLS" | tr ' ' '\012' | sort | uniq || logfail $LINENO masonlib: YYYY 0029` ;	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 || logfail $LINENO masonlib: YYYY 0030` ;					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 || :
		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.
		sleep 10
		exit 0
	fi

	#FIXME - iptables detect
	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, iptables 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?).
	#FIXME - fall back on "ip route", etc.?
	for ONEUTIL in awk bash cat chmod cut grep head ifconfig mkdir ps route sed sleep sort tail touch tr 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' || logfail $LINENO masonlib: YYYY 0031` ; 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}' || logfail $LINENO masonlib: YYYY 0032` ; do
		NEWIP=`ifconfig $ONEIF | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://' || logfail $LINENO masonlib: YYYY 0033`
		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

	#FIXME - add iptables
	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 "$IPCHAINSBIN" ]; then
			echo WARNING! User has requested ipchains, but $IPCHAINSBIN 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 input output forward ; do		#Was `$IPCHAINSBIN -L -n | grep '^Chain ' | awk '{print $2}'`
				#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 ! $IPCHAINSBIN -L $ONECHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null ; then  #If nolog chain does not exist
						#LOGCHAINSEXIST="no"	#In the process of being removed; just placing NOLOGSUFFIX="" below is all that's needed. #REMOVEME
						NOLOGSUFFIX=""
						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		#In the process of being removed. #REMOVEME
		fi
	fi

	CKPTCHECKSYS=" checksys: Check promisc" ; #ckpt $CKPTCHECKSYS
	if [ -n "`ifconfig | grep MTU | grep PROMISC`" ]; then
		echo Warning: at least one of your interfaces is in promiscuous mode. >/dev/stderr
		echo You are likely to create a lot of rules you did not want. >/dev/stderr
		echo Unless you know this is what you want, you should turn off >/dev/stderr
		echo promiscuous mode on all interfaces.  Press Ctrl-c now or this >/dev/stderr
		echo will continue in 15 seconds. >/dev/stderr
		sleep 15
	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
		#Please use caution if you're trying to group these together!
		  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 [ "$PRPROTO" = "udp" ] && [ $CLIENTPORT -ge $TRACEROUTE_BEGIN ] && [ $CLIENTPORT -le $TRACEROUTE_END ] ; 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/[Tt][Cc][Pp]|[Ss][Ss][Hh]/[Tt][Cc][Pp])
				if [ $CLIENTPORT -le 1023 ]; then
					while [ "$CLIENTPORT" -lt "$LOWSSHPORT" ]; do
						LOWSSHPORT=$[ $LOWSSHPORT - 10 ]
					done
					CPRRETVAL="$LOWSSHPORT:1023"
				fi													;;
			111/[Tt][Cc][Pp]|sunrpc/[Tt][Cc][Pp]|rpcbind/[Tt][Cc][Pp]|111/[Uu][Dd][Pp]|sunrpc/[Uu][Dd][Pp]|rpcbind/[Tt][Cc][Pp]|635/[Tt][Cc][Pp]|mount/[Tt][Cc][Pp]|635/[Uu][Dd][Pp]|mount/[Uu][Dd][Pp]|2049/[Uu][Dd][Pp]|nfs/[Uu][Dd][Pp])
#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/[Tt][Cc][Pp]|nfs/[Tt][Cc][Pp])	#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 || logfail $LINENO masonlib: YYYY 0034
		cat $ONEFILE.temp >$ONEFILE || logfail $LINENO masonlib: YYYY 0035
		rm -f $ONEFILE.temp || logfail $LINENO masonlib: YYYY 0036
	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 both: `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

		SPLITIP=$MINIP ;			MINO1=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MINO2=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MINO3=${SPLITIP%%.*}
		#SPLITIP=${SPLITIP#*.} ;	MINO4=$SPLITIP			#We don't need the MIN04 and MAX04.
		SPLITIP=$MAXIP ;			MAXO1=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MAXO2=${SPLITIP%%.*}
		SPLITIP=${SPLITIP#*.} ;		MAXO3=${SPLITIP%%.*}
		#SPLITIP=${SPLITIP#*.} ;	MAXO4=$SPLITIP

		#Find the _starting_ _point_ for the search.
		# - if the first octets are different, start at /8.
		# - if the second octets are different, start at /16.
		# - if the third octets are different, start at /24.
		# - else start at /32.
		#This relatively simple optimization sped up this function by a theoretical factor of 4 
		#and a timed factor of 10 on one example.  *smile*
		#(BTW - It would appear we could start the search at 7, 15, or 23, but the result from 
		#encompassingnetworkof 10.1.2.3 11.12.13.14 10.2.3.4  comes back as 8.0.0.0/6: wrong.
		  if [ $MINO1 -ne $MAXO1 ]; then		ENONUMBITS=8 ;	ENONETMASK=255.0.0.0
		elif [ $MINO2 -ne $MAXO2 ]; then		ENONUMBITS=16 ;	ENONETMASK=255.255.0.0
		elif [ $MINO3 -ne $MAXO3 ]; then		ENONUMBITS=24 ;	ENONETMASK=255.255.255.0
		else									ENONUMBITS=32 ;	ENONETMASK=255.255.255.255 ; fi
		ENONETWORK=$MINIP
		ENOBROADCAST=$MINIP

		#Keep expanding the network until it includes MAXIP.  This takes almost all of the time.
		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
	#FIXME - Add section for iptables
	if [ -f /proc/net/ip_fwchains ]; then
		updatecounts
		echo -n Flushing... >/dev/stderr
		FLUSHEDPOLICY=`echo $FLUSHEDPOLICY | tr a-z A-Z || logfail $LINENO masonlib: 0037 echo $FLUSHEDPOLICY pipe tr a-z A-Z`
		$IPCHAINSBIN -P output $FLUSHEDPOLICY	|| logfail $LINENO masonlib: 0038 $IPCHAINSBIN -P output $FLUSHEDPOLICY
		$IPCHAINSBIN -F output					|| logfail $LINENO masonlib: 0039 $IPCHAINSBIN -F output
		$IPCHAINSBIN -P forward $FLUSHEDPOLICY	|| logfail $LINENO masonlib: 0040 $IPCHAINSBIN -P forward $FLUSHEDPOLICY
		$IPCHAINSBIN -F forward					|| logfail $LINENO masonlib: 0041 $IPCHAINSBIN -F forward
		$IPCHAINSBIN -P input $FLUSHEDPOLICY	|| logfail $LINENO masonlib: 0042 $IPCHAINSBIN -P input $FLUSHEDPOLICY
		$IPCHAINSBIN -F input					|| logfail $LINENO masonlib: 0043 $IPCHAINSBIN -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 [ `$IPCHAINSBIN -L -n | grep "^Chain $ONECHAIN$NOLOGSUFFIX" | wc -l` -gt 0 ]; then
					$IPCHAINSBIN -F $ONECHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null || logfail $LINENO masonlib: 0044 $IPCHAINSBIN -F $ONECHAIN$NOLOGSUFFIX
				else
					$IPCHAINSBIN -N $ONECHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null || logfail $LINENO masonlib: 0045 $IPCHAINSBIN -N $ONECHAIN$NOLOGSUFFIX
				fi
			done
		fi

		CKPTFLUSHFIREWALL=" flushfirewall: Create or flush NoSpoof chain." ; #ckpt $CKPTFLUSHFIREWALL
		if [ `$IPCHAINSBIN -L -n | grep "^Chain NoSpoof" | wc -l` -gt 0 ]; then
			$IPCHAINSBIN -F NoSpoof >/dev/null 2>/dev/null || logfail $LINENO masonlib: 0134 $IPCHAINSBIN -F NoSpoof
		fi

		echo Done!
	elif [ -f /proc/net/ip_input ]; then
		echo -n Flushing... >/dev/stderr
		FLUSHEDPOLICY=`echo $FLUSHEDPOLICY | tr A-Z a-z || logfail $LINENO masonlib: 0046 echo $FLUSHEDPOLICY pipe tr A-Z a-z`
		$IPFWADMBIN -O -p $FLUSHEDPOLICY		|| logfail $LINENO masonlib: 0047 $IPFWADMBIN -O -p $FLUSHEDPOLICY
		$IPFWADMBIN -O -f						|| logfail $LINENO masonlib: 0048 $IPFWADMBIN -O -f
		$IPFWADMBIN -F -p $FLUSHEDPOLICY		|| logfail $LINENO masonlib: 0049 $IPFWADMBIN -F -p $FLUSHEDPOLICY
		$IPFWADMBIN -F -f						|| logfail $LINENO masonlib: 0050 $IPFWADMBIN -F -f
		$IPFWADMBIN -I -p $FLUSHEDPOLICY		|| logfail $LINENO masonlib: 0051 $IPFWADMBIN -I -p $FLUSHEDPOLICY
		$IPFWADMBIN -I -f						|| logfail $LINENO masonlib: 0052 $IPFWADMBIN -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
#FIXME - should we leave 65535 on its own?  Probably.
	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 () {
	if [ "$1" = "$2" ]; then
		return 0	#True
	else
		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
	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
	if [ "$1" = "$2" ]; then
		CKPTIPLE="" ; return 0	#True
	else
		CKPTIPLE=" iple: start, addresses $1 and $2" ; #ckpt $CKPTIPLE

		SPLITIP1=$1 ;				I1O1=${SPLITIP1%%.*}
		SPLITIP2=$2 ;				I2O1=${SPLITIP2%%.*}
		  if [ $I1O1 -lt $I2O1 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O1 -gt $I2O1 ]; then	CKPTIPLE="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O2=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O2=${SPLITIP2%%.*}
		  if [ $I1O2 -lt $I2O2 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O2 -gt $I2O2 ]; then	CKPTIPLE="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O3=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O3=${SPLITIP2%%.*}
		  if [ $I1O3 -lt $I2O3 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O3 -gt $I2O3 ]; then	CKPTIPLE="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O4=$SPLITIP1
		SPLITIP2=${SPLITIP2#*.} ;	I2O4=$SPLITIP2
		  if [ $I1O4 -lt $I2O4 ]; then	CKPTIPLE="" ; return 0
		elif [ $I1O4 -gt $I2O4 ]; then	CKPTIPLE="" ; return 1
		else							CKPTIPLE="" ; return 0
		fi
	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
#As a speedup, only come up with the individual numbers as they are needed.
	if [ "$1" = "$2" ]; then
		CKPTIPLT="" ; return 1	#False
	else
		CKPTIPLT=" iplt: start, addresses $1 and $2" ; #ckpt $CKPTIPLT

		SPLITIP1=$1 ;				I1O1=${SPLITIP1%%.*}
		SPLITIP2=$2 ;				I2O1=${SPLITIP2%%.*}
		  if [ $I1O1 -lt $I2O1 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O1 -gt $I2O1 ]; then	CKPTIPLT="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O2=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O2=${SPLITIP2%%.*}
		  if [ $I1O2 -lt $I2O2 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O2 -gt $I2O2 ]; then	CKPTIPLT="" ; return 1
        fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O3=${SPLITIP1%%.*}
		SPLITIP2=${SPLITIP2#*.} ;	I2O3=${SPLITIP2%%.*}
		  if [ $I1O3 -lt $I2O3 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O3 -gt $I2O3 ]; then	CKPTIPLT="" ; return 1
		fi

		SPLITIP1=${SPLITIP1#*.} ;	I1O4=$SPLITIP1
		SPLITIP2=${SPLITIP2#*.} ;	I2O4=$SPLITIP2
		  if [ $I1O4 -lt $I2O4 ]; then	CKPTIPLT="" ; return 0
		elif [ $I1O4 -gt $I2O4 ]; then	CKPTIPLT="" ; return 1
		else							CKPTIPLT="" ; return 1
		fi
	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 || logfail $LINENO masonlib: 0053 . $MASONCONF
	else
		touch $MASONCONF || logfail $LINENO masonlib: 0054 touch $MASONCONF
		chmod 700 $MASONCONF || logfail $LINENO masonlib: 0055 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/ .*//' || logfail $LINENO masonlib: YYYY 0056` \
	`route -n | grep '^[0-9\.]* *[0-9\.]* *255\.255\.255\.255' | awk '{print $1}' || logfail $LINENO masonlib: YYYY 0057`"
	ALLBCS=`ifconfig | grep 'Bcast' | sed -e 's/.*Bcast://' -e 's/ .*//' || logfail $LINENO masonlib: YYYY 0058`
#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 || logfail $LINENO masonlib: YYYY 0059`" ]; 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}' || logfail $LINENO masonlib: YYYY 0060`

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


#-------------------------------------------------------------------------
# logfail subroutine, record the fact that a command returned non-true.
#-------------------------------------------------------------------------
logfail () {
#To use, add:
#  || logfail $LINENO filename some words that will identify what bombed
#at the end of any command that could conceivably return false.
#DO NOT send ANYTHING to stdout - this function is used inside backticks.  Use stderr if necessary.
#Don't assume everything has been initialized yet.
	LOGRETVAL="$?"		#This should be placed first to preserve the return code of the failed command.
	TEMPMASONDIR=${MASONDIR:-"/var/lib/mason/"}

#FIXME - test if masoncrash is writable, fall back to stderr if not?
	echo "`date` - $MASONVER" >>${TEMPMASONDIR}masoncrash
	case "$1" in
	0|1)										shift	;;
	[0-9]*)	echo -n "Line $1, " >>${TEMPMASONDIR}masoncrash ;	shift	;;
	esac
	echo "Caught failure ($LOGRETVAL) on: $*" >>${TEMPMASONDIR}masoncrash
	return 0 	#True; this makes bash happy
} #End of logfail


#-------------------------------------------------------------------------
# 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 ) || logfail $LINENO masonlib: YYYY 0061`
			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 ! reservedip $NAMEOFINPUT ; then		#One approach might be to avoid looking up rfc1918 addresses entirely
			#FIXME - don't run host twice
			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/.* //' || logfail $LINENO masonlib: YYYY 0062`
				#do double reverse, see if same as input ip, only _then_ assign.
				#I specifically removed the head --lines=1 because I don't want to provide a round-robin name.
				ONEIPADDR=`host -t a $ONEHOSTNAME 2>/dev/null | grep 'has address' | sed -e 's/.* //' || logfail $LINENO masonlib: YYYY 0133`
				if [ -n "$ONEHOSTNAME" ] && [ "$NAMEOFINPUT" = "$ONEIPADDR" ] && [ "$ONEHOSTNAME" != "read-rfc1918-for-details.iana.net" ]; then		#Grrr...
					NAMEOFRETVAL="$ONEHOSTNAME"
				fi
			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 () {
	#FIXME - handle, or get networkof/broadcastof to handle, '0' as the network
	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
	#FIXME - convert /udp, /tcp, /icmp over to case insensitive checks
	CKPTPORT2CISCOPORT=" port2ciscoport: Start" ; #ckpt $CKPTPORT2CISCOPORT
	PCPRETVAL=""

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


#-------------------------------------------------------------------------
# preexit procedure.  Called on receipt of signal 0 (exiting) from bash
#-------------------------------------------------------------------------
#We check to see if any of the checkpoint variables are still set; if so, 
#the script probably crashed before finishing that module.  Bitch to the user.
#Be careful of system variables; they may not be loaded yet.
preexit () {
#FIXME - test for masoncrash writable?
	if [ -n "$CKPTMGT$CKPTMASON$CKPTCHECKSYS$CKPTCLIENTPORTRANGE$CKPTGENERALIZEIP$CKPTIPLE$CKPTIPLT$CKPTISNUMERICIP$CKPTLOADCONF$CKPTSERVERPORTRANGE$CKPTADDCOUNTS$CKPTNAMEOF$CKPTBROADCASTOF$CKPTCHECKCONF$CKPTDELCOUNTS$CKPTFLUSHFIREWALL$CKPTPORT2CISCOPORT$CKPTPROTONUM2NAME$CKPTRULETAG$CKPTRUNFIREWALL$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 $CKPTRUNFIREWALL \
		 $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 $CKPTRUNFIREWALL \
		 $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
		#FIXME - add test file for iptables if there is one. lsmod, perhaps?
		for ONESYSFILE in /sbin/ipchains /sbin/ipfwadm /proc/net/ip_input /proc/net/ip_fwchains /sbin/iptables /usr/local/bin/iptables ; do
			ls -ald $ONESYSFILE 												>>${MASONDIR}masoncrash 2>&1 || :
		done
		mount -t proc 															>>${MASONDIR}masoncrash 2>&1 || :
		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 || :
	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}' || logfail $LINENO masonlib: YYYY 0063`
		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}' || logfail $LINENO masonlib: YYYY 0064`"		#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.
#-------------------------------------------------------------------------
runfirewall () {
	#FIXME - add iptables support
	CKPTRUNFIREWALL=" runfirewall: Start" ; #ckpt $CKPTRUNFIREWALL
	if [ -f /proc/net/ip_fwchains ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr a-z A-Z || logfail $LINENO masonlib: YYYY 0065`
		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

		CKPTRUNFIREWALL=" runfirewall: ipchains blockedhosts" ; #ckpt $CKPTRUNFIREWALL
		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
				$IPCHAINSBIN -I input  -s $BLOCKEDHOST -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0066
				$IPCHAINSBIN -I output -s $BLOCKEDHOST -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0067
				$IPCHAINSBIN -I input  -d $BLOCKEDHOST -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0068
				$IPCHAINSBIN -I output -d $BLOCKEDHOST -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0069
			done
		else echo -n No Blockedhost blocks... ; fi

		CKPTRUNFIREWALL=" runfirewall: ipchains spoofblocks" ; #ckpt $CKPTRUNFIREWALL
		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

			#The simple approach is to block packets coming from a given local net if they don't come from 
			#the nic leading to that net - that's the second 'for' loop.  Unfortunately, we have a special 
			#case to allow first.  Say 192.168.0.1 is eth0's ip.  If I telnet to that IP on this machine, 
			#the source and destination addresses will be 192.168.0.1 - the spoof block would see this as 
			#spoofing because the packets are showing up on an interface other than eth0.  We need to exempt 
			#lo from the check.  '-j RETURN' on a chain inserted into input will do that.

			if [ `$IPCHAINSBIN -L -n | grep "^Chain NoSpoof" | wc -l` -gt 0 ]; then
				$IPCHAINSBIN -F NoSpoof >/dev/null 2>/dev/null || logfail $LINENO masonlib: YYYY 0070
			else
				$IPCHAINSBIN -N NoSpoof >/dev/null 2>/dev/null || logfail $LINENO masonlib: YYYY 0071
			fi
			$IPCHAINSBIN -I input -j NoSpoof || logfail $LINENO masonlib: YYYY 0072

			$IPCHAINSBIN -A NoSpoof -i lo -j RETURN || logfail $LINENO masonlib: YYYY 0073		#Here's the exemption if the interface is lo.

			##Loop through loips as ok input on lo
			#for ONELOCALIP in `ifconfig | grep 'inet addr' | sed -e 's/.*addr://' -e 's/ .*//' || logfail $LINENO masonlib: YYYY 0074` ; do
			#	$IPCHAINSBIN -I input  -s ${ONELOCALIP}  -i lo -j ACCEPT $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0075
			#done
			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}' || logfail $LINENO masonlib: YYYY 0076` ; do
				$IPCHAINSBIN -A NoSpoof  -s ${ONEROUTE%%-*}  -i ! ${ONEROUTE##*-} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0077
			done
		else echo -n Not blocking spoofed packets... ; fi

		CKPTRUNFIREWALL=" runfirewall: ipchains noleakrfc1918" ; #ckpt $CKPTRUNFIREWALL
		#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
					$IPCHAINSBIN -I output -i $MASQIF -s $RESNET -j DENY || logfail $LINENO masonlib: YYYY 0078
				done
			done
		else echo -n No NoLeakRFC1918 blocks... ; fi

		CKPTRUNFIREWALL=" runfirewall: ipchains noincoming" ; #ckpt $CKPTRUNFIREWALL
		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
					*.*/[Ii][Cc][Mm][Pp])
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPBOTH##*.}
						$IPCHAINSBIN -I input -i $OUTSIDEIF -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0079				;;
					*/[Ii][Cc][Mm][Pp])	$IPCHAINSBIN -I input -i $OUTSIDEIF -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0080				;;
					113/[Tt][Cc][Pp]|[Aa][Uu][Tt][Hh]/[Tt][Cc][Pp])
						$IPCHAINSBIN -I input -i $OUTSIDEIF -p tcp -d 0/0 ${BLOCKPROTO%%/*} -y -j REJECT $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0081 						;;
					*/[Tt][Cc][Pp])	$IPCHAINSBIN -I input -i $OUTSIDEIF -p tcp -d 0/0 ${BLOCKPROTO%%/*} -y -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0082 			;;
					*/*)			$IPCHAINSBIN -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0083 	;;
					*)				$IPCHAINSBIN -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0084							;;
					esac
				done
			done
		else echo -n No incoming blocks... ; fi

		CKPTRUNFIREWALL=" runfirewall: ipchains nooutgoing" ; #ckpt $CKPTRUNFIREWALL
		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
					*.*/[Ii][Cc][Mm][Pp])
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPBOTH##*.}
						$IPCHAINSBIN -I output -i $OUTSIDEIF -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0085				;;
					*/[Ii][Cc][Mm][Pp])	$IPCHAINSBIN -I output -i $OUTSIDEIF -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0086				;;
					#*/*)			$IPCHAINSBIN -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0087 ;;
					#*)				$IPCHAINSBIN -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0088							;;
					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
		#
		CKPTRUNFIREWALL=" runfirewall: ipchains baserules" ; #ckpt $CKPTRUNFIREWALL
		echo -n Fixed rules...
		. $BASERULEFILE

		if [ "$1" = "LEARN" ] || [ "$1" = "learn" ]; then
			CKPTRUNFIREWALL=" runfirewall: ipchains newrules" ; #ckpt $CKPTRUNFIREWALL
			echo -n New rules...
			. $NEWRULEFILE
		fi
		set -e

		if [ "$1" = "LEARN" ] || [ "$1" = "learn" ]; then
			#Finally, create a "nolog' chain for each of the existing chains, have each existing 
			#chain jump to it, then log everything else.
			CKPTRUNFIREWALL=" runfirewall: ipchains logging rules" ; #ckpt $CKPTRUNFIREWALL
			echo -n Adding logging rules...
			for ACHAIN in input output forward ; do
				#FIXME - shouldn't the flush be in the else clause?
				$IPCHAINSBIN -F $ACHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null || logfail $LINENO masonlib: YYYY 0089				#Flush it as it might have existed before.
				if ! $IPCHAINSBIN -L $ACHAIN$NOLOGSUFFIX >/dev/null 2>/dev/null ; then	#If nolog chain does not exist
					$IPCHAINSBIN -N $ACHAIN$NOLOGSUFFIX || logfail $LINENO masonlib: YYYY 0090					#Create it
			  	fi
				#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
				$IPCHAINSBIN -A $ACHAIN -j $ACHAIN$NOLOGSUFFIX || logfail $LINENO masonlib: YYYY 0091
				$IPCHAINSBIN -A $ACHAIN -l || logfail $LINENO masonlib: YYYY 0092
				$IPCHAINSBIN -P $ACHAIN $DEFAULTPOLICY || logfail $LINENO masonlib: YYYY 0093
			done
		else
			CKPTRUNFIREWALL=" runfirewall: ipchains policy" ; #ckpt $CKPTRUNFIREWALL
			for ACHAIN in input output forward ; do
				$IPCHAINSBIN -P $ACHAIN $DEFAULTPOLICY || logfail $LINENO masonlib: YYYY 0094
			done
		fi

		echo Done!
	elif [ -f /proc/net/ip_input ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr A-Z a-z || logfail $LINENO masonlib: YYYY 0095`
		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

		CKPTRUNFIREWALL=" runfirewall: ipfwadm blockedhosts" ; #ckpt $CKPTRUNFIREWALL
		if [ -n "$BLOCKEDHOSTS" ]; then
			echo -n Blockedhost blocks...
			for BLOCKEDHOST in $BLOCKEDHOSTS ; do
				$IPFWADMBIN -I -i deny -S $BLOCKEDHOST $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0096
				$IPFWADMBIN -O -i deny -S $BLOCKEDHOST $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0097
				$IPFWADMBIN -I -i deny -D $BLOCKEDHOST $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0098
				$IPFWADMBIN -O -i deny -D $BLOCKEDHOST $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0099
			done
		else echo -n No Blockedhost blocks... ; fi

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

		CKPTRUNFIREWALL=" runfirewall: ipfwadm noleakrfc1918" ; #ckpt $CKPTRUNFIREWALL
		#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
					$IPFWADMBIN -O -i deny -W $MASQIF -S $RESNET || logfail $LINENO masonlib: YYYY 0100
				done
			done
		else echo -n No NoLeakRFC1918 blocks... ; fi

		CKPTRUNFIREWALL=" runfirewall: ipfwadm noincoming" ; #ckpt $CKPTRUNFIREWALL
		if [ -n "$NOINCOMING" ] && [ -n "$INCOMINGINTERFACES" ]; then
			echo -n Incoming blocks...
			for OUTSIDEIF in $INCOMINGINTERFACES ; do
				for BLOCKPROTO in $NOINCOMING ; do
					case $BLOCKPROTO in
					*.*/[Ii][Cc][Mm][Pp])
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPBOTH##*.}		#Cannot do subcode on ipfwadm icmp.
						$IPFWADMBIN -I -i deny -W $OUTSIDEIF -P icmp -S 0/0 $ICMPCODE $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0101				;;
					*/[Ii][Cc][Mm][Pp])	$IPFWADMBIN -I -i deny -W $OUTSIDEIF -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0102				;;
					113/[Tt][Cc][Pp]|[Aa][Uu][Tt][Hh]/[Tt][Cc][Pp])
						$IPFWADMBIN -I -i reject -W $OUTSIDEIF -P tcp -D 0/0 ${BLOCKPROTO%%/*} -y $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0103						;;
					*/[Tt][Cc][Pp])	$IPFWADMBIN -I -i deny -W $OUTSIDEIF -P tcp -D 0/0 ${BLOCKPROTO%%/*} -y $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0104			;;
					*/*)			$IPFWADMBIN -I -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0105	;;
					*)				$IPFWADMBIN -I -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0106							;;
					esac
				done
			done
		else echo -n No incoming blocks... ; fi

		CKPTRUNFIREWALL=" runfirewall: ipfwadm nooutgoing" ; #ckpt $CKPTRUNFIREWALL
		if [ -n "$NOOUTGOING" ] && [ -n "$OUTGOINGINTERFACES" ]; then
			echo -n Outgoing blocks...
			for OUTSIDEIF in $OUTGOINGINTERFACES ; do
				for BLOCKPROTO in $NOOUTGOING ; do
					case $BLOCKPROTO in
					*.*/[Ii][Cc][Mm][Pp])
						ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPBOTH##*.} 	#Cannot do subcode on ipfwadm icmp.
						$IPFWADMBIN -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 $ICMPCODE $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0107				;;
					*/[Ii][Cc][Mm][Pp])	$IPFWADMBIN -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0108				;;
					#*/*)			$IPFWADMBIN -O -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0109	;;
					#*)				$IPFWADMBIN -O -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0110							;;
					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
		#
		CKPTRUNFIREWALL=" runfirewall: ipfwadm baserules" ; #ckpt $CKPTRUNFIREWALL
		echo -n Fixed rules...
		. $BASERULEFILE

		if [ "$1" = "LEARN" ] || [ "$1" = "learn" ]; then
			CKPTRUNFIREWALL=" runfirewall: ipfwadm newrules" ; #ckpt $CKPTRUNFIREWALL
			echo -n New rules...
			. $NEWRULEFILE
		fi
		set -e

		if [ "$1" = "LEARN" ] || [ "$1" = "learn" ]; then
			#Finally, log everything else.
			CKPTRUNFIREWALL=" runfirewall: ipfwadm logging" ; #ckpt $CKPTRUNFIREWALL
			echo -n Adding logging rules...
			for ACHAIN in I O F ; do
				$IPFWADMBIN -$ACHAIN -a $LOGGINGPOLICY -o || logfail $LINENO masonlib: YYYY 0111
				$IPFWADMBIN -$ACHAIN -p $DEFAULTPOLICY || logfail $LINENO masonlib: YYYY 0112
			done
		else
			CKPTRUNFIREWALL=" runfirewall: ipfwadm policy" ; #ckpt $CKPTRUNFIREWALL
			for ACHAIN in I O F ; do
				$IPFWADMBIN -$ACHAIN -p $DEFAULTPOLICY || logfail $LINENO masonlib: YYYY 0113
			done
		fi

		echo Done!
	else
		CKPTRUNFIREWALL=" runfirewall: neither ipchains nor ipfwadm supported." ; #ckpt $CKPTRUNFIREWALL
		echo This kernel supports neither ipchains nor ipfwadm! >/dev/stderr
	fi
	CKPTRUNFIREWALL=""
} #End of runfirewall


#Compatibility wrappers:
#-------------------------------------------------------------------------
#Start up a firewall from scratch.  Use both baserules and newrules.
#-------------------------------------------------------------------------
runlearnfirewall () {
	echo "Please use \"runfirewall LEARN\" instead of runlearnfirewall" >/dev/stderr
	runfirewall LEARN
} #End of runlearnfirewall
#-------------------------------------------------------------------------
#Start up a firewall from scratch.  Only use baserules.
#-------------------------------------------------------------------------
runstandardfirewall () {
	echo "Please use \"runfirewall STANDARD\" instead of runstandardfirewall" >/dev/stderr
	runfirewall STANDARD
} #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 ) || logfail $LINENO masonlib: YYYY 0114`"
		#Mason will not be manipulating /etc/services.
		#SERVICELINE="`grep "[[:space:]]$1/$2" $SERVICES | head -n 1 || logfail $LINENO masonlib: YYYY 0115`"
		#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 || logfail $LINENO masonlib: YYYY 0116`" ]; then		# $1 is already converted to text and a server port
		#FIXME - is the above check all that is needed?
		#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 () {
	#FIXME - should this be 'trap 0'?
	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 CKPTRUNFIREWALL \
	 CKPTSETTOS CKPTSORTRULEFILE \
	 CKPTUNIQRULEFILE CKPTUPDATECOUNTS CKPTNETWORKOF || :
	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 () {
	#FIXME - can we set TOS on iptables?
	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.
		#I also specifically don't check to see whether this is an output rule.  It's overkill to 
		#set if on in, out, _and_ forward, but the user might only be generating input rules with Mason.
		case "$2/$3" in
		"$IRC_BEGIN:$IRC_END/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x10"	;;	#IRC				Minimize delay
		"$TRACEROUTE_BEGIN:$TRACEROUTE_END/[Uu][Dd][Pp]")
							TOS=" -t 0x01 0x10" ;;	#Traceroute			Minimize delay
		esac
		case "$1/$3" in
		"21/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x10"	;;	#FTP				Minimize delay
		"23/[Tt][Cc][Pp]"|"22/[Tt][Cc][Pp]"|"513/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x10"	;;	#Telnet,SSH,rlogin	Minimize delay
		"53/[Uu][Dd][Pp]")
							TOS=" -t 0x01 0x10"	;;	#dns				Minimize delay
		"69/[Uu][Dd][Pp]")
							TOS=" -t 0x01 0x10"	;;	#tftp				Minimize delay
		"20/[Tt][Cc][Pp]"|"25/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x08"	;;	#FTP-data,SMTP		Maximize throughput
		"53/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x08"	;;	#DNS zone transfer	Maximize throughput
		"80/[Tt][Cc][Pp]"|"443/[Tt][Cc][Pp]"|"563/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x08"	;;	#Web & secure web	Maximize throughput
		"8080/[Tt][Cc][Pp]"|"3128/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x08"	;;	#Web Caches			Maximize throughput
		"161/[Uu][Dd][Pp]")
							TOS=" -t 0x01 0x04"	;;	#SNMP				Maximize reliability
		"119/[Tt][Cc][Pp]"|"110/[Tt][Cc][Pp]"|"143/[Tt][Cc][Pp]")
							TOS=" -t 0x01 0x02"	;;	#NNTP,POP3,IMAP		Minimize cost
		esac
	fi

	#FIXME - iptables
	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 || logfail $LINENO masonlib: YYYY 0117 ; 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 || logfail $LINENO masonlib: YYYY 0118 ; 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 || logfail $LINENO masonlib: YYYY 0119
		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 || logfail $LINENO masonlib: YYYY 0120
				else
					cat $ONEFILE.$SECTION >>$ONEFILE.new || logfail $LINENO masonlib: YYYY 0121
				fi
				rm -f $ONEFILE.$SECTION || logfail $LINENO masonlib: YYYY 0122
			fi
		done
		cat $ONEFILE.new >$ONEFILE || logfail $LINENO masonlib: YYYY 0123
		rm -f $ONEFILE.new || logfail $LINENO masonlib: YYYY 0124
	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 || logfail $LINENO masonlib: YYYY 0125
	#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 || logfail $LINENO masonlib: YYYY 0126
	cat $1.sorted >$1 || logfail $LINENO masonlib: YYYY 0127			#This preserves the permissions of fwrules
	rm -f $1.sorted || logfail $LINENO masonlib: YYYY 0128
	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
	#FIXME - update for iptables
	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 || logfail $LINENO masonlib: YYYY 0129` ; 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}' || logfail $LINENO masonlib: YYYY 0130` ; 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 || logfail $LINENO masonlib: YYYY 0131
			CURRENTCOUNT=$NEWCOUNT
		fi
		DUPMARKS=`ipchains -L -n -x -v | cut -b 1-9,66-75 - | grep '0x' | awk '{print $2}' | sort | uniq -d || logfail $LINENO masonlib: YYYY 0132`
		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




