summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/check_ica_master_browser.pl229
1 files changed, 229 insertions, 0 deletions
diff --git a/contrib/check_ica_master_browser.pl b/contrib/check_ica_master_browser.pl
new file mode 100755
index 00000000..1bbab60b
--- /dev/null
+++ b/contrib/check_ica_master_browser.pl
@@ -0,0 +1,229 @@
1#!/usr/bin/perl -w
2
3# $Id$
4
5# $Log$
6# Revision 1.1 2005/01/25 09:09:33 stanleyhopcroft
7# New plugin - checks that ICA master browser is what it should be (important for firewalled dialup)
8#
9
10use strict ;
11
12use IO::Socket;
13use IO::Select;
14use Getopt::Long ;
15
16use lib qw(/usr/local/nagios/libexec) ;
17use utils qw(%ERRORS &print_revision &support &usage);
18use packet_utils qw(&pdump &tethereal) ;
19
20my $PROGNAME = 'check_ica_master_browser' ;
21
22# You might have to change this...
23
24my $PACKET_TIMEOUT = 1;
25 # Number of seconds to wait for further UDP packets
26my $TEST_COUNT = 2;
27 # Number of datagrams sent without reply
28my $BUFFER_SIZE = 1500;
29 # buffer size used for 'recv' calls.
30my $ICA_PORT = 1604;
31 # what port ICA runs on. Unlikely to change.
32
33# End user config.
34
35my ($debug, $preferred_master, $bcast_addr, $ica_browser, $timeout) ;
36
37Getopt::Long::Configure('bundling', 'no_ignore_case');
38GetOptions
39 ("V|version" => \&version,
40 "h|help" => \&help,
41 "v|verbose" => \$debug,
42 "B|broadcast_addr:s" => \$bcast_addr,
43 "I|ica_browser:s" => \$ica_browser,
44 "P|preferred_master:s" => \$preferred_master,
45 "T|Packet_timeout:i" => \$timeout,
46) ;
47
48
49my $broadcast_addr = $1 if $bcast_addr and $bcast_addr =~ m#(\d+\.\d+\.\d+\.\d+)# ;
50usage("Invalid broadcast address: $bcast_addr")
51 if $bcast_addr and not defined($broadcast_addr) ;
52
53usage("You must provide either the name of an ICA browser or the broadcast address of the subnet containing them\n")
54 unless ($ica_browser or $broadcast_addr) ;
55
56usage("You must provide the name or address of a preferred ICA master browser\n")
57 unless ($preferred_master) ;
58
59my $preferred_master_n = $preferred_master =~ m#(\d+\.\d+\.\d+\.\d+)#
60 ? $preferred_master
61 : inet_ntoa(scalar gethostbyname($preferred_master)) ;
62
63my $Timeout = $timeout || $PACKET_TIMEOUT ;
64
65 # Definitions of query strings. Change at your own risk :)
66 # this info was gathered with tcpdump whilst trying to use an ICA client,
67 # so I'm not 100% sure of what each value is.
68
69my $bcast_helo = &tethereal(<<'End_of_Tethereal_trace', '1e') ;
700020 ff ff 04 d6 06 44 00 26 4a 76 1e 00 01 30 02 fd .....D.&Jv...0..
710030 a8 e3 00 02 f5 95 9f f5 30 07 00 00 00 00 00 00 ........0.......
720040 00 00 00 00 00 00 01 00 ........
73End_of_Tethereal_trace
74
75my $direct_helo = &tethereal(<<'End_of_Tethereal_trace', '20') ;
760020 64 17 05 0f 06 44 00 28 ab b5 20 00 01 30 02 fd d....D.(.. ..0..
770030 a8 e3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
780040 00 00 00 00 00 00 00 00 00 00 ........
79End_of_Tethereal_trace
80
81my $Udp = IO::Socket::INET->new( Proto => 'udp' )
82 || die "Socket failure: $!";
83
84 # select is here to allow us to set timeouts on the connections. Otherwise they
85 # just 'stop' until a server appears.
86
87my $select = IO::Select->new($Udp)
88 || die "Select failure: $!";
89
90$Udp->sockopt(SO_BROADCAST, 1 );
91
92my ($remote_host, $buff, $destination, $raddr, $rport, $rhost, @remote_response);
93my ($query_message, $send_addr, $this_test) ;
94
95$buff = '';
96$this_test = 0;
97
98 # If there is no response to the first helo packet it will be resent
99 # up to $TEST_COUNT (see at the top).
100
101$query_message = $broadcast_addr ? $bcast_helo : $direct_helo ;
102$destination = $broadcast_addr ? $broadcast_addr: $ica_browser ;
103$send_addr = sockaddr_in($ICA_PORT, inet_aton($destination) ) ;
104
105while ( ++$this_test <= $TEST_COUNT && !$buff ) {
106
107 print "Sending helo datagram. datagram number: ", $this_test, "\n"
108 if $debug ;
109
110 print "Querying $destination for master browser\n"
111 if $debug ;
112 &pdump($query_message)
113 if $debug ;
114 $Udp->send($query_message, 0, $send_addr );
115 if ( $select->can_read($Timeout) ) {
116 $remote_host = $Udp->recv($buff, $BUFFER_SIZE, 0 );
117 }
118
119 last
120 if $buff ;
121 sleep 1 ;
122
123}
124
125 # Ok we've looped several times, looking for a response. If we don't have one
126 # yet, we simply mark the whole lot as being unavailable.
127
128unless ( $buff ) {
129 print "Failed. No response to helo datagram (master browser query) from $destination.\n" ;
130 exit $ERRORS{CRITICAL} ;
131}
132
133($rport, $raddr) = sockaddr_in( $remote_host );
134$rhost = gethostbyaddr( $raddr, AF_INET );
135my @tmpbuf = unpack('C*', $buff );
136if ( $debug ) {
137 print "$rhost:$rport responded with: ",length($buff), " bytes\n";
138 &pdump($buff) ;
139}
140
141 # Now we have a response, then we need to figure out the master browser, and
142 # query it for published applications...
143
144my $master_browser = join '.', @tmpbuf[32..35] ;
145my ($master_browser_a) = gethostbyaddr(inet_aton($master_browser), AF_INET) =~ /^(\w+?)\./ ;
146
147 # Ok should probably error check this, because it's remotely possible
148 # that a server response might be completely wrong...
149
150print "Master browser = $master_browser_a/$master_browser\n"
151 if $debug ;
152
153$send_addr = sockaddr_in($ICA_PORT, inet_aton($master_browser));
154
155my $subject_clause = $bcast_addr ? "of the \"$destination\" subnet" : "known to ICA server \"$destination\"" ;
156
157if ( $master_browser eq $preferred_master_n ) {
158 print "Preferred master browser \"$preferred_master\" __is__ the master browser (\"$master_browser_a/$master_browser\") $subject_clause.\n" ;
159 exit $ERRORS{OK} ;
160} else {
161 print "\"\u$preferred_master\" is __not__ the master browser (\"$master_browser_a/$master_browser\") $subject_clause: remote clients (dialup) may not find Published applications from Master Browser.\n" ;
162 exit $ERRORS{CRITICAL} ;
163}
164
165close $Udp;
166
167
168sub print_usage () {
169 print "Usage: $PROGNAME (-B <broadcast_address>| -I <citrix_server>) - P <preferred_master_browser>" ;
170}
171
172sub print_help () {
173 print_revision($PROGNAME,'$Revision$ ');
174 print "Copyright (c) 2002 Ed Rolison/Tom De Blende/S Hopcroft
175
176Perl Check Citrix Master Browser plugin for Nagios.
177
178Returns OK if the Citrix master browser is that given by the -P option.
179
180The plugin works by
181 If the -B option is specified, sends a broadcast helo to find the address of the Citrix master browser in the specified subnet.
182 return critical if there is no reply;
183 Else if the -I option is specified
184 send a direct helo to the specified server until there is a response (containing the address of the Citrix master browser)
185
186
187 return Critical if the response does not contain the address of the 'preferred master browser' (-P option).
188 return OK
189
190 How ICA Clients Use the Master ICA Browser.
191
192Citrix ICA Clients must locate the master browser to get the address of a server or published application.
193
194The Citrix ICA Client can locate the master browser by sending out broadcast packets, or,
195if the address of a Citrix server is specified in the Citrix ICA Client or in an ICA file,
196the ICA Client locates the master browser by sending directed packets to the specified address.
197The ICA Client requests the address of the ICA master browser from the Citrix server.
198
199";
200 print_usage();
201 print '
202-B, --broadcast_address:STRING
203 The broadcast address that should contain Citrix master browser. This option takes precedence over -I.
204-I, --ica_browser:STRING
205 Optional name or address of an ICA server that could be the master browser (used when broadcast not possible).
206-P, --preferred_master:STRING
207 Name or address of the ICA server that _should_ be the master browser.
208 Required.
209-T, --packet-timeout:INTEGER
210 Time to wait for UDP packets (default 1 sec).
211-v, --verbose
212 Debugging output.
213-h, --help
214 This stuff.
215
216';
217 support();
218}
219
220sub version () {
221 print_revision($PROGNAME,'$Revision$ ');
222 exit $ERRORS{'OK'};
223}
224
225sub help () {
226 print_help();
227 exit $ERRORS{'OK'};
228}
229