ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/host/ihost-perl/ihost.pl
Revision: 1.37
Committed: Mon Nov 19 14:15:14 2001 UTC (23 years ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.36: +18 -12 lines
Log Message:
Feature fullfilling some of the following tracker ID on sourceforge:
  [ #479690 ] make ihost/statgrab more modular

This commit adds support for a plugins directory. Any executable file in
the directory will be run, making it easier to add more input sources. The
next stage will be to move statgrab.pl into the plugins, either in whole
or in smaller chunks.

Note: is this a possibly security issue? Running all scripts found in a
directory might be a bad idea... but assuming the directory is set up ok,
I guess it ill be ok.

File Contents

# Content
1 #!/usr/bin/perl -w
2
3 # -----------------------------------------------------------
4 # Perl i-scream Host.
5 # http://www.i-scream.org.uk
6 #
7 # An all-in-one script to act as an i-scream host on
8 # a typical Unix/Linux box.
9 #
10 # $Author: tdb1 $
11 # $Id: ihost.pl,v 1.36 2001/11/14 16:41:30 tdb1 Exp $
12 #------------------------------------------------------------
13
14 $| = 1;
15
16 use strict;
17 use IO::Socket;
18 use Sys::Hostname;
19
20 use vars qw (
21 $filter_manager_addr
22 $filter_manager_port
23 $seq_no
24 $udp_update_time
25 $tcp_update_time
26 $last_udp_time
27 $last_tcp_time
28 $last_modified
29 $udp_port
30 $tcp_port
31 $filter_addr
32 $file_list
33 $fqdn
34 $pidfile
35 $retry_wait
36 @data
37 );
38
39 if (@ARGV != 2) {
40 die "Usage: ihost.pl [i-scream filter manager] [TCP port]\n";
41 }
42
43 $filter_manager_addr = $ARGV[0];
44 $filter_manager_port = $ARGV[1];
45
46 $seq_no = 1;
47 $retry_wait = 60;
48
49 # write our PID to a file
50 $pidfile = "/var/tmp/ihost.pid";
51 &write_pid();
52
53 &tcp_configure();
54 &send_udp_packet();
55
56 $last_udp_time = time;
57 $last_tcp_time = time;
58 while (1) {
59 my($time) = time;
60 if ($time >= $last_udp_time + $udp_update_time) {
61 &send_udp_packet();
62 $last_udp_time = $time;
63 }
64 if ($time >= $last_tcp_time + $tcp_update_time) {
65 &send_tcp_heartbeat();
66 $last_tcp_time = $time;
67 }
68 my($next_udp) = $udp_update_time - $time + $last_udp_time;
69 my($next_tcp) = $tcp_update_time - $time + $last_tcp_time;
70 my($delay);
71 if ($next_udp < $next_tcp) {
72 $delay = $next_udp
73 }
74 else {
75 $delay = $next_tcp;
76 }
77 sleep $delay;
78 }
79
80 # we'll probably never get here...
81 `rm -f $pidfile`;
82 exit(0);
83
84
85 #-----------------------------------------------------------------------
86 # wait_then_retry
87 # Waits for the period of time specified in $retry_wait, then attempts
88 # to reconfigure with the server.
89 #-----------------------------------------------------------------------
90 sub wait_then_retry() {
91 print "Will retry configuration with filter manager in $retry_wait seconds.\n";
92 sleep $retry_wait;
93 }
94
95
96 #-----------------------------------------------------------------------
97 # tcp_configure
98 # Establishes a TCP connection to the specified i-scream filter manager.
99 # The host then requests details from the server, such as the intervals
100 # at which to send UDP packets.
101 #-----------------------------------------------------------------------
102 sub tcp_configure() {
103
104 while (1) {
105 my($sock) = new IO::Socket::INET(
106 PeerAddr => $filter_manager_addr,
107 PeerPort => $filter_manager_port,
108 Proto => 'tcp'
109 ) or die "Cannot connect!";
110 if (!defined $sock) {
111 print "IHOST ERROR: Could not connect to $filter_manager_addr:$filter_manager_port.\n";
112 print "Please check that there is an i-scream server at this address.\n";
113 wait_then_retry();
114 next;
115 }
116
117 # Now run through the configuration process...
118 my($response);
119
120 print $sock "STARTCONFIG\n";
121 $response = <$sock>;
122 if ($response && !($response eq "OK\n")) {
123 print "The i-scream server rejected the STARTCONFIG command.\n";
124 close($sock);
125 wait_then_retry();
126 next;
127 }
128
129 print "Config started okay.\n";
130
131 print $sock "LASTMODIFIED\n";
132 $response = <$sock>;
133 if (!$response) {
134 print "The i-scream server did not return anything for the LASTMODIFIED command.\n";
135 close($sock);
136 wait_then_retry();
137 next;
138 }
139 chop $response;
140 $last_modified = $response;
141
142 print "Config last modified: ". (scalar localtime $last_modified/1000) . "\n";
143
144 print $sock "FILELIST\n";
145 $response = <$sock>;
146 if (!$response) {
147 print "The i-scream server did not provide a configuration file list.\n";
148 close($sock);
149 wait_then_retry();
150 next;
151 }
152 chop $response;
153 $file_list = $response;
154
155 print "File list obtained: $file_list\n";
156
157 print $sock "FQDN\n";
158 $response = <$sock>;
159 if (!$response) {
160 print "The i-scream server did not tell us our FQDN.\n";
161 close($sock);
162 wait_then_retry();
163 next;
164 }
165 chop $response;
166 $fqdn = $response;
167
168 print "FQDN returned: $fqdn\n";
169
170 print $sock "UDPUpdateTime\n";
171 $response = <$sock>;
172 if (!$response) {
173 print "The i-scream server did not give us a UDPUpdateTime.\n";
174 close($sock);
175 wait_then_retry();
176 next;
177 }
178 chop $response;
179 $udp_update_time = $response;
180
181 print $sock "TCPUpdateTime\n";
182 $response = <$sock>;
183 if (!$response) {
184 print "The i-scream server did not give us a TCPUpdateTime.\n";
185 close($sock);
186 wait_then_retry();
187 next;
188 }
189 chop $response;
190 $tcp_update_time = $response;
191
192 print "UDP packet period: $udp_update_time seconds.\nTCP heartbeat period: $tcp_update_time seconds.\n";
193
194 print $sock "ENDCONFIG\n";
195 $response = <$sock>;
196 if ($response && !($response eq "OK\n")) {
197 print "ENDCONFIG command to server failed. Terminated.\n";
198 close($sock);
199 wait_then_retry();
200 next;
201 }
202
203 print "Config ended.\n";
204
205 print $sock "FILTER\n";
206 $response = <$sock>;
207 if (!$response) {
208 print "Failed: Could not get a filter address from the filter manager.\n";
209 close($sock);
210 wait_then_retry();
211 next;
212 }
213 chop $response;
214 $response =~ /^(.*);(.*);(.*)/;
215 if ($response eq "ERROR") {
216 print "There are no active configured filters for your host.\n";
217 close($sock);
218 wait_then_retry();
219 next;
220 }
221 ($filter_addr, $udp_port, $tcp_port) = ($1, $2, $3);
222 unless (defined($filter_addr) && defined($udp_port) && defined($tcp_port)) {
223 print "Failed: Filter address response from server did not make sense: $response\n";
224 close($sock);
225 wait_then_retry();
226 next;
227 }
228
229 print "Got filter data ($filter_addr, $udp_port, $tcp_port)\n";
230
231 print $sock "END\n";
232 $response = <$sock>;
233 if ($response && ($response eq "OK\n")) {
234 print "Host successfully configured via TCP.\n"
235 }
236 else {
237 print "The server failed the host configuration on the END command.\n";
238 close($sock);
239 wait_then_retry();
240 next;
241 }
242
243 close($sock);
244
245 print "Configuration finished sucessfully!\n";
246 last;
247 }
248 return;
249 }
250
251
252 #-----------------------------------------------------------------------
253 # send_udp_packet
254 # Sends a UDP packet to an i-scream filter.
255 # The packet contains XML markup describing some of the machine's state.
256 # Receipt of UDP packets is not guaranteed.
257 #-----------------------------------------------------------------------
258 sub send_udp_packet() {
259
260 my($plugins_dir) = "plugins";
261
262 opendir PLUGINS, $plugins_dir;
263 my(@plugins) = readdir PLUGINS;
264 foreach my $plugin (@plugins) {
265 push @data, `$plugins_dir/$plugin` if -x "$plugins_dir/$plugin" && -f "$plugins_dir/$plugin";
266 }
267
268 # get some extra data
269 my($date) = time;
270 my($ip);
271 $ip = inet_ntoa(scalar(gethostbyname(hostname())) || 'localhost') or $ip = 'localhost';
272
273 # add some extra data to the array
274 push(@data, "packet.attributes.seq_no=$seq_no");
275 push(@data, "packet.attributes.machine_name=$fqdn");
276 push(@data, "packet.attributes.date=$date");
277 push(@data, "packet.attributes.type=data");
278 push(@data, "packet.attributes.ip=$ip");
279
280 # turn the array into some nice XML
281 my($xml) = &make_xml("", "");
282
283 my($sock) = new IO::Socket::INET (
284 PeerPort => $udp_port,
285 PeerAddr => $filter_addr,
286 Proto => 'udp'
287 ) or die "Could not send UDP: $!\n";
288
289 print $sock $xml or die "Could not send UDP packet: $!\n";
290 close($sock);
291 $seq_no++;
292 print "-: $xml\n";
293
294 return;
295 }
296
297
298 #-----------------------------------------------------------------------
299 # send_tcp_heartbeat
300 # Establishes a TCP connection to an i-scream filter.
301 # The heartbeat is used as a guaranteed "I'm alive" delivery mechanism.
302 # If we need to reconfigure, then we complete the heartbeat before
303 # doing so.
304 #-----------------------------------------------------------------------
305 sub send_tcp_heartbeat() {
306
307 my ($doReconfigure) = 0;
308
309 my($sock) = new IO::Socket::INET(
310 PeerAddr => $filter_addr,
311 PeerPort => $tcp_port,
312 Proto => 'tcp'
313 ) or return;
314 if (!defined $sock) {
315 print "IHOST WARNING: Failed to deliver a heartbeat to the i-scream filter.\n";
316 &tcp_configure();
317 return;
318 }
319
320 # Now run through the configuration process.
321 my($response);
322
323 print $sock "HEARTBEAT\n";
324 $response = <$sock>;
325 if (!$response eq "OK\n") {
326 close($sock);
327 print "Server gave wrong response to HEARTBEAT: $response\n";
328 &tcp_configure();
329 return;
330 }
331
332 print $sock "CONFIG\n";
333 $response = <$sock>;
334 if (!$response eq "OK\n") {
335 close($sock);
336 print "Server gave wrong response to CONFIG: $response\n";
337 &tcp_configure();
338 return;
339 }
340
341 print $sock "$file_list\n";
342 $response = <$sock>;
343 if (!$response eq "OK\n") {
344 close($sock);
345 print "Server gave wrong response to file list: $response\n";
346 &tcp_configure();
347 return;
348 }
349
350 print $sock "$last_modified\n";
351 $response = <$sock>;
352 if ($response eq "ERROR\n") {
353 close($sock);
354 print "Server configuration changed. Reconfiguring with filter manager.\n";
355 $doReconfigure = 1;
356 }
357 if (!$response eq "OK\n") {
358 close($sock);
359 print "Server gave wrong response to HEARTBEAT: $response\n";
360 &tcp_configure();
361 return;
362 }
363
364 print $sock "ENDHEARTBEAT\n";
365 $response = <$sock>;
366 if (!$response eq "OK\n") {
367 close($sock);
368 print "Server gave wrong response to ENDHEARTBEAT: $response\n";
369 &tcp_configure();
370 return;
371 }
372
373 close($sock);
374 print "^";
375
376 &tcp_configure() if $doReconfigure;
377
378 return;
379 }
380
381
382 #-----------------------------------------------------------------------
383 # write_pid
384 # Writes the PID (process ID) of this instance to $pidfile.
385 # This is then used by a seperate script to check (and restart) ihost.
386 #-----------------------------------------------------------------------
387 sub write_pid() {
388 open PID, ">$pidfile";
389 print PID $$;
390 close PID;
391
392 return;
393 }
394
395 #-----------------------------------------------------------------------
396 # make_xml
397 # Turns an array of plugins data into an XML string.
398 #-----------------------------------------------------------------------
399 sub make_xml() {
400 my($curlevel, $curline) = @_;
401 my($xmltemp) = ""; my($curtag) = ""; my($attributes) = "";
402 while(true) {
403 $curline = shift(@data) if $curline eq ""; chomp $curline;
404 if($curline =~ /^$curlevel([^\.\s]+\.)/) {
405 $curtag=$1;
406 }
407 if($curline =~ /^$curlevel$curtag([^\.\s]+)\s+(.*)$/) {
408 $xmltemp .= "<$1$attributes>$2</$1>";
409 }
410 elsif($curline =~ /^$curlevel$curtag(attributes)\.([^\.=]+)=(.*)$/) {
411 $attributes .= " $2=\"$3\"";
412 }
413 else {
414 $xmltemp .= &make_xml("$curlevel$curtag", $curline);
415 }
416 my($nextline) = $data[0]; chomp $nextline if defined $nextline;
417 $curtag =~ s/(.*)\./$1/;
418 if(defined $nextline && $nextline =~ /^$curlevel$curtag\./) {
419 $curline = "";
420 }
421 else {
422 $xmltemp = "<$curtag$attributes>$xmltemp</$curtag>" unless $curtag eq "";
423 return $xmltemp;
424 }
425 }
426 }