#!/bin/bash
#A library of functions and subroutines for Mason
#Copyright 1999-2001, 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: 0149, use 0150 next

if [ -f /usr/lib/samlib/samlib ]; then
	. /usr/lib/samlib/samlib
else
	echo "/usr/lib/samlib/samlib is missing - please get it from" >/dev/stderr
	echo "http://www.stearns.org/samlib/" >/dev/stderr
	echo "Exiting." >/dev/stderr
	exit 1
fi
for ONEFUNC in askYN encompassingnetworkof ipeq iple iplt ipof isdigits \
 isnumericip mask2bits mask2cisco networksoverlap seqfunc wrap ; do
	if ! type $ONEFUNC >/dev/null 2>/dev/null ; then
		echo "Missing $ONEFUNC , please update samlib from" >/dev/stderr
		echo "http://www.stearns.org/samlib/" >/dev/stderr
		echo "Exiting." >/dev/stderr
		exit 1
	fi
done

MASONVER="1.0.0, 5/12/2002"

#-------------------------------------------------------------------------
# addcounts procedure, adds the packet counts to the rules in a file.
#-------------------------------------------------------------------------
addcounts () {	#SUDO checked
#Params: $* is/are the filespec(s) for the files that need counts added.
	CKPTADDCOUNTS=" addcounts: Start $*" ; #ckpt $CKPTADDCOUNTS
	#FIXME - test for iptables  || [ -n "`lsmod | grep '^ip_tables '`" ]		#Hmmm... will iptables have mark values?
	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=""
		#FIXME - $* instead of $1?
		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
					wrap ${WARN}Warning - the following marks are used more than once in $ONEFILE:${NORM} >/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
					wrap ${WARN}This will give incorrect packet counts.${NORM} >/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 () {	#SUDO checked
	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 () {	#SUDO checked
#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


#-------------------------------------------------------------------------
# catchall procedure.  Catch every darn signal.  Because I'm _really_
# tired of getting random children nuked.
#-------------------------------------------------------------------------
catchall () {	#SUDO checked
    #All signals except SIGKILL are caught.
    trap 'logger SIGHUP'    SIGHUP
    trap 'logger SIGINT'    SIGINT
    trap 'logger SIGQUIT'   SIGQUIT
    trap 'logger SIGILL'    SIGILL
    trap 'logger SIGTRAP'   SIGTRAP
#Warning.  BIG Sandbox talk.
#Who the &(%@ decided that SIGIOT needed to be renamed?
#Renamed?  You've _got_ to be kidding me.
#We now have to poll for the name of signal 6.
#I absolutely refuse to apologize for the following kludge; trap should accept
#both the old and the new name.
#GRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR!
#    trap 'logger SIGIOT'    SIGIOT
#OK, this is overkill, just use the "trap on 6 that follows
#    trap 'logger SIGIOT'    `kill -l | grep '\W6)' | sed -e 's/.*\W6)//' | awk '{print $1}'`
    trap 'logger SIGIOT'    6
    trap 'logger SIGBUS'    SIGBUS
    trap 'logger SIGFPE'    SIGFPE
    trap 'logger SIGUSR1'   SIGUSR1
    trap 'logger SIGSEGV'   SIGSEGV
    trap 'logger SIGUSR2'   SIGUSR2
    trap 'logger SIGPIPE'   SIGPIPE
    trap 'logger SIGALRM'   SIGALRM
    trap 'logger SIGTERM'   SIGTERM
    trap 'logger SIGCHLD'   SIGCHLD
    trap 'logger SIGCONT'   SIGCONT
    trap 'logger SIGSTOP'   SIGSTOP
    trap 'logger SIGTSTP'   SIGTSTP
    trap 'logger SIGTTIN'   SIGTTIN
    trap 'logger SIGTTOU'   SIGTTOU
    trap 'logger SIGURG'    SIGURG
    trap 'logger SIGXCPU'   SIGXCPU
    trap 'logger SIGXFSZ'   SIGXFSZ
    trap 'logger SIGVTALRM' SIGVTALRM
    trap 'logger SIGPROF'   SIGPROF
    trap 'logger SIGWINCH'  SIGWINCH
    trap 'logger SIGIO'     SIGIO 
    trap 'logger SIGPWR'    SIGPWR
} #End of catchall


#-------------------------------------------------------------------------
# chainnameof function, returns the form of the chain appropriate for the given DOCOMMAND
#-------------------------------------------------------------------------
chainnameof () {	#SUDO checked
	if [ "$1" = "" ]; then
		wrap ${WARN}Missing chain name in chainnameof.${NORM} >/dev/stderr
	else
		case $DOCOMMAND in
		[Ii][Pp][Ff][Ww][Aa][Dd][Mm])
			case $1 in
			[Ii]*)								echo "-I"				;;
			[Ff]*)								echo "-F"				;;
			[Oo]*)								echo "-O"				;;
			esac													;;
		[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])
			case $1 in
			[Ii][Nn][Pp][Uu][Tt])				echo "input"			;;
			[Ff][Oo][Rr][Ww][Aa][Rr][Dd])		echo "forward"			;;
			[Oo][Uu][Tt][Pp][Uu][Tt])			echo "output"			;;
			*)									echo "$1"				;;
			esac													;;
		[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])
			case $1 in
			[Ii][Nn][Pp][Uu][Tt])				echo "INPUT"			;;
			[Ff][Oo][Rr][Ww][Aa][Rr][Dd])		echo "FORWARD"			;;
			[Oo][Uu][Tt][Pp][Uu][Tt])			echo "OUTPUT"			;;
			*)									echo "$1"				;;
			esac													;;
		[Nn][Oo][Nn][Ee])					:	 					;;
		esac #Case docommand
	fi
} #End of chainnameof




#-------------------------------------------------------------------------
#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"}
	MASONDECIDE=${MASONDECIDE:-"/usr/bin/mason-decide"}

	CKPTCHECKCONF=" checkconf: Set up ANSI escape codes" ; #ckpt $CKPTCHECKCONF
	if [ "$USEANSI" != "NO" ]; then
		      ENH="-e"
		    BLACK="\033[1;30m"
		      RED="\033[1;31m"
		    GREEN="\033[1;32m"
		   YELLOW="\033[1;33m"
		     BLUE="\033[1;34m"
		     PINK="\033[1;35m"
		TURQUOISE="\033[1;36m"
		     NORM="\033[1;37m"
		   BRIGHT="\033[1;39m"
	else
		      ENH=""
		    BLACK=""
		      RED=""
		    GREEN=""
		   YELLOW=""
		     BLUE=""
		     PINK=""
		TURQUOISE=""
		     NORM=""
		   BRIGHT=""
	fi
	   KEY="$GREEN"
 	  WARN="$RED"
	HEADER="$TURQUOISE"

