Re: [Nagios-users] Citrix Plugin
"Tom DE BLENDE" <[email protected]>
| Newsgroups | gmane.network.netsaint.user,gmane.network.nagios.user |
|---|---|
| Organization | DHL GCC |
| Message-ID | <[email protected]> |
Grae Noble wrote: > > Theres some interesting plugins for BigBrother that could be modified to work with netsaint. I've modified a few but most require extensive changes to work. > > http://www.deadcat.net > > >From memory there is one there for citrix. (quite neat too, it will check for the existence of a specific application ). OK. I've grabbed the Big Brother Citrix plugin from Ed Rolison (http://www.deadcat.net/cgi-bin/download.pl?section=1&file=bb-citrix.pl). He managed to write it with the help of tcpdump. I personally think this is very cool and a job well done. Thanks Ed. However, the output that NetSaint expects is totally different from the output BB wants. So I've changed parts of the code so it works with NetSaint. I then tested it in our environment, and it works OK. This plugin does not take any command line arguments. Just adjust the beginning of the script so it reflects your setup. If you use a farm, then you can use the broadcast address (that's how I use it), otherwise add the server address(es) you want to check. Good luck, Tom De Blende So here it is: ******************************************************************************************************************************************** #!/usr/bin/perl -w # Ed Rolison 15/06/02 # [email protected] # If it doesn't work, please let me know, I've only had access to my environment # so I'm not 100% sure. # # No liability accepted for problems, mistakes, inaccuracies or nuclear war. # # If you want to mess around with this script, then please feel free to do so. # however, if you add anything 'funky' then I'd really appreciate hearing about it. # # Oh, and if you do ever make huge amounts of money out of it, cut me in :) # version 1.5 ish # # Revision history: # version 1.0 ish. Shell script which used netcat # version 1.1 ish. extended script to use a non-broadcast method of querying # version 1.3 re-written in perl # version 1.4 updated perl for 'yellow' and 'red' apps + some minor fixes. # version 1.5 ish added support for 'long' published apps lists. # Changed plugin output so it works with NetSaint. # Tom De Blende 16/09/02 # [email protected] use IO::Socket::INET; use IO::Select; use FileHandle; #configuration section my $debug = 0; my $timeout = 1; my $test_count = 2; #You might have to change this... my $date = `date +%s`; my $buffer_size = 1500; # buffer size used for 'recv' calls. #a word of warning - at the moment these test _will_ match substrings #of the applications. So if you have something like 'Desktop' and 'DesktopFull' #Desktop will match on either. I'll probably fix this in a later version. #a 'single' target will be assumed to be a broadcast address for a cluster. #that's probably not right, but I've got a local subnet cluster, and #a remote cluster that I can't broadcast to. So this works well enough. #feel free to hack in support for discriminating between broadcast/standalone though.... my (%tests) = ( 'netsaint' => #this is the name of the 'machine that this test appears to #be from in the bb display { testname => 'icaclstr', #hopefully fairly obvious - which column in BB target => [ "172.16.200.255" ], #either a list of servers, or a broadcast address red_published_apps => # apps which trigger a 'CRITICAL' when down [ "Critical1", "Critical2", "Critical With Spaces 3" ], yellow_published_apps => #apps which trigger a 'WARNING' when down. [ "Warning1", "Not So Critical", "Warning App 3" ], longlist => 0, # this is for if you have many published applications. # if you set it, it won't do any harm, but may slow the test # down a little. (Since it does a 'recv' twice instead of # once and therefore may have to wait for a timeout). }, # 'othersite' => # { # testname => 'icaclstr', # target => # [ "server1","server2","server3","server4","server5"], # red_published_apps => # [ "Critical 4" ], # yellow_published_apps => [ "Critical 5" ], # longlist => 1 # }, ); #End user config. #ica port number. my $ica_port = 1604; #what port ICA runs on. Unlikely to change. #definitions of query strings. Change at your own risk :) #this info was gathered with tcpdump whilst trying to use an ICA client, #so I'm not 100% sure of what each value is. my $app_response_offset = 0x28; my @bcast_helo = ( 0x1e,0x00,0x01,0x30,0x02,0xfd,0xa8,0xe3,0x00,0x02,0xf5,0x95,0x9f,0xf5,0x30,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00 ); my @bcast_query_app = ( 0x24,0x00,0x01,0x32,0x02,0xfd,0xa8,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x02,0x00,0x00,0x00,0x00,0x00, 0x00 ); my @direct_helo = ( 0x20,0x00,0x01,0x30,0x02,0xfd,0xa8,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ); my @direct_query_app = ( 0x2c,0x00,0x02,0x32,0x02,0xfd,0xa8,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ); if ( $debug == 1 ) { print "*** Running in test mode\n"; } #we open 2 UDP ports - one to send the 'search' and the other to query the app list. my $UDP_HELO = IO::Socket::INET -> new ( Proto => "udp" ) || die "Socket failure: $!"; my $UDP_QUERY = IO::Socket::INET -> new ( Proto => "udp" ) || die "Socket failure: $!"; #select is here to allow us to set timeouts on the connections. Otherwise they #just 'stop' until a server appears. my $select_helo = IO::Select -> new ($UDP_HELO) || die "Select failure: $!"; my $select_query = IO::Select -> new ($UDP_QUERY) || die "Select failure: $!"; my $send_addr ; #helo needs to be broadcast, but query does not. $UDP_HELO -> sockopt(SO_BROADCAST, 1 ); #autoflush both. $UDP_HELO -> autoflush(1); $UDP_QUERY -> autoflush(1); my ( $remote_host, $buff, $buff2, $raddr, $rport, $rhost, @remote_response ); #right, run through the %tests hash above, and test each of the machines listed. foreach my $test_target ( keys ( %tests ) ) { $color = "clear"; $line2 = ""; if ( $debug ) { print "testing $test_target\n" }; $buff = ""; $buff2 = ""; my $this_test = 0; #If the first test fails, (as it sometimes does, UDP being unreliable) #then it'll retry up to $test_count times (see at the top). while ( $this_test <= $test_count && !$buff ) { if ( $debug ) { print "Running test: ", ++$this_test,"\n" }; #if we have multiple targets, we probe each of them until we get a #response... foreach my $destination ( @ { $tests{$test_target}{target} } ) { my @query_message = @bcast_helo; #if we haven't got a response yet, try this one. if ( !$buff ) { if ( $debug ) { print "Querying $destination for master browser\n"; } $send_addr = sockaddr_in("$ica_port", inet_aton("$destination") ); if ( $#{ $tests{$test_target}{target} } > 1) { @query_message = @direct_helo; } $UDP_HELO -> send ( pack ("C"x $#query_message, @query_message), 0, $send_addr ); if ( $select_helo -> can_read($timeout) ) { $remote_host = $UDP_HELO -> recv($buff, $buffer_size, 0 ); } } # if (!$buff) } #foreach destination } # if test count loop #ok we've looped several times, looking for a response. If we don't have one #yet, we simply mark the whole lot as being unavailable. if ( $buff ) { ($rport, $raddr) = sockaddr_in ( $remote_host ); $rhost = gethostbyaddr ( $raddr, AF_INET ); my @tmpbuf = unpack ("C" x length($buff), $buff ); if ( $debug ) { print "$rhost:$rport responded with: ",length($buff), " bytes\n"; foreach (@tmpbuf) { printf ("%02X ", $_ ); } print "\n"; } #if debug #now we have a response, then we need to figure out the master browser, and #query it for published applications... $master_browser = "$tmpbuf[32].$tmpbuf[33].$tmpbuf[34].$tmpbuf[35]"; #ok should probably error check this, because it's remotely possible #that a server response might be completely wrong... $color="green"; if ( $debug ) { print "Master browser = $master_browser\n" } ; $send_addr = sockaddr_in($ica_port, inet_aton("$master_browser") ); if ( $#{ $tests{$test_target}{target} } > 1) { if ( $debug ) { print "using directed query\n" }; @query_message = @direct_query_app; } else { if ( $debug ) { print "using broadcast query\n" }; @query_message = @bcast_query_app; } #now we send the appropriate query string, to the master browser we've found. $buff = ""; while ( $this_test <= $test_count && !$buff ) { $UDP_QUERY -> send ( pack ("C"x $#query_message, @query_message), 0, $send_addr ); if ( $select_query -> can_read($timeout) ) { $remote_host = $UDP_QUERY -> recv($buff, $buffer_size, 0 ); } #this is icky, because i _most_ situations, there isn't going to be #any more data... but we have a server with a LONG published apps list #which takes two packets to deliver. Good eh? if ( $tests{$test_target}{longlist} && $select_query -> can_read($timeout) ) { $UDP_QUERY -> recv($buff2, $buffer_size, 0 ); if ( $buff2 ) { $buff = join ("", $buff, $buff2); } } } #while test_count if ($buff) #eg if we got a response from a couple of retries of the app query { ($rport, $raddr) = sockaddr_in ( $remote_host ); $rhost = gethostbyaddr ( $raddr, AF_INET ); @tmpbuf = unpack ("C" x length($buff), $buff ); if ( $debug ) { print "$rhost:$rport responded to app query with: ",length($buff), " bytes\n"; foreach (@tmpbuf) { printf ("%02X ",$_ ); } print "\n"; } #debug #now we strip out the icky null chars. This is what makes the pattern #matching on the app list less selective. The problem is that some #serves return an app list in ASCII, and others return it in unicode... #stripping the nulls is the easiest way of converting it to a common format. my @newbuf; foreach my $value (@tmpbuf) { if ( $value > 31 ) { push(@newbuf, $value); } } #now after trashing the nulls, we need to append one as a string terminator. push(@newbuf, 0 ); @tmpbuf=@newbuf; my $app_list = join("", pack("C" x $#tmpbuf, @tmpbuf ) ); if ( $debug ) { print "Recieved list of applications: $app_list\n" }; $line2 = ""; #yellow first, so a red overrides it... foreach $app (@{$tests{$test_target}{yellow_published_apps}} ) { my $app_test = $app_list; if ( $app_test =~ /$app/ ) { $line2 = join ( "", $line2 ); } else { $line2 = join ( " -", $line2, " $app" ); $color = "yellow"; } } #foreach foreach $app (@{$tests{$test_target}{red_published_apps}} ) { my $app_test = $app_list; if ( $app_test =~ /$app/ ) { $line2 = join ( "", $line2 ); } else { $line2 = join ( " -", $line2, " $app" ); $color = "red"; } } #foreach sleep $timeout; #because otherwise we can get responses from the WRONG servers. DOH } # if ( !$buff) else { $color = "red"; $line2 = "CRITICAL - No response from master browser."; print "$line2"; exit 2; } } #if !$buff - so we skip this chunk if there was no response from any of our master browsers, since #there's not point trying to get an app list... else { $color = "red"; $line2 = "CRITICAL - No response recieved to discovery messages.\n"; print "$line2"; exit 2; } if ( $color eq 'green' ) { $line = "OK - All published applications are available.\n"; print "$line"; $exitvalue = "0"; } elsif( $color eq 'yellow' ) { $line = "WARNING$line2 unavailable!\n"; print "$line"; $exitvalue = "1"; } else { $line = "CRITICAL$line2 unavailable!\n"; print "$line"; $exitvalue = "2"; } } #foreach close $UDP_QUERY; close $UDP_HELO; exit $exitvalue ******************************************************************************************************************************************** ------------------------------------------------------- Sponsored by: AMD - Your access to the experts on Hammer Technology! Open Source & Linux Developers, register now for the AMD Developer Symposium. Code: EX8664 http://www.developwithamd.com/developerlab