#!/bin/bash -e
#For those who actually read code, welcome.  Please note: there appears to be support for
#accepting "ipchains -L -n -x -v" input.  It sorta works, it generally doesn't.  I won't
#be working on it in the near future.  Play with it if you'd like.
#Last YYYY code used: 0017, use 0018 next

cat <<EOTEXT1 >/dev/null
	(The above line allows me to put the documentation right in the
script... Cool, eh?)

>>>>>>>>>>>>>>>If you read nothing else, please read this<<<<<<<<<<<<<<<<

	This program offers an aid to creating firewall rules.  It offers
ABSOLUTELY NO intelligence in deciding what should be allowed or
disallowed.  It has ABSOLUTELY NO ability to understand your security
policy and implement it.  YOU are responsible for reviewing the rules and
massaging them to fit your needs.
	While the documentation in mason.txt attempts to provide some
general guidelines on how to use Mason, please remember:  the author has
no knowledge of what you want your firewall to do and has not tailored the
documentation or program to specially fit your needs.  If there is ever a
discrepancy between your needs and the program output or your needs and
the documentation, the program and/or documentation are _dead_ _wrong_. 


Copyleft:
	Mason interactively creates a Linux packet filtering firewall.
	Copyright (C) 1998, 1999 William Stearns <wstearns@pobox.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

	The author can also be reached at:
        William Stearns
email:  wstearns@pobox.com				(preferred)
web:    http://www.pobox.com/~wstearns
snail:  544 Winchester Place
        Colchester VT, 05446, USA


	This code is entirely owned by William Stearns
(wstearns@pobox.com) and has no relation to any employer or employer
sponsored project.  

------------------------------ Mason ------------------------------
	The Mason script interactively builds a (fire)wall on a Linux
machine. For more details about how this is done, please see mason.txt,
which gives background, theory of operation, a quick start, and additional
documentation on firewalls and firewall gotchas. 
	mason.txt and related documentation should have been installed to
/usr/doc/mason-{version}/ .  If they are missing or you would like to make
sure you have the latest version, please go to
http://www.pobox.com/~wstearns/mason/ . 
	All configuration of this program is done in the /etc/masonrc
file.  This script should probably not be directly edited.

- Bill Stearns

The EOTEXT line is the end of the text and the start of the code. 
EOTEXT1

CKPTMASON=" mason: Ground0" ; #ckpt $CKPTMASON

MASONDIR=${MASONDIR:-"/var/lib/mason/"}
MASONCONF=${MASONCONF:-"/etc/masonrc"}
MASONLIB=${MASONLIB:-"/var/lib/mason/masonlib"}
if [ -f $MASONLIB ]; then
	. $MASONLIB
else
	echo Missing $MASONLIB library file.  Please get a complete copy of Mason from >/dev/stderr
	echo http://www.pobox.com/~wstearns/mason/ .  Exiting. >/dev/stderr
	sleep 10
	exit 0
fi

trap preexit 0		#This gets nullified if we get a SIGHUP or SIGINT; see sigexitscript.


#-------------------------------------------------------------------------
# Start setting up.
#-------------------------------------------------------------------------
CKPTMASON=" mason: Setup" ; #ckpt $CKPTMASON

#LOGCHAINSEXIST="yes"	In the process of being removed.  Only used in checksys. #REMOVEME

LAST1="" ; LAST2="" ; LAST3="" ; LAST4="" ; LAST5="" ; LAST6="" ; LAST7="" ; LAST8="" ; CURRENT=""
EXITMASON=${EXITMASON:-"NO"}

trap sigexitscript SIGHUP
trap sigexitscript SIGINT		#Ctrl-C generates this
trap loadconf SIGUSR1


#---------- Start of Main code ----------
CKPTMASON=" mason: Start main" ; #ckpt $CKPTMASON
echo "---- Mason firewall builder for Linux                         ----" >/dev/stderr
echo "---- see http://www.pobox.com/~wstearns/mason/ for more info. ----" >/dev/stderr
echo "---- William Stearns <wstearns@pobox.com>                     ----" >/dev/stderr 
echo "(This is release $MASONVER )" >/dev/stderr
loadconf
checksys
SIGGED="NO"

CKPTMASON=" mason: Save pid" ; #ckpt $CKPTMASON
echo "$$" >>$MASONPIDFILE

#NAMECACHE Support has been disabled
##Hmmm... I _hate_ overwriting /etc/passwd...
#if [ -L $NAMECACHE ]; then
#	rm -f $NAMECACHE
#fi
#
##Create the name cache file if it doesn't exist
#if [ ! -e $NAMECACHE ]; then
#	touch $NAMECACHE
#	#This is a security-related program.  I don't want to let people know who we're even talking to.
#	chmod og-rwx $NAMECACHE
#fi

for ONEIF in $DYNIF ; do
	if [ ! -f ${MASONDIR}${ONEIF}-ips ]; then touch ${MASONDIR}${ONEIF}-ips ; fi
	ifconfig $ONEIF 2>/dev/null | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'>>${MASONDIR}${ONEIF}-ips || logfail $LINENO ifconfig $ONEIF and save
	#if [ "$DYNIFMODE" != "ANYADDRESS" ]; then echo -n "$CMNT $CMNT" ; fi
	if [ "$DYNIFMODE" = "ANYADDRESS" ]; then	#This is a hidden option.  The use of 0/0 to match a dynamic address opens some disturbing possibilities for holes in the firewall that I don't really want to uncover.
		echo "export ${ONEIF}ADDR=\"0/0\"	${CMNT} ${CMNT}Use this if you want to match any address on $ONEIF."
	fi
	if [ "$DYNIFMODE" != "SPECIFICIP" ]; then echo -n "$CMNT $CMNT" ; fi
	echo "export ${ONEIF}ADDR=\"\`ifconfig $ONEIF 2>/dev/null | grep 'inet addr' | awk '{print \$2}' | sed -e 's/.*://'\`$SINGLEMACHSPEC\"	${CMNT} ${CMNT}Use this if you want to match a single address on $ONEIF."
	if [ "$DYNIFMODE" != "SMALLESTRANGE" ]; then echo -n "$CMNT $CMNT" ; fi
#FIXME - what if the file is empty?
	echo "export ${ONEIF}ADDR=\"$(encompassingnetworkof $(cat ${MASONDIR}${ONEIF}-ips | sort | uniq) || logfail $LINENO return encompassing network for $ONEIF)\"	${CMNT} ${CMNT}Use this if you want to match all addresses seen so far on $ONEIF."
	eval ${ONEIF}ADDR=`ifconfig $ONEIF 2>/dev/null | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'` || logfail $LINENO Set $ONEIF into environment
done

#DEBUG
#set -x

#FIXME - output this header even if we switch to ipchains-save, but only once per mason run.
if [ "$ECHOCOMMAND" = "ipchains-save" ]; then
	for ONECHAIN in input forward output ; do
		echo ':'$ONECHAIN $DEFAULTPOLICY
	done
	if [ -n "$NOLOGSUFFIX" ]; then
		for ONECHAIN in input forward output ; do
			echo ':'$ONECHAIN$NOLOGSUFFIX '-'
		done
	fi
fi

#Get the first log entry
#CKPTMASON=" mason: Get log entry" ; #ckpt $CKPTMASON
CKPTMASON="" ; #ckpt $CKPTMASON
unset ACK COMMENT CURRCHAIN DEST DESTHOST DESTIP DESTPORT DIR DIRLETTER \
DOACK ECHOACK IF IGNOREPORT INIF ISLOGLINE \
J1 J2 J3 J4 J5 J6 J7 J8 J9 J10 J11 J12 J13 J14 J15 J16 J17 J18 J19 J20 J21 J22 J23 J24 J25 J26 J27 J28 J29 J30 \
      O3 O4 O5 O6 O7 O8 O9 O10 O11 O12 O13 \
      A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 \
LINEHASDYNAMIC LOGTHIS MESSPOL NUMBYTES NUMPACKETS PROTO SRC SRCHOST SRCIP SRCPORT SYNFLAG SYNFLAGSEEN TAIL TOS || :
#unset DFFLAG FFLAG FOFLAG IFLAG LFLAG SFLAG TFLAG || :			#These fields are not used at this time.
if [ -n "$MINMARK" ]; then INCMINMARK="0" ; fi
TOS=""
if ! read J1 J2 J3 J4 J5 J6 J7 J8 J9 J10 J11 J12 J13 J14 J15 J16 J17 J18 J19 J20 J21 J22 J23 J24 J25 J26 J27 J28 J29 J30 ; then
	if [ "$SIGGED" != "YES" ]; then EXITMASON="YES" ; fi
