#!/bin/bash
# =========================================================================
# $Id: ipkungfu.in 160 2007-01-21 20:23:37Z trappist $
# =========================================================================
#             $URL: http://ipkungfu.ufsoft.org/svn/tags/ipkungfu-0.6.1/ipkungfu.in $
# $LastChangedDate: 2007-01-21 14:23:37 -0600 (Sun, 21 Jan 2007) $
#             $Rev: 160 $
#   $LastChangedBy: trappist $
# =========================================================================

###########################################################################
#                                                                         #
# Copyright © 2002 by Rocco Stanzione                                     #
#                                                                         #
# 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.                            #
#                                                                         #
###########################################################################

# -------------------------------------------------------------------------
# vim: set tabstop=4
# vim: set shiftwidth=4
# vim: set foldmethod=marker
# -------------------------------------------------------------------------

IPKF_VERSION="0.6.1"
IPKUNGFU="$0"
IPKUNGFU_BINS_PATH="$(dirname $0)"

# System Binaries path provided by autoconf.
# -------------------------------------------------------------------------
IPTABLES="/usr/bin/iptables"
MD5SUM="/usr/bin/md5sum"
MODPROBE="/usr/bin/modprobe"
SU="/usr/bin/su"
KILLALL="/usr/bin/killall"
NETSTAT="/usr/bin/netstat"
CHOWN="/usr/bin/chown"
LSMOD="/usr/bin/lsmod"
DEPMOD="/usr/bin/depmod"
RMMOD="/usr/bin/rmmod"
# -------------------------------------------------------------------------
# End of System Binaries Path provided by autoconf.

# Ipkungfu ETC and CACHE dir
# -------------------------------------------------------------------------
IPK_ETC_DIR="/etc/ipkungfu"
IPK_CACHE_DIR="$IPK_ETC_DIR/cache"
# -------------------------------------------------------------------------

# Files to check ipkungfu's runtime behaviour
# -------------------------------------------------------------------------
NOT_THE_FIRST_RUN="$IPK_CACHE_DIR/not-the-first-run.rnd"
NO_DEPRECATION_WARNING_FILE="$IPK_CACHE_DIR/no-deprecation-check.rnd"
# -------------------------------------------------------------------------

# Path to files needed by ipkungfu
# -------------------------------------------------------------------------
IPK_MD5_SIG_FILE="$IPK_CACHE_DIR/ipkungfu.md5"
BEHAVIOUR_MD5_SIG_FILE="$IPK_CACHE_DIR/behaviour_files.md5"
PROC_CACHE_FILE="$IPK_CACHE_DIR/proc.cache"
RULES_CACHE_FILE="$IPK_CACHE_DIR/rules.cache"
CONFIG_FILES_MD5_SIGS_FILE="$IPK_CACHE_DIR/config_files.md5"
# -------------------------------------------------------------------------

# In certain configurations $IP_FORWARD will fail to be set,
# so we set it to a default value here.
IP_FORWARD="0"

if [ -f "$IPK_MD5_SIG_FILE" ]; then
	IPK_MD5_SIG="$(head -n1 $IPK_MD5_SIG_FILE | awk '{print $1}')"
fi

# Set some exit codes (To be expanded in 0.7.0)
# To follow the C/C++ convention which can be applied to shell scripts,
# error codes start at 64.
# For any more info, check '/usr/include/sysexits.h'
# -------------------------------------------------------------------------
defineExitCodes() {
# {{{ Error codes defenition
	E_CLEAN_EXIT=0			# Clean Exit, same as 'exit 0'
	E_DIRTY_EXIT=1			# Error happened, same as 'exit 1'
	E_CREATE_FILE=64		# Error creating file
	E_DELETE_FILE=65		# Error deleting file
	E_CLEAN_EXEC=66			# Clean Function Execution
	E_ANSWER_YES=67			# Yes Answer
	E_ANSWER_NO=68			# No Answer
	E_ANSWER_BAD=69			# Bad Answer
	E_BAD_MD5_CREATE=70		# Error Creating MD5 signature
	E_GOOD_MD5_CREATE=71	# Good Creation Of MD5 Signature
	E_BAD_MD5_CHECK=72		# Error Checking MD5 signature
	E_GOOD_MD5_CHECK=73		# Good Checking Of MD5 signature	
# }}}
}
defineExitCodes
# -------------------------------------------------------------------------
# End of Exit codes definition

defineColours() {
	RED_COLOUR="\033[1;31m"		# Light Red Colour
	GREEN_COLOUR="\033[1;32m"	# Light Green Colour
	BLUE_COLOUR="\033[1;34m"	# Light Blue Colour
	BRIGHT_COLOUR="\033[1m"		# Bright(en) Colour
	CLOSE_COLOUR="\033[m"		# Close Colour
}
defineColours

# We need to check for '--quiet' here because INIT will only be set when
# the script passes the 'usage' part, and we will need it before that.
if [ "$1" == "--quiet" -o "$1" == "--init" ]; then
	INIT=1
fi

# Set ipkungfu's runtime error log
# This shouldn't be done here, and will probably change for 0.7
IPKUNGFU_LOG="$(head -n20 $IPK_ETC_DIR/ipkungfu.conf | grep -v '#' \
| grep 'IPKUNGFU_LOG=')"
if [ -z "$IPKUNGFU_LOG" ]; then
	IPKUNGFU_LOG="/var/log/ipkungfu.log"
fi

DATE_STRING="+%Y-%m-%d %H:%M:%S"

function logError() {
	if [ "$1" != "" ]; then
		echo "$(date \"${DATE_STRING}\") - $1" >> ${IPKUNGFU_LOG}
	fi
}

# Check to see if the ipkungfu's cache directory exists
# {{{
if [ ! -d "$IPK_CACHE_DIR" ]; then
	if [ "$INIT" != "1" ]; then
		echo -n "Creating runtime cache directory: "
	fi
	# Create the runtime cache directory
	mkdir $IPK_CACHE_DIR
	if [ "$?" == "0" ]; then
		if [ "$INIT" != "1" ]; then
			echo -n "."
		fi
		# Define the permissions to the cache dir
		# TODO: Should it be 700?
		chmod 600 $IPK_CACHE_DIR
		if [ "$?" == "0" ]; then
			if [ "$INIT" != "1" ]; then
				echo -e ".${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
			fi
		else
			if [ "$INIT" != "1" ]; then
				echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
				exit $E_DIRTY_EXIT
			fi
		fi
	else
		if [ "$INIT" != "1" ]; then
			echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
		fi
		exit $E_DIRTY_EXIT
	fi
fi
# }}}

