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


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

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

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

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


#-------------------------------------------------------------------------
# broadcastof function, returns the broadcast of the given network and netmask.
#-------------------------------------------------------------------------
broadcastof () {
	#Basically, the broadcast is (network bitwise-or (255.255.255.255-netmask))
	SPLITIP=$1
	I1O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I1O4=$SPLITIP
	SPLITIP=$2
	I2O1=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O2=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O3=${SPLITIP%%.*} ; SPLITIP=${SPLITIP#*.}
	I2O4=$SPLITIP

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


checkconf () {
#FIXME - double check all vars have default values.
	echo -n "Check vars..." >/dev/stderr

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

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

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

	case $NEWRULEPOLICY in			#Set LCPOLICY (lower case) and UCPOLICY...
	a*|A*)				LCPOLICY="accept" ;	UCPOLICY="ACCEPT"	;;
	r*|R*)				LCPOLICY="reject" ;	UCPOLICY="REJECT"	;;
	d*|D*)				LCPOLICY="deny" ;	UCPOLICY="DENY"		;;
	*)	echo WARNING! NEWRULEPOLICY is neither accept, reject, nor deny >/dev/stderr
		echo in $MASONCONF.  >/dev/stderr
		while [ "$LCPOLICY" != "accept" ] && [ "$LCPOLICY" != "reject" ] && [ "$LCPOLICY" != "deny" ] ; do
			echo Please choose accept, reject, or deny: >/dev/stderr
			read NEWRULEPOLICY JUNK
			case "$NEWRULEPOLICY" in
			a*|A*)		LCPOLICY="accept" ;	UCPOLICY="ACCEPT"	;;
			r*|R*)		LCPOLICY="reject" ;	UCPOLICY="REJECT"	;;
			d*|D*)		LCPOLICY="deny" ;	UCPOLICY="DENY"		;;
			esac
		done
		echo "NEWRULEPOLICY=$NEWRULEPOLICY" >>$MASONCONF
		echo NEWRULEPOLICY is being reset to \"$NEWRULEPOLICY\". >/dev/stderr
																;;
	esac

	case $DEFAULTPOLICY in
	accept|ACCEPT)		DEFAULTPOLICY="accept" ;				;;
	reject|REJECT)		DEFAULTPOLICY="reject" ;				;;
	deny|DENY)			DEFAULTPOLICY="deny" ;					;;
	*)	echo WARNING! DEFAULTPOLICY is neither accept, reject, nor deny. >/dev/stderr
		echo in $MASONCONF.  >/dev/stderr
		while [ "$DEFAULTPOLICY" != "accept" ] && [ "$DEFAULTPOLICY" != "reject" ] && [ "$DEFAULTPOLICY" != "deny" ] ; do
			echo Please choose accept, reject, or deny: >/dev/stderr
			read DEFAULTPOLICY JUNK
			case "$DEFAULTPOLICY" in
			a*|A*)		DEFAULTPOLICY="accept"					;;
			r*|R*)		DEFAULTPOLICY="reject"					;;
			d*|D*)		DEFAULTPOLICY="deny"					;;
			esac
		done
		echo "DEFAULTPOLICY=$DEFAULTPOLICY" >>$MASONCONF
		echo DEFAULTPOLICY is being reset to \"$DEFAULTPOLICY\". >/dev/stderr
																;;
	esac

	case $LOGGINGPOLICY in
	accept|ACCEPT)		LOGGINGPOLICY="accept" ;				;;
	reject|REJECT)		LOGGINGPOLICY="reject" ;				;;
	deny|DENY)			LOGGINGPOLICY="deny" ;					;;
	*)	LOGGINGPOLICY=$NEWRULEPOLICY							;;
	esac

	case $FLUSHEDPOLICY in
	accept|ACCEPT)		FLUSHEDPOLICY="accept" ;				;;
	reject|REJECT)		FLUSHEDPOLICY="reject" ;				;;
	deny|DENY)			FLUSHEDPOLICY="deny" ;					;;
	*)	FLUSHEDPOLICY=accept									;;
	esac

	case $ECHOCOMMAND in
	ipfwadm|IPFWADM)				ECHOCOMMAND="ipfwadm"		;;
	ipchains|IPCHAINS)				ECHOCOMMAND="ipchains"		;;
	ipchains-save|IPCHAINS-SAVE)	ECHOCOMMAND="ipchains-save"	;;
	cisco|CISCO)					ECHOCOMMAND="cisco"			;;
	no|NO|none|NONE)				ECHOCOMMAND="none"			;;
	*)	if [ -f /proc/net/ip_fwchains ]; then		ECHOCOMMAND="ipchains"
		elif [ -f /proc/net/ip_input ]; then		ECHOCOMMAND="ipfwadm"
		else										ECHOCOMMAND="ipchains"			#Set default here
		fi														;;
	esac

	case $DOCOMMAND in
	ipfwadm|IPFWADM)
		DOCOMMAND="ipfwadm"
		if [ ! -f /proc/net/ip_input ]; then
			echo WARNING! User has requested ipfwadm, but it appears to be >/dev/stderr
			echo unavailable.  Proceeding, but this is not likely to work. >/dev/stderr
		fi
		if [ ! -x /sbin/ipfwadm ]; then
			echo WARNING! User has requested ipfwadm, but /sbin/ipfwadm is not >/dev/stderr
			echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
		fi														;;
	ipchains|IPCHAINS)
		DOCOMMAND="ipchains"
		if [ ! -f /proc/net/ip_fwchains ]; then
			echo WARNING! User has requested ipchains, but it appears to be >/dev/stderr
			echo unavailable.  Proceeding, but this is not likely to work. >/dev/stderr
		fi
		if [ ! -x /sbin/ipchains ]; then
			echo WARNING! User has requested ipchains, but /sbin/ipchains is not >/dev/stderr
			echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
		fi														;;
	no|NO|none|NONE)	DOCOMMAND="none"						;;
	*)
		if [ -f /proc/net/ip_fwchains ]; then
			DOCOMMAND="ipchains"
			if [ ! -x /sbin/ipchains ]; then
				echo WARNING! This kernel uses ipchains, but /sbin/ipchains is not >/dev/stderr
				echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
				echo Please get a copy of the ipchains binary and place it in /sbin . >/dev/stderr
			fi
		elif [ -f /proc/net/ip_input ]; then
			DOCOMMAND="ipfwadm"
			if [ ! -x /sbin/ipfwadm ]; then
				echo WARNING! This kernel uses ipfwadm, but /sbin/ipfwadm is not >/dev/stderr
				echo executable.  Proceeding, but this is not likely to work. >/dev/stderr
				echo Please get a copy of the ipfwadm binary and place it in /sbin . >/dev/stderr
			fi
		else
			DOCOMMAND="none"				#Well, we can't _do_ either!
			echo WARNING! Neither ipchains nor ipfwadm appears to be >/dev/stderr
			echo unavailable.  Proceeding anyways. >/dev/stderr
		fi														;;
	esac

	case $HEARTBEAT in
	YES|yes|TRUE|true)					HEARTBEAT="YES"			;;
	NO|no|NONE|none|FALSE|false)		HEARTBEAT="NO"			;;
	*)									HEARTBEAT="YES"			;;
	esac

	case $LOGBLOCKS in
	YES|yes|TRUE|true|-l|-o)			LOGBLOCKS="-l"			;;
	NO|no|NONE|none|FALSE|false)		LOGBLOCKS=""			;;
	*)									LOGBLOCKS=""			;;
	esac



	case $IPCONV in
	HOSTNAME|hostname|HOST|host)		IPCONV="HOST"			;;
	NETWORK|network|NET|net)			IPCONV="NETWORK"		;;
	NO|no|NONE|none)					IPCONV="NONE"			;;
	#CUSTOM|custom)						IPCONV="CUSTOM"			;;
	*)									IPCONV="NETWORK"		;;
	esac

	case $HOSTLOOKUP in
	NO|no|NONE|none)					HOSTLOOKUP="NONE"		;;
	FILES|files|FILESONLY|filesonly)	HOSTLOOKUP="FILESONLY"	;;
	FULL|full|YES|yes)					HOSTLOOKUP="FULL"		;;
	*)									HOSTLOOKUP="FULL"		;;
	esac

	#Class A 0-127, Class B 128-191, Class C 192-223, Class D 224-254.
	#A long time ago that would have been a good way to calculate the netmask automatically.  Unfortunately, CIDR makes that useless now.
	TEMPNETWORKS="$NETWORKS"
	NETWORKS=""
	for ONENET in $TEMPNETWORKS ; do
		case $ONENET in
		#I'm not going to _add_ .252's, but if the user wants them, OK.
		*/255.255.255.255|*/255.255.255.254|*/0.0.0.0|*/0)	:					;;
		*-*/*)		NETWORKS="$NETWORKS $ONENET"								;;
		*/*)		NETWORKS="$NETWORKS ${ONENET%%/*}-`broadcastof ${ONENET%%/*} ${ONENET##*/}`/${ONENET##*/}"	;;	#network-broadcast/netmask
		0|0.*)		NETWORKS="$NETWORKS 0.0.0.0-0.255.255.255/255.0.0.0"		;;
		127|127.*)	NETWORKS="$NETWORKS 127.0.0.0-127.255.255.255/255.0.0.0"	;;
		*)
					ROUTEMASK=`route -n | grep "^$ONENET[[:space:]]" | awk '{print $3}' | uniq`
					if [ `echo "$ROUTEMASK" | wc -l` -eq 1 ]; then
						NETWORKS="$NETWORKS ${ONENET}-`broadcastof $ONENET $ROUTEMASK`/$ROUTEMASK"
					else
						echo Unable to determine the netmask for $ONENET.  Please >/dev/stderr
						echo put an entry in the form network-broadcast/netmask in >/dev/stderr
						echo the NETWORKS variable in $MASONCONF . >/dev/stderr
					fi
																				;;
		esac
	done
	unset TEMPNETWORKS

	DOBEEP=${DOBEEP:-"YES"}	# "YES" = beep at user with new rule, "NO" = dont

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

	MAXDISPLAYS=${MAXDISPLAYS:-6}

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