fi

while [ "$SIGGED" = "YES" ]; do
	SIGGED="NO"
	if ! read J1 J2 J3 J4 J5 J6 J7 J8 J9 J10 J11 J12 J13 J14 J15 J16 J17 J18 J19 J20 J21 J22 J23 J24 J25 J26 J27 J28 J29 J30 ; then
		if [ "$SIGGED" != "YES" ]; then EXITMASON="YES" ; fi
	fi
done

CKPTMASON=" mason: post get log entry" ; #ckpt $CKPTMASON

while [ "$EXITMASON" != "YES" ] && [ -n "$J1" ] && [ "$J1" != '!!EXIT!!' ]; do
CKPTMASON=" mason: In main loop" ; #ckpt $CKPTMASON
#Only do the work if the line is a firewalling log entry.
	if [ "$J6 $J7" = "Packet log:" ]; then		#Load variables from ipchains log entry
		INFORMAT="ipchains-log"
		case $J8 in
		output)		DIR='output ' ;	DIRLETTER='O'				;;
		input)		DIR='input  ' ;	DIRLETTER='I'				;;
		forward)	DIR='forward' ;	DIRLETTER='F'				;;
		*)	echo Unknown direction $J8 >/dev/stderr				;;
		esac
		IF="$J10"
		protonum2name "${J11##PROTO=}"
		SRC="$J12" ; DEST="$J13"		#SRC and DEST are only temporary variables for ipfwadm and ipchains formats to split into SRCIP and SRCPORT in a mo.
		SRCPORT=${SRC##*:}
		DESTPORT=${DEST##*:}
		SRCIP=${SRC%%:*}
		DESTIP=${DEST%%:*}
		#Even if there were a way to extract a mark value from the log line, it wouldn't seem correct to use it.
		#MESSPOL="$J9" ; LFLAG="$J14" ; SFLAG="$J15" ; IFLAG="$J16" ; FFLAG="$J17" ; TFLAG="$J18"		#Unused
		SYNFLAG="$J19"
		if [ "$SYNFLAG" = "SYN" ]; then
			SYNFLAGSEEN="YES"
		else
			SYNFLAG=""
		fi
		ISLOGLINE="YES"
	elif [ "$J5 $J6" = "kernel: IP" ]; then	#Load variables from ipfwadm log entry
		INFORMAT="ipfwadm-log"
		case $J7 in				#Formerly [ "`echo $J7 | cut -b 1-3`" = "fw-" ]
		fw-out|fw-in|fw-fwd)
			case $J7 in
			fw-out)	DIR='output ' ;	DIRLETTER='O'					;;
			fw-in)	DIR='input  ' ;	DIRLETTER='I'					;;
			fw-fwd)	DIR='forward' ;	DIRLETTER='F'					;;
			*)	echo Unknown direction $J7 >/dev/stderr				;;
			esac
			IF="$J9"
			PROTO=`echo $J10 | tr A-Z a-z`
			SRC="$J11" ; DEST="$J12"		#SRC and DEST are only temporary variables for ipfwadm and ipchains formats to split into SRCIP and SRCPORT in a mo.
			SRCIP=${SRC%%:*}
			DESTIP=${DEST%%:*}
			#MESSPOL="$J8" ; LFLAG="$J13" ; SFLAG="$J14" ; IFLAG="$J15" ; FOFLAG="$J16" ; TFLAG="$J17" ; DFFLAG="$J18"		#Unused
#Break up ipfwadmin's habit of gluing the icmp port onto the protocol.
			if [ "${PROTO%%/*}" = "icmp" ]; then
				SRCPORT=${PROTO##*/}
				PROTO="icmp"
				DESTPORT=""
				if [ "$DEBUG" = "YES" ]; then echo proto= $PROTO srcport= $SRCPORT destport= $DESTPORT >/dev/stderr ; fi
			else
				SRCPORT=${SRC##*:}
				DESTPORT=${DEST##*:}
			fi
			ISLOGLINE="YES"
			#No need to set IGNOREPORT - ipfwadm only handles tcp, udp, and icmp.
																;;
		esac
	elif [ "$J5" = "kernel:" ]; then	#Load variables from possible iptables log entry
		case $J6 in				#Formerly [ "`echo $J6 | cut -b 1-4`" = "SRC=" ]
		SRC=*)			#FIXME - it seems reasonably likely that J6 might be something other than SRC= in some circumstances.
			INFORMAT="iptables-log"
			#FIXME - more than 30 fields needed?
			for ONEFIELD in $J6 $J7 $J8 $J9 $J10 $J11 $J12 $J13 $J14 $J15 $J16 $J17 $J18 $J19 $J20 $J21 $J22 $J23 $J24 $J25 $J26 $J27 $J28 $J29 $J30 ; do
				case $ONEFIELD in
				DPT=*)		DESTPORT=${ONEFIELD##*=}					;;
				DST=*)		DESTIP=${ONEFIELD##*=}						;;
				PROTO=*)	PROTO=`echo ${ONEFIELD##*=} | tr A-Z a-z`	;;
				SPT=*)		SRCPORT=${ONEFIELD##*=}						;;
				SRC=*)		SRCIP=${ONEFIELD##*=}						;;
				TYPE=*)		SRCPORT=${ONEFIELD##*=}						;;		#FIXME - not sure about subcode
#ZZZZ
				IN=*)		INIF=${ONEFIELD##*=}						;;		
				OUT=*)		IF=${ONEFIELD##*=}							;;
				#ACK)		#ACK set									;;
				#SYN)		#SYN set									;;
				#*)	#Ignore (digits), ACK=digits, CODE=digits, DF, ID=digits, LEN=digits, OPT, PSH, RES=hexdigits, SEQ=digits, TOS=hexdigits, TTL=digits, URGP=digits, WINDOW=digits
				#														;;
				esac
			done
			if [ -n "$INIF" ] && [ -z "$IF" ]; then		#FIXME - DIR needs to be lowercase for all but iptables
				DIR='INPUT  ' ;	DIRLETTER='I'
			elif [ -n "$INIF" ] && [ -n "$IF" ]; then
				DIR='FORWARD' ;	DIRLETTER='F'
			elif [ -z "$INIF" ] && [ -n "$IF" ]; then
				DIR='OUTPUT ' ;	DIRLETTER='O'
			elif [ -z "$INIF" ] && [ -z "$IF" ]; then	#This case shouldn't happen
				DIR='' ;	DIRLETTER=''
			fi
			#FIXME - if either ECHOCOMMAND or DOCOMMAND isn't iptables, we need to handle INIF -> IF if IF unset.  It probably needs to be done in the ECHO/DO sections.  Bash ${  } macro?
			ISLOGLINE="YES"
#FIXME - temporary test code
			#ISLOGLINE="NO"
			#DIR='forward' ;	DIRLETTER='F'
			#IF="lo"
			#echo J1=$J1 J2=$J2 J3=$J3 J4=$J4 J5=$J5 J6=$J6 J7=$J7 J8=$J8 >/dev/stderr 
			#echo J9=$J9 J10=$J10 J11=$J11 J12=$J12 J13=$J13 J14=$J14 J15=$J15 J16=$J16 >/dev/stderr
			#echo J17=$J17 J18=$J18 J19=$J19 DIR=$DIR DIRLETTER=$DIRLETTER >/dev/stderr
			#echo DESTPORT=$DESTPORT DESTIP=$DESTIP PROTO=$PROTO SRCPORT=$SRCPORT SRCIP=$SRCIP >/dev/stderr
#FIXME - what about these?
			#case $J7 in
			#fw-out)	DIR='output ' ;	DIRLETTER='O'					;;
			#fw-in)	DIR='input  ' ;	DIRLETTER='I'					;;
			#fw-fwd)	DIR='forward' ;	DIRLETTER='F'					;;
			#*)	echo Unknown direction $J7 >/dev/stderr				;;
			#esac
			#IF="$J9"
			##MESSPOL="$J8" ; LFLAG="$J13" ; SFLAG="$J14" ; IFLAG="$J15" ; FOFLAG="$J16" ; TFLAG="$J17" ; DFFLAG="$J18"		#Unused
			#if [ "${PROTO%%/*}" = "icmp" ]; then
			#	SRCPORT=${PROTO##*/}
			#	PROTO="icmp"
			#	DESTPORT=""
			#	if [ "$DEBUG" = "YES" ]; then echo proto= $PROTO srcport= $SRCPORT destport= $DESTPORT >/dev/stderr ; fi
			#else
			#	SRCPORT=${SRC##*:}
			#	DESTPORT=${DEST##*:}
			#fi
			#No need to set IGNOREPORT - ipfwadm only handles tcp, udp, and icmp.
																;;
		esac
	elif [ "$J1" = "Chain" ]; then	#Load variables from ipchains -Lv listing; this is a header line.
		CURRCHAIN=$J2
		INFORMAT="ipchains-lv"
	elif [ "$J6" = "0xFF" ] || [ "$J6" = "0x01" ]; then	#Load variables from ipchains -Lv listing; this is a data line.
		case $J7 in
		0x*)
			ISLOGLINE="YES"
			INFORMAT="ipchains-lv"
			case $CURRCHAIN in
			output)		DIR='output' ;		DIRLETTER='O'							;;
			input)		DIR='input' ;		DIRLETTER='I'							;;
			forward)	DIR='forward' ;		DIRLETTER='F'							;;
			"")		echo No chain name has been registered.  Mason cannot process this entry. >/dev/stderr ; ISLOGLINE=""	;;
			*)			DIR="$CURRCHAIN" ;	DIRLETTER='Q'
						if [ -z "$OTHERCHAINWARNISSUED" ]; then
							case "$ECHOCOMMAND" in
							ipchains|ipchains-lv|iptables)	:									;;
							*)
								echo "$CMNT Any following rules with a direction of \"Q\" need to be edited.  They"
								echo "$CMNT came from an ipchains/iptables rule other than input, output, or forward."
								OTHERCHAINWARNISSUED="YES"
																						;;
							esac
						fi
																					;;
			esac
			case $J5 in
