#!/bin/bash
#todo:		#echo

pathto () {		#Single parameter: host
	echo 127.0.0.1 `traceroute $1 2>/dev/null | awk '{print $3}' | sed -e 's/(//' -e 's/)//'`
}

reachable () {	#Single parameter: host
	if [ -n "$SIMULATEDEAD" ] && [ `echo "$SIMULATEDEAD" | grep " $1 " | wc -l` -gt 0 ]; then
		echo Simulating $1 dead. ;		return 1	#False, Lie.
	elif [ -n "$ASSUMELIVE" ] && [ `echo "$ASSUMELIVE" | grep " $1 " | wc -l` -gt 0 ]; then
		echo Assuming $1 line. ;		return 0	#True, Lie.
	elif [ `ping -s 56 -c 4 $1 | grep '^64 bytes' | wc -l` -eq 0 ]; then
		return 1	#False
	else
		if [ -d $PSPATH/$1 ]; then
			touch $PSPATH/$1
			touch $PSPATH/$1/HOST-REACHABLE
		fi
		return 0	#True
	fi
}

checkconn () {
#Have inline function to return talkport, servicetype from "http", "80", or "3128=80".  case servicetype below.
#Check case on all
#server, port

	case "$2" in
	53|dns|domain|nameserver)	#Ummm, for the moment we only do udp dns checks
		#DNS check.  It fails if the host is unreachable too.
		if nslookup -query=A localhost "$1" >/dev/null 2>/dev/null ; then
			return 0 #True
		else
			return 1 #False
		fi
		;;
	*)
		case $3 in
		[Ii][Cc][Mm][Pp])	PROTO="icmp"				;;
		[Tt][Cc][Pp])		PROTO="tcp"					;;
		[Uu][Dd][Pp])		PROTO="udp" ;	NCUDP="-u"	;;
		'')					PROTO="tcp"					;;
		esac

		case "$2/$PROTO" in
		7|7/tcp|echo|echo/tcp)			SEND='ggg\n'				EXPECT='ggg'				;;	#Hmmm, not yet...
		13|13/tcp|daytime|daytime/tcp)	SEND='\n'					EXPECT='... ... [0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]' ;;
		21|21/tcp|ftp|ftp/tcp)			SEND='QUIT\n'				EXPECT='FTP server'			;;
		22|22/tcp|ssh|ssh/tcp)			SEND='\n'					EXPECT='^SSH'				;;
		25|25/tcp|smtp|smtp/tcp)		SEND='QUIT\n'				EXPECT='ESMTP Sendmail'		;;
		37|37/tcp|time|time/tcp)		SEND='\n'					EXPECT='^....$'				;;
		80|80/tcp|http|http/tcp)		SEND='GET / HTTP/1.0\n\n'	EXPECT='^HTTP'				;;
		110|110/tcp|pop-3|pop-3/tcp)	SEND='QUIT'					EXPECT='^\+OK'				;;
		143|143/tcp|imap|imap/tcp)		SEND='A0001 LOGOUT\n'		EXPECT='A0001 OK LOGOUT'	;;
		3128|3128/tcp|squid|squid/tcp)	SEND='GET / HTTP/1.0\n\n'	EXPECT='^HTTP'				;;
		8080|8080/tcp)					SEND='GET / HTTP/1.0\n\n'	EXPECT='^HTTP'				;;
		*)			echo "Unknown protocol $2/$PROTO, please set." ; return		;;
		esac

		#echo -e "$SEND" | nc $NCUDP "$1" "$2" 2>/dev/null | grep "$EXPECT"
		#echo -e "$SEND" | nc $NCUDP "$1" "$2" 2>/dev/null | head
		if echo -e "$SEND" | nc $NCUDP "$1" "$2" 2>/dev/null | grep "$EXPECT" >/dev/null ; then
			#echo -e "$1 port $2\tOK"
			return 0 #True
		else
			#echo -e "$1 port $2\tFAIL"
			return 1 #False
		fi
		;;
	esac

}

#Setup:
if [ -f /etc/portstatus.conf ]; then
	. /etc/portstatus.conf
fi
#SIMULATEDEAD="144.228.175.6 205.166.61.185"	#One line, space separated
#ASSUMELIVE="144.232.7.1"	#One line, space separated.  This might screw up the "Last live IP" report.
if [ -n "$SIMULATEDEAD" ]; then SIMULATEDEAD=" $SIMULATEDEAD " ; fi
if [ -n "$ASSUMELIVE" ]; then ASSUMELIVE=" $ASSUMELIVE " ; fi
PSPATH=${PSPATH:-"/var/state/portstatus/"}				; if [ ! -d "$PSPATH" ]; then mkdir -p $PSPATH ; fi
HOSTSFILE=${HOSTSFILE:-"/var/state/portstatus/hosts"}	; if [ ! -f "$HOSTSFILE" ]; then touch $HOSTSFILE ; fi
touch $PSPATH/last-run

for ONEIP in `cat $HOSTSFILE | grep '##' | sed -e 's/#.*//' | awk '{print $1}'` ; do
	HOSTLINE=`egrep "^$ONEIP[^0-9]" $HOSTSFILE | tail --lines=1`
	HOSTNAME=`echo $HOSTLINE | sed -e 's/#.*//' | awk '{print $2}'`
	HOSTNAME=${HOSTNAME:-$ONEIP}
	CHECKSERVICES=`echo $HOSTLINE | sed -e 's/.*##//' -e 's/,/ /'`
	echo -n "Host $HOSTNAME,"
	if [ "$HOSTNAME" != "$ONEIP" ]; then
		echo -n " with IP address $ONEIP,"
	fi
	echo " checking for" $CHECKSERVICES
	if reachable $ONEIP ; then
		if [ ! -d $PSPATH/$ONEIP ]; then mkdir -p $PSPATH/$ONEIP ; fi
		echo -n "     $HOSTNAME reachable, Live:"
		echo `pathto $ONEIP` >$PSPATH/$ONEIP-path
		for SERVICE in $CHECKSERVICES ; do
			if checkconn $ONEIP $SERVICE ; then
				echo -n " $SERVICE"
				touch $PSPATH/$ONEIP/$SERVICE
			fi
		done
		echo
	else
		if [ -f "$PSPATH/$ONEIP-path" ]; then
			LASTLIVE='' ; FIRSTDEAD=''
			for ONESTEP in `cat $PSPATH/$ONEIP-path` ; do
				if reachable $ONESTEP ; then
					LASTLIVE="$ONESTEP" ; FIRSTDEAD=''
				elif [ -z "$FIRSTDEAD" ]; then
					FIRSTDEAD="$ONESTEP"
				fi
			done
			echo "     $HOSTNAME unreachable, last reachable IP is $LASTLIVE, first dead IP is $FIRSTDEAD"
		else
			echo "     $HOSTNAME unreachable."
		fi
	fi
done