#Remove duplicates
	if [ -n "$SSP" ]; then 				SSP=`echo "$SSP" | tr ' ' '\012' | sort | uniq` ; fi
	if [ -n "$SCP" ]; then				SCP=`echo "$SCP" | tr ' ' '\012' | sort | uniq` ; fi
	if [ -n "$BLOCKEDHOSTS" ]; then 	BLOCKEDHOSTS=`echo "$BLOCKEDHOSTS" | tr ' ' '\012' | sort | uniq` ; fi
	if [ -n "$NOINCOMING" ]; then		NOINCOMING=`echo "$NOINCOMING" | tr ' ' '\012' | sort | uniq` ; fi
	if [ -n "$NETWORKS" ]; then			NETWORKS=`echo "$NETWORKS" | tr ' ' '\012' | sort | uniq` ; fi
	if [ -n "$POISONPROTOCOLS" ]; then	POISONPROTOCOLS=`echo "$POISONPROTOCOLS" | tr ' ' '\012' | sort | uniq` ; fi

	LOWSSHPORT=${LOWSSHPORT:-"1010"}

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


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

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


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



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

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


#-------------------------------------------------------------------------
# convicmpcode procedure.  Take the icmp (code and subcode?) parameters
# and set COMMENT.  In the future, return a readable icmp code name?
#-------------------------------------------------------------------------
convicmpcode () {
#FIXME - handle subcode (in comment2) if dest != 0
#FIXME - add case for text versions of these numeric codes
	case "$1" in
	0)		COMMENT="$CMNT Echo reply/icmp ($DIRLETTER)"				;;
	3)		COMMENT="$CMNT Dest Unreach/icmp ($DIRLETTER)"				;;
	4)		COMMENT="$CMNT Source Quench/icmp ($DIRLETTER)"				;;
	5)		COMMENT="$CMNT Redirect/icmp ($DIRLETTER)"					;;
	8)		COMMENT="$CMNT Echo req/icmp ($DIRLETTER)"					;;
	11)		COMMENT="$CMNT Time exceeded/icmp ($DIRLETTER)"				;;
	12)		COMMENT="$CMNT Parameter prob/icmp ($DIRLETTER)"			;;
	13)		COMMENT="$CMNT Timestamp req/icmp ($DIRLETTER)"				;;
	14)		COMMENT="$CMNT Timestamp reply/icmp ($DIRLETTER)"			;;
	15)		COMMENT="$CMNT Info req/icmp ($DIRLETTER)"					;;
	16)		COMMENT="$CMNT Info reply/icmp ($DIRLETTER)"				;;
	17)		COMMENT="$CMNT Addr Mask req/icmp ($DIRLETTER)"				;;
	18)		COMMENT="$CMNT Addr Mask reply/icmp ($DIRLETTER)"			;;