#Ipnatctl isn't used any more.
#	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'
#			wrap ${WARN}ipnatctl was not found in your path or in /usr/local/bin. You may need to copy it or add an explicit path to it in the following commands.${NORM} >/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'
			wrap ${WARN}iptables was not found in your path, in /usr/local/bin or in /sbin. You may need to copy it or add an explicit path to it in the following commands.${NORM} >/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'
			wrap ${WARN}ipchains was not found in your path or in /sbin. You may need to copy it or add an explicit path to it in the following commands.${NORM} >/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'
			wrap ${WARN}ipfwadm was not found in your path or in /sbin. You may need to copy it or add an explicit path to it in the following commands.${NORM} >/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"}

	DEFROUTEIFS=`/sbin/route -n | grep '^0\.0\.0\.0[ \t]' | awk '{print $8}' | sort | uniq || logfail $LINENO masonlib: YYYY 0017`
	INCOMINGINTERFACES=${INCOMINGINTERFACES:-$DEFROUTEIFS}
	OUTGOINGINTERFACES=${OUTGOINGINTERFACES:-$DEFROUTEIFS}

	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"		;;
	*)	wrap ${WARN}WARNING! NEWRULEPOLICY is neither accept, reject, nor deny in $MASONCONF.${NORM}  >/dev/stderr
		while [ "$LCPOLICY" != "accept" ] && [ "$LCPOLICY" != "reject" ] && [ "$LCPOLICY" != "deny" ] ; do
			wrap Please choose ${KEY}accept${NORM}, ${KEY}reject${NORM}, or ${KEY}deny${NORM}: >/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
		if echo -n $ENH "Shall I write this value to $MASONCONF(${KEY}Y${NORM}/${KEY}N${NORM})" >/dev/stderr ; askYN >/dev/stderr ; then
			echo "NEWRULEPOLICY=$NEWRULEPOLICY" >>$MASONCONF
		fi
		wrap 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"	;;
	*)	wrap ${WARN}WARNING! DEFAULTPOLICY is neither accept, reject, nor deny in $MASONCONF.${NORM}  >/dev/stderr
		while [ "$DEFAULTPOLICY" != "accept" ] && [ "$DEFAULTPOLICY" != "reject" ] && [ "$DEFAULTPOLICY" != "deny" ] ; do
			wrap Please choose ${KEY}accept${NORM}, ${KEY}reject${NORM}, or ${KEY}deny${NORM}: >/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
		if echo -n $ENH "Shall I write this value to $MASONCONF(${KEY}Y${NORM}/${KEY}N${NORM})" ; askYN ; then
			echo "DEFAULTPOLICY=$DEFAULTPOLICY" >>$MASONCONF
		fi
		wrap 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"
		elif [ -n "`lsmod | grep '^ip_tables '`" ]; then		ECHOCOMMAND="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
			wrap ${WARN}WARNING! User has requested ipfwadm, but it appears to be unavailable. Proceeding, but this is not likely to work.${NORM} >/dev/stderr
			sleep 10
		fi
		if [ ! -x "$IPFWADMBIN" ]; then
			wrap ${WARN}WARNING! User has requested ipfwadm, but $IPFWADMBIN is not executable. Proceeding, but this is not likely to work.${NORM} >/dev/stderr
			sleep 10
		fi																				;;
	[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])
		DOCOMMAND="ipchains"
		if [ ! -f /proc/net/ip_fwchains ]; then
			wrap ${WARN}WARNING! User has requested ipchains, but it appears to be unavailable. Proceeding, but this is not likely to work.${NORM} >/dev/stderr
			sleep 10
		fi
		if [ ! -x "$IPCHAINSBIN" ]; then
			wrap ${WARN}WARNING! User has requested ipchains, but $IPCHAINSBIN is not executable. Proceeding, but this is not likely to work.${NORM} >/dev/stderr
			sleep 10
		fi																				;;
	[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])
		DOCOMMAND="iptables"
		#FIXME - how to reliably test for kernel iptables support
		#if [ -z "`lsmod | grep '^ip_tables '`" ]; then
		#	wrap ${WARN}WARNING! User has requested iptables, but it appears to be unavailable. Proceeding, but this is not likely to work.${NORM} >/dev/stderr
		#	sleep 10
		#fi
		if [ ! -x "$IPTABLESBIN" ]; then
			wrap ${WARN}WARNING! User has requested iptables, but $IPTABLESBIN is not executable. Proceeding, but this is not likely to work.${NORM} >/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
				wrap ${WARN}WARNING! This kernel uses ipchains, but $IPCHAINSBIN is not executable. Proceeding, but this is not likely to work. Please get a copy of the ipchains binary and place it in /sbin .${NORM} >/dev/stderr
				sleep 10
			fi
		elif [ -f /proc/net/ip_input ]; then
			DOCOMMAND="ipfwadm"
			if [ ! -x "$IPFWADMBIN" ]; then
				wrap ${WARN}WARNING! This kernel uses ipfwadm, but $IPFWADMBIN is not executable. Proceeding, but this is not likely to work. Please get a copy of the ipfwadm binary and place it in /sbin .${NORM} >/dev/stderr
				sleep 10
			fi
		#FIXME - find reliable test for kernel iptables support.
		#elif [ -n "`lsmod | grep '^ip_tables '`" ]; then
		else
			DOCOMMAND="iptables"
			if [ ! -x "$IPTABLESBIN" ]; then
				wrap ${WARN}WARNING! This kernel uses iptables, but $IPTABLESBIN is not executable. Proceeding, but this is not likely to work. Please get a copy of the iptables binary and place it in /sbin .${NORM} >/dev/stderr
				sleep 10
			fi
		#else
		#	DOCOMMAND="none"				#Well, we cant _do_ any!
		#	wrap ${WARN}WARNING! ipchains, ipfwadm and iptables appear to be unavailable. Proceeding anyways.${NORM} >/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"
			#I believe that the spoof blocking is now safe even in the case of overlapping routes.
			#The only dangerous case is where packets arrive from a network not in the routing table 
			#for that interface - including asymmetric routing setups like one way satellite/cable.
			#Even in that case, you can add a specific or default route to that network by hand...
			#if routesoverlap ; then
			#	wrap ${WARN}Warning! - Spoof blocking has been requested, but the following entries in your routing table overlap and point to different interfaces:${NORM} >/dev/stderr
			#	echo $OVERLAPPINGROUTES >/dev/stderr
			#	wrap ${WARN}Continuing, but communication from machines in the overlapping portion will be disrupted.${NORM} >/dev/stderr
			#	sleep 20
			#fi
		else
			wrap 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"		;;
	*)
		SPOOFBLOCKS="YES"
		#See above note.
		#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
			wrap ${WARN}The \"host\" utility is not available for resolving IP addresses into hostnames. Until this is available, Mason will only use /etc/hosts for resolution. This warning can be disabled by setting HOSTLOOKUP=\"FILESONLY\" in /etc/masonrc .${NORM} >/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)	wrap ${WARN}$ONENET is not a valid network for generalization.${NORM} >/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
						wrap ${WARN}Unable to determine the netmask for $ONENET. Please put an entry in the form network-broadcast/netmask in the NETWORKS variable in $MASONCONF .${NORM} >/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 once iptables supports mark values.
	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
				wrap Editor default of $EDITOR taken. >/dev/stderr
			fi
		done
		unset TRYEDITOR || :
		if [ -z "$EDITOR" ]; then
			wrap ${WARN}No editor was specified by the EDITOR= variable and this script was unable to find mcedit, pico, vi, jove, nedit or emacs on your system. Please set EDITOR=the_name_of_an_editor in $MASONCONF or your environment and re-start.${NORM} >/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
		wrap ${WARN}WARNING! Proc filesystem not supported or not mounted. Please fix and restart.${NORM} >/dev/stderr
		sleep 10
		exit 0
	fi

	if [ ! -f /proc/net/ip_fwchains ] && [ ! -f /proc/net/ip_input ] && [ -z "`lsmod | grep '^ip_tables '`" ]; then
		wrap ${WARN}This kernel does not support ipchains, ipfwadm or iptables!${NORM} >/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?). is lsmod in LSB?
	#FIXME - fall back on "ip route", etc.?
	for ONEUTIL in awk bash cat chmod cut grep head ifconfig lsmod 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
		wrap ${WARN}The following tool/tools do not appear to be available on this system:${NORM} >/dev/stderr
		wrap $MISSINGUTILS >/dev/stderr
		wrap ${NORM}You should try to get these before continuing. Press Ctrl-C to fix this, or wait 10 seconds if you want to try continuing anyways - cross your fingers.${NORM} >/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"
		wrap ${WARN}Note: The following directory/directories was/were not included in your PATH variable: \"$MISSINGPATH\"${NORM} >/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=`ipof $ONEIF || 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
			if [ -z "$MASONDIR" ]; then
				wrap ${WARN}Warning - MASONDIR unset in masonlib in checksys.${NORM} >/dev/stderr
			fi
			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
			wrap ${WARN}WARNING! User has requested ipchains, but it appears to be unavailable. Proceeding, but this is not likely to work.${NORM} >/dev/stderr
			sleep 10
		fi
		if [ ! -x "$IPCHAINSBIN" ]; then
			wrap ${WARN}WARNING! User has requested ipchains, but $IPCHAINSBIN is not executable. Proceeding, but this is not likely to work.${NORM} >/dev/stderr
			sleep 10
		fi
		if [ -n "$NOLOGSUFFIX" ]; then
			for ONECHAIN in `chainnameof input` `chainnameof output` `chainnameof 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=""
						wrap ${WARN}The $ONECHAIN chain exists without a corresponding $ONECHAIN$NOLOGSUFFIX chain. For the moment, the \"nolog\" feature will revert to sticking the rules at the top of the original chain.${NORM} >/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
		wrap ${WARN}Warning: at least one of your interfaces is in promiscuous mode. You are likely to create a lot of rules you did not want. Unless you know this is what you want, you should turn off promiscuous mode on all interfaces. Press Ctrl-c now or this will continue in 15 seconds.${NORM} >/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 () {	#SUDO checked
	#I don't make an exception for auth=113/tcp here as we'd never hit this function with a "client" port in /etc/services.
	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 -le 1023 ]; then
			CPRRETVAL="0:1023"
		elif [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "MASQ" ] && [ $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" ]; then
			CPRRETVAL="1024:65535"
		elif [ "$GENERALIZETCPACK" = "YES" ] && [ "$PRPROTO" = "tcp" ] && [ "$ACKFLAG" = "! -y" ] && [ "$UCPOLICY" = "MASQ" ] && [ $CLIENTPORT -ge "1024" ]; 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													;;
#Some nat boxes replace the client port with a port below 1023 on a dns lookup.  Ugh.
			#FIXME - do we need to do this for tcp too?
			53/[Uu][Dd][Pp]|[Dd][Oo][Mm][Aa][Ii][Nn]/[Uu][Dd][Pp]|[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/[Uu][Dd][Pp])
				if [ $CLIENTPORT -eq 53 ]; then
					CPRRETVAL="53"
				elif [ $CLIENTPORT -ge 20 ] && [ $CLIENTPORT -le 1023 ]; then
					CPRRETVAL="20:1023"
				elif [ $CLIENTPORT -le 1023 ]; then	#We're down into the chargen/echo range.  Ugh.
					CPRRETVAL="$CLIENTPORT"
				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 () {	#SUDO checked
	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


#-------------------------------------------------------------------------
# dorule procedure, adds, inserts, or deletes a rule to/from the running firewall.
#-------------------------------------------------------------------------
dorule () {
#Remember positional parameters >=10 need to be in braces.
#Parameters - order is important! :
#1. action: AaIiDdFfNnPp (required) (F and N only use $2=chain, P uses $2=chain and ${12}=target)
#2. chain or direction (required)
#3. interface, or incoming interface for iptables. (optional)
#4. null, or outgoing interface for iptables. (optional)
#5. protocol lowercase name or number (optional)
#6. source address (optional)
#7. source port (optional)
#8. dest ip (optional)
#9. dest port (optional)
#10. mark value (optional)
#11. ack/syn (optional)
#12. target/action (required - or is it?  "Accounting" rules?)
#13. TOS string (optional, enclose in quotes)
#14. log rule (non-null means log, null means don't)
#15. special iptables match string (optional) (future: or just additional stuff)

#FIXME - specifically check for return code and at least log problems.
#FIXME - log anomilies in input parameters.

#dorule "AID" "chaindir" "inif" "outif" "proto" "sip" "sport" "dip" "dport" "mark" "synack" "action" "tos" "log" "matchorstuff"
#dorule "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""

	#REMOVEME - DEBUG
	#echo 1 $1 2 $2 3 $3 4 $4 5 $5 6 $6 7 $7 8 $8 9 $9 10 ${10} 11 ${11} 12 ${12} 13 ${13} 14 ${14} 15 ${15} >>${MASONDIR}masoncrash
	if [ -d ${MASONDIR}debug ]; then	#Internal debugging
		echo $1    >>${MASONDIR}debug/1
		echo $2    >>${MASONDIR}debug/2
		echo $3    >>${MASONDIR}debug/3
		echo $4    >>${MASONDIR}debug/4
		echo $5    >>${MASONDIR}debug/5
		echo $6    >>${MASONDIR}debug/6
		echo $7    >>${MASONDIR}debug/7
		echo $8    >>${MASONDIR}debug/8
		echo $9    >>${MASONDIR}debug/9
		echo ${10} >>${MASONDIR}debug/10
		echo ${11} >>${MASONDIR}debug/11
		echo ${12} >>${MASONDIR}debug/12
		echo ${13} >>${MASONDIR}debug/13
		echo ${14} >>${MASONDIR}debug/14
		echo ${15} >>${MASONDIR}debug/15
	fi

	unset CHAINTARGET || :
	case $DOCOMMAND in
	#FIXME drop, reject, masq, redirect, return, specific_chain, queue, LOG and other module specific targets?
	#FIXME - _each_ of the input targets has to be handled in each of the firewall types.
	[Ii][Pp][Ff][Ww][Aa][Dd][Mm])
		#Valid targets: accept, deny, reject, "accept -m", "-r port"
		case ${12} in
		[Aa][Cc][Cc][Ee][Pp][Tt])			CHAINTARGET="accept"		;;
		[Rr][Ee][Jj][Ee][Cc][Tt])			CHAINTARGET="reject"		;;
		[Dd][Ee][Nn][Yy]|[Dd][Rr][Oo][Pp])		CHAINTARGET="deny"		;;
		#FIXME - Handle case of $12=INPUTN or other.
		esac														;;
	[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])
		#Valid targets: ACCEPT, DENY, REJECT, MASQ, REDIRECT, "REDIRECT 0", "REDIRECT port", RETURN, user chains, none at all.
		case ${12} in
		[Aa][Cc][Cc][Ee][Pp][Tt])			CHAINTARGET="ACCEPT"		;;
		[Rr][Ee][Jj][Ee][Cc][Tt])			CHAINTARGET="REJECT"		;;
		[Dd][Ee][Nn][Yy]|[Dd][Rr][Oo][Pp])		CHAINTARGET="DENY"		;;
		[Rr][Ee][Tt][Uu][Rr][Nn])			CHAINTARGET="RETURN"		;;
		esac														;;
	[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])
		#Valid targets: ACCEPT, DROP, QUEUE, RETURN, LOG, none at all.
		case ${12} in
		[Aa][Cc][Cc][Ee][Pp][Tt])			CHAINTARGET="ACCEPT"		;;
		[Rr][Ee][Jj][Ee][Cc][Tt])			CHAINTARGET="REJECT"		;;
		[Dd][Ee][Nn][Yy]|[Dd][Rr][Oo][Pp])	CHAINTARGET="DROP"			;;
		[Rr][Ee][Tt][Uu][Rr][Nn])			CHAINTARGET="RETURN"		;;
		[Ll][Oo][Gg])						CHAINTARGET="LOG"			;;
#FIXME - Temporary crutches
		NoSpoof)							CHAINTARGET="NoSpoof"		;;
		INPUTN)								CHAINTARGET="INPUTN"		;;
		OUTPUTN)							CHAINTARGET="OUTPUTN"		;;
		FORWARDN)							CHAINTARGET="FORWARDN"		;;
		esac														;;
	[Nn][Oo][Nn][Ee])					:	 						;;
	esac #Case docommand

	case $1 in
	[Ff]*)
		case $DOCOMMAND in
		[Ii][Pp][Ff][Ww][Aa][Dd][Mm])			$IPFWADMBIN `chainnameof $2` -f || logfail $LINENO masonlib: YYYY 0138			;;
		[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])		$IPCHAINSBIN -F `chainnameof $2` || logfail $LINENO masonlib: YYYY 0139			;;
		[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])		$IPTABLESBIN -F `chainnameof $2` || logfail $LINENO masonlib: YYYY 0140			;;
		[Nn][Oo][Nn][Ee])				:											;;
		esac 																		;; #Case docommand
	[Nn]*)
		case $DOCOMMAND in
		[Ii][Pp][Ff][Ww][Aa][Dd][Mm])			:												;; #Not possible
		[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])		$IPCHAINSBIN -N `chainnameof $2` || logfail $LINENO masonlib: YYYY 0141			;;
		[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])		$IPTABLESBIN -N `chainnameof $2` || logfail $LINENO masonlib: YYYY 0142			;;
		[Nn][Oo][Nn][Ee])				:											;;
		esac 																		;; #Case docommand
	[Pp]*)
		case $DOCOMMAND in
		[Ii][Pp][Ff][Ww][Aa][Dd][Mm])			$IPFWADMBIN `chainnameof $2` -p $CHAINTARGET || logfail $LINENO masonlib: YYYY 0143	;;
		[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])		$IPCHAINSBIN -P `chainnameof $2` $CHAINTARGET || logfail $LINENO masonlib: YYYY 0144	;;
		[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])		$IPTABLESBIN -P `chainnameof $2` $CHAINTARGET || logfail $LINENO masonlib: YYYY 0145	;;
		[Nn][Oo][Nn][Ee])				:											;;
		esac																		;; #Case docommand
	*)
		case $DOCOMMAND in
		[Ii][Pp][Ff][Ww][Aa][Dd][Mm])	#FIXME - handle insert if ipfwadm case
			case $1 in
			[Aa]*)					BUILDRULE="$IPFWADMBIN -a"				;;
			[Ii]*)					BUILDRULE="$IPFWADMBIN -i"				;;
			[Dd]*)					BUILDRULE="$IPFWADMBIN -d"				;;
			esac
			BUILDRULE="$BUILDRULE $CHAINTARGET"
			if [ -n "$3$4" ]; then			BUILDRULE="$BUILDRULE -W $3$4" ;	fi
			BUILDRULE="$BUILDRULE `chainnameof $2`"
			if [ -n "$5" ]; then			BUILDRULE="$BUILDRULE -P $5" ;		fi
			if [ -n "$6" ]; then			BUILDRULE="$BUILDRULE -S $6 $7" ;	else BUILDRULE="$BUILDRULE -S 0/0 $7" ; fi
			case $5 in	#drop icmp subcode in dest port for ipfwadm.
			[Ii][Cc][Mm][Pp])	if [ -n "$8" ]; then	BUILDRULE="$BUILDRULE -D $8" ;	fi												;;
			*)					if [ -n "$8" ]; then	BUILDRULE="$BUILDRULE -D $8 $9" ;	else BUILDRULE="$BUILDRULE -D 0/0 $9" ; fi	;;
			esac
			case "${11}" in
			"-y"|"! -k"|"--syn")			BUILDRULE="$BUILDRULE -y"				;;
			"! -y"|"-k"|"! --syn")			BUILDRULE="$BUILDRULE -k"				;;
			esac
			if [ -n "${13}" ]; then			BUILDRULE="$BUILDRULE -t ${13}" ;			fi
			if [ -n "${14}" ]; then			BUILDRULE="$BUILDRULE -o" ;				fi
			eval "$BUILDRULE" || logfail $LINENO masonlib: YYYY 0146
			;;
		[Ii][Pp][Cc][Hh][Aa][Ii][Nn][Ss])
			case $1 in
			[Aa]*)					BUILDRULE="$IPCHAINSBIN -A `chainnameof $2`"		;;
			[Ii]*)					BUILDRULE="$IPCHAINSBIN -I `chainnameof $2` 1"	;;
			[Dd]*)					BUILDRULE="$IPCHAINSBIN -D `chainnameof $2`"		;;
			esac
			if [ -n "$3$4" ]; then			BUILDRULE="$BUILDRULE -i $3$4" ;			fi
			if [ -n "$5" ]; then			BUILDRULE="$BUILDRULE -p $5" ;				fi
			if [ -n "$6$7" ]; then	#If either has content
				if [ -n "$6" ]; then		BUILDRULE="$BUILDRULE -s $6 $7" ;			else BUILDRULE="$BUILDRULE --sport $7" ; fi
			fi
			if [ -n "$8$9" ]; then
				if [ -n "$8" ]; then		BUILDRULE="$BUILDRULE -d $8 $9" ;			else BUILDRULE="$BUILDRULE --dport $9" ; fi
			fi
			if [ -n "${10}" ]; then			BUILDRULE="$BUILDRULE -m ${10}" ;			fi
			case "${11}" in
			"-y"|"! -k"|"--syn")			BUILDRULE="$BUILDRULE -y"				;;
			"! -y"|"-k"|"! --syn")			BUILDRULE="$BUILDRULE ! -y"				;;
			esac
			if [ -n "$CHAINTARGET" ]; then		BUILDRULE="$BUILDRULE -j $CHAINTARGET" ;	fi
			if [ -n "${13}" ]; then			BUILDRULE="$BUILDRULE -t ${13}" ;	fi
			if [ -n "${14}" ]; then			BUILDRULE="$BUILDRULE -l" ;			fi
			eval "$BUILDRULE" || logfail $LINENO masonlib: YYYY 0147
			;;
		[Ii][Pp][Tt][Aa][Bb][Ll][Ee][Ss])
			#FIXME - Check for missing $2?
			case $1 in
			[Aa]*)								BUILDRULE="$IPTABLESBIN -A `chainnameof $2`"		;;
			[Ii]*)								BUILDRULE="$IPTABLESBIN -I `chainnameof $2` 1"	;;
			[Dd]*)								BUILDRULE="$IPTABLESBIN -D `chainnameof $2`"		;;
			esac
			if [ -n "$3" ]; then				BUILDRULE="$BUILDRULE -i $3" ;		fi
			if [ -n "$4" ]; then				BUILDRULE="$BUILDRULE -o $4" ;		fi
			if [ -n "$5" ]; then				BUILDRULE="$BUILDRULE -p $5" ;		fi
			if [ -n "$6" ]; then				BUILDRULE="$BUILDRULE -s $6" ;		fi
			if [ -n "$8" ]; then				BUILDRULE="$BUILDRULE -d $8" ;		fi
			case $5 in
			[Ii][Cc][Mm][Pp])
				if [ -n "$7" ]; then
					BUILDRULE="$BUILDRULE --icmp-type $7"
					if [ -n "$9" ]; then				BUILDRULE="$BUILDRULE/$9" ;	fi
				fi
				;;
			*)
				if [ -n "$7" ]; then				BUILDRULE="$BUILDRULE --sport $7" ;	fi
				if [ -n "$9" ]; then				BUILDRULE="$BUILDRULE --dport $9" ;	fi
				;;
			esac
			#if [ -n "${10}" ]; then			BUILDRULE="$BUILDRULE -m ${10}" ;	fi	#FIXME - mark values later?
			case "${11}" in
			"-y"|"! -k"|"--syn")				BUILDRULE="$BUILDRULE --syn"		;;
			"! -y"|"-k"|"! --syn")				BUILDRULE="$BUILDRULE ! --syn"		;;
			esac
			#if [ -n "${13}" ]; then			BUILDRULE="$BUILDRULE -t ${13}" ;	fi	#FIXME - tos values later?
			if [ -n "${14}" ]; then
				eval "$BUILDRULE -j LOG" || logfail $LINENO masonlib: YYYY 0148 $BUILDRULE -j LOG
			fi
			if [ -n "$CHAINTARGET" ]; then		BUILDRULE="$BUILDRULE -j $CHAINTARGET" ;	fi
			#if [ -n "$DEBUG" ]; then echo $BUILDRULE ; fi
			eval $SUDO $BUILDRULE || logfail $LINENO masonlib: YYYY 0149 $BUILDRULE
			;;
		[Nn][Oo][Nn][Ee])
			: ;;
		esac #Case docommand
		;;
	esac #Case $1=action
} #End of dorule



#-------------------------------------------------------------------------
#Flush the existing rules so we start with a clean slate.
#-------------------------------------------------------------------------
flushfirewall () {	#SUDO checked
	CKPTFLUSHFIREWALL=" flushfirewall: Start" ; #ckpt $CKPTFLUSHFIREWALL
	updatecounts
	echo -n Flushing... >/dev/stderr

	#REMOVEME
	#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
	#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
	for ONECHAIN in output forward input ; do
		dorule p "$ONECHAIN" '' '' '' '' '' '' '' '' '' "$FLUSHEDPOLICY" '' '' '' || logfail $LINENO masonlib: 0038/0040/0042/0047/0049/0051
		dorule f "$ONECHAIN" '' '' '' '' '' '' '' '' '' '' '' '' '' || logfail $LINENO masonlib: 0039/0041/0043/0048/0050/0052
	done

	if [ -f /proc/net/ip_fwchains ] || [ -n "`lsmod | grep '^ip_tables '`" ]; then
		#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 `chainnameof output` `chainnameof forward` `chainnameof input` ; do
				flushornewchain "$ONECHAIN$NOLOGSUFFIX"
			done
		fi

		CKPTFLUSHFIREWALL=" flushfirewall: Create or flush NoSpoof chain." ; #ckpt $CKPTFLUSHFIREWALL
		flushornewchain NoSpoof
	fi

	echo Done! >/dev/stderr

	CKPTFLUSHFIREWALL=""
} #End of flushfirewall


#-------------------------------------------------------------------------
#If the chain exists, flush it, otherwise create it.
#-------------------------------------------------------------------------
flushornewchain () {	#SUDO checked
	if [ -n "$1" ]; then
		CHAINNAME="`chainnameof $1`"
		if [ -f /proc/net/ip_fwchains ]; then
			#REMOVEME
			#if [ `$SUDO $IPCHAINSBIN -L -n | grep "^Chain $CHAINNAME" | wc -l` -gt 0 ]; then
			if $SUDO $IPCHAINSBIN -L $CHAINNAME >/dev/null 2>/dev/null ; then	#If chain exists
				$SUDO $IPCHAINSBIN -F $CHAINNAME >/dev/null 2>/dev/null || logfail $LINENO masonlib: 0044/0070/0089/0134 $IPCHAINSBIN -F $CHAINNAME
			else
				$SUDO $IPCHAINSBIN -N $CHAINNAME >/dev/null 2>/dev/null || logfail $LINENO masonlib: 0045/0071/0090 $IPCHAINSBIN -N $CHAINNAME
			fi
		elif [ -n "`lsmod | grep '^ip_tables '`" ]; then
#FIXME, check everywhere.
#if iptables -L -n >/dev/null 2>/dev/null ; then echo iptables successful ; fi
			if $SUDO $IPTABLESBIN -L $CHAINNAME >/dev/null 2>/dev/null ; then	#If chain exists
				$SUDO $IPTABLESBIN -F $CHAINNAME >/dev/null 2>/dev/null || logfail $LINENO masonlib: 0135 $IPTABLESBIN -F $CHAINNAME
			else
				$SUDO $IPTABLESBIN -N $CHAINNAME >/dev/null 2>/dev/null || logfail $LINENO masonlib: 0136 $IPTABLESBIN -N $CHAINNAME
			fi
		fi
	fi
} #End of flushornewchain


#-------------------------------------------------------------------------
# generalportrange function, returns the masq/high/low port range of the given port.
#-------------------------------------------------------------------------
generalportrange () {	#SUDO checked
#We have already tested for isdigits
	  if [ $1 -eq 0 ]; then													echo "0"
	elif [ $1 -eq 113 ]; then												echo "113"
	elif [ $1 -eq 65535 ]; then												echo "65535"
	elif [ $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 () {	#SUDO checked
	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


#-------------------------------------------------------------------------
# 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
		wrap ${WARN}WARNING - Unable to load options, $MASONCONF does not exist.${NORM} >/dev/stderr	#Not a problem if colors unset.
	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
		wrap ${WARN}WARNING! The $NETCACHE file is no longer used by Mason. Please transfer all values from this file to the NETWORKS variable in $MASONCONF.${NORM} >/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?
	wrap "`date` - $MASONVER" >>${TEMPMASONDIR}masoncrash
	case "$1" in
	0|1)										shift	;;
	[0-9]*)	echo -n "Line $1, " >>${TEMPMASONDIR}masoncrash ;	shift	;;
	esac
	wrap Caught failure \($LOGRETVAL\) on: $* >>${TEMPMASONDIR}masoncrash
	return 0 	#True; this makes bash happy
} #End of logfail


#-------------------------------------------------------------------------
# nameof function, returns the hostname from the IP address parameter.
#-------------------------------------------------------------------------
nameof () {	#SUDO checked
#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 () {	#SUDO checked
#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



#-------------------------------------------------------------------------
# oneblockproto procedure, blocks a single protocol from coming in on the given interface.
#-------------------------------------------------------------------------
oneblockproto () {	#SUDO checked
#Parameters: Protocol, (optional)Interface
	case $BLOCKPROTO in			#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
	*.*/[Ii][Cc][Mm][Pp])
		ICMPBOTH=${BLOCKPROTO%%/*} ; ICMPCODE=${ICMPBOTH%%.*} ; ICMPSUBCODE=${ICMPBOTH##*.}
		#REMOVEME
		#$IPCHAINSBIN -I input -i $2 -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0079
		#Cannot do subcode on ipfwadm icmp.
		#$IPFWADMBIN -I -i deny -W $2 -P icmp -S 0/0 $ICMPCODE $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0101
		dorule i input "$2" '' icmp '' "$ICMPCODE" '' "$ICMPSUBCODE" '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0079/0101
		;;
	*/[Ii][Cc][Mm][Pp])
		#REMOVEME
		#$IPCHAINSBIN -I input -i $2 -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0080
		#$IPFWADMBIN -I -i deny -W $2 -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0102
		dorule i input "$2" '' icmp '' "${BLOCKPROTO%%/*}" '' '' '' '' deny '' "$LOGBLOCKS" "" || logfail $LINENO masonlib: YYYY 0080/0102
		;;
	113/[Tt][Cc][Pp]|[Aa][Uu][Tt][Hh]/[Tt][Cc][Pp])
		#REMOVEME
		#$IPCHAINSBIN -I input -i $2 -p tcp -d 0/0 ${BLOCKPROTO%%/*} -y -j REJECT $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0081
		#$IPFWADMBIN -I -i reject -W $2 -P tcp -D 0/0 ${BLOCKPROTO%%/*} -y $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0103
		dorule i input "$2" '' tcp '' '' '' "${BLOCKPROTO%%/*}" '' -y reject '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0081/0103
		;;
	*/[Tt][Cc][Pp])
		#REMOVEME
		#$IPCHAINSBIN -I input -i $2 -p tcp -d 0/0 ${BLOCKPROTO%%/*} -y -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0082
		#$IPFWADMBIN -I -i deny -W $2 -P tcp -D 0/0 ${BLOCKPROTO%%/*} -y $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0104
		dorule i input "$2" '' tcp '' '' '' "${BLOCKPROTO%%/*}" '' -y deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0082/0104
		;;
	*/*)
		#REMOVEME
		#$IPCHAINSBIN -I input -i $2 -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0083
		#$IPFWADMBIN -I -i deny -W $2 -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0105
		dorule i input "$2" '' "${BLOCKPROTO##*/}" '' '' '' "${BLOCKPROTO%%/*}" '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0083/0105
		;;
	*)
		#REMOVEME
		#$IPCHAINSBIN -I input -i $2 -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0084
		#$IPFWADMBIN -I -i deny -W $2 -P ${BLOCKPROTO##*/} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0106
		dorule i input "$2" '' "${BLOCKPROTO##*/}" '' '' '' '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0084/0106
		;;
	esac
} #End of oneblockproto



#-------------------------------------------------------------------------
# port2ciscoport function, returns the individual port or range of 
# ports for the given port/port range and protocol parameters in cisco format.
#-------------------------------------------------------------------------
port2ciscoport () {	#SUDO checked
#Parameters: $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 () {
#ZZZZ
#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
		wrap ${WARN}Abnormal exit from $0 $MASONVER.${NORM}									>/dev/stderr
		wrap The author, William Stearns, would be very grateful if you would email the following information to wstearns@pobox.com, as well as anything else that you think might be relevant. It would help make future versions of mason more stable. The easiest way to do this is to attach ${MASONDIR}masoncrash to a message to wstearns@pobox.com . >/dev/stderr
		echo																	>/dev/stderr
		date																	>/dev/stderr
		wrap Most recent checkpoints:											>/dev/stderr
		wrap $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
		wrap End of checkpoints.												>/dev/stderr
		echo																	>/dev/stderr
		wrap This file was created as a result of a crash of $0 $MASONVER. It was created automatically. Please mail it to wstearns@pobox.com >>${MASONDIR}masoncrash
		date																	>>${MASONDIR}masoncrash
		wrap Most recent checkpoints:											>>${MASONDIR}masoncrash
		wrap $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
		wrap End of checkpoints.												>>${MASONDIR}masoncrash
		echo																	>>${MASONDIR}masoncrash
		if [ -n "$MASONCONF" ]; then
			if [ -e "$MASONCONF" ]; then
				wrap 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
				wrap End of Masonconf.											>>${MASONDIR}masoncrash
			else
				wrap No Masonconf found.										>>${MASONDIR}masoncrash
			fi
		else
			wrap Masonconf environment variable not set.						>>${MASONDIR}masoncrash
		fi
		echo																	>>${MASONDIR}masoncrash
		wrap System details:													>>${MASONDIR}masoncrash
		wrap It is not necessarily a problem if some of these are missing.		>>${MASONDIR}masoncrash
		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
		lsmod																	>>${MASONDIR}masoncrash 2>&1 || :
		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 () {	#SUDO checked
	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 () {	#SUDO checked
	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 () {	#SUDO checked
	#My first pass at spoof blocking failed on the overlapping portion of two networks that arrive on
	#different nics.  The new spoof blocking code handles that case, so this check is no longer needed.
	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 () {	#SUDO checked
#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 () {	#SUDO checked
	#FIXME - add iptables support
	CKPTRUNFIREWALL=" runfirewall: Start" ; #ckpt $CKPTRUNFIREWALL

	#FIXME - use this or not?
	#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
	#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
	#else
	#	CKPTRUNFIREWALL=" runfirewall: neither ipchains nor ipfwadm supported." ; #ckpt $CKPTRUNFIREWALL
	#	wrap ${WARN}This kernel supports neither ipchains nor ipfwadm!${NORM} >/dev/stderr
	#fi

	if [ -f /proc/sys/net/ipv4/ip_forward ]; then
		#If forwarding is disabled _and_ there are two or more interfaces in the system
		if [ "`cat /proc/sys/net/ipv4/ip_forward`" = "0" ] && \
		   [ `ifconfig | cut -b 1-10 | grep -v ':' | grep -v '^lo' | grep -v '^ *$' | wc -l` -ge 2 ]; then
			wrap ${WARN}Please note that forwarding is disabled in the kernel. If this machine is expected to be a router, this should be fixed.${NORM} >/dev/stderr
		fi
	fi

	CKPTRUNFIREWALL=" runfirewall: ipchains/ipfwadm 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
			#REMOVEME
			#$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
			#$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
			dorule i input '' '' '' "$BLOCKEDHOST" '' '' '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0066/0096
			dorule i output '' '' '' "$BLOCKEDHOST" '' '' '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0067/0097
			dorule i input '' '' '' '' '' "$BLOCKEDHOST" '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0068/0098
			dorule i output '' '' '' '' '' "$BLOCKEDHOST" '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0069/0099
		done
	else echo -n No Blockedhost blocks... ; fi

	if [ -f /proc/net/ip_fwchains ] || [ -n "`lsmod | grep '^ip_tables '`" ]; then
		CKPTRUNFIREWALL=" runfirewall: ipchains/iptables 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

			flushornewchain NoSpoof

			#REMOVEME
			#$IPCHAINSBIN -I input -j NoSpoof || logfail $LINENO masonlib: YYYY 0072
			dorule i input '' '' '' '' '' '' '' '' '' "NoSpoof" '' '' '' || logfail $LINENO masonlib: YYYY 0072
			#In iptables, we have to check for spoofing on the forward chain as well.
			if [ -n "`lsmod | grep '^ip_tables '`" ]; then
				dorule i forward '' '' '' '' '' '' '' '' '' "NoSpoof" '' '' '' || logfail $LINENO masonlib: YYYY 0137
			fi

#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.
			#REMOVEME
			#$IPCHAINSBIN -A NoSpoof -i lo -j RETURN || logfail $LINENO masonlib: YYYY 0073
			dorule a NoSpoof lo '' '' '' '' '' '' '' '' return '' '' '' || logfail $LINENO masonlib: YYYY 0073

			#REMOVEME
			##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
#If the packet's network and IP are in the (non-default) routing table, go back to the main firewall.
			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
				#REMOVEME
				#$IPCHAINSBIN -A NoSpoof  -s ${ONEROUTE%%-*}  -i ${ONEROUTE##*-} -j RETURN || logfail $LINENO masonlib: YYYY 0077
				dorule a NoSpoof "${ONEROUTE##*-}" '' '' "${ONEROUTE%%-*}" '' '' '' '' '' return '' '' '' || logfail $LINENO masonlib: YYYY 0077
			done
#Block packets coming from a given local net if they don't come from the nic leading to that net.
			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 0135` ; do
				#REMOVEME
				#$IPCHAINSBIN -A NoSpoof  -s ${ONEROUTE%%-*}  -i ! ${ONEROUTE##*-} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0136
				dorule a NoSpoof "! ${ONEROUTE##*-}" '' '' "${ONEROUTE%%-*}" '' '' '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0136
			done
