#
# Defs configuration file for netscript.
#

# If below is adjusted, please change stuff in 
# /etc/netscript/netscript-compile.conf
FWDCHAIN="ipfwd"
LOCALCHAIN="iplcl"

# Source the compiled functions
IPFILTER_DEFS_COMPILED="/etc/netscript/ipfilter-defs-compiled.conf"
[ -f $IPFILTER_DEFS_COMPILED ] && source $IPFILTER_DEFS_COMPILED


# Generate the firewall rule set.
ipf4_Configure () {
	local CHAIN=""

	# Set Default Policies
	$IPTBL -t filter -P INPUT DROP
	$IPTBL -t filter -P FORWARD DROP
	$IPTBL -t filter -P OUTPUT ACCEPT
	
	$IPTBL -t nat -P PREROUTING ACCEPT
	$IPTBL -t nat -P POSTROUTING ACCEPT
	$IPTBL -t nat -P OUTPUT ACCEPT

	# Clear all tables except mangle
	$IPTBL -t filter -F 
	$IPTBL -t filter -X
	$IPTBL -t nat -F 
	$IPTBL -t nat -X


	# Populate the Input Chain
	ipf4_INPUT

	# Populate the Forwarding Chain
	ipf4_FORWARD

	if [ "$USE_COMPILED_NAT" = "YES" \
		-o "$USE_COMPILED_NAT" = "Yes" \
		-o "$USE_COMPILED_NAT" = "yes" ]
	then
		qt type ipf4_POSTROUTING \
			&& ipf4_POSTROUTING
		
		qt type ipf4_PREROUTING \
			&& ipf4_PREROUTING
	fi
	
	return 0
}


# populate input chain
ipf4_INPUT () {
	local CHAIN=INPUT
	local TUPLE IF	

	# Clean out any existing chain
	qt $IPTBL -F $CHAIN
	# Set chain policy
	$IPTBL -P $CHAIN DROP

	# Make sure prerequisite chains are around
	ipv4_createChain droplog log droplog DROP 	# default log target
	ipv4_createChain log log			# Alternate log target
	ipv4_createChain icmphost icmphost		# ICMP protection...

	
	# Groom input
	# Detect Portscans
	[ "$INPUT_DETECT_PORTSCAN" = "YES" \
		-o  "$INPUT_DETECT_PORTSCAN" = "Yes" \
		-o  "$INPUT_DETECT_PORTSCAN" = "yes" ] \
	&& ipv4_createChain portscan portscan \
	&&	$IPTBL -A $CHAIN -j portscan 
	
        # Accept everything off the local interface
        $IPTBL -A $CHAIN -i lo -j ACCEPT

	# Deal with log noise 
	# Drop RIP and IPP packets from other boxes.... just noise
	for TUPLE in $INPUT_DROP; do
		$IPTBL -A $CHAIN -j DROP \
			-p `echoParam '$1' $TUPLE` \
			-i `echoParam '$2' $TUPLE` \
			-d `echoIpPort '$3' ' --dport $4' '$4' $TUPLE` 
	done	

	# Deal with incoming Broadcast
	[ "$INPUT_DROP_BROADCAST" = "YES" \
                -o  "$INPUT_DROP_BROADCAST" = "Yes" \
                -o  "$INPUT_DROP_BROADCAST" = "yes" ] \
		&& $IPTBL -A $CHAIN -j DROP -m pkttype --pkt-type BROADCAST

	# Deal with martians
	[ -n "INPUT_MARTIAN_IF" ] && ipv4_createChain martians martians
	for IF in $INPUT_MARTIAN_IF; do
		$IPTBL -A $CHAIN -j martians -i $IF
	done
			
	# Do ingress filtering	
	[ -n "INPUT_INGRESS_IF" ] && ipv4_createChain ingress ingress
	for IF in $INPUT_INGRESS_IF; do
		$IPTBL -A $CHAIN -j ingress -i $IF
	done

	# Clean up icmp
	$IPTBL -A $CHAIN -j icmphost

	# Deal with incoming SMB
	[ "$INPUT_REJECT_SMB" = "YES" \
                -o  "$INPUT_REJECT_SMB" = "Yes" \
                -o  "$INPUT_REJECT_SMB" = "yes" ] \
		&& ipv4_createChain smb smb \
		&& $IPTBL -A $CHAIN -j smb

	# Do we want to reject TCP auth connections as they are
	[ "$INPUT_REJECT_AUTH" = "YES" \
		-o "$INPUT_REJECT_AUTH" = "Yes" \
		-o "$INPUT_REJECT_AUTH" = "yes" ] \
		&& $IPTBL -A $CHAIN -j REJECT -p tcp --dport auth

	# Add chain for input processing
	ipf4_iplcl $LOCALCHAIN
	$IPTBL -A $CHAIN -j $LOCALCHAIN

	# Drop and log everything that we did not accept above
	if [ -n "$INPUT_DEFLOG" ]; then
		if [ -n "$INPUT_DEFLOG_IF" ]; then
			for IF in $INPUT_DEFLOG_IF; do
				$IPTBL -A $CHAIN -j $INPUT_DEFLOG -i $IF
			done
		else
			$IPTBL -A $CHAIN -j $INPUT_DEFLOG
		fi
	fi

	# Rule so that we have a counter of things falling off the end of 
	# chain in an easy to see place
	$IPTBL -A $CHAIN
}