#FIXME - include source and dest IPs for the following?
	*)		COMMENT="$CMNT unknown-$SRCPORT/icmp ($DIRLETTER)"			;;
	esac
} #End of convicmpcode




flushfirewall () {
#Flush the existing rules so we start with a clean slate.
	if [ -f /proc/net/ip_fwchains ]; then
		echo -n Flushing... >/dev/stderr
		FLUSHEDPOLICY=`echo $FLUSHEDPOLICY | tr a-z A-Z`
		/sbin/ipchains -P output $FLUSHEDPOLICY ;	/sbin/ipchains -F output
		/sbin/ipchains -P forward $FLUSHEDPOLICY ;	/sbin/ipchains -F forward
		/sbin/ipchains -P input $FLUSHEDPOLICY ;	/sbin/ipchains -F input
#Flush the nolog chains if they exist, create them if not.
		if [ -n "$NOLOGSUFFIX" ]; then
			if [ `/sbin/ipchains -L -n | grep "^Chain output$NOLOGSUFFIX" | wc -l` -gt 0 ]; then
				/sbin/ipchains -F output$NOLOGSUFFIX >/dev/null 2>/dev/null
			else
				/sbin/ipchains -N output$NOLOGSUFFIX >/dev/null 2>/dev/null
			fi

			if [ `/sbin/ipchains -L -n | grep "^Chain forward$NOLOGSUFFIX" | wc -l` -gt 0 ]; then
				/sbin/ipchains -F forward$NOLOGSUFFIX >/dev/null 2>/dev/null
			else
				/sbin/ipchains -N forward$NOLOGSUFFIX >/dev/null 2>/dev/null
			fi

			if [ `/sbin/ipchains -L -n | grep "^Chain input$NOLOGSUFFIX" | wc -l` -gt 0 ]; then
				/sbin/ipchains -F input$NOLOGSUFFIX >/dev/null 2>/dev/null
			else
				/sbin/ipchains -N input$NOLOGSUFFIX >/dev/null 2>/dev/null
			fi
		fi
		echo Done!
	elif [ -f /proc/net/ip_input ]; then
		echo -n Flushing... >/dev/stderr
		FLUSHEDPOLICY=`echo $FLUSHEDPOLICY | tr A-Z a-z`
		/sbin/ipfwadm -O -p $FLUSHEDPOLICY ;	/sbin/ipfwadm -O -f
		/sbin/ipfwadm -F -p $FLUSHEDPOLICY ;	/sbin/ipfwadm -F -f
		/sbin/ipfwadm -I -p $FLUSHEDPOLICY ;	/sbin/ipfwadm -I -f
		echo Done!
	else
		echo This kernel supports neither ipchains nor ipfwadm! >/dev/stderr
	fi
} #End of flushfirewall


