#!/bin/sh

VERSION=5.1
readonly VERSION

# Copyright (C) 2000-2001, Jean-Sebastien Morisset <jsmoriss@mvlan.net>.
#
# 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 <http://www.gnu.org/copyleft/gpl.txt>.
#
# 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 (LICENSE file in archive) for more details.
#
# See the accompanying INSTALL file for installation notes. The file is also
# available online at <http://jsmoriss.mvlan.net/linux/rcf/INSTALL>.
#
# Updates are available from <http://jsmoriss.mvlan.net/linux/rcf/>
# or <ftp://ftp.axess.com/mirrors/jsmoriss.mvlan.net/linux/rcf/>.
#
# I created this script using several sources, one of which is David A. 
# Ranch's excellent Linux configuration docs available at
# <http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html#trinityos>
# Linux Firewalls by Robert L. Ziegler from New Riders Publishing (ISBN: 
# 0-7357-0900-9) is another essential reference for any Linux Firewall 
# administrator.

# ======================================================================
# CONVENTIONS
# ======================================================================

# Function names should have the first letter of every word capitalized.
# Upper case variables are meant to exist throughout the script and 
# associated functions. Lower case variables should be used only within
# a funtion or block. They are temporary variables and should be unset
# before exiting the function or block.

# This code was written in vim with a tabstop of 4, line numbers, and
# a screen width of 132 collumns.

# ======================================================================
# FUNCTIONS
# ======================================================================

Read_Command_Line () {
	# ARG_EXEC variable accumulates unrecognized parameters
	# which can be passed-on to an executable.
	#   
	ARG_ORIG="$*"
	while : 
	do  
		for ARG in $*
		do
			case $ARG in 
				--help|-h)
					Show_Help
					exit 0
					;;
				--conf*)
					CONF="$2"
					readonly CONF
					shift
					;;
				--prefix)
					CMDL_PREFIX="$2"
					shift
					;;
				--groups)
					CMDL_GROUP_DIR="$2"
					shift
					;;
				--modules)
					CMDL_MODULE_DIR="$2"
					shift
					;;
				--functions)
					CMDL_FUNCTION_DIR="$2"
					shift
					;;
				--update-conf*)
					UPDATE_CONFIG="yes"
					;;
				--show-conf*)
					SHOW_CONFIG="yes"
					readonly SHOW_CONFIG
					;;
				--mode)
					CMDL_PUBLIC_INTERFACES_SECURITY="$2"
					shift
					;;
				--strict|--relaxed|--paranoid)
					CMDL_PUBLIC_INTERFACES_SECURITY="`echo $1|sed 's/^--//'`"
					;;
				--accept-all|--allow-all)
					ACCEPT_ALL="yes"
					readonly ACCEPT_ALL
					;;
				--*-interfaces|--*-*-security|--*-*-*-*)
					VALUE=""

					# Change variable name to upper case, etc.
					VAR=`echo $1|sed 's/^--//'| tr ':-' '_'|tr '[a-z]' '[A-Z]'`

					# Keep accumulating the value of this variable until you 
					# reach another parameter or you reach the end.
					while [ "$2" -a "`echo $2 | egrep -c '^--'`" -eq 0 ]
					do
						[ "$VALUE" ] && VALUE="$VALUE $2" || VALUE="$2"
						shift
					done
					eval CMDL_$VAR=\"$VALUE\"
					;;
				--test)
					TEST="yes"

					ipchains () { echo "	ipchains $*"; }
					modprobe () { echo "	modprobe $*"; }
					ipmasqadm () { echo "	ipmasqadm $*"; }
					;;
				--debug)
					while [ "$2" -a "`echo $2 | egrep -c '^--'`" -eq 0 ]
					do
						[ "$CMDL_DEBUG" ] && CMDL_DEBUG="$CMDL_DEBUG $2" || CMDL_DEBUG="$2"
						shift
					done
					: ${CMDL_DEBUG:="yes"}
					;;
				--nodebug)
					CMDL_DEBUG="no"	# needs a negetive to over-ride a positive in config. file
					;;
				--nosecurity-file-check)
					SECURITY_FILE_CHECK="no"
					;;
				*)	ARG_EXEC="$ARG_EXEC $1"
					;;
			esac    
			shift
			continue 2
		done
		break
	done
	unset ARG
}

