#!/bin/bash
#################################################################
# BB script to poll a citrix cluster
# 27-08-01
# at the moment, it's nasty nasty hackery involving sending 
# binary data, through netcat, to your udp ports.
# Use at your own risk etc. etc.
#
# A Big Brother External Script
#
#################################################################
#
# Instructions: Modify the variables below to something appropriate
#		for your system.  
#
#                Add an entry for bb-citrix.sh in the EXT variable
#                STOP and START BB
#
#
#################################################################

#
# Uncomment the line below to run manually
#

#DEBUG="Y"
if test "$DEBUG" = "Y"
then
	echo "*** BEGIN: TEST ***"
	set -xv
	BBHOME=/usr/local/bigbrother/bb; export BBHOME
	GREP=/usr/bin/grep #get this from defs normally
	AWK=awk
fi

#
# INITIALIZE VARIABLES WE'LL BE NEEDING
#
TEST="icaclstr"		# THE NAME OF OUR TEST
MACHINE="citrix"	# who the test comes from
NC=$BBHOME/ext/nc
BC=/bin/bc
TIMEOUT=3		#how long to wait, in seconds for a response,
			#and after recieving a response to see if there is any
			#more data.
LIST_PORT=6666		#udp port for us to use locally
			#We send a request, from this port, and then 
			#listen on this port for responses. So pick something
			#which won't clash.
#ok this is icky, but... field 1 = test name. field 2=machine name IF IT IS
#just a SINGLE MACHINE make sure you have a comma in there. 
#field 3 = broadcast address _or_ comma separated list of servers
#field 4 = applications to test for (comma separated).
#I know this is messy, but it _does_ work. I'll update it when I'm next 
#idle enough :) Each set of tests should be ; separated.

TEST_LIST="icaclstr:citrix:159.245.55.255:Desktop,Admin;icaclstr:linc:tsl05,tsl07,tsl08,tsl09,tsl10,tsl11,tsl12,tsl13,tsl14:Asap,Archive,E-Learning,Oracle,UserManager;"

ICA_PORT=1604			#the udp port that your ICA servers are using
				#probably won't need to change this.

TMP_SVC="/tmp/citrixsvc.$$"
TMP_OUT="/tmp/citrixout.$$"

#these chars were grabbed from a packet dump of a citrix client.
#they work for me.
#there must be a better way, but there seems to be no published specs of the
#ICA protocol.

#HELO_STR is sent by the client to the broadcast address.
#the response to the broadcast (hopefully from your ICA server) will be
#sent the RESP_STR to query what services it is using.
#these were grabbed simply with a combination of ethereal and tcpdump - they're
#basically the data segements of the UDP traffic.


#these ones would seem to work for the local citrix boxen
LRESP_STR="\\x24\\x00\\x01\\x32\\x02\\xfd\\xa8\\xe3\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x21\\x00\\x02\\x00\\x00\\x00\\x00\\x00"
LHELO_STR="\\x1e\\x00\\x01\\x30\\x02\\xfd\\xa8\\xe3\\x00\\x02\\xf5\\x95\\x9f\\xf5\\x30\\x07\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x00"

#and these would be for the remote.
RHELO_STR="\\x20\\x00\\x01\\x30\\x02\\xfd\\xa8\\xe3\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00"
RRESP_STR="\\x2c\\x00\\x02\\x32\\x02\\xfd\\xa8\\xe3\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x21\\x00\\x02\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00"

#################################################################
#
#   NO CONFIGURATION BEYOND THIS POINT
#
#################################################################
PROG="bb-citrix.sh"

#
# Check that we have a basic environment setup
#
if test "X$BBHOME" = "X"
then
        echo ERROR: BBHOME variable not set
        exit 1  
#fi

#if test "X$BBTMP" = "X"			# GET DEFINITIONS IF NEEDED 
#then
	# echo "*** LOADING BBDEF ***"
	. $BBHOME/etc/bbdef.sh          # INCLUDE STANDARD DEFINITIONS
fi

#need to check if our port is free, cos otherwise no response is recieved
#even if it is all working. Sigh.