#FIXME - formalize this parsing.  double check these, check other flag fields.
			-y*)	ACK="! -k"										;;
			!y*)	ACK="-k"										;;
			*l-)	LOGTHIS="-l"									;;
			--*)	ACK=""											;;
			esac
			MESSPOL=$J3
			if [ "$J8" = "*" ]; then	IF="" ; else	IF="$J8" ; fi
			if [ "$J4" = "all" ]; then	PROTO="" ; else	protonum2name $J4 ; fi
			if [ "$J6 $J7" != "0xFF 0x00" ]; then TOS=" -t $J6 $J7" ; else TOS="" ; fi
#FIXME - handle case of existing or missing mark and outsize fields
			case $J9 in
			*/*)	SRCIP="$J9"		;;
			*)		SRCIP="$J9/32"	;;
			esac
			case $J10 in
			*/*)	DESTIP="$J10"		;;
			*)		DESTIP="$J10/32"	;;
			esac
			NUMPACKETS=$J1 ; NUMBYTES=$J2
			#LFLAG="$J13" ; SFLAG="$J14" ; IFLAG="$J15" ; FOFLAG="$J16" ; TFLAG="$J17" ; DFFLAG="$J18"		#Unused

			case $J11 in
			n/a)	SRCPORT=""																				;;
			'*')	SRCPORT=""																				;;
			*:*)	if [ "${J11%%:*}" = "${J11##*:}" ]; then SRCPORT=${J11%%:*} ; else SRCPORT=$J11 ; fi	;;
			*)		SRCPORT=$J11																			;;
			esac
			case $J13 in
			'*')	DESTPORT=""																				;;
			*:*)	if [ "${J13%%:*}" = "${J13##*:}" ]; then DESTPORT=${J13%%:*} ; else DESTPORT=$J13 ; fi	;;
			*)		DESTPORT=$J13																			;;
			esac
																;;
		esac
	fi


	CKPTMASON=" mason: Process line, set line policy" ; #ckpt $CKPTMASON
	if [ "$ISLOGLINE" = "YES" ]; then
		if [ "$INFORMAT" = "ipchains-lv" ] && { [ "$DOCOMMAND" = "ipchains" ] || [ "$DOCOMMAND" = "iptables" ] ; } ; then	#We actually use the policy in each line in ipchains-lv entries
			case "$MESSPOL" in
			accept|ACCEPT)	LCPOLICY="accept" ;	UCPOLICY="ACCEPT"	;;
			reject|REJECT)	LCPOLICY="reject" ;	UCPOLICY="REJECT"	;;
			deny|DENY)		LCPOLICY="deny" ;	UCPOLICY="DENY"		;;
			"-")			LCPOLICY="" ;		UCPOLICY=""			;;
			*)				LCPOLICY=$MESSPOL ; UCPOLICY=$MESSPOL	;;
			esac
		elif [ "$INFORMAT" = "ipchains-lv" ]; then	#We actually use the policy in each line in ipchains-lv entries
			case "$MESSPOL" in
			accept|ACCEPT)	LCPOLICY="accept" ;	UCPOLICY="ACCEPT"	;;
			reject|REJECT)	LCPOLICY="reject" ;	UCPOLICY="REJECT"	;;
			deny|DENY)		LCPOLICY="deny" ;	UCPOLICY="DENY"		;;
			"-")	#FIXME - technically these should be accounting rules for I and O, a warning for F.
				case "$NEWRULEPOLICY" in
				a*|A*)		LCPOLICY="accept" ; UCPOLICY="ACCEPT"	;;
				r*|R*)		LCPOLICY="reject" ; UCPOLICY="REJECT"	;;
				d*|D*)		LCPOLICY="deny"   ; UCPOLICY="DENY"		;;
				esac
																	;;
			*)				LCPOLICY=$MESSPOL ; UCPOLICY=$MESSPOL	;;
			esac
		else
			case "$NEWRULEPOLICY" in
			a*|A*)			LCPOLICY="accept" ; UCPOLICY="ACCEPT"	;;
			r*|R*)			LCPOLICY="reject" ; UCPOLICY="REJECT"	;;
			d*|D*)			LCPOLICY="deny"   ; UCPOLICY="DENY"		;;
			esac
		fi

#Handle AUTOMASQ feature.  Masquerade packets forwarded to requested interfaces if source 
#address is a reserved (rfc1918) address.
		CKPTMASON=" mason: Process line, check for masq" ; #ckpt $CKPTMASON
		if [ "$DIRLETTER" = "F" ] && [ -n "$AUTOMASQIF" ] && [ "$LCPOLICY" = "accept" ] && reservedip $SRCIP ; then
			for ANIF in $AUTOMASQIF ; do
				if [ "$ANIF" = "$IF" ]; then
					UCPOLICY="MASQ"				#For ipchains 
					LCPOLICY="accept -m"		#For ipfwadm
												#FIXME - iptables...
				fi
			done
		fi #If forwarding and automasq requested.
		if [ "$IGNOREPORT" = "YES" ]; then SRCPORT="" ; DESTPORT="" ; fi

