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

Me='catchmapreply'
MyVersion='0.3.3'
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						-j $Me
		$IptablesBin $AppIn FORWARD							-j $Me
		$IptablesBin $AppIn OUTPUT -o \! lo						-j $Me
		;;
	unlink)
		$IptablesBin -D INPUT -i \! lo							-j $Me
		$IptablesBin -D FORWARD								-j $Me
		$IptablesBin -D OUTPUT -o \! lo							-j $Me
		$IptablesBin -X $Me >/dev/null 2>&1
		;;
	create)
		echo "Starting $Me" >&2
		FlushOrNewChain $Me
		#Here we log the _destination_ address of any proto, host, network, or port unreachable, or
		#time exceeded packets.  Note these have to be RELATED packets, meaning that there 
		#had to be a packet that elicited the error.  The original packet might still have had
		#a spoofed source, so a) we can't ban forever, and b) this may still affect normal operation.
		#For this reason, the punishmapper script should follow the "allow ESTABLISHED,RELATED" rule.
		LogAs='mapper-proto'	$Ipt -A $Me -p icmp --icmp-type protocol-unreachable	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-network'	$Ipt -A $Me -p icmp --icmp-type network-unreachable	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-hostt'	$Ipt -A $Me -p icmp --icmp-type TOS-host-unreachable	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-networkt'	$Ipt -A $Me -p icmp --icmp-type TOS-network-unreachable	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-hostp'	$Ipt -A $Me -p icmp --icmp-type host-prohibited		-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-networkp'	$Ipt -A $Me -p icmp --icmp-type network-prohibited	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-commp'	$Ipt -A $Me -p icmp --icmp-type communication-prohibited -m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-hostu'	$Ipt -A $Me -p icmp --icmp-type host-unknown		-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-networku'	$Ipt -A $Me -p icmp --icmp-type network-unknown		-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-timeex'	$Ipt -A $Me -p icmp --icmp-type time-exceeded		-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-srcrt'	$Ipt -A $Me -p icmp --icmp-type source-route-failed	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		LogAs='mapper-param'	$Ipt -A $Me -p icmp --icmp-type parameter-problem	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		#I would _like_ to tag the recipients of rst's as mappers too, but I can't tell between an
		#IP getting a reset because they're mapping tcp ports, and an IP getting a reset because
		#the server to which they were connected was shut down.  Instead, we'll depend on the psd
		#(port scan detector) module in catchmapper.
		#Also, port and host unreachable do show up in normal use.  We'll have to use canaries
		#to handle tcp rst, port unreach and host unreach.
		#LogAs='mapper-host'	$Ipt -A $Me -p icmp --icmp-type host-unreachable	-m state --state RELATED -m recent --name mapper --rdest --set	$Tail
		#LogAs='mapper-port'	$Ipt -A $Me -p icmp --icmp-type port-unreachable	-m state --state RELATED -m recent --name mapper --rdest --set	$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		-j $Me
			$IptablesBin -R FORWARD `$IptablesBin -L FORWARD -n --line-numbers | grep $TempChain | awk '{print $1}'`		-j $Me
			$IptablesBin -R OUTPUT `$IptablesBin -L OUTPUT -n --line-numbers | grep $TempChain | awk '{print $1}'` -o \! lo		-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 identifies people trying to map our network.  It
looks for icmp errors such as proto, host, network, or port
unreachables, as well as time exceeded in transit errors, and remembers
the _destination_ ip address of those packets - the IP that sent the
probe packet.
	Because of the potential for a spoofed source address in a probe
packet, this is a potentially dangerous module.
EOTEXT
		;;
	*)
		echo "Unknown action $Action in $Me, no action taken." >&2
		;;
	esac
done
