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

Me='mapssh'
MyVersion='0.4.0'
#DefaultActions=''

[ -r /etc/modwall/modwall.conf ] &&			. /etc/modwall/modwall.conf
[ -r /etc/modwall/$Me.conf ] &&				. /etc/modwall/$Me.conf
[ -r ${MWLibDir:-'/usr/lib/modwall/'}/modwalllib ] &&	. ${MWLibDir:-'/usr/lib/modwall/'}/modwalllib
if [ -z "$MWLibVer" ]; then
	echo 'It looks like modwalllib 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 \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375	-j $Me
		$IptablesBin $AppIn FORWARD -p tcp \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375		-j $Me
		$IptablesBin $AppIn OUTPUT -p tcp \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375		-j $Me
		;;
	unlink)
		$IptablesBin -D INPUT -i \! lo -p tcp \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375	-j $Me
		$IptablesBin -D FORWARD -p tcp \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375		-j $Me
		$IptablesBin -D OUTPUT -p tcp \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375		-j $Me
		$IptablesBin -X $Me >/dev/null 2>&1
		;;
	create)
		echo "Starting $Me" >&2
		FlushOrNewChain $Me

		#Check for first 255 bytes of tcp connection, hex
		#0x5353482d ("SSH-") as first 4 payload octets,
		#established, <192 bytes (mine was 77, even with 12
		#bytes of tcp options.

		#The entire command is as follows, but we've already checked most of this 
		#in IOF.  The shorter version follows this long one.
		#LogAs='sshserver'	$Ipt -A $Me -p tcp \! -f -m connbytes --connbytes 0:255 \
		# -m state --state ESTABLISHED -m length --length 46:375 -m u32 \
		# --u32 "0>>22&0x3C@ 12>>26&0x3C@ 0=0x5353482D"	$Tail
		#FIXME - put in tests for specific ssh versions here with -m string
		LogAs='sshserver'	$Ipt -A $Me -m u32 --u32 '"0>>22&0x3C@ 12>>26&0x3C@ 0=0x5353482D"'	$Tail
		;;
	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 \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375	-j $Me
			$IptablesBin -R FORWARD `$IptablesBin -L FORWARD -n --line-numbers | grep $TempChain | awk '{print $1}'` -p tcp \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375		-j $Me
			$IptablesBin -R OUTPUT `$IptablesBin -L OUTPUT -n --line-numbers | grep $TempChain | awk '{print $1}'` -p tcp \! -f -m connbytes --connbytes 0:255 -m state --state ESTABLISHED -m length --length 46:375		-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, modwalllib $MWLibVer" >&2
		;;
	help)
		DefaultHelp
		cat <<EOTEXT >&2
	The $Me module uses some very tight checks to identify the SSH
protocol string found at the beginning of a connection.  Because it
strictly limits how many packets it inspects, it _should_ not produce
high load on the system, even when inspecting every tcp connection. 
There is a small chance of false positives and/or false negatives.
EOTEXT
		;;
	*)
		echo "Unknown action $Action in $Me, no action taken." >&2
		;;
	esac
done