#Quickly put in a completely specific rule for this packet to stop the flow - it will be deleted later
		#in masonlib: LCPOLICY, UCPOLICY
		#from above: IF, DIR, DIRLETTER, PROTO, SRCIP, SRCPORT, DESTIP, DESTPORT
		#not set? ACK, SRCHOST, DESTHOST, TOS, DOACK
		UNDOSPECIFICRULE=""
		if [ "$DOCOMMAND" = "ipfwadm" ]; then
			CKPTMASON=" mason: Process line, ipfwadm specific rule" ; #ckpt $CKPTMASON
			$IPFWADMBIN -i $LCPOLICY ${IF:+"-W"} $IF -$DIRLETTER ${PROTO:+"-P"} $PROTO -S $SRCIP $SRCPORT -D $DESTIP $DESTPORT || logfail $LINENO Mason: YYYY 0001
			UNDOSPECIFICRULE="$IPFWADMBIN -d $LCPOLICY ${IF:+"-W"} $IF -$DIRLETTER ${PROTO:+"-P"} $PROTO -S $SRCIP $SRCPORT -D $DESTIP $DESTPORT || logfail $LINENO Mason: YYYY 0002"
			CKPTMASON=" mason: Process line, ipfwadm post specific rule" ; #ckpt $CKPTMASON
		elif [ "$DOCOMMAND" = "ipchains" ]; then
			case $DIRLETTER in
			I)		DODIR="input$NOLOGSUFFIX"					;;
			O)		DODIR="output$NOLOGSUFFIX"					;;
			F)		DODIR="forward$NOLOGSUFFIX"					;;
			esac
			CKPTMASON=" mason: pre specific rule" ; #ckpt $CKPTMASON
			#ckpt CHAIN -I $DODIR 1 ${IF:+"-i "}$IF ${PROTO:+"-p "}$PROTO -s $SRCIP $SRCPORT -d $DESTIP $DESTPORT ${UCPOLICY:+"-j"} $UCPOLICY
			$IPCHAINSBIN -I $DODIR 1 ${IF:+"-i"} $IF ${PROTO:+"-p"} $PROTO -s $SRCIP $SRCPORT -d $DESTIP $DESTPORT ${UCPOLICY:+"-j"} $UCPOLICY || logfail $LINENO Mason: YYYY 0003
			CKPTMASON=" mason: post specific rule" ; #ckpt $CKPTMASON
			UNDOSPECIFICRULE="$IPCHAINSBIN -D $DODIR ${IF:+"-i"} $IF ${PROTO:+"-p"} $PROTO -s $SRCIP $SRCPORT -d $DESTIP $DESTPORT ${UCPOLICY:+"-j"} $UCPOLICY || logfail $LINENO Mason: YYYY 0004"
			unset DODIR || :
		#FIXME - add in iptables section for quick stop.  Should we do a quick stop for iptables?
		fi # no need to handle DOCOMMAND=none :-)

#Put the dynamic IP addresses in the current environment.
		for ONEIF in $DYNIF ; do
			CKPTMASON=" mason: eval dynif of $ONEIF" ; #ckpt $CKPTMASON
			#this just places the value of a var right back in that same var!
			#eval ${ONEIF}ADDR=$(eval echo \${$(eval echo ${ONEIF}ADDR)})	#No, really.  That's the IP address.
			#Umm, this is what I think I need... *smile*
			eval ${ONEIF}ADDR=`ifconfig $ONEIF 2>/dev/null | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://' || logfail $LINENO Mason: YYYY 0005`
		done

		CKPTMASON=" mason: gen ip" ; #ckpt $CKPTMASON
		if [ "$INFORMAT" = "ipchains-lv" ]; then
			SRCHOST=$SRCIP
			DESTHOST=$DESTIP
		elif [ "$IGNOREPORT" = "YES" ]; then		#For non tcp/udp/icmp protocols (w/o port numbers), restrict to machine to machine
			HOLDIPCONV="$IPCONV"	#Convert to hostname, but honor Dynamic IP macros.  Temporarily set IPCONV to HOST to do this.
			IPCONV="HOST"
			SRCHOST=`generalizeip $SRCIP`
			DESTHOST=`generalizeip $DESTIP`
			IPCONV="$HOLDIPCONV"
		else
#If this is a DNS request and the server is one of those listed in /etc/resolv.conf, don't generalize the ip address.
#Also, don't generalize if this is one of the Sparse Server or Sparse Client protocols.

			HOLDIPCONV="$IPCONV" ; HOLDHOSTLOOKUP="$HOSTLOOKUP"
			if [ "$SRCPORT" = "53" ] && ( [ "$PROTO" = "udp" ] || [ "$PROTO" = "tcp" ] ) ; then
				for ONEDNSSERVER in $DNSSERVERS ; do
					if [ "$SRCIP" = "$ONEDNSSERVER" ]; then 
						if [ "$IPCONV" = "NETWORK" ]; then IPCONV="HOST" ; fi
						if [ "$HOSTLOOKUP" = "FULL" ]; then HOSTLOOKUP="FILESONLY" ; fi
					fi
				done
			fi
			for ONESPARSE in $SSP ; do
				if [ "$SRCPORT/$PROTO" = "$ONESPARSE" ] && [ "$IPCONV" = "NETWORK" ]; then IPCONV="HOST" ; fi
			done
			for ONESPARSE in $SCP ; do
				if [ "$DESTPORT/$PROTO" = "$ONESPARSE" ] && [ "$IPCONV" = "NETWORK" ]; then IPCONV="HOST" ; fi
			done
			SRCHOST=`generalizeip $SRCIP`
			IPCONV="$HOLDIPCONV" ; HOSTLOOKUP="$HOLDHOSTLOOKUP"

			HOLDIPCONV="$IPCONV" ; HOLDHOSTLOOKUP="$HOSTLOOKUP"
			if [ "$DESTPORT" = "53" ] && ( [ "$PROTO" = "udp" ] || [ "$PROTO" = "tcp" ] ) ; then
				for ONEDNSSERVER in $DNSSERVERS ; do
					if [ "$DESTIP" = "$ONEDNSSERVER" ]; then
						if [ "$IPCONV" = "NETWORK" ]; then IPCONV="HOST" ; fi
						if [ "$HOSTLOOKUP" = "FULL" ]; then HOSTLOOKUP="FILESONLY" ; fi
					fi
				done
			fi
			for ONESPARSE in $SSP ; do
				if [ "$DESTPORT/$PROTO" = "$ONESPARSE" ] && [ "$IPCONV" = "NETWORK" ]; then IPCONV="HOST" ; fi
			done
			for ONESPARSE in $SCP ; do
				if [ "$SRCPORT/$PROTO" = "$ONESPARSE" ] && [ "$IPCONV" = "NETWORK" ]; then IPCONV="HOST" ; fi
			done
			DESTHOST=`generalizeip $DESTIP`
			IPCONV="$HOLDIPCONV" ; HOSTLOOKUP="$HOLDHOSTLOOKUP"
		fi


#Clean up protocol type and number fields, visualize source and dest port fields, set ack flag.
#If port not in /etc/services and >=1024, generalize to "high port"
		CKPTMASON=" mason: port range and comment" ; #ckpt $CKPTMASON
		COMMENT2="" ;	COMMENT="$CMNT" ; SRCCISCOPORTSPEC="" ; DESTCISCOPORTSPEC=""
		
		if [ "$PROTO" = "tcp" ] || [ "$PROTO" = "udp" ]; then
			if [ -n "$SRCPORT" ]; then
				serverportrange "$SRCPORT" "$PROTO"
				if [ "$INFORMAT" = "ipchains-lv" ]; then SRCSERVICE="$SRCPORT" ; else SRCSERVICE="$READABLEPORT" ; fi
				SRCCOMMENT="$PARTIALCOMMENT"
			fi

			if [ -n "$DESTPORT" ]; then
				serverportrange "$DESTPORT" "$PROTO"
				if [ "$INFORMAT" = "ipchains-lv" ]; then DESTSERVICE="$DESTPORT" ; else DESTSERVICE="$READABLEPORT" ; fi
				DESTCOMMENT="$PARTIALCOMMENT"
			fi
			CKPTMASON=" mason: src $SRCSERVICE $SRCCOMMENT dest $DESTSERVICE $DESTCOMMENT" ; #ckpt $CKPTMASON

			if [ "$INFORMAT" != "ipchains-lv" ]; then 
				if [ "$PROTO" = "tcp" ] && [ "$INFORMAT" != "ipchains-lv" ]; then
					#The ack flag should be set if port=tcp and source port is a server service.
					#The one tcpdump I've seen of an ftp connection seems to indicate that the 
					#ftp-data connection is from the _server_ to the client - backwards.
					#Passive mode FTP is supposed to reverse this.  Ugh.  And again, I say, Ugh.
					#FIXME - use the SYN / PENANCE flag Rusty's putting into later 2.2's.  Thanks, Rusty!
					#From 2.2.10/ip_fw.c:
					#if(tcp->syn && !(tcp->ack || tcp->rst))
						#tcpsyn=1;
					#if [ "$SYNFLAGSEEN" = "YES" ] && [ "SYNFLAG" != "SYN" ]; then
						#ACK="-k"	#Change next line to elif - hmmm, did I if block this right?
					if [ -n "$SRCSERVICE" ] && [ -z "$DESTSERVICE" ] && [ "$SRCPORT/$PROTO" != "20/tcp" ]; then
						ACK="-k"
					fi
					if [ "$GENERALIZETCPACK" = "YES" ] && [ "$ACK" = "-k" ]; then
						#If we're in this section we already know PROTO=tcp
						if [ "$UCPOLICY" = "ACCEPT" ] || [ "$UCPOLICY" = "MASQ" ]; then
							if isdigits "$SRCPORT"; then
								SRCSERVICE=`generalportrange "$SRCPORT"` ;		SRCCOMMENT="GENERALIZED TCP RESPONSE - place last"
							fi
							if isdigits "$DESTPORT"; then
								DESTSERVICE=`generalportrange "$DESTPORT"` ;	DESTCOMMENT="GENERALIZED TCP RESPONSE - place last"
							fi
						fi	#Is accept or masq
					fi	#Generalizetcpack and ack flag set
				fi	#proto=tcp and not ipchains-lv

				CKPTMASON=" mason: port and service sservice $SRCSERVICE dservice $DESTSERVICE" ; #ckpt $CKPTMASON
				if [ -n "$SRCSERVICE" ] && [ -n "$DESTSERVICE" ]; then		# Both source and destination ports are servers.  Rare, but possible.
					SRCPORT=$SRCSERVICE
					DESTPORT=$DESTSERVICE
				elif [ -n "$SRCSERVICE" ]; then								# Source port is a server port.
					DESTPORT=`clientportrange "$DESTPORT" "$SRCPORT" "$PROTO" "$ACK"`
					settos "$SRCPORT" "$SRCSERVICE" "$PROTO"
					SRCPORT=$SRCSERVICE
				elif [ -n "$DESTSERVICE" ]; then							# Dest port is a server port.
					SRCPORT=`clientportrange "$SRCPORT" "$DESTPORT" "$PROTO" "$ACK"`
					settos "$DESTPORT" "$DESTSERVICE" "$PROTO"
					DESTPORT=$DESTSERVICE
				else														# Neither source nor dest is a server port.
					#COMMENT2="$CMNT$CMNT S=`nameof $SRCIP`:$SRCPORT D=`nameof $DESTIP`:$DESTPORT"