Show_Help () {
	cat <<EOF

Command Line Parameters:

--help

    This summary of options. Several man pages are also available:
    firewall-groups(5), firewall-modules(5), firewall.conf(5), and
    rc.firewall(8).

--config {config-file}

    Specify an alternate path for the configuration file instead of
    /etc/firewall.conf.

    Examples:
        `basename $0` --config /etc/firewall/daytime.conf
        `basename $0` --config /etc/firewall/offhours.conf

--prefix {prefix-dir}

    Specify an alternate base directory instead of the default
    /etc/firewall/. This includes all sub-directories. Using
	the --functions, --groups, or --modules parameters will over-
	ride this option for that specific sub-directory.

--functions {functions-dir}

    Specify an alternate base directory instead of the default
    /etc/firewall/functions/

--groups {groups-dir}

    Specify an alternate base directory instead of the default
    /etc/firewall/groups/

--modules {module-dir}

    Specify an alternate base directory instead of the default
    /etc/firewall/modules/

--update-config

    Update the configuration file with all interface-based options. This
    is essential when upgrading to a new version of rcf.

--show-config

    Displays a summary of options and configuration values.

--test

    Show the commands which would be executed by rc.firewall. The
    ipchains rules are not changed.

--debug [yes|no]

    Turn ON or OFF debugging, over-riding the configured value. Debug
    mode will log as many input/output/masquerade deny/accept packets
    as possible to the kernel.info syslogd category.

--nosecurity-file-check

    When verifying the system security, don't check file permissions and
    owners.

--[public|private|dmz|mz]-interfaces {interface} {...}

    Add network interface(s) to the configured set. The configuration
    file options for these interfaces are not created automatically. If
    you want to implement rules for these interfaces, you'll have to use
    additional command line options.

    Example:
        `basename $0` --public-interfaces eth3 \\
            --accept-eth3-telnet-clients any/0

--private-interfaces-security [open|relaxed|strict|paranoid]
--[public|dmz|mz]-interfaces-security [relaxed|strict|paranoid]
--[dmz|mz]-clusters-security [relaxed|strict|paranoid]

    "open" mode allows all standard TCP traffic to pass in/out of these
    interfaces. Broadcast based services (dhcp, etc.) will have to be
    given explicit access. ONLY USE THIS MODE ON PRIVATE INTERFACES!

    "relaxed" mode allows outgoing TCP connections and incoming/outgoing
    UDP traffic on high ports. When used for public interfaces, this
    mode will allow port-scanning of remote hosts from your firewall.
    Access must be granted for each service offered (web and ftp
    servers, etc.).

    "strict" mode allows outgoing TCP connections except to known
    hacker-friendly service ports (sunrpc, rlogin, telnet, etc.). All
    UDP traffic is denied. Access must be given for each UDP based
    service and local TCP services offered to remote users (web and ftp
    servers, etc.).

    "paranoid" mode denies all incoming/outgoing TCP and UDP traffic.
    Each service (local and remote) must be granted access. Make sure
    you execute rcf with the --update-config parameter after switching
    to paranoid mode. This will add several options to the configuration
    file. You should review these before running rcf again.

--accept-all

    Set the default ipchains policy to accept, flush all firewall rules,
    and remove all chains. This effectively disables the firewall.

--{action}-{interface}-{service}-{type} {option-value} {...}

    Add a temporary entry to a configuration option; Useful when you
    want to open-up a service "on the fly". These settings will be lost 
    the next time the firewall is executed.

    Examples:
        `basename $0` --accept-eth1-telnet-clients somehost.com
        `basename $0` --accept-eth1:1-battlenet-hostports \\
            www.battle.net/24 4000 6112:6119 

EOF
}