#-------------------------------------------------------------------------
# generalizeip function.  For the given ip address parameter, return one
# of the following:
# - $DYNIFADDR for interfaces with dynamic IP addresses.
# - the corresponding hostname
# - itself, if a local address, broadcast address, or special address.
# - its IP network 
# - as a last resort, 0/0
# User can select operation with IPCONV= in masonconf.
#-------------------------------------------------------------------------
generalizeip () {
	case $1 in
	anywhere)			GIRETVAL="0/0"							;;
	*/0|*/0.0.0.0)		GIRETVAL="0/0"							;;
	*/*)				GIRETVAL="$1"							;;
	*)
		GIRETVAL="$1${SINGLEMACHSPEC}QQ1"
		ISASSIGNED="NO"
		for ONEIF in $DYNIF ; do
			DYNIP=$(eval echo \${$(eval echo ${ONEIF}ADDR)})	#No, really.
			if [ "$1" = "$DYNIP" ]; then
				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}QQ2"								;;
			NETWORK)
#Handle special addresses
				case $1 in
				0.0.0.0)					GIRETVAL="0.0.0.0${SINGLEMACHSPEC}QQ3"			ISASSIGNED="YES"	;;
				127.0.0.1|127.0.0.1/32)		GIRETVAL="localhost${SINGLEMACHSPEC}QQ4"			ISASSIGNED="YES"	;;
				255.255.255.255)			GIRETVAL="255.255.255.255${SINGLEMACHSPEC}QQ5"	ISASSIGNED="YES"	;;
				esac

				#ckpt Generalizing $1
				case $1 in	#We should only be converting numeric addresses
				*[-A-Za-z]*)	GIRETVAL="$1" ; ISASSIGNED="YES"	;;
				*)
					#ckpt all numeric
#Leave local IP addresses and broadcasts as they are.
					if [ "$ISASSIGNED" = "NO" ]; then
						for ONELOCALIP in $ALLIPS $ALLBCS ; do
							if [ "$1" = "$ONELOCALIP" ]; then 
								GIRETVAL="`nameof $1`${SINGLEMACHSPEC}QQ6"
								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
										if [ "$ECHOCOMMAND" = "cisco" ]; then
											GIRETVAL="$ONENET `mask2cisco $NETMASK`"
										else
											GIRETVAL="$ONENET/`mask2bits $NETMASK`"
										fi
										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
	#ckpt generalizeip returns $GIRETVAL
} #End of generalizeip



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

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


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

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



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



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

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

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

	return $INIRETVAL
	#ckpt end isnumericip
} #End of isnumericip



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

	checkconf

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

	if [ -n "$NETCACHE" ] && [ -n "`cat $NETCACHE | grep -v '^$'`" ]; then
		echo WARNING!  The $NETCACHE file is no longer used by Mason.  Please >/dev/stderr
		echo transfer all values from this file to the NETWORKS variable in $MASONCONF.  >/dev/stderr
	fi
	#rm -f $NETCACHE ; touch $NETCACHE ; chmod 700 $NETCACHE

	#ckpt about to load NETWORKS
	if [ -z "$NETWORKS" ]; then		#load the NETWORKS variable with all non-trivial networks in the routing table.
		for ONENET in `route -n | grep -v '^127\.' | grep -v '^0\.0\.0\.0' | grep '^[0-9]' | awk '{print $1 "/" $3}'` ; do
			case $ONENET in
			*/255.255.255.255|*/255.255.255.254|*/255.255.255.252|*/0.0.0.0)	:							;;
			*)	NETWORKS="$NETWORKS ${ONENET%%/*}-`broadcastof ${ONENET%%/*} ${ONENET##*/}`/${ONENET##*/}"	;;	#network-broadcast/netmask
			esac
		done
	fi
	DNSSERVERS=`cat /etc/resolv.conf | grep '^nameserver' | awk '{print $2}'`

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


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



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



