#!/bin/bash
set -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: 0024, use 0025 next

#cat <<EOTEXT1 >/dev/null
#	(The above line allows me to put the documentation right in the
#script... Cool, eh?  OK, I've had enough fun.  Now stop wasting customer 
#CPU Cycles!  *smile*)
#
#>>>>>>>>>>>>>>>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-2000 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.stearns.org/mason/
#snail:  6 Manchester Dr.
#        Lebanon NH, 03766, 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 EOTEXT1 line is the end of the text and the start of the code. 
#EOTEXT1

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

#ZZZZ
#DEBUG="non-null"

MASONDIR=${MASONDIR:-"/var/lib/mason/"}
MASONCONF=${MASONCONF:-"/etc/masonrc"}
MASONLIB=${MASONLIB:-"/var/lib/mason/masonlib"}
if [ -f $MASONLIB ]; then
	. $MASONLIB
else
	#Can't use wrap here - no library.
	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 1
fi

catchall
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

loadconf
checksys


#---------- Start of Main code ----------
CKPTMASON=" mason: Start main" ; #ckpt $CKPTMASON
echo $ENH "${HEADER}---- ${BLUE}Mason${HEADER} firewall builder for Linux                         ----${NORM}" >/dev/stderr
echo $ENH "${HEADER}---- see http://www.pobox.com/~wstearns/mason/ for more info. ----${NORM}" >/dev/stderr
echo $ENH "${HEADER}---- William Stearns <wstearns@pobox.com>                     ----${NORM}" >/dev/stderr 
if [ -n "$MASONVER" ]; then
	echo $ENH "${HEADER}(This is release $MASONVER )${NORM}" >/dev/stderr
fi
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
	ipof $ONEIF >>${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 | awk '/inet addr/{print substr($2,6)}'\`$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=`ipof $ONEIF` || 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 `chainnameof input` `chainnameof forward` `chainnameof 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'				;;
		*)	wrap ${WARN}Unknown direction $J8${NORM} >/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'					;;
			*)	wrap ${WARN}Unknown direction $J7${NORM} >/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 wrap 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=" ]
		IN=*|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
#FIXME - gracefully handle passing the interface to ipfwadm/ipchains/etc.
				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"
			#wrap J1=$J1 J2=$J2 J3=$J3 J4=$J4 J5=$J5 J6=$J6 J7=$J7 J8=$J8 J9=$J9 J10=$J10 J11=$J11 J12=$J12 J13=$J13 J14=$J14 J15=$J15 J16=$J16 J17=$J17 J18=$J18 J19=$J19 DIR=$DIR DIRLETTER=$DIRLETTER 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'					;;
			#*)	wrap ${WARN}Unknown direction $J7${NORM} >/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 wrap 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 [ "$J1" = "Chain" ]; then	#Load variables from ipchains -Lv listing; this is a header line.
		:
	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'							;;
			"")		wrap ${WARN}No chain name has been registered.  Mason cannot process this entry.${NORM} >/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
	elif [ "$J6" = "->" ]; then	#Load variables from an ipfilter log line
#1               2    3    4 5                   6  7                8  9    10  11 12   13   14
#15:57:33.803147 ppp0 @0:2 b 100.100.100.103,443 -> 20.20.20.10,4923 PR tcp  len 20 1488 -A 
#                     rule p                                                            flags
#                     #
#12:46:12.470951 xl0  @0:1 S 20.20.20.254        -> 255.255.255.255  PR icmp len 20 9216 icmp 9/0 
#                                                                                             router discovery
		:
	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
			#REMOVEME
			#$IPFWADMBIN -i $LCPOLICY ${IF:+"-W"} $IF -$DIRLETTER ${PROTO:+"-P"} $PROTO -S $SRCIP $SRCPORT -D $DESTIP $DESTPORT || logfail $LINENO Mason: YYYY 0001
