1 /*****************************************************************************
2 *
3 * CHECK_REAL.C
4 *
5 * Program: RealMedia plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Pedro Leite (leite@cic.ua.pt)
8 *
9 * Based on CHECK_HTTP.C
10 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
11 *
12 * Last Modified: $Date$
13 *
14 * Command line: CHECK_REAL <host_address> [-e expect] [-u url] [-p port]
15 * [-hn host_name] [-wt warn_time] [-ct crit_time]
16 * [-to to_sec]
17 *
18 * Description:
19 *
20 * This plugin will attempt to open an RTSP connection with the host.
21 * Successul connects return STATE_OK, refusals and timeouts return
22 * STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,
23 * but incorrect reponse messages from the host result in STATE_WARNING return
24 * values. If you are checking a virtual server that uses "host headers"you
25 * must supply the FQDN (fully qualified domain name) as the [host_name]
26 * argument.
27 *
28 * License Information:
29 *
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
43 *
44 ****************************************************************************/
46 #include "config.h"
47 #include "common.h"
48 #include "netutils.h"
49 #include "utils.h"
51 #define PROGNAME "check_real"
53 #define PORT 554
54 #define EXPECT "RTSP/1."
55 #define URL ""
57 int process_arguments (int, char **);
58 int call_getopt (int, char **);
59 int validate_arguments (void);
60 int check_disk (int usp, int free_disk);
61 void print_help (void);
62 void print_usage (void);
64 int server_port = PORT;
65 char *server_address = NULL;
66 char *host_name = NULL;
67 char *server_url = NULL;
68 char *server_expect = NULL;
69 int warning_time = 0;
70 int check_warning_time = FALSE;
71 int critical_time = 0;
72 int check_critical_time = FALSE;
73 int verbose = FALSE;
75 int
76 main (int argc, char **argv)
77 {
78 int sd;
79 int result;
80 char buffer[MAX_INPUT_BUFFER];
81 char *status_line = NULL;
83 if (process_arguments (argc, argv) != OK)
84 usage ("Invalid command arguments supplied\n");
86 /* initialize alarm signal handling */
87 signal (SIGALRM, socket_timeout_alarm_handler);
89 /* set socket timeout */
90 alarm (socket_timeout);
91 time (&start_time);
93 /* try to connect to the host at the given port number */
94 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
95 terminate (STATE_CRITICAL, "Unable to connect to %s on port %d\n",
96 server_address, server_port);
98 /* Part I - Server Check */
100 /* send the OPTIONS request */
101 sprintf (buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\n", host_name, server_port);
102 result = send (sd, buffer, strlen (buffer), 0);
104 /* send the header sync */
105 sprintf (buffer, "CSeq: 1\n");
106 result = send (sd, buffer, strlen (buffer), 0);
108 /* send a newline so the server knows we're done with the request */
109 sprintf (buffer, "\n");
110 result = send (sd, buffer, strlen (buffer), 0);
112 /* watch for the REAL connection string */
113 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
115 /* return a CRITICAL status if we couldn't read any data */
116 if (result == -1)
117 terminate (STATE_CRITICAL, "No data received from %s\n", host_name);
119 /* make sure we find the response we are looking for */
120 if (!strstr (buffer, EXPECT)) {
121 if (server_port == PORT)
122 printf ("Invalid REAL response received from host\n");
123 else
124 printf ("Invalid REAL response received from host on port %d\n",
125 server_port);
126 }
127 else {
128 /* else we got the REAL string, so check the return code */
130 time (&end_time);
132 result = STATE_OK;
134 status_line = (char *) strtok (buffer, "\n");
136 if (strstr (status_line, "200"))
137 result = STATE_OK;
139 /* client errors result in a warning state */
140 else if (strstr (status_line, "400"))
141 result = STATE_WARNING;
142 else if (strstr (status_line, "401"))
143 result = STATE_WARNING;
144 else if (strstr (status_line, "402"))
145 result = STATE_WARNING;
146 else if (strstr (status_line, "403"))
147 result = STATE_WARNING;
148 else if (strstr (status_line, "404"))
149 result = STATE_WARNING;
151 /* server errors result in a critical state */
152 else if (strstr (status_line, "500"))
153 result = STATE_CRITICAL;
154 else if (strstr (status_line, "501"))
155 result = STATE_CRITICAL;
156 else if (strstr (status_line, "502"))
157 result = STATE_CRITICAL;
158 else if (strstr (status_line, "503"))
159 result = STATE_CRITICAL;
161 else
162 result = STATE_UNKNOWN;
163 }
165 /* Part II - Check stream exists and is ok */
166 if ((result == STATE_OK) && (server_url != NULL)) {
168 /* Part I - Server Check */
170 /* send the OPTIONS request */
171 sprintf (buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\n", host_name,
172 server_port, server_url);
173 result = send (sd, buffer, strlen (buffer), 0);
175 /* send the header sync */
176 sprintf (buffer, "CSeq: 2\n");
177 result = send (sd, buffer, strlen (buffer), 0);
179 /* send a newline so the server knows we're done with the request */
180 sprintf (buffer, "\n");
181 result = send (sd, buffer, strlen (buffer), 0);
183 /* watch for the REAL connection string */
184 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
186 /* return a CRITICAL status if we couldn't read any data */
187 if (result == -1) {
188 printf ("No data received from host\n");
189 result = STATE_CRITICAL;
190 }
191 else {
192 /* make sure we find the response we are looking for */
193 if (!strstr (buffer, EXPECT)) {
194 if (server_port == PORT)
195 printf ("Invalid REAL response received from host\n");
196 else
197 printf ("Invalid REAL response received from host on port %d\n",
198 server_port);
199 }
200 else {
202 /* else we got the REAL string, so check the return code */
204 time (&end_time);
206 result = STATE_OK;
208 status_line = (char *) strtok (buffer, "\n");
210 if (strstr (status_line, "200"))
211 result = STATE_OK;
213 /* client errors result in a warning state */
214 else if (strstr (status_line, "400"))
215 result = STATE_WARNING;
216 else if (strstr (status_line, "401"))
217 result = STATE_WARNING;
218 else if (strstr (status_line, "402"))
219 result = STATE_WARNING;
220 else if (strstr (status_line, "403"))
221 result = STATE_WARNING;
222 else if (strstr (status_line, "404"))
223 result = STATE_WARNING;
225 /* server errors result in a critical state */
226 else if (strstr (status_line, "500"))
227 result = STATE_CRITICAL;
228 else if (strstr (status_line, "501"))
229 result = STATE_CRITICAL;
230 else if (strstr (status_line, "502"))
231 result = STATE_CRITICAL;
232 else if (strstr (status_line, "503"))
233 result = STATE_CRITICAL;
235 else
236 result = STATE_UNKNOWN;
237 }
238 }
239 }
241 /* Return results */
242 if (result == STATE_OK) {
244 if (check_critical_time == TRUE
245 && (end_time - start_time) > critical_time) result = STATE_CRITICAL;
246 else if (check_warning_time == TRUE
247 && (end_time - start_time) > warning_time) result =
248 STATE_WARNING;
250 /* Put some HTML in here to create a dynamic link */
251 printf ("REAL %s - %d second response time\n",
252 (result == STATE_OK) ? "ok" : "problem",
253 (int) (end_time - start_time));
254 }
255 else
256 printf ("%s\n", status_line);
258 /* close the connection */
259 close (sd);
261 /* reset the alarm */
262 alarm (0);
264 return result;
265 }
272 /* process command-line arguments */
273 int
274 process_arguments (int argc, char **argv)
275 {
276 int c;
278 if (argc < 2)
279 return ERROR;
281 for (c = 1; c < argc; c++) {
282 if (strcmp ("-to", argv[c]) == 0)
283 strcpy (argv[c], "-t");
284 else if (strcmp ("-wt", argv[c]) == 0)
285 strcpy (argv[c], "-w");
286 else if (strcmp ("-ct", argv[c]) == 0)
287 strcpy (argv[c], "-c");
288 }
292 c = 0;
293 while ((c += (call_getopt (argc - c, &argv[c]))) < argc) {
295 if (is_option (argv[c]))
296 continue;
298 if (server_address == NULL) {
299 if (is_host (argv[c])) {
300 server_address = argv[c];
301 }
302 else {
303 usage ("Invalid host name");
304 }
305 }
306 }
308 if (server_expect == NULL)
309 server_expect = strscpy (NULL, EXPECT);
311 return validate_arguments ();
312 }
319 int
320 call_getopt (int argc, char **argv)
321 {
322 int c, i = 0;
324 #ifdef HAVE_GETOPT_H
325 int option_index = 0;
326 static struct option long_options[] = {
327 {"hostname", required_argument, 0, 'H'},
328 {"IPaddress", required_argument, 0, 'I'},
329 {"expect", required_argument, 0, 'e'},
330 {"url", required_argument, 0, 'u'},
331 {"port", required_argument, 0, 'p'},
332 {"critical", required_argument, 0, 'c'},
333 {"warning", required_argument, 0, 'w'},
334 {"timeout", required_argument, 0, 't'},
335 {"verbose", no_argument, 0, 'v'},
336 {"version", no_argument, 0, 'V'},
337 {"help", no_argument, 0, 'h'},
338 {0, 0, 0, 0}
339 };
340 #endif
342 while (1) {
343 #ifdef HAVE_GETOPT_H
344 c =
345 getopt_long (argc, argv, "+hVI:H:e:u:p:w:c:t:", long_options,
346 &option_index);
347 #else
348 c = getopt (argc, argv, "+?hVI:H:e:u:p:w:c:t");
349 #endif
351 i++;
353 if (c == -1 || c == EOF || c == 1)
354 break;
356 switch (c) {
357 case 'I':
358 case 'H':
359 case 'e':
360 case 'u':
361 case 'p':
362 case 'w':
363 case 'c':
364 case 't':
365 i++;
366 }
368 switch (c) {
369 case 'I': /* hostname */
370 if (is_host (optarg)) {
371 server_address = optarg;
372 }
373 else {
374 usage ("Invalid host name\n");
375 }
376 break;
377 case 'H': /* hostname */
378 if (is_host (optarg)) {
379 server_address = optarg;
380 }
381 else {
382 usage ("Invalid host name\n");
383 }
384 break;
385 case 'e': /* string to expect in response header */
386 server_expect = optarg;
387 break;
388 case 'u': /* string to expect in response header */
389 server_url = optarg;
390 break;
391 case 'p': /* port */
392 if (is_intpos (optarg)) {
393 server_port = atoi (optarg);
394 }
395 else {
396 usage ("Server port must be a positive integer\n");
397 }
398 break;
399 case 'w': /* warning time threshold */
400 if (is_intnonneg (optarg)) {
401 warning_time = atoi (optarg);
402 check_warning_time = TRUE;
403 }
404 else {
405 usage ("Warning time must be a nonnegative integer\n");
406 }
407 break;
408 case 'c': /* critical time threshold */
409 if (is_intnonneg (optarg)) {
410 critical_time = atoi (optarg);
411 check_critical_time = TRUE;
412 }
413 else {
414 usage ("Critical time must be a nonnegative integer\n");
415 }
416 break;
417 case 'v': /* verbose */
418 verbose = TRUE;
419 break;
420 case 't': /* timeout */
421 if (is_intnonneg (optarg)) {
422 socket_timeout = atoi (optarg);
423 }
424 else {
425 usage ("Time interval must be a nonnegative integer\n");
426 }
427 break;
428 case 'V': /* version */
429 print_revision (PROGNAME, "$Revision$");
430 exit (STATE_OK);
431 case 'h': /* help */
432 print_help ();
433 exit (STATE_OK);
434 case '?': /* help */
435 usage ("Invalid argument\n");
436 }
437 }
438 return i;
439 }
445 int
446 validate_arguments (void)
447 {
448 return OK;
449 }
455 void
456 print_help (void)
457 {
458 print_revision (PROGNAME, "$Revision$");
459 printf
460 ("Copyright (c) 2000 Pedro Leite (leite@cic.ua.pt)/Karl DeBisschop\n\n"
461 "This plugin tests the REAL service on the specified host.\n\n");
462 print_usage ();
463 printf
464 ("\nOptions:\n"
465 " -H, --hostname=STRING or IPADDRESS\n"
466 " Check this server on the indicated host\n"
467 " -I, --IPaddress=STRING or IPADDRESS\n"
468 " Check server at this host address\n"
469 " -p, --port=INTEGER\n"
470 " Make connection on the indicated port (default: %d)\n"
471 " -u, --url=STRING\n"
472 " Connect to this url\n"
473 " -e, --expect=STRING\n"
474 " String to expect in first line of server response (default: %s)\n"
475 " -w, --warning=INTEGER\n"
476 " Seconds necessary to result in a warning status\n"
477 " -c, --critical=INTEGER\n"
478 " Seconds necessary to result in a critical status\n"
479 " -t, --timeout=INTEGER\n"
480 " Seconds before connection attempt times out (default: %d)\n"
481 " -v, --verbose\n"
482 " Print extra information (command-line use only)\n"
483 " -h, --help\n"
484 " Print detailed help screen\n"
485 " -V, --version\n"
486 " Print version information\n\n",
487 PORT, EXPECT, DEFAULT_SOCKET_TIMEOUT);
488 support ();
489 }
495 void
496 print_usage (void)
497 {
498 printf
499 ("Usage: %s -H host [-e expect] [-p port] [-w warn] [-c crit]\n"
500 " [-t timeout] [-v]\n"
501 " %s --help\n"
502 " %s --version\n", PROGNAME, PROGNAME, PROGNAME);
503 }
508 /*
509 // process command-line arguments
510 int
511 process_arguments (int argc, char **argv)
512 {
513 int x;
515 // no options were supplied
516 if (argc < 2)
517 return ERROR;
519 // first option is always the server name/address
520 strncpy (server_address, argv[1], sizeof (server_address) - 1);
521 server_address[sizeof (server_address) - 1] = 0;
523 // set the host name to the server address (until its overridden)
524 strcpy (host_name, server_address);
526 // process all remaining arguments
527 for (x = 3; x <= argc; x++)
528 {
530 // we got the string to expect from the server
531 if (!strcmp (argv[x - 1], "-e"))
532 {
533 if (x < argc)
534 {
535 strncpy (server_expect, argv[x], sizeof (server_expect) - 1);
536 server_expect[sizeof (server_expect) - 1] = 0;
537 x++;
538 }
539 else
540 return ERROR;
541 }
543 // we got the URL to check
544 else if (!strcmp (argv[x - 1], "-u"))
545 {
546 if (x < argc)
547 {
548 strncpy (server_url, argv[x], sizeof (server_url) - 1);
549 server_url[sizeof (server_url) - 1] = 0;
550 x++;
551 }
552 else
553 return ERROR;
554 }
556 // we go the host name to use in the host header
557 else if (!strcmp (argv[x - 1], "-hn"))
558 {
559 if (x < argc)
560 {
561 strncpy (host_name, argv[x], sizeof (host_name) - 1);
562 host_name[sizeof (host_name) - 1] = 0;
563 x++;
564 }
565 else
566 return ERROR;
567 }
569 // we got the port number to use
570 else if (!strcmp (argv[x - 1], "-p"))
571 {
572 if (x < argc)
573 {
574 server_port = atoi (argv[x]);
575 x++;
576 }
577 else
578 return ERROR;
579 }
581 // we got the socket timeout
582 else if (!strcmp (argv[x - 1], "-to"))
583 {
584 if (x < argc)
585 {
586 socket_timeout = atoi (argv[x]);
587 if (socket_timeout <= 0)
588 return ERROR;
589 x++;
590 }
591 else
592 return ERROR;
593 }
595 // we got the warning threshold time
596 else if (!strcmp (argv[x - 1], "-wt"))
597 {
598 if (x < argc)
599 {
600 warning_time = atoi (argv[x]);
601 check_warning_time = TRUE;
602 x++;
603 }
604 else
605 return ERROR;
606 }
608 // we got the critical threshold time
609 else if (!strcmp (argv[x - 1], "-ct"))
610 {
611 if (x < argc)
612 {
613 critical_time = atoi (argv[x]);
614 check_critical_time = TRUE;
615 x++;
616 }
617 else
618 return ERROR;
619 }
621 // else we got something else...
622 else
623 return ERROR;
624 }
626 return OK;
627 }
629 result = process_arguments (argc, argv);
631 if (result != OK)
632 {
634 printf ("Incorrect number of arguments supplied\n");
635 printf ("\n");
636 print_revision(argv[0],"$Revision$");
637 printf ("Copyright (c) 1999 Pedro Leite (leite@cic.ua.pt)\n");
638 printf ("Last Modified: 30-10-1999\n");
639 printf ("License: GPL\n");
640 printf ("\n");
641 printf ("Usage: %s <host_address> [-e expect] [-u url] [-p port] [-hn host_name] [-wt warn_time]\n",argv[0]);
642 printf(" [-ct crit_time] [-to to_sec] [-a auth]\n");
643 printf ("\n");
644 printf ("Options:\n");
645 printf (" [expect] = String to expect in first line of server response - default is \"%s\"\n", EXPECT);
646 printf (" [url] = Optional URL to GET - default is root document\n");
647 printf (" [port] = Optional port number to use - default is %d\n", PORT);
648 printf (" [host_name] = Optional host name argument to GET command - used for servers using host headers\n");
649 printf (" [warn_time] = Response time in seconds necessary to result in a warning status\n");
650 printf (" [crit_time] = Response time in seconds necessary to result in a critical status\n");
651 printf (" [to_sec] = Number of seconds before connection attempt times out - default is %d seconds\n", DEFAULT_SOCKET_TIMEOUT);
652 printf (" [auth] = Optional username:password for sites requiring basic authentication\n");
653 printf ("\n");
654 printf ("This plugin attempts to contact the REAL service on the specified host.\n");
655 printf ("If possible, supply an IP address for the host address, as this will bypass the DNS lookup.\n");
656 printf ("\n");
658 return STATE_UNKNOWN;
659 }
661 */