#FIXME - put in case to test for null, */0, local IP, otherwise display
					COMMENT2="$CMNT$CMNT"
					if [ -n "$SRCIP" ]; then	COMMENT2="$COMMENT2 S=`nameof $SRCIP`" ; 	fi
					if [ -n "$SRCPORT" ]; then	COMMENT2="$COMMENT2:$SRCPORT" ;				fi
					if [ -n "$DESTIP" ]; then	COMMENT2="$COMMENT2 D=`nameof $DESTIP`" ;	fi
					if [ -n "$DESTPORT" ]; then	COMMENT2="$COMMENT2:$DESTPORT" ;			fi
					ORIGSRCPORT=$SRCPORT
					SRCPORT=`clientportrange "$SRCPORT" "$DESTPORT" "$PROTO" "$ACK"`
					DESTPORT=`clientportrange "$DESTPORT" "$ORIGSRCPORT" "$PROTO" "$ACK"`
					unset ORIGSRCPORT
					#if [ "$INFORMAT" != "ipchains-lv" ]; then TOS=" -t 0x01 0x08" ; fi		#Maximize throughput on the assumption that this is FTP data or irc dcc?

					#If we have a high port to high port connection (darn ftp and irc dcc), do _not_ generalize to anywhere
					if [ "$SRCPORT" = "1024:65535" ] && [ "$DESTPORT" = "1024:65535" ]; then
						if [ "$SRCHOST" = "0/0" ]; then
							HOLDIPCONV="$IPCONV" ; IPCONV="HOST" ; SRCHOST=`generalizeip $SRCIP` ; IPCONV="$HOLDIPCONV"
						fi
						if [ "$DESTHOST" = "0/0" ]; then
							HOLDIPCONV="$IPCONV" ; IPCONV="HOST" ; DESTHOST=`generalizeip $DESTIP` ; IPCONV="$HOLDIPCONV"
						fi
					fi
				fi
				if [ -n "$SRCCOMMENT" ]; then COMMENT="$COMMENT $SRCCOMMENT" ; fi
				if [ -n "$DESTCOMMENT" ]; then
					if [ "$SRCCOMMENT" != "$DESTCOMMENT" ]; then COMMENT="$COMMENT $DESTCOMMENT" ; fi
				fi
				COMMENT="$COMMENT ($DIRLETTER)"
				SRCCISCOPORTSPEC="`port2ciscoport $SRCPORT $PROTO`"
				DESTCISCOPORTSPEC="`port2ciscoport $DESTPORT $PROTO`"
			fi	#not ipchains-lv
		elif [ "$PROTO" = "icmp" ]; then	#Handle ICMP comments
			convicmpcode $SRCPORT $DESTPORT
			#FIXME - maybe someday we'll do the cisco conversions to names too.
			DESTCISCOPORTSPEC=" $SRCPORT${DESTPORT:+" "}$DESTPORT"
		else	#Handle non tcp/udp/icmp protocols
			COMMENT="$CMNT $PROTO ($DIRLETTER)"
			#COMMENT2="$CMNT$CMNT S=`nameof $SRCIP` D=`nameof $DESTIP`"
			COMMENT2="$CMNT$CMNT"
#FIXME - put in case to test for null, */0, otherwise display
			if [ -n "$SRCIP" ]; then	COMMENT2="$COMMENT2 S=`nameof $SRCIP`" ; 	fi
			if [ -n "$DESTIP" ]; then	COMMENT2="$COMMENT2 D=`nameof $DESTIP`" ; 	fi
		fi
		if [ -n "$NUMPACKETS" ]; then	COMMENT2="$COMMENT2 #^ $NUMPACKETS" ; fi
		if [ -n "$NUMBYTES" ]; then		COMMENT2="$COMMENT2 #@ $NUMBYTES" ; fi

		#if [ "$LINEHASDYNAMIC" = "YES" ]; then COMMENT="$COMMENT DynamicIP" ; fi
		#LINEHASDYNAMIC is not exported because generalizeip is a function.  Not used.

		CKPTMASON=" mason: var debug" ; #ckpt $CKPTMASON
		if [ "$DEBUG" = "YES" ]; then
			echo J1=$J1 J2=$J2 J3=$J3 J4=$J4 J5=$J5 J6=$J6 J7=$J7 J8=$J8 >/dev/stderr 
			echo J9=$J9 J10=$J10 J11=$J11 J12=$J12 J13=$J13 J14=$J14 J15=$J15 J16=$J16 >/dev/stderr
			echo J17=$J17 J18=$J18 J19=$J19 DIR=$DIR DIRLETTER=$DIRLETTER >/dev/stderr
			echo MESSPOL=$MESSPOL IF=$IF PROTO=$PROTO SRC=$SRC DEST=$DEST LFLAG=$LFLAG >/dev/stderr
			echo SFLAG=$SFLAG IFLAG=$IFLAG FOFLAG=$FOFLAG FFLAG=$FFLAG TFLAG=$TFLAG DFFLAG=$DFFLAG TAIL=$TAIL >/dev/stderr
			echo Unused: DFFLAG, FFLAG, FOFLAG, IFLAG, LFLAG, MESSPOL, SFLAG, TFLAG >/dev/stderr
		fi


#Actually create and implement the firewall command to display.
		CKPTMASON=" mason: Display" ; #ckpt $CKPTMASON
		DODISPLAY="YES"
		case "$ECHOCOMMAND" in
		#CURRENT=`awk "BEGIN {printf \"%x %0.0s %-12s %s x \n\", 57005, \"$AA$BB\", \"aaa\", \"cheeky\"}"`
		ipchains)
			CKPTMASON=" mason: ipchains display" ; #ckpt $CKPTMASON
			case "$ACK" in
			""|"  ")	ECHOACK=""									;;
			"-k")		ECHOACK="! -y"								;;
			"! -k")		ECHOACK="-y"								;;
			esac
			if [ -n "$LOGTHIS" ]; then LOGTHIS="-l" ; fi
