#!/bin/bash
#Copyright 2003 William Stearns <wstearns@pobox.com>
#Released under the GPL.

#FIXME - sort by flag frequency

Me='tcpchk'
MyVersion='0.3.2'
DefaultActions='DROP'

[ -r /etc/firebricks/firebricks.conf ] &&			. /etc/firebricks/firebricks.conf
[ -r /etc/firebricks/$Me.conf ] &&				. /etc/firebricks/$Me.conf
[ -r ${FBLibDir:-'/usr/lib/firebricks/'}/firebrickslib ] &&	. ${FBLibDir:-'/usr/lib/firebricks/'}/firebrickslib
if [ -z "$FBLibVer" ]; then
	echo 'It looks like firebrickslib was not loaded, why?  Exiting' >&2
	exit 1
fi

for OneTask in $Tasks ; do
	case "$OneTask" in
	link)
		$IptablesBin -N $Me >/dev/null 2>&1
		$IptablesBin $AppIn INPUT -i \! lo -p tcp					-j $Me
		$IptablesBin $AppIn FORWARD -p tcp						-j $Me
		$IptablesBin $AppIn OUTPUT -p tcp						-j $Me
		;;
	unlink)
		$IptablesBin -D INPUT -i \! lo -p tcp						-j $Me
		$IptablesBin -D FORWARD -p tcp							-j $Me
		$IptablesBin -D OUTPUT -p tcp							-j $Me
		$IptablesBin -X $Me >/dev/null 2>&1
		;;
	create)
		echo "Starting $Me" >&2
		FlushOrNewChain $Me

		LogAs='tcp-lowport'	$Ipt -A $Me -p tcp --sport 0:19				$Tail
		LogAs='tcp-lowport'	$Ipt -A $Me -p tcp --dport 0:19				$Tail

#UAPRSF
#We put in no rules for these as they're legal for flags, but might get
#chucked later for a different reason (invalid source/dest address, etc.)
#010000	A legal
					$IptablesBin -A $Me -p tcp --tcp-flags ALL ACK		-j RETURN
#011000	PA legal
					$IptablesBin -A $Me -p tcp --tcp-flags ALL PSH,ACK	-j RETURN
#000000	NULL block (confirmed)
		LogAs='tcpflag-null'	$Ipt -A $Me -p tcp --tcp-flags ALL NONE			$Tail
#111111	XMAS block
		LogAs='tcpflag-xmas'	$Ipt -A $Me -p tcp --tcp-flags ALL ALL			$Tail
#????11	SF block (confirmed)
		LogAs='tcpflag-sf'	$Ipt -A $Me -p tcp --tcp-flags SYN,FIN SYN,FIN		$Tail
#???11?	SR block (confirmed)
		LogAs='tcpflag-sr'	$Ipt -A $Me -p tcp --tcp-flags SYN,RST SYN,RST		$Tail
#???1?1	RF block (confirmed)
		LogAs='tcpflag-rf'	$Ipt -A $Me -p tcp --tcp-flags RST,FIN RST,FIN		$Tail
#1???1?	SU block (no payload on syn, cannot have urg data)
		LogAs='tcpflag-su'	$Ipt -A $Me -p tcp --tcp-flags SYN,URG SYN,URG		$Tail
#001010	SP block (no payload on syn)
		LogAs='tcpflag-sp'	$Ipt -A $Me -p tcp --tcp-flags ALL SYN,PSH		$Tail
#011010	SAP block (no payload on syn/ack)
		LogAs='tcpflag-sap'	$Ipt -A $Me -p tcp --tcp-flags ALL SYN,ACK,PSH		$Tail
#?0???1	F, no A block
		LogAs='tcpflag-f'	$Ipt -A $Me -p tcp --tcp-flags ACK,FIN FIN		$Tail
#??0??1	P, no A block
		LogAs='tcpflag-p'	$Ipt -A $Me -p tcp --tcp-flags ACK,PSH PSH		$Tail
#0????1	U, no A block
		LogAs='tcpflag-u'	$Ipt -A $Me -p tcp --tcp-flags ACK,URG URG		$Tail
#RST only?  I get them from the razor servers.  strange.
					$IptablesBin -A $Me -p tcp --tcp-flags ALL RST		-j RETURN
#?0??0?	neither S nor A block
		LogAs='tcpflag-nosa'	$Ipt -A $Me -p tcp --tcp-flags SYN,ACK NONE		$Tail
#000010	S legal
					$IptablesBin -A $Me -p tcp --tcp-flags ALL SYN		-j RETURN