ipf4_FORWARD () {
	local CHAIN=FORWARD
	
	# Clean out any existing rules
	qt $IPTBL -F $CHAIN
	# Set chain policy
	$IPTBL -P $CHAIN DROP

	# Make sure prerequisite chains are around
	ipv4_createChain droplog log droplog DROP 	# default log target
	ipv4_createChain log log			# Alternate log target
	ipv4_createChain icmpfwd icmpfwd		# ICMP protection...

	# Groom input
	# Detect Portscans
	[ "$FWD_DETECT_PORTSCAN" = "YES" \
		-o  "$FWD_DETECT_PORTSCAN" = "Yes" \
		-o  "$FWD_DETECT_PORTSCAN" = "yes" ] \
	&& ipv4_createChain portscan portscan \
	&&	$IPTBL -A $CHAIN -j portscan 
	
	# Deal with log noise 
	# Drop RIP and IPP packets from other boxes.... just noise
	for TUPLE in $FWD_DROP; do
		$IPTBL -A $CHAIN -j DROP \
			-p `echoParam '$1' $TUPLE` \
			-i `echoParam '$2' $TUPLE` \
			-d `echoIpPort '$3' ' --dport $4' '$4' $TUPLE` 
	done	

	# Deal with incoming Broadcast
	[ "$FWD_DROP_BROADCAST" = "YES" \
                -o  "$FWD_DROP_BROADCAST" = "Yes" \
                -o  "$FWD_DROP_BROADCAST" = "yes" ] \
		&& $IPTBL -A $CHAIN -j DROP -m pkttype --pkt-type BROADCAST

	# Deal with martians
	[ -n "FWD_MARTIAN_IF" ] && ipv4_createChain martians martians
	for IF in $FWD_MARTIAN_IF; do
		$IPTBL -A $CHAIN -j martians -i $IF
	done

	# Do ingress filtering	
	[ -n "FWD_INGRESS_IF" ] && ipv4_createChain ingrssfwd ingrssfwd
	for IF in $FWD_INGRESS_IF; do
		$IPTBL -A $CHAIN -j ingrssfwd -i $IF
	done
	
	# Clean up icmp
	$IPTBL -A $CHAIN -j icmpfwd

	# Deal with incoming SMB
	[ "$FWD_REJECT_SMB" = "YES" \
                -o  "$FWD_REJECT_SMB" = "Yes" \
                -o  "$FWD_REJECT_SMB" = "yes" ] \
		&& ipv4_createChain smb smb \
		&& $IPTBL -A $CHAIN -j smb

	# Do we want to reject TCP auth connections as they are
	[ "$FWD_REJECT_AUTH" = "YES" \
		-o "$FWD_REJECT_AUTH" = "Yes" \
		-o "$FWD_REJECT_AUTH" = "yes" ] \
		&& $IPTBL -A $CHAIN -j REJECT -p tcp --dport auth

	# Add chain for input processing
	ipf4_ipfwd
	$IPTBL -A $CHAIN -j "$FWDCHAIN"

	# Drop and log everything that we did not accept above
	if [ -n "$FWD_DEFLOG" ]; then
		if [ -n "$FWD_DEFLOG_IF" ]; then
			for IF in $FWD_DEFLOG_IF; do
				$IPTBL -A $CHAIN -j $FWD_DEFLOG -i $IF
			done
		else
			$IPTBL -A $CHAIN -j $FWD_DEFLOG
		fi
	fi


	# Rule so that we have a counter of things falling off the end of 
	# chain in an easy to see place
	$IPTBL -A $CHAIN
}