#Handle 0/0 host spec or missing port spec - thanks, Rusty!
			case $SRCHOST in
			*/0|*/0.0.0.0)	if [ -n "$SRCPORT" ]; then SRCSPEC="--sport $SRCPORT " ;		else SRCSPEC="" ; fi					;;
			*)				if [ -n "$SRCPORT" ]; then SRCSPEC="-s $SRCHOST $SRCPORT " ;	else SRCSPEC="-s $SRCHOST " ; fi		;;
			esac
			case $DESTHOST in
			*/0|*/0.0.0.0)	if [ -n "$DESTPORT" ]; then DESTSPEC="--dport $DESTPORT" ;		else DESTSPEC="" ; fi				;;
			*)				if [ -n "$DESTPORT" ]; then DESTSPEC="-d $DESTHOST $DESTPORT" ;	else DESTSPEC="-d $DESTHOST" ; fi	;;	
			esac
			#CURRENT="$IPCHAINSBIN -A $DIR ${IF:+"-i "}$IF ${PROTO:+"-p "}$PROTO $ECHOACK $SRCSPEC$DESTSPEC$TOS ${UCPOLICY:+"-j"} $UCPOLICY $LOGTHIS" #TOS is either blank or has a leading space #REMOVEME
#FIXME - dont pad variables any more.     -------------15----12----9----12---5---83 = 136
			CKPTMASON=" mason: ipchains display - awk" ; #ckpt $CKPTMASON
			CURRENT=`awk "BEGIN {printf \"$IPCHAINSBIN %-11s %-8s %-11s %4s %-83s\", \
					\"${DIR:+"-A "}$DIR\", \
					\"${IF:+"-i "}$IF\", \
					\"${PROTO:+"-p "}$PROTO\", \
					\"$ECHOACK\", \
					\"$SRCSPEC$DESTSPEC$TOS${MINMARK:+" -m "}$MINMARK${UCPOLICY:+" -j "}$UCPOLICY${LOGTHIS:+" "}$LOGTHIS\" \
					}" || logfail $LINENO Mason: YYYY 0006`
			if [ -n "$MINMARK" ]; then INCMINMARK="1" ; fi
																				;;
		#FIXME - add iptables section

#ZZZZ - start of ECHOCOMMAND conversion to iptables.  This is NOT complete.
		iptables)
			CKPTMASON=" mason: iptables display" ; #ckpt $CKPTMASON
			#FIXME - fix ACK matching
			case "$ACK" in
			""|"  ")	ECHOACK=""									;;
			"-k")		ECHOACK="! -y"								;;
			"! -k")		ECHOACK="-y"								;;
			esac
			#FIXME - fix logging
			if [ -n "$LOGTHIS" ]; then LOGTHIS="-l" ; fi
#Handle 0/0 host spec or missing port spec - thanks, Rusty!
			case $SRCHOST in
			*/0|*/0.0.0.0)	if [ -n "$SRCPORT" ]; then SRCSPEC="--sport $SRCPORT " ;		else SRCSPEC="" ; fi					;;
			*)				if [ -n "$SRCPORT" ]; then SRCSPEC="-s $SRCHOST $SRCPORT " ;	else SRCSPEC="-s $SRCHOST " ; fi		;;
			esac
			case $DESTHOST in
			*/0|*/0.0.0.0)	if [ -n "$DESTPORT" ]; then DESTSPEC="--dport $DESTPORT" ;		else DESTSPEC="" ; fi				;;
			*)				if [ -n "$DESTPORT" ]; then DESTSPEC="-d $DESTHOST $DESTPORT" ;	else DESTSPEC="-d $DESTHOST" ; fi	;;	
			esac
			#CURRENT="$IPCHAINSBIN -A $DIR ${IF:+"-i "}$IF ${PROTO:+"-p "}$PROTO $ECHOACK $SRCSPEC$DESTSPEC$TOS ${UCPOLICY:+"-j"} $UCPOLICY $LOGTHIS" #TOS is either blank or has a leading space #REMOVEME
#FIXME - dont pad variables any more.     -------------15----12----9----12---5---83 = 136
			CKPTMASON=" mason: ipchains display - awk" ; #ckpt $CKPTMASON
			CURRENT=`awk "BEGIN {printf \"$IPTABLESBIN %-11s %-8s %-11s %4s %-83s\", \
					\"${DIR:+"-A "}$DIR\", \
					\"${IF:+"-i "}$IF\", \
					\"${PROTO:+"-p "}$PROTO\", \
					\"$ECHOACK\", \
					\"$SRCSPEC$DESTSPEC$TOS${MINMARK:+" -m "}$MINMARK${UCPOLICY:+" -j "}$UCPOLICY${LOGTHIS:+" "}$LOGTHIS\" \
					}" || logfail $LINENO Mason: YYYY 0007`
			if [ -n "$MINMARK" ]; then INCMINMARK="1" ; fi
																				;;
#ZZZZ - end of conversion

		ipchains-save)		#Currently experimental
			CKPTMASON=" mason: ipchains-save display" ; #ckpt $CKPTMASON
			case "$ACK" in
			"  ")		ECHOACK=""									;;
			"-k")		ECHOACK="! -y"								;;
			"! -k")		ECHOACK="-y"								;;
			esac
			if [ -n "$LOGTHIS" ]; then LOGTHIS="-l" ; fi
			case $SRCHOST in
			*/0|*/0.0.0.0)	SRCSPEC=" -s 0.0.0.0/0.0.0.0"											;;
			*)				SRCSPEC=" -s ${SRCHOST%%/*}/`bits2mask ${SRCHOST##*/}`"					;;
			esac
			case "$SRCPORT" in		#serverportrange should have returned a numeric port for ipchains-save
			"")				SRCSPEC="$SRCSPEC 0:65535"												;;
			*:*)			SRCSPEC="$SRCSPEC $SRCPORT"												;;
			*)				SRCSPEC="$SRCSPEC $SRCPORT:$SRCPORT"									;;
			esac
			case $DESTHOST in
			*/0|*/0.0.0.0)	DESTSPEC=" -d 0.0.0.0/0.0.0.0"											;;
			*)				DESTSPEC=" -d ${DESTHOST%%/*}/`bits2mask ${DESTHOST##*/}`"				;;
			esac
			case "$DESTPORT" in
			"")				DESTSPEC="$DESTSPEC 0:65535"											;;
			*:*)			DESTSPEC="$DESTSPEC $DESTPORT"											;;
			*)				DESTSPEC="$DESTSPEC $DESTPORT:$DESTPORT"								;;
			esac
			PROTONUMBER=`grep -i "^$PROTO[[:space:]]" /etc/protocols | awk '{print $2}' || logfail $LINENO Mason: YYYY 0008`	#Head -1?
			if [ -z "$PROTONUMBER" ]; then
				#CURRENT="-A $DIR $SRCSPEC $DESTSPEC ${IF:+"-i "}$IF ${PROTO:+"-p "}$PROTO $TOS ${UCPOLICY:+"-j "}$UCPOLICY $LOGTHIS $ECHOACK ${MINMARK:+"-m"} $MINMARK" #TOS is either blank or has a leading space #REMOVEME
				CURRENT=`awk "BEGIN {printf \"%-111s\", \
						\"${DIR:+"-A "}$DIR$SRCSPEC$DESTSPEC${IF:+" -i "}$IF${PROTO:+" -p "}$PROTO$TOS${UCPOLICY:+" -j "}$UCPOLICY${LOGTHIS:+" "}$LOGTHIS${ECHOACK:+" "}$ECHOACK${MINMARK:+" -m "}$MINMARK\" }" || logfail $LINENO Mason: YYYY 0009`
			else
				#CURRENT="-A $DIR $SRCSPEC $DESTSPEC ${IF:+"-i "}$IF ${PROTONUMBER:+"-p "}$PROTONUMBER $TOS ${UCPOLICY:+"-j "}$UCPOLICY $LOGTHIS $ECHOACK ${MINMARK:+"-m"} $MINMARK" #TOS is either blank or has a leading space #REMOVEME
				CURRENT=`awk "BEGIN {printf \"%-111s\", \
						\"${DIR:+"-A "}$DIR$SRCSPEC$DESTSPEC${IF:+" -i "}$IF${PROTONUMBER:+" -p "}$PROTONUMBER$TOS${UCPOLICY:+" -j "}$UCPOLICY${LOGTHIS:+" "}$LOGTHIS${ECHOACK:+" "}$ECHOACK${MINMARK:+" -m "}$MINMARK\" }" || logfail $LINENO Mason: YYYY 0010`
			fi
																				;;
		ipfwadm)
			CKPTMASON=" mason: ipfwadm display" ; #ckpt $CKPTMASON
			if [ -n "$LOGTHIS" ]; then LOGTHIS="-o" ; fi
			#CURRENT="$IPFWADMBIN -a $LCPOLICY ${IF:+"-W "}$IF ${DIRLETTER:+"-"}$DIRLETTER ${PROTO:+"-P "}$PROTO $ACK -S $SRCHOST $SRCPORT -D $DESTHOST $DESTPORT$TOS $LOGTHIS" #REMOVEME
			CURRENT=`awk "BEGIN {printf \"$IPFWADMBIN  %-9s %-8s %-2s %-11s %4s %-72s\", \
					\"${LCPOLICY:+"-a "}$LCPOLICY\", \
					\"${IF:+"-W "}$IF\", \
					\"${DIRLETTER:+"-"}$DIRLETTER\", \
					\"${PROTO:+"-P "}$PROTO\", \
					\"$ACK\", \
					\"-S $SRCHOST $SRCPORT -D $DESTHOST $DESTPORT$TOS $LOGTHIS\" \
					}" || logfail $LINENO Mason: YYYY 0011`
			case $PROTO in
			[Tt][Cc][Pp]|[Uu][Dd][Pp]|[Ii][Cc][Mm][Pp])
				eval "$IPFWADMBIN ${LCPOLICY:+"-i"} $LCPOLICY ${IF:+"-W"} $IF -$DIRLETTER ${PROTO:+"-P"} $PROTO $ACK -S $SRCHOST $SRCPORT -D $DESTHOST $DESTPORT $TOS $LOGTHIS || logfail $LINENO Mason: YYYY 0012"
																			;;
			*)
				CURRENT="# $CURRENT"
				#only show the warning once.
				if [ -z "$NONIPFWADMPROTOWARNED" ]; then
					echo "# ipfwadm cannot handle protocols other than tcp, udp and icmp." >/dev/stderr
					echo "# This rule wanted to use protocol: $PROTO." >/dev/stderr
					echo "# This is the only warning you will get this run.">/dev/stderr
					NONIPFWADMPROTOWARNED="YES"
				fi
																			;;
			esac
																				;;
		cisco)
