summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xcontrib/check_ica_program_neigbourhood.pl619
1 files changed, 619 insertions, 0 deletions
diff --git a/contrib/check_ica_program_neigbourhood.pl b/contrib/check_ica_program_neigbourhood.pl
new file mode 100755
index 00000000..f29c0d1d
--- /dev/null
+++ b/contrib/check_ica_program_neigbourhood.pl
@@ -0,0 +1,619 @@
1#!/usr/bin/perl -w
2
3# $Id$
4
5# $Log$
6# Revision 1.1 2005/01/25 09:05:53 stanleyhopcroft
7# New plugin to check Citrix Metaframe XP "Program Neighbourhood"
8#
9# Revision 1.1 2005-01-25 16:50:30+11 anwsmh
10# Initial revision
11#
12
13use strict ;
14
15use Getopt::Long;
16
17use utils qw($TIMEOUT %ERRORS &print_revision &support);
18use LWP 5.65 ;
19use XML::Parser ;
20
21my $PROGNAME = 'check_program_neigbourhood' ;
22my ($debug, $xml_debug, $pn_server, $pub_apps, $app_servers, $server_farm, $usage) ;
23
24Getopt::Long::Configure('bundling', 'no_ignore_case') ;
25GetOptions
26 ("V|version" => \&version,
27 "A|published_app:s" => \$pub_apps,
28 "h|help" => \&help,
29 'usage|?' => \&usage,
30 "F|server_farm=s" => \$server_farm,
31 "P|pn_server=s" => \$pn_server,
32 "S|app_server=s" => \$app_servers,
33 "v|verbose" => \$debug,
34 "x|xml_debug" => \$xml_debug,
35) ;
36
37$pn_server || do {
38 print "Name or IP Address of _one_ Program Neighbourhood server is required.\n" ;
39 &print_usage ;
40 exit $ERRORS{UNKNOWN} ;
41} ;
42
43$pub_apps ||= 'Word 2003' ;
44$pub_apps =~ s/["']//g ;
45my @pub_apps = split /,\s*/, $pub_apps ;
46
47my @app_servers = split /,\s*/, $app_servers ;
48
49@app_servers || do {
50 print "IP Address of _each_ Application server in the Metaframe Citrix XP server farm is required.\n" ;
51 &print_usage ;
52 exit $ERRORS{UNKNOWN} ;
53} ;
54
55my @non_ip_addresses = grep ! /\d+\.\d+\.\d+\.\d+/, @app_servers ;
56
57scalar(@non_ip_addresses) && do {
58 print qq(Application servers must be specified by IP Address (not name): "@non_ip_addresses".\n) ;
59 &print_usage ;
60 exit $ERRORS{UNKNOWN} ;
61} ;
62
63$server_farm || do {
64 print "Name of Citrix Metaframe XP server farm is required.\n" ;
65 &print_usage ;
66 exit $ERRORS{UNKNOWN} ;
67} ;
68
69my %xml_tag = () ;
70my @tag_stack = () ;
71
72my $xml_p = new XML::Parser(Handlers => {Start => \&handle_start,
73 End => sub { pop @tag_stack },
74 Char => \&handle_char}) ;
75
76# values required by Metaframe XP that don't appear to matter too much
77
78my $client_host = 'Nagios server (http://www.Nagios.ORG)' ;
79my $user_name = 'nagios' ;
80my $domain = 'Nagios_Uber_Alles' ;
81
82# end values required by Metaframe XP
83
84my $nilpotent_req = <<'EOR' ;
85<?xml version="1.0" encoding="ISO-8859-1"?>
86<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd"><NFuseProtocol version="1.1">
87 <RequestProtocolInfo>
88 <ServerAddress addresstype="dns-port" />
89 </RequestProtocolInfo>
90</NFuseProtocol>
91EOR
92
93my $server_farm_req = <<'EOR' ;
94<?xml version="1.0" encoding="ISO-8859-1"?>
95<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
96<NFuseProtocol version="1.1">
97 <RequestServerFarmData>
98 <Nil />
99 </RequestServerFarmData>
100</NFuseProtocol>
101EOR
102
103my $spec_server_farm_req = <<EOR ;
104<?xml version="1.0" encoding="ISO-8859-1"?>
105<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
106<NFuseProtocol version="1.1">
107 <RequestAddress>
108 <Name>
109 <UnspecifiedName>$server_farm*</UnspecifiedName>
110 </Name>
111 <ClientName>$client_host</ClientName>
112 <ClientAddress addresstype="dns-port" />
113 <ServerAddress addresstype="dns-port" />
114 <Flags />
115 <Credentials>
116 <UserName>$user_name</UserName>
117 <Domain>$domain</Domain>
118 </Credentials>
119 </RequestAddress>
120</NFuseProtocol>
121EOR
122
123my $app_req = <<EOR ;
124<?xml version="1.0" encoding="ISO-8859-1"?>
125<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
126<NFuseProtocol version="1.1">
127 <RequestAddress>
128 <Name>
129 <UnspecifiedName>PUBLISHED_APP_ENCODED</UnspecifiedName>
130 </Name>
131 <ClientName>Nagios_Service_Check</ClientName>
132 <ClientAddress addresstype="dns-port"/>
133 <ServerAddress addresstype="dns-port" />
134 <Flags />
135 <Credentials>
136 <UserName>$PROGNAME</UserName>
137 <Domain>$domain</Domain>
138 </Credentials>
139 </RequestAddress>
140</NFuseProtocol>
141EOR
142
143my $ua = LWP::UserAgent->new ;
144my $req = HTTP::Request->new('POST', "http://$pn_server/scripts/WPnBr.dll") ;
145 $req->content_type('text/xml') ;
146
147my $svr ;
148
149my @pubapp_encoded = map { my $x = $_ ; $x =~ s/(\W)/'&#' . ord($1) . ';'/eg; $x } @pub_apps ;
150
151my $error_tag_cr = sub { ! exists($xml_tag{ErrorId}) } ;
152
153my @app_reqs = (
154 # { Content => url, Ok => ok_condition, Seq => \d+ }
155
156 { Content => $nilpotent_req, Ok => $error_tag_cr, Seq => 0 },
157 { Content => $server_farm_req, Ok => sub {
158 ! exists($xml_tag{ErrorId}) &&
159 exists( $xml_tag{ServerFarmName}) &&
160 defined($xml_tag{ServerFarmName}) &&
161 $xml_tag{ServerFarmName} eq $server_farm
162 }, Seq => 2 },
163 { Content => $nilpotent_req, Ok => $error_tag_cr, Seq => 4 },
164 { Content => $spec_server_farm_req, Ok => sub {
165 ! exists($xml_tag{ErrorId}) &&
166 exists( $xml_tag{ServerAddress}) &&
167 defined($xml_tag{ServerAddress}) &&
168 $xml_tag{ServerAddress} =~ /\d+\.\d+\.\d+\.\d+:\d+/
169 }, Seq => 6 },
170 { Content => $nilpotent_req, Ok => $error_tag_cr, Seq => 8 },
171 { Content => $app_req, Ok => sub {
172 ! exists($xml_tag{ErrorId}) &&
173 exists( $xml_tag{ServerAddress}) &&
174 defined($xml_tag{ServerAddress}) &&
175 (($svr) = split(/:/, $xml_tag{ServerAddress})) &&
176 defined($svr) &&
177 scalar(grep $_ eq $svr, @app_servers)
178 }, Seq => 10 }
179) ;
180
181my $app_location ;
182
183foreach my $pub_app (@pub_apps) {
184
185 my $pubapp_enc = shift @pubapp_encoded ;
186 my $app_req_tmp = $app_reqs[5]{Content} ;
187 $app_reqs[5]{Content} =~ s/PUBLISHED_APP_ENCODED/$pubapp_enc/ ;
188
189 foreach (@app_reqs) {
190
191 $req->content($_->{Content}) ;
192
193 $debug && print STDERR "App: $pub_app Seq: $_->{Seq}\n", $req->as_string, "\n" ;
194
195 my $resp = $ua->request($req) ;
196
197 $debug && print STDERR "App: $pub_app Seq: ", $_->{Seq} + 1, "\n", $resp->as_string, "\n" ;
198
199 $resp->is_error && do {
200 my $err = $resp->as_string ;
201 $err =~ s/\n//g ;
202 &outahere(qq(Failed. HTTP error finding $pub_app at seq $_->{Seq}: "$err")) ;
203 } ;
204 my $xml = $resp->content ;
205
206 my $xml_disp ;
207 ($xml_disp = $xml) =~ s/\n//g ;
208 $xml_disp =~ s/ \s+/ /g ;
209
210 &outahere($resp->as_string)
211 unless $xml ;
212
213 my ($xml_ok, $whine) = &valid_xml($xml_p, $xml) ;
214
215 $xml_ok || &outahere(qq(Failed. Bad XML finding $pub_app at eq $_->{Seq} in "$xml_disp".)) ;
216
217 &{$_->{Ok}} || &outahere(qq(Failed. \"\&\$_->{Ok}\" false finding $pub_app at seq $_->{Seq} in "$xml_disp".)) ;
218
219 # Ugly but alternative is $_->{Ok}->().
220 # eval $_->{Ok} where $_->{Ok} is an
221 # expression returning a bool is possible. but
222 # sub { } prevent recompilation.
223
224 }
225
226 $app_reqs[5]{Content} = $app_req_tmp ;
227
228 $app_location .= qq("$pub_app" => $svr, ) ;
229
230}
231
232substr($app_location, -2, 2) = '' ;
233print qq(Ok. Citrix XML service located all published apps $app_location.\n) ;
234exit $ERRORS{'OK'} ;
235
236sub outahere {
237 print "Citrix XML service $_[0]\n" ;
238 exit $ERRORS{CRITICAL} ;
239}
240
241sub valid_xml {
242 my ($p, $input) = @_ ;
243
244 %xml_tag = () ;
245 @tag_stack = () ;
246
247 eval {
248 $p->parse($input)
249 } ;
250
251 return (0, qq(XML::Parser->parse failed: Bad XML in "$input".!))
252 if $@ ;
253
254 if ( $xml_debug ) {
255 print STDERR pack('A4 A30 A40', ' ', $_, qq(-> "$xml_tag{$_}")), "\n"
256 foreach (keys %xml_tag)
257 }
258
259 return (1, 'valid xml')
260
261}
262
263
264sub handle_start {
265 push @tag_stack, $_[1] ;
266
267 $xml_debug && print STDERR pack('A8 A30 A40', ' ', 'handle_start - tag', " -> '$_[1]'"), "\n" ;
268 $xml_debug && print STDERR pack('A8 A30 A60', ' ', 'handle_start - @tag_stack', " -> (@tag_stack)"), "\n" ;
269}
270
271sub handle_char {
272 my $text = $_[1] ;
273
274 !($text =~ /\S/ || $text =~ /^[ \t]$/) && return ;
275
276 $text =~ s/\n//g ;
277
278 my $tag = $tag_stack[-1] ;
279
280 $xml_debug && print STDERR pack('A8 A30 A30', ' ', 'handle_char - tag', " -> '$tag'"), "\n" ;
281 $xml_debug && print STDERR pack('A8 A30 A40', ' ', 'handle_char - text', " -> '$text'"), "\n" ;
282
283 $xml_tag{$tag} .= $text ;
284
285}
286
287
288sub print_help() {
289
290# 1 2 3 4 5 6 7 8
291#12345678901234567890123456789012345678901234567890123456789012345678901234567890
292
293 print_revision($PROGNAME,'$Revision$ ');
294
295my $help = <<EOHELP ;
296Copyright (c) 2004 Karl DeBisschop/S Hopcroft
297
298$PROGNAME -P <pn_server> -S <svr1,svr2,..> -A <app1,app2,..>
299 -F <Farm> [-v -x -h -V]
300
301Check the Citrix Metaframe XP service by completing an HTTP dialogue with a Program
302Neigbourhood server (pn_server) that returns an ICA server in the named Server farm
303hosting the specified applications (an ICA server in a farm which runs some MS app).
304EOHELP
305
306 print $help ;
307 print "\n";
308 print "\n";
309 print_usage();
310 print "\n";
311 support();
312}
313
314sub print_usage () {
315
316# 1 2 3 4 5 6 7 8
317#12345678901234567890123456789012345678901234567890123456789012345678901234567890
318
319my $usage = <<EOUSAGE ;
320$PROGNAME
321[-P | --pn_server] The name or address of the Citrix Metaframe XP
322 Program Neigbourhood server (required).
323[-A | --pub_apps] The name or names of an application published by the
324 server farm (default 'Word 2003').
325[-F | --server_farm] The name of a Citrix Metaframe XP server farm. (required)
326[-S | --app_servers] The _IP addresses_ of _all_ of the Farms ICA servers expected
327 to host the published application.
328 Enter as a comma separated string eg 'Srv1, Svr2, ..,Srvn'.
329 Since the PN servers round-robin the app servers to the clients,
330 _all_ the server farm addresses must be specified or the check
331 will fail (required).
332[-v | --verbose]
333[-h | --help]
334[-x | --xml_debug]
335[-V | --version]
336EOUSAGE
337
338 print $usage ;
339
340}
341
342sub usage {
343 &print_usage ;
344 exit $ERRORS{'OK'} ;
345}
346
347sub version () {
348 print_revision($PROGNAME,'$Revision$ ');
349 exit $ERRORS{'OK'};
350}
351
352sub help () {
353 print_help();
354 exit $ERRORS{'OK'};
355}
356
357=begin comment
358
359This is the set of requests and responses transmitted between a Citrix Metaframe XP Program Neigbourhood (PN) client and a PN server.
360
361This dialogue was captured by and reconstructed from tcpdump.
362
363Citrix are not well known for documenting their protocols although the DTD may be informative. Note that the pair(s) 0 and 1, 4 and 5, ...
364do not appear to do anything.
365
366req 0
367POST /scripts/WPnBr.dll HTTP/1.1
368Content-type: text/xml
369Host: 10.1.2.2:80
370Content-Length: 220
371Connection: Keep-Alive
372
373
374<?xml version="1.0" encoding="ISO-8859-1"?>
375<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
376<NFuseProtocol version="1.1"><RequestProtocolInfo><ServerAddress addresstype="dns-port" /></RequestProtocolInfo></NFuseProtocol>
377
378HTTP/1.1 100 Continue
379Server: Citrix Web PN Server
380Date: Thu, 30 Sep 2004 00:12:40 GMT
381
382
383resp 1
384HTTP/1.1 200 OK
385Server: Citrix Web PN Server
386Date: Thu, 30 Sep 2004 00:12:40 GMT
387Content-type: text/xml
388Content-length: 253
389
390
391<?xml version="1.0" encoding="ISO-8859-1" ?>
392<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
393<NFuseProtocol version="1.1">
394 <ResponseProtocolInfo>
395 <ServerAddress addresstype="no-change"></ServerAddress>
396 </ResponseProtocolInfo>
397</NFuseProtocol>
398
399req 2
400POST /scripts/WPnBr.dll HTTP/1.1
401Content-type: text/xml
402Host: 10.1.2.2:80
403Content-Length: 191
404Connection: Keep-Alive
405
406
407<?xml version="1.0" encoding="ISO-8859-1"?>
408<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
409<NFuseProtocol version="1.1"><RequestServerFarmData><Nil /></RequestServerFarmData></NFuseProtocol>
410
411HTTP/1.1 100 Continue
412Server: Citrix Web PN Server
413Date: Thu, 30 Sep 2004 00:12:40 GMT
414
415
416resp 3
417HTTP/1.1 200 OK
418Server: Citrix Web PN Server
419Date: Thu, 30 Sep 2004 00:12:40 GMT
420Content-type: text/xml
421Content-length: 293
422
423
424<?xml version="1.0" encoding="ISO-8859-1" ?>
425<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
426<NFuseProtocol version="1.1">
427 <ResponseServerFarmData>
428 <ServerFarmData>
429 <ServerFarmName>FOOFARM01</ServerFarmName>
430 </ServerFarmData>
431 </ResponseServerFarmData>
432</NFuseProtocol>
433
434req 4
435POST /scripts/WPnBr.dll HTTP/1.1
436Content-type: text/xml
437Host: 10.1.2.2:80
438Content-Length: 220
439Connection: Keep-Alive
440
441
442<?xml version="1.0" encoding="ISO-8859-1"?>
443<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
444<NFuseProtocol version="1.1"><RequestProtocolInfo><ServerAddress addresstype="dns-port" /></RequestProtocolInfo></NFuseProtocol>
445
446HTTP/1.1 100 Continue
447Server: Citrix Web PN Server
448Date: Thu, 30 Sep 2004 00:12:55 GMT
449
450
451resp 5
452HTTP/1.1 200 OK
453Server: Citrix Web PN Server
454Date: Thu, 30 Sep 2004 00:12:55 GMT
455Content-type: text/xml
456Content-length: 253
457
458
459<?xml version="1.0" encoding="ISO-8859-1" ?>
460<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
461<NFuseProtocol version="1.1">
462 <ResponseProtocolInfo>
463 <ServerAddress addresstype="no-change"></ServerAddress>
464 </ResponseProtocolInfo>
465</NFuseProtocol>
466
467req 6
468POST /scripts/WPnBr.dll HTTP/1.1
469Content-type: text/xml
470Host: 10.1.2.2:80
471Content-Length: 442
472Connection: Keep-Alive
473
474
475<?xml version="1.0" encoding="ISO-8859-1"?>
476<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
477<NFuseProtocol version="1.1">
478<RequestAddress><Name>i
479 <UnspecifiedName>FOOFARM01*</UnspecifiedName>
480 </Name><ClientName>WS09535</ClientName>
481 <ClientAddress addresstype="dns-port" />
482 <ServerAddress addresstype="dns-port" />
483 <Flags />
484 <Credentials>
485 <UserName>foo-user</UserName>
486 <Domain>some-domain</Domain>
487 </Credentials>
488</RequestAddress></NFuseProtocol>
489
490HTTP/1.1 100 Continue
491Server: Citrix Web PN Server
492Date: Thu, 30 Sep 2004 00:12:56 GMT
493
494
495resp 7
496HTTP/1.1 200 OK
497Server: Citrix Web PN Server
498Date: Thu, 30 Sep 2004 00:12:56 GMT
499Content-type: text/xml
500Content-length: 507
501
502
503<?xml version="1.0" encoding="ISO-8859-1" ?>
504<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
505<NFuseProtocol version="1.1">
506 <ResponseAddress>
507 <ServerAddress addresstype="dot-port">10.1.2.2:1494</ServerAddress>
508 <ServerType>win32</ServerType>
509 <ConnectionType>tcp</ConnectionType>
510 <ClientType>ica30</ClientType>
511 <TicketTag>10.1.2.2</TicketTag>
512 <SSLRelayAddress addresstype="dns-port">ica_svr01.some.domain:443</SSLRelayAddress>
513 </ResponseAddress>
514</NFuseProtocol>
515
516req 8
517POST /scripts/WPnBr.dll HTTP/1.1
518Content-type: text/xml
519Host: 10.1.2.2:80
520Content-Length: 220
521Connection: Keep-Alive
522
523
524<?xml version="1.0" encoding="ISO-8859-1"?>
525<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
526<NFuseProtocol version="1.1"><RequestProtocolInfo><ServerAddress addresstype="dns-port" /></RequestProtocolInfo></NFuseProtocol>
527
528HTTP/1.1 100 Continue
529Server: Citrix Web PN Server
530Date: Thu, 30 Sep 2004 00:13:29 GMT
531
532
533resp 9
534HTTP/1.1 200 OK
535Server: Citrix Web PN Server
536Date: Thu, 30 Sep 2004 00:13:29 GMT
537Content-type: text/xml
538Content-length: 253
539
540
541<?xml version="1.0" encoding="ISO-8859-1" ?>
542<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
543<NFuseProtocol version="1.1">
544 <ResponseProtocolInfo>
545 <ServerAddress addresstype="no-change"></ServerAddress>
546 </ResponseProtocolInfo>
547</NFuseProtocol>
548
549req 10
550POST /scripts/WPnBr.dll HTTP/1.1
551Content-type: text/xml
552Host: 10.1.2.2:80
553Content-Length: 446
554Connection: Keep-Alive
555
556
557<?xml version="1.0" encoding="ISO-8859-1"?>
558<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
559<NFuseProtocol version="1.1">
560<RequestAddress>i
561 <Name>
562 <UnspecifiedName>EXCEL#32;2003</UnspecifiedName>
563 </Name>
564 <ClientName>WS09535</ClientName>
565 <ClientAddress addresstype="dns-port" />
566 <ServerAddress addresstype="dns-port" />
567 <Flags />
568 <Credentials><UserName>foo-user</UserName>
569 <Domain>some-domain</Domain>
570 </Credentials>
571</RequestAddress>i
572</NFuseProtocol>
573
574HTTP/1.1 100 Continue
575Server: Citrix Web PN Server
576Date: Thu, 30 Sep 2004 00:13:29 GMT
577
578
579resp 11
580HTTP/1.1 200 OK
581Server: Citrix Web PN Server
582Date: Thu, 30 Sep 2004 00:13:29 GMT
583Content-type: text/xml
584Content-length: 509
585
586
587<?xml version="1.0" encoding="ISO-8859-1" ?>
588<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
589<NFuseProtocol version="1.1">
590 <ResponseAddress>
591 <ServerAddress addresstype="dot-port">10.1.2.14:1494</ServerAddress>
592 <ServerType>win32</ServerType>
593 <ConnectionType>tcp</ConnectionType>
594 <ClientType>ica30</ClientType>
595 <TicketTag>10.1.2.14</TicketTag>
596 <SSLRelayAddress addresstype="dns-port">ica_svr02.some.domain:443</SSLRelayAddress>
597 </ResponseAddress>
598</NFuseProtocol>
599
600** One sees this XML on an error (there may well be other error XML also, but I haven't seen it) **
601
602<?xml version="1.0" encoding="ISO-8859-1" ?>
603<!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd">
604<NFuseProtocol version="1.1">
605 <ResponseAddress>
606 <ErrorId>unspecified</ErrorId>
607 <BrowserError>0x0000000E</BrowserError>
608 </ResponseAddress>
609</NFuseProtocol>
610
611
612=end comment
613
614=cut
615
616
617# You never know when you may be embedded ...
618
619