# ======================================================================
# END OF FUNCTIONS
# ======================================================================


# ======================================================================
# MAIN
# ======================================================================

cat <<EOF

Copyright (C) 2000-2001, Jean-Sebastien Morisset <jsmoriss@mvlan.net>.
rcf (aka rc.firewall) v$VERSION and all related scripts come with ABSOLUTELY NO
WARRANTY; for details see the LICENSE file included in the rcf distribution.
EOF

#
# SYSTEM VARIABLES, ETC.
# ----------------------

umask 077

ANY="any/0"
readonly ANY

# Make sure we have all the standard OS paths available. I also prefer
# using the standard OS utilities instead of what we might find under 
# /usr/local/bin.
#
ORIGINAL_PATH="$PATH"
PATH="/sbin:/usr/sbin:/bin:/usr/bin:$PATH"
export PATH

SECURITY_FILE_CHECK="yes"
ERROR_PAUSE="10"	# in seconds.
TOTAL_MODULES="0"	# will be incremented as modules are read

CONF="/etc/firewall.conf"			# Over-ride w/ command line parameter.
PREFIX="/etc/firewall"				# Over-ride w/ command line parameter.

#
# PARSE COMMAND LINE PARAMETERS
# -----------------------------

Read_Command_Line $*

#
# SET FILE LOCATION VARIABLES
# ---------------------------

[ "$CMDL_PREFIX" ] \
	&& { PREFIX="$CMDL_PREFIX"; unset CMDL_PREFIX; }

[ "$CMDL_GROUP_DIR" ] \
	&& { GROUP_DIR="$CMDL_GROUP_DIR"; unset CMDL_GROUP_DIR; } \
	|| { GROUP_DIR="${PREFIX}/groups"; }

[ "$CMDL_MODULE_DIR" ] \
	&& { MODULE_DIR="$CMDL_MODULE_DIR"; unset CMDL_MODULE_DIR; } \
	|| { MODULE_DIR="${PREFIX}/modules"; }

[ "$CMDL_FUNCTION_DIR" ] \
	&& { FUNCTION_DIR="$CMDL_FUNCTION_DIR"; unset CMDL_FUNCTION_DIR; } \
	|| { FUNCTION_DIR="${PREFIX}/functions"; }

#
# READ-IN FUNCTIONS
# -----------------

