Fix INADDR_NONE value (for systems which don't define it).
[monitoring-plugins.git] / plugins / check_http.c
blobbec02e1af5af67ce2a16d32604b3ba759cc27921
1 /******************************************************************************
3 * Nagios check_http plugin
5 * License: GPL
6 * Copyright (c) 1999-2006 nagios-plugins team
8 * Last Modified: $Date$
10 * Description:
12 * This file contains the check_http plugin
14 * This plugin tests the HTTP service on the specified host. It can test
15 * normal (http) and secure (https) servers, follow redirects, search for
16 * strings and regular expressions, check connection times, and report on
17 * certificate expiration times.
20 * License Information:
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 $Id$
38 ******************************************************************************/
39 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
41 const char *progname = "check_http";
42 const char *revision = "$Revision$";
43 const char *copyright = "1999-2006";
44 const char *email = "nagiosplug-devel@lists.sourceforge.net";
46 #include <ctype.h>
48 #include "common.h"
49 #include "netutils.h"
50 #include "utils.h"
51 #include "base64.h"
53 #define INPUT_DELIMITER ";"
55 #define HTTP_EXPECT "HTTP/1."
56 enum {
57 MAX_IPV4_HOSTLENGTH = 255,
58 HTTP_PORT = 80,
59 HTTPS_PORT = 443,
60 MAX_PORT = 65535
63 #ifdef HAVE_SSL
64 int check_cert = FALSE;
65 int days_till_exp;
66 char *randbuff;
67 X509 *server_cert;
68 # define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
69 # define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
70 #else /* ifndef HAVE_SSL */
71 # define my_recv(buf, len) read(sd, buf, len)
72 # define my_send(buf, len) send(sd, buf, len, 0)
73 #endif /* HAVE_SSL */
74 int no_body = FALSE;
75 int maximum_age = -1;
77 enum {
78 REGS = 2,
79 MAX_RE_SIZE = 256
81 #include "regex.h"
82 regex_t preg;
83 regmatch_t pmatch[REGS];
84 char regexp[MAX_RE_SIZE];
85 char errbuf[MAX_INPUT_BUFFER];
86 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
87 int errcode;
88 int invert_regex = 0;
90 struct timeval tv;
92 #define HTTP_URL "/"
93 #define CRLF "\r\n"
95 int specify_port = FALSE;
96 int server_port = HTTP_PORT;
97 char server_port_text[6] = "";
98 char server_type[6] = "http";
99 char *server_address;
100 char *host_name;
101 char *server_url;
102 char *user_agent;
103 int server_url_length;
104 int server_expect_yn = 0;
105 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
106 char string_expect[MAX_INPUT_BUFFER] = "";
107 double warning_time = 0;
108 int check_warning_time = FALSE;
109 double critical_time = 0;
110 int check_critical_time = FALSE;
111 char user_auth[MAX_INPUT_BUFFER] = "";
112 int display_html = FALSE;
113 char **http_opt_headers;
114 int http_opt_headers_count = 0;
115 int onredirect = STATE_OK;
116 int use_ssl = FALSE;
117 int verbose = FALSE;
118 int sd;
119 int min_page_len = 0;
120 int max_page_len = 0;
121 int redir_depth = 0;
122 int max_depth = 15;
123 char *http_method;
124 char *http_post_data;
125 char *http_content_type;
126 char buffer[MAX_INPUT_BUFFER];
128 int process_arguments (int, char **);
129 int check_http (void);
130 void redir (char *pos, char *status_line);
131 int server_type_check(const char *type);
132 int server_port_check(int ssl_flag);
133 char *perfd_time (double microsec);
134 char *perfd_size (int page_len);
135 void print_help (void);
136 void print_usage (void);
139 main (int argc, char **argv)
141 int result = STATE_UNKNOWN;
143 setlocale (LC_ALL, "");
144 bindtextdomain (PACKAGE, LOCALEDIR);
145 textdomain (PACKAGE);
147 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
148 server_url = strdup(HTTP_URL);
149 server_url_length = strlen(server_url);
150 asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
151 clean_revstring (revision), VERSION);
153 if (process_arguments (argc, argv) == ERROR)
154 usage4 (_("Could not parse arguments"));
156 if (display_html == TRUE)
157 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
158 use_ssl ? "https" : "http", host_name ? host_name : server_address,
159 server_port, server_url);
161 /* initialize alarm signal handling, set socket timeout, start timer */
162 (void) signal (SIGALRM, socket_timeout_alarm_handler);
163 (void) alarm (socket_timeout);
164 gettimeofday (&tv, NULL);
166 result = check_http ();
167 return result;
172 /* process command-line arguments */
174 process_arguments (int argc, char **argv)
176 int c = 1;
178 enum {
179 INVERT_REGEX = CHAR_MAX + 1
182 int option = 0;
183 static struct option longopts[] = {
184 STD_LONG_OPTS,
185 {"link", no_argument, 0, 'L'},
186 {"nohtml", no_argument, 0, 'n'},
187 {"ssl", no_argument, 0, 'S'},
188 {"post", required_argument, 0, 'P'},
189 {"IP-address", required_argument, 0, 'I'},
190 {"url", required_argument, 0, 'u'},
191 {"port", required_argument, 0, 'p'},
192 {"authorization", required_argument, 0, 'a'},
193 {"string", required_argument, 0, 's'},
194 {"expect", required_argument, 0, 'e'},
195 {"regex", required_argument, 0, 'r'},
196 {"ereg", required_argument, 0, 'r'},
197 {"eregi", required_argument, 0, 'R'},
198 {"linespan", no_argument, 0, 'l'},
199 {"onredirect", required_argument, 0, 'f'},
200 {"certificate", required_argument, 0, 'C'},
201 {"useragent", required_argument, 0, 'A'},
202 {"header", required_argument, 0, 'k'},
203 {"no-body", no_argument, 0, 'N'},
204 {"max-age", required_argument, 0, 'M'},
205 {"content-type", required_argument, 0, 'T'},
206 {"pagesize", required_argument, 0, 'm'},
207 {"invert-regex", no_argument, NULL, INVERT_REGEX},
208 {"use-ipv4", no_argument, 0, '4'},
209 {"use-ipv6", no_argument, 0, '6'},
210 {0, 0, 0, 0}
213 if (argc < 2)
214 return ERROR;
216 for (c = 1; c < argc; c++) {
217 if (strcmp ("-to", argv[c]) == 0)
218 strcpy (argv[c], "-t");
219 if (strcmp ("-hn", argv[c]) == 0)
220 strcpy (argv[c], "-H");
221 if (strcmp ("-wt", argv[c]) == 0)
222 strcpy (argv[c], "-w");
223 if (strcmp ("-ct", argv[c]) == 0)
224 strcpy (argv[c], "-c");
225 if (strcmp ("-nohtml", argv[c]) == 0)
226 strcpy (argv[c], "-n");
229 while (1) {
230 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);
231 if (c == -1 || c == EOF)
232 break;
234 switch (c) {
235 case '?': /* usage */
236 usage5 ();
237 break;
238 case 'h': /* help */
239 print_help ();
240 exit (STATE_OK);
241 break;
242 case 'V': /* version */
243 print_revision (progname, revision);
244 exit (STATE_OK);
245 break;
246 case 't': /* timeout period */
247 if (!is_intnonneg (optarg))
248 usage2 (_("Timeout interval must be a positive integer"), optarg);
249 else
250 socket_timeout = atoi (optarg);
251 break;
252 case 'c': /* critical time threshold */
253 if (!is_nonnegative (optarg))
254 usage2 (_("Critical threshold must be integer"), optarg);
255 else {
256 critical_time = strtod (optarg, NULL);
257 check_critical_time = TRUE;
259 break;
260 case 'w': /* warning time threshold */
261 if (!is_nonnegative (optarg))
262 usage2 (_("Warning threshold must be integer"), optarg);
263 else {
264 warning_time = strtod (optarg, NULL);
265 check_warning_time = TRUE;
267 break;
268 case 'A': /* User Agent String */
269 asprintf (&user_agent, "User-Agent: %s", optarg);
270 break;
271 case 'k': /* Additional headers */
272 if (http_opt_headers_count == 0)
273 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
274 else
275 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
276 http_opt_headers[http_opt_headers_count - 1] = optarg;
277 /* asprintf (&http_opt_headers, "%s", optarg); */
278 break;
279 case 'L': /* show html link */
280 display_html = TRUE;
281 break;
282 case 'n': /* do not show html link */
283 display_html = FALSE;
284 break;
285 case 'C': /* Check SSL cert validity */
286 #ifdef HAVE_SSL
287 if (!is_intnonneg (optarg))
288 usage2 (_("Invalid certificate expiration period"), optarg);
289 else {
290 days_till_exp = atoi (optarg);
291 check_cert = TRUE;
293 /* Fall through to -S option */
294 #endif
295 case 'S': /* use SSL */
296 #ifndef HAVE_SSL
297 usage4 (_("Invalid option - SSL is not available"));
298 #endif
299 use_ssl = TRUE;
300 if (specify_port == FALSE)
301 server_port = HTTPS_PORT;
302 break;
303 case 'f': /* onredirect */
304 if (!strcmp (optarg, "follow"))
305 onredirect = STATE_DEPENDENT;
306 if (!strcmp (optarg, "unknown"))
307 onredirect = STATE_UNKNOWN;
308 if (!strcmp (optarg, "ok"))
309 onredirect = STATE_OK;
310 if (!strcmp (optarg, "warning"))
311 onredirect = STATE_WARNING;
312 if (!strcmp (optarg, "critical"))
313 onredirect = STATE_CRITICAL;
314 if (verbose)
315 printf(_("option f:%d \n"), onredirect);
316 break;
317 /* Note: H, I, and u must be malloc'd or will fail on redirects */
318 case 'H': /* Host Name (virtual host) */
319 host_name = strdup (optarg);
320 if (strstr (optarg, ":"))
321 sscanf (optarg, "%*[^:]:%d", &server_port);
322 break;
323 case 'I': /* Server IP-address */
324 server_address = strdup (optarg);
325 break;
326 case 'u': /* URL path */
327 server_url = strdup (optarg);
328 server_url_length = strlen (server_url);
329 break;
330 case 'p': /* Server port */
331 if (!is_intnonneg (optarg))
332 usage2 (_("Invalid port number"), optarg);
333 else {
334 server_port = atoi (optarg);
335 specify_port = TRUE;
337 break;
338 case 'a': /* authorization info */
339 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
340 user_auth[MAX_INPUT_BUFFER - 1] = 0;
341 break;
342 case 'P': /* HTTP POST data in URL encoded format */
343 if (http_method || http_post_data) break;
344 http_method = strdup("POST");
345 http_post_data = strdup (optarg);
346 break;
347 case 's': /* string or substring */
348 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
349 string_expect[MAX_INPUT_BUFFER - 1] = 0;
350 break;
351 case 'e': /* string or substring */
352 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
353 server_expect[MAX_INPUT_BUFFER - 1] = 0;
354 server_expect_yn = 1;
355 break;
356 case 'T': /* Content-type */
357 asprintf (&http_content_type, "%s", optarg);
358 break;
359 case 'l': /* linespan */
360 cflags &= ~REG_NEWLINE;
361 break;
362 case 'R': /* regex */
363 cflags |= REG_ICASE;
364 case 'r': /* regex */
365 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
366 regexp[MAX_RE_SIZE - 1] = 0;
367 errcode = regcomp (&preg, regexp, cflags);
368 if (errcode != 0) {
369 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
370 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
371 return ERROR;
373 break;
374 case INVERT_REGEX:
375 invert_regex = 1;
376 break;
377 case '4':
378 address_family = AF_INET;
379 break;
380 case '6':
381 #ifdef USE_IPV6
382 address_family = AF_INET6;
383 #else
384 usage4 (_("IPv6 support not available"));
385 #endif
386 break;
387 case 'v': /* verbose */
388 verbose = TRUE;
389 break;
390 case 'm': /* min_page_length */
392 char *tmp;
393 if (strchr(optarg, ':') != (char *)NULL) {
394 /* range, so get two values, min:max */
395 tmp = strtok(optarg, ":");
396 if (tmp == NULL) {
397 printf("Bad format: try \"-m min:max\"\n");
398 exit (STATE_WARNING);
399 } else
400 min_page_len = atoi(tmp);
402 tmp = strtok(NULL, ":");
403 if (tmp == NULL) {
404 printf("Bad format: try \"-m min:max\"\n");
405 exit (STATE_WARNING);
406 } else
407 max_page_len = atoi(tmp);
408 } else
409 min_page_len = atoi (optarg);
410 break;
412 case 'N': /* no-body */
413 no_body = TRUE;
414 break;
415 case 'M': /* max-age */
417 int L = strlen(optarg);
418 if (L && optarg[L-1] == 'm')
419 maximum_age = atoi (optarg) * 60;
420 else if (L && optarg[L-1] == 'h')
421 maximum_age = atoi (optarg) * 60 * 60;
422 else if (L && optarg[L-1] == 'd')
423 maximum_age = atoi (optarg) * 60 * 60 * 24;
424 else if (L && (optarg[L-1] == 's' ||
425 isdigit (optarg[L-1])))
426 maximum_age = atoi (optarg);
427 else {
428 fprintf (stderr, "unparsable max-age: %s\n", optarg);
429 exit (STATE_WARNING);
432 break;
436 c = optind;
438 if (server_address == NULL && c < argc)
439 server_address = strdup (argv[c++]);
441 if (host_name == NULL && c < argc)
442 host_name = strdup (argv[c++]);
444 if (server_address == NULL) {
445 if (host_name == NULL)
446 usage4 (_("You must specify a server address or host name"));
447 else
448 server_address = strdup (host_name);
451 if (check_critical_time && critical_time>(double)socket_timeout)
452 socket_timeout = (int)critical_time + 1;
454 if (http_method == NULL)
455 http_method = strdup ("GET");
457 return TRUE;
462 /* Returns 1 if we're done processing the document body; 0 to keep going */
463 static int
464 document_headers_done (char *full_page)
466 const char *body;
468 for (body = full_page; *body; body++) {
469 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
470 break;
473 if (!*body)
474 return 0; /* haven't read end of headers yet */
476 full_page[body - full_page] = 0;
477 return 1;
480 static time_t
481 parse_time_string (const char *string)
483 struct tm tm;
484 time_t t;
485 memset (&tm, 0, sizeof(tm));
487 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
489 if (isupper (string[0]) && /* Tue */
490 islower (string[1]) &&
491 islower (string[2]) &&
492 ',' == string[3] &&
493 ' ' == string[4] &&
494 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
495 isdigit (string[6]) &&
496 ' ' == string[7] &&
497 isupper (string[8]) && /* Dec */
498 islower (string[9]) &&
499 islower (string[10]) &&
500 ' ' == string[11] &&
501 isdigit (string[12]) && /* 2001 */
502 isdigit (string[13]) &&
503 isdigit (string[14]) &&
504 isdigit (string[15]) &&
505 ' ' == string[16] &&
506 isdigit (string[17]) && /* 02: */
507 isdigit (string[18]) &&
508 ':' == string[19] &&
509 isdigit (string[20]) && /* 59: */
510 isdigit (string[21]) &&
511 ':' == string[22] &&
512 isdigit (string[23]) && /* 03 */
513 isdigit (string[24]) &&
514 ' ' == string[25] &&
515 'G' == string[26] && /* GMT */
516 'M' == string[27] && /* GMT */
517 'T' == string[28]) {
519 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
520 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
521 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
522 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
523 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
524 !strncmp (string+8, "Feb", 3) ? 1 :
525 !strncmp (string+8, "Mar", 3) ? 2 :
526 !strncmp (string+8, "Apr", 3) ? 3 :
527 !strncmp (string+8, "May", 3) ? 4 :
528 !strncmp (string+8, "Jun", 3) ? 5 :
529 !strncmp (string+8, "Jul", 3) ? 6 :
530 !strncmp (string+8, "Aug", 3) ? 7 :
531 !strncmp (string+8, "Sep", 3) ? 8 :
532 !strncmp (string+8, "Oct", 3) ? 9 :
533 !strncmp (string+8, "Nov", 3) ? 10 :
534 !strncmp (string+8, "Dec", 3) ? 11 :
535 -1);
536 tm.tm_year = ((1000 * (string[12]-'0') +
537 100 * (string[13]-'0') +
538 10 * (string[14]-'0') +
539 (string[15]-'0'))
540 - 1900);
542 tm.tm_isdst = 0; /* GMT is never in DST, right? */
544 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
545 return 0;
548 This is actually wrong: we need to subtract the local timezone
549 offset from GMT from this value. But, that's ok in this usage,
550 because we only comparing these two GMT dates against each other,
551 so it doesn't matter what time zone we parse them in.
554 t = mktime (&tm);
555 if (t == (time_t) -1) t = 0;
557 if (verbose) {
558 const char *s = string;
559 while (*s && *s != '\r' && *s != '\n')
560 fputc (*s++, stdout);
561 printf (" ==> %lu\n", (unsigned long) t);
564 return t;
566 } else {
567 return 0;
573 static void
574 check_document_dates (const char *headers)
576 const char *s;
577 char *server_date = 0;
578 char *document_date = 0;
580 s = headers;
581 while (*s) {
582 const char *field = s;
583 const char *value = 0;
585 /* Find the end of the header field */
586 while (*s && !isspace(*s) && *s != ':')
587 s++;
589 /* Remember the header value, if any. */
590 if (*s == ':')
591 value = ++s;
593 /* Skip to the end of the header, including continuation lines. */
594 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
595 s++;
596 s++;
598 /* Process this header. */
599 if (value && value > field+2) {
600 char *ff = (char *) malloc (value-field);
601 char *ss = ff;
602 while (field < value-1)
603 *ss++ = tolower(*field++);
604 *ss++ = 0;
606 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
607 const char *e;
608 while (*value && isspace (*value))
609 value++;
610 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
612 ss = (char *) malloc (e - value + 1);
613 strncpy (ss, value, e - value);
614 ss[e - value] = 0;
615 if (!strcmp (ff, "date")) {
616 if (server_date) free (server_date);
617 server_date = ss;
618 } else {
619 if (document_date) free (document_date);
620 document_date = ss;
623 free (ff);
627 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
628 if (!server_date || !*server_date) {
629 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Server date unknown\n"));
630 } else if (!document_date || !*document_date) {
631 die (STATE_CRITICAL, _("HTTP CRITICAL - Document modification date unknown\n"));
632 } else {
633 time_t srv_data = parse_time_string (server_date);
634 time_t doc_data = parse_time_string (document_date);
636 if (srv_data <= 0) {
637 die (STATE_CRITICAL, _("HTTP CRITICAL - Server date \"%100s\" unparsable"), server_date);
638 } else if (doc_data <= 0) {
639 die (STATE_CRITICAL, _("HTTP CRITICAL - Document date \"%100s\" unparsable"), document_date);
640 } else if (doc_data > srv_data + 30) {
641 die (STATE_CRITICAL, _("HTTP CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
642 } else if (doc_data < srv_data - maximum_age) {
643 int n = (srv_data - doc_data);
644 if (n > (60 * 60 * 24 * 2))
645 die (STATE_CRITICAL,
646 _("HTTP CRITICAL - Last modified %.1f days ago\n"),
647 ((float) n) / (60 * 60 * 24));
648 else
649 die (STATE_CRITICAL,
650 _("HTTP CRITICAL - Last modified %d:%02d:%02d ago\n"),
651 n / (60 * 60), (n / 60) % 60, n % 60);
654 free (server_date);
655 free (document_date);
660 get_content_length (const char *headers)
662 const char *s;
663 int content_length = 0;
665 s = headers;
666 while (*s) {
667 const char *field = s;
668 const char *value = 0;
670 /* Find the end of the header field */
671 while (*s && !isspace(*s) && *s != ':')
672 s++;
674 /* Remember the header value, if any. */
675 if (*s == ':')
676 value = ++s;
678 /* Skip to the end of the header, including continuation lines. */
679 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
680 s++;
681 s++;
683 /* Process this header. */
684 if (value && value > field+2) {
685 char *ff = (char *) malloc (value-field);
686 char *ss = ff;
687 while (field < value-1)
688 *ss++ = tolower(*field++);
689 *ss++ = 0;
691 if (!strcmp (ff, "content-length")) {
692 const char *e;
693 while (*value && isspace (*value))
694 value++;
695 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
697 ss = (char *) malloc (e - value + 1);
698 strncpy (ss, value, e - value);
699 ss[e - value] = 0;
700 content_length = atoi(ss);
701 free (ss);
703 free (ff);
706 return (content_length);
710 check_http (void)
712 char *msg;
713 char *status_line;
714 char *status_code;
715 char *header;
716 char *page;
717 char *auth;
718 int http_status;
719 int i = 0;
720 size_t pagesize = 0;
721 char *full_page;
722 char *buf;
723 char *pos;
724 long microsec;
725 double elapsed_time;
726 int page_len = 0;
727 int result = STATE_UNKNOWN;
729 /* try to connect to the host at the given port number */
730 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
731 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
732 #ifdef HAVE_SSL
733 if (use_ssl == TRUE) {
734 np_net_ssl_init(sd);
735 if (check_cert == TRUE) {
736 result = np_net_ssl_check_cert(days_till_exp);
737 np_net_ssl_cleanup();
738 if(sd) close(sd);
739 return result;
742 #endif /* HAVE_SSL */
744 asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
746 /* tell HTTP/1.1 servers not to keep the connection alive */
747 asprintf (&buf, "%sConnection: close\r\n", buf);
749 /* optionally send the host header info */
750 if (host_name)
751 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
753 /* optionally send any other header tag */
754 if (http_opt_headers_count) {
755 for (i = 0; i < http_opt_headers_count ; i++) {
756 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
757 asprintf (&buf, "%s%s\r\n", buf, pos);
759 free(http_opt_headers);
762 /* optionally send the authentication info */
763 if (strlen(user_auth)) {
764 auth = base64 (user_auth, strlen (user_auth));
765 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
768 /* either send http POST data */
769 if (http_post_data) {
770 if (http_content_type) {
771 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
772 } else {
773 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
776 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
777 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
779 else {
780 /* or just a newline so the server knows we're done with the request */
781 asprintf (&buf, "%s%s", buf, CRLF);
784 if (verbose) printf ("%s\n", buf);
785 my_send (buf, strlen (buf));
787 /* fetch the page */
788 full_page = strdup("");
789 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
790 buffer[i] = '\0';
791 asprintf (&full_page, "%s%s", full_page, buffer);
792 pagesize += i;
794 if (no_body && document_headers_done (full_page)) {
795 i = 0;
796 break;
800 if (i < 0 && errno != ECONNRESET) {
801 #ifdef HAVE_SSL
803 if (use_ssl) {
804 sslerr=SSL_get_error(ssl, i);
805 if ( sslerr == SSL_ERROR_SSL ) {
806 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
807 } else {
808 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
811 else {
813 #endif
814 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
815 #ifdef HAVE_SSL
816 /* XXX
819 #endif
822 /* return a CRITICAL status if we couldn't read any data */
823 if (pagesize == (size_t) 0)
824 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
826 /* close the connection */
827 #ifdef HAVE_SSL
828 np_net_ssl_cleanup();
829 #endif
830 if(sd) close(sd);
832 /* reset the alarm */
833 alarm (0);
835 /* leave full_page untouched so we can free it later */
836 page = full_page;
838 if (verbose)
839 printf ("%s://%s:%d%s is %d characters\n",
840 use_ssl ? "https" : "http", server_address,
841 server_port, server_url, (int)pagesize);
843 /* find status line and null-terminate it */
844 status_line = page;
845 page += (size_t) strcspn (page, "\r\n");
846 pos = page;
847 page += (size_t) strspn (page, "\r\n");
848 status_line[strcspn(status_line, "\r\n")] = 0;
849 strip (status_line);
850 if (verbose)
851 printf ("STATUS: %s\n", status_line);
853 /* find header info and null-terminate it */
854 header = page;
855 while (strcspn (page, "\r\n") > 0) {
856 page += (size_t) strcspn (page, "\r\n");
857 pos = page;
858 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
859 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
860 page += (size_t) 2;
861 else
862 page += (size_t) 1;
864 page += (size_t) strspn (page, "\r\n");
865 header[pos - header] = 0;
866 if (verbose)
867 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
868 (no_body ? " [[ skipped ]]" : page));
870 /* make sure the status line matches the response we are looking for */
871 if (!strstr (status_line, server_expect)) {
872 if (server_port == HTTP_PORT)
873 asprintf (&msg,
874 _("Invalid HTTP response received from host\n"));
875 else
876 asprintf (&msg,
877 _("Invalid HTTP response received from host on port %d\n"),
878 server_port);
879 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
882 /* Exit here if server_expect was set by user and not default */
883 if ( server_expect_yn ) {
884 asprintf (&msg,
885 _("HTTP OK: Status line output matched \"%s\"\n"),
886 server_expect);
887 if (verbose)
888 printf ("%s\n",msg);
890 else {
891 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
892 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
893 /* Status-Code = 3 DIGITS */
895 status_code = strchr (status_line, ' ') + sizeof (char);
896 if (strspn (status_code, "1234567890") != 3)
897 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
899 http_status = atoi (status_code);
901 /* check the return code */
903 if (http_status >= 600 || http_status < 100)
904 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
906 /* server errors result in a critical state */
907 else if (http_status >= 500)
908 die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
910 /* client errors result in a warning state */
911 else if (http_status >= 400)
912 die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
914 /* check redirected page if specified */
915 else if (http_status >= 300) {
917 if (onredirect == STATE_DEPENDENT)
918 redir (header, status_line);
919 else if (onredirect == STATE_UNKNOWN)
920 printf (_("HTTP UNKNOWN"));
921 else if (onredirect == STATE_OK)
922 printf (_("HTTP OK"));
923 else if (onredirect == STATE_WARNING)
924 printf (_("HTTP WARNING"));
925 else if (onredirect == STATE_CRITICAL)
926 printf (_("HTTP CRITICAL"));
927 microsec = deltime (tv);
928 elapsed_time = (double)microsec / 1.0e6;
929 die (onredirect,
930 _(" - %s - %.3f second response time %s|%s %s\n"),
931 status_line, elapsed_time,
932 (display_html ? "</A>" : ""),
933 perfd_time (elapsed_time), perfd_size (pagesize));
934 } /* end if (http_status >= 300) */
936 } /* end else (server_expect_yn) */
938 if (maximum_age >= 0) {
939 check_document_dates (header);
942 /* check elapsed time */
943 microsec = deltime (tv);
944 elapsed_time = (double)microsec / 1.0e6;
945 asprintf (&msg,
946 _(" - %s - %.3f second response time %s|%s %s\n"),
947 status_line, elapsed_time,
948 (display_html ? "</A>" : ""),
949 perfd_time (elapsed_time), perfd_size (pagesize));
950 if (check_critical_time == TRUE && elapsed_time > critical_time)
951 die (STATE_CRITICAL, "HTTP %s: %s", _("CRITICAL"), msg);
952 if (check_warning_time == TRUE && elapsed_time > warning_time)
953 die (STATE_WARNING, "HTTP %s: %s", _("WARNING"), msg);
955 /* Page and Header content checks go here */
956 /* these checks should be last */
958 if (strlen (string_expect)) {
959 if (strstr (page, string_expect)) {
960 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
961 status_line, elapsed_time,
962 (display_html ? "</A>" : ""),
963 perfd_time (elapsed_time), perfd_size (pagesize));
964 exit (STATE_OK);
966 else {
967 printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
968 (display_html ? "</A>" : ""),
969 perfd_time (elapsed_time), perfd_size (pagesize));
970 exit (STATE_CRITICAL);
974 if (strlen (regexp)) {
975 errcode = regexec (&preg, page, REGS, pmatch, 0);
976 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
977 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
978 status_line, elapsed_time,
979 (display_html ? "</A>" : ""),
980 perfd_time (elapsed_time), perfd_size (pagesize));
981 exit (STATE_OK);
983 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
984 if (invert_regex == 0)
985 msg = strdup(_("pattern not found"));
986 else
987 msg = strdup(_("pattern found"));
988 printf (("%s - %s%s|%s %s\n"),
989 _("HTTP CRITICAL"),
990 msg,
991 (display_html ? "</A>" : ""),
992 perfd_time (elapsed_time), perfd_size (pagesize));
993 exit (STATE_CRITICAL);
995 else {
996 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
997 printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
998 exit (STATE_CRITICAL);
1002 /* make sure the page is of an appropriate size */
1003 /* page_len = get_content_length(header); */
1004 page_len = pagesize;
1005 if ((max_page_len > 0) && (page_len > max_page_len)) {
1006 printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1007 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1008 exit (STATE_WARNING);
1009 } else 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);
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\n"),
1016 status_line, page_len, elapsed_time,
1017 (display_html ? "</A>" : ""),
1018 perfd_time (elapsed_time), perfd_size (page_len));
1019 die (STATE_OK, "%s", msg);
1020 return STATE_UNKNOWN;
1025 /* per RFC 2396 */
1026 #define URI_HTTP "%5[HTPShtps]"
1027 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1028 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1029 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1030 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1031 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1032 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1033 #define HD4 URI_HTTP "://" URI_HOST
1034 #define HD5 URI_PATH
1036 void
1037 redir (char *pos, char *status_line)
1039 int i = 0;
1040 char *x;
1041 char xx[2];
1042 char type[6];
1043 char *addr;
1044 char *url;
1046 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1047 if (addr == NULL)
1048 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1050 url = malloc (strcspn (pos, "\r\n"));
1051 if (url == NULL)
1052 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
1054 while (pos) {
1055 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1056 if (i == 0) {
1057 pos += (size_t) strcspn (pos, "\r\n");
1058 pos += (size_t) strspn (pos, "\r\n");
1059 if (strlen(pos) == 0)
1060 die (STATE_UNKNOWN,
1061 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1062 status_line, (display_html ? "</A>" : ""));
1063 continue;
1066 pos += i;
1067 pos += strspn (pos, " \t");
1070 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1071 * preceding each extra line with at least one SP or HT.''
1073 for (; (i = strspn (pos, "\r\n")); pos += i) {
1074 pos += i;
1075 if (!(i = strspn (pos, " \t"))) {
1076 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1077 display_html ? "</A>" : "");
1081 url = realloc (url, strcspn (pos, "\r\n") + 1);
1082 if (url == NULL)
1083 die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1085 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1086 if (sscanf (pos, HD1, type, addr, &i, url) == 4)
1087 use_ssl = server_type_check (type);
1089 /* URI_HTTP URI_HOST URI_PATH */
1090 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1091 use_ssl = server_type_check (type);
1092 i = server_port_check (use_ssl);
1095 /* URI_HTTP URI_HOST URI_PORT */
1096 else if(sscanf (pos, HD3, type, addr, &i) == 3) {
1097 strcpy (url, HTTP_URL);
1098 use_ssl = server_type_check (type);
1101 /* URI_HTTP URI_HOST */
1102 else if(sscanf (pos, HD4, type, addr) == 2) {
1103 strcpy (url, HTTP_URL);
1104 use_ssl = server_type_check (type);
1105 i = server_port_check (use_ssl);
1108 /* URI_PATH */
1109 else if (sscanf (pos, HD5, url) == 1) {
1110 /* relative url */
1111 if ((url[0] != '/')) {
1112 if ((x = strrchr(server_url, '/')))
1113 *x = '\0';
1114 asprintf (&url, "%s/%s", server_url, url);
1116 i = server_port;
1117 strcpy (type, server_type);
1118 strcpy (addr, host_name ? host_name : server_address);
1121 else {
1122 die (STATE_UNKNOWN,
1123 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1124 pos, (display_html ? "</A>" : ""));
1127 break;
1129 } /* end while (pos) */
1131 if (++redir_depth > max_depth)
1132 die (STATE_WARNING,
1133 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1134 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1136 if (server_port==i &&
1137 !strcmp(server_address, addr) &&
1138 (host_name && !strcmp(host_name, addr)) &&
1139 !strcmp(server_url, url))
1140 die (STATE_WARNING,
1141 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1142 type, addr, i, url, (display_html ? "</A>" : ""));
1144 strcpy (server_type, type);
1146 free (host_name);
1147 host_name = strdup (addr);
1149 free (server_address);
1150 server_address = strdup (addr);
1152 free (server_url);
1153 if ((url[0] == '/'))
1154 server_url = strdup (url);
1155 else if (asprintf(&server_url, "/%s", url) == -1)
1156 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate server_url%s\n"),
1157 display_html ? "</A>" : "");
1158 free(url);
1160 if ((server_port = i) > MAX_PORT)
1161 die (STATE_UNKNOWN,
1162 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1163 MAX_PORT, server_type, server_address, server_port, server_url,
1164 display_html ? "</A>" : "");
1166 if (verbose)
1167 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1168 host_name ? host_name : server_address, server_port, server_url);
1170 check_http ();
1176 server_type_check (const char *type)
1178 if (strcmp (type, "https"))
1179 return FALSE;
1180 else
1181 return TRUE;
1185 server_port_check (int ssl_flag)
1187 if (ssl_flag)
1188 return HTTPS_PORT;
1189 else
1190 return HTTP_PORT;
1193 char *perfd_time (double elapsed_time)
1195 return fperfdata ("time", elapsed_time, "s",
1196 check_warning_time, warning_time,
1197 check_critical_time, critical_time,
1198 TRUE, 0, FALSE, 0);
1203 char *perfd_size (int page_len)
1205 return perfdata ("size", page_len, "B",
1206 (min_page_len>0?TRUE:FALSE), min_page_len,
1207 (min_page_len>0?TRUE:FALSE), 0,
1208 TRUE, 0, FALSE, 0);
1211 void
1212 print_help (void)
1214 print_revision (progname, revision);
1216 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1217 printf (COPYRIGHT, copyright, email);
1219 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1220 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1221 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1222 printf ("%s\n", _("certificate expiration times."));
1224 printf ("\n\n");
1226 print_usage ();
1228 printf (_("NOTE: One or both of -H and -I must be specified"));
1230 printf ("\n");
1232 printf (_(UT_HELP_VRSN));
1234 printf (" %s\n", "-H, --hostname=ADDRESS");
1235 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1236 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1237 printf (" %s\n", "-I, --IP-address=ADDRESS");
1238 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1239 printf (" %s\n", "-p, --port=INTEGER");
1240 printf (" %s", _("Port number (default: "));
1241 printf ("%d)\n", HTTP_PORT);
1243 printf (_(UT_IPv46));
1245 #ifdef HAVE_SSL
1246 printf (" %s\n", "-S, --ssl");
1247 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1248 printf (" %s\n", "-C, --certificate=INTEGER");
1249 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1250 printf (" %s\n", _("(when this option is used the url is not checked.)\n"));
1251 #endif
1253 printf (" %s\n", "-e, --expect=STRING");
1254 printf (" %s\n", _("String to expect in first (status) line of server response (default: "));
1255 printf ("%s)\n", HTTP_EXPECT);
1256 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1257 printf (" %s\n", "-s, --string=STRING");
1258 printf (" %s\n", _("String to expect in the content"));
1259 printf (" %s\n", "-u, --url=PATH");
1260 printf (" %s\n", _("URL to GET or POST (default: /)"));
1261 printf (" %s\n", "-P, --post=STRING");
1262 printf (" %s\n", _("URL encoded http POST data"));
1263 printf (" %s\n", "-N, --no-body");
1264 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1265 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1266 printf (" %s\n", "-M, --max-age=SECONDS");
1267 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1268 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1269 printf (" %s\n", "-T, --content-type=STRING");
1270 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1272 printf (" %s\n", "-l, --linespan");
1273 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1274 printf (" %s\n", "-r, --regex, --ereg=STRING");
1275 printf (" %s\n", _("Search page for regex STRING"));
1276 printf (" %s\n", "-R, --eregi=STRING");
1277 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1278 printf (" %s\n", "--invert-regex");
1279 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1281 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1282 printf (" %s\n", _("Username:password on sites with basic authentication"));
1283 printf (" %s\n", "-A, --useragent=STRING");
1284 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1285 printf (" %s\n", "-k, --header=STRING");
1286 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1287 printf (" %s\n", "-L, --link");
1288 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1289 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1290 printf (" %s\n", _("How to handle redirected pages"));
1291 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1292 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1294 printf (_(UT_WARN_CRIT));
1296 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1298 printf (_(UT_VERBOSE));
1300 printf (_("Notes:"));
1301 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1302 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1303 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1304 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1305 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1306 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1308 #ifdef HAVE_SSL
1309 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1310 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1311 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1312 printf (_("Examples:"));
1313 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1314 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1315 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1316 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1317 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1319 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1320 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1321 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1322 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1323 printf (" %s\n\n", _("the certificate is expired."));
1324 #endif
1326 printf (_(UT_SUPPORT));
1332 void
1333 print_usage (void)
1335 printf (_("Usage:"));
1336 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1337 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1338 printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1339 printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1340 printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1341 printf (" [-k string] [-S] [-C <age>] [-T <content-type>]\n");