#FIXME handle comments to user for $IF, $DIRLETTER, fix "eq", TOS format? no forwarding rules (maybe in baserules?)
#FIXME - is this screwing up the DOCOMMAND=ipchains parameters?
			CKPTMASON=" mason: cisco display" ; #ckpt $CKPTMASON
			if [ "$DIRLETTER" = "F" ]; then
				DODISPLAY="NO" ; echo "Forwarding rule skipped in cisco mode" >/dev/stderr
			elif [ "$IF" = "lo" ]; then
				DODISPLAY="NO" ; echo "Loopback interface skipped in cisco mode" >/dev/stderr
			else
				case "$LCPOLICY" in
				"reject"|"deny  "|"deny")						CISCOPOLICY="deny"		;;
				"accept"|"accept -m")							CISCOPOLICY="permit"	;;	#Cisco Masq? sorry, do not know how.
				*)												CISCOPOLICY="unknown"	;;
				esac
				case "$ACK" in
				"  ")		ECHOACK=""									;;
				"-k")		ECHOACK="established"						;;
				"! -k")		ECHOACK=""									;;
				esac
				if [ -n "$LOGTHIS" ]; then LOGTHIS="log" ; fi
				if [ -n "$TOS" ]; then CISCOTOS=" tos$TOS" ; else CISCOTOS="" ; fi
				case $IF in
				eth0)		CISCOIF="E0"	;;
				eth1)		CISCOIF="E1"	;;
				eth2)		CISCOIF="E2"	;;
				eth3)		CISCOIF="E3"	;;
				ppp0)		CISCOIF="S0"	;;
				ppp1)		CISCOIF="S1"	;;
				ppp2)		CISCOIF="S2"	;;
				ppp3)		CISCOIF="S3"	;;
				tr0)		CISCOIF="To0"	;;
				tr1)		CISCOIF="To1"	;;
				tr2)		CISCOIF="To2"	;;
				tr3)		CISCOIF="To3"	;;
				*)			CISCOIF="`echo "$IF" | sed -e 's/^eth/E/' -e 's/^ppp/S/' -e 's/^tr/To/'`"	;;
				esac
				#CURRENT="access-list $DIRLETTER$CISCOIF $CISCOPOLICY $PROTO $SRCHOST$SRCCISCOPORTSPEC $DESTHOST$DESTCISCOPORTSPEC$CISCOTOS $ECHOACK $LOGTHIS" #REMOVEME
				CURRENT=`awk "BEGIN {printf \"access-list %-4s %-6s %-8s %-90s\", \
						\"$DIRLETTER$CISCOIF\", \
						\"$CISCOPOLICY\", \
						\"$PROTO\", \
						\"$SRCHOST$SRCCISCOPORTSPEC $DESTHOST$DESTCISCOPORTSPEC$CISCOTOS $ECHOACK $LOGTHIS\" \
						}" || logfail $LINENO Mason: YYYY 0013`
			fi
																				;;
		esac # No need to handle ECHOCOMMAND=none :-)
		CKPTMASON=" mason: finished display" ; #ckpt $CKPTMASON

		if [ "$DEBUG" = "YES" ]; then echo current= "$CURRENT" >/dev/stderr ; fi

		if [ -n "$UNDOSPECIFICRULE" ]; then eval "$UNDOSPECIFICRULE" ; fi

#Don't do anything if this is the same as one of the last 8 rules.  This 
#reduces the occurence of repeated rules showing up.
		CKPTMASON=" mason: Implement new rule" ; #ckpt $CKPTMASON
		#Yank mark values before comparing
		case `echo $CURRENT | sed -e 's/ -m [0-9][0-9]* //'` in
		$LAST1|$LAST2|$LAST3|$LAST4|$LAST5|$LAST6|$LAST7|$LAST8)
			if [ "$HEARTBEAT" = "YES" ]; then echo -n "-" >/dev/stderr ; NEEDLF="YES" ; fi
																;;
		*)
			if [ "$NEEDLF" = "YES" ]; then echo >/dev/stderr ; NEEDLF="NO" ; fi
			if [ "$DOBEEP" = "YES" ]; then echo -n -e "\a" >/dev/stderr ; fi
			if [ "$DODISPLAY" = "YES" ]; then
				case $ECHOCOMMAND in
				ipchains|ipfwadm|cisco|iptables)	echo "$CURRENT $COMMENT $COMMENT2"		;;
				ipchains-save)						echo $CURRENT							;;
				esac
			fi


#Put a real rule in the rule chain so that we don't log it again.  We need to use eval since ${xxxHOST} may be a $DYNIP 
#and may need to be evaluated to its real value.
			CKPTMASON=" mason: Actually put new rule in" ; #ckpt $CKPTMASON
			if [ "$DOCOMMAND" = "ipfwadm" ]; then
				if [ -n "$LOGTHIS" ]; then LOGTHIS="-o" ; fi
				case $PROTO in
				[Tt][Cc][Pp]|[Uu][Dd][Pp]|[Ii][Cc][Mm][Pp])
					eval "$IPFWADMBIN ${LCPOLICY:+"-i"} $LCPOLICY ${IF:+"-W"} $IF -$DIRLETTER ${PROTO:+"-P"} $PROTO $ACK -S $SRCHOST $SRCPORT -D $DESTHOST $DESTPORT $TOS $LOGTHIS || logfail $LINENO Mason: YYYY 0014"
																				;;
				*)
					#only show the warning once.
					if [ -z "$NONIPFWADMPROTOWARNED" ]; then
						echo "# ipfwadm cannot handle protocols other than tcp, udp and icmp." >/dev/stderr
						echo "# This rule wanted to use protocol: $PROTO." >/dev/stderr
						echo "# This is the only warning you will get this run.">/dev/stderr
						NONIPFWADMPROTOWARNED="YES"
					fi
																				;;
				esac
			elif [ "$DOCOMMAND" = "ipchains" ]; then
				case "$ACK" in
				""|"  ")	DOACK=""									;;
				"-k")		DOACK="! -y"								;;
				"! -k")		DOACK="-y"									;;
				esac
				if [ -n "$LOGTHIS" ]; then LOGTHIS="-l" ; fi
				case $DIRLETTER in
				I)		DIR="input$NOLOGSUFFIX"					;;
				O)		DIR="output$NOLOGSUFFIX"				;;
				F)		DIR="forward$NOLOGSUFFIX"				;;
				esac
				eval "$IPCHAINSBIN ${DIR:+"-I"} $DIR 1 ${IF:+"-i"} $IF ${PROTO:+"-p"} $PROTO $DOACK -s $SRCHOST $SRCPORT -d $DESTHOST $DESTPORT $TOS ${MINMARK:+"-m"} $MINMARK ${UCPOLICY:+"-j"} $UCPOLICY $LOGTHIS || logfail $LINENO Mason: YYYY 0015"
				if [ -n "$MINMARK" ]; then INCMINMARK="1" ; fi