while [ -n "`netstat -a | grep "\.$LIST_PORT "`" ]
do
  LIST_PORT=`echo $LIST_PORT + 1 | $BC`
done

OLDIFS=$IFS
IFS=";"
for CLUSTER in $TEST_LIST
do
  TEST=`echo $CLUSTER | cut -d: -f1`
  MACHINE=`echo $CLUSTER | cut -d: -f2`
  TARGET=`echo $CLUSTER | cut -d: -f3`
  SVC_LIST=`echo $CLUSTER | cut -d: -f4`

  if [ -z "`echo $TARGET | $GREP ,`" ] 
  then
     # zero grep for , means only 1 target - so is a broadcast
     printf %b "$LRESP_STR" | $NC -l -v -u -p $LIST_PORT -w $TIMEOUT > $TMP_OUT 2>>$TMP_OUT&
    printf %b "$LHELO_STR" | $NC -u -w $TIMEOUT -p $LIST_PORT $TARGET $ICA_PORT

  else
  #it's a cluster. Actually, it's anything _other_ than a broadcast (so could
  #be just a standalone machine)
     OLDIFS=$IFS
     IFS=,
     for HOST in $TARGET
     do
       MASTER_BROWSER=`printf  "%b" $RHELO_STR | $NC -u -p $LIST_PORT -w $TIMEOUT $HOST $ICA_PORT | od -X | $AWK -F' ' '{print $2}' | $TAIL -2 | $HEAD -1`
       
       #if we got a response, then we know the server is up
       #and we now know which machine to ask for an app list. So we break here.
       if [ -n "$MASTER_BROWSER" ]
       then
         break;
       fi
     done 
     IFS=$OLDIFS
     #now we parse the hex browse into an IP address
     for i in `echo $MASTER_BROWSER | $SED  "s/\([0-9,a-f][0-9,a-f]\)/\1$IFS/g"`
     do
       typeset -i VAL=16#${i}
       if [ -n "$ICABROWSE" ]
       then
         ICABROWSE="$ICABROWSE.$VAL"
       else
         ICABROWSE="$VAL"
       fi
     done
     printf "%b" "$RRESP_STR" | $NC -u -p $LIST_PORT -w $TIMEOUT $ICABROWSE $ICA_PORT > $TMP_OUT

  fi # got our data now.

  echo -e "\n" >> $TMP_OUT

  if [ -s $TMP_OUT ]
  then

    $CAT $TMP_OUT | tr -d '[:cntrl:]' > $TMP_SVC
    if [ -z "$ICABROWSE" ]
    then
      ICABROWSE=`$GREP connect $TMP_SVC | $SED -e 's/.* from //g' -e  's/\].*$/]/g'`
    fi

    COLOR="green"

    if [ -n "$ICABROWSE" ]
    then
      LINE="Reponse from Master browser $ICABROWSE"
    fi

    LINE="$LINE
Citrix Published applications:"

    OLDIFS=$IFS
    IFS=,
    for SVC in $SVC_LIST
    do
      SVCHERE=`$GREP $SVC $TMP_SVC`
      if [ -n "$SVCHERE" ] 
      then
        LINE="$LINE
	$SVC is available"
      else
        LINE="$LINE
	$SVC is DOWN"
        COLOR="red"
      fi

    done
    IFS=$OLDIFS
  else
    LINE="$LINE
	The output file does not exist or is zero length.
	No response was recieved from the Citrix cluster."
    COLOR="red"
  fi
  #clean up

  # FORMAT IT PROPERLY FOR BB...
  LINE="status $MACHINE.$TEST $COLOR `date`
$LINE
"

#
# Send a status update to the Big Brother display
#

#
# Debugging
#
if test "$DEBUG" = "Y"
then
        echo "COLOR = ${COLOR}"
        echo "LINE  = ${LINE}"
        echo "*** END: TEST ***"
else
	$BB $BBDISP "$LINE"	# SEND IT TO BBDISPLAY
fi

done
IFS=$OLDIFS

$RM -f $TMP_OUT $TMP_SVC

#
# END OF bb-citrix.sh
#