#-------------------------------------------------------------------------
# nameof function, returns the hostname from the IP address parameter.
#-------------------------------------------------------------------------
nameof () {
#Use /etc/hosts and the "host" command to look up names for source and destination addresses.
	NAMEOFRETVAL=""
#FIXME - Should we just drop everything after the /?
	NAMEOFINPUT=${1%%/32}
	if [ "$HOSTLOOKUP" = "FILESONLY" ] || [ "$HOSTLOOKUP" = "FULL" ]; then
		ONEHOSTNAME=`cat /etc/hosts | egrep "^$NAMEOFINPUT[^0-9]" | tail --lines=1 | awk '{print $2}'`
		if [ -n "$ONEHOSTNAME" ]; then
			NAMEOFRETVAL="$ONEHOSTNAME"
		fi
	fi

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

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

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


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

	case "$1/$2" in
	1024:65535/tcp)								PCPRETVAL=" gt 1023"								;;
	*:*/*)										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"
} #End of port2ciscoport


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


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

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


runlearnfirewall () {
	if [ -f /proc/net/ip_fwchains ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr a-z A-Z`
		if [ "$LOGBLOCKS" = "-o" ]; then LOGBLOCKS="-l" ; fi

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

		if [ -n "$BLOCKEDHOSTS" ]; then
			echo -n Blockedhost blocks...
			for BLOCKEDHOST in $BLOCKEDHOSTS ; do
				/sbin/ipchains -I input  -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I input  -d $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -d $BLOCKEDHOST -j DENY $LOGBLOCKS
			done
		else
			echo -n No Blockedhost blocks...
		fi

		if [ -n "$NOINCOMING" ] && [ -n "$INCOMINGINTERFACES" ]; then
			echo -n Incoming blocks...
			for OUTSIDEIF in $INCOMINGINTERFACES ; do
				for BLOCKPROTO in $NOINCOMING ; do
					case $BLOCKPROTO in
					*/*)	/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS	;;
					*)		/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS							;;
					esac
				done
			done
		else
			echo -n No incoming blocks...
		fi

		set +e		#Turn off failure checking; Mason has no control over the final contents of these files
		echo -n Fixed rules...
		. $BASERULEFILE

		echo -n New rules...
		. $NEWRULEFILE
		set -e

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

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

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

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

		set +e		#Turn off failure checking; Mason has no control over the final contents of these files
		echo -n Fixed rules...
		. $BASERULEFILE

		echo -n New rules...
		. $NEWRULEFILE
		set -e

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