#If the packet is coming from a default route interface, accept it.
			for ONEROUTE in `route -n | cut -b 1-16,33-48,73-80 | grep '^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*[[:space:]]' | \
			 grep '^0\.0\.0\.0[[:space:]]' | awk '{print $1 "/" $2 "-" $3}' || logfail $LINENO masonlib: YYYY 0137` ; do
				#REMOVEME
			 	#$IPCHAINSBIN -A NoSpoof -i ${ONEROUTE##*-} -j RETURN || logfail $LINENO masonlib: YYYY 0138
				dorule a NoSpoof "${ONEROUTE##*-}" '' '' '' '' '' '' '' '' return '' '' '' || logfail $LINENO masonlib: YYYY 0138
			done
#Finally, if it wasn't caught above, deny it.
			#REMOVEME
			#$IPCHAINSBIN -A NoSpoof -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0139
			dorule a NoSpoof '' '' '' '' '' '' '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0139
		else echo -n Not blocking spoofed packets... ; fi
	elif [ -f /proc/net/ip_input ]; then
		echo -n Not blocking spoofed packets under ipfwadm...
	fi

	CKPTRUNFIREWALL=" runfirewall: ipchains/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
				#REMOVEME
				#$IPCHAINSBIN -I output -i $MASQIF -s $RESNET -j DENY || logfail $LINENO masonlib: YYYY 0078
				#$IPFWADMBIN -O -i deny -W $MASQIF -S $RESNET || logfail $LINENO masonlib: YYYY 0100
				dorule i output '' "$MASQIF" '' "$RESNET" '' '' '' '' '' deny '' '' ''
			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
				oneblockproto $BLOCKPROTO $OUTSIDEIF
			done
		done
	else echo -n No incoming blocks... ; fi

	CKPTRUNFIREWALL=" runfirewall: ipchains/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##*.}
					#REMOVEME
					#$IPCHAINSBIN -I output -i $OUTSIDEIF -p icmp -s 0/0 $ICMPCODE -d 0/0 $ICMPSUBCODE -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0085
					#Cannot do subcode on ipfwadm icmp.
					#$IPFWADMBIN -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 $ICMPCODE $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0107
					dorule i output '' "$OUTSIDEIF" icmp '' "$ICMPCODE" '' "$ICMPSUBCODE" '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0085/0107
					;;
				*/[Ii][Cc][Mm][Pp])
					#REMOVEME
					#$IPCHAINSBIN -I output -i $OUTSIDEIF -p icmp -s 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0086
					#$IPFWADMBIN -O -i deny -W $OUTSIDEIF -P icmp -S 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0108
					dorule i output '' "$OUTSIDEIF" icmp '' "${BLOCKPROTO%%/*}" '' '' '' '' deny '' "$LOGBLOCKS" '' || logfail $LINENO masonlib: YYYY 0086/0108
					;;
				#*/*)	#FIXME - convert over to dorules.
				#	$IPCHAINSBIN -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0087
				#	$IPFWADMBIN -O -i deny -W $OUTSIDEIF -P ${BLOCKPROTO##*/} -D 0/0 ${BLOCKPROTO%%/*} $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0109
				#	;;
				#*)
				#	$IPCHAINSBIN -I output -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS || logfail $LINENO masonlib: YYYY 0088
				#	$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: ipchains/ipfwadm baserules" ; #ckpt $CKPTRUNFIREWALL
	echo -n Fixed rules...
	. $BASERULEFILE

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

	if [ "$1" = "LEARN" ] || [ "$1" = "learn" ]; then
		CKPTRUNFIREWALL=" runfirewall: ipchains/ipfwadm logging rules" ; #ckpt $CKPTRUNFIREWALL
		echo -n Adding logging rules...

		#Finally, create a "nolog' chain for each of the existing chains, have each existing 
		#chain jump to it.
		for ACHAIN in `chainnameof input` `chainnameof output` `chainnameof forward` ; do
			if [ -n "$NOLOGSUFFIX" ]; then
				flushornewchain $ACHAIN$NOLOGSUFFIX
			fi
			#${MINMARK:+"-m"} $MINMARK ; if [ -n "$MINMARK" ]; then MINMARK=$[$MINMARK+1] ; fi
			#REMOVEME
			#$IPCHAINSBIN -A $ACHAIN -j $ACHAIN$NOLOGSUFFIX || logfail $LINENO masonlib: YYYY 0091