#REMOVEME
			echo 0018 DIRLETTER $DIRLETTER >>${MASONDIR}masoncrash
			dorule i "$DIRLETTER" "$IF" '' "$PROTO" "$SRCIP" "$SRCPORT" "$DESTIP" "$DESTPORT" '' '' "$LCPOLICY" '' '' '' || logfail $LINENO Mason: YYYY 0018
			#UNDOSPECIFICRULE="$IPFWADMBIN -d $LCPOLICY ${IF:+"-W"} $IF -$DIRLETTER ${PROTO:+"-P"} $PROTO -S $SRCIP $SRCPORT -D $DESTIP $DESTPORT || logfail $LINENO Mason: YYYY 0002"
			#FIXME global - quoting on ''?
			UNDOSPECIFICRULE="dorule d \"$DIRLETTER\" \"$IF\" '' \"$PROTO\" \"$SRCIP\" \"$SRCPORT\" \"$DESTIP\" \"$DESTPORT\" '' '' \"$LCPOLICY\" '' '' '' || logfail $LINENO Mason: YYYY 0019"
			CKPTMASON=" mason: Process line, ipfwadm post specific rule" ; #ckpt $CKPTMASON
		elif [ "$DOCOMMAND" = "ipchains" ]; then
			case $DIRLETTER in
			I)		DODIR="`chainnameof input`$NOLOGSUFFIX"					;;
			O)		DODIR="`chainnameof output`$NOLOGSUFFIX"				;;
			F)		DODIR="`chainnameof forward`$NOLOGSUFFIX"				;;
			esac
			CKPTMASON=" mason: pre specific rule" ; #ckpt $CKPTMASON
			#REMOVEME
			#$IPCHAINSBIN -I $DODIR 1 ${IF:+"-i"} $IF ${PROTO:+"-p"} $PROTO -s $SRCIP $SRCPORT -d $DESTIP $DESTPORT ${UCPOLICY:+"-j"} $UCPOLICY || logfail $LINENO Mason: YYYY 0003 $IPCHAINSBIN -I $DODIR 1 ${IF:+"-i"} $IF ${PROTO:+"-p"} $PROTO -s $SRCIP $SRCPORT -d $DESTIP $DESTPORT ${UCPOLICY:+"-j"} $UCPOLICY
