Set the pointers to the SSL and SSL_CTX objects back to NULL after
[monitoring-plugins.git] / plugins / check_http.c
blob5e33ec86113e485a55a24b1750e3ef6aea799bab
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 "common.h"
47 #include "netutils.h"
48 #include "utils.h"
50 #define INPUT_DELIMITER ";"
52 #define HTTP_EXPECT "HTTP/1."
53 enum {
54 MAX_IPV4_HOSTLENGTH = 255,
55 HTTP_PORT = 80,
56 HTTPS_PORT = 443
59 #ifdef HAVE_SSL
60 int check_cert = FALSE;
61 int days_till_exp;
62 char *randbuff;
63 X509 *server_cert;
64 # define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
65 # define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
66 #else /* ifndef HAVE_SSL */
67 # define my_recv(buf, len) read(sd, buf, len)
68 # define my_send(buf, len) send(sd, buf, len, 0)
69 #endif /* HAVE_SSL */
70 int no_body = FALSE;
71 int maximum_age = -1;
73 enum {
74 REGS = 2,
75 MAX_RE_SIZE = 256
77 #include "regex.h"
78 regex_t preg;
79 regmatch_t pmatch[REGS];
80 char regexp[MAX_RE_SIZE];
81 char errbuf[MAX_INPUT_BUFFER];
82 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
83 int errcode;
84 int invert_regex = 0;
86 struct timeval tv;
88 #define HTTP_URL "/"
89 #define CRLF "\r\n"
91 int specify_port = FALSE;
92 int server_port = HTTP_PORT;
93 char server_port_text[6] = "";
94 char server_type[6] = "http";
95 char *server_address;
96 char *host_name;
97 char *server_url;
98 char *user_agent;
99 int server_url_length;
100 int server_expect_yn = 0;
101 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
102 char string_expect[MAX_INPUT_BUFFER] = "";
103 double warning_time = 0;
104 int check_warning_time = FALSE;
105 double critical_time = 0;
106 int check_critical_time = FALSE;
107 char user_auth[MAX_INPUT_BUFFER] = "";
108 int display_html = FALSE;
109 char **http_opt_headers;
110 int http_opt_headers_count = 0;
111 int onredirect = STATE_OK;
112 int use_ssl = FALSE;
113 int verbose = FALSE;
114 int sd;
115 int min_page_len = 0;
116 int max_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 void print_help (void);
133 void print_usage (void);
136 main (int argc, char **argv)
138 int result = STATE_UNKNOWN;
140 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
141 server_url = strdup(HTTP_URL);
142 server_url_length = strlen(server_url);
143 asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
144 clean_revstring (revision), VERSION);
146 if (process_arguments (argc, argv) == ERROR)
147 usage4 (_("Could not parse arguments"));
149 if (display_html == TRUE)
150 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
151 use_ssl ? "https" : "http", host_name,
152 server_port, server_url);
154 /* initialize alarm signal handling, set socket timeout, start timer */
155 (void) signal (SIGALRM, socket_timeout_alarm_handler);
156 (void) alarm (socket_timeout);
157 gettimeofday (&tv, NULL);
159 result = check_http ();
160 return result;
165 /* process command-line arguments */
167 process_arguments (int argc, char **argv)
169 int c = 1;
171 enum {
172 INVERT_REGEX = CHAR_MAX + 1
175 int option = 0;
176 static struct option longopts[] = {
177 STD_LONG_OPTS,
178 {"link", no_argument, 0, 'L'},
179 {"nohtml", no_argument, 0, 'n'},
180 {"ssl", no_argument, 0, 'S'},
181 {"post", required_argument, 0, 'P'},
182 {"IP-address", required_argument, 0, 'I'},
183 {"url", required_argument, 0, 'u'},
184 {"port", required_argument, 0, 'p'},
185 {"authorization", required_argument, 0, 'a'},
186 {"string", required_argument, 0, 's'},
187 {"expect", required_argument, 0, 'e'},
188 {"regex", required_argument, 0, 'r'},
189 {"ereg", required_argument, 0, 'r'},
190 {"eregi", required_argument, 0, 'R'},
191 {"linespan", no_argument, 0, 'l'},
192 {"onredirect", required_argument, 0, 'f'},
193 {"certificate", required_argument, 0, 'C'},
194 {"useragent", required_argument, 0, 'A'},
195 {"header", required_argument, 0, 'k'},
196 {"no-body", no_argument, 0, 'N'},
197 {"max-age", required_argument, 0, 'M'},
198 {"content-type", required_argument, 0, 'T'},
199 {"pagesize", required_argument, 0, 'm'},
200 {"invert-regex", no_argument, NULL, INVERT_REGEX},
201 {"use-ipv4", no_argument, 0, '4'},
202 {"use-ipv6", no_argument, 0, '6'},
203 {0, 0, 0, 0}
206 if (argc < 2)
207 return ERROR;
209 for (c = 1; c < argc; c++) {
210 if (strcmp ("-to", argv[c]) == 0)
211 strcpy (argv[c], "-t");
212 if (strcmp ("-hn", argv[c]) == 0)
213 strcpy (argv[c], "-H");
214 if (strcmp ("-wt", argv[c]) == 0)
215 strcpy (argv[c], "-w");
216 if (strcmp ("-ct", argv[c]) == 0)
217 strcpy (argv[c], "-c");
218 if (strcmp ("-nohtml", argv[c]) == 0)
219 strcpy (argv[c], "-n");
222 while (1) {
223 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);
224 if (c == -1 || c == EOF)
225 break;
227 switch (c) {
228 case '?': /* usage */
229 usage5 ();
230 break;
231 case 'h': /* help */
232 print_help ();
233 exit (STATE_OK);
234 break;
235 case 'V': /* version */
236 print_revision (progname, revision);
237 exit (STATE_OK);
238 break;
239 case 't': /* timeout period */
240 if (!is_intnonneg (optarg))
241 usage2 (_("Timeout interval must be a positive integer"), optarg);
242 else
243 socket_timeout = atoi (optarg);
244 break;
245 case 'c': /* critical time threshold */
246 if (!is_nonnegative (optarg))
247 usage2 (_("Critical threshold must be integer"), optarg);
248 else {
249 critical_time = strtod (optarg, NULL);
250 check_critical_time = TRUE;
252 break;
253 case 'w': /* warning time threshold */
254 if (!is_nonnegative (optarg))
255 usage2 (_("Warning threshold must be integer"), optarg);
256 else {
257 warning_time = strtod (optarg, NULL);
258 check_warning_time = TRUE;
260 break;
261 case 'A': /* User Agent String */
262 asprintf (&user_agent, "User-Agent: %s", optarg);
263 break;
264 case 'k': /* Additional headers */
265 if (http_opt_headers_count == 0)
266 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
267 else
268 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
269 http_opt_headers[http_opt_headers_count - 1] = optarg;
270 /* asprintf (&http_opt_headers, "%s", optarg); */
271 break;
272 case 'L': /* show html link */
273 display_html = TRUE;
274 break;
275 case 'n': /* do not show html link */
276 display_html = FALSE;
277 break;
278 case 'C': /* Check SSL cert validity */
279 #ifdef HAVE_SSL
280 if (!is_intnonneg (optarg))
281 usage2 (_("Invalid certificate expiration period"), optarg);
282 else {
283 days_till_exp = atoi (optarg);
284 check_cert = TRUE;
286 /* Fall through to -S option */
287 #endif
288 case 'S': /* use SSL */
289 #ifndef HAVE_SSL
290 usage4 (_("Invalid option - SSL is not available"));
291 #endif
292 use_ssl = TRUE;
293 if (specify_port == FALSE)
294 server_port = HTTPS_PORT;
295 break;
296 case 'f': /* onredirect */
297 if (!strcmp (optarg, "follow"))
298 onredirect = STATE_DEPENDENT;
299 if (!strcmp (optarg, "unknown"))
300 onredirect = STATE_UNKNOWN;
301 if (!strcmp (optarg, "ok"))
302 onredirect = STATE_OK;
303 if (!strcmp (optarg, "warning"))
304 onredirect = STATE_WARNING;
305 if (!strcmp (optarg, "critical"))
306 onredirect = STATE_CRITICAL;
307 if (verbose)
308 printf(_("option f:%d \n"), onredirect);
309 break;
310 /* Note: H, I, and u must be malloc'd or will fail on redirects */
311 case 'H': /* Host Name (virtual host) */
312 host_name = strdup (optarg);
313 if (strstr (optarg, ":"))
314 sscanf (optarg, "%*[^:]:%d", &server_port);
315 break;
316 case 'I': /* Server IP-address */
317 server_address = strdup (optarg);
318 break;
319 case 'u': /* URL path */
320 server_url = strdup (optarg);
321 server_url_length = strlen (server_url);
322 break;
323 case 'p': /* Server port */
324 if (!is_intnonneg (optarg))
325 usage2 (_("Invalid port number"), optarg);
326 else {
327 server_port = atoi (optarg);
328 specify_port = TRUE;
330 break;
331 case 'a': /* authorization info */
332 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
333 user_auth[MAX_INPUT_BUFFER - 1] = 0;
334 break;
335 case 'P': /* HTTP POST data in URL encoded format */
336 if (http_method || http_post_data) break;
337 http_method = strdup("POST");
338 http_post_data = strdup (optarg);
339 break;
340 case 's': /* string or substring */
341 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
342 string_expect[MAX_INPUT_BUFFER - 1] = 0;
343 break;
344 case 'e': /* string or substring */
345 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
346 server_expect[MAX_INPUT_BUFFER - 1] = 0;
347 server_expect_yn = 1;
348 break;
349 case 'T': /* Content-type */
350 asprintf (&http_content_type, "%s", optarg);
351 break;
352 case 'l': /* linespan */
353 cflags &= ~REG_NEWLINE;
354 break;
355 case 'R': /* regex */
356 cflags |= REG_ICASE;
357 case 'r': /* regex */
358 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
359 regexp[MAX_RE_SIZE - 1] = 0;
360 errcode = regcomp (&preg, regexp, cflags);
361 if (errcode != 0) {
362 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
363 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
364 return ERROR;
366 break;
367 case INVERT_REGEX:
368 invert_regex = 1;
369 break;
370 case '4':
371 address_family = AF_INET;
372 break;
373 case '6':
374 #ifdef USE_IPV6
375 address_family = AF_INET6;
376 #else
377 usage4 (_("IPv6 support not available"));
378 #endif
379 break;
380 case 'v': /* verbose */
381 verbose = TRUE;
382 break;
383 case 'm': /* min_page_length */
385 char *tmp;
386 if (strchr(optarg, ':') != (char *)NULL) {
387 /* range, so get two values, min:max */
388 tmp = strtok(optarg, ":");
389 if (tmp == NULL) {
390 printf("Bad format: try \"-m min:max\"\n");
391 exit (STATE_WARNING);
392 } else
393 min_page_len = atoi(tmp);
395 tmp = strtok(NULL, ":");
396 if (tmp == NULL) {
397 printf("Bad format: try \"-m min:max\"\n");
398 exit (STATE_WARNING);
399 } else
400 max_page_len = atoi(tmp);
401 } else
402 min_page_len = atoi (optarg);
403 break;
405 case 'N': /* no-body */
406 no_body = TRUE;
407 break;
408 case 'M': /* max-age */
410 int L = strlen(optarg);
411 if (L && optarg[L-1] == 'm')
412 maximum_age = atoi (optarg) * 60;
413 else if (L && optarg[L-1] == 'h')
414 maximum_age = atoi (optarg) * 60 * 60;
415 else if (L && optarg[L-1] == 'd')
416 maximum_age = atoi (optarg) * 60 * 60 * 24;
417 else if (L && (optarg[L-1] == 's' ||
418 isdigit (optarg[L-1])))
419 maximum_age = atoi (optarg);
420 else {
421 fprintf (stderr, "unparsable max-age: %s\n", optarg);
422 exit (STATE_WARNING);
425 break;
429 c = optind;
431 if (server_address == NULL && c < argc)
432 server_address = strdup (argv[c++]);
434 if (host_name == NULL && c < argc)
435 host_name = strdup (argv[c++]);
437 if (server_address == NULL) {
438 if (host_name == NULL)
439 usage4 (_("You must specify a server address or host name"));
440 else
441 server_address = strdup (host_name);
444 if (check_critical_time && critical_time>(double)socket_timeout)
445 socket_timeout = (int)critical_time + 1;
447 if (http_method == NULL)
448 http_method = strdup ("GET");
450 return TRUE;
455 /* written by lauri alanko */
456 static char *
457 base64 (const char *bin, size_t len)
460 char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
461 size_t i = 0, j = 0;
463 char BASE64_END = '=';
464 char base64_table[64];
465 strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
467 while (j < len - 2) {
468 buf[i++] = base64_table[bin[j] >> 2];
469 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
470 buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
471 buf[i++] = base64_table[bin[j + 2] & 63];
472 j += 3;
475 switch (len - j) {
476 case 1:
477 buf[i++] = base64_table[bin[j] >> 2];
478 buf[i++] = base64_table[(bin[j] & 3) << 4];
479 buf[i++] = BASE64_END;
480 buf[i++] = BASE64_END;
481 break;
482 case 2:
483 buf[i++] = base64_table[bin[j] >> 2];
484 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
485 buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
486 buf[i++] = BASE64_END;
487 break;
488 case 0:
489 break;
492 buf[i] = '\0';
493 return buf;
498 /* Returns 1 if we're done processing the document body; 0 to keep going */
499 static int
500 document_headers_done (char *full_page)
502 const char *body;
504 for (body = full_page; *body; body++) {
505 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
506 break;
509 if (!*body)
510 return 0; /* haven't read end of headers yet */
512 full_page[body - full_page] = 0;
513 return 1;
516 static time_t
517 parse_time_string (const char *string)
519 struct tm tm;
520 time_t t;
521 memset (&tm, 0, sizeof(tm));
523 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
525 if (isupper (string[0]) && /* Tue */
526 islower (string[1]) &&
527 islower (string[2]) &&
528 ',' == string[3] &&
529 ' ' == string[4] &&
530 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
531 isdigit (string[6]) &&
532 ' ' == string[7] &&
533 isupper (string[8]) && /* Dec */
534 islower (string[9]) &&
535 islower (string[10]) &&
536 ' ' == string[11] &&
537 isdigit (string[12]) && /* 2001 */
538 isdigit (string[13]) &&
539 isdigit (string[14]) &&
540 isdigit (string[15]) &&
541 ' ' == string[16] &&
542 isdigit (string[17]) && /* 02: */
543 isdigit (string[18]) &&
544 ':' == string[19] &&
545 isdigit (string[20]) && /* 59: */
546 isdigit (string[21]) &&
547 ':' == string[22] &&
548 isdigit (string[23]) && /* 03 */
549 isdigit (string[24]) &&
550 ' ' == string[25] &&
551 'G' == string[26] && /* GMT */
552 'M' == string[27] && /* GMT */
553 'T' == string[28]) {
555 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
556 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
557 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
558 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
559 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
560 !strncmp (string+8, "Feb", 3) ? 1 :
561 !strncmp (string+8, "Mar", 3) ? 2 :
562 !strncmp (string+8, "Apr", 3) ? 3 :
563 !strncmp (string+8, "May", 3) ? 4 :
564 !strncmp (string+8, "Jun", 3) ? 5 :
565 !strncmp (string+8, "Jul", 3) ? 6 :
566 !strncmp (string+8, "Aug", 3) ? 7 :
567 !strncmp (string+8, "Sep", 3) ? 8 :
568 !strncmp (string+8, "Oct", 3) ? 9 :
569 !strncmp (string+8, "Nov", 3) ? 10 :
570 !strncmp (string+8, "Dec", 3) ? 11 :
571 -1);
572 tm.tm_year = ((1000 * (string[12]-'0') +
573 100 * (string[13]-'0') +
574 10 * (string[14]-'0') +
575 (string[15]-'0'))
576 - 1900);
578 tm.tm_isdst = 0; /* GMT is never in DST, right? */
580 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
581 return 0;
584 This is actually wrong: we need to subtract the local timezone
585 offset from GMT from this value. But, that's ok in this usage,
586 because we only comparing these two GMT dates against each other,
587 so it doesn't matter what time zone we parse them in.
590 t = mktime (&tm);
591 if (t == (time_t) -1) t = 0;
593 if (verbose) {
594 const char *s = string;
595 while (*s && *s != '\r' && *s != '\n')
596 fputc (*s++, stdout);
597 printf (" ==> %lu\n", (unsigned long) t);
600 return t;
602 } else {
603 return 0;
609 static void
610 check_document_dates (const char *headers)
612 const char *s;
613 char *server_date = 0;
614 char *document_date = 0;
616 s = headers;
617 while (*s) {
618 const char *field = s;
619 const char *value = 0;
621 /* Find the end of the header field */
622 while (*s && !isspace(*s) && *s != ':')
623 s++;
625 /* Remember the header value, if any. */
626 if (*s == ':')
627 value = ++s;
629 /* Skip to the end of the header, including continuation lines. */
630 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
631 s++;
632 s++;
634 /* Process this header. */
635 if (value && value > field+2) {
636 char *ff = (char *) malloc (value-field);
637 char *ss = ff;
638 while (field < value-1)
639 *ss++ = tolower(*field++);
640 *ss++ = 0;
642 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
643 const char *e;
644 while (*value && isspace (*value))
645 value++;
646 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
648 ss = (char *) malloc (e - value + 1);
649 strncpy (ss, value, e - value);
650 ss[e - value] = 0;
651 if (!strcmp (ff, "date")) {
652 if (server_date) free (server_date);
653 server_date = ss;
654 } else {
655 if (document_date) free (document_date);
656 document_date = ss;
659 free (ff);
663 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
664 if (!server_date || !*server_date) {
665 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Server date unknown\n"));
666 } else if (!document_date || !*document_date) {
667 die (STATE_CRITICAL, _("HTTP CRITICAL - Document modification date unknown\n"));
668 } else {
669 time_t srv_data = parse_time_string (server_date);
670 time_t doc_data = parse_time_string (document_date);
672 if (srv_data <= 0) {
673 die (STATE_CRITICAL, _("HTTP CRITICAL - Server date \"%100s\" unparsable"), server_date);
674 } else if (doc_data <= 0) {
675 die (STATE_CRITICAL, _("HTTP CRITICAL - Document date \"%100s\" unparsable"), document_date);
676 } else if (doc_data > srv_data + 30) {
677 die (STATE_CRITICAL, _("HTTP CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
678 } else if (doc_data < srv_data - maximum_age) {
679 int n = (srv_data - doc_data);
680 if (n > (60 * 60 * 24 * 2))
681 die (STATE_CRITICAL,
682 _("HTTP CRITICAL - Last modified %.1f days ago\n"),
683 ((float) n) / (60 * 60 * 24));
684 else
685 die (STATE_CRITICAL,
686 _("HTTP CRITICAL - Last modified %d:%02d:%02d ago\n"),
687 n / (60 * 60), (n / 60) % 60, n % 60);
690 free (server_date);
691 free (document_date);
696 get_content_length (const char *headers)
698 const char *s;
699 int content_length = 0;
701 s = headers;
702 while (*s) {
703 const char *field = s;
704 const char *value = 0;
706 /* Find the end of the header field */
707 while (*s && !isspace(*s) && *s != ':')
708 s++;
710 /* Remember the header value, if any. */
711 if (*s == ':')
712 value = ++s;
714 /* Skip to the end of the header, including continuation lines. */
715 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
716 s++;
717 s++;
719 /* Process this header. */
720 if (value && value > field+2) {
721 char *ff = (char *) malloc (value-field);
722 char *ss = ff;
723 while (field < value-1)
724 *ss++ = tolower(*field++);
725 *ss++ = 0;
727 if (!strcmp (ff, "content-length")) {
728 const char *e;
729 while (*value && isspace (*value))
730 value++;
731 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
733 ss = (char *) malloc (e - value + 1);
734 strncpy (ss, value, e - value);
735 ss[e - value] = 0;
736 content_length = atoi(ss);
737 free (ss);
739 free (ff);
742 return (content_length);
746 check_http (void)
748 char *msg;
749 char *status_line;
750 char *status_code;
751 char *header;
752 char *page;
753 char *auth;
754 int http_status;
755 int i = 0;
756 size_t pagesize = 0;
757 char *full_page;
758 char *buf;
759 char *pos;
760 long microsec;
761 double elapsed_time;
762 int page_len = 0;
763 int result = STATE_UNKNOWN;
765 /* try to connect to the host at the given port number */
766 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
767 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
768 #ifdef HAVE_SSL
769 if (use_ssl == TRUE) {
770 np_net_ssl_init(sd);
771 if (check_cert == TRUE) {
772 result = np_net_ssl_check_cert(days_till_exp);
773 np_net_ssl_cleanup();
774 if(sd) close(sd);
775 return result;
778 #endif /* HAVE_SSL */
780 asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
782 /* optionally send the host header info */
783 if (host_name)
784 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
786 /* optionally send any other header tag */
787 if (http_opt_headers_count) {
788 for (i = 0; i < http_opt_headers_count ; i++) {
789 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
790 asprintf (&buf, "%s%s\r\n", buf, pos);
792 free(http_opt_headers);
795 /* optionally send the authentication info */
796 if (strlen(user_auth)) {
797 auth = base64 (user_auth, strlen (user_auth));
798 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
801 /* either send http POST data */
802 if (http_post_data) {
803 if (http_content_type) {
804 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
805 } else {
806 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
809 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
810 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
812 else {
813 /* or just a newline so the server knows we're done with the request */
814 asprintf (&buf, "%s%s", buf, CRLF);
817 if (verbose) printf ("%s\n", buf);
818 my_send (buf, strlen (buf));
820 /* fetch the page */
821 full_page = strdup("");
822 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
823 buffer[i] = '\0';
824 asprintf (&full_page, "%s%s", full_page, buffer);
825 pagesize += i;
827 if (no_body && document_headers_done (full_page)) {
828 i = 0;
829 break;
833 if (i < 0 && errno != ECONNRESET) {
834 #ifdef HAVE_SSL
836 if (use_ssl) {
837 sslerr=SSL_get_error(ssl, i);
838 if ( sslerr == SSL_ERROR_SSL ) {
839 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
840 } else {
841 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
844 else {
846 #endif
847 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
848 #ifdef HAVE_SSL
849 /* XXX
852 #endif
855 /* return a CRITICAL status if we couldn't read any data */
856 if (pagesize == (size_t) 0)
857 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
859 /* close the connection */
860 #ifdef HAVE_SSL
861 np_net_ssl_cleanup();
862 #endif
863 if(sd) close(sd);
865 /* reset the alarm */
866 alarm (0);
868 /* leave full_page untouched so we can free it later */
869 page = full_page;
871 if (verbose)
872 printf ("%s://%s:%d%s is %d characters\n",
873 use_ssl ? "https" : "http", server_address,
874 server_port, server_url, (int)pagesize);
876 /* find status line and null-terminate it */
877 status_line = page;
878 page += (size_t) strcspn (page, "\r\n");
879 pos = page;
880 page += (size_t) strspn (page, "\r\n");
881 status_line[strcspn(status_line, "\r\n")] = 0;
882 strip (status_line);
883 if (verbose)
884 printf ("STATUS: %s\n", status_line);
886 /* find header info and null-terminate it */
887 header = page;
888 while (strcspn (page, "\r\n") > 0) {
889 page += (size_t) strcspn (page, "\r\n");
890 pos = page;
891 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
892 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
893 page += (size_t) 2;
894 else
895 page += (size_t) 1;
897 page += (size_t) strspn (page, "\r\n");
898 header[pos - header] = 0;
899 if (verbose)
900 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
901 (no_body ? " [[ skipped ]]" : page));
903 /* make sure the status line matches the response we are looking for */
904 if (!strstr (status_line, server_expect)) {
905 if (server_port == HTTP_PORT)
906 asprintf (&msg,
907 _("Invalid HTTP response received from host\n"));
908 else
909 asprintf (&msg,
910 _("Invalid HTTP response received from host on port %d\n"),
911 server_port);
912 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
915 /* Exit here if server_expect was set by user and not default */
916 if ( server_expect_yn ) {
917 asprintf (&msg,
918 _("HTTP OK: Status line output matched \"%s\"\n"),
919 server_expect);
920 if (verbose)
921 printf ("%s\n",msg);
923 else {
924 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
925 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
926 /* Status-Code = 3 DIGITS */
928 status_code = strchr (status_line, ' ') + sizeof (char);
929 if (strspn (status_code, "1234567890") != 3)
930 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
932 http_status = atoi (status_code);
934 /* check the return code */
936 if (http_status >= 600 || http_status < 100)
937 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
939 /* server errors result in a critical state */
940 else if (http_status >= 500)
941 die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
943 /* client errors result in a warning state */
944 else if (http_status >= 400)
945 die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
947 /* check redirected page if specified */
948 else if (http_status >= 300) {
950 if (onredirect == STATE_DEPENDENT)
951 redir (header, status_line);
952 else if (onredirect == STATE_UNKNOWN)
953 printf (_("HTTP UNKNOWN"));
954 else if (onredirect == STATE_OK)
955 printf (_("HTTP OK"));
956 else if (onredirect == STATE_WARNING)
957 printf (_("HTTP WARNING"));
958 else if (onredirect == STATE_CRITICAL)
959 printf (_("HTTP CRITICAL"));
960 microsec = deltime (tv);
961 elapsed_time = (double)microsec / 1.0e6;
962 die (onredirect,
963 _(" - %s - %.3f second response time %s|%s %s\n"),
964 status_line, elapsed_time,
965 (display_html ? "</A>" : ""),
966 perfd_time (elapsed_time), perfd_size (pagesize));
967 } /* end if (http_status >= 300) */
969 } /* end else (server_expect_yn) */
971 if (maximum_age >= 0) {
972 check_document_dates (header);
975 /* check elapsed time */
976 microsec = deltime (tv);
977 elapsed_time = (double)microsec / 1.0e6;
978 asprintf (&msg,
979 _("HTTP WARNING: %s - %.3f second response time %s|%s %s\n"),
980 status_line, elapsed_time,
981 (display_html ? "</A>" : ""),
982 perfd_time (elapsed_time), perfd_size (pagesize));
983 if (check_critical_time == TRUE && elapsed_time > critical_time)
984 die (STATE_CRITICAL, "%s", msg);
985 if (check_warning_time == TRUE && elapsed_time > warning_time)
986 die (STATE_WARNING, "%s", msg);
988 /* Page and Header content checks go here */
989 /* these checks should be last */
991 if (strlen (string_expect)) {
992 if (strstr (page, string_expect)) {
993 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
994 status_line, elapsed_time,
995 (display_html ? "</A>" : ""),
996 perfd_time (elapsed_time), perfd_size (pagesize));
997 exit (STATE_OK);
999 else {
1000 printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
1001 (display_html ? "</A>" : ""),
1002 perfd_time (elapsed_time), perfd_size (pagesize));
1003 exit (STATE_CRITICAL);
1007 if (strlen (regexp)) {
1008 errcode = regexec (&preg, page, REGS, pmatch, 0);
1009 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1010 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1011 status_line, elapsed_time,
1012 (display_html ? "</A>" : ""),
1013 perfd_time (elapsed_time), perfd_size (pagesize));
1014 exit (STATE_OK);
1016 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1017 if (invert_regex == 0)
1018 msg = strdup(_("pattern not found"));
1019 else
1020 msg = strdup(_("pattern found"));
1021 printf (("%s - %s%s|%s %s\n"),
1022 _("HTTP CRITICAL"),
1023 msg,
1024 (display_html ? "</A>" : ""),
1025 perfd_time (elapsed_time), perfd_size (pagesize));
1026 exit (STATE_CRITICAL);
1028 else {
1029 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1030 printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
1031 exit (STATE_CRITICAL);
1035 /* make sure the page is of an appropriate size */
1036 /* page_len = get_content_length(header); */
1037 page_len = pagesize;
1038 if ((max_page_len > 0) && (page_len > max_page_len)) {
1039 printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1040 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1041 exit (STATE_WARNING);
1042 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1043 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1044 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1045 exit (STATE_WARNING);
1047 /* We only get here if all tests have been passed */
1048 asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1049 status_line, page_len, elapsed_time,
1050 (display_html ? "</A>" : ""),
1051 perfd_time (elapsed_time), perfd_size (page_len));
1052 die (STATE_OK, "%s", msg);
1053 return STATE_UNKNOWN;
1058 /* per RFC 2396 */
1059 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1060 #define URI_HTTP "%[HTPShtps]://"
1061 #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1062 #define URI_PORT ":%[0123456789]"
1063 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1064 #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
1065 #define HD2 URI_HTTP URI_HOST URI_PATH
1066 #define HD3 URI_HTTP URI_HOST URI_PORT
1067 #define HD4 URI_HTTP URI_HOST
1068 #define HD5 URI_PATH
1070 void
1071 redir (char *pos, char *status_line)
1073 int i = 0;
1074 char *x;
1075 char xx[2];
1076 char type[6];
1077 char *addr;
1078 char port[6];
1079 char *url;
1081 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1082 if (addr == NULL)
1083 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1085 url = malloc (strcspn (pos, "\r\n"));
1086 if (url == NULL)
1087 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
1089 while (pos) {
1090 sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i);
1091 if (i == 0) {
1092 pos += (size_t) strcspn (pos, "\r\n");
1093 pos += (size_t) strspn (pos, "\r\n");
1094 if (strlen(pos) == 0)
1095 die (STATE_UNKNOWN,
1096 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1097 status_line, (display_html ? "</A>" : ""));
1098 continue;
1101 pos += i;
1102 pos += strspn (pos, " \t\r\n");
1104 url = realloc (url, strcspn (pos, "\r\n"));
1105 if (url == NULL)
1106 die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1108 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1109 if (sscanf (pos, HD1, type, addr, port, url) == 4) {
1110 use_ssl = server_type_check (type);
1111 i = atoi (port);
1114 /* URI_HTTP URI_HOST URI_PATH */
1115 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1116 use_ssl = server_type_check (type);
1117 i = server_port_check (use_ssl);
1120 /* URI_HTTP URI_HOST URI_PORT */
1121 else if(sscanf (pos, HD3, type, addr, port) == 3) {
1122 strcpy (url, HTTP_URL);
1123 use_ssl = server_type_check (type);
1124 i = atoi (port);
1127 /* URI_HTTP URI_HOST */
1128 else if(sscanf (pos, HD4, type, addr) == 2) {
1129 strcpy (url, HTTP_URL);
1130 use_ssl = server_type_check (type);
1131 i = server_port_check (use_ssl);
1134 /* URI_PATH */
1135 else if (sscanf (pos, HD5, url) == 1) {
1136 /* relative url */
1137 if ((url[0] != '/')) {
1138 if ((x = strrchr(server_url, '/')))
1139 *x = '\0';
1140 asprintf (&url, "%s/%s", server_url, url);
1142 i = server_port;
1143 strcpy (type, server_type);
1144 strcpy (addr, host_name);
1147 else {
1148 die (STATE_UNKNOWN,
1149 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1150 pos, (display_html ? "</A>" : ""));
1153 break;
1155 } /* end while (pos) */
1157 if (++redir_depth > max_depth)
1158 die (STATE_WARNING,
1159 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1160 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1162 if (server_port==i &&
1163 !strcmp(server_address, addr) &&
1164 (host_name && !strcmp(host_name, addr)) &&
1165 !strcmp(server_url, url))
1166 die (STATE_WARNING,
1167 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1168 type, addr, i, url, (display_html ? "</A>" : ""));
1170 server_port = i;
1171 strcpy (server_type, type);
1173 free (host_name);
1174 host_name = strdup (addr);
1176 free (server_address);
1177 server_address = strdup (addr);
1179 free (server_url);
1180 server_url = strdup (url);
1182 check_http ();
1188 server_type_check (const char *type)
1190 if (strcmp (type, "https"))
1191 return FALSE;
1192 else
1193 return TRUE;
1197 server_port_check (int ssl_flag)
1199 if (ssl_flag)
1200 return HTTPS_PORT;
1201 else
1202 return HTTP_PORT;
1205 char *perfd_time (double elapsed_time)
1207 return fperfdata ("time", elapsed_time, "s",
1208 check_warning_time, warning_time,
1209 check_critical_time, critical_time,
1210 TRUE, 0, FALSE, 0);
1215 char *perfd_size (int page_len)
1217 return perfdata ("size", page_len, "B",
1218 (min_page_len>0?TRUE:FALSE), min_page_len,
1219 (min_page_len>0?TRUE:FALSE), 0,
1220 TRUE, 0, FALSE, 0);
1223 void
1224 print_help (void)
1226 print_revision (progname, revision);
1228 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1229 printf (COPYRIGHT, copyright, email);
1231 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1232 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1233 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1234 printf ("%s\n", _("certificate expiration times."));
1236 printf ("\n\n");
1238 print_usage ();
1240 printf (_("NOTE: One or both of -H and -I must be specified"));
1242 printf ("\n");
1244 printf (_(UT_HELP_VRSN));
1246 printf (" %s\n", "-H, --hostname=ADDRESS");
1247 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1248 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1249 printf (" %s\n", "-I, --IP-address=ADDRESS");
1250 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1251 printf (" %s\n", "-p, --port=INTEGER");
1252 printf (" %s", _("Port number (default: "));
1253 printf ("%d)\n", HTTP_PORT);
1255 printf (_(UT_IPv46));
1257 #ifdef HAVE_SSL
1258 printf (" %s\n", "-S, --ssl");
1259 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1260 printf (" %s\n", "-C, --certificate=INTEGER");
1261 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1262 printf (" %s\n", _("(when this option is used the url is not checked.)\n"));
1263 #endif
1265 printf (" %s\n", "-e, --expect=STRING");
1266 printf (" %s\n", _("String to expect in first (status) line of server response (default: "));
1267 printf ("%s)\n", HTTP_EXPECT);
1268 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1269 printf (" %s\n", "-s, --string=STRING");
1270 printf (" %s\n", _("String to expect in the content"));
1271 printf (" %s\n", "-u, --url=PATH");
1272 printf (" %s\n", _("URL to GET or POST (default: /)"));
1273 printf (" %s\n", "-P, --post=STRING");
1274 printf (" %s\n", _("URL encoded http POST data"));
1275 printf (" %s\n", "-N, --no-body");
1276 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1277 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1278 printf (" %s\n", "-M, --max-age=SECONDS");
1279 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1280 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1281 printf (" %s\n", "-T, --content-type=STRING");
1282 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1284 printf (" %s\n", "-l, --linespan");
1285 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1286 printf (" %s\n", "-r, --regex, --ereg=STRING");
1287 printf (" %s\n", _("Search page for regex STRING"));
1288 printf (" %s\n", "-R, --eregi=STRING");
1289 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1290 printf (" %s\n", "--invert-regex");
1291 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1293 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1294 printf (" %s\n", _("Username:password on sites with basic authentication"));
1295 printf (" %s\n", "-A, --useragent=STRING");
1296 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1297 printf (" %s\n", "-k, --header=STRING");
1298 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1299 printf (" %s\n", "-L, --link");
1300 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1301 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1302 printf (" %s\n", _("How to handle redirected pages"));
1303 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1304 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1306 printf (_(UT_WARN_CRIT));
1308 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1310 printf (_(UT_VERBOSE));
1312 printf (_("Notes:"));
1313 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1314 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1315 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1316 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1317 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1318 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1320 #ifdef HAVE_SSL
1321 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1322 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1323 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1324 printf (_("Examples:"));
1325 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1326 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1327 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1328 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1329 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1331 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1332 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1333 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1334 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1335 printf (" %s\n\n", _("the certificate is expired."));
1336 #endif
1338 printf (_(UT_SUPPORT));
1344 void
1345 print_usage (void)
1347 printf (_("Usage:"));
1348 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1349 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1350 printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1351 printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1352 printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1353 printf (" [-k string] [-S] [-C <age>] [-T <content-type>]\n");