#ZZZZ
			dorule a "$ACHAIN" '' '' '' '' '' '' '' '' '' "$ACHAIN$NOLOGSUFFIX" '' '' '' || logfail $LINENO masonlib: YYYY 0091
		done

		#Finally, log everything else.
		for ACHAIN in input output forward ; do
			#REMOVEME
			#$IPCHAINSBIN -A $ACHAIN -l || logfail $LINENO masonlib: YYYY 0092
			#$IPFWADMBIN -$ACHAIN -a $LOGGINGPOLICY -o || logfail $LINENO masonlib: YYYY 0111
			dorule a "$ACHAIN" '' '' '' '' '' '' '' '' '' "$LOGGINGPOLICY" '' "-l" '' || logfail $LINENO masonlib: YYYY 0092/0111
		done
	fi

	CKPTRUNFIREWALL=" runfirewall: ipchains/ipfwadm policy" ; #ckpt $CKPTRUNFIREWALL
	for ACHAIN in input output forward ; do
		#REMOVEME
		#$IPCHAINSBIN -P $ACHAIN $DEFAULTPOLICY || logfail $LINENO masonlib: YYYY 0093/0094
		#$IPFWADMBIN -$ACHAIN -p $DEFAULTPOLICY || logfail $LINENO masonlib: YYYY 0112/0113
		dorule p "$ACHAIN" '' '' '' '' '' '' '' '' '' "$DEFAULTPOLICY" '' '' '' || logfail $LINENO masonlib: YYYY 0093/0094/0112/0113
	done

	echo Done!

	CKPTRUNFIREWALL=""
} #End of runfirewall