runstandardfirewall () {
	if [ -f /proc/net/ip_fwchains ]; then
		DEFAULTPOLICY=`echo $DEFAULTPOLICY | tr a-z A-Z`
		if [ "$LOGBLOCKS" = "-o" ]; then LOGBLOCKS="-l" ; fi

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

		if [ -n "$BLOCKEDHOSTS" ]; then
			echo -n Blockedhost blocks...
			for BLOCKEDHOST in $BLOCKEDHOSTS ; do
				/sbin/ipchains -I input  -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -s $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I input  -d $BLOCKEDHOST -j DENY $LOGBLOCKS
				/sbin/ipchains -I output -d $BLOCKEDHOST -j DENY $LOGBLOCKS
			done
		else
			echo -n No Blockedhost blocks...
		fi

		if [ -n "$NOINCOMING" ] && [ -n "$INCOMINGINTERFACES" ]; then
			echo -n Incoming blocks...
			for OUTSIDEIF in $INCOMINGINTERFACES ; do
				for BLOCKPROTO in $NOINCOMING ; do
					case $BLOCKPROTO in
					*/*)	/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -d 0/0 ${BLOCKPROTO%%/*} -j DENY $LOGBLOCKS	;;
					*)		/sbin/ipchains -I input -i $OUTSIDEIF -p ${BLOCKPROTO##*/} -j DENY $LOGBLOCKS							;;
					esac
				done
			done
		else
			echo -n No incoming blocks...
		fi

		set +e		#Turn off failure checking; Mason has no control over the final contents of this file.
		echo -n Fixed rules...
		. $BASERULEFILE
		set -e

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

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

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

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

		set +e		#Turn off failure checking; Mason has no control over the final contents of this file.
		echo -n Fixed rules...
		. $BASERULEFILE
		set -e

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



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

	
	if isdigits "$1" ; then
		SERVICE="`cat $SERVICES | grep "$1/$2" | head -n 1 | awk '{print $1}'`"
		#Mason will not be manipulating /etc/services.
		#SERVICELINE="`cat $SERVICES | grep "$1/$2" | head -n 1`"
		#if [ `cat /etc/services | grep "$1/$2" | 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
		#ckpt spr isdigits $READABLEPORT $PARTIALCOMMENT
	elif [ -n "`cat /etc/services | grep -E $1`" ]; then		# $1 is already converted to text and a server port
		#egrep "^$1[[:space:]]+[0-9]+/$2"
		#ckpt in spr isname
		READABLEPORT=$1											PARTIALCOMMENT="$1/$PROTO"
		#ckpt spr isname $READABLEPORT $PARTIALCOMMENT
#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"
		#ckpt setting to X
	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
		#ckpt spr neither $1 $2
	fi
	#echo $READABLEPORT		#Can't do this because we need to return PARTIALCOMMENT as well.
} #end of serverportrange


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


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

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