#ZZZZ - start conversion to iptables.  NOT complete.
			elif [ "$DOCOMMAND" = "iptables" ]; then
				case "$ACK" in
				""|"  ")	DOACK=""									;;
				"-k")		DOACK="! -y"								;;
				"! -k")		DOACK="-y"									;;
				esac
				if [ -n "$LOGTHIS" ]; then LOGTHIS="-l" ; fi
				case $DIRLETTER in
				I)		DIR="input$NOLOGSUFFIX"					;;
				O)		DIR="output$NOLOGSUFFIX"				;;
				F)		DIR="forward$NOLOGSUFFIX"				;;
				esac
				eval "$IPTABLESBIN ${DIR:+"-I"} $DIR 1 ${IF:+"-i"} $IF ${PROTO:+"-p"} $PROTO $DOACK -s $SRCHOST $SRCPORT -d $DESTHOST $DESTPORT $TOS ${MINMARK:+"-m"} $MINMARK ${UCPOLICY:+"-j"} $UCPOLICY $LOGTHIS || logfail $LINENO Mason: YYYY 0016"
				if [ -n "$MINMARK" ]; then INCMINMARK="1" ; fi
#ZZZZ - end iptables conversion
			fi # no need to handle DOCOMMAND=none :-)
			CKPTMASON=" mason: push current rule on last stack" ; #ckpt $CKPTMASON
			LAST8=$LAST7 ; LAST7=$LAST6 ; LAST6=$LAST5 ; LAST5=$LAST4
			LAST4=$LAST3 ; LAST3=$LAST2 ; LAST2=$LAST1 ; LAST1=`echo $CURRENT | sed -e 's/ -m [0-9][0-9]* //' || logfail $LINENO Mason: YYYY 0017`	;;
		esac #Check that current isn't equal to one of the previous 8 rules.

		if [ "$DEBUG" = "YES" ]; then  echo src= $SRCIP $SRCPORT dest= $DESTIP $DESTPORT if= $IF proto= $PROTO >/dev/stderr ; fi

		if [ "$LCPOLICY" = "accept -m" ]; then	#Reset policy to non-masq for the next rule.
			UCPOLICY="ACCEPT" ; LCPOLICY="accept"
		fi
	fi #if ISLOGLINE

	if [ -n "$MINMARK" ]; then MINMARK=$[ $MINMARK + $INCMINMARK ] ; fi

#Get the next log entry and start over.
	unset ACK COMMENT DEST DESTHOST DESTIP DESTPORT DIR DIRLETTER DOACK ECHOACK IF IGNOREPORT INIF ISLOGLINE \
	LINEHASDYNAMIC LOGTHIS MESSPOL NUMBYTES NUMPACKETS PROTO SRC SRCHOST SRCIP SRCPORT SYNFLAG SYNFLAGSEEN TAIL TOS || :
	#unset DFFLAG FFLAG FOFLAG IFLAG LFLAG SFLAG TFLAG || :		#These are unused.
	if [ -n "$MINMARK" ]; then INCMINMARK="0" ; fi
	TOS=""
	A3=$O3 ; A4=$O4 ; A5=$O5 ; A6=$O6 ; A7=$O7 ; A8=$O8 ; A9=$O9 ; A10=$O10 ; A11=$O11 ; A12=$O12 ; A13=$O13
	O3=$J3 ; O4=$J4 ; O5=$J5 ; O6=$J6 ; O7=$J7 ; O8=$J8 ; O9=$J9 ; O10=$J10 ; O11=$J11 ; O12=$J12 ; O13=$J13
	#CKPTMASON=" mason: reading next line" ; #ckpt $CKPTMASON
	CKPTMASON="" ; #ckpt $CKPTMASON
	if ! read J1 J2 J3 J4 J5 J6 J7 J8 J9 J10 J11 J12 J13 J14 J15 J16 J17 J18 J19 J20 J21 J22 J23 J24 J25 J26 J27 J28 J29 J30 ; then
		if [ "$SIGGED" != "YES" ]; then EXITMASON="YES" ; fi
	fi
#Keep reading until a line with different firewall values is found.
	#FIXME - test for J19 once SYN checking is in place. J20+?
	#FIXME {O3=J3||INFORMAT=ipfwadm } or something like that for fields that don't need to be checked?  A function?
	while { [ "$O3"  = "$J3"  ] && [ "$O4"  = "$J4"  ] && [ "$O5"  = "$J5"  ] && [ "$O6" = "$J6" ] && \
			[ "$O7"  = "$J7"  ] && [ "$O8"  = "$J8"  ] && [ "$O9"  = "$J9"  ] && [ "$O10" = "$J10" ] && \
			[ "$O11" = "$J11" ] && [ "$O12" = "$J12" ] && [ "$O13" = "$J13" ] ; } ||
		  { [ "$A3"  = "$J3"  ] && [ "$A4"  = "$J4"  ] && [ "$A5"  = "$J5"  ] && [ "$A6" = "$J6" ] && \
			[ "$A7"  = "$J7"  ] && [ "$A8"  = "$J8"  ] && [ "$A9"  = "$J9"  ] && [ "$A10" = "$J10" ] && \
			[ "$A11" = "$J11" ] && [ "$A12" = "$J12" ] && [ "$A13" = "$J13" ] ; } ||
		  { [ "$SIGGED" = "YES" ] ; } ; do
		#CKPTMASON=" mason: duped line or sigged" ; #ckpt $CKPTMASON
		CKPTMASON="" ; #ckpt $CKPTMASON
		if [ "$EXITMASON" = "YES" ]; then continue ; fi
		if [ "$SIGGED" = "YES" ]; then
			SIGGED="NO"
		else
			if [ "$HEARTBEAT" = "YES" ]; then echo -n "." >/dev/stderr ; NEEDLF="YES" ; fi
			A3=$O3 ; A4=$O4 ; A5=$O5 ; A6=$O6 ; A7=$O7 ; A8=$O8 ; A9=$O9 ; A10=$O10 ; A11=$O11 ; A12=$O12 ; A13=$O13
			O3=$J3 ; O4=$J4 ; O5=$J5 ; O6=$J6 ; O7=$J7 ; O8=$J8 ; O9=$J9 ; O10=$J10 ; O11=$J11 ; O12=$J12 ; O13=$J13
		fi
		if ! read J1 J2 J3 J4 J5 J6 J7 J8 J9 J10 J11 J12 J13 J14 J15 J16 J17 J18 J19 J20 J21 J22 J23 J24 J25 J26 J27 J28 J29 J30 ; then
			if [ "$SIGGED" != "YES" ]; then EXITMASON="YES" ; fi
		fi
	done
done

#CKPTMASON=" mason: outside of main loop" ; #ckpt $CKPTMASON
CKPTMASON="" ; #ckpt $CKPTMASON
if [ "$NEEDLF" = "YES" ]; then echo >/dev/stderr ; NEEDLF="NO" ; fi
if [ "$J1" = '!!EXIT!!' ]; then
	echo Mason is exiting because of an exit request on stdin. >/dev/stderr
elif [ "$EXITMASON" = "YES" ]; then
	echo Mason is exiting because of a SIGHUP or EXITMASON=YES. >/dev/stderr
else
	echo Mason is exiting because of an end of input data. >/dev/stderr
fi

CKPTMASON=""

exit 0
