#!/bin/sh
#
# /etc/rc.d/firewall - start/stop/close/restart iptables firewall
#


# configuration variables
IPTABLES="/usr/sbin/iptables"
IFCONFIG="/sbin/ifconfig"
EXTIF="eth0"


# services are defined as name|protocol (tcp/udp)|port(s)|connections-per-second
# examples:
#  bittorrent|tcp|6881:6889  (port range)
#  samba.udp|udp|137,138         (multiple nonconsecutive ports)
#  samba.tcp|tcp|139,445         (multiple nonconsecutive ports)
#  ssh|tcp|22|1              (1 connection max per second)

SERVICES=(
	"ssh|tcp|22" \
	"ident|tcp|113|1" \
	"bittorrent|tcp|6881:6889" \
	"samba.udp|udp|137,138" \
	"samba.tcp|tcp|139,445" \
)


# sanity checks
if [ ! -x $IPTABLES ]
then
	echo "ERROR: $IPTABLES doesn't exist or isn't executable."
	exit
fi

if [ ! -x $IFCONFIG ]
then
	echo "ERROR: $IFCONFIG doesn't exist or isn't executable."
	exit
fi


# gather network information
IP_ADDR=`$IFCONFIG $EXTIF | grep "inet addr:" | cut -d: -f2 | cut -d" " -f1`
NETMASK=`$IFCONFIG $EXTIF | grep "Mask:" | cut -d: -f4`
NETWORK="$IP_ADDR/$NETMASK"


case "$1" in
	"start")
		# clear out the old rules, if any

		# filter
		echo -n "Flushing iptables rules: "
		echo -n "filter"
		$IPTABLES -F

		echo ""


		# clear and create custom tables, if any
		echo -n "Creating custom tables: "

		# log and drop
		echo -n "LOGDROP"
		$IPTABLES -t filter -N LOGDROP

		echo ""


		# set default policies
		echo -n "Setting default policies: "

		# input (drop)
		echo -n "INPUT:DROP"
		$IPTABLES -t filter -P INPUT DROP
		echo -n " "

		# output (accept)
		echo -n "OUTPUT:ACCEPT"
		$IPTABLES -t filter -P OUTPUT ACCEPT

		echo ""


		# define custom tables, if any
		echo -n "Defining custom tables: "

		# log and drop
		echo -n "LOGDROP"
		LOGDROP="$IPTABLES -t filter -A LOGDROP"
		#$LOGDROP -j LOG --log-prefix="LOGDROP: "
		$LOGDROP -j DROP

		echo ""

		# input filtering rules
		INPUT="$IPTABLES -t filter -A INPUT"
		echo -n "Setting INPUT rules: "
		$INPUT -m state --state INVALID -j LOGDROP
		$INPUT -i lo -j ACCEPT
		$INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

		# icmp
		$INPUT -i $EXTIF -p icmp -j ACCEPT

		# services defined above
		for SERVICE in ${SERVICES[@]}
		do
			SERVICE_NAME=`echo $SERVICE | cut -d\| -f1`
			SERVICE_PROTO=`echo $SERVICE | cut -d\| -f2`
			SERVICE_PORT=`echo $SERVICE | cut -d\| -f3`
			SERVICE_FREQ=`echo $SERVICE | cut -d\| -f4`

			echo -n "$SERVICE_NAME "

			IPT_COMMAND="$INPUT --in-interface $EXTIF"
			case "$SERVICE_PROTO" in
				"tcp")
					IPT_COMMAND="$IPT_COMMAND --protocol tcp"
					;;
				"udp")
					IPT_COMMAND="$IPT_COMMAND --protocol udp"
					;;
				*)
					echo "Unknown protocol \"$SERVICE_PROTO\"! Skipping this rule: $SERVICE_NAME"
					continue
					;;
			esac

			if echo "$SERVICE_PORT" | grep -q ","
			then
				IPT_COMMAND="$IPT_COMMAND --match multiport --dports $SERVICE_PORT"
			else
				IPT_COMMAND="$IPT_COMMAND --dport $SERVICE_PORT"
			fi

			if [ ! -z "$SERVICE_FREQ" ]
			then
				IPT_COMMAND="$IPT_COMMAND --match limit --limit $SERVICE_FREQ/s"
			fi

			IPT_COMMAND="$IPT_COMMAND --jump ACCEPT"

			# run it
			$IPT_COMMAND

		done
		echo

		# SSH Throttling
		echo "Configuring SSH throttling..."
		$IPTABLES --new-chain sshthrottle

		$IPTABLES --append sshthrottle \
			--match recent --update --seconds 15 --name sshthrottlelog \
			--jump DROP
 
		$IPTABLES --append sshthrottle \
			--match recent --set --name sshthrottlelog \
			--jump LOG --log-prefix "Throttling SSH: "

		$IPTABLES --append sshthrottle --jump DROP

		$IPTABLES --append INPUT --in-interface $EXTIF \
			--protocol tcp --destination-port 22 \
			--match state --state NEW \
			--match recent --update --seconds 15 --name sshthrottle \
			--jump sshthrottle

		$IPTABLES --append INPUT --in-interface $EXTIF \
			--protocol tcp --destination-port 22 \
			--match state --state NEW \
			--match recent --set --name sshthrottle \
			--jump ACCEPT
		;;
	"stop")
		$IPTABLES -F
		$IPTABLES -X LOGDROP
		$IPTABLES -X sshthrottle
		$IPTABLES -P INPUT ACCEPT
		$IPTABLES -P OUTPUT ACCEPT
		;;
	"close")
		$IPTABLES -F
		$IPTABLES -X LOGDROP
		$IPTABLES -X sshthrottle
		$IPTABLES -P INPUT DROP
		$IPTABLES -P OUTPUT DROP
		echo "WARNING: This firewall mode is only for emergency maintenance! Default policies are DROP, networking isn't useful in this state!"
		;;
	"restart")
		$0 stop; $0 start
		;;
	*)
		echo "Usage: $0 start|stop|close|restart"
		;;
esac
