#!/bin/sh
# iptables rules as example for my routing workstation laptop.
# see and understand..	(c) 2006 sebastian kucharczyk
# v0.2

### configure REJECTion TCP ports ###############################################
REJECT_TCP_PORTS="ssh domain http x11 microsoft-ds netbios-ssn"
### configure REJECTion UDP ports ###############################################
REJECT_UDP_PORTS="domain bootps bootpc x11 32768 netbios-dgm netbios-ns"
### configure port FORWARDing ###################################################
# syntax: dport/host[:port]     
FORWARD_TCP_PORTS=""
FORWARD_UDP_PORTS=""
#################################################################################

EXT="eth2 ppp0"	 # externe(s) interface(s); inet-router
INT=eth0	 # internes local area network
ENABLE_ROUTER=0	 # wanna act as router? 0=change nothing, 1=yes, 2=no
TCP_SYNCOOKIES=1 # useful against some kind of dos
		 # with a gateway ip there will be added such a route:
SET_ROUTE="192.168.2.1"

IPTABLES="/sbin/iptables"	# usually this is the path to iptables
ROUTE="/sbin/route"

function syntax() {
	echo "Syntax: $0 <start|stop|restart>"
	exit 1
}

function header() {
	echo "**** cake's firewall * v0.1 ********"
}

function footer() {
	echo "************************************"
}

function fw_stop() {
	echo "* Flushing existing rules          *"
	$IPTABLES -F	# Flush chains..
	$IPTABLES -F -t nat	# same for network address translation rules.
	# wenn nicht aktiviert, garnichts aendern an der alten einstellung
	test $ENABLE_ROUTER -gt 0 && echo "0" > /proc/sys/net/ipv4/ip_forward
	# sind laut kernel wegen etwaigen problemen immer noch nicht standardmaessig aktiviert
	test $TCP_SYNCOOKIES -ne 0 && echo "0" > /proc/sys/net/ipv4/tcp_syncookies
	test -e /tmp/ciptr_firewall && if [ $SET_ROUTE ]; then
		$ROUTE del -net default gw $SET_ROUTE
	fi
	rm /tmp/ciptr_firewall 2>/dev/null # remove cookie; singleton-styles
}

function started() {
	echo "* Error: already started.. stop first or restart." > /dev/stderr
	footer
	exit 1
}

function fw_start() {
	test -e /tmp/ciptr_firewall && started

	error[1]="Could not set up MASQUERADE on $EXT output"
	error[2]="Error while applying REJECT rule for"
	error[3]="The default route could not be set up"
	error[4]="Port forwarding was not successfull for"
	chain_err=0
	masq_err=0
	route_err=0
	forw_err=0

	touch /tmp/ciptr_firewall
	if [ $TCP_SYNCOOKIES -ne 0 ]; then
		echo "* enabling TCP SYN cookies         *"
		echo "1" > /proc/sys/net/ipv4/tcp_syncookies
	fi
	# anfragen auf interne server werden nicht erlaubt;
	# manuell. white-listing ist viel zu aufwendig, nerviger und damit mau.
	# .. Append to INPUT chain, interface $INT, protocol udp, dest. port, Jump to rule REJECT
	test "$REJECT_TCP_PORTS" && echo "* appending TCP protocol REJECTs   *	<- ${REJECT_TCP_PORTS[@]}"
	for port in $REJECT_TCP_PORTS; do
		for iface in $EXT; do
			$IPTABLES -A INPUT -i $iface -p tcp --dport $port -j REJECT 2>/dev/null
			if [ $? -ne 0 ]; then
				error[2]="${error[2]} TCP:$port"
				let chain_err=$chain_err+1
			fi
		done
	done
        test "$REJECT_UDP_PORTS" && echo "* appending UDP protocol REJECTs   *	<- ${REJECT_UDP_PORTS[@]}"
	for port in $REJECT_UDP_PORTS; do
		for iface in $EXT; do
			$IPTABLES -A INPUT -i $iface -p udp --dport $port -j REJECT 2>/dev/null
			if [ $? -ne 0 ]; then
				error[2]="${error[2]} UDP:$port"
				let chain_err=$chain_err+1
			fi
		done
	done
	if [ "$FORWARD_TCP_PORTS" ]; then
		echo -n "* configuring FORWARD of UDP ports *	<-"
		for forw in $FORWARD_TCP_PORTS; do
			dport=`echo -n $forw|awk -F/ '{print $1}'`
			echo -n " $dport"
			dest=`echo -n $forw|awk -F/ '{print $2}'`
			for iface in $EXT; do
				$IPTABLES -t nat -A PREROUTING -i $iface -p tcp --dport $dport -j DNAT --to $dest
				if [ $? -ne 0 ]; then
					error[4]="${error[4]} TCP:$dport->$dest"
					let forw_err=$forw_err+1
				fi
			done
		done
		echo
	fi
	if [ "$FORWARD_UDP_PORTS" ]; then
		echo -n "* configuring FORWARD of UDP ports *	<-"
		for forw in $FORWARD_UDP_PORTS; do
			dport=`echo -n $forw|awk -F/ '{print $1}'`
			echo -n " $dport"
			dest=`echo -n $forw|awk -F/ '{print $2}'`
			for iface in $EXT; do
				$IPTABLES -t nat -A PREROUTING -i $iface -p udp --dport $dport -j DNAT --to $dest
				if [ $? -ne 0 ]; then
					error[4]="${error[4]} UDP:$dport->$dest"
					let forw_err=$forw_err+1
				fi
			done
		done
		echo
	fi

	if [ $SET_ROUTE ]; then
		echo "* setting up ROUTE..               *	<- $SET_ROUTE"
		$ROUTE add -net 0.0.0.0 gw $SET_ROUTE || route_err=1
	fi

	if [ $ENABLE_ROUTER -ne 0 ]; then
		echo "* making host to gateway           *"
		# masquerade bei ausgehenden paketen.. ausgehende pakete werden
		# auf die source-ip getestet und wenn's von einer anderen
		# kommt (bzw. einem anderen host), wirds notiert
		# und die entsprechenden antworten vom router weitergeleitet..
		for iface in $EXT; do
			$IPTABLES -t nat -A POSTROUTING -o $iface -j MASQUERADE >/dev/null 2>&1 || masq_err=1
		done
		# `test` != 0 is just used to prevent override of old settings and with `2' to disable it globally.
		_tmp_path=/proc/sys/net/ipv4/ip_forward
		if [ $ENABLE_ROUTER -eq 1 ]; then echo "1" > $_tmp_path
		elif [ $ENABLE_ROUTER -eq 0 ]; then echo "0" > $_tmp_path; fi
	fi

	let i=$chain_err+$masq_err+$route_err
	test $i -gt 0 && echo	# bei min. einem fehler nen line feed ,)
	test $chain_err -ne 0 && echo "*! ${error[2]} [$chain_err]">/dev/stderr
	test $masq_err -eq 1 && echo "*! ${error[1]}" >/dev/stderr
	test $forw_err -ne 0 && echo "*! ${error[4]}" >/dev/stderr
	test $route_err -eq 1 && echo "*! ${error[3]}">/dev/stderr

	footer
	exit $i
}

function _start() {
	header
	fw_start
}

function _stop() {
	header
	fw_stop
	footer
}

function _restart() {
	header
	fw_stop
	fw_start
}

case "$1" in
	start)
		_start;;
	stop)
		_stop;;
	restart)
		_restart;;
	*)
		syntax;;
esac