#Compatibility wrappers:
#-------------------------------------------------------------------------
#Start up a firewall from scratch.  Use both baserules and newrules.
#-------------------------------------------------------------------------
runlearnfirewall () {	#SUDO checked
	wrap ${WARN}"Please use \"runfirewall LEARN\" instead of runlearnfirewall"${NORM} >/dev/stderr
	runfirewall LEARN
} #End of runlearnfirewall
#-------------------------------------------------------------------------
#Start up a firewall from scratch.  Only use baserules.
#-------------------------------------------------------------------------
runstandardfirewall () {	#SUDO checked
	wrap ${WARN}"Please use \"runfirewall STANDARD\" instead of runstandardfirewall"${NORM} >/dev/stderr
	runfirewall STANDARD
} #End of runstandardfirewall


#-------------------------------------------------------------------------
# serverportrange subroutine, tries to determine whether the given numeric
# port and protocol specify a server port.  If so, returns the appropriate
# readable representation for that server and sets the comment.
# If no corresponding server port is known, both are left blank.
#-------------------------------------------------------------------------
serverportrange () {	#SUDO checked
#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


#-------------------------------------------------------------------------
# showstate procedure, used to display the state of the running program
#-------------------------------------------------------------------------
showstate () {	#SUDO checked
#Param: p1 is the string to be displayed.
	if [ "$USEANSI" != "NO" ]; then
		if [ "${TERM}" = "xterm" -o "${TERM}" = "xterm-color" ]; then
			echo -ne "\033]0;${1}\007"
		fi
	fi
} #end of showstate


#-------------------------------------------------------------------------
# sigexitscript function, called on receipt of SIGHUP
#-------------------------------------------------------------------------
sigexitscript () {	#SUDO checked
	#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
	wrap Received HUP signal, exiting at next pass >/dev/stderr
	#FIXME - this needs to be written to the ONEKILLFILE; do we have access to that?  export it?
	if type -path logger >/dev/null 2>/dev/null ; then
		logger '!!EXIT!!'
	fi
	EXITMASON="YES"
	#FIXME - should we just exit 0?
	exit 0
} #End of sigexitscript


#-------------------------------------------------------------------------
# settos subroutine, sets the TOS variable for the given port, port range, and protocol.
#-------------------------------------------------------------------------
#params: port, port range, protocol
settos () {	#SUDO checked
	#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
			wrap ${WARN}Warning - the following marks are used more than once in the currently running firewall:${NORM} >/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
			wrap This will give incorrect packet counts in your rulefiles. >/dev/stderr
		fi
	fi
	CKPTUPDATECOUNTS=""
} #End of updatecounts