[ -d "$FUNCTION_DIR" ] && \
	for FUNCTION in $FUNCTION_DIR/*.sh
	do
		[ -f "$FUNCTION" ] && . "$FUNCTION"
	done

#
# COMMERCIAL USE BANNER
# ---------------------

if [ "$UPDATE_CONFIG" ]
then
	echo ""
	echo "--------------------------------------------------------------------------------"
	echo "            IF YOU USE RCF IN A COMMERCIAL SETTING, PLEASE REFER TO"
	echo "             <http://jsmoriss.mvlan.net/linux/rcf.html#commercial>."
	echo "--------------------------------------------------------------------------------"
fi

#
# SECURITY CHECK
# --------------
# Call the Security_Check function AFTER the CONF variable has been 
# defined. The idea is not to call any binaries before we can check 
# the environment.

Security_Check

#
# READ CONFIGURATION FILE
# -----------------------

Check_Old_Config_Paths

Read_Config

#
# VALIDATE CONFIGURATION VARIABLES
# --------------------------------
# These changes will be saved when the configuration file is written.

Verify_All_Yn_Variables

#
# WRITE CONFIGURATION FILE
# ------------------------

[ "$UPDATE_CONFIG" ] && {
	#
	# DEFINE VARIABLES FOR CLUSTER NAMES ETC.
	# These are used when writing the configuration file,
	# so they must be defined before.
	#
	Set_Cluster_Vars DMZ MZ
	Set_Mode_Num
	Write_Config
	exit 0
}

#
# MANIPULATE CONFIGURATION VARIABLES
# ----------------------------------
# This goes on after the configuration file is written so we don't save
# these changes (removing downed interfaces, add hosts to variables, etc.).

LOOPBACK_INTERFACES="lo"
readonly LOOPBACK_INTERFACES

for VAR in `set|sed -n 's/^CMDL_\(.*\)=.*$/\1/p'`
do
	case $VAR in
		DEBUG|ENABLE_*)
			eval Set_Yn_Variable CMDL_${VAR}
			echo -n "Setting $VAR to \""
			eval echo -n "\$CMDL_$VAR"
			echo "\"."
			eval $VAR=\"\$CMDL_$VAR\"
			;;
		*_INTERFACES_SECURITY|*_CLUSTERS_SECURITY)
			echo -n "Setting $VAR to \""
			eval echo -n "\$CMDL_$VAR"
			echo "\"."
			eval $VAR=\"\$CMDL_$VAR\"
			;;
		*)
			echo -n "Adding \""
			eval echo -n "\$CMDL_$VAR"
			echo "\" to $VAR"
			eval $VAR=\"\$$VAR \$CMDL_$VAR\"
			;;
	esac
	eval unset \$CMDL_$VAR
done

#
# READ-IN GROUP FILES
# -------------------
#
for var in PUBLIC_INTERFACES PRIVATE_INTERFACES DMZ_INTERFACES MZ_INTERFACES
do
	Include_Group $var
done
unset var

for interface in $PUBLIC_INTERFACES $PRIVATE_INTERFACES $DMZ_INTERFACES $MZ_INTERFACES
do
	interface="`echo ${interface}|tr '[a-z]' '[A-Z]'|tr ':-' '_'`"
	for action in ACCEPT IGNORE DENY FORWARD
	do
		for var in `set|sed -n "s/^\(${action}_${interface}_[^\=]*\)=[^\=]*\$/\1/p"`
		do
			Include_Group $var
		done
	done
done
unset interface action var

for var in IANA_RESERVED_NETWORKS
do
	Include_Group $var
done
unset var

#
# VALIDATE INTERFACES
# -------------------
# Remove interfaces which are down (ppp0, etc.) and/or don't have an IP 
# address. The firewall script can then be executed when the server is 
# disconnected.
#
echo "Validating Interfaces..."
for interface_type in PUBLIC PRIVATE DMZ MZ
do
	eval INTERFACES=\"\$${interface_type}_INTERFACES\"
	for INTERFACE in $INTERFACES
	do
		if [ -z "`ifconfig $INTERFACE 2>/dev/null|egrep ' addr:'`" -o \
			-z "`ifconfig $INTERFACE 2>/dev/null|egrep ' UP '`" ]
		then
			echo -n "Removing $INTERFACE (down) Interface from "
			eval echo \"${interface_type}_INTERFACES\"
			eval VALUE=\"\$${interface_type}_INTERFACES\"
			VALUE="`echo $VALUE|sed \"s/^${INTERFACE}$//g\"`"
			VALUE="`echo $VALUE|sed \"s/^${INTERFACE} //g\"`"
			VALUE="`echo $VALUE|sed \"s/ ${INTERFACE} / /g\"`"
			VALUE="`echo $VALUE|sed \"s/ ${INTERFACE}$//g\"`"
			eval ${interface_type}_INTERFACES=\"${VALUE}\"
		fi
	done
done
unset interface_type

#
# SET INTERFACE VARIABLES
# -----------------------
#
echo "Setting Up Internal Variables..."

# Define variables for cluster names etc.
#
Set_Cluster_Vars DMZ MZ

# Define variable arrays based on interface names.
#
Set_Interface_Vars LOOPBACK PUBLIC PRIVATE DMZ MZ

#
# OTHER CONFIG DEPENDENT VARIABLES
# --------------------------------

Set_Mode_Num

if [ "$DEBUG" = "yes" ]
then
	LOG="-l"				# used in most ipchains commands
	LOG_MSG="(logged)"		# added to most echo'ed strings
	readonly LOG LOG_MSG
fi

#
# FIXED VARIABLES
# ---------------

BROADCAST_SRC="0.0.0.0"
BROADCAST_DEST="255.255.255.255"
readonly BROADCAST_SRC BROADCAST_DEST

PRIVPORTS="0:1023"
UNPRIVPORTS="1024:65535"
XWINPORTS="6000:6063"
####SSHPORTS="513:1023"
SSHPORTS="513:65535"
readonly PRIVPORTS UNPRIVPORTS XWINPORTS SSHPORTS

CLASS_A_PRIVATE="10.0.0.0/8"
CLASS_B_PRIVATE="172.16.0.0/12"
CLASS_C_PRIVATE="192.168.0.0/16"
CLASS_D_MULTICAST="224.0.0.0/4"
CLASS_E_RESERVED_NET="240.0.0.0/5"
readonly CLASS_A_PRIVATE CLASS_B_PRIVATE CLASS_C_PRIVATE CLASS_D_MULTICAST CLASS_E_RESERVED_NET

if [ "$SHOW_CONFIG" = "yes" ]
then
	Show_Config
	exit 0
fi

#
# START OF FIREWALL RULES
# -----------------------

echo ""
echo "BASIC OPERATING SYSTEM SETUP"
echo "================================================================================"

Ipv4_Check

for INTERFACE in $PUBLIC_INTERFACES $DMZ_INTERFACES
do
	if [ "`Option_Value accept $INTERFACE mcastigmp servers`" ]
	then
		if [ "`netstat -nre|egrep -c \"224.0.0.0  *0.0.0.0  *240.0.0.0 .* $INTERFACE\"`" -eq 0 ]
		then
			echo "$INTERFACE: Adding Multicast (224.0.0.0) Route"
			[ "$TEST" ] \
				&& echo "	route add -net 224.0.0.0 netmask 240.0.0.0 dev $INTERFACE" \
				|| route add -net 224.0.0.0 netmask 240.0.0.0 dev $INTERFACE
		fi
	fi
done

echo -n "Loading Masquerading Module(s):"
[ "$TEST" ] && echo ""
for MODULE in $MASQ_MODULES
do
	[ "$TEST" ] && echo "${MODULE}:" || echo -n " $MODULE"
	modprobe ip_masq_$MODULE
done
[ "$TEST" ] || echo ""

if [ "`echo $MASQ_TIMEOUTS|egrep -c '^[0-9]+ +[0-9]+ +[0-9]+$'`" -gt "0" ]
then
	echo "Changing IP Masquerading Timeouts"
	ipchains -M -S $MASQ_TIMEOUTS
else
	echo "WARNING: ipmasq-timeouts option set incorrectly!"
fi

#--------------------------------------------------------------------
# Default Policies
#--------------------------------------------------------------------

if [ "$ACCEPT_ALL" = "yes" ]
then
	echo "Setting Default Policies (input/output/forward=ACCEPT)"
	ipchains -P input ACCEPT
	ipchains -P output ACCEPT
	ipchains -P forward ACCEPT
else
	echo "Setting Default Policies (input=DENY, output/forward=REJECT)"
	ipchains -P input DENY
	ipchains -P output REJECT
	ipchains -P forward REJECT
fi

# Save IP Accounting data before we flush all the chains.
#
if [ -x ${IPAC_BINDIR}/fetchipac ]
then
	echo "Saving IP Accounting Data"
	if [ "$TEST" ]
	then
		echo "	${IPAC_BINDIR}/fetchipac 2>/dev/null"
	else
		${IPAC_BINDIR}/fetchipac 2>/dev/null
	fi
fi

echo "Removing Chains and Flushing Rules"
ipchains -F
ipchains -X

#--------------------------------------------------------------------
# Setup Each Interface Chain
#--------------------------------------------------------------------

for INTERFACE in lo $PUBLIC_INTERFACES $PRIVATE_INTERFACES $DMZ_INTERFACES $MZ_INTERFACES
do
	Get_Interface_Vars "$INTERFACE"
	if [ "$VIRTUAL" = "no" ]
	then
		echo "Creating and Linking $INCHAIN and $OUTCHAIN Chains"

		ipchains -N $INCHAIN
		ipchains -N $OUTCHAIN

		ipchains -A input  -i $DEVICE -j $INCHAIN
		ipchains -A output -i $DEVICE -j $OUTCHAIN
	fi
done

#-----------------------------------------------------------------------
# A NOTE ABOUT ARROWS
#-----------------------------------------------------------------------
# You'll notice that I use arrows when printing messages on the screen.
# Typically they might look like this:
#
#   Accept interface IP# ServiceName <- hostname
#
# You might wonder what that arrow means. :-) The one pointing to the 
# left means the host is typically the one that initiates a connection.
# An arrow pointing to the right means the firewall initiates the 
# connection. It's not perfect, but it gives a sense about how traffic
# flows.
#-----------------------------------------------------------------------

#--------------------------------------------------------------------
# LOOPBACK INTERFACE
#--------------------------------------------------------------------
#
Get_Interface_Vars "lo"
for INTERFACE in $LOOPBACK_INTERFACES
do
	echo "Accept $INTERFACE $ANY <-> $ANY $LOG_MSG"
	ipchains -A $INCHAIN  -j ACCEPT -i $INTERFACE -s $ANY -d $ANY $LOG
	ipchains -A $OUTCHAIN -j ACCEPT -i $INTERFACE -s $ANY -d $ANY $LOG
done

echo ""
echo "FORWARDING AND MASQUERADING"
echo "================================================================================"

# There are TWO methods of turning on this feature. The first method is
# the Red Hat way. Edit the /etc/sysconfig/network file and change the 
# "FORWARD_IPV4" line to say FORWARD_IPV4=true. The second method is 
# shown below and can executed at any time while the system is running.
#
if [ -w /proc/sys/net/ipv4/ip_forward ]
then
	if [ "`cat /proc/sys/net/ipv4/ip_forward`" -ne "1" ]
	then
		echo "Enabling IP Forwarding in Linux Kernel"
		[ "$TEST" ] \
			&& echo "	echo \"1\" >/proc/sys/net/ipv4/ip_forward" \
			|| echo "1" >/proc/sys/net/ipv4/ip_forward
	fi
else
	echo "WARNING: Please enable IP Forwarding in your kernel!"
fi

#
# MASQUERADING
# ------------

# Masquerade all private (LAN) traffic going out on a public interface.
# Traffic going out on DMZ interfaces is NOT masqueraded (private IPs
# should be routable on the firewall).
#
for interface in $PUBLIC_INTERFACES $PRIVATE_INTERFACES $DMZ_INTERFACES $MZ_INTERFACES
do
	Get_Interface_Vars $interface
	if [ "$VIRTUAL" = "no" ]
	then
		for masq_network in `Option_Value forward $interface masq networks`
		do
			echo "Forward $interface IP Masquerade $masq_network -> $ANY $LOG_MSG"
			ipchains -A forward -j MASQ -i $interface -s $masq_network -d $ANY $LOG
		done
	fi
done
unset interface masq_network

#
# FORWARDING
# ----------

Forward_Interfaces "$PRIVATE_INTERFACES" "$DMZ_INTERFACES"
Forward_Interfaces "$PRIVATE_INTERFACES" "$MZ_INTERFACES"

for FIRST_INTERFACE in $1
do
	Get_Interface_Vars $FIRST_INTERFACE FIRST
	[ "$FIRST_VIRTUAL" = "no" ] \
		&& for FIRST_NET in `Device_Subnets FIRST`
		do
			Forward_Subnets "${FIRST_NET}<->any/0"
		done
done

#--------------------------------------------------------------------
# PORT FORWARDING
#--------------------------------------------------------------------

# Flush the PORT FORWADING rules before setting them up
if [ -x "`which ipmasqadm 2>/dev/null`" ]
then
	echo "Flushing Port Forwarding Rules"
	ipmasqadm portfw -f
fi

Port_Forwarding_Rules PUBLIC PRIVATE DMZ MZ

if [ "$ACCEPT_ALL" = "yes" ]
then
	# Enable IP Accounting chains
	Ip_Accounting
	
	echo ""
	echo "IPchains Firewall Rules Disabled"
	echo ""
	exit 0
fi

# Catch all rule, all other forwarding is denied.
#
echo "Reject All Other Forwarding (logged)"
ipchains -A forward -j REJECT -s $ANY -d $ANY -l

#--------------------------------------------------------------------
# PUBLIC INTERFACES AND DMZS
#--------------------------------------------------------------------

for INTERFACE in $PUBLIC_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	echo ""
	echo "`echo $INTOPT|tr '[a-z]' '[A-Z]'` PUBLIC INTERFACE SERVICES"
	echo "================================================================================"
	Service_Rules public $PUBLIC_INTERFACES_MODE
	High_Port_Rules public $PUBLIC_INTERFACES_MODE
done

for INTERFACE in $DMZ_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	echo ""
	echo "`echo $INTOPT|tr '[a-z]' '[A-Z]'` DMZ INTERFACE SERVICES"
	echo "================================================================================"
	Service_Rules public $DMZ_INTERFACES_MODE
	High_Port_Rules public $DMZ_INTERFACES_MODE
done

for INTERFACE in $DMZ_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	NETADDR="${NETWORK}/${NETMASK}"
	for CLUSTER_NAME in `Option_Value dmz $INTERFACE cluster names`
	do
		INTOPT="${INTERFACE}:${CLUSTER_NAME}"
		echo ""
		echo "`echo $INTOPT|tr '[a-z]' '[A-Z]'` DMZ CLUSTER SERVICES"
		echo "================================================================================"
		for cluster_network in `Option_Value dmz $INTERFACE $CLUSTER_NAME cluster`
		do
			Get_Cluster_Vars $INTERFACE $cluster_network
			Service_Rules public $DMZ_CLUSTERS_MODE
			High_Port_Rules public $DMZ_CLUSTERS_MODE
		done
		unset cluster_network
	done
	unset CLUSTER_NAME
done

#--------------------------------------------------------------------
# PRIVATE INTERFACES
#--------------------------------------------------------------------

for INTERFACE in $PRIVATE_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	echo ""
	echo "`echo $INTOPT|tr '[a-z]' '[A-Z]'` PRIVATE INTERFACE SERVICES"
	echo "================================================================================"
	Service_Rules private $PRIVATE_INTERFACES_MODE
	High_Port_Rules private $PRIVATE_INTERFACES_MODE
done

for INTERFACE in $MZ_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	echo ""
	echo "`echo $INTOPT|tr '[a-z]' '[A-Z]'` MZ INTERFACE SERVICES"
	echo "================================================================================"
	Service_Rules private $MZ_INTERFACES_MODE
	High_Port_Rules private $MZ_INTERFACES_MODE
done

for INTERFACE in $MZ_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	NETADDR="${NETWORK}/${NETMASK}"
	for CLUSTER_NAME in `Option_Value mz $INTERFACE cluster names`
	do
		INTOPT="${INTERFACE}:${CLUSTER_NAME}"
		echo ""
		echo "`echo $INTOPT|tr '[a-z]' '[A-Z]'` MZ CLUSTER SERVICES"
		echo "================================================================================"
		for cluster_network in `Option_Value mz $INTERFACE $CLUSTER_NAME CLUSTER`
		do
			Get_Cluster_Vars $INTERFACE $cluster_network
			Service_Rules private $MZ_CLUSTERS_MODE
			High_Port_Rules private $MZ_CLUSTERS_MODE
		done
		unset cluster_network
	done
	unset CLUSTER_NAME
done

echo ""
echo "ALL INTERFACES"
echo "================================================================================"

echo "Setting Type of Service (ToS) for: ftp ssh telnet www ircd"
#
# In theory, you can tell the Internet how to handle your traffic, be 
# it sensitive to delay, throughput, etc.
#
#       -t 0x01 0x10 = Minimum Delay
#       -t 0x01 0x08 = Maximum Throughput
#       -t 0x01 0x04 = Maximum Reliability
#       -t 0x01 0x02 = Minimum Cost
#
# NOTE: To make use of these flags, you must compile your Linux kernel
# with CONFIG_IP_ROUTE_TOS=y.
#
for INTERFACE in $PUBLIC_INTERFACES $PRIVATE_INTERFACES $DMZ_INTERFACES $MZ_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	if [ "$VIRTUAL" = "no" ]
	then
		ipchains -A $OUTCHAIN -p tcp -d 0/0 ftp      -t 0x01 0x10
		ipchains -A $OUTCHAIN -p tcp -d 0/0 ftp-data -t 0x01 0x08
		ipchains -A $OUTCHAIN -p tcp -d 0/0 ssh      -t 0x01 0x10   
		ipchains -A $OUTCHAIN -p tcp -d 0/0 telnet   -t 0x01 0x10   
		ipchains -A $OUTCHAIN -p tcp -d 0/0 www      -t 0x01 0x10
		ipchains -A $OUTCHAIN -p tcp -d 0/0 6667     -t 0x01 0x10	# ircd
	fi
done

#--------------------------------------------------------------------
# Catch All Rule
#--------------------------------------------------------------------

# Allow traffic from subnets to go anywhere. The interface has already
# been protected by specific deny/reject rules for the interface IP.
# This is kind of like an "allservers" cluster.
#
for interface in $PRIVATE_INTERFACES
do
	Get_Interface_Vars $interface

	# This open's up pretty much everything except broadcast-based services like DHCP.
	# This must be executed AFTER all virtual interface rules have been setup.
	#
	if [ "$VIRTUAL" = "no" ]
	then
		for net in `Device_Subnets`
		do
			echo "Accept $DEVICE $ANY <-> $net $LOG_MSG"
			ipchains -A $INCHAIN  -j ACCEPT -s $net -d $ANY $LOG
			ipchains -A $OUTCHAIN -j ACCEPT -s $ANY -d $net $LOG
		done
		unset net
	fi
done

echo "Deny/Reject All Other Input/Output (logged)"
for INTERFACE in $PRIVATE_INTERFACES $PUBLIC_INTERFACES $DMZ_INTERFACES $MZ_INTERFACES
do
	Get_Interface_Vars $INTERFACE
	if [ "$VIRTUAL" = "no" ]
	then
		ipchains -A $INCHAIN  -j DENY   -s $ANY -d $ANY -l
		ipchains -A $OUTCHAIN -j REJECT -s $ANY -d $ANY -l
	fi
done

# Enable IP Accounting chains
Ip_Accounting

echo ""
if [ "$TEST" ]
then
	echo "IPchains Firewall Rules Displayed"
	echo "THESE RULES HAVE NOT BEEN IMPLEMENTED!"
else
	echo "`Print_Rule_Total` IPchains Firewall Rules Implemented"
fi
echo ""