#010010	SA legal
					$IptablesBin -A $Me -p tcp --tcp-flags ALL SYN,ACK	-j RETURN
#010001	FA legal
					$IptablesBin -A $Me -p tcp --tcp-flags ALL FIN,ACK	-j RETURN
#010100	RA legal
					$IptablesBin -A $Me -p tcp --tcp-flags ALL RST,ACK	-j RETURN
#111000	APU (legal, ctrl-c on telnet)
					$IptablesBin -A $Me -p tcp --tcp-flags ALL ACK,PSH,RST	-j RETURN
#011001	FPA RETURN (FIN implies a push, but we're seeing this on legit traffic)
					$IptablesBin -A $Me -p tcp --tcp-flags ALL FIN,PSH,ACK	-j RETURN

#For the following, I want to be conservative; I'm not sure if they're bad or good.
#Leaving them as counter rules for the moment.
#011100	RAP block?
					$IptablesBin -A $Me -p tcp --tcp-flags ALL RST,ACK,PSH	#-j DROP
#110100	RAU block?
					$IptablesBin -A $Me -p tcp --tcp-flags ALL RST,ACK,URG	#-j DROP
#111100	RAPU block?
					$IptablesBin -A $Me -p tcp --tcp-flags ALL RST,ACK,PSH,URG #-j DROP
#111001	FPAU block? (FIN implies a push)
					$IptablesBin -A $Me -p tcp --tcp-flags ALL FIN,PSH,ACK,URG #-j DROP
#110000	AU? (APU more likely)
					$IptablesBin -A $Me -p tcp --tcp-flags ALL ACK,URG	#-j DROP
#110001	AUF?
					$IptablesBin -A $Me -p tcp --tcp-flags ALL ACK,URG,FIN	#-j DROP
		;;
	destroy)
		echo "Stopping $Me" >&2
		DestroyChain $Me
		;;
	renamechain)
		TempChain="$Me-$RANDOM"
		echo "Replacing existing rules in $Me with new rules" >&2
		$IptablesBin -E $Me $TempChain
		;;
	replacelinks)
		if [ -z "$TempChain" ]; then
			echo "No temporary chain to relink in $Me replacelinks, replace operation incomplete." >&2
		elif ! $IptablesBin -L $Me -n >/dev/null 2>&1 ; then
			echo "No $Me chain in $Me, replace operation incomplete." >&2
		elif ! $IptablesBin -L $TempChain -n >/dev/null 2>&1 ; then
			echo "No $TempChain chain in $Me, replace operation incomplete." >&2
		elif [ "`$IptablesBin -L INPUT -n --line-numbers | grep $TempChain | wc -l`" -ne 1 ]; then
			echo "Too few/many references to $TempChain in INPUT in $Me replacelinks, replace operation incomplete." >&2
		elif [ "`$IptablesBin -L FORWARD -n --line-numbers | grep $TempChain | wc -l`" -ne 1 ]; then
			echo "Too few/many references to $TempChain in FORWARD in $Me replacelinks, replace operation incomplete." >&2
		elif [ "`$IptablesBin -L OUTPUT -n --line-numbers | grep $TempChain | wc -l`" -ne 1 ]; then
			echo "Too few/many references to $TempChain in OUTPUT in $Me replacelinks, replace operation incomplete." >&2
		else
			$IptablesBin -R INPUT `$IptablesBin -L INPUT -n --line-numbers | grep $TempChain | awk '{print $1}'` -i \! lo -p tcp	-j $Me
			$IptablesBin -R FORWARD `$IptablesBin -L FORWARD -n --line-numbers | grep $TempChain | awk '{print $1}'` -p tcp		-j $Me
			$IptablesBin -R OUTPUT `$IptablesBin -L OUTPUT -n --line-numbers | grep $TempChain | awk '{print $1}'` -p tcp		-j $Me
			DestroyChain $TempChain
			unset TempChain
		fi
		;;
	status)
		if $IptablesBin -L $Me -n >/dev/null 2>&1 ; then
			echo "$Me created" >&2
		else
			echo "$Me destroyed" >&2
		fi
		;;
	version)
		echo "$Me $MyVersion, firebrickslib $FBLibVer" >&2
		;;
	help)
		DefaultHelp
		cat <<EOTEXT >&2
	The $Me module checks characteristics of tcp traffic.  It
handles low port (ports 0-19) and illegal tcp flag combinations.  The
flag rules tend to be conservative, so it should be safe to use these in
any environment (unless you know you are using small services).

EOTEXT
		;;
	*)
		echo "Unknown action $Action in $Me, no action taken." >&2
		;;
	esac
done