buildBehaviourFilesMD5() {
# {{{ create md5 sigs of behaviour files
	${MD5SUM} $IPK_CACHE_DIR/*.rnd > $BEHAVIOUR_MD5_SIG_FILE
	if [ "$?" == "0" ]; then
		EXIT_CODE=$E_GOOD_MD5_CREATE
	else
		EXIT_CODE=$E_BAD_MD5_CREATE
	fi
	return $EXIT_CODE
# }}}
}

checkBehaviourFilesMD5() {
# {{{ check md5 sigs of behaviour files
	${MD5SUM} -c $BEHAVIOUR_MD5_SIG_FILE > /dev/null 2>&1
	if [ "$?" == "0" ]; then
		EXIT_CODE=$E_GOOD_MD5_CHECK
	else
		EXIT_CODE=$E_BAD_MD5_CHECK
	fi	
	return $EXIT_CODE
# }}}
}

checkCacheDir() {
# {{{ Check to see if behavioural files were manually tampered
	if [ -f "$NOT_THE_FIRST_RUN" ]; then
		if [ ! -f "$BEHAVIOUR_MD5_SIG_FILE" ]; then
			TAMPERED="TRUE"
		fi
		if [ ! -f "$IPK_MD5_SIG_FILE" ]; then
			TAMPERED="TRUE"
		fi
	elif [ -f "$IPK_MD5_SIG_FILE" ]; then
		if [ ! -f "$NOT_THE_FIRST_RUN" ]; then
			TAMPERED="TRUE"
		fi
		if [ ! -f "$BEHAVIOUR_MD5_SIG_FILE" ]; then
			TAMPERED="TRUE"
		fi
	elif [ -f "$BEHAVIOUR_MD5_SIG_FILE" ]; then
		if [ ! -f "$IPK_MD5_SIG_FILE" ]; then
			TAMPERED="TRUE"
		fi
		if [ ! -f "$NOT_THE_FIRST_RUN" ]; then
			TAMPERED="TRUE"
		fi
	fi
	if [ "$TAMPERED" == "TRUE" ]; then
		echo -e "${RED_COLOUR}Cache dir has been manualy tampered with!"
		echo -e -n "${CLOSE_COLOUR}ipkungfu won't run anymore, "
		echo "it's advisable to re-install ipkungfu."
		exit $E_DIRTY_EXIT
	fi
# }}}
}

# First we check if /etc/ipkungfu/cache/not-the-first-run.rnd
# doesn't exist.
if [ ! -f "$NOT_THE_FIRST_RUN" ]; then
	checkCacheDir
	if [ "$INIT" != "1" ]; then
		echo "Since this is the first time ipkungfu is running on your system,"
		echo -n "we will build its own md5sum signature: "
	fi
	IPK_MD5_SIG="$(${MD5SUM} $IPKUNGFU)" 
	echo "$IPK_MD5_SIG" > $IPK_MD5_SIG_FILE
	if [ "$INIT" != "1" ]; then
		if [ "$?" == "0" ]; then
			echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
		else
			echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
		fi
		echo
	fi
	# Now, we'll create 'not-the-first-run.rnd' with a random number
	# inside followed by ipkungfu's md5 signature so we can have a
	# valid md5sum signature to later check to see if it has been
	# tampered.
	echo "$RANDOM:$(echo $IPK_MD5_SIG | awk '{print $1}')" > $NOT_THE_FIRST_RUN
	# Now we create the md5 signatures of all *.rnd files on
	# ipkungfu's cache dir
	buildBehaviourFilesMD5
	# TODO: Check the above function call exit code?
else
	checkCacheDir
	if [ "$INIT" != "1" ]; then
		echo -n "Checking integrity: "
	fi
	${MD5SUM} -c $IPK_MD5_SIG_FILE > /dev/null 2>&1
	if [ "$?" == "0" ]; then
		if [ "$INIT" != "1" ]; then
			echo -n "."
		fi
	else
		if [ "$INIT" != "1" ]; then
			echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
			echo -e "${IPKUNGFU} has been tampered with!"
			echo -e "It's advisable to re-install ipkungfu!!!"
			echo -e "Like this, ipkungfu won't run anymore."
			exit $E_DIRTY_EXIT
		fi
	fi
	RND_FILES_ARRAY="$(cat $BEHAVIOUR_MD5_SIG_FILE | awk '{print $2}')"
	for rnd_file in $RND_FILES_ARRAY; do
		if [ "$(head -n1 $rnd_file | cut -d ':' -f2)" == \
			"$IPK_MD5_SIG" ]; then
			if [ "$INIT" != "1" ]; then
				echo -n "."
			fi
		else
			if [ "$INIT" != "1" ]; then
				echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
				echo "$rnd_file has been tampered"
				echo "It's advisable to re-install ipkungfu."
				echo "If the changes we're made by you you can try to"
				echo "'rm -rf /etc/ipkungfu/cache' and ipkungfu will execute"
				echo "as if it was the first time."
			fi
			exit $E_DIRTY_EXIT
		fi
	done
	checkBehaviourFilesMD5
	if [ "$?" == "$E_GOOD_MD5_CHECK" ]; then
		if [ "$INIT" != "1" ]; then
			echo -e "${BRIGHT_COLOUR}\tPASSED${CLOSE_COLOUR}"
		fi
	else
		if [ "$INIT" != "1" ]; then
			echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
			echo
			echo "It's advisable to re-install ipkungfu"
			echo "$IPKUNGFU was changed"
		fi
		exit $E_DIRTY_EXIT
	fi
fi

checkAnswer() {
# {{{ Check user's answer function
	if [ "x$1" != "x" ]; then
		local answer="`echo $1 | tr a-z A-Z`"
		if [ "$answer" == "N" -o "$answer" == "NO" ]; then
			exit_code=$E_ANSWER_NO
		elif [ "$answer" == "Y" -o "$answer" == "YE" -o "$answer" == "YES" ]; then
			exit_code=$E_ANSWER_YES
		else
			exit_code=$E_ANSWER_BAD
		fi
	else
		exit_code=$E_ANSWER_BAD
	fi
	return $exit_code
# }}}
}

handleProc() {
# {{{ /proc settings
	echo "$IP_FORWARD" > /proc/sys/net/ipv4/ip_forward
	echo "$LOG_MARTIANS" > /proc/sys/net/ipv4/conf/all/log_martians
	echo "$BLOCK_PINGS" > /proc/sys/net/ipv4/icmp_echo_ignore_all

	if [ ! -z $ICMP_ECHO_IGNORE_BROADCASTS ] ; then
		# Smurf-proofing
		echo "$ICMP_ECHO_IGNORE_BROADCASTS" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
	else
		echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
	fi

	# Disable ICMP redirect acceptance. ICMP redirects can be used to 
	# alter your routing tables, possibly to a bad end.
	echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects

	# Enable bad error message protection.
	echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses

	# Helps slow down DoS attacks
	echo "$FIN_TIMEOUT" > /proc/sys/net/ipv4/tcp_fin_timeout
	echo "$TCP_KEEPALIVE" > /proc/sys/net/ipv4/tcp_keepalive_intvl
	echo "$TCP_KEEPALIVE" > /proc/sys/net/ipv4/tcp_keepalive_time
	echo "$TCP_WINDOW_SCALING" > /proc/sys/net/ipv4/tcp_window_scaling
	echo "$TCP_SACK" > /proc/sys/net/ipv4/tcp_sack
	echo "$MAX_SYN_BACKLOG" > /proc/sys/net/ipv4/tcp_max_syn_backlog
	if [ -e /proc/sys/net/ipv4/tcp_syncookies ] ; then
		echo "$SYN_COOKIES" > /proc/sys/net/ipv4/tcp_syncookies 2> /dev/null
	fi

	# If enabled, prevents nmap from guessing your uptime
	echo "$TCP_TIMESTAMPS" > /proc/sys/net/ipv4/tcp_timestamps
	
	# ICMP Dead Error Messages protection
	if [ -e /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses ]; then
		echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
	fi

	# LooseUDP patch is required by some internet-based games
	if [ -e /proc/sys/net/ipv4/ip_masq_udp_dloose ]; then
		if [ "$LOOSE_UDP_PATCH" == "1" ]; then
			echo "1" > /proc/sys/net/ipv4/ip_masq_udp_dloose
		else
			echo "0" > /proc/sys/net/ipv4/ip_masq_udp_dloose
		fi
	fi

	# Reject source routing
	if [ -e /proc/sys/net/ipv4/conf/all/accept_source_route ]; then
		for interface in /proc/sys/net/ipv4/conf/*/accept_source_route; do
			echo "0" > $interface
		done
	fi

	# Increase the default queuelength. (Kernel Default: 1024)
	if [ -e /proc/sys/net/ipv4/ipv4/ip_queue_maxlen ]; then
		if [ ! -z $IP_QUEUE_MAXLEN ] ; then
			echo "$IP_QUEUE_MAXLEN" > /proc/sys/net/ipv4/ip_queue_maxlen
		else
			echo "2048" > /proc/sys/net/ipv4/ip_queue_maxlen
		fi
	fi

	# Prevent IP spoofs
	for i in /proc/sys/net/ipv4/conf/* ; do
		echo 1 > $i/rp_filter
		echo "$LOG_MARTIANS" > $i/log_martians
	done

	return $E_CLEAN_EXEC
# }}}
}

# {{{ Build MD5 of config files
function buildConfigsMD5() {
	if [ "$INIT" != 1 ]; then
		echo -n "Building MD5 hash of config files:"
	fi
	${MD5SUM} ${IPK_ETC_DIR}/*.conf > ${CONFIG_FILES_MD5_SIGS_FILE}
	if [ $? == 0 ]; then
		if [ "$INIT" != 1 ]; then
			echo -e "\t${BRIGHT_COLOUR}OK${CLOSE_COLOUR}"
		fi
	else
		if [ "$INIT" != 1 ]; then
			echo -e "\t${BRIGHT_COLOUR}FAILED${CLOSE_COLOUR}"
		fi
	fi				
# }}}
}

function checkConfigsMD5() {
# {{{ Check md5 of config files to see if they changed
	if [ -f "${NOT_THE_FIRST_RUN}" ]; then
		if [ -e "${CONFIG_FILES_MD5_SIGS_FILE}" ]; then
			if [ "$INIT" != 1 ]; then
				echo -n "Checking MD5 Hash of config files:"
			fi
			${MD5SUM} -c ${CONFIG_FILES_MD5_SIGS_FILE} > /dev/null 2>&1
			if [ "$?" -eq "0" ]; then
				if [ "$INIT" != "1" ]; then
					echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
					echo -n "Restoring /proc settings from cache:"
				fi
				# Restore proc setting from cache
				source "${PROC_CACHE_FILE}"
				handleProc
				if [ "$?" -eq "$E_CLEAN_EXEC" ]; then
					if [ "$INIT" != "1" ]; then
						echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
					fi
				else
					if [ "$INIT" != 1 ]; then
						echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
					fi
				fi
				# Restore saved iptables rules
				if [ "$INIT" != 1 ]; then
					echo -n "Restoring iptables rules from cache:"
				fi
				${IPTABLES}-restore < ${RULES_CACHE_FILE}
				if [ $? == 0 ]; then
					if [ "$INIT" != 1 ]; then
						echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
					fi
					exit $E_CLEAN_EXIT
				else
					if [ "$INIT" != 1 ]; then
						echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
					fi
					exit $E_DIRTY_EXIT
				fi
			else
				if [ "$INIT" != 1 ]; then
					echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
					echo -n "Re-"
				fi
				buildConfigsMD5
			fi
		else
			buildConfigsMD5
		fi
	fi
# }}}
}

# {{{ IPKungFu rules caching check
# Check to see if we're not passing any argument that needs to ipkungfu to
# run all the way, if we are, skip iptables-save/restore.
if [ "$1" != "--no-caching" -o "$1" != "--create-services-file" ]; then
	# Check to see if we're not passing any argument, or if we're
	# passing '--init' or '--quiet', the only acceptable arguments
	# to use rules caching, otherwise, skip iptables-save/restore,
	# It's the only way we can have ipkungfu react to passed arguments.
	if [ "$1" == "--init" -o "$1" == "--quiet" -o "$1" == ""  ]; then
		# Check to see if there are any cached rules, if there ain't
		# it's probably the first time ipkungfu is running, otherwise
		# just check configs MD5 signatures.
		if [ ! -f "$RULES_CACHE_FILE" ] ; then
			if [ "$INIT" != 1 ]; then
				echo "Could not find any cached rules. (First time running?)"
				echo "iptables-restore functionality is disabled."
			fi
			buildConfigsMD5
		else
			checkConfigsMD5
		fi
	fi
fi
# }}}


DATE_STRING="+%Y-%m-%d %H:%M:%S"

function logError() {
	if [ "$1" != "" ]; then
		echo "`date "${DATE_STRING}"` - $1" >> ${IPKUNGFU_LOG}
	fi
}

# {{{ Run pre script
if [ -f /etc/ipkungfu/pre.conf ] ; then
	source /etc/ipkungfu/pre.conf
fi
# }}}

source /etc/ipkungfu/ipkungfu.conf

# {{{ Get Variables
# Get PATH
if [ -z "`grep ^PATH /etc/ipkungfu/ipkungfu.conf`" ] ; then
	PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin
fi

# Detect EXT_NET if not specified
if [ -z "$EXT_NET" ] ; then
	EXT_NET=`route -n | grep ^0.0.0.0 | head -n1 | awk '{print $8}'`
fi

# Detect INT_NET if not defined
if [ -z "$INT_NET" ] ; then
	INT_NET=`echo $(ls /proc/sys/net/ipv4/conf | egrep -v \
      "^lo$|^all$|^default$|$EXT_NET" | cut -d/ -f1)`
fi
if [ -z "$INT_NET" ] ; then
	INT_NET="lo"
fi

# Reasonable guess for LOCAL_NET if not defined
if [ -z "$LOCAL_NET" ] ; then
	LOCAL_NET="192.168.0.0/255.255.0.0 10.0.0.0/255.0.0.0"
fi
LOCAL_NETS=($LOCAL_NET)

# Enable internet connection sharing by default
if [ "$MASQ_LOCAL_NET" != "0" -a "$GATEWAY" != "0" ] ; then
	if [ "$INT_NET" != "lo" ] ; then
		MASQ_LOCAL_NET="1"
		IP_FORWARD="1"
	else
		MASQ_LOCAL_NET="0"
		IP_FORWARD="0"
	fi
fi

# Play nice by default
if [ "$BLOCK_PINGS" != "1" ] ; then
	BLOCK_PINGS="0"
fi

# Drop naughty packets by default
if [ -z "$SUSPECT" ] ; then
	SUSPECT="DROP"
fi
if [ -z "$KNOWN_BAD" ] ; then
	KNOWN_BAD="DROP"
fi
if [ -z "$PORT_SCAN" ] ; then
	PORT_SCAN="DROP"
fi

# Save rules by defalt
if [ "$SAVE_RULES" != "0" ] ; then
	SAVE_RULES="1"
fi

# Don't get IP of EXT_NET if no method for doing so is specified
if [ -z "$GET_IP" ] ; then
	GET_IP="NONE"
fi

if [ "$DONT_DROP_IDENTD" != "1" ] ; then
	DONT_DROP_IDENTD="0"
fi

# Drop requests from private IPs on EXT_NET
if [ "$INT_NET" = "lo" ] ; then
	DISALLOW_PRIVATE="0"
fi
if [ "$DISALLOW_PRIVATE" != "0" ] ; then
	DISALLOW_PRIVATE="1"
fi

# Enumerate internal interfaces
INT_DEV=(${INT_NET})
INT_NET=${INT_DEV[0]}   # For backward compatibility

# Defaults for Port Cloaking
if [ -z "$PORTCLOAK" ] ; then
	PORTCLOAK="0"
fi
if [ -z "$CLOAKUSER" ] ; then
	CLOAKUSER="nobody"
fi
if [ -z "$DUMMYPORT" ] ; then
	DUMMYPORT=29800
fi
if [ -z "$MAXQUEUE" ] ; then
	MAXQUEUE=10
fi
source /etc/ipkungfu/log.conf
# }}}

INIT=0

function loadKernelModules() {
# {{{ Load Kernel Modules
	# Needed to initially load modules (from iptables manual example script)
	${DEPMOD} -a
	# In case user hasn't set the modules to load, see if the default
	# ones exist on the filesystem, and if so load them, else, assume
	# they're built in.
	DEFAULT_MODULES_LIST="ip_nat_irc ip_conntrack_ftp ip_nat_ftp ip_conntrack_irc"
	for default_module in $DEFAULT_MODULES_LIST; do
		if [ -f $($MODPROBE -la | grep ${default_module}) ]; then
			$MODPROBE ${default_module} 2>&1 | logError
		fi
	done
	if [ "$MODULES_LIST" != "" ]; then
		# The user has set MODULES_LIST, so we set the array
		MODULES_ARRAY=(${MODULES_LIST})

		for module in ${MODULES_ARRAY[@]}; do
			if [ -e /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/${module}* ]; then
				if [ -z "`${LSMOD} | grep ${module}`" ] ; then			
					if [ $INIT != 1 ] ; then
						echo -n -e "Loading ${BRIGHT_COLOUR}${module}${CLOSE_COLOUR} module..."
					fi
					$MODPROBE ${module} 2>&1 | logError
					if [ "$?" == "0" ]; then
						if [ $INIT != 1 ] ; then
							echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
						fi
					else
						if [ "$INIT" != "1" ] ; then
							echo "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
						else
							logError "Failed to load ${module}."
						fi
					fi
				else
					if [ $INIT != 1 ] ; then
						echo -e "${BRIGHT_COLOUR}${module}${CLOSE_COLOUR} already loaded."
					fi
				fi
			else
				ERROR_MSG="You're trying to load ${module}, but its not present on your system."
				logError "${ERROR_MSG}"
				
				if [ $INIT != 1 ] ; then
					echo "${ERROR_MSG}"
					echo "Perhaps it's not built or it's built into the kernel."
					echo "Correct MODULES_LIST in ipkungfu.conf and run ipkungfu again."
				fi
			fi
		done
	fi
# }}}
}

function checkDottedQuad {
# {{{ Check for valid IP address
	QUAD="${1}"
	OCTETS=(${QUAD//./ })
	if [ ${#OCTETS[@]} -ne 4 ] ; then
		if [ -z "${FAILURE}" ]; then
			FAILURE="Invalid dotted quad ${QUAD}"
		fi
	return 1
	fi
	
	for OCTET in ${OCTETS[@]}; do
		if echo "$OCTET" | grep -cq "[^[:digit:]]" ; then
			FAILURE="Non-decimal in dotted quad ${QUAD}"
			return 1
		elif [ "$OCTET" -lt "0" -o "$OCTET" -gt "255" ]; then
			FAILURE="Value ${OCTET} out of range 0-255 in dotted quad ${QUAD}"
			return 1
		fi
	done

# }}}
}

function checkNetmaskCidr {
# {{{ check for valid netmask
	CIDR="${1}"
	if echo "$CIDR" | grep -cq "[^[:digit:]]"; then
		FAILURE="Non-decimal in CIDR mask ${CIDR}"
		return 1
	elif [ "$CIDR" -lt "0" -o "$CIDR" -gt "16" ]; then
		FAILURE="Value ${CIDR} out of range 0-32"
		return 1
	fi
# }}}
}

function checkNetwork {
# {{{ Checks config options that involve a host/mask 
	FAILURE=""
	HOSTMASK=(${1//\// })
	HOST=${HOSTMASK[0]}
	MASK=${HOSTMASK[1]}	# Optional: Netfilter assumes /32 if not defined.
	if ! checkDottedQuad $HOST ; then
		FAILURE="Network addresses must be in dotted decimal format: ${FAILURE}"
		return 1
	fi
	
	if [ -n "$MASK" ] && ! checkNetmaskCidr $MASK && ! checkDottedQuad $MASK ; then
		FAILURE="Bad netmask ($MASK): ${FAILURE}"
		return 1
	fi
# }}}
}

# {{{ Get IP of external device
if [ "$GET_IP" != "NONE" -a "$GET_IP" != "None" -a "$GET_IP" != "none" -a ! -z "$GET_IP" ] ; then
	if [ "$GET_IP" == "AUTO" -o "$GET_IP" == "Auto" -o "$GET_IP" == "auto" ] ; then
		inEXT_IP="-d `ifconfig $EXT_NET | grep 'inet addr' | cut -d: -f2 | cut -d ' ' -f1`"
		outEXT_IP="-s `ifconfig $EXT_NET | grep 'inet addr' | cut -d: -f2 | cut -d ' ' -f1`"
		EXT_LAN_BCAST="`ifconfig $EXT_NET | grep 'Bcast' | cut -d: -f3 | cut -d ' ' -f1`"
		EXT_LAN_NET="`route -n | egrep "$EXT_NET$" | cut -d ' ' -f1 | grep -v '0.0.0.0'`/`ifconfig $EXT_NET | grep 'Mask' | cut -d: -f4 | cut -d ' ' -f1`"
		if [ -z "$1" ] ; then
			echo "Using external IP address `echo $inEXT_IP | cut -d ' ' -f2`"
		fi
	fi
else
	checkNetwork $GET_IP
	if [ "$?" == "0" ] ; then
		inEXT_IP="-d $GET_IP"
		outEXT_IP="-s $GET_IP"
	else
		inEXT_IP=""
		outEXT_IP=""
	fi
fi
# }}}

if [ -n "$EXT_LAN_NET" -a -n "$EXT_LAN_BCAST" ] ; then
	if checkNetwork $EXT_LAN_NET && checkNetwork $EXT_LAN_BCAST ; then
		inEXT_LAN_BCAST="-d $EXT_LAN_BCAST"
		outEXT_LAN_BCAST="-s $EXT_LAN_NET"
	else
		inEXT_LAN_BCAST=""
		outEXT_LAN_BCAST=""
	fi
fi

function delTestChain {
# {{{ Flush and delete test chains, if exist
	if $IPTABLES -t filter -L SYSTEST > /dev/null 2>&1 ; then
		$IPTABLES -t filter -F SYSTEST
		$IPTABLES -t filter -X SYSTEST
	fi
	if $IPTABLES -t mangle -L SYSTEST > /dev/null 2>&1 ; then
		$IPTABLES -t mangle -F SYSTEST
		$IPTABLES -t mangle -X SYSTEST
	fi
# }}}
}

function iptFlush {
# {{{ Gets rid of all rules and custom chains
	if [ $INIT != 1 ] ; then
		echo "Clearing old chains and tables..."
	fi
	cat /proc/net/ip_tables_names | while read table; do
		$IPTABLES -t $table -L -n | while read c chain rest; do
			if test "X$c" = "XChain" ; then
				$IPTABLES -t $table -F $chain
			fi
		done
		$IPTABLES -t $table -X
	done
	$IPTABLES -Z
	$IPTABLES -t nat -Z
	$IPTABLES -t mangle -Z
# }}}
}

setupLogging() {
# {{{ Setup logging
	if [ "$LOG_FACILITY" == "ulog" -o "$LOG_FACILITY" == "ULOG" -o "$LOG_FACILITY" == "ulogd" -o "$LOG_FACILITY" == "ULOGD" ] ; then
		LOG_CMD="-m limit --limit ${LOG_FLOOD} -j ULOG"
		if [ "$LOG_PREFIXES" != "0" ] ; then
			LOG_CMD="$LOG_CMD --ulog-prefix"
		fi
	#  TEST_FOR_LOG_SUPPORT=0
	else
		LOG_CMD="-m limit --limit ${LOG_FLOOD} -j LOG"
		if [ "$LOG_PREFIXES" != "0" ] ; then
			LOG_CMD="$LOG_CMD --log-prefix"
		fi
	#  TEST_FOR_LOG_SUPPORT=1
	fi
# }}}
}

function fwdPorts {
# {{{ Port Forwarding
	FWT=`grep : /etc/ipkungfu/vhosts.conf | cut -d \# -f1`
	for NET in ${LOCAL_NETS[@]}; do
		$IPTABLES -t nat -A PREROUTING -s $NET -d ! $NET -j RETURN
	done
	for i in $FWT; do
		# Set up the variables - this gets pretty convoluted
		HPD=":"
		HPDa=":"
		ALLOWED=`echo $i | cut -d ':' -f 1 | sed s/\!/\!\ /`
		VHOST=`echo $i | cut -d ':' -f 2`
		ORIGINAL_PORT=`echo $i | cut -d ':' -f 3 | sed s/-/:/`
		VHOST_PORT=`echo $i | cut -d ':' -f 4`
		VHOST_PORTb=`echo $i | cut -d ':' -f 4 | sed s/-/:/`
		if [ ! -z `echo $VHOST_PORT | grep \-` ] ; then
			VHOST_PORTa=""
			HPDa=""
		else
			VHOST_PORTa=$VHOST_PORT
			HPDa=":"
		fi
		if [ -z "$VHOST_PORTa" -a -z "$ORIGINAL_PORT" ] ; then
			HPDa=""
		fi
		if [ ! -z "$ORIGINAL_PORT" ] ; then
			ORIGINAL_PORT="--dport $ORIGINAL_PORT"
		fi
		if [ ! -z "$VHOST_PORTb" ] ; then
			VHOST_PORTb="--dport $VHOST_PORTb"
		fi
		PROTO=`echo $i | cut -d ':' -f 5`;
		if [ -z "$PROTO" -o "$PROTO" == "any" -o "$PROTO" == "both" -o "$PROTO" == "ANY" -o "$PROTO" == "BOTH" ] ; then
			PROTO="tcp udp"
		fi

		for PCOL in $PROTO; do
			# This is the really important line
			$IPTABLES -t nat -A PREROUTING -p $PCOL $ORIGINAL_PORT -s $ALLOWED $inEXT_IP -j DNAT --to-destination $VHOST$HPDa$VHOST_PORTa
		done
		if [ -z "$inEXT_IP" ] ; then
			for INT_NET in "${INT_DEV[@]}"; do
				for PCOL in $PROTO; do
					# Do it differently if we don't know the external ip address
					$IPTABLES -t nat -A PREROUTING -p $PCOL $ORIGINAL_PORT -s $ALLOWED -i $INT_NET -j DNAT --to-destination $VHOST$HPDa$VHOST_PORTa
				done
			done
		fi
		i=0

		if [ "$DONT_NAT_LOCAL" != "1" ]; then
			for INT_NET in "${INT_DEV[@]}"; do
				LOCAL_IP=`ifconfig $INT_NET | grep 'inet addr' | cut -d: -f2 | cut -d' ' -f1`
				NET=${LOCAL_NETS[$i]}
				# This is what allows it to work on the local network
				$IPTABLES -t nat -A POSTROUTING -p $PCOL $VHOST_PORTb -s $NET -d $VHOST -j SNAT --to-source $LOCAL_IP
				let "i = $i + 1"
			done
		fi

		if [ $INIT != 1 ] ; then
			for PCOL in $PROTO; do
				echo -n "VHost: $VHOST"
				echo -n ", $PCOL"
				if [ ! -z "$ORIGINAL_PORT" ] ; then
					echo -n -e "/${GREEN_COLOUR}`echo $ORIGINAL_PORT | cut -d' ' -f2`${CLOSE_COLOUR}"
				fi

				echo -n " to $PCOL"
				if [ ! -z "$ORIGINAL_PORT" ] ; then
					echo -n -e "/${GREEN_COLOUR}$VHOST_PORT${CLOSE_COLOUR}"
				fi
				echo ", from $ALLOWED"
			done
		fi
	done
# }}}
}
										  
function rdrPorts {
# {{{ Port Redirecting
	RPT=`grep : /etc/ipkungfu/redirect.conf | cut -d \# -f1`
	for i in $RPT; do
		PROTO=`echo $i | cut -d ':' -f1`
		ORIGINAL_PORT=`echo $i | cut -d ':' -f2`
		NEWPORT=`echo $i | cut -d ':' -f3`
		DIRECTION=`echo $i | cut -d ':' -f4`
		if [ $INIT != 1 ] ; then
			echo -e "Redirecting ${GREEN_COLOUR}${ORIGINAL_PORT}/$PROTO${CLOSE_COLOUR} to ${GREEN_COLOUR}${NEWPORT}${CLOSE_COLOUR}"
		fi
		if [ -z "$DIRECTION" ] ; then
			$IPTABLES -t nat -A PREROUTING -p $PROTO --dport $ORIGINAL_PORT -j REDIRECT --to-ports $NEWPORT
		else
			if [ "$DIRECTION" == "internal" -o "$DIRECTION" == "INTERNAL" -o "$DIRECTION" == "int" -o "$DIRECTION" == "INT" ] ; then
				for INT_NET in "${INT_DEV[@]}"; do
					$IPTABLES -t nat -A PREROUTING -p $PROTO --dport $ORIGINAL_PORT -i $INT_NET -j REDIRECT --to-ports $NEWPORT
				done
			else
				$IPTABLES -t nat -A PREROUTING -p $PROTO --dport $ORIGINAL_PORT -i $EXT_NET -j REDIRECT --to-ports $NEWPORT
			fi
		fi
	done
# }}}
}

function manageForward {
# {{{ Manage the FORWARD chain per forward.conf
	for rule in `grep ':' /etc/ipkungfu/forward.conf | grep -v ^\#`; do
		FWD_SRC=`echo $rule | cut -d: -f1`
		FWD_DST=`echo $rule | cut -d: -f2`
		FWD_PORT=`echo $rule | cut -d: -f3`
		FWD_PROTO=`echo $rule | cut -d: -f4`
		FWD_TARGET=`echo $rule | cut -d: -f5`
		FWD_PREFIX=`echo $rule | cut -d: -f6`
		COMMAND="$IPTABLES -A FORWARD"
		if [ ! -z "$FWD_SRC" ] ; then
			COMMAND="$COMMAND -s $FWD_SRC"
		fi
		if [ ! -z "$FWD_DST" ] ; then
			COMMAND="$COMMAND -d $FWD_DST"
		fi
		if [ ! -z "$FWD_PROTO" ] ; then
			COMMAND="$COMMAND -p $FWD_PROTO"
			if [ ! -z "$FWD_PORT" ] ; then
				COMMAND="$COMMAND --dport $FWD_PORT"
			fi
		fi
		if [ "$FWD_TARGET" != "LOG" -a "$FWD_TARGET" != "Log" -a "$FWD_TARGET" != "log" ] ; then
			COMMAND="$COMMAND -j $FWD_TARGET"
		else
			if [ ! -z "$FWD_PREFIX" ] ; then
				COMMAND="$COMMAND $LOG_CMD $FWD_PREFIX"
			else
				COMMAND="$COMMAND $FWD_TARGET"
			fi
		fi
		$COMMAND
	done
# }}}
}

function ipMasq {
# {{{ Masquerading
	if [ "$MASQ_LOCAL_NET" = "1" ]; then
		for NET in ${LOCAL_NET[@]}; do
			$IPTABLES -t nat -A POSTROUTING -o $EXT_NET -s $NET -j MASQUERADE
		done
	fi
# }}}
}

# Usage statement is now a function, it respects the blank spaces
# with the previous behaviour, it didn't.
usage() {
# {{{ Usage Statement
	echo
	echo -e "${BRIGHT_COLOUR}USAGE:${CLOSE_COLOUR} $IPKUNGFU ${BRIGHT_COLOUR}[option]${CLOSE_COLOUR}"
	echo "   [-c or --check]          Check to see if ipkungfu is loaded & mode if any."
	echo "   [-d or --disable]        Disable the firewall & set default poilicy to ACCEPT."
	echo "   [--quiet]                Run with no standard output."
	echo "   [-h or --help]           Display this help message and exit."
	echo "   [-l or --list]           Displays the iptables rule sets."
	echo "   [--panic]                Shut down all internal and external access."
	echo "   [-t or --test]           Test the firewall configuration."
	echo "   [-f or --flush]          Flush all rules."
	echo "   [-v or --version]        Display the version of ipkungfu and exit."
	echo "   [--show-vars]            Show main configuration options, whether specified or detected."
	echo "   [--no-caching]           Disable rules caching."
	echo "   [--failsafe]             If ipkungfu fails, disable the firewall to prevent loss of remote access."
	echo "   [--create-services-file] It just does what it says in case you disabled the warning."
# }}}
}

# {{{ Get command line option
if [ $# -ne 0 ] ; then
	if [ $# -gt 1 ] ; then
		echo -e "Please select one option only or none\n"
		usage
		exit $E_DIRTY_EXIT
	fi

	case "$1" in
		"--version" | "-v")
			# {{{ version
			echo -e "${RED_COLOUR}ipkungfu-$IPKF_VERSION${CLOSE_COLOUR}"
			exit $E_CLEAN_EXIT
			;;
			# }}}
		"--show-vars")
			# {{{ show variables
			echo "IPTABLES=$IPTABLES"
			echo "MODPROBE=$MODPROBE"
			echo "EXT_NET=$EXT_NET"
			echo "EXT_LAN_NET=$EXT_LAN_NET"
			echo "EXT_LAN_BCAST=$EXT_LAN_BCAST"
			echo "ALLOW_EXT_LAN_BCAST=$ALLOW_EXT_LAN_BCAST"
			echo "INT_NET=$INT_NET"
			echo "LOCAL_NET=$LOCAL_NET"
			echo "MASQ_LOCAL_NET=$MASQ_LOCAL_NET"
			echo "IP_FORWARD=$IP_FORWARD"
			echo "ALLOWED_TCP_IN=$ALLOWED_TCP_IN"
			echo "ALLOWED_UDP_IN=$ALLOWED_UDP_IN"
			echo "FORBIDDEN_PORTS=$FORBIDDEN_PORTS"
			echo "BLOCK_PINGS=$BLOCK_PINGS"
			echo "PING_FLOOD=$PING_FLOOD"
			echo "SUSPECT=$SUSPECT"
			echo "KNOWN_BAD=$KNOWN_BAD"
			echo "PORT_SCAN=$PORT_SCAN"
			echo "GET_IP=$GET_IP"
			echo "DONT_DROP_IDENTD=$DONT_DROP_IDENTD"
			echo "DISALLOW_PRIVATE=$DISALLOW_PRIVATE"
			echo "WAIT_SECONDS=$WAIT_SECONDS"
			echo "LOG_FACILITY=$LOG_FACILITY"
			echo "GATEWAY=$GATEWAY"
			exit $E_CLEAN_EXIT
			;;
			# }}}
		"--no-caching")
			# {{{ Disable Rules Caching
			echo "Rules caching disabled"
			NO_CACHING="true"
			;;
			# }}}
		"--list" | "-l") 
			# {{{ list
			${IPTABLES}-save | grep -v -e '^#\|COMMIT\|^:\|^\*'|while read line;do echo "${IPTABLES} $line";done
			exit $E_CLEAN_EXIT
			;;
			# }}} 
		"--test" | "-t")
			# {{{ test configuration and stop
			;;
			# }}}
		"--disable" | "-d")
			# {{{ disable
			# Checking INIT here because we might have been caled from an
			# init script, and if so, no output should be done.
			if [ "$INIT" != "1" ]; then
				echo -n "Stopping ipkungfu:"
			fi
			# Store old init value so we can hardcode INIT's value to
			# disable output
			OLD_INIT="$INIT"
			INIT=1
			iptFlush
			$IPTABLES -P INPUT ACCEPT
			$IPTABLES -P OUTPUT ACCEPT
			$IPTABLES -P FORWARD ACCEPT
			# s0undt3ch
			#$IPTABLES -P IPK_CHK_TOS ACCEPT
			echo "$IP_FORWARD" > /proc/sys/net/ipv4/ip_forward
			rdrPorts
			fwdPorts
			ipMasq
			$IPTABLES -A INPUT -i ${INT_DEV[0]} -s 0.0.0.1 -j LOG --log-prefix "IPKungFu_($1)"
			# Restoring INIT's value to the initial one
			INIT="$OLD_INIT"
			# OLD_INIT is not used anymore, unset it
			unset OLD_INIT
			if [ "$INIT" != "1" ]; then
				echo -e "${GREEN_COLOUR}\tOK${CLOSE_COLOUR}"
			fi
			echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_all
			exit $E_CLEAN_EXIT
			killDummyServer
			;;
			# }}}
		"--check" | "-c")
			# {{{ check status
			if [ -z "`${IPTABLES}-save | grep IPKungFu`" ] ; then
				echo "IPKungFu does NOT appear to be loaded."
			else
				echo -n "IPKungFu is loaded "
				if [ -z "`${IPTABLES}-save | grep IPKungFu | cut -d '(' -f 2 | cut -d ')' -f 1`" ] ; then
					echo ""
				else
					echo -n "with option "
					echo "`${IPTABLES}-save | grep IPKungFu | cut -d '(' -f 2 | cut -d ')' -f 1`"
				fi
			fi
			exit $E_CLEAN_EXIT
			;;
			# }}}
		"--panic")
			# {{{ drop everything
			iptFlush
			$IPTABLES -P INPUT DROP
			$IPTABLES -P OUTPUT DROP
			$IPTABLES -P FORWARD DROP
			echo "0" > /proc/sys/net/ipv4/ip_forward
			echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
			echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
			;;
			# }}}
		"--init")
			# {{{ we were probably called from an init script
			INIT=1
			if [ ! -z "$WAIT_SECONDS" ] ; then
				sleep $WAIT_SECONDS
			fi
			;;
			# }}}
		"--quiet")
			# {{{ quiet
			INIT=1
			;;
			# }}}
		"--help" | "-h")
			# {{{ help
			#echo -e $USAGE"\n"
			usage
			exit $E_CLEAN_EXIT
			;;
			# }}}
		"--flush" | "-f")
			# {{{ flush chains and rules
			echo "Flushing ALL chains and rules..."
			iptFlush
			echo "Done"
			exit $E_CLEAN_EXIT
			;;
			# }}}
		"--failsafe")
			# {{{ Override users Failsafe setting in ipkungfu.conf
			FAILSAFE=1
			# }}}
			;;
		"--create-services-file")
			# {{{ Create services.conf file
			CREATE_SERVICES="YES"
			# }}}
			;;
		*)
			# {{{ usage statement 
			echo
			echo -e "ipkungfu: unknown option: ${BRIGHT_COLOUR}$1${CLOSE_COLOUR}"
			#echo -e $USAGE"\n"
			usage
			exit $E_DIRTY_EXIT
			;;
			# }}}
	esac
fi
# }}}

function configSanityCheck() {
	# {{{ Configuration Sanity Checks
	if [ ! -e /etc/ipkungfu/ipkungfu.conf ] ; then
		# Make sure it's installed
		echo "/etc/ipkungfu/ipkungfu.conf not found."
		echo "IPKungFu must be installed before it can be executed."
		echo "If you have not installed it yet do:"
		echo "	./configure && make && make install"
		echo "If this is your first time using IPKungFu on this machine,"
		echo "by default, the configuration files are not in place, so, do:"
		echo "	make install-config"
		echo "To install the default configuration files."
		echo "Don't forget to edit them to suite your needs"
		exit $E_DIRTY_EXIT
	fi

	source /etc/ipkungfu/advanced.conf

	if [ $INIT != 1 ] ; then
		echo "Checking configuration..."
	fi

	if [ "$UID" != "0" ]; then
		echo -e "${RED_COLOUR}ERROR: Root check FAILED (you MUST be root to use this script)! Quitting...${CLOSE_COLOUR}"
		exit $E_DIRTY_EXIT
	fi

	# It's hard to run an iptables script without iptables... 
	if [ ! -x $IPTABLES ]; then
		echo -e "${RED_COLOUR}ERROR: Binary \"$IPTABLES\" does not exist or is not executable!${CLOSE_COLOUR}"
		echo "Please, make sure that IPTABLES is (properly) installed."
		exit 3
	fi 

	# Make sure ipchains isn't loaded, as this causes problems
	${RMMOD} ipchains > /dev/null 2>&1

	for NET in $LOCAL_NET; do
		if ! checkNetwork $NET ; then
			echo "There is a problem with LOCAL_NET in ${IPK_ETC_DIR}/ipkungfu.conf:"
			echo "$FAILURE"
			echo "You have $NET"
			exit $E_DIRTY_EXIT
		fi
	done

	if [ -n "$EXT_LAN_NET" -a -n "$EXT_LAN_BCAST" ] ; then
		if ! checkNetwork $EXT_LAN_NET ; then
			echo "There is a problem with EXT_LAN_NET in ${IPK_ETC_DIR}/ipkungfu.conf:"
			echo "$FAILURE"
			exit $E_DIRTY_EXIT
		fi

		if ! checkNetwork $EXT_LAN_BCAST ; then
			echo "There is a problem with EXT_LAN_BCAST in ${IPK_ETC_DIR}/ipkungfu.conf:"
			echo "$FAILURE"
			exit $E_DIRTY_EXIT
		fi
	fi

	if [ "$SUSPECT" != "DROP" -a "$SUSPECT" != "REJECT" -a "$SUSPECT" != "MIRROR" \
	-a "$SUSPECT" != "RETURN" ] ; then
		echo "Configuration error:"
		echo "In ${IPK_ETC_DIR}/ipkungfu.conf, SUSPECT must be one of"
		e1cho "DROP, REJECT, or MIRROR (case sensitive)."
		echo "You have $SUSPECT."
		exit $E_DIRTY_EXIT
	fi

	if [ "$KNOWN_BAD" != "DROP" -a "$KNOWN_BAD" != "REJECT" -a "$KNOWN_BAD" != "MIRROR" \
	-a "$KNOWN_BAD" != "RETURN" ] ; then
		echo "Configuration error:"
		echo "In ${IPK_ETC_DIR}/ipkungfu.conf, KNOWN_BAD must be one of"
		echo "DROP, REJECT, or MIRROR (case sensitive)."
		echo "You have $KNOWN_BAD."
		exit $E_DIRTY_EXIT
	fi

	if [ "$PORT_SCAN" != "DROP" -a "$PORT_SCAN" != "REJECT" -a "$PORT_SCAN" != "MIRROR" \
	-a "$PORT_SCAN" != "TARPIT" -a "$PORT_SCAN" != "RETURN" ] ; then
		echo "Configuration error:"
		echo "In ${IPK_ETC_DIR}/ipkungfu.conf, PORT_SCAN must be one of"
		echo "DROP, REJECT, RETURN, or MIRROR (case sensitive)."
		echo "You have $PORT_SCAN."
		exit $E_DIRTY_EXIT
	fi

	GOODHOSTS=`grep . ${IPK_ETC_DIR}/accept_hosts.conf | grep : | cut -d \# -f1`
	for HOST in $GOODHOSTS; do
		PROTO=`echo $HOST | cut -d: -f3`
		if [ "$PROTO" != "tcp" -a "$PROTO" != "TCP" -a "$PROTO" != "udp" -a "$PROTO" != "UDP" \
		-a ! -z "$PROTO" ] ; then
			echo "There is a problem in ${IPK_ETC_DIR}/accept_hosts:"
			echo "Format is host[:port:protocol]"
			echo "You have $HOST"
			exit $E_DIRTY_EXIT
		fi
	done

	BADHOSTS=`grep . ${IPK_ETC_DIR}/deny_hosts.conf | grep : | cut -d \# -f1`
	for HOST in $BADHOSTS; do
		PROTO=`echo $HOST | cut -d: -f3`
		if [ "$PROTO" != "tcp" -a "$PROTO" != "TCP" -a "$PROTO" != "udp" -a "$PROTO" != "UDP" \
		-a ! -z "$PROTO" ] ; then
			echo "There is a problem in ${IPK_ETC_DIR}/deny_hosts:"
			echo "Format is host[:port:protocol]"
			echo "You have $HOST"
			exit $E_DIRTY_EXIT
		fi
	done

	LFNUM=`echo $LOG_FLOOD | cut -d / -f1`
	LFINT=`echo $LOG_FLOOD | cut -d / -f2`
	if [ -z `echo "$LFNUM" | grep -c "[^[:digit:]]"` ] ; then
		echo "There is a problem in ${IPK_ETC_DIR}/log.conf:"
		echo "LOG_FLOOD must be in the format number/interval"
		echo "where interval is one of s,m,h, or d, or second,"
		echo "minute, hour, or day."
		echo "You have $LOG_FLOOD"
		exit $E_DIRTY_EXIT
	fi

	if [ "$LFINT" != "s" -a "$LFINT" != "m" -a "$LFINT" != "h" -a "$LFINT" != "d" \
	-a "$LFINT" != "second" -a "$LFINT" != "minute" -a "$LFINT" != "hour" -a "$LFINT" != "day" ] ; then
		echo "There is a problem in ${IPK_ETC_DIR}/log.conf:"
		echo "LOG_FLOOD must be in the format number/interval"
		echo "where interval is one of s,m,h, or d, or second,"
		echo "minute, hour, or day."
		echo "You have $LOG_FLOOD"
		exit $E_DIRTY_EXIT
	fi

	if [ ! -f "${NO_DEPRECATION_WARNING_FILE}" ]; then
		if [ -f "${IPK_ETC_DIR}/services.conf" ]; then
			if [ "$ALLOWED_TCP_IN" != "" -o "$ALLOWED_UDP_IN" != "" ]; then
				TIMELIMIT=30
				echo
				echo -e "${BRIGHT_COLOUR}WARNING:${CLOSE_COLOUR}"
				echo "You have '${IPK_ETC_DIR}/services.conf' and yet, you still"
				echo "define ALLOWED_TCP_IN or ALLOWED_UDP_IN."
				echo
				echo "As of ipkungfu 0.6.0 both those vars are deprecated and"
				echo "handled on '${IPK_ETC_DIR}/services.conf'"
				echo
				echo "We can re-create your 'services.conf' based on the settings"
				echo "you have on ALLOWED_TCP_IN and/or ALLOWED_UDP_IN."
				echo
				echo "Would you like to take care of this now?"
				echo "We will wait $TIMELIMIT secconds for your answer(s)."
				echo
				echo -n "Answer Yes/No [Default: no]: "
				read -t $TIMELIMIT answer_handle <&1
				if [ -z "$answer_handle" ]; then
					answer_handle="no"
					echo $answer_handle
					NO_HUMAN_ATTENTION_Q1=true
					checkAnswer $answer_handle
				else
					NO_HUMAN_ATTENTION_Q1=false
					checkAnswer $answer_handle
				fi
				returned=$?
				if [ "$returned" == "$E_ANSWER_NO" ]; then
					CREATE_SERVICES="NO"
				elif [ "$returned" == "$E_ANSWER_YES" ]; then
					CREATE_SERVICES="YES"
				else
					CREATE_SERVICES="BAD"
				fi
			fi
		fi
	fi
}
# }}}
configSanityCheck

echoWrongAnswer() {
	echo
	echo "Please answer yes/no only."
	echo "Re-run ipkungfu to be asked again. Exiting."
	exit $E_DIRTY_EXIT
}
	
if [ ! -f "${NO_DEPRECATION_WARNING_FILE}" ]; then
	if [ "$CREATE_SERVICES" == "BAD" ]; then
		echoWrongAnswer
	fi

	if [ "$CREATE_SERVICES" == "NO" ]; then
		echo
		echo "Would you like to disable this warning?"
		echo
		echo -n "Answer Yes/No [Default: no]: "
		read -t $TIMELIMIT answer_warning <&1
		if [ -z "$answer_warning" ]; then
			answer_warning="no"
			NO_HUMAN_ATTENTION_Q2=true
			echo $answer_warning
			checkAnswer $answer_warning
		else
			NO_HUMAN_ATTENTION_Q2=false
			checkAnswer $answer_warning
		fi
	fi
	returned=$?
	if [ "$returned" == "$E_ANSWER_BAD" ]; then
		echoWrongAnswer
	elif [ "$returned" == "$E_ANSWER_NO" ]; then
		# Only log if there's no human interaction, like on boot up.
		if [ "$NO_HUMAN_ATTENTION_Q1" == "true" -a "$NO_HUMAN_ATTENTION_Q2" == "true" ]; then
			LOG_MESSAGE="ipkungfu needs some human attention, please run it to see what's going on"
			logError "$LOG_MESSAGE"
		fi
		# But since this is critical information, echo it to tty until the warning
		# is disabled
		echo
		echo "Since the answer is 'no', ipkungfu won't run until one of these occurs:"
		echo "1 - You disable the warning"
		echo "2 - You transfer you're ALLOWED_TCP_IN and/or ALLOWED_UDP_IN"
		echo "    to services.conf"
		echo "3 - You let us create your services.conf based on what you have"
		echo "    on ALLOWED_TCP_IN and/or ALLOWED_UDP_IN"
		exit $E_DIRTY_EXIT
	elif  [ "$returned" == "$E_ANSWER_YES" ]; then
		echo -n "Disabling the warning:"
		echo "$RANDOM:$(echo $IPK_MD5_SIG | awk '{print $1}')" > ${NO_DEPRECATION_WARNING_FILE}
		if [ $? == 0 ]; then
			echo -n "."
		else
			echo -e "\tFAILED"
		fi
		buildBehaviourFilesMD5
		if [ $? == 0 ]; then
			echo -e "\tDone"
		else
			echo -e "\tFAILED"
		fi
		echo "ATTENTION:"
		echo "Be advised that by disabling the warning it's possible"
		echo "that some unintended behavior may be introduced to"
		echo "ipkungfu without warnings."
		echo
		echo "We can still create the 'services.conf' file for you,"
		echo "just pass '--create-services-file' to ipkungfu."
		exit $E_DIRTY_EXIT
	fi
fi		
		
if [ "$CREATE_SERVICES" == "YES" ]; then
	if [ "$ALLOWED_TCP_IN" == "" -a "$ALLOWED_UDP_IN" == "" ]; then
		echo "ALLOWED_TCP_IN and/or ALLOWED_UDP_IN aren't defined,"
		echo "so, no need to create your services.conf file. Exiting."
		exit $E_CLEAN_EXIT
	fi
	DEF_SERV="# Services needed for TOS."
	DEF_SERV="$DEF_SERV\n# Do NOT change the list below, unless you run"
	DEF_SERV="$DEF_SERV these services on different ports,"
	DEF_SERV="$DEF_SERV\n# or you want to accept their traffic. In this"
	DEF_SERV="$DEF_SERV case add ':ACCEPT' or any"
	DEF_SERV="$DEF_SERV\n# other valid target."
	DEF_SERV="$DEF_SERV\n#"
	DEF_SERV="$DEF_SERV\n# Service Names and Protocols are lowercase,"
	DEF_SERV="$DEF_SERV Targets are UPPERCASE."
	DEF_SERV="$DEF_SERV\n#"
	DEF_SERV="$DEF_SERV\n# Example:"
	DEF_SERV="$DEF_SERV\n#	ssh:22:tcp:ACCEPT"
	DEF_SERV="$DEF_SERV\nftp-data:20:tcp"
	DEF_SERV="$DEF_SERV\nftp:21:tcp"
	DEF_SERV="$DEF_SERV\nssh:22:tcp"
	DEF_SERV="$DEF_SERV\ntelnet:23:tcp"
	DEF_SERV="$DEF_SERV\nsmtp:25:tcp"
	DEF_SERV="$DEF_SERV\ndomain:53:tcp"
	DEF_SERV="$DEF_SERV\nbootps:63:tcp"
	DEF_SERV="$DEF_SERV\nhttp:80:tcp"
	DEF_SERV="$DEF_SERV\npop3:110:tcp"
	DEF_SERV="$DEF_SERV\nauth:113:tcp"
	DEF_SERV="$DEF_SERV\nntp:123:tcp"
	DEF_SERV="$DEF_SERV\nimap:143:tcp"
	DEF_SERV="$DEF_SERV\nhttps:443:tcp"
	DEF_SERV="$DEF_SERV\nimaps:993:tcp"
	DEF_SERV="$DEF_SERV\npop3s:995:tcp"
	DEF_SERV="$DEF_SERV\nsocks:1080:tcp"
	DEF_SERV="$DEF_SERV\n# Add your services below. The rule is:"
	DEF_SERV="$DEF_SERV\n#   ServiceName:ServicePort:Protocol[:ACCEPT|DROP"
	DEF_SERV="$DEF_SERV|REJECT|or any valid target)]  # extra comments"
	DEF_SERV="$DEF_SERV\n#"

	echo -n "Backing ${IPK_ETC_DIR}/services.conf:"
	SERVICES_BACKUP_FILE="${IPK_ETC_DIR}/services.conf.bak"
	cp ${IPK_ETC_DIR}/services.conf $SERVICES_BACKUP_FILE
	if [ $? == 0 ]; then
		echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
		echo "It's $SERVICES_BACKUP_FILE"
	else
		echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
	fi
	echo -n "Replacing ${IPK_ETC_DIR}/services.conf with the default contents:"
	$(echo -e $DEF_SERV > ${IPK_ETC_DIR}/services.conf)
	if [ $? == 0 ]; then
		echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
	else
		echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
	fi
	if [ ! -z "$ALLOWED_TCP_IN" ]; then
		echo "Taking care of the following TCP ports:"
		for port_tcp in $ALLOWED_TCP_IN; do
			echo -n "Port $port_tcp:"
			if [ "$port_tcp" == "20" ]; then
				sed -n s/"ftp-data:20:tcp"/"ftp-data:20:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "21" ]; then
				sed -n s/"ftp:21:tcp"/"ftp:21:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "22" ]; then
				sed -n s/"ssh:22:tcp"/"ssh:22:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "23" ]; then
				sed -n s/"telnet:23:tcp"/"telnet:23:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "25" ]; then
				sed -n s/"smtp:25:tcp"/"smtp:25:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "53" ]; then
				sed -n s/"domain:53:tcp"/"domain:53:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "63" ]; then
				sed -n s/"bootps:63:tcp"/"bootps:63:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "80" ]; then
				sed -n s/"http:80:tcp"/"http:80:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "110" ]; then
				sed -n s/"pop3:110:tcp"/"pop3:110:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "113" ]; then
				sed -n s/"auth:113:tcp"/"auth:113:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "123" ]; then
				sed -n s/"ntp:123:tcp"/"ntp:123:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "143" ]; then
				sed -n s/"imap:143:tcp"/"imap:143:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "443" ]; then
				sed -n s/"https:443:tcp"/"https:443:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "993" ]; then
				sed -n s/"imaps:993:tcp"/"imaps:993:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "995" ]; then
				sed -n s/"pop3s:995:tcp"/"pop3s:995:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			elif [ "$port_tcp" == "1080" ]; then
				sed -n s/"socks:1080:tcp"/"socks:1080:tcp:ACCEPT"/g /etc/ipkungfu/services.conf
			else
				service=`grep "\b$port_tcp/tcp" /etc/services | cut -f1`
				echo "$service:$port_tcp:tcp:ACCEPT" >> ${IPK_ETC_DIR}/services.conf
			fi
			if [ $? == 0 ]; then
				echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
			else
				echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
			fi
		done
	fi
	
	if [ ! -z "$ALLOWED_UDP_IN" ]; then
		echo "Taking care of the following UDP ports:"
		for port_udp in $ALLOWED_UDP_IN; do
			echo -n "Port $port_udp:"
			service=`grep "\b$port_udp/udp" /etc/services | cut -f1`
			echo "$service:$port_udp:udp:ACCEPT" >> ${IPK_ETC_DIR}/services.conf
			if [ $? == 0 ]; then
				echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
			else
				echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
			fi
		done
	fi

	if [ ! -z "$ALLOWED_TCP_IN" ]; then
		echo -n "Commenting out ALLOWED_TCP_IN in ${IPK_ETC_DIR}/ipkungfu.conf"
		sed -i s/"ALLOWED_TCP_IN=\""/"#ALLOWED_TCP_IN=\""/g ${IPK_ETC_DIR}/ipkungfu.conf
		if [ $? == 0 ]; then
			echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
		else
			echo -e "${BRIGHT_COLOUR}\tFAILED${CLOSE_COLOUR}"
		fi
	fi
	if [ ! -z "$ALLOWED_UDP_IN" ]; then
		echo -n "Commenting ALLOWED_UDP_IN in ${IPK_ETC_DIR}/ipkungfu.conf:"
		sed -i s/"ALLOWED_UDP_IN=\""/"#ALLOWED_UDP_IN=\""/g ${IPK_ETC_DIR}/ipkungfu.conf
		if [ $? == 0 ]; then
			echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
		else
			echo -e "${BRIGHT_COLOUR}\tFAILED${CLOSE_COLOUR}"
		fi
	fi
	
	exit $E_CLEAN_EXIT
fi

loadKernelModules

function createTestChain() {	
# {{{ Create a test chain to work with for system abilities testing
	$IPTABLES -N SYSTEST && $IPTABLES -t mangle -N SYSTEST
	if [ "$?" != "0" ] ; then
		echo
		echo "ipkungfu can't create new chains or the script was interrupted previously!"
		echo "Flushing iptables rulesets..."
		$IPTABLES -F
		echo "Clearing old chains and tables..."
		cat /proc/net/ip_tables_names | while read table; do
			$IPTABLES -t $table -L -n | while read c chain rest; do
				if test "X$c" = "XChain" ; then
					$IPTABLES -t $table -F $chain
				fi
			done
			$IPTABLES -t $table -X
		done
		if [ "$1" == "--failsafe" -o "$FAILSAFE" == "1" ] ; then
			echo ""
			echo -e "     ${GREEN_COLOUR}***********${CLOSE_COLOUR}"
			echo -e "     ${GREEN_COLOUR}* WARNING *${CLOSE_COLOUR}"
			echo -e "     ${GREEN_COLOUR}***********${CLOSE_COLOUR}"
			echo ""
			echo "ipkungfu has failed - setting policies to ACCEPT"
			$IPTABLES -P INPUT ACCEPT
			$IPTABLES -P OUTPUT ACCEPT
			$IPTABLES -P FORWARD ACCEPT
			echo "Done.  Please check your config and try again."
			exit $E_DIRTY_EXIT
		fi
	fi
}
# }}}
delTestChain
createTestChain

function testVhostsConfig() {
# {{{ Test for valid vhosts config
	FWT=`grep : /etc/ipkungfu/vhosts.conf | cut -d \# -f 1`
	for i in $FWT; do
		HPD=":"
		HPDa=":"
		ALLOWED=`echo $i | cut -d ':' -f 1 | sed s/\!/\!\ /`
		VHOST=`echo $i | cut -d ':' -f 2`
		OPORT=`echo $i | cut -d ':' -f 3 | sed s/-/:/`
		VPORT=`echo $i | cut -d ':' -f 4`
		VPORTb=`echo $i | cut -d ':' -f 4 | sed s/-/:/`
		if [ ! -z `echo $VHOST_PORT | grep \-` ] ; then
			VPORTa=""
			HPDa=""
		else
			VPORTa=$VPORT
			HPDa=":"
		fi
		PROTO=`echo $i | cut -d ':' -f 5`;
		if [ -z "$PROTO" -o "$PROTO" == "any" -o "$PROTO" == "both" \
		-o "$PROTO" == "ANY" -o "$PROTO" == "BOTH" ] ; then
			PROTO="tcp"
		fi
		if [ ! -z "$OPORT" ] ; then
			OPORT="--dport $OPORT"
		fi
		$IPTABLES -A SYSTEST -p $PROTO $OPORT -s $ALLOWED -d 0.0.0.1 -j ACCEPT > /dev/null 2>&1
		if [ "$?" != "0" ] ; then
			echo "There is a problem in /etc/ipkungfu/vhosts.conf:"
			echo "Format is allowedhost:virtualhostIP:originalport:destinationport:protocol"
			echo "You have $i"
			exit $E_DIRTY_EXIT
		fi
	done
}
# }}}
testVhostsConfig


function redirectError {
# {{{ Test redirect.conf directives
	echo "There is a problem in /etc/ipkungfu/redirect.conf:"
	echo "Format is protocol:originalport:newport"
	echo "You have $ITEM"
	exit $E_DIRTY_EXIT
# }}}
}

function killDummyServer {
# {{{ find and kill fake server
	$NETSTAT -tpln | grep dummy_server > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		$KILLALL dummy_server
	fi
# }}}
}

function testRedirectsConfig() {
# {{{ Test validity of redirect.conf
	RPT=`grep : /etc/ipkungfu/redirect.conf | cut -d \# -f 1`
	for ITEM in $RPT; do
		PROTO=`echo $ITEM | cut -d: -f1`
		OPORT=`echo $ITEM | cut -d: -f2`
		DPORT=`echo $ITEM | cut -d: -f3`
		if [ "$PROTO" != "tcp" -a "$PROTO" != "TCP" -a "$PROTO" != "udp" \
		-a "$PROTO" != "UDP" -a ! -z "$PROTO" ] ; then
			redirectError
		fi
		$IPTABLES -A SYSTEST -p tcp --dport $OPORT -j REJECT > /dev/null 2>&1
		if [ "$?" != "0" ] ; then
			redirectError
		fi
		$IPTABLES -A SYSTEST -p tcp --dport $DPORT -j REJECT > /dev/null 2>&1
		if [ "$?" != "0" ] ; then
			redirectError
		fi
	done
}
# }}}
testRedirectsConfig

function testKernelExtras() {
# {{{ Test for kernel support for extra features
	# {{{ Check for ULOG support
	$IPTABLES -A SYSTEST -j ULOG > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_ULOG="true"
		#  No need to brag about it anymore.  It's in the mainline kernel.
		# if [ $INIT != 1 ] ; then
		#  echo -e " ${BLUE_COLOUR}ULOG${CLOSE_COLOUR} kernel support detected!"
		# fi
	else
		HAVE_ULOG="false"
		if [ "$TEST_FOR_LOG_SUPPORT" == "0" ] ; then
			echo "ULOG support not detected!  Edit /etc/ipkungfu/log.conf accordingly."
			echo "Aborting."
			exit 3
		fi
	fi
	# }}}

	# {{{ Check for string matching support
	$IPTABLES -A SYSTEST -m string --string "test" > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_STRING="true"
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}String matching${CLOSE_COLOUR} support detected!"
		fi
	else
		HAVE_STRING="false"
	fi
	# }}}

	# {{{ Check for LENGTH support
	$IPTABLES -A SYSTEST -m length --length 64 -j ACCEPT > /dev/null 2>&1
	if [ "$?" == "0" ] ; then
		HAVE_LENGTH="true"
	else
		HAVE_LENGTH="false"
	fi
	# }}}

	# {{{ Check for TOS target support
	$IPTABLES -t mangle -A SYSTEST -p tcp -d 1.2.3.4 -j TOS --set-tos Minimize-Delay
	if [ "$?" == "0" ]; then
		HAVE_TOS_TARGET="true"
	else
		HAVE_TOS_TARGET="false"
	fi
	# }}}
	
	# {{{ Check for LIMIT support
	$IPTABLES -A SYSTEST -m limit --limit 5/minute --limit-burst 5 -j ACCEPT > /dev/null 2>&1
	if [ "$?" != "0" ] ; then
		HAVE_LIMIT="true"
	else
		HAVE_LIMIT="false"
	fi
	# }}}

	# {{{ Check for TTL support
	$IPTABLES -t mangle -A SYSTEST -j TTL --ttl-set 80 > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_TTL="true"
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}TTL${CLOSE_COLOUR} support detected!"
		fi
	else
		HAVE_TTL="false"
	fi
	# }}}
	
	# {{{ Check for unclean support
	$IPTABLES -A SYSTEST -m unclean > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_UNCLEAN="true"
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}Unclean${CLOSE_COLOUR} support detected!"
		fi
	else
		HAVE_UNCLEAN="false"
	fi
	# }}}


	# {{{ Check for nth support
	$IPTABLES -A SYSTEST -m nth > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_NTH="true"
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}ipt_nth${CLOSE_COLOUR} patch detected!"
		fi
	else
		HAVE_NTH="false"
	fi
	# }}}
	
	# {{{ Check for 'recent' support
	$IPTABLES -A SYSTEST -m recent --name test --set > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_RECENT="true"
		#  No need to brag about it anymore.  It's in the mainline kernel.
		# if [ $INIT != 1 ] ; then
		#  echo -e " ${BLUE_COLOUR}RECENT${CLOSE_COLOUR} support detected!"
		# fi
	else
		HAVE_RECENT="false"
	fi
	# }}}

	# {{{ Check for iplimit support
	$IPTABLES -A SYSTEST -p tcp --dport 1234 -m iplimit --iplimit-above 2 > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_IPLIMIT="true"
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}iplimit${CLOSE_COLOUR} support detected!"
		fi
	else
		HAVE_IPLIMIT="false"
	fi
	# }}}

	# {{{ Check for psd support
	$IPTABLES -A SYSTEST -m psd > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_PSD="true"
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}Advanced Portscan Detection${CLOSE_COLOUR} support detected!"
		fi
	else
		HAVE_PSD="false"
	fi
	# }}}

	# {{{ Check for Time support
	$IPTABLES -A SYSTEST -m time --timestart 8:00 --timestop 8:01 --days Mon > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_TIME="true"
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}Time${CLOSE_COLOUR} matching support detected!"
		fi
	else
		HAVE_TIME="false"
	fi
	# }}}

	# {{{ Check for LOG support
	$IPTABLES -A SYSTEST -j LOG > /dev/null 2>&1
	if [ "$?" != "0" ] ; then
		if [ "$TEST_FOR_LOG_SUPPORT" == "1" ] ; then
			if [ "$LOG_FACILITY" == "syslog" -o "$LOG_FACILITY" == "SYSLOG" -o "LOG_FACILITY" == "Syslog" ]; then
				echo "Your kernel lacks LOG support, required by your LOG_FACILITY"
				echo "setting in log.conf. Aborting."
				exit 3
			fi
		fi
	fi
	# }}}

	# {{{ Check for stateful matching
	$IPTABLES -A SYSTEST -m state --state ESTABLISHED -j ACCEPT > /dev/null 2>&1
	if [ "$?" != "0" ] ; then
		echo "Your kernel lacks stateful matching, this would break this script. Aborting."
		exit 3
	fi
	# }}}

	# {{{ Check for the limit match
	$IPTABLES -A SYSTEST -m limit -j ACCEPT > /dev/null 2>&1
	if [ "$?" != "0" ] ; then
		echo "Support not found for limiting needed by this script. Aborting."
		exit 3
	fi
	# }}}
	
	# {{{ Check for MARK packets support
	$IPTABLES -t mangle -A SYSTEST -p tcp -d 1.2.3.4 -j MARK --set-mark 1 > /dev/null 2>&1
	if [ "$?" = "0" ] ; then
		HAVE_MARK="true" # This is still not used, but here alreaddy ;)
		if [ $INIT != 1 ] ; then
			echo -e " ${BLUE_COLOUR}MARK${CLOSE_COLOUR} support detected!"
		fi
	else
		HAVE_MARK="false"
	fi
	# }}}
	
}

# }}}
testKernelExtras

# Setup our CMD_LOG
setupLogging

delTestChain

function configTest() {
# {{{ Configuration test
	if [ "$1" = "--test" -o "$1" = "-t" ] ; then
		echo "Your external interface is: $EXT_NET"
		for INT_NET in "${INT_DEV[@]}"; do
			echo "Your internal interface is: $INT_NET"
		done
		if [ -n "$EXT_LAN_NET" -a -n "$EXT_LAN_BCAST" ] ; then
			echo "Your external LAN is: $EXT_LAN_NET, broadcast $EXT_LAN_BCAST"
		fi
		echo -n "You "
		if [ "$ALLOW_EXT_LAN_BCAST" != "1" ] ; then
			echo -n "do NOT "
		fi
		echo "want broadcasts from your external LAN"
		echo -n "You "
		if [ "$IP_FORWARD" != "1" ] ; then
			echo -n "do NOT "
		fi
		echo "want IP forwarding"
		echo -n "You "
		if [ "$MASQ_LOCAL_NET" != "1" ] ; then
			echo -n "do NOT "
		fi
		echo "want IP masquerading"
		for NET in ${LOCAL_NETS[@]}; do
			echo "Your local subnet is $NET"
		done
		echo "The following tcp ports will be open: $ALLOWED_TCP_IN"
		echo "The following udp ports will be open: $ALLOWED_UDP_IN"
		exit $E_CLEAN_EXIT
	fi
}
# }}}
configTest

logger -p info "Activating ipkungfu"
handleProc

iptFlush
TRUSTED_HOSTS=`grep . /etc/ipkungfu/accept_hosts.conf | cut -d \# -f 1`
BADGUY_HOSTS=`grep . /etc/ipkungfu/deny_hosts.conf | cut -d \# -f 1`
FORWARD_POLICY=`grep FORWARD_POLICY /etc/ipkungfu/forward.conf | grep -v ^\# | cut -d= -f2`

# Set default chain policies
$IPTABLES -P OUTPUT  ACCEPT
$IPTABLES -P INPUT   DROP
$IPTABLES -P FORWARD $FORWARD_POLICY

if [ $INIT != 1 ] ; then
	echo "Implementing custom rules..."
fi
source /etc/ipkungfu/custom.conf 


# Useless rule for checking that ipkungfu is loaded
$IPTABLES -A INPUT -i ${INT_DEV[0]} -s 0.0.0.1 -j LOG --log-prefix "IPKF_IPKungFu $1"

getServicesValidRules() {
# {{{ Gather Valid Rules in services.conf
	local TMP_SERVICE=`grep . /etc/ipkungfu/services.conf | cut -d "#" -f1`
	for service in ${TMP_SERVICE}; do
		SERVICES="$SERVICES $service"
	done
# }}}
}
getServicesValidRules

function badGuys() {
# {{{ deal with "badguys"
	if [ ! -z "$BADGUY_HOSTS" ] ; then
		if [ $INIT != 1 ] ; then
			echo "$KNOWN_BAD all traffic from the following hosts/nets:"
		fi

		for HOST in $BADGUY_HOSTS; do
			LINE=`echo $HOST | cut -d ':' -f 2,3 --output-delimiter=QWQ | grep QWQ`
			if [ ! -z "$LINE" ] ; then
				DHOST=`echo $HOST | cut -d ':' -f 1`
				PORT=`echo $HOST | cut -d ':' -f 2 | sed s/-/:/`
				PROTO=`echo $HOST | cut -d ':' -f 3`
				$IPTABLES -A INPUT -i $EXT_NET -s $DHOST -p $PROTO --dport $PORT -j $KNOWN_BAD
				$IPTABLES -A FORWARD -i $EXT_NET -s $DHOST -p $PROTO --dport $PORT -j $KNOWN_BAD
				if [ $INIT != 1 ] ; then
					echo -e " ${GREEN_COLOUR}$DHOST:$PORT/$PROTO${CLOSE_COLOUR}"
				fi
			else
				$IPTABLES -A INPUT -s $HOST -i $EXT_NET -j $KNOWN_BAD
				if [ $INIT != 1 ] ; then
					echo -e " ${GREEN_COLOUR}$HOST${CLOSE_COLOUR}"
				fi
			fi
		done
	fi
	
	if [ "$HAVE_RECENT" = "true" ]; then
		$IPTABLES -A INPUT -m recent --name badguy --rcheck --seconds 120 -j $KNOWN_BAD
		$IPTABLES -A FORWARD -i $EXT_NET -m recent --name badguy --rcheck --seconds 120 -j $KNOWN_BAD
		for PORT in $FORBIDDEN_PORTS; do
			$IPTABLES -A INPUT -p tcp -i $EXT_NET --dport $PORT $LOG_CMD "IPKF_BADGUY_on_port $PORT: "
			$IPTABLES -A FORWARD -p tcp -i $EXT_NET --dport $PORT $LOG_CMD "IPKF_BADGUY_on_port $PORT: "
			$IPTABLES -A INPUT -p tcp -i $EXT_NET --dport $PORT -m recent --name badguy --set -j $KNOWN_BAD
			$IPTABLES -A FORWARD -p tcp -i $EXT_NET --dport $PORT -m recent --name badguy --set -j $KNOWN_BAD
		done
	fi
}
# }}}
badGuys


rdrPorts
fwdPorts

function trustedHosts() {
# {{{ deal with trusted hosts
	if [ ! -z "$TRUSTED_HOSTS" ] ; then
		if [ $INIT != 1 ] ; then
			echo "ACCEPT all connections from the following hosts/nets:"
		fi

		for HOST in $TRUSTED_HOSTS; do
			LINE=`echo $HOST | cut -d ':' -f 2,3 --output-delimiter=QWQ | grep QWQ`
			if [ ! -z "$LINE" ] ; then
				THOST=`echo $HOST | cut -d ':' -f 1`
				PORT=`echo $HOST | cut -d ':' -f 2 | sed s/-/:/`
				PROTO=`echo $HOST | cut -d ':' -f 3`
				if [ "$LOG_EST_EXT" == "1" ] ; then
					$IPTABLES -A INPUT -s $THOST -p $PROTO --dport $PORT $LOG_CMD 'IPKF_New_Connection: '
					$IPTABLES -A FORWARD -i $EXT_NET -s $THOST -p $PROTO --dport $PORT $LOG_CMD 'IPKF_New_Connection: '
				fi
				$IPTABLES -A INPUT -s $THOST -p $PROTO --dport $PORT -j ACCEPT
				$IPTABLES -A FORWARD -i $EXT_NET -s $THOST -p $PROTO --dport $PORT -j ACCEPT
				if [ $INIT != 1 ] ; then
					echo -e " ${GREEN_COLOUR}$THOST:$PORT/$PROTO${CLOSE_COLOUR}"
				fi
			else
				if [ "$LOG_EST_EXT" == "1" ] ; then
					$IPTABLES -A INPUT -s $HOST $LOG_CMD 'IPKF_New_Connection: '
					$IPTABLES -A FORWARD -i $EXT_NET -s $HOST $LOG_CMD 'IPKF_New_Connection: '
				fi
				$IPTABLES -A INPUT -s $HOST -j ACCEPT
				$IPTABLES -A FORWARD -i $EXT_NET -s $HOST -j ACCEPT
				if [ $INIT != 1 ] ; then
					echo -e " ${GREEN_COLOUR}$HOST${CLOSE_COLOUR}"
				fi
			fi
		done
	fi
}
# }}}
trustedHosts

ipMasq

manageForward

if [ "$MASQUERADE_FIX" == "1" ]; then
	for NET in $LOCAL_NET; do
		$IPTABLES -I FORWARD -p tcp -o $EXT_NET -s $NET -m state --state INVALID -j REJECT
		$IPTABLES -I FORWARD -p udp -o $EXT_NET -s $NET -m state --state INVALID -j REJECT
	done
fi

function detectPortScans() {
# {{{ Attempt to detect port scans
if [ "$HAVE_PSD" = "true" ] ; then
	if [ "$LOG_PORT_SCANS" = "1" ] ; then
		$IPTABLES -A INPUT -i $EXT_NET -m psd --psd-delay-threshold 2000 $LOG_CMD 'IPKF_PORTSCAN: '
		$IPTABLES -A FORWARD -i $EXT_NET -m psd --psd-delay-threshold 2000 $LOG_CMD 'IPKF_PORTSCAN: '
	fi
	if [ "$PORTCLOAK" = "1" ] ; then
		killDummyServer
		if [ "$CLOAKUSER" != "nobody" ] ; then
			$CHOWN $CLOAKUSER $IPKUNGFU_BINS_PATH/dummy_server
		fi
		$SU $CLOAKUSER -c "$IPKUNGFU_BINS_PATH/dummy_server $DUMMYPORT $MAXQUEUE &"
		if [ "$?" = "0" ] ; then
			$IPTABLES -t nat -A PREROUTING -p tcp -i $EXT_NET -m psd --psd-delay-threshold 2000 \
			-j REDIRECT --to-ports $DUMMYPORT
		else
			echo "$IPKUNGFU_BINS_PATH/dummy_server could not be started, please check permissions"
		fi
	else
		$IPTABLES -A INPUT -i $EXT_NET -m psd --psd-delay-threshold 2000 -j $PORT_SCAN
		$IPTABLES -A FORWARD -i $EXT_NET -m psd --psd-delay-threshold 2000 -j $PORT_SCAN
	fi
fi

if [ "$LOG_PORT_SCANS" = "1" ] ; then
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL ALL $LOG_CMD 'IPKF_flags_ALL: '
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL NONE $LOG_CMD 'IPKF_flags_NONE: '
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH $LOG_CMD 'IPKF_PORTSCAN_nmap_XMAS: '
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL FIN $LOG_CMD 'IPKF_PORTSCAN_nmap_FIN: '
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN $LOG_CMD 'IPKF_flags_SYN_FIN: '
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST $LOG_CMD 'IPKF_flags_SYN_RST: '
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG $LOG_CMD 'IPKF_SYN_RST_ACK_FIN_URG: '
	$IPTABLES -A INPUT   -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE $LOG_CMD 'IPKF_PORTSCAN_nmap_NULL: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL ALL $LOG_CMD 'IPKF_flags_ALL: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL NONE $LOG_CMD 'IPKF_flags_NONE: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH $LOG_CMD 'IPKF_flags_FIN_URG_PSH: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN $LOG_CMD 'IPKF_PORTSCAN_nmap_XMAS: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN $LOG_CMD 'IPKF_flags_SYN_FIN: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST $LOG_CMD 'IPKF_flags_SYN_RST: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG $LOG_CMD 'IPKF_SYN_RST_ACK_FIN_URG: '
	$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE $LOG_CMD 'IPKF_PORTSCAN_nmap_NULL: '
fi
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL NONE -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL ALL -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags ALL FIN -j $PORT_SCAN
$IPTABLES -A INPUT -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL SYN,RST,ACK,FIN,URG -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL NONE -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,FIN SYN,FIN -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags SYN,RST SYN,RST -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN,URG,PSH -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL ALL -j $PORT_SCAN
$IPTABLES -A FORWARD -p tcp -i $EXT_NET --tcp-flags ALL FIN -j $PORT_SCAN
}
# }}}
detectPortScans

if [ "$BLOCK_PINGS" != "1" ] ; then
	$IPTABLES -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
fi

# {{{ Kill invalid packets (illegal combinations of flags)
if [ "$LOG_INVALID" = "1" ] ; then
	$IPTABLES -A INPUT -m state -p tcp --state INVALID $LOG_CMD 'IPKF_Invalid_TCP_Flag: '
	$IPTABLES -A FORWARD -m state -p tcp -i $EXT_NET --state INVALID $LOG_CMD 'IPKF_Invalid_TCP_flag: '
fi
$IPTABLES -A FORWARD -m state  -i $EXT_NET --state INVALID -j $SUSPECT
$IPTABLES -A INPUT -m state --state INVALID -j $SUSPECT
# }}}

# {{{ Kill and log fragments
if [ "$DROP_FRAGMENTS" == "1" ] ; then
	if [ "$LOG_FRAGMENTS" == "1" ] ; then
		$IPTABLES -A INPUT -i $EXT_NET -f $LOG_CMD 'IPKF_Fragmented_Packet: '
		$IPTABLES -A FORWARD -i $EXT_NET -f $LOG_CMD 'IPKF_Fragmented_Packet: '
	fi
	$IPTABLES -A INPUT -i $EXT_NET -f -j $SUSPECT
	$IPTABLES -A FORWARD -i $EXT_NET -f -j $SUSPECT
fi
# }}}

# {{{ Drop unclean
if [ "$DROP_UNCLEAN" == "1" ] ; then
	if [ "$HAVE_UNCLEAN" == "true" ] ; then
		$IPTABLES -A INPUT -i $EXT_NET -m unclean $LOG_CMD 'IPKF_Unclean: '
		$IPTABLES -A INPUT -i $EXT_NET -m unclean -j $SUSPECT
		$IPTABLES -A FORWARD -i $EXT_NET -m unclean $LOG_CMD 'IPKF_Unclean: '
		$IPTABLES -A FORWARD -i $EXT_NET -m unclean -j $SUSPECT
	fi
fi
# }}}

# {{{ Block possibly dangerous ICMP timestamp requests
$IPTABLES -A INPUT -p icmp --icmp-type timestamp-request -i $EXT_NET $LOG_CMD 'IPKF_ICMP_Timestamp: '
$IPTABLES -A FORWARD -p icmp --icmp-type timestamp-request -i $EXT_NET $LOG_CMD 'IPKF_ICMP_Timestamp: '
$IPTABLES -A INPUT -p icmp --icmp-type timestamp-request -i $EXT_NET -j $SUSPECT
$IPTABLES -A FORWARD -p icmp --icmp-type timestamp-request -i $EXT_NET -j $SUSPECT
# }}}

# {{{ Prevent SYN-floods
$IPTABLES -N syn-flood
$IPTABLES -A INPUT -i $EXT_NET -p tcp --syn -j syn-flood
$IPTABLES -A FORWARD -i $EXT_NET -p tcp --syn -j syn-flood
$IPTABLES -A syn-flood -m limit --limit $SYN_FLOOD/s --limit-burst $SYN_FLOOD_BURST -j RETURN
if [ "$LOG_DOS" = "1" ] ; then
	$IPTABLES -A syn-flood $LOG_CMD 'IPKF_SYN_flood: '
fi
$IPTABLES -A syn-flood -j $SUSPECT
# }}}

$IPTABLES -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -I OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

# {{{ Accounting chains for allowed ports
if [ "$ACCOUNTING" == "1" ] ; then
	$IPTABLES -N acctin
	$IPTABLES -N acctout
	$IPTABLES -I INPUT -j acctin
	$IPTABLES -I OUTPUT -j acctout
fi
# }}}

# {{{ Make sure NEW tcp connections are SYN packets
if [ "$LOG_INVALID" = "1" ] ; then
	$IPTABLES -A INPUT -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW $LOG_CMD 'IPKF_New_Not_SYN: '
	$IPTABLES -A FORWARD -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW $LOG_CMD 'IPKF_New_Not_SYN: '
fi
$IPTABLES -A INPUT -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j $SUSPECT
$IPTABLES -A FORWARD -i $EXT_NET -p tcp ! --tcp-flags SYN,RST,ACK SYN -m state --state NEW -j $SUSPECT
# }}}

# {{{ Drop these tcp ports without logging
PORTS=`echo "$DONT_LOG_TCP" | sed 's/\ /,/g' | sed s/-/:/`
if [ ! -z "$PORTS" ] ; then
	if [ "$DONT_LOG_TCP_USE_MULTIPORT" != "0" ] ; then
		$IPTABLES -A INPUT -i $EXT_NET -p tcp -m multiport --destination-port $PORTS -j $KNOWN_BAD
		$IPTABLES -A FORWARD -i $EXT_NET -p tcp -m multiport --destination-port $PORTS -j $KNOWN_BAD
	else
		for PORT in $DONT_LOG_TCP; do
			$IPTABLES -A INPUT -i $EXT_NET -p tcp --dport $PORT -j $KNOWN_BAD
			$IPTABLES -A FORWARD -i $EXT_NET -p tcp --dport $PORT -j $KNOWN_BAD
		done
	fi
fi
# }}}

# {{{ Drop these udp ports without logging
PORTS=`echo "$DONT_LOG_UDP" | sed 's/\ /,/g' | sed s/-/:/`
if [ ! -z "$PORTS" ] ; then
	if [ "$DONT_LOG_UDP_USE_MULTIPORT" != "0" ] ; then
		$IPTABLES -A INPUT -i $EXT_NET -p udp -m multiport --destination-port $PORTS -j DROP
		$IPTABLES -A FORWARD -i $EXT_NET -p udp -m multiport --destination-port $PORTS -j DROP
	else
		for PORT in $DONT_LOG_UDP; do
			$IPTABLES -A INPUT -i $EXT_NET -p tcp --dport $PORT -j $KNOWN_BAD
			$IPTABLES -A FORWARD -i $EXT_NET -p tcp --dport $PORT -j $KNOWN_BAD
		done
	fi
fi
# }}}

# {{{ Prevent Spoofs
if [ "$DISALLOW_PRIVATE" == "1" ] ; then
	$IPTABLES -A INPUT -s 10.0.0.0/255.0.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 172.16.0.0/255.240.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 192.168.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 127.0.0.0/255.255.255.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 169.254.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 192.0.2.0/255.255.255.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 198.18.0.0/255.254.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 255.255.255.255/255.255.255.255 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 10.0.0.0/255.0.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 172.16.0.0/255.240.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 192.168.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 127.0.0.0/255.255.255.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 169.254.0.0/255.255.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 192.0.2.0/255.255.255.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 198.18.0.0/255.254.0.0 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A FORWARD -s 255.255.255.255/255.255.255.255 -i $EXT_NET $LOG_CMD 'IPKF_Spoof: '
	$IPTABLES -A INPUT -s 10.0.0.0/255.0.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A INPUT -s 172.16.0.0/255.240.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A INPUT -s 192.168.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A INPUT -s 127.0.0.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A INPUT -s 169.254.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A INPUT -s 192.0.2.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A INPUT -s 198.18.0.0/255.254.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A INPUT -s 255.255.255.255/255.255.255.255 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 10.0.0.0/255.0.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 172.16.0.0/255.240.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 192.168.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 127.0.0.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 169.254.0.0/255.255.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 192.0.2.0/255.255.255.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 198.18.0.0/255.254.0.0 -i $EXT_NET -j $KNOWN_BAD
	$IPTABLES -A FORWARD -s 255.255.255.255/255.255.255.255 -i $EXT_NET -j $KNOWN_BAD
fi
# }}}

# {{{ Allow tcp traffic according to ALLOWED_TCP_IN
if [ $INIT != 1 ] ; then
	if [ ! -z "$ALLOWED_TCP_IN" ] ; then
		echo "Allowing Incoming TCP Packets to the Following Ports..."
	fi
fi
SINGLE_PORTS="$(for i in $ALLOWED_TCP_IN; do echo $i | egrep -v -- ':|-';done)"
PORT_RANGES="$(for i in $ALLOWED_TCP_IN; do echo $i | egrep -- ':|-';done | sed s/-/:/g)"

if [ ! -z "$SINGLE_PORTS" ] ; then
	if [ "$LOG_EST_EXT" == "1" ] ; then
		if [ "$ALLOWED_TCP_IN_USE_MULTIPORT" != "0" ] ; then
			$IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW -m multiport \
			--destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` $LOG_CMD 'IPKF_New_Connection: '
		else
			for PORT in $ALLOWED_TCP_IN; do
				$IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW \
				--dport $PORT $LOG_CMD 'IPKF_New_Connection: '
			done
		fi
	fi
	if [ "$ALLOWED_TCP_IN_USE_MULTIPORT" != "0" ] ; then
		$IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW -m multiport \
		--destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` -j ACCEPT
	else
		for PORT in $ALLOWED_TCP_IN; do
			$IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW --dport $PORT -j ACCEPT
		done
	fi
fi

if [ "$ACCOUNTING" = "1" ] ; then
	for PORT in $SINGLE_PORTS; do
		$IPTABLES -A acctin -p tcp --destination-port $PORT -j RETURN
		$IPTABLES -A acctout -p tcp --source-port $PORT -j RETURN
	done
fi

if [ ! -z "$PORT_RANGES" ] ; then
	for RANGE in $PORT_RANGES; do
		if [ "$LOG_EST_EXT" == "1" ] ; then
			$IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW -p tcp \
			--dport $RANGE $LOG_CMD 'IPKF_New_Connection: '
		fi
		$IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW --dport $RANGE -j ACCEPT
		if [ "$ACCOUNTING" = "1" ] ; then
			$IPTABLES -A acctin -p tcp --destination-port $RANGE -j RETURN
			$IPTABLES -A acctout -p tcp --source-port $RANGE -j RETURN
		fi
	done
fi

if [ "$PORTCLOAK" = "1" ] ; then
	$IPTABLES -A INPUT -i $EXT_NET -p tcp -m state --state NEW --dport $DUMMYPORT -j ACCEPT
fi

if [ $INIT != 1 ] ; then
	for PORT in $SINGLE_PORTS; do
		# First check /etc/ipkungfu/services.conf for service name, if not found
		# fall back to old behaviour.
		service=`grep . /etc/ipkungfu/services.conf | grep $PORT | grep tcp | cut -d ':' -f1`
		if [ -z "$service" -o "$service" == "" ] ; then
			service=`grep "\b$PORT/tcp" /etc/services | cut -f1`
		fi
		if [ -z "$service" ] ; then
			service="?"
		fi
		echo -e " ${GREEN_COLOUR}$PORT${CLOSE_COLOUR}\t($service)"
	done
	for RANGE in $PORT_RANGES; do
		echo -e " ${GREEN_COLOUR}$RANGE${CLOSE_COLOUR}"
	done
	if [ "$PORTCLOAK" = "1" ] ; then
		echo -e " ${GREEN_COLOUR}$DUMMYPORT${CLOSE_COLOUR}\t(PortCloaking)"
	fi
fi
# }}}

# {{{ Allow UDP traffic according to ALLOWED_UDP_IN
if [ $INIT != 1 ] ; then
	if [ ! -z "$ALLOWED_UDP_IN" ] ; then
		echo "Allowing Incoming UDP Packets to the Following Ports..."
	fi
fi
SINGLE_PORTS="$(for i in $ALLOWED_UDP_IN; do echo $i | egrep -v -- ':|-';done)"
PORT_RANGES="$(for i in $ALLOWED_UDP_IN; do echo $i | egrep -- ':|-';done | sed s/-/:/g)"
if [ ! -z "$SINGLE_PORTS" ] ; then
	if [ "$LOG_EST_EXT" == "1" ] ; then
		if [ "$ALLOWED_UDP_IN_USE_MULTIPORT" != "0" ] ; then
			$IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW -m multiport \
			--destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` $LOG_CMD 'IPKF_New_Connection: '
		else
			for PORT in $ALLOWED_UDP_IN; do
				$IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW \
				--dport $PORT $LOG_CMD 'IPKF_New_Connection: '
			done
		fi
	fi
	if [ "$ALLOWED_UDP_IN_USE_MULTIPORT" != "0" ] ; then
		$IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW -m multiport \
		--destination-port `echo $SINGLE_PORTS | sed 's/\ /,/g'` -j ACCEPT
	else
		for PORT in $ALLOWED_UDP_IN; do
			$IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW --dport $PORT -j ACCEPT
		done
	fi
fi

if [ "$ACCOUNTING" = "1" ] ; then
	for PORT in $SINGLE_PORTS; do
		$IPTABLES -A acctin -p udp --destination-port $PORT -j RETURN
		$IPTABLES -A acctout -p udp --source-port $PORT -j RETURN
	done
fi

if [ ! -z "$PORT_RANGES" ] ; then
	for RANGE in $PORT_RANGES; do
		if [ "$LOG_EST_EXT" == "1" ] ; then
			$IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW -p tcp \
			--dport $RANGE $LOG_CMD 'IPKF_New_Connection: '
			$IPTABLES -A INPUT -i $EXT_NET -p udp -m state --state NEW --dport $RANGE -j ACCEPT
			if [ "$ACCOUNTING" = "1" ] ; then
				$IPTABLES -A acctin -p udp --destination-port $RANGE -j RETURN
				$IPTABLES -A acctout -p udp --source-port $RANGE -j RETURN
			fi
		fi
	done
fi

if [ "$INIT" != "1" ] ; then
	for PORT in $SINGLE_PORTS; do
		# First check /etc/ipkungfu/services.conf for service name, if not found
		# fall back to old behaviour.
		service=`grep . /etc/ipkungfu/services.conf | grep $PORT | grep udp | cut -d ':' -f1`
		if [ -z "$service" -o "$service" == "" ] ; then
			service=`grep "\b$PORT/udp" /etc/services | cut -f1`
		fi
		if [ -z "$service" ] ; then
			service="?"
		fi
		echo -e " ${GREEN_COLOUR}$PORT${CLOSE_COLOUR}\t($service)"
	done
	for RANGE in $PORT_RANGES; do
		echo -e " ${GREEN_COLOUR}$RANGE${CLOSE_COLOUR}"
	done
fi
# }}}

handleServices() {
# {{{ Handle services.conf
	local name_n=4		# Char Lenght of 'Name'
	local port_n=4		# Char Lenght of 'Port'
	local target_n=6	# Char Lenght of 'Target'
    for service in $SERVICES; do
		if [ "$(echo $service | cut -d ':' -f4)" != "" ]; then
			local name=$(echo $service | cut -d ':' -f1)
			local port=$(echo $service | cut -d ':' -f2 | sed s/-/:/g)
			local proto=$(echo $service | cut -d ':' -f3)
			local target=$(echo $service | cut -d ':' -f4)
			if [ "$LOG_EST_EXT" == "1" ] ; then
				$IPTABLES -A INPUT -i $EXT_NET -p $proto -m state --state NEW \
				--dport $port $LOG_CMD 'IPKF_New_Connection: '
			fi
			$IPTABLES -A INPUT -i $EXT_NET -p $proto -m state --state NEW --dport $port -j $target
			if [ "$ACCOUNTING" = "1" ] ; then
				$IPTABLES -A acctin -p $proto --destination-port $port -j RETURN
				$IPTABLES -A acctout -p $proto --source-port $port -j RETURN
			fi
			
			# If not in INIT, then find out longest strings to neat the output
			if [ "$INIT" != "1" ]; then
				if [ "$(printf "$name" | wc -m)" -gt "$name_n" ]; then
					name_n="${#name}"
				fi
				if [ "$(printf "$port" | wc -m)" -gt "$port_n" ]; then
					port_n="${#port}"
				fi
				if [ "$(printf "$target" | wc -m)" -gt "$target_n" ]; then
					target_n="${#target}"
				fi
			fi
		fi
	done
	
	# Start of neat look
	if [ "$INIT" != "1" ]; then
		# Do we have any valid rule on services.conf ?
		# If not, there's no need to run the code bellow
		if [ "$(grep . /etc/ipkungfu/services.conf | grep -v '#' | \
			cut -d ':' -f4)" != "" ]; then
			echo "Handling Services On The Following Ports..."
			PORT_LBL="Port"
			PORT_LBL_L="4"
			# Loop until both lengths are equal
			until [ "$PORT_LBL_L" -eq "$port_n" ]
			do
				# PORT_LBL_L is already greter than name_n, in this
				# case we define 'port_n += $NAME_LBL_L - $name_n'
				# and break out of the loop, else it would be an infinite
				# loop
				if [ "$PORT_LBL_L" -gt "$port_n" ]; then
					let "port_n += $PORT_LBL_L - $port_n"
					break
				fi
				PORT_LBL="${PORT_LBL} "
				let "PORT_LBL_L += 1"
			done
			NAME_LBL="Name"
			NAME_LBL_L="4"
			# Loop until both lengths are equal
			until [ "$NAME_LBL_L" -eq "$name_n" ]
			do
				# NAME_LBL_L is already greter than name_n, in this
				# case we define 'name_n += $NAME_LBL_L - $name_n'
				# and break out of the loop, else it would be an infinite
				# loop
				if [ "$NAME_LBL_L" -gt "$name_n" ]; then
					let "name_n += $NAME_LBL_L - $name_n"
					break
				fi
				NAME_LBL="$NAME_LBL "
				let "NAME_LBL_L += 1"
			done

			# Case out target is bigger than 6(the lenght of 'Target')
			# Then take into considerantion yet another loop
			if [ "$target_n" -gt "6" ]; then
				TARGET_LBL="Target"
				TARGET_LBL_L="6"
				# Loop until both lengths are equal
				until [ "$TARGET_LBL_L" -eq "$target_n" ]
				do
					# TARGET_LBL_L is already greter than name_n, in this
					# case we define 'target_n += $TARGET_LBL_L - $target_n'
					# and break out of the loop, else it would be an
					# infinite loop.
					# Actually this 'if' sentence doesn't need to be here
					# because its cheched before we arrive here, but for
					# the sake of no infinite loops, here it is.
					if [ "$TARGET_LBL_L" -gt "$target_n" ]; then
						let "target_n += $TARGET_LBL_L - $target_n"
						break
					fi
					TARGET_LBL="$TARGET_LBL "
					let "TARGET_LBL_L += 1"
				done
				HEADER=" ${PORT_LBL}  Protocol  ${NAME_LBL}  ${TARGET_LBL} "
			else
				HEADER=" ${PORT_LBL}  Protocol  ${NAME_LBL}  Target "
			fi
		
			HEADER_L="${#HEADER}"
			
			# The shortest header size is 30 chars wide, so we make
			# ruller 30 '-' wide by default because it will reduce the
			# until loop time.
			RULER="------------------------------"
			RULER_L=30
			until [ "$RULER_L" -ge "$HEADER_L" ]
			do
				RULER="${RULER}-"
				let "RULER_L += 1"
			done
			echo "$RULER"
			echo -e "${BRIGHT_COLOUR}${HEADER}${CLOSE_COLOUR}"
			echo "$RULER"
			for service in $SERVICES; do
				if [ "$(echo $service | cut -d ':' -f4)" != "" ]; then
					local name=$(echo $service | cut -d ':' -f1)
					local port=$(echo $service | cut -d ':' -f2)
					local proto=$(echo $service | cut -d ':' -f3)
					local target=$(echo $service | cut -d ':' -f4)
					if [ "$name" == "" ]; then
						name=$(grep "\b$port/tcp" /etc/services | cut -f1)
					fi
					if [ -z "$name" ] ; then
						name="(?)"
					fi
					port_l="${#port}"
					name_l="${#name}"
					# Loop until both lengths are equal
					until [ "$port_l" -eq "$port_n" ]
					do
						# This check is actually un-necessary, but for the
						# sake of no infinite loops, it's here.
						if [ "$port_l" -gt "$port_n" ]; then
							break
						fi
						# Do the resizing
						port="$port "
						let "port_l += 1"
					done
					# Loop until both lengths are equal
					until [ "$name_l" -eq "$name_n" ]
					do
						# This check is actually un-necessary, but for the
						# sake of no infinite loops, it's here.
						if [ "$name_l" -gt "$name_n" ]; then
							break
						fi
						# Do the resizing
						name="$name "
						let "name_l += 1"
					done
					local output=" ${GREEN_COLOUR}$port  $proto    "
					output="${output} ${CLOSE_COLOUR} ${BRIGHT_COLOUR} $name"
					output="${output} ${BLUE_COLOUR} $target${CLOSE_COLOUR}"
					echo -e "${output}"
				fi
			done
			echo "$RULER"
		fi
	fi	
# }}}
}
handleServices


# {{{ Allow broadcasts from external LAN
if [ "$ALLOW_EXT_LAN_BCAST" == "1" -a -n "$inEXT_LAN_BCAST" -a -n "$outEXT_LAN_BCAST" ] ; then
	$IPTABLES -A INPUT -i $EXT_NET -p udp $inEXT_LAN_BCAST $outEXT_LAN_BCAST -j ACCEPT
fi
# }}}

# {{{ Allow local traffic
$IPTABLES -I INPUT -i lo -m state --state NEW -j ACCEPT
i=0
for INT_NET in ${INT_DEV[@]}; do
	NET=${LOCAL_NETS[$i]}
	if [ "$LOG_EST_INT" == "1" ] ; then
		$IPTABLES -I INPUT -m state --state NEW -s $NET -i $INT_NET $LOG_CMD 'IPKF_New_Connection: '
	fi
	$IPTABLES -I INPUT -m state --state NEW -s $NET -i $INT_NET -j ACCEPT
	if [ "$MASQ_LOCAL_NET" = "1" ] ; then
		# Set up masquerading for internet connection sharing
		$IPTABLES -I FORWARD -m state --state NEW -s $NET -i $INT_NET -j ACCEPT
	fi
	let "i = $i + 1"
done
$IPTABLES -A OUTPUT -m state --state NEW -j ACCEPT
# }}}

# {{{ Gracefully close identd probes
if [ "$DONT_DROP_IDENTD" = "1" ] ; then
	$IPTABLES -A INPUT -p tcp --dport 113 -j REJECT --reject-with tcp-reset
	$IPTABLES -A FORWARD -i $EXT_NET -p tcp --dport 113 -j REJECT --reject-with tcp-reset
fi
# }}}

# {{{ Log new connections to the internal network from the internet.
# This shouldn't happen unless you have servers set up in
# vhosts.conf or you have one or more public IP addresses
# inside your LAN
if [ "$LOG_EST_EXT" == "1" ] ; then
	for NET in ${LOCAL_NETS[@]}; do
		$IPTABLES -A FORWARD -d $NET -m state --state NEW -p tcp \
		--tcp-flags SYN,RST,ACK SYN $LOG_CMD 'IPKF_New_Connection: '
	done
fi

if [ "$LOG_EST_INT" == "1" ] ; then
	for NET in ${LOCAL_NETS[@]}; do
		$IPTABLES -A FORWARD -s $NET -m state --state NEW -p tcp \
		--tcp-flags SYN,RST,ACK SYN $LOG_CMD 'IPKF_New_Connection: '
	done
fi
# }}}

# {{{ Anything not caught by another rule gets caught here
if [ "$LOG_CATCH_ALL" = "1" ] ; then
	$IPTABLES -A INPUT -p ! icmp $LOG_CMD ' IPKF_INPUT_Catch-all: '
fi
$IPTABLES -A INPUT -j $SUSPECT
# }}}

# {{{ Try to foil NAT detection
if [ ! -z "$TTL" ] ; then
	if [ "$HAVE_LENGTH" = "true" ] ; then
		if [ "$HAVE_TTL" = "true" ] ; then
			$IPTABLES -t mangle -N NATCLOAK
			$IPTABLES -t mangle -I POSTROUTING -j NATCLOAK
			$IPTABLES -t mangle -A NATCLOAK -p udp -m udp --dport 33434:33500 -m length --length 38 -j RETURN
			$IPTABLES -t mangle -A NATCLOAK -p icmp -m icmp --icmp-type 8 -m length --length 92 -j RETURN
			$IPTABLES -t mangle -A NATCLOAK -j TTL --ttl-set $TTL
		else
			echo -e "${BLUE_COLOUR}Warning:${CLOSE_COLOUR} TTL configured in advanced.conf but not supported by your kernel"
		fi
	fi
fi
# }}}

function setServicePortsNeededForTos() {
# {{{ Setup the port numbers needed for TOS
	# {{{ Parse /etc/ipkungfu/services.conf
	SERVICES_FILE="/etc/ipkungfu/services.conf"
	SERVICE_FTP_DATA=`grep ^ftp-data: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_FTP=`grep ^ftp: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_SSH=`grep ^ssh: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_TELNET=`grep ^ftp: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_SMTP=`grep ^smtp: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_DOMAIN=`grep ^domain: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_BOOTPS=`grep ^bootps: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_HTTP=`grep ^http: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_POP3=`grep ^pop3: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_AUTH=`grep ^auth: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_NTP=`grep ^ntp: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_IMAP=`grep ^imap: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_HTTPS=`grep ^https: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_IMAPS=`grep ^imaps: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_POP3S=`grep ^pop3s: ${SERVICES_FILE} | cut -d: -f2`
	SERVICE_SOCKS=`grep ^socks: ${SERVICES_FILE} | cut -d: -f2`
	# }}}
	# {{{ Check to see if they were defined, if not fall trough /etc/services
	if [ -z "${SERVICE_FTP_DATA}" ]; then SERVICE_FTP_DATA="ftp-data"; fi
	if [ -z "${SERVICE_FTP}" ]; then SERVICE_FTP="ftp"; fi
	if [ -z "${SERVICE_SSH}" ]; then SERVICE_SSH="ssh"; fi
	if [ -z "${SERVICE_TELNET}" ]; then SERVICE_TELNET="telnet"; fi
	if [ -z "${SERVICE_SMTP}" ]; then SERVICE_SMTP="smtp"; fi
	if [ -z "${SERVICE_DOMAIN}" ]; then SERVICE_DOMAIN="domain"; fi
	if [ -z "${SERVICE_BOOTPS}" ]; then SERVICE_BOOTPS="bootps"; fi
	if [ -z "${SERVICE_HTTP}" ]; then SERVICE_HTTP="http"; fi
	if [ -z "${SERVICE_POP3}" ]; then SERVICE_POP3="pop3"; fi
	if [ -z "${SERVICE_AUTH}" ]; then SERVICE_AUTH="auth"; fi
	if [ -z "${SERVICE_NTP}" ]; then SERVICE_NTP="ntp"; fi
	if [ -z "${SERVICE_IMAP}" ]; then SERVICE_IMAP="imap"; fi
	if [ -z "${SERVICE_HTTPS}" ]; then SERVICE_HTTPS="https"; fi
	if [ -z "${SERVICE_IMAPS}" ]; then SERVICE_IMAPS="imaps"; fi
	if [ -z "${SERVICE_POP3S}" ]; then SERVICE_POP3S="pop3s"; fi
	if [ -z "${SERVICE_SOCKS}" ]; then SERVICE_SOCKS="socks"; fi
	# }}}
# }}}
}

function setOutputTos() {
# {{{ OUTPUT - RFC 1060/1349 suggested TOS values
	$IPTABLES -t mangle -A OUTPUT -p icmp -j TOS --set-tos Minimize-Delay
	
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_FTP_DATA} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_FTP} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_SSH} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_TELNET} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_SMTP} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p udp --dport ${SERVICE_DOMAIN} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_BOOTPS} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_HTTP} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_POP3} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_AUTH} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_NTP} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_IMAP} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_HTTPS} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_IMAPS} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_POP3S} -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport ${SERVICE_SOCKS} -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A OUTPUT -p tcp --dport 6000:6063 -j TOS --set-tos Maximize-Throughput
# }}}
}

function setInputTos() {
# {{{ INPUT - RFC 1060/1349 suggested TOS values
	# $IPTABLES -t mangle -A INPUT -p tcp --sport 20 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p tcp --sport ftp-data -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 21 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport ftp -j TOS --set-tos Minimize-Delay
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 22 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport ssh -j TOS --set-tos Minimize-Delay
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 23 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport telnet -j TOS --set-tos Minimize-Delay
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 25 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport smtp -j TOS --set-tos Minimize-Delay
	#$IPTABLES -t mangle -A INPUT -p udp --sport 53 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p udp --sport domain -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 67 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport bootps -j TOS --set-tos Minimize-Delay
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 80 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p tcp --sport http -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 110 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p tcp --sport pop3 -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 113 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport auth -j TOS --set-tos Minimize-Delay
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 123 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport ntp -j TOS --set-tos Minimize-Delay
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 143 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p tcp --sport imap -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 443 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p tcp --sport https -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 993 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p tcp --sport imaps -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 995 -j TOS --set-tos Maximize-Throughput
	$IPTABLES -t mangle -A INPUT -p tcp --sport pop3s -j TOS --set-tos Maximize-Throughput
	#$IPTABLES -t mangle -A INPUT -p tcp --sport 1080 -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport socks -j TOS --set-tos Minimize-Delay
	$IPTABLES -t mangle -A INPUT -p tcp --sport 6000:6063 -j TOS --set-tos Maximize-Throughput
# }}}
}

function correctTos() {
# {{{ Correct already set TOS
	correctLargePacketTos() {
	# {{{ Correct TOS for large packets with Minimize-Delay
		$IPTABLES -t mangle -A IPT_CHK_TOS -p tcp -m length --length 0:512  -j RETURN
		$IPTABLES -t mangle -A IPT_CHK_TOS -p udp -m length --length 0:1024  -j RETURN
		$IPTABLES -t mangle -A IPT_CHK_TOS -j TOS --set-tos Maximize-Throughput
		$IPTABLES -t mangle -A IPT_CHK_TOS -j RETURN

		$IPTABLES -t mangle -A PREROUTING -m tos --tos Minimize-Delay -j IPK_CHK_TOS
	# }}}
	}
	modifyTcpControlPacketTos() {
	# {{{ Modifying TOS for TCP control packets: (from www.docum.org / Stef Coene)
		$IPTABLES -t mangle -A IPK_ACK_TOS -m tos --tos ! Normal-Service -j RETURN
		$IPTABLES -t mangle -A IPK_ACK_TOS -p tcp -m length --length 0:256 -j TOS --set-tos Minimize-Delay
		$IPTABLES -t mangle -A IPK_ACK_TOS -p tcp -m length --length 256: -j TOS --set-tos Maximize-Throughput
		$IPTABLES -t mangle -A IPK_ACK_TOS -j RETURN
		$IPTABLES -t mangle -A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK ACK -j IPK_ACK_TOS
	# }}}
	}
	correctLargePacketTos
	modifyTcpControlPacketTos	
# }}}
}

if [ "$HAVE_TOS_TARGET" == "true" ]; then
	setServicePortsNeededForTos
	setOutputTos
fi
#setInputTos
#correctTos

# {{{ Run post script
if [ -f /etc/ipkungfu/post.conf ] ; then
	source /etc/ipkungfu/post.conf
fi
# }}}

createProcCache() {
# {{{ Create a "cache" file with proc settings
	echo "IP_FORWARD=$IP_FORWARD" > $PROC_CACHE_FILE
	echo "LOG_MARTIANS=$LOG_MARTIANS" >> $PROC_CACHE_FILE
	echo "BLOCK_PINGS=$BLOCK_PINGS" >> $PROC_CACHE_FILE
	if [ ! -z $ICMP_ECHO_IGNORE_BROADCASTS ] ; then
		echo "ICMP_ECHO_IGNORE_BROADCASTS=$ICMP_ECHO_IGNORE_BROADCASTS" \
		>> $PROC_CACHE_FILE
	fi
	echo "FIN_TIMEOUT=$FIN_TIMEOUT" >> $PROC_CACHE_FILE
	echo "TCP_KEEPALIVE=$TCP_KEEPALIVE" >> $PROC_CACHE_FILE
	echo "TCP_WINDOW_SCALING=$TCP_WINDOW_SCALING" >> $PROC_CACHE_FILE
	echo "TCP_SACK=$TCP_SACK" >> $PROC_CACHE_FILE
	echo "MAX_SYN_BACKLOG=$MAX_SYN_BACKLOG" >> $PROC_CACHE_FILE
	echo "SYN_COOKIES=$SYN_COOKIES" >> $PROC_CACHE_FILE
	echo "TCP_TIMESTAMPS=$TCP_TIMESTAMPS" >> $PROC_CACHE_FILE
	echo "LOOSE_UDP_PATCH=$LOOSE_UDP_PATCH" >> $PROC_CACHE_FILE
	if [ ! -z $IP_QUEUE_MAXLEN ] ; then
		echo "IP_QUEUE_MAXLEN=$IP_QUEUE_MAXLEN" >> $PROC_CACHE_FILE
	fi
	return $E_CLEAN_EXEC
# }}}
}
		
createRulesCache() {
# Create a cache file of iptables rules
	${IPTABLES}-save > ${RULES_CACHE_FILE}
	return $E_CLEAN_EXEC
}

if [ "${NO_CACHING}" != "true" -o ! -f "$NO_CACHING_FILE" ]; then
	if [ "$INIT" != 1 ]; then
		echo -n "Creating proc settings cache:"
	fi
	createProcCache
	if [ $? == $E_CLEAN_EXEC ]; then
		if [ "$INIT" != 1 ]; then
			echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
		fi
	else
		if [ "$INIT" != 1 ]; then
			echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
		fi
	fi
	
	if [ "$INIT" != 1 ]; then
		echo -n "Creating iptables rules cache:"
	fi
	createRulesCache
	if [ $? == $E_CLEAN_EXEC ]; then
		if [ "$INIT" != 1 ]; then
			echo -e "${BRIGHT_COLOUR}\tOK${CLOSE_COLOUR}"
		fi
	else
		if [ "$INIT" != 1 ]; then
			echo -e "${RED_COLOUR}\tFAILED${CLOSE_COLOUR}"
		fi
	fi
else
	if [ "$INIT" != 1 ]; then
		echo "Skiping Rules Caching!"
	fi
fi
# }}}

exit $E_CLEAN_EXIT
