1 /******************************************************************************
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 $Id$
19 ******************************************************************************/
20 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
22 const char *progname = "check_http";
23 const char *revision = "$Revision$";
24 const char *copyright = "1999-2004";
25 const char *email = "nagiosplug-devel@lists.sourceforge.net";
27 #include "common.h"
28 #include "netutils.h"
29 #include "utils.h"
31 #define INPUT_DELIMITER ";"
33 #define HTTP_EXPECT "HTTP/1."
34 enum {
35 MAX_IPV4_HOSTLENGTH = 255,
36 HTTP_PORT = 80,
37 HTTPS_PORT = 443
38 };
40 #ifdef HAVE_SSL_H
41 #include <rsa.h>
42 #include <crypto.h>
43 #include <x509.h>
44 #include <pem.h>
45 #include <ssl.h>
46 #include <err.h>
47 #include <rand.h>
48 #else
49 # ifdef HAVE_OPENSSL_SSL_H
50 # include <openssl/rsa.h>
51 # include <openssl/crypto.h>
52 # include <openssl/x509.h>
53 # include <openssl/pem.h>
54 # include <openssl/ssl.h>
55 # include <openssl/err.h>
56 # include <openssl/rand.h>
57 # endif
58 #endif
60 #ifdef HAVE_SSL
61 int check_cert = FALSE;
62 int days_till_exp;
63 char *randbuff;
64 SSL_CTX *ctx;
65 SSL *ssl;
66 X509 *server_cert;
67 int connect_SSL (void);
68 int check_certificate (X509 **);
69 #endif
70 int no_body = FALSE;
71 int maximum_age = -1;
73 #ifdef HAVE_REGEX_H
74 enum {
75 REGS = 2,
76 MAX_RE_SIZE = 256
77 };
78 #include <regex.h>
79 regex_t preg;
80 regmatch_t pmatch[REGS];
81 char regexp[MAX_RE_SIZE];
82 char errbuf[MAX_INPUT_BUFFER];
83 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
84 int errcode;
85 #endif
87 struct timeval tv;
89 #define HTTP_URL "/"
90 #define CRLF "\r\n"
92 char timestamp[17] = "";
93 int specify_port = FALSE;
94 int server_port = HTTP_PORT;
95 char server_port_text[6] = "";
96 char server_type[6] = "http";
97 char *server_address;
98 char *host_name;
99 char *server_url;
100 char *user_agent;
101 int server_url_length;
102 int server_expect_yn = 0;
103 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
104 char string_expect[MAX_INPUT_BUFFER] = "";
105 double warning_time = 0;
106 int check_warning_time = FALSE;
107 double critical_time = 0;
108 int check_critical_time = FALSE;
109 char user_auth[MAX_INPUT_BUFFER] = "";
110 int display_html = FALSE;
111 char *http_opt_headers;
112 int onredirect = STATE_OK;
113 int use_ssl = FALSE;
114 int verbose = FALSE;
115 int sd;
116 int min_page_len = 0;
117 int max_page_len = 0;
118 int redir_depth = 0;
119 int max_depth = 15;
120 char *http_method;
121 char *http_post_data;
122 char *http_content_type;
123 char buffer[MAX_INPUT_BUFFER];
125 int process_arguments (int, char **);
126 static char *base64 (const char *bin, size_t len);
127 int check_http (void);
128 void redir (char *pos, char *status_line);
129 int server_type_check(const char *type);
130 int server_port_check(int ssl_flag);
131 char *perfd_time (double microsec);
132 char *perfd_size (int page_len);
133 int my_recv (void);
134 int my_close (void);
135 void print_help (void);
136 void print_usage (void);
138 int
139 main (int argc, char **argv)
140 {
141 int result = STATE_UNKNOWN;
143 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
144 server_url = strdup(HTTP_URL);
145 server_url_length = strlen(server_url);
146 asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
147 clean_revstring (revision), VERSION);
149 if (process_arguments (argc, argv) == ERROR)
150 usage4 (_("Could not parse arguments"));
152 if (strstr (timestamp, ":")) {
153 if (strstr (server_url, "?"))
154 asprintf (&server_url, "%s&%s", server_url, timestamp);
155 else
156 asprintf (&server_url, "%s?%s", server_url, timestamp);
157 }
159 if (display_html == TRUE)
160 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
161 use_ssl ? "https" : "http", host_name,
162 server_port, server_url);
164 /* initialize alarm signal handling, set socket timeout, start timer */
165 (void) signal (SIGALRM, socket_timeout_alarm_handler);
166 (void) alarm (socket_timeout);
167 gettimeofday (&tv, NULL);
169 #ifdef HAVE_SSL
170 if (use_ssl && check_cert == TRUE) {
171 if (connect_SSL () != OK)
172 die (STATE_CRITICAL, _("HTTP CRITICAL - Could not make SSL connection\n"));
173 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
174 result = check_certificate (&server_cert);
175 X509_free (server_cert);
176 }
177 else {
178 printf (_("CRITICAL - Cannot retrieve server certificate.\n"));
179 result = STATE_CRITICAL;
180 }
181 SSL_shutdown (ssl);
182 SSL_free (ssl);
183 SSL_CTX_free (ctx);
184 close (sd);
185 }
186 else {
187 result = check_http ();
188 }
189 #else
190 result = check_http ();
191 #endif
192 return result;
193 }
197 /* process command-line arguments */
198 int
199 process_arguments (int argc, char **argv)
200 {
201 int c = 1;
203 int option = 0;
204 static struct option longopts[] = {
205 STD_LONG_OPTS,
206 {"file",required_argument,0,'F'},
207 {"link", no_argument, 0, 'L'},
208 {"nohtml", no_argument, 0, 'n'},
209 {"ssl", no_argument, 0, 'S'},
210 {"verbose", no_argument, 0, 'v'},
211 {"post", required_argument, 0, 'P'},
212 {"IP-address", required_argument, 0, 'I'},
213 {"url", required_argument, 0, 'u'},
214 {"string", required_argument, 0, 's'},
215 {"regex", required_argument, 0, 'r'},
216 {"ereg", required_argument, 0, 'r'},
217 {"eregi", required_argument, 0, 'R'},
218 {"linespan", no_argument, 0, 'l'},
219 {"onredirect", required_argument, 0, 'f'},
220 {"certificate", required_argument, 0, 'C'},
221 {"useragent", required_argument, 0, 'A'},
222 {"header", required_argument, 0, 'k'},
223 {"no-body", no_argument, 0, 'N'},
224 {"max-age", required_argument, 0, 'M'},
225 {"content-type", required_argument, 0, 'T'},
226 {"pagesize", required_argument, 0, 'm'},
227 {"use-ipv4", no_argument, 0, '4'},
228 {"use-ipv6", no_argument, 0, '6'},
229 {0, 0, 0, 0}
230 };
232 if (argc < 2)
233 return ERROR;
235 for (c = 1; c < argc; c++) {
236 if (strcmp ("-to", argv[c]) == 0)
237 strcpy (argv[c], "-t");
238 if (strcmp ("-hn", argv[c]) == 0)
239 strcpy (argv[c], "-H");
240 if (strcmp ("-wt", argv[c]) == 0)
241 strcpy (argv[c], "-w");
242 if (strcmp ("-ct", argv[c]) == 0)
243 strcpy (argv[c], "-c");
244 if (strcmp ("-nohtml", argv[c]) == 0)
245 strcpy (argv[c], "-n");
246 }
248 while (1) {
249 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:T:I:a:e:p:s:R:r:u:f:C:nlLSm:M:N", longopts, &option);
250 if (c == -1 || c == EOF)
251 break;
253 switch (c) {
254 case '?': /* usage */
255 usage2 (_("Unknown argument"), optarg);
256 break;
257 case 'h': /* help */
258 print_help ();
259 exit (STATE_OK);
260 break;
261 case 'V': /* version */
262 print_revision (progname, revision);
263 exit (STATE_OK);
264 break;
265 case 't': /* timeout period */
266 if (!is_intnonneg (optarg))
267 usage2 (_("Timeout interval must be a positive integer"), optarg);
268 else
269 socket_timeout = atoi (optarg);
270 break;
271 case 'c': /* critical time threshold */
272 if (!is_nonnegative (optarg))
273 usage2 (_("Critical threshold must be integer"), optarg);
274 else {
275 critical_time = strtod (optarg, NULL);
276 check_critical_time = TRUE;
277 }
278 break;
279 case 'w': /* warning time threshold */
280 if (!is_nonnegative (optarg))
281 usage2 (_("Warning threshold must be integer"), optarg);
282 else {
283 warning_time = strtod (optarg, NULL);
284 check_warning_time = TRUE;
285 }
286 break;
287 case 'A': /* User Agent String */
288 asprintf (&user_agent, "User-Agent: %s", optarg);
289 break;
290 case 'k': /* Additional headers */
291 asprintf (&http_opt_headers, "%s", optarg);
292 break;
293 case 'L': /* show html link */
294 display_html = TRUE;
295 break;
296 case 'n': /* do not show html link */
297 display_html = FALSE;
298 break;
299 case 'S': /* use SSL */
300 #ifndef HAVE_SSL
301 usage4 (_("Invalid option - SSL is not available"));
302 #endif
303 use_ssl = TRUE;
304 if (specify_port == FALSE)
305 server_port = HTTPS_PORT;
306 break;
307 case 'C': /* Check SSL cert validity */
308 #ifdef HAVE_SSL
309 if (!is_intnonneg (optarg))
310 usage2 (_("Invalid certificate expiration period"), optarg);
311 else {
312 days_till_exp = atoi (optarg);
313 check_cert = TRUE;
314 }
315 #else
316 usage4 (_("Invalid option - SSL is not available"));
317 #endif
318 break;
319 case 'f': /* onredirect */
320 if (!strcmp (optarg, "follow"))
321 onredirect = STATE_DEPENDENT;
322 if (!strcmp (optarg, "unknown"))
323 onredirect = STATE_UNKNOWN;
324 if (!strcmp (optarg, "ok"))
325 onredirect = STATE_OK;
326 if (!strcmp (optarg, "warning"))
327 onredirect = STATE_WARNING;
328 if (!strcmp (optarg, "critical"))
329 onredirect = STATE_CRITICAL;
330 if (verbose)
331 printf(_("option f:%d \n"), onredirect);
332 break;
333 /* Note: H, I, and u must be malloc'd or will fail on redirects */
334 case 'H': /* Host Name (virtual host) */
335 host_name = strdup (optarg);
336 if (strstr (optarg, ":"))
337 sscanf (optarg, "%*[^:]:%d", &server_port);
338 break;
339 case 'I': /* Server IP-address */
340 server_address = strdup (optarg);
341 break;
342 case 'u': /* URL path */
343 server_url = strdup (optarg);
344 server_url_length = strlen (server_url);
345 break;
346 case 'p': /* Server port */
347 if (!is_intnonneg (optarg))
348 usage2 (_("Invalid port number"), optarg);
349 else {
350 server_port = atoi (optarg);
351 specify_port = TRUE;
352 }
353 break;
354 case 'a': /* authorization info */
355 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
356 user_auth[MAX_INPUT_BUFFER - 1] = 0;
357 break;
358 case 'P': /* HTTP POST data in URL encoded format */
359 if (http_method || http_post_data) break;
360 http_method = strdup("POST");
361 http_post_data = strdup (optarg);
362 break;
363 case 's': /* string or substring */
364 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
365 string_expect[MAX_INPUT_BUFFER - 1] = 0;
366 break;
367 case 'e': /* string or substring */
368 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
369 server_expect[MAX_INPUT_BUFFER - 1] = 0;
370 server_expect_yn = 1;
371 break;
372 case 'T': /* Content-type */
373 asprintf (&http_content_type, "%s", optarg);
374 break;
375 #ifndef HAVE_REGEX_H
376 case 'l': /* linespan */
377 case 'r': /* linespan */
378 case 'R': /* linespan */
379 usage4 (_("Call for regex which was not a compiled option"));
380 break;
381 #else
382 case 'l': /* linespan */
383 cflags &= ~REG_NEWLINE;
384 break;
385 case 'R': /* regex */
386 cflags |= REG_ICASE;
387 case 'r': /* regex */
388 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
389 regexp[MAX_RE_SIZE - 1] = 0;
390 errcode = regcomp (&preg, regexp, cflags);
391 if (errcode != 0) {
392 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
393 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
394 return ERROR;
395 }
396 break;
397 #endif
398 case '4':
399 address_family = AF_INET;
400 break;
401 case '6':
402 #ifdef USE_IPV6
403 address_family = AF_INET6;
404 #else
405 usage4 (_("IPv6 support not available"));
406 #endif
407 break;
408 case 'v': /* verbose */
409 verbose = TRUE;
410 break;
411 case 'm': /* min_page_length */
412 {
413 char *tmp;
414 if (strchr(optarg, ':') != (char *)NULL) {
415 /* range, so get two values, min:max */
416 tmp = strtok(optarg, ":");
417 if (tmp == NULL) {
418 printf("Bad format: try \"-m min:max\"\n");
419 exit (STATE_WARNING);
420 } else
421 min_page_len = atoi(tmp);
423 tmp = strtok(NULL, ":");
424 if (tmp == NULL) {
425 printf("Bad format: try \"-m min:max\"\n");
426 exit (STATE_WARNING);
427 } else
428 max_page_len = atoi(tmp);
429 } else
430 min_page_len = atoi (optarg);
431 break;
432 }
433 case 'N': /* no-body */
434 no_body = TRUE;
435 break;
436 case 'M': /* max-age */
437 {
438 int L = strlen(optarg);
439 if (L && optarg[L-1] == 'm')
440 maximum_age = atoi (optarg) * 60;
441 else if (L && optarg[L-1] == 'h')
442 maximum_age = atoi (optarg) * 60 * 60;
443 else if (L && optarg[L-1] == 'd')
444 maximum_age = atoi (optarg) * 60 * 60 * 24;
445 else if (L && (optarg[L-1] == 's' ||
446 isdigit (optarg[L-1])))
447 maximum_age = atoi (optarg);
448 else {
449 fprintf (stderr, "unparsable max-age: %s\n", optarg);
450 exit (STATE_WARNING);
451 }
452 }
453 break;
454 }
455 }
457 c = optind;
459 if (server_address == NULL && c < argc)
460 server_address = strdup (argv[c++]);
462 if (host_name == NULL && c < argc)
463 host_name = strdup (argv[c++]);
465 if (server_address == NULL) {
466 if (host_name == NULL)
467 usage4 (_("You must specify a server address or host name"));
468 else
469 server_address = strdup (host_name);
470 }
472 if (check_critical_time && critical_time>(double)socket_timeout)
473 socket_timeout = (int)critical_time + 1;
475 if (http_method == NULL)
476 http_method = strdup ("GET");
478 return TRUE;
479 }
483 /* written by lauri alanko */
484 static char *
485 base64 (const char *bin, size_t len)
486 {
488 char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
489 size_t i = 0, j = 0;
491 char BASE64_END = '=';
492 char base64_table[64];
493 strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
495 while (j < len - 2) {
496 buf[i++] = base64_table[bin[j] >> 2];
497 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
498 buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
499 buf[i++] = base64_table[bin[j + 2] & 63];
500 j += 3;
501 }
503 switch (len - j) {
504 case 1:
505 buf[i++] = base64_table[bin[j] >> 2];
506 buf[i++] = base64_table[(bin[j] & 3) << 4];
507 buf[i++] = BASE64_END;
508 buf[i++] = BASE64_END;
509 break;
510 case 2:
511 buf[i++] = base64_table[bin[j] >> 2];
512 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
513 buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
514 buf[i++] = BASE64_END;
515 break;
516 case 0:
517 break;
518 }
520 buf[i] = '\0';
521 return buf;
522 }
526 /* Returns 1 if we're done processing the document body; 0 to keep going */
527 static int
528 document_headers_done (char *full_page)
529 {
530 const char *body;
532 for (body = full_page; *body; body++) {
533 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
534 break;
535 }
537 if (!*body)
538 return 0; /* haven't read end of headers yet */
540 full_page[body - full_page] = 0;
541 return 1;
542 }
544 static time_t
545 parse_time_string (const char *string)
546 {
547 struct tm tm;
548 time_t t;
549 memset (&tm, 0, sizeof(tm));
551 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
553 if (isupper (string[0]) && /* Tue */
554 islower (string[1]) &&
555 islower (string[2]) &&
556 ',' == string[3] &&
557 ' ' == string[4] &&
558 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
559 isdigit (string[6]) &&
560 ' ' == string[7] &&
561 isupper (string[8]) && /* Dec */
562 islower (string[9]) &&
563 islower (string[10]) &&
564 ' ' == string[11] &&
565 isdigit (string[12]) && /* 2001 */
566 isdigit (string[13]) &&
567 isdigit (string[14]) &&
568 isdigit (string[15]) &&
569 ' ' == string[16] &&
570 isdigit (string[17]) && /* 02: */
571 isdigit (string[18]) &&
572 ':' == string[19] &&
573 isdigit (string[20]) && /* 59: */
574 isdigit (string[21]) &&
575 ':' == string[22] &&
576 isdigit (string[23]) && /* 03 */
577 isdigit (string[24]) &&
578 ' ' == string[25] &&
579 'G' == string[26] && /* GMT */
580 'M' == string[27] && /* GMT */
581 'T' == string[28]) {
583 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
584 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
585 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
586 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
587 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
588 !strncmp (string+8, "Feb", 3) ? 1 :
589 !strncmp (string+8, "Mar", 3) ? 2 :
590 !strncmp (string+8, "Apr", 3) ? 3 :
591 !strncmp (string+8, "May", 3) ? 4 :
592 !strncmp (string+8, "Jun", 3) ? 5 :
593 !strncmp (string+8, "Jul", 3) ? 6 :
594 !strncmp (string+8, "Aug", 3) ? 7 :
595 !strncmp (string+8, "Sep", 3) ? 8 :
596 !strncmp (string+8, "Oct", 3) ? 9 :
597 !strncmp (string+8, "Nov", 3) ? 10 :
598 !strncmp (string+8, "Dec", 3) ? 11 :
599 -1);
600 tm.tm_year = ((1000 * (string[12]-'0') +
601 100 * (string[13]-'0') +
602 10 * (string[14]-'0') +
603 (string[15]-'0'))
604 - 1900);
606 tm.tm_isdst = 0; /* GMT is never in DST, right? */
608 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
609 return 0;
611 /*
612 This is actually wrong: we need to subtract the local timezone
613 offset from GMT from this value. But, that's ok in this usage,
614 because we only comparing these two GMT dates against each other,
615 so it doesn't matter what time zone we parse them in.
616 */
618 t = mktime (&tm);
619 if (t == (time_t) -1) t = 0;
621 if (verbose) {
622 const char *s = string;
623 while (*s && *s != '\r' && *s != '\n')
624 fputc (*s++, stdout);
625 printf (" ==> %lu\n", (unsigned long) t);
626 }
628 return t;
630 } else {
631 return 0;
632 }
633 }
637 static void
638 check_document_dates (const char *headers)
639 {
640 const char *s;
641 char *server_date = 0;
642 char *document_date = 0;
644 s = headers;
645 while (*s) {
646 const char *field = s;
647 const char *value = 0;
649 /* Find the end of the header field */
650 while (*s && !isspace(*s) && *s != ':')
651 s++;
653 /* Remember the header value, if any. */
654 if (*s == ':')
655 value = ++s;
657 /* Skip to the end of the header, including continuation lines. */
658 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
659 s++;
660 s++;
662 /* Process this header. */
663 if (value && value > field+2) {
664 char *ff = (char *) malloc (value-field);
665 char *ss = ff;
666 while (field < value-1)
667 *ss++ = tolower(*field++);
668 *ss++ = 0;
670 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
671 const char *e;
672 while (*value && isspace (*value))
673 value++;
674 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
675 ;
676 ss = (char *) malloc (e - value + 1);
677 strncpy (ss, value, e - value);
678 ss[e - value] = 0;
679 if (!strcmp (ff, "date")) {
680 if (server_date) free (server_date);
681 server_date = ss;
682 } else {
683 if (document_date) free (document_date);
684 document_date = ss;
685 }
686 }
687 free (ff);
688 }
689 }
691 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
692 if (!server_date || !*server_date) {
693 die (STATE_UNKNOWN, _("Server date unknown\n"));
694 } else if (!document_date || !*document_date) {
695 die (STATE_CRITICAL, _("Document modification date unknown\n"));
696 } else {
697 time_t srv_data = parse_time_string (server_date);
698 time_t doc_data = parse_time_string (document_date);
700 if (srv_data <= 0) {
701 die (STATE_CRITICAL, _("CRITICAL - Server date \"%100s\" unparsable"), server_date);
702 } else if (doc_data <= 0) {
703 die (STATE_CRITICAL, _("CRITICAL - Document date \"%100s\" unparsable"), document_date);
704 } else if (doc_data > srv_data + 30) {
705 die (STATE_CRITICAL, _("CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
706 } else if (doc_data < srv_data - maximum_age) {
707 int n = (srv_data - doc_data);
708 if (n > (60 * 60 * 24 * 2))
709 die (STATE_CRITICAL,
710 _("CRITICAL - Last modified %.1f days ago\n"),
711 ((float) n) / (60 * 60 * 24));
712 else
713 die (STATE_CRITICAL,
714 _("CRITICAL - Last modified %d:%02d:%02d ago\n"),
715 n / (60 * 60), (n / 60) % 60, n % 60);
716 }
718 free (server_date);
719 free (document_date);
720 }
721 }
723 int
724 get_content_length (const char *headers)
725 {
726 const char *s;
727 int content_length = 0;
729 s = headers;
730 while (*s) {
731 const char *field = s;
732 const char *value = 0;
734 /* Find the end of the header field */
735 while (*s && !isspace(*s) && *s != ':')
736 s++;
738 /* Remember the header value, if any. */
739 if (*s == ':')
740 value = ++s;
742 /* Skip to the end of the header, including continuation lines. */
743 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
744 s++;
745 s++;
747 /* Process this header. */
748 if (value && value > field+2) {
749 char *ff = (char *) malloc (value-field);
750 char *ss = ff;
751 while (field < value-1)
752 *ss++ = tolower(*field++);
753 *ss++ = 0;
755 if (!strcmp (ff, "content-length")) {
756 const char *e;
757 while (*value && isspace (*value))
758 value++;
759 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
760 ;
761 ss = (char *) malloc (e - value + 1);
762 strncpy (ss, value, e - value);
763 ss[e - value] = 0;
764 content_length = atoi(ss);
765 free (ss);
766 }
767 free (ff);
768 }
769 }
770 return (content_length);
771 }
773 int
774 check_http (void)
775 {
776 char *msg;
777 char *status_line;
778 char *status_code;
779 char *header;
780 char *page;
781 char *auth;
782 int http_status;
783 int i = 0;
784 size_t pagesize = 0;
785 char *full_page;
786 char *buf;
787 char *pos;
788 long microsec;
789 double elapsed_time;
790 int page_len = 0;
791 #ifdef HAVE_SSL
792 int sslerr;
793 #endif
795 /* try to connect to the host at the given port number */
796 #ifdef HAVE_SSL
797 if (use_ssl == TRUE) {
799 if (connect_SSL () != OK) {
800 die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
801 }
803 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
804 X509_free (server_cert);
805 }
806 else {
807 printf (_("CRITICAL - Cannot retrieve server certificate.\n"));
808 return STATE_CRITICAL;
809 }
811 }
812 else {
813 #endif
814 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
815 die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
816 #ifdef HAVE_SSL
817 }
818 #endif
820 asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
822 /* optionally send the host header info */
823 if (host_name)
824 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
826 /* optionally send any other header tag */
827 if (http_opt_headers) {
828 for ((pos = strtok(http_opt_headers, INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
829 asprintf (&buf, "%s%s\r\n", buf, pos);
830 }
832 /* optionally send the authentication info */
833 if (strlen(user_auth)) {
834 auth = base64 (user_auth, strlen (user_auth));
835 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
836 }
838 /* either send http POST data */
839 if (http_post_data) {
840 if (http_content_type) {
841 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
842 } else {
843 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
844 }
846 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, strlen (http_post_data));
847 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
848 }
849 else {
850 /* or just a newline so the server knows we're done with the request */
851 asprintf (&buf, "%s%s", buf, CRLF);
852 }
854 if (verbose)
855 printf ("%s\n", buf);
857 #ifdef HAVE_SSL
858 if (use_ssl == TRUE) {
859 if (SSL_write (ssl, buf, (int)strlen(buf)) == -1) {
860 ERR_print_errors_fp (stderr);
861 return STATE_CRITICAL;
862 }
863 }
864 else {
865 #endif
866 send (sd, buf, strlen (buf), 0);
867 #ifdef HAVE_SSL
868 }
869 #endif
871 /* fetch the page */
872 full_page = strdup("");
873 while ((i = my_recv ()) > 0) {
874 buffer[i] = '\0';
875 asprintf (&full_page, "%s%s", full_page, buffer);
876 pagesize += i;
878 if (no_body && document_headers_done (full_page)) {
879 i = 0;
880 break;
881 }
882 }
884 if (i < 0 && errno != ECONNRESET) {
885 #ifdef HAVE_SSL
886 if (use_ssl) {
887 sslerr=SSL_get_error(ssl, i);
888 if ( sslerr == SSL_ERROR_SSL ) {
889 die (STATE_WARNING, _("Client Certificate Required\n"));
890 } else {
891 die (STATE_CRITICAL, _("Error on receive\n"));
892 }
893 }
894 else {
895 #endif
896 die (STATE_CRITICAL, _("Error on receive\n"));
897 #ifdef HAVE_SSL
898 }
899 #endif
900 }
902 /* return a CRITICAL status if we couldn't read any data */
903 if (pagesize == (size_t) 0)
904 die (STATE_CRITICAL, _("No data received %s\n"), timestamp);
906 /* close the connection */
907 my_close ();
909 /* reset the alarm */
910 alarm (0);
912 /* leave full_page untouched so we can free it later */
913 page = full_page;
915 if (verbose)
916 printf ("%s://%s:%d%s is %d characters\n",
917 use_ssl ? "https" : "http", server_address,
918 server_port, server_url, pagesize);
920 /* find status line and null-terminate it */
921 status_line = page;
922 page += (size_t) strcspn (page, "\r\n");
923 pos = page;
924 page += (size_t) strspn (page, "\r\n");
925 status_line[strcspn(status_line, "\r\n")] = 0;
926 strip (status_line);
927 if (verbose)
928 printf ("STATUS: %s\n", status_line);
930 /* find header info and null-terminate it */
931 header = page;
932 while (strcspn (page, "\r\n") > 0) {
933 page += (size_t) strcspn (page, "\r\n");
934 pos = page;
935 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
936 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
937 page += (size_t) 2;
938 else
939 page += (size_t) 1;
940 }
941 page += (size_t) strspn (page, "\r\n");
942 header[pos - header] = 0;
943 if (verbose)
944 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
945 (no_body ? " [[ skipped ]]" : page));
947 /* make sure the status line matches the response we are looking for */
948 if (!strstr (status_line, server_expect)) {
949 if (server_port == HTTP_PORT)
950 asprintf (&msg,
951 _("Invalid HTTP response received from host\n"));
952 else
953 asprintf (&msg,
954 _("Invalid HTTP response received from host on port %d\n"),
955 server_port);
956 die (STATE_CRITICAL, "%s", msg);
957 }
959 /* Exit here if server_expect was set by user and not default */
960 if ( server_expect_yn ) {
961 asprintf (&msg,
962 _("HTTP OK: Status line output matched \"%s\"\n"),
963 server_expect);
964 if (verbose)
965 printf ("%s\n",msg);
966 }
967 else {
968 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
969 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
970 /* Status-Code = 3 DIGITS */
972 status_code = strchr (status_line, ' ') + sizeof (char);
973 if (strspn (status_code, "1234567890") != 3)
974 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
976 http_status = atoi (status_code);
978 /* check the return code */
980 if (http_status >= 600 || http_status < 100)
981 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
983 /* server errors result in a critical state */
984 else if (http_status >= 500)
985 die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
987 /* client errors result in a warning state */
988 else if (http_status >= 400)
989 die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
991 /* check redirected page if specified */
992 else if (http_status >= 300) {
994 if (onredirect == STATE_DEPENDENT)
995 redir (header, status_line);
996 else if (onredirect == STATE_UNKNOWN)
997 printf (_("UNKNOWN"));
998 else if (onredirect == STATE_OK)
999 printf (_("OK"));
1000 else if (onredirect == STATE_WARNING)
1001 printf (_("WARNING"));
1002 else if (onredirect == STATE_CRITICAL)
1003 printf (_("CRITICAL"));
1004 microsec = deltime (tv);
1005 elapsed_time = (double)microsec / 1.0e6;
1006 die (onredirect,
1007 _(" - %s - %.3f second response time %s%s|%s %s\n"),
1008 status_line, elapsed_time, timestamp,
1009 (display_html ? "</A>" : ""),
1010 perfd_time (elapsed_time), perfd_size (pagesize));
1011 } /* end if (http_status >= 300) */
1013 } /* end else (server_expect_yn) */
1015 if (maximum_age >= 0) {
1016 check_document_dates (header);
1017 }
1019 /* check elapsed time */
1020 microsec = deltime (tv);
1021 elapsed_time = (double)microsec / 1.0e6;
1022 asprintf (&msg,
1023 _("HTTP WARNING: %s - %.3f second response time %s%s|%s %s\n"),
1024 status_line, elapsed_time, timestamp,
1025 (display_html ? "</A>" : ""),
1026 perfd_time (elapsed_time), perfd_size (pagesize));
1027 if (check_critical_time == TRUE && elapsed_time > critical_time)
1028 die (STATE_CRITICAL, "%s", msg);
1029 if (check_warning_time == TRUE && elapsed_time > warning_time)
1030 die (STATE_WARNING, "%s", msg);
1032 /* Page and Header content checks go here */
1033 /* these checks should be last */
1035 if (strlen (string_expect)) {
1036 if (strstr (page, string_expect)) {
1037 printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
1038 status_line, elapsed_time,
1039 timestamp, (display_html ? "</A>" : ""),
1040 perfd_time (elapsed_time), perfd_size (pagesize));
1041 exit (STATE_OK);
1042 }
1043 else {
1044 printf (_("CRITICAL - string not found%s|%s %s\n"),
1045 (display_html ? "</A>" : ""),
1046 perfd_time (elapsed_time), perfd_size (pagesize));
1047 exit (STATE_CRITICAL);
1048 }
1049 }
1050 #ifdef HAVE_REGEX_H
1051 if (strlen (regexp)) {
1052 errcode = regexec (&preg, page, REGS, pmatch, 0);
1053 if (errcode == 0) {
1054 printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
1055 status_line, elapsed_time,
1056 timestamp, (display_html ? "</A>" : ""),
1057 perfd_time (elapsed_time), perfd_size (pagesize));
1058 exit (STATE_OK);
1059 }
1060 else {
1061 if (errcode == REG_NOMATCH) {
1062 printf (_("CRITICAL - pattern not found%s|%s %s\n"),
1063 (display_html ? "</A>" : ""),
1064 perfd_time (elapsed_time), perfd_size (pagesize));
1065 exit (STATE_CRITICAL);
1066 }
1067 else {
1068 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1069 printf (_("CRITICAL - Execute Error: %s\n"), errbuf);
1070 exit (STATE_CRITICAL);
1071 }
1072 }
1073 }
1074 #endif
1076 /* make sure the page is of an appropriate size */
1077 /* page_len = get_content_length(header); */
1078 page_len = pagesize;
1079 if ((max_page_len > 0) && (page_len > max_page_len)) {
1080 printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1081 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1082 exit (STATE_WARNING);
1083 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1084 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1085 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1086 exit (STATE_WARNING);
1087 }
1088 /* We only get here if all tests have been passed */
1089 asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s%s|%s %s\n"),
1090 status_line, page_len, elapsed_time,
1091 timestamp, (display_html ? "</A>" : ""),
1092 perfd_time (elapsed_time), perfd_size (page_len));
1093 die (STATE_OK, "%s", msg);
1094 return STATE_UNKNOWN;
1095 }
1099 /* per RFC 2396 */
1100 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1101 #define URI_HTTP "%[HTPShtps]://"
1102 #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1103 #define URI_PORT ":%[0123456789]"
1104 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1105 #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
1106 #define HD2 URI_HTTP URI_HOST URI_PATH
1107 #define HD3 URI_HTTP URI_HOST URI_PORT
1108 #define HD4 URI_HTTP URI_HOST
1109 #define HD5 URI_PATH
1111 void
1112 redir (char *pos, char *status_line)
1113 {
1114 int i = 0;
1115 char *x;
1116 char xx[2];
1117 char type[6];
1118 char *addr;
1119 char port[6];
1120 char *url;
1122 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1123 if (addr == NULL)
1124 die (STATE_UNKNOWN, _("Could not allocate addr\n"));
1126 url = malloc (strcspn (pos, "\r\n"));
1127 if (url == NULL)
1128 die (STATE_UNKNOWN, _("Could not allocate url\n"));
1130 while (pos) {
1132 if (sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i) < 1) {
1134 pos += (size_t) strcspn (pos, "\r\n");
1135 pos += (size_t) strspn (pos, "\r\n");
1136 if (strlen(pos) == 0)
1137 die (STATE_UNKNOWN,
1138 _("UNKNOWN - Could not find redirect location - %s%s\n"),
1139 status_line, (display_html ? "</A>" : ""));
1140 continue;
1141 }
1143 pos += i;
1144 pos += strspn (pos, " \t\r\n");
1146 url = realloc (url, strcspn (pos, "\r\n"));
1147 if (url == NULL)
1148 die (STATE_UNKNOWN, _("could not allocate url\n"));
1150 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1151 if (sscanf (pos, HD1, type, addr, port, url) == 4) {
1152 use_ssl = server_type_check (type);
1153 i = atoi (port);
1154 }
1156 /* URI_HTTP URI_HOST URI_PATH */
1157 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1158 use_ssl = server_type_check (type);
1159 i = server_port_check (use_ssl);
1160 }
1162 /* URI_HTTP URI_HOST URI_PORT */
1163 else if(sscanf (pos, HD3, type, addr, port) == 3) {
1164 strcpy (url, HTTP_URL);
1165 use_ssl = server_type_check (type);
1166 i = atoi (port);
1167 }
1169 /* URI_HTTP URI_HOST */
1170 else if(sscanf (pos, HD4, type, addr) == 2) {
1171 strcpy (url, HTTP_URL);
1172 use_ssl = server_type_check (type);
1173 i = server_port_check (use_ssl);
1174 }
1176 /* URI_PATH */
1177 else if (sscanf (pos, HD5, url) == 1) {
1178 /* relative url */
1179 if ((url[0] != '/')) {
1180 if ((x = strrchr(server_url, '/')))
1181 *x = '\0';
1182 asprintf (&url, "%s/%s", server_url, url);
1183 }
1184 i = server_port;
1185 strcpy (type, server_type);
1186 strcpy (addr, host_name);
1187 }
1189 else {
1190 die (STATE_UNKNOWN,
1191 _("UNKNOWN - Could not parse redirect location - %s%s\n"),
1192 pos, (display_html ? "</A>" : ""));
1193 }
1195 break;
1197 } /* end while (pos) */
1199 if (++redir_depth > max_depth)
1200 die (STATE_WARNING,
1201 _("WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1202 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1204 if (server_port==i &&
1205 !strcmp(server_address, addr) &&
1206 (host_name && !strcmp(host_name, addr)) &&
1207 !strcmp(server_url, url))
1208 die (STATE_WARNING,
1209 _("WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1210 type, addr, i, url, (display_html ? "</A>" : ""));
1212 server_port = i;
1213 strcpy (server_type, type);
1215 free (host_name);
1216 host_name = strdup (addr);
1218 free (server_address);
1219 server_address = strdup (addr);
1221 free (server_url);
1222 server_url = strdup (url);
1224 check_http ();
1225 }
1229 int
1230 server_type_check (const char *type)
1231 {
1232 if (strcmp (type, "https"))
1233 return FALSE;
1234 else
1235 return TRUE;
1236 }
1238 int
1239 server_port_check (int ssl_flag)
1240 {
1241 if (ssl_flag)
1242 return HTTPS_PORT;
1243 else
1244 return HTTP_PORT;
1245 }
1249 #ifdef HAVE_SSL
1250 int connect_SSL (void)
1251 {
1252 SSL_METHOD *meth;
1254 asprintf (&randbuff, "%s", "qwertyuiopasdfghjklqwertyuiopasdfghjkl");
1255 RAND_seed (randbuff, (int)strlen(randbuff));
1256 if (verbose)
1257 printf(_("SSL seeding: %s\n"), (RAND_status()==1 ? _("OK") : _("Failed")) );
1259 /* Initialize SSL context */
1260 SSLeay_add_ssl_algorithms ();
1261 meth = SSLv23_client_method ();
1262 SSL_load_error_strings ();
1263 if ((ctx = SSL_CTX_new (meth)) == NULL) {
1264 printf (_("CRITICAL - Cannot create SSL context.\n"));
1265 return STATE_CRITICAL;
1266 }
1268 /* Initialize alarm signal handling */
1269 signal (SIGALRM, socket_timeout_alarm_handler);
1271 /* Set socket timeout */
1272 alarm (socket_timeout);
1274 /* Save start time */
1275 gettimeofday (&tv, NULL);
1277 /* Make TCP connection */
1278 if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK) {
1279 /* Do the SSL handshake */
1280 if ((ssl = SSL_new (ctx)) != NULL) {
1281 SSL_set_cipher_list(ssl, "ALL");
1282 SSL_set_fd (ssl, sd);
1283 if (SSL_connect (ssl) != -1)
1284 return OK;
1285 ERR_print_errors_fp (stderr);
1286 }
1287 else {
1288 printf (_("CRITICAL - Cannot initiate SSL handshake.\n"));
1289 }
1290 SSL_free (ssl);
1291 }
1293 SSL_CTX_free (ctx);
1294 close (sd);
1296 return STATE_CRITICAL;
1297 }
1298 #endif
1302 #ifdef HAVE_SSL
1303 int
1304 check_certificate (X509 ** certificate)
1305 {
1306 ASN1_STRING *tm;
1307 int offset;
1308 struct tm stamp;
1309 int days_left;
1312 /* Retrieve timestamp of certificate */
1313 tm = X509_get_notAfter (*certificate);
1315 /* Generate tm structure to process timestamp */
1316 if (tm->type == V_ASN1_UTCTIME) {
1317 if (tm->length < 10) {
1318 printf (_("CRITICAL - Wrong time format in certificate.\n"));
1319 return STATE_CRITICAL;
1320 }
1321 else {
1322 stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
1323 if (stamp.tm_year < 50)
1324 stamp.tm_year += 100;
1325 offset = 0;
1326 }
1327 }
1328 else {
1329 if (tm->length < 12) {
1330 printf (_("CRITICAL - Wrong time format in certificate.\n"));
1331 return STATE_CRITICAL;
1332 }
1333 else {
1334 stamp.tm_year =
1335 (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
1336 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
1337 stamp.tm_year -= 1900;
1338 offset = 2;
1339 }
1340 }
1341 stamp.tm_mon =
1342 (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
1343 stamp.tm_mday =
1344 (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
1345 stamp.tm_hour =
1346 (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
1347 stamp.tm_min =
1348 (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
1349 stamp.tm_sec = 0;
1350 stamp.tm_isdst = -1;
1352 days_left = (mktime (&stamp) - time (NULL)) / 86400;
1353 snprintf
1354 (timestamp, 17, "%02d/%02d/%04d %02d:%02d",
1355 stamp.tm_mon + 1,
1356 stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_hour, stamp.tm_min);
1358 if (days_left > 0 && days_left <= days_till_exp) {
1359 printf (_("WARNING - Certificate expires in %d day(s) (%s).\n"), days_left, timestamp);
1360 return STATE_WARNING;
1361 }
1362 if (days_left < 0) {
1363 printf (_("CRITICAL - Certificate expired on %s.\n"), timestamp);
1364 return STATE_CRITICAL;
1365 }
1367 if (days_left == 0) {
1368 printf (_("WARNING - Certificate expires today (%s).\n"), timestamp);
1369 return STATE_WARNING;
1370 }
1372 printf (_("OK - Certificate will expire on %s.\n"), timestamp);
1374 return STATE_OK;
1375 }
1376 #endif
1380 char *perfd_time (double elapsed_time)
1381 {
1382 return fperfdata ("time", elapsed_time, "s",
1383 check_warning_time, warning_time,
1384 check_critical_time, critical_time,
1385 TRUE, 0, FALSE, 0);
1386 }
1390 char *perfd_size (int page_len)
1391 {
1392 return perfdata ("size", page_len, "B",
1393 (min_page_len>0?TRUE:FALSE), min_page_len,
1394 (min_page_len>0?TRUE:FALSE), 0,
1395 TRUE, 0, FALSE, 0);
1396 }
1400 int
1401 my_recv (void)
1402 {
1403 int i;
1404 #ifdef HAVE_SSL
1405 if (use_ssl) {
1406 i = SSL_read (ssl, buffer, MAX_INPUT_BUFFER - 1);
1407 }
1408 else {
1409 i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1410 }
1411 #else
1412 i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1413 #endif
1414 return i;
1415 }
1419 int
1420 my_close (void)
1421 {
1422 #ifdef HAVE_SSL
1423 if (use_ssl == TRUE) {
1424 SSL_shutdown (ssl);
1425 SSL_free (ssl);
1426 SSL_CTX_free (ctx);
1427 return 0;
1428 }
1429 else {
1430 #endif
1431 return close (sd);
1432 #ifdef HAVE_SSL
1433 }
1434 #endif
1435 }
1439 void
1440 print_help (void)
1441 {
1442 print_revision (progname, revision);
1444 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1445 printf (COPYRIGHT, copyright, email);
1447 printf (_("\
1448 This plugin tests the HTTP service on the specified host. It can test\n\
1449 normal (http) and secure (https) servers, follow redirects, search for\n\
1450 strings and regular expressions, check connection times, and report on\n\
1451 certificate expiration times.\n\n"));
1453 print_usage ();
1455 printf (_("NOTE: One or both of -H and -I must be specified\n"));
1457 printf (_(UT_HELP_VRSN));
1459 printf (_("\
1460 -H, --hostname=ADDRESS\n\
1461 Host name argument for servers using host headers (virtual host)\n\
1462 Append a port to include it in the header (eg: example.com:5000)\n\
1463 -I, --IP-address=ADDRESS\n\
1464 IP address or name (use numeric address if possible to bypass DNS lookup).\n\
1465 -p, --port=INTEGER\n\
1466 Port number (default: %d)\n"), HTTP_PORT);
1468 printf (_(UT_IPv46));
1470 #ifdef HAVE_SSL
1471 printf (_("\
1472 -S, --ssl\n\
1473 Connect via SSL\n\
1474 -C, --certificate=INTEGER\n\
1475 Minimum number of days a certificate has to be valid.\n\
1476 (when this option is used the url is not checked.)\n"));
1477 #endif
1479 printf (_("\
1480 -e, --expect=STRING\n\
1481 String to expect in first (status) line of server response (default: %s)\n\
1482 If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)\n\
1483 -s, --string=STRING\n\
1484 String to expect in the content\n\
1485 -u, --url=PATH\n\
1486 URL to GET or POST (default: /)\n\
1487 -P, --post=STRING\n\
1488 URL encoded http POST data\n\
1489 -N, --no-body\n\
1490 Don't wait for document body: stop reading after headers.\n\
1491 (Note that this still does an HTTP GET or POST, not a HEAD.)\n\
1492 -M, --max-age=SECONDS\n\
1493 Warn if document is more than SECONDS old. the number can also be of \n\
1494 the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.\n\
1495 -T, --content-type=STRING\n\
1496 specify Content-Type header media type when POSTing\n"), HTTP_EXPECT);
1498 #ifdef HAVE_REGEX_H
1499 printf (_("\
1500 -l, --linespan\n\
1501 Allow regex to span newlines (must precede -r or -R)\n\
1502 -r, --regex, --ereg=STRING\n\
1503 Search page for regex STRING\n\
1504 -R, --eregi=STRING\n\
1505 Search page for case-insensitive regex STRING\n"));
1506 #endif
1508 printf (_("\
1509 -a, --authorization=AUTH_PAIR\n\
1510 Username:password on sites with basic authentication\n\
1511 -A, --useragent=STRING\n\
1512 String to be sent in http header as \"User Agent\"\n\
1513 -k, --header=STRING\n\
1514 Any other tags to be sent in http header, separated by semicolon\n\
1515 -L, --link=URL\n\
1516 Wrap output in HTML link (obsoleted by urlize)\n\
1517 -f, --onredirect=<ok|warning|critical|follow>\n\
1518 How to handle redirected pages\n\
1519 -m, --pagesize=INTEGER<:INTEGER>\n\
1520 Minimum page size required (bytes) : Maximum page size required (bytes)\n"));
1522 printf (_(UT_WARN_CRIT));
1524 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1526 printf (_(UT_VERBOSE));
1528 printf (_("\
1529 This plugin will attempt to open an HTTP connection with the host. Successful\n\
1530 connects return STATE_OK, refusals and timeouts return STATE_CRITICAL, other\n\
1531 errors return STATE_UNKNOWN. Successful connects, but incorrect reponse\n\
1532 messages from the host result in STATE_WARNING return values. If you are\n\
1533 checking a virtual server that uses 'host headers' you must supply the FQDN\n\
1534 (fully qualified domain name) as the [host_name] argument.\n"));
1536 #ifdef HAVE_SSL
1537 printf (_("\n\
1538 This plugin can also check whether an SSL enabled web server is able to\n\
1539 serve content (optionally within a specified time) or whether the X509 \n\
1540 certificate is still valid for the specified number of days.\n"));
1541 printf (_("\n\
1542 CHECK CONTENT: check_http -w 5 -c 10 --ssl www.verisign.com\n\n\
1543 When the 'www.verisign.com' server returns its content within 5 seconds, a\n\
1544 STATE_OK will be returned. When the server returns its content but exceeds\n\
1545 the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,\n\
1546 a STATE_CRITICAL will be returned.\n\n"));
1548 printf (_("\
1549 CHECK CERTIFICATE: check_http www.verisign.com -C 14\n\n\
1550 When the certificate of 'www.verisign.com' is valid for more than 14 days, a\n\
1551 STATE_OK is returned. When the certificate is still valid, but for less than\n\
1552 14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when\n\
1553 the certificate is expired.\n"));
1554 #endif
1556 printf (_(UT_SUPPORT));
1558 }
1562 void
1563 print_usage (void)
1564 {
1565 printf ("\
1566 Usage: %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n\
1567 [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\
1568 [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\
1569 [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\
1570 [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] \n\
1571 [-M <age>] [-A string] [-k string]\n", progname);
1572 }