# Functions for building the ipfwd and iplcl chains needed above
ipf4_iplcl () {
	local USAGE="net ipfilter exec iplcl [-f] [-h] [chain-name]"
	local FORCE=0
	local NAME

	local OPTIND=1
	while getopts fh F; do
                case $F in 
                f)	FORCE=1;;
		h|\?)   echo 1>&2
                        echo "$USAGE" 1>&2
                        echo 1>&2
                        return 1
                        ;;
                esac
        done
        shift $(($OPTIND - 1))

	local CHAIN="$1"

	[ -z "$CHAIN" ] && CHAIN=${LOCALCHAIN}
	
	# Don't do ANYTHING if the chain already exists, unless FORCED!!
	if ! qt $IPTBL -N $CHAIN && [ $FORCE -eq 0 ]; then
		return 0
	fi
	
	qt $IPTBL -F $CHAIN

	for NAME in $IPV4_LOAD_LCL_CHAINS; do
		NAME=${NAME#*-}
		ipf4_${NAME}	
	done

}

ipf4_ipfwd () {
	local USAGE="net ipfilter exec ipfwd [-f] [-h] [chain-name]"
	local FORCE=0
	local NAME

	local OPTIND=1
	while getopts fh F; do
                case $F in 
                f)	FORCE=1;;
		h|\?)   echo 1>&2
                        echo "$USAGE" 1>&2
                        echo 1>&2
                        return 1
                        ;;
                esac
        done
        shift $(($OPTIND - 1))

	local CHAIN="$1"

	[ -z "$CHAIN" ] && CHAIN=${FWDCHAIN}
	
	# Don't do ANYTHING if the chain already exists, unless FORCED!!
	if ! qt $IPTBL -N $CHAIN && [ $FORCE -eq 0 ]; then
		return 0
	fi
	
	qt $IPTBL -F $CHAIN

	for NAME in $IPV4_LOAD_FWD_CHAINS; do
		NAME=${NAME#*-}
		ipf4_${NAME}	
	done

}

# Synopsis - ipdefs_getIndex <chain-name> <lace_chain> <load-list>
ipdefs_getIndex () {

	# if there are not enough args, blow this lot UP!!!
	if [ $# != 3 ]; then
		echo 1>&2 
		echo "$PRAOGNAME fN ipdefs_getIndex: FATAL ERROR - need 3 args"	1>&2
		echo "       ipdefs_getIndex <chain-name> <lace-chain> <load-list>" 1>&2
		echo 1>&2
		exit 2
	fi
	
	local ORDERED_LIST=`echo $3 | tr ' ' '\n' | sort -n`
	local WIT_LIST=`iptables -nL $2 \
			| grep -v 'Chain \|target[         ]*prot' \
			| sed -e 's/^[ 0-9]*\([_a-zA-Z0-9]\+\).*$/\1/'`
	local NAME ITEM
	local KEY_NAME
	# Build a name hash to take O(n2) lookups out of lop below
	for NAME in $ORDERED_LIST; do
		ITEM="${NAME#*-}"
		eval local HASH_"$ITEM"="${NAME%%-*}"
		if [ "$1" = "$ITEM" ]; then
			[ -z "$KEY_NAME" ] && KEY_NAME="$NAME"
		fi
	done
	local I=1
	local P
	[ -z "$KEY_NAME" ] && return 1
	local WP="${KEY_NAME%%-*}"
	for NAME in $WIT_LIST; do
		eval P=\$HASH_"$NAME"
		[ $P -gt $WP ] && echo "$I" && return 0
		I=$(($I+1))
	done

	echo "-A"
	
	return 0
		
}
