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