#REMOVEME
			echo 0020 DODIR $DODIR >>${MASONDIR}masoncrash
			dorule i "$DODIR" "$IF" '' "$PROTO" "$SRCIP" "$SRCPORT" "$DESTIP" "$DESTPORT" '' '' "$UCPOLICY" '' '' '' || logfail $LINENO Mason: YYYY 0020
			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"
			UNDOSPECIFICRULE="dorule d \"$DODIR\" \"$IF\" '' \"$PROTO\" \"$SRCIP\" \"$SRCPORT\" \"$DESTIP\" \"$DESTPORT\" '' '' \"$UCPOLICY\" '' '' '' || logfail $LINENO Mason: YYYY 0021"
			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=`ipof $ONEIF || 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
#ZZZZ - auth exception...
					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
			wrap J1=$J1 J2=$J2 J3=$J3 J4=$J4 J5=$J5 J6=$J6 J7=$J7 J8=$J8 J9=$J9 J10=$J10 J11=$J11 J12=$J12 J13=$J13 J14=$J14 J15=$J15 J16=$J16 J17=$J17 J18=$J18 J19=$J19 DIR=$DIR DIRLETTER=$DIRLETTER MESSPOL=$MESSPOL IF=$IF PROTO=$PROTO SRC=$SRC DEST=$DEST LFLAG=$LFLAG SFLAG=$SFLAG IFLAG=$IFLAG FOFLAG=$FOFLAG FFLAG=$FFLAG TFLAG=$TFLAG DFFLAG=$DFFLAG TAIL=$TAIL >/dev/stderr
			wrap 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
																				;;
#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="! --syn"							;;
			"! -k")		ECHOACK="--syn"								;;
			esac
			#FIXME - fix logging
			#if [ -n "$LOGTHIS" ]; then LOGTHIS="-l" ; fi
#Handle 0/0 host spec or missing port spec - thanks, Rusty!
			case $PROTO in
			[Ii][Cc][Mm][Pp])
				case $SRCHOST in
				*/0|*/0.0.0.0)	SRCSPEC=""					;;
				*)				SRCSPEC="-s $SRCHOST "		;;
				esac
				case $DESTHOST in
				*/0|*/0.0.0.0)	DESTSPEC=""					;;
				*)				DESTSPEC="-d $DESTHOST"		;;
				esac
				if [ -n "$SRCPORT" ]; then 
					if [ -n "$DESTSPEC" ]; then DESTSPEC="$DESTSPEC " ; fi
					DESTSPEC="$DESTSPEC--icmp-type $SRCPORT"
					if [ -n "$DESTPORT" ]; then
						DESTSPEC="$DESTSPEC/$DESTPORT"
					fi
				fi
				;;
			*)
				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 --sport $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 --dport $DESTPORT" ;	else DESTSPEC="-d $DESTHOST" ; fi	;;	
				esac
				;;
			esac
			if [ -n "$INIF" ] && [ -n "$IF" ]; then	IFSPEC="-i $INIF -o $IF"
			elif [ -n "$INIF" ]; then				IFSPEC="-i $INIF"
			elif [ -n "$IF" ]; then					IFSPEC="-o $IF"
			else									IFSPEC=""
			fi
			#CURRENT="$IPTABLESBIN -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: iptables display - awk" ; #ckpt $CKPTMASON
			CURRENT=`awk "BEGIN {printf \"$IPTABLESBIN %-11s %-8s %-11s %4s %-83s\", \
					\"${DIR:+"-A "}$DIR\", \
					\"$IFSPEC\", \
					\"${PROTO:+"-p "}$PROTO\", \
					\"$ECHOACK\", \
					\"$SRCSPEC$DESTSPEC$TOS${UCPOLICY:+" -j "}$UCPOLICY${LOGTHIS:+" "}$LOGTHIS\" \
					}" || logfail $LINENO Mason: YYYY 0007`
			#${MINMARK:+" -m "}$MINMARK	#FIXME - future mark support?
			#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])		#FIXME - should we be actually running a rule here?  I really think this is wrong.
				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="#(invalid protocol for ipfwadm) $CURRENT"
				#only show the warning once.
				if [ -z "$NONIPFWADMPROTOWARNED" ]; then
					wrap ${WARN}ipfwadm cannot handle protocols other than tcp, udp and icmp. This rule wanted to use protocol: $PROTO . This is the only warning you will get this run.${NORM} >/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" ; wrap Forwarding rule skipped in cisco mode. >/dev/stderr
			elif [ "$IF" = "lo" ]; then
				DODISPLAY="NO" ; wrap 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])
					#FIXME - here and below - watch out for data fields that have their own parameters "-t 0x..."
					#REMOVEME
					#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"
#REMOVEME
					echo 0022 DIRLETTER $DIRLETTER >>${MASONDIR}masoncrash
					dorule "i" "$DIRLETTER" "$IF" '' "$PROTO" "$SRCHOST" "$SRCPORT" "$DESTHOST" "$DESTPORT" '' "$ACK" "$LCPOLICY" "$TOS" "$LOGTHIS" "" || logfail $LINENO Mason: YYYY 0022
																				;;
				*)
					#only show the warning once.
					if [ -z "$NONIPFWADMPROTOWARNED" ]; then
						wrap ${WARN}ipfwadm cannot handle protocols other than tcp, udp and icmp. This rule wanted to use protocol: $PROTO. This is the only warning you will get this run${NORM}. >/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 #FIXME - yank these once we're using dorule.
				case $DIRLETTER in
				I)		DIR="`chainnameof input`$NOLOGSUFFIX"				;;
				O)		DIR="`chainnameof output`$NOLOGSUFFIX"				;;
				F)		DIR="`chainnameof forward`$NOLOGSUFFIX"				;;
				esac
				#REMOVEME
				#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"
#REMOVEME
				echo 0023 DIR $DIR >>${MASONDIR}masoncrash
				dorule i "$DIR" "$IF" '' "$PROTO" "$SRCHOST" "$SRCPORT" "$DESTHOST" "$DESTPORT" "$MINMARK" "$DOACK" "$UCPOLICY" "$TOS" "$LOGTHIS" "" || logfail $LINENO Mason: YYYY 0023
				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
				#FIXME - simplify, no case needed.  global fix.
				case $DIRLETTER in
				I)		DIR="`chainnameof INPUT`$NOLOGSUFFIX"				;;
				O)		DIR="`chainnameof OUTPUT`$NOLOGSUFFIX"				;;
				F)		DIR="`chainnameof FORWARD`$NOLOGSUFFIX"				;;
				esac
				#REMOVEME
				#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"
#REMOVEME
				echo 0024 DIR $DIR >>${MASONDIR}masoncrash	#Returns INPUTN, FORWARDN, OUTPUTN
				dorule i "$DIR" "$INIF" "$IF" "$PROTO" "$SRCHOST" "$SRCPORT" "$DESTHOST" "$DESTPORT" "$MINMARK" "$DOACK" "$UCPOLICY" "$TOS" "$LOGTHIS" "" || logfail $LINENO Mason: YYYY 0024
				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 wrap 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
	wrap Mason is exiting because of an exit request on stdin. >/dev/stderr
elif [ "$EXITMASON" = "YES" ]; then
	wrap Mason is exiting because of a SIGHUP or EXITMASON=YES. >/dev/stderr
else
	wrap Mason is exiting because of an end of input data. >/dev/stderr
fi

CKPTMASON=""

exit 0
