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 redir_depth = 0;
118 int max_depth = 15;
119 char *http_method;
120 char *http_post_data;
121 char *http_content_type;
122 char buffer[MAX_INPUT_BUFFER];
124 int process_arguments (int, char **);
125 static char *base64 (const char *bin, size_t len);
126 int check_http (void);
127 void redir (char *pos, char *status_line);
128 int server_type_check(const char *type);
129 int server_port_check(int ssl_flag);
130 char *perfd_time (double microsec);
131 char *perfd_size (int page_len);
132 int my_recv (void);
133 int my_close (void);
134 void print_help (void);
135 void print_usage (void);
137 int
138 main (int argc, char **argv)
139 {
140 int result = STATE_UNKNOWN;
142 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
143 server_url = strdup(HTTP_URL);
144 server_url_length = strlen(server_url);
145 asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
146 clean_revstring (revision), VERSION);
148 if (process_arguments (argc, argv) == ERROR)
149 usage4 (_("Could not parse arguments"));
151 if (strstr (timestamp, ":")) {
152 if (strstr (server_url, "?"))
153 asprintf (&server_url, "%s&%s", server_url, timestamp);
154 else
155 asprintf (&server_url, "%s?%s", server_url, timestamp);
156 }
158 if (display_html == TRUE)
159 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
160 use_ssl ? "https" : "http", host_name,
161 server_port, server_url);
163 /* initialize alarm signal handling, set socket timeout, start timer */
164 (void) signal (SIGALRM, socket_timeout_alarm_handler);
165 (void) alarm (socket_timeout);
166 gettimeofday (&tv, NULL);
168 #ifdef HAVE_SSL
169 if (use_ssl && check_cert == TRUE) {
170 if (connect_SSL () != OK)
171 die (STATE_CRITICAL, _("HTTP CRITICAL - Could not make SSL connection\n"));
172 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
173 result = check_certificate (&server_cert);
174 X509_free (server_cert);
175 }
176 else {
177 printf (_("CRITICAL - Cannot retrieve server certificate.\n"));
178 result = STATE_CRITICAL;
179 }
180 SSL_shutdown (ssl);
181 SSL_free (ssl);
182 SSL_CTX_free (ctx);
183 close (sd);
184 }
185 else {
186 result = check_http ();
187 }
188 #else
189 result = check_http ();
190 #endif
191 return result;
192 }
196 /* process command-line arguments */
197 int
198 process_arguments (int argc, char **argv)
199 {
200 int c = 1;
202 int option = 0;
203 static struct option longopts[] = {
204 STD_LONG_OPTS,
205 {"file",required_argument,0,'F'},
206 {"link", no_argument, 0, 'L'},
207 {"nohtml", no_argument, 0, 'n'},
208 {"ssl", no_argument, 0, 'S'},
209 {"verbose", no_argument, 0, 'v'},
210 {"post", required_argument, 0, 'P'},
211 {"IP-address", required_argument, 0, 'I'},
212 {"url", required_argument, 0, 'u'},
213 {"string", required_argument, 0, 's'},
214 {"regex", required_argument, 0, 'r'},
215 {"ereg", required_argument, 0, 'r'},
216 {"eregi", required_argument, 0, 'R'},
217 {"linespan", no_argument, 0, 'l'},
218 {"onredirect", required_argument, 0, 'f'},
219 {"certificate", required_argument, 0, 'C'},
220 {"useragent", required_argument, 0, 'A'},
221 {"header", required_argument, 0, 'k'},
222 {"no-body", no_argument, 0, 'N'},
223 {"max-age", required_argument, 0, 'M'},
224 {"content-type", required_argument, 0, 'T'},
225 {"min", required_argument, 0, 'm'},
226 {"use-ipv4", no_argument, 0, '4'},
227 {"use-ipv6", no_argument, 0, '6'},
228 {0, 0, 0, 0}
229 };
231 if (argc < 2)
232 return ERROR;
234 for (c = 1; c < argc; c++) {
235 if (strcmp ("-to", argv[c]) == 0)
236 strcpy (argv[c], "-t");
237 if (strcmp ("-hn", argv[c]) == 0)
238 strcpy (argv[c], "-H");
239 if (strcmp ("-wt", argv[c]) == 0)
240 strcpy (argv[c], "-w");
241 if (strcmp ("-ct", argv[c]) == 0)
242 strcpy (argv[c], "-c");
243 if (strcmp ("-nohtml", argv[c]) == 0)
244 strcpy (argv[c], "-n");
245 }
247 while (1) {
248 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);
249 if (c == -1 || c == EOF)
250 break;
252 switch (c) {
253 case '?': /* usage */
254 usage2 (_("Unknown argument"), optarg);
255 break;
256 case 'h': /* help */
257 print_help ();
258 exit (STATE_OK);
259 break;
260 case 'V': /* version */
261 print_revision (progname, revision);
262 exit (STATE_OK);
263 break;
264 case 't': /* timeout period */
265 if (!is_intnonneg (optarg))
266 usage2 (_("Timeout interval must be a positive integer"), optarg);
267 else
268 socket_timeout = atoi (optarg);
269 break;
270 case 'c': /* critical time threshold */
271 if (!is_nonnegative (optarg))
272 usage2 (_("Critical threshold must be integer"), optarg);
273 else {
274 critical_time = strtod (optarg, NULL);
275 check_critical_time = TRUE;
276 }
277 break;
278 case 'w': /* warning time threshold */
279 if (!is_nonnegative (optarg))
280 usage2 (_("Warning threshold must be integer"), optarg);
281 else {
282 warning_time = strtod (optarg, NULL);
283 check_warning_time = TRUE;
284 }
285 break;
286 case 'A': /* User Agent String */
287 asprintf (&user_agent, "User-Agent: %s", optarg);
288 break;
289 case 'k': /* Additional headers */
290 asprintf (&http_opt_headers, "%s", optarg);
291 break;
292 case 'L': /* show html link */
293 display_html = TRUE;
294 break;
295 case 'n': /* do not show html link */
296 display_html = FALSE;
297 break;
298 case 'S': /* use SSL */
299 #ifndef HAVE_SSL
300 usage4 (_("Invalid option - SSL is not available"));
301 #endif
302 use_ssl = TRUE;
303 if (specify_port == FALSE)
304 server_port = HTTPS_PORT;
305 break;
306 case 'C': /* Check SSL cert validity */
307 #ifdef HAVE_SSL
308 if (!is_intnonneg (optarg))
309 usage2 (_("Invalid certificate expiration period"), optarg);
310 else {
311 days_till_exp = atoi (optarg);
312 check_cert = TRUE;
313 }
314 #else
315 usage4 (_("Invalid option - SSL is not available"));
316 #endif
317 break;
318 case 'f': /* onredirect */
319 if (!strcmp (optarg, "follow"))
320 onredirect = STATE_DEPENDENT;
321 if (!strcmp (optarg, "unknown"))
322 onredirect = STATE_UNKNOWN;
323 if (!strcmp (optarg, "ok"))
324 onredirect = STATE_OK;
325 if (!strcmp (optarg, "warning"))
326 onredirect = STATE_WARNING;
327 if (!strcmp (optarg, "critical"))
328 onredirect = STATE_CRITICAL;
329 if (verbose)
330 printf(_("option f:%d \n"), onredirect);
331 break;
332 /* Note: H, I, and u must be malloc'd or will fail on redirects */
333 case 'H': /* Host Name (virtual host) */
334 host_name = strdup (optarg);
335 if (strstr (optarg, ":"))
336 sscanf (optarg, "%*[^:]:%d", &server_port);
337 break;
338 case 'I': /* Server IP-address */
339 server_address = strdup (optarg);
340 break;
341 case 'u': /* URL path */
342 server_url = strdup (optarg);
343 server_url_length = strlen (server_url);
344 break;
345 case 'p': /* Server port */
346 if (!is_intnonneg (optarg))
347 usage2 (_("Invalid port number"), optarg);
348 else {
349 server_port = atoi (optarg);
350 specify_port = TRUE;
351 }
352 break;
353 case 'a': /* authorization info */
354 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
355 user_auth[MAX_INPUT_BUFFER - 1] = 0;
356 break;
357 case 'P': /* HTTP POST data in URL encoded format */
358 if (http_method || http_post_data) break;
359 http_method = strdup("POST");
360 http_post_data = strdup (optarg);
361 break;
362 case 's': /* string or substring */
363 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
364 string_expect[MAX_INPUT_BUFFER - 1] = 0;
365 break;
366 case 'e': /* string or substring */
367 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
368 server_expect[MAX_INPUT_BUFFER - 1] = 0;
369 server_expect_yn = 1;
370 break;
371 case 'T': /* Content-type */
372 asprintf (&http_content_type, "%s", optarg);
373 break;
374 #ifndef HAVE_REGEX_H
375 case 'l': /* linespan */
376 case 'r': /* linespan */
377 case 'R': /* linespan */
378 usage4 (_("Call for regex which was not a compiled option"));
379 break;
380 #else
381 case 'l': /* linespan */
382 cflags &= ~REG_NEWLINE;
383 break;
384 case 'R': /* regex */
385 cflags |= REG_ICASE;
386 case 'r': /* regex */
387 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
388 regexp[MAX_RE_SIZE - 1] = 0;
389 errcode = regcomp (&preg, regexp, cflags);
390 if (errcode != 0) {
391 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
392 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
393 return ERROR;
394 }
395 break;
396 #endif
397 case '4':
398 address_family = AF_INET;
399 break;
400 case '6':
401 #ifdef USE_IPV6
402 address_family = AF_INET6;
403 #else
404 usage4 (_("IPv6 support not available"));
405 #endif
406 break;
407 case 'v': /* verbose */
408 verbose = TRUE;
409 break;
410 case 'm': /* min_page_length */
411 min_page_len = atoi (optarg);
412 break;
413 case 'N': /* no-body */
414 no_body = TRUE;
415 break;
416 case 'M': /* max-age */
417 {
418 int L = strlen(optarg);
419 if (L && optarg[L-1] == 'm')
420 maximum_age = atoi (optarg) * 60;
421 else if (L && optarg[L-1] == 'h')
422 maximum_age = atoi (optarg) * 60 * 60;
423 else if (L && optarg[L-1] == 'd')
424 maximum_age = atoi (optarg) * 60 * 60 * 24;
425 else if (L && (optarg[L-1] == 's' ||
426 isdigit (optarg[L-1])))
427 maximum_age = atoi (optarg);
428 else {
429 fprintf (stderr, "unparsable max-age: %s\n", optarg);
430 exit (1);
431 }
432 }
433 break;
434 }
435 }
437 c = optind;
439 if (server_address == NULL && c < argc)
440 server_address = strdup (argv[c++]);
442 if (host_name == NULL && c < argc)
443 host_name = strdup (argv[c++]);
445 if (server_address == NULL) {
446 if (host_name == NULL)
447 usage4 (_("You must specify a server address or host name"));
448 else
449 server_address = strdup (host_name);
450 }
452 if (check_critical_time && critical_time>(double)socket_timeout)
453 socket_timeout = (int)critical_time + 1;
455 if (http_method == NULL)
456 http_method = strdup ("GET");
458 return TRUE;
459 }
463 /* written by lauri alanko */
464 static char *
465 base64 (const char *bin, size_t len)
466 {
468 char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
469 size_t i = 0, j = 0;
471 char BASE64_END = '=';
472 char base64_table[64];
473 strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
475 while (j < len - 2) {
476 buf[i++] = base64_table[bin[j] >> 2];
477 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
478 buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
479 buf[i++] = base64_table[bin[j + 2] & 63];
480 j += 3;
481 }
483 switch (len - j) {
484 case 1:
485 buf[i++] = base64_table[bin[j] >> 2];
486 buf[i++] = base64_table[(bin[j] & 3) << 4];
487 buf[i++] = BASE64_END;
488 buf[i++] = BASE64_END;
489 break;
490 case 2:
491 buf[i++] = base64_table[bin[j] >> 2];
492 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
493 buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
494 buf[i++] = BASE64_END;
495 break;
496 case 0:
497 break;
498 }
500 buf[i] = '\0';
501 return buf;
502 }
506 /* Returns 1 if we're done processing the document body; 0 to keep going */
507 static int
508 document_headers_done (char *full_page)
509 {
510 const char *body;
512 for (body = full_page; *body; body++) {
513 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
514 break;
515 }
517 if (!*body)
518 return 0; /* haven't read end of headers yet */
520 full_page[body - full_page] = 0;
521 return 1;
522 }
524 static time_t
525 parse_time_string (const char *string)
526 {
527 struct tm tm;
528 time_t t;
529 memset (&tm, 0, sizeof(tm));
531 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
533 if (isupper (string[0]) && /* Tue */
534 islower (string[1]) &&
535 islower (string[2]) &&
536 ',' == string[3] &&
537 ' ' == string[4] &&
538 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
539 isdigit (string[6]) &&
540 ' ' == string[7] &&
541 isupper (string[8]) && /* Dec */
542 islower (string[9]) &&
543 islower (string[10]) &&
544 ' ' == string[11] &&
545 isdigit (string[12]) && /* 2001 */
546 isdigit (string[13]) &&
547 isdigit (string[14]) &&
548 isdigit (string[15]) &&
549 ' ' == string[16] &&
550 isdigit (string[17]) && /* 02: */
551 isdigit (string[18]) &&
552 ':' == string[19] &&
553 isdigit (string[20]) && /* 59: */
554 isdigit (string[21]) &&
555 ':' == string[22] &&
556 isdigit (string[23]) && /* 03 */
557 isdigit (string[24]) &&
558 ' ' == string[25] &&
559 'G' == string[26] && /* GMT */
560 'M' == string[27] && /* GMT */
561 'T' == string[28]) {
563 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
564 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
565 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
566 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
567 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
568 !strncmp (string+8, "Feb", 3) ? 1 :
569 !strncmp (string+8, "Mar", 3) ? 2 :
570 !strncmp (string+8, "Apr", 3) ? 3 :
571 !strncmp (string+8, "May", 3) ? 4 :
572 !strncmp (string+8, "Jun", 3) ? 5 :
573 !strncmp (string+8, "Jul", 3) ? 6 :
574 !strncmp (string+8, "Aug", 3) ? 7 :
575 !strncmp (string+8, "Sep", 3) ? 8 :
576 !strncmp (string+8, "Oct", 3) ? 9 :
577 !strncmp (string+8, "Nov", 3) ? 10 :
578 !strncmp (string+8, "Dec", 3) ? 11 :
579 -1);
580 tm.tm_year = ((1000 * (string[12]-'0') +
581 100 * (string[13]-'0') +
582 10 * (string[14]-'0') +
583 (string[15]-'0'))
584 - 1900);
586 tm.tm_isdst = 0; /* GMT is never in DST, right? */
588 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
589 return 0;
591 /*
592 This is actually wrong: we need to subtract the local timezone
593 offset from GMT from this value. But, that's ok in this usage,
594 because we only comparing these two GMT dates against each other,
595 so it doesn't matter what time zone we parse them in.
596 */
598 t = mktime (&tm);
599 if (t == (time_t) -1) t = 0;
601 if (verbose) {
602 const char *s = string;
603 while (*s && *s != '\r' && *s != '\n')
604 fputc (*s++, stdout);
605 printf (" ==> %lu\n", (unsigned long) t);
606 }
608 return t;
610 } else {
611 return 0;
612 }
613 }
617 static void
618 check_document_dates (const char *headers)
619 {
620 const char *s;
621 char *server_date = 0;
622 char *document_date = 0;
624 s = headers;
625 while (*s) {
626 const char *field = s;
627 const char *value = 0;
629 /* Find the end of the header field */
630 while (*s && !isspace(*s) && *s != ':')
631 s++;
633 /* Remember the header value, if any. */
634 if (*s == ':')
635 value = ++s;
637 /* Skip to the end of the header, including continuation lines. */
638 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
639 s++;
640 s++;
642 /* Process this header. */
643 if (value && value > field+2) {
644 char *ff = (char *) malloc (value-field);
645 char *ss = ff;
646 while (field < value-1)
647 *ss++ = tolower(*field++);
648 *ss++ = 0;
650 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
651 const char *e;
652 while (*value && isspace (*value))
653 value++;
654 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
655 ;
656 ss = (char *) malloc (e - value + 1);
657 strncpy (ss, value, e - value);
658 ss[e - value] = 0;
659 if (!strcmp (ff, "date")) {
660 if (server_date) free (server_date);
661 server_date = ss;
662 } else {
663 if (document_date) free (document_date);
664 document_date = ss;
665 }
666 }
667 free (ff);
668 }
669 }
671 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
672 if (!server_date || !*server_date) {
673 die (STATE_UNKNOWN, _("Server date unknown\n"));
674 } else if (!document_date || !*document_date) {
675 die (STATE_CRITICAL, _("Document modification date unknown\n"));
676 } else {
677 time_t srv_data = parse_time_string (server_date);
678 time_t doc_data = parse_time_string (document_date);
680 if (srv_data <= 0) {
681 die (STATE_CRITICAL, _("CRITICAL - Server date \"%100s\" unparsable"), server_date);
682 } else if (doc_data <= 0) {
683 die (STATE_CRITICAL, _("CRITICAL - Document date \"%100s\" unparsable"), document_date);
684 } else if (doc_data > srv_data + 30) {
685 die (STATE_CRITICAL, _("CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
686 } else if (doc_data < srv_data - maximum_age) {
687 int n = (srv_data - doc_data);
688 if (n > (60 * 60 * 24 * 2))
689 die (STATE_CRITICAL,
690 _("CRITICAL - Last modified %.1f days ago\n"),
691 ((float) n) / (60 * 60 * 24));
692 else
693 die (STATE_CRITICAL,
694 _("CRITICAL - Last modified %d:%02d:%02d ago\n"),
695 n / (60 * 60), (n / 60) % 60, n % 60);
696 }
698 free (server_date);
699 free (document_date);
700 }
701 }
705 int
706 check_http (void)
707 {
708 char *msg;
709 char *status_line;
710 char *status_code;
711 char *header;
712 char *page;
713 char *auth;
714 int http_status;
715 int i = 0;
716 size_t pagesize = 0;
717 char *full_page;
718 char *buf;
719 char *pos;
720 long microsec;
721 double elapsed_time;
722 int page_len = 0;
723 #ifdef HAVE_SSL
724 int sslerr;
725 #endif
727 /* try to connect to the host at the given port number */
728 #ifdef HAVE_SSL
729 if (use_ssl == TRUE) {
731 if (connect_SSL () != OK) {
732 die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
733 }
735 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
736 X509_free (server_cert);
737 }
738 else {
739 printf (_("CRITICAL - Cannot retrieve server certificate.\n"));
740 return STATE_CRITICAL;
741 }
743 }
744 else {
745 #endif
746 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
747 die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
748 #ifdef HAVE_SSL
749 }
750 #endif
752 asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
754 /* optionally send the host header info */
755 if (host_name)
756 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
758 /* optionally send any other header tag */
759 if (http_opt_headers) {
760 for ((pos = strtok(http_opt_headers, INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
761 asprintf (&buf, "%s%s\r\n", buf, pos);
762 }
764 /* optionally send the authentication info */
765 if (strlen(user_auth)) {
766 auth = base64 (user_auth, strlen (user_auth));
767 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
768 }
770 /* either send http POST data */
771 if (http_post_data) {
772 if (http_content_type) {
773 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
774 } else {
775 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
776 }
777 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, strlen (http_post_data));
778 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
779 }
780 else {
781 /* or just a newline so the server knows we're done with the request */
782 asprintf (&buf, "%s%s", buf, CRLF);
783 }
785 if (verbose)
786 printf ("%s\n", buf);
788 #ifdef HAVE_SSL
789 if (use_ssl == TRUE) {
790 if (SSL_write (ssl, buf, (int)strlen(buf)) == -1) {
791 ERR_print_errors_fp (stderr);
792 return STATE_CRITICAL;
793 }
794 }
795 else {
796 #endif
797 send (sd, buf, strlen (buf), 0);
798 #ifdef HAVE_SSL
799 }
800 #endif
802 /* fetch the page */
803 full_page = strdup("");
804 while ((i = my_recv ()) > 0) {
805 buffer[i] = '\0';
806 asprintf (&full_page, "%s%s", full_page, buffer);
807 pagesize += i;
809 if (no_body && document_headers_done (full_page)) {
810 i = 0;
811 break;
812 }
813 }
815 if (i < 0 && errno != ECONNRESET) {
816 #ifdef HAVE_SSL
817 if (use_ssl) {
818 sslerr=SSL_get_error(ssl, i);
819 if ( sslerr == SSL_ERROR_SSL ) {
820 die (STATE_WARNING, _("Client Certificate Required\n"));
821 } else {
822 die (STATE_CRITICAL, _("Error on receive\n"));
823 }
824 }
825 else {
826 #endif
827 die (STATE_CRITICAL, _("Error on receive\n"));
828 #ifdef HAVE_SSL
829 }
830 #endif
831 }
833 /* return a CRITICAL status if we couldn't read any data */
834 if (pagesize == (size_t) 0)
835 die (STATE_CRITICAL, _("No data received %s\n"), timestamp);
837 /* close the connection */
838 my_close ();
840 /* reset the alarm */
841 alarm (0);
843 /* leave full_page untouched so we can free it later */
844 page = full_page;
846 if (verbose)
847 printf ("%s://%s:%d%s is %d characters\n",
848 use_ssl ? "https" : "http", server_address,
849 server_port, server_url, pagesize);
851 /* find status line and null-terminate it */
852 status_line = page;
853 page += (size_t) strcspn (page, "\r\n");
854 pos = page;
855 page += (size_t) strspn (page, "\r\n");
856 status_line[strcspn(status_line, "\r\n")] = 0;
857 strip (status_line);
858 if (verbose)
859 printf ("STATUS: %s\n", status_line);
861 /* find header info and null-terminate it */
862 header = page;
863 while (strcspn (page, "\r\n") > 0) {
864 page += (size_t) strcspn (page, "\r\n");
865 pos = page;
866 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
867 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
868 page += (size_t) 2;
869 else
870 page += (size_t) 1;
871 }
872 page += (size_t) strspn (page, "\r\n");
873 header[pos - header] = 0;
874 if (verbose)
875 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
876 (no_body ? " [[ skipped ]]" : page));
878 /* make sure the status line matches the response we are looking for */
879 if (!strstr (status_line, server_expect)) {
880 if (server_port == HTTP_PORT)
881 asprintf (&msg,
882 _("Invalid HTTP response received from host\n"));
883 else
884 asprintf (&msg,
885 _("Invalid HTTP response received from host on port %d\n"),
886 server_port);
887 die (STATE_CRITICAL, "%s", msg);
888 }
890 /* Exit here if server_expect was set by user and not default */
891 if ( server_expect_yn ) {
892 asprintf (&msg,
893 _("HTTP OK: Status line output matched \"%s\"\n"),
894 server_expect);
895 if (verbose)
896 printf ("%s\n",msg);
897 }
898 else {
899 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
900 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
901 /* Status-Code = 3 DIGITS */
903 status_code = strchr (status_line, ' ') + sizeof (char);
904 if (strspn (status_code, "1234567890") != 3)
905 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
907 http_status = atoi (status_code);
909 /* check the return code */
911 if (http_status >= 600 || http_status < 100)
912 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
914 /* server errors result in a critical state */
915 else if (http_status >= 500)
916 die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
918 /* client errors result in a warning state */
919 else if (http_status >= 400)
920 die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
922 /* check redirected page if specified */
923 else if (http_status >= 300) {
925 if (onredirect == STATE_DEPENDENT)
926 redir (header, status_line);
927 else if (onredirect == STATE_UNKNOWN)
928 printf (_("UNKNOWN"));
929 else if (onredirect == STATE_OK)
930 printf (_("OK"));
931 else if (onredirect == STATE_WARNING)
932 printf (_("WARNING"));
933 else if (onredirect == STATE_CRITICAL)
934 printf (_("CRITICAL"));
935 microsec = deltime (tv);
936 elapsed_time = (double)microsec / 1.0e6;
937 die (onredirect,
938 _(" - %s - %.3f second response time %s%s|%s %s\n"),
939 status_line, elapsed_time, timestamp,
940 (display_html ? "</A>" : ""),
941 perfd_time (elapsed_time), perfd_size (pagesize));
942 } /* end if (http_status >= 300) */
944 } /* end else (server_expect_yn) */
946 if (maximum_age >= 0) {
947 check_document_dates (header);
948 }
950 /* check elapsed time */
951 microsec = deltime (tv);
952 elapsed_time = (double)microsec / 1.0e6;
953 asprintf (&msg,
954 _("HTTP WARNING: %s - %.3f second response time %s%s|%s %s\n"),
955 status_line, elapsed_time, timestamp,
956 (display_html ? "</A>" : ""),
957 perfd_time (elapsed_time), perfd_size (pagesize));
958 if (check_critical_time == TRUE && elapsed_time > critical_time)
959 die (STATE_CRITICAL, "%s", msg);
960 if (check_warning_time == TRUE && elapsed_time > warning_time)
961 die (STATE_WARNING, "%s", msg);
963 /* Page and Header content checks go here */
964 /* these checks should be last */
966 if (strlen (string_expect)) {
967 if (strstr (page, string_expect)) {
968 printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
969 status_line, elapsed_time,
970 timestamp, (display_html ? "</A>" : ""),
971 perfd_time (elapsed_time), perfd_size (pagesize));
972 exit (STATE_OK);
973 }
974 else {
975 printf (_("CRITICAL - string not found%s|%s %s\n"),
976 (display_html ? "</A>" : ""),
977 perfd_time (elapsed_time), perfd_size (pagesize));
978 exit (STATE_CRITICAL);
979 }
980 }
981 #ifdef HAVE_REGEX_H
982 if (strlen (regexp)) {
983 errcode = regexec (&preg, page, REGS, pmatch, 0);
984 if (errcode == 0) {
985 printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
986 status_line, elapsed_time,
987 timestamp, (display_html ? "</A>" : ""),
988 perfd_time (elapsed_time), perfd_size (pagesize));
989 exit (STATE_OK);
990 }
991 else {
992 if (errcode == REG_NOMATCH) {
993 printf (_("CRITICAL - pattern not found%s|%s %s\n"),
994 (display_html ? "</A>" : ""),
995 perfd_time (elapsed_time), perfd_size (pagesize));
996 exit (STATE_CRITICAL);
997 }
998 else {
999 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1000 printf (_("CRITICAL - Execute Error: %s\n"), errbuf);
1001 exit (STATE_CRITICAL);
1002 }
1003 }
1004 }
1005 #endif
1007 /* make sure the page is of an appropriate size */
1008 page_len = strlen (page);
1009 if ((min_page_len > 0) && (page_len < min_page_len)) {
1010 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1011 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1012 exit (STATE_WARNING);
1013 }
1014 /* We only get here if all tests have been passed */
1015 asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s%s|%s %s\n"),
1016 status_line, page_len, elapsed_time,
1017 timestamp, (display_html ? "</A>" : ""),
1018 perfd_time (elapsed_time), perfd_size (page_len));
1019 die (STATE_OK, "%s", msg);
1020 return STATE_UNKNOWN;
1021 }
1025 /* per RFC 2396 */
1026 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1027 #define URI_HTTP "%[HTPShtps]://"
1028 #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1029 #define URI_PORT ":%[0123456789]"
1030 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1031 #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
1032 #define HD2 URI_HTTP URI_HOST URI_PATH
1033 #define HD3 URI_HTTP URI_HOST URI_PORT
1034 #define HD4 URI_HTTP URI_HOST
1035 #define HD5 URI_PATH
1037 void
1038 redir (char *pos, char *status_line)
1039 {
1040 int i = 0;
1041 char *x;
1042 char xx[2];
1043 char type[6];
1044 char *addr;
1045 char port[6];
1046 char *url;
1048 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1049 if (addr == NULL)
1050 die (STATE_UNKNOWN, _("Could not allocate addr\n"));
1052 url = malloc (strcspn (pos, "\r\n"));
1053 if (url == NULL)
1054 die (STATE_UNKNOWN, _("Could not allocate url\n"));
1056 while (pos) {
1058 if (sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i) < 1) {
1060 pos += (size_t) strcspn (pos, "\r\n");
1061 pos += (size_t) strspn (pos, "\r\n");
1062 if (strlen(pos) == 0)
1063 die (STATE_UNKNOWN,
1064 _("UNKNOWN - Could not find redirect location - %s%s\n"),
1065 status_line, (display_html ? "</A>" : ""));
1066 continue;
1067 }
1069 pos += i;
1070 pos += strspn (pos, " \t\r\n");
1072 url = realloc (url, strcspn (pos, "\r\n"));
1073 if (url == NULL)
1074 die (STATE_UNKNOWN, _("could not allocate url\n"));
1076 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1077 if (sscanf (pos, HD1, type, addr, port, url) == 4) {
1078 use_ssl = server_type_check (type);
1079 i = atoi (port);
1080 }
1082 /* URI_HTTP URI_HOST URI_PATH */
1083 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1084 use_ssl = server_type_check (type);
1085 i = server_port_check (use_ssl);
1086 }
1088 /* URI_HTTP URI_HOST URI_PORT */
1089 else if(sscanf (pos, HD3, type, addr, port) == 3) {
1090 strcpy (url, HTTP_URL);
1091 use_ssl = server_type_check (type);
1092 i = atoi (port);
1093 }
1095 /* URI_HTTP URI_HOST */
1096 else if(sscanf (pos, HD4, type, addr) == 2) {
1097 strcpy (url, HTTP_URL);
1098 use_ssl = server_type_check (type);
1099 i = server_port_check (use_ssl);
1100 }
1102 /* URI_PATH */
1103 else if (sscanf (pos, HD5, url) == 1) {
1104 /* relative url */
1105 if ((url[0] != '/')) {
1106 if ((x = strrchr(server_url, '/')))
1107 *x = '\0';
1108 asprintf (&url, "%s/%s", server_url, url);
1109 }
1110 i = server_port;
1111 strcpy (type, server_type);
1112 strcpy (addr, host_name);
1113 }
1115 else {
1116 die (STATE_UNKNOWN,
1117 _("UNKNOWN - Could not parse redirect location - %s%s\n"),
1118 pos, (display_html ? "</A>" : ""));
1119 }
1121 break;
1123 } /* end while (pos) */
1125 if (++redir_depth > max_depth)
1126 die (STATE_WARNING,
1127 _("WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1128 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1130 if (server_port==i &&
1131 !strcmp(server_address, addr) &&
1132 (host_name && !strcmp(host_name, addr)) &&
1133 !strcmp(server_url, url))
1134 die (STATE_WARNING,
1135 _("WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1136 type, addr, i, url, (display_html ? "</A>" : ""));
1138 server_port = i;
1139 strcpy (server_type, type);
1141 free (host_name);
1142 host_name = strdup (addr);
1144 free (server_address);
1145 server_address = strdup (addr);
1147 free (server_url);
1148 server_url = strdup (url);
1150 check_http ();
1151 }
1155 int
1156 server_type_check (const char *type)
1157 {
1158 if (strcmp (type, "https"))
1159 return FALSE;
1160 else
1161 return TRUE;
1162 }
1164 int
1165 server_port_check (int ssl_flag)
1166 {
1167 if (ssl_flag)
1168 return HTTPS_PORT;
1169 else
1170 return HTTP_PORT;
1171 }
1175 #ifdef HAVE_SSL
1176 int connect_SSL (void)
1177 {
1178 SSL_METHOD *meth;
1180 asprintf (&randbuff, "%s", "qwertyuiopasdfghjklqwertyuiopasdfghjkl");
1181 RAND_seed (randbuff, (int)strlen(randbuff));
1182 if (verbose)
1183 printf(_("SSL seeding: %s\n"), (RAND_status()==1 ? _("OK") : _("Failed")) );
1185 /* Initialize SSL context */
1186 SSLeay_add_ssl_algorithms ();
1187 meth = SSLv23_client_method ();
1188 SSL_load_error_strings ();
1189 if ((ctx = SSL_CTX_new (meth)) == NULL) {
1190 printf (_("CRITICAL - Cannot create SSL context.\n"));
1191 return STATE_CRITICAL;
1192 }
1194 /* Initialize alarm signal handling */
1195 signal (SIGALRM, socket_timeout_alarm_handler);
1197 /* Set socket timeout */
1198 alarm (socket_timeout);
1200 /* Save start time */
1201 gettimeofday (&tv, NULL);
1203 /* Make TCP connection */
1204 if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK) {
1205 /* Do the SSL handshake */
1206 if ((ssl = SSL_new (ctx)) != NULL) {
1207 SSL_set_cipher_list(ssl, "ALL");
1208 SSL_set_fd (ssl, sd);
1209 if (SSL_connect (ssl) != -1)
1210 return OK;
1211 ERR_print_errors_fp (stderr);
1212 }
1213 else {
1214 printf (_("CRITICAL - Cannot initiate SSL handshake.\n"));
1215 }
1216 SSL_free (ssl);
1217 }
1219 SSL_CTX_free (ctx);
1220 close (sd);
1222 return STATE_CRITICAL;
1223 }
1224 #endif
1228 #ifdef HAVE_SSL
1229 int
1230 check_certificate (X509 ** certificate)
1231 {
1232 ASN1_STRING *tm;
1233 int offset;
1234 struct tm stamp;
1235 int days_left;
1238 /* Retrieve timestamp of certificate */
1239 tm = X509_get_notAfter (*certificate);
1241 /* Generate tm structure to process timestamp */
1242 if (tm->type == V_ASN1_UTCTIME) {
1243 if (tm->length < 10) {
1244 printf (_("CRITICAL - Wrong time format in certificate.\n"));
1245 return STATE_CRITICAL;
1246 }
1247 else {
1248 stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
1249 if (stamp.tm_year < 50)
1250 stamp.tm_year += 100;
1251 offset = 0;
1252 }
1253 }
1254 else {
1255 if (tm->length < 12) {
1256 printf (_("CRITICAL - Wrong time format in certificate.\n"));
1257 return STATE_CRITICAL;
1258 }
1259 else {
1260 stamp.tm_year =
1261 (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
1262 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
1263 stamp.tm_year -= 1900;
1264 offset = 2;
1265 }
1266 }
1267 stamp.tm_mon =
1268 (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
1269 stamp.tm_mday =
1270 (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
1271 stamp.tm_hour =
1272 (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
1273 stamp.tm_min =
1274 (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
1275 stamp.tm_sec = 0;
1276 stamp.tm_isdst = -1;
1278 days_left = (mktime (&stamp) - time (NULL)) / 86400;
1279 snprintf
1280 (timestamp, 17, "%02d/%02d/%04d %02d:%02d",
1281 stamp.tm_mon + 1,
1282 stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_hour, stamp.tm_min);
1284 if (days_left > 0 && days_left <= days_till_exp) {
1285 printf (_("WARNING - Certificate expires in %d day(s) (%s).\n"), days_left, timestamp);
1286 return STATE_WARNING;
1287 }
1288 if (days_left < 0) {
1289 printf (_("CRITICAL - Certificate expired on %s.\n"), timestamp);
1290 return STATE_CRITICAL;
1291 }
1293 if (days_left == 0) {
1294 printf (_("WARNING - Certificate expires today (%s).\n"), timestamp);
1295 return STATE_WARNING;
1296 }
1298 printf (_("OK - Certificate will expire on %s.\n"), timestamp);
1300 return STATE_OK;
1301 }
1302 #endif
1306 char *perfd_time (double elapsed_time)
1307 {
1308 return fperfdata ("time", elapsed_time, "s",
1309 check_warning_time, warning_time,
1310 check_critical_time, critical_time,
1311 TRUE, 0, FALSE, 0);
1312 }
1316 char *perfd_size (int page_len)
1317 {
1318 return perfdata ("size", page_len, "B",
1319 (min_page_len>0?TRUE:FALSE), min_page_len,
1320 (min_page_len>0?TRUE:FALSE), 0,
1321 TRUE, 0, FALSE, 0);
1322 }
1326 int
1327 my_recv (void)
1328 {
1329 int i;
1330 #ifdef HAVE_SSL
1331 if (use_ssl) {
1332 i = SSL_read (ssl, buffer, MAX_INPUT_BUFFER - 1);
1333 }
1334 else {
1335 i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1336 }
1337 #else
1338 i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1339 #endif
1340 return i;
1341 }
1345 int
1346 my_close (void)
1347 {
1348 #ifdef HAVE_SSL
1349 if (use_ssl == TRUE) {
1350 SSL_shutdown (ssl);
1351 SSL_free (ssl);
1352 SSL_CTX_free (ctx);
1353 return 0;
1354 }
1355 else {
1356 #endif
1357 return close (sd);
1358 #ifdef HAVE_SSL
1359 }
1360 #endif
1361 }
1365 void
1366 print_help (void)
1367 {
1368 print_revision (progname, revision);
1370 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1371 printf (COPYRIGHT, copyright, email);
1373 printf (_("\
1374 This plugin tests the HTTP service on the specified host. It can test\n\
1375 normal (http) and secure (https) servers, follow redirects, search for\n\
1376 strings and regular expressions, check connection times, and report on\n\
1377 certificate expiration times.\n\n"));
1379 print_usage ();
1381 printf (_("NOTE: One or both of -H and -I must be specified\n"));
1383 printf (_(UT_HELP_VRSN));
1385 printf (_("\
1386 -H, --hostname=ADDRESS\n\
1387 Host name argument for servers using host headers (virtual host)\n\
1388 Append a port to include it in the header (eg: example.com:5000)\n\
1389 -I, --IP-address=ADDRESS\n\
1390 IP address or name (use numeric address if possible to bypass DNS lookup).\n\
1391 -p, --port=INTEGER\n\
1392 Port number (default: %d)\n"), HTTP_PORT);
1394 printf (_(UT_IPv46));
1396 #ifdef HAVE_SSL
1397 printf (_("\
1398 -S, --ssl\n\
1399 Connect via SSL\n\
1400 -C, --certificate=INTEGER\n\
1401 Minimum number of days a certificate has to be valid.\n\
1402 (when this option is used the url is not checked.)\n"));
1403 #endif
1405 printf (_("\
1406 -e, --expect=STRING\n\
1407 String to expect in first (status) line of server response (default: %s)\n\
1408 If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)\n\
1409 -s, --string=STRING\n\
1410 String to expect in the content\n\
1411 -u, --url=PATH\n\
1412 URL to GET or POST (default: /)\n\
1413 -P, --post=STRING\n\
1414 URL encoded http POST data\n\
1415 -N, --no-body\n\
1416 Don't wait for document body: stop reading after headers.\n\
1417 (Note that this still does an HTTP GET or POST, not a HEAD.)\n\
1418 -M, --max-age=SECONDS\n\
1419 Warn if document is more than SECONDS old. the number can also be of \n\
1420 the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.\n\
1421 -T, --content-type=STRING\n\
1422 specify Content-Type header media type when POSTing\n"), HTTP_EXPECT);
1424 #ifdef HAVE_REGEX_H
1425 printf (_("\
1426 -l, --linespan\n\
1427 Allow regex to span newlines (must precede -r or -R)\n\
1428 -r, --regex, --ereg=STRING\n\
1429 Search page for regex STRING\n\
1430 -R, --eregi=STRING\n\
1431 Search page for case-insensitive regex STRING\n"));
1432 #endif
1434 printf (_("\
1435 -a, --authorization=AUTH_PAIR\n\
1436 Username:password on sites with basic authentication\n\
1437 -A, --useragent=STRING\n\
1438 String to be sent in http header as \"User Agent\"\n\
1439 -k, --header=STRING\n\
1440 Any other tags to be sent in http header, separated by semicolon\n\
1441 -L, --link=URL\n\
1442 Wrap output in HTML link (obsoleted by urlize)\n\
1443 -f, --onredirect=<ok|warning|critical|follow>\n\
1444 How to handle redirected pages\n\
1445 -m, --min=INTEGER\n\
1446 Minimum page size required (bytes)\n"));
1448 printf (_(UT_WARN_CRIT));
1450 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1452 printf (_(UT_VERBOSE));
1454 printf (_("\
1455 This plugin will attempt to open an HTTP connection with the host. Successful\n\
1456 connects return STATE_OK, refusals and timeouts return STATE_CRITICAL, other\n\
1457 errors return STATE_UNKNOWN. Successful connects, but incorrect reponse\n\
1458 messages from the host result in STATE_WARNING return values. If you are\n\
1459 checking a virtual server that uses 'host headers' you must supply the FQDN\n\
1460 (fully qualified domain name) as the [host_name] argument.\n"));
1462 #ifdef HAVE_SSL
1463 printf (_("\n\
1464 This plugin can also check whether an SSL enabled web server is able to\n\
1465 serve content (optionally within a specified time) or whether the X509 \n\
1466 certificate is still valid for the specified number of days.\n"));
1467 printf (_("\n\
1468 CHECK CONTENT: check_http -w 5 -c 10 --ssl www.verisign.com\n\n\
1469 When the 'www.verisign.com' server returns its content within 5 seconds, a\n\
1470 STATE_OK will be returned. When the server returns its content but exceeds\n\
1471 the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,\n\
1472 a STATE_CRITICAL will be returned.\n\n"));
1474 printf (_("\
1475 CHECK CERTIFICATE: check_http www.verisign.com -C 14\n\n\
1476 When the certificate of 'www.verisign.com' is valid for more than 14 days, a\n\
1477 STATE_OK is returned. When the certificate is still valid, but for less than\n\
1478 14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when\n\
1479 the certificate is expired.\n"));
1480 #endif
1482 printf (_(UT_SUPPORT));
1484 }
1488 void
1489 print_usage (void)
1490 {
1491 printf ("\
1492 Usage: %s -H <vhost> | -I <IP-address>) [-u <uri>] [-p <port>]\n\
1493 [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\
1494 [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\
1495 [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\
1496 [-P string] [-m min_pg_size] [-4|-6] [-N] [-M <age>]\n\
1497 [-A string] [-k string]\n", progname);
1498 }