1 /*****************************************************************************
2 *
3 * Nagios check_http plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2008 Nagios Plugins Development Team
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
11 *
12 * This file contains the check_http plugin
13 *
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.
18 *
19 *
20 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation, either version 3 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 *
33 * $Id$
34 *
35 *****************************************************************************/
37 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
39 const char *progname = "check_http";
40 const char *revision = "$Revision$";
41 const char *copyright = "1999-2008";
42 const char *email = "nagiosplug-devel@lists.sourceforge.net";
44 #include "common.h"
45 #include "netutils.h"
46 #include "utils.h"
47 #include "base64.h"
48 #include <ctype.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,
57 MAX_PORT = 65535
58 };
60 #ifdef HAVE_SSL
61 int check_cert = FALSE;
62 int days_till_exp;
63 char *randbuff;
64 X509 *server_cert;
65 # define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
66 # define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
67 #else /* ifndef HAVE_SSL */
68 # define my_recv(buf, len) read(sd, buf, len)
69 # define my_send(buf, len) send(sd, buf, len, 0)
70 #endif /* HAVE_SSL */
71 int no_body = FALSE;
72 int maximum_age = -1;
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 int invert_regex = 0;
87 struct timeval tv;
89 #define HTTP_URL "/"
90 #define CRLF "\r\n"
92 int specify_port = FALSE;
93 int server_port = HTTP_PORT;
94 char server_port_text[6] = "";
95 char server_type[6] = "http";
96 char *server_address;
97 char *host_name;
98 char *server_url;
99 char *user_agent;
100 int server_url_length;
101 int server_expect_yn = 0;
102 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
103 char string_expect[MAX_INPUT_BUFFER] = "";
104 double warning_time = 0;
105 int check_warning_time = FALSE;
106 double critical_time = 0;
107 int check_critical_time = FALSE;
108 char user_auth[MAX_INPUT_BUFFER] = "";
109 int display_html = FALSE;
110 char **http_opt_headers;
111 int http_opt_headers_count = 0;
112 int onredirect = STATE_OK;
113 int use_ssl = FALSE;
114 int verbose = FALSE;
115 int sd;
116 int min_page_len = 0;
117 int max_page_len = 0;
118 int redir_depth = 0;
119 int max_depth = 15;
120 char *http_method;
121 char *http_post_data;
122 char *http_content_type;
123 char buffer[MAX_INPUT_BUFFER];
125 int process_arguments (int, char **);
126 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);
135 int
136 main (int argc, char **argv)
137 {
138 int result = STATE_UNKNOWN;
140 setlocale (LC_ALL, "");
141 bindtextdomain (PACKAGE, LOCALEDIR);
142 textdomain (PACKAGE);
144 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
145 server_url = strdup(HTTP_URL);
146 server_url_length = strlen(server_url);
147 asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
148 clean_revstring (revision), VERSION);
150 /* Parse extra opts if any */
151 argv=np_extra_opts (&argc, argv, progname);
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;
168 }
172 /* process command-line arguments */
173 int
174 process_arguments (int argc, char **argv)
175 {
176 int c = 1;
177 char *p;
179 enum {
180 INVERT_REGEX = CHAR_MAX + 1
181 };
183 int option = 0;
184 static struct option longopts[] = {
185 STD_LONG_OPTS,
186 {"link", no_argument, 0, 'L'},
187 {"nohtml", no_argument, 0, 'n'},
188 {"ssl", no_argument, 0, 'S'},
189 {"post", required_argument, 0, 'P'},
190 {"method", required_argument, 0, 'j'},
191 {"IP-address", required_argument, 0, 'I'},
192 {"url", required_argument, 0, 'u'},
193 {"port", required_argument, 0, 'p'},
194 {"authorization", required_argument, 0, 'a'},
195 {"string", required_argument, 0, 's'},
196 {"expect", required_argument, 0, 'e'},
197 {"regex", required_argument, 0, 'r'},
198 {"ereg", required_argument, 0, 'r'},
199 {"eregi", required_argument, 0, 'R'},
200 {"linespan", no_argument, 0, 'l'},
201 {"onredirect", required_argument, 0, 'f'},
202 {"certificate", required_argument, 0, 'C'},
203 {"useragent", required_argument, 0, 'A'},
204 {"header", required_argument, 0, 'k'},
205 {"no-body", no_argument, 0, 'N'},
206 {"max-age", required_argument, 0, 'M'},
207 {"content-type", required_argument, 0, 'T'},
208 {"pagesize", required_argument, 0, 'm'},
209 {"invert-regex", no_argument, NULL, INVERT_REGEX},
210 {"use-ipv4", no_argument, 0, '4'},
211 {"use-ipv6", no_argument, 0, '6'},
212 {0, 0, 0, 0}
213 };
215 if (argc < 2)
216 return ERROR;
218 for (c = 1; c < argc; c++) {
219 if (strcmp ("-to", argv[c]) == 0)
220 strcpy (argv[c], "-t");
221 if (strcmp ("-hn", argv[c]) == 0)
222 strcpy (argv[c], "-H");
223 if (strcmp ("-wt", argv[c]) == 0)
224 strcpy (argv[c], "-w");
225 if (strcmp ("-ct", argv[c]) == 0)
226 strcpy (argv[c], "-c");
227 if (strcmp ("-nohtml", argv[c]) == 0)
228 strcpy (argv[c], "-n");
229 }
231 while (1) {
232 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:e:p:s:R:r:u:f:C:nlLSm:M:N", longopts, &option);
233 if (c == -1 || c == EOF)
234 break;
236 switch (c) {
237 case '?': /* usage */
238 usage5 ();
239 break;
240 case 'h': /* help */
241 print_help ();
242 exit (STATE_OK);
243 break;
244 case 'V': /* version */
245 print_revision (progname, revision);
246 exit (STATE_OK);
247 break;
248 case 't': /* timeout period */
249 if (!is_intnonneg (optarg))
250 usage2 (_("Timeout interval must be a positive integer"), optarg);
251 else
252 socket_timeout = atoi (optarg);
253 break;
254 case 'c': /* critical time threshold */
255 if (!is_nonnegative (optarg))
256 usage2 (_("Critical threshold must be integer"), optarg);
257 else {
258 critical_time = strtod (optarg, NULL);
259 check_critical_time = TRUE;
260 }
261 break;
262 case 'w': /* warning time threshold */
263 if (!is_nonnegative (optarg))
264 usage2 (_("Warning threshold must be integer"), optarg);
265 else {
266 warning_time = strtod (optarg, NULL);
267 check_warning_time = TRUE;
268 }
269 break;
270 case 'A': /* User Agent String */
271 asprintf (&user_agent, "User-Agent: %s", optarg);
272 break;
273 case 'k': /* Additional headers */
274 if (http_opt_headers_count == 0)
275 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
276 else
277 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
278 http_opt_headers[http_opt_headers_count - 1] = optarg;
279 /* asprintf (&http_opt_headers, "%s", optarg); */
280 break;
281 case 'L': /* show html link */
282 display_html = TRUE;
283 break;
284 case 'n': /* do not show html link */
285 display_html = FALSE;
286 break;
287 case 'C': /* Check SSL cert validity */
288 #ifdef HAVE_SSL
289 if (!is_intnonneg (optarg))
290 usage2 (_("Invalid certificate expiration period"), optarg);
291 else {
292 days_till_exp = atoi (optarg);
293 check_cert = TRUE;
294 }
295 /* Fall through to -S option */
296 #endif
297 case 'S': /* use SSL */
298 #ifndef HAVE_SSL
299 usage4 (_("Invalid option - SSL is not available"));
300 #endif
301 use_ssl = TRUE;
302 if (specify_port == FALSE)
303 server_port = HTTPS_PORT;
304 break;
305 case 'f': /* onredirect */
306 if (!strcmp (optarg, "follow"))
307 onredirect = STATE_DEPENDENT;
308 if (!strcmp (optarg, "unknown"))
309 onredirect = STATE_UNKNOWN;
310 if (!strcmp (optarg, "ok"))
311 onredirect = STATE_OK;
312 if (!strcmp (optarg, "warning"))
313 onredirect = STATE_WARNING;
314 if (!strcmp (optarg, "critical"))
315 onredirect = STATE_CRITICAL;
316 if (verbose)
317 printf(_("option f:%d \n"), onredirect);
318 break;
319 /* Note: H, I, and u must be malloc'd or will fail on redirects */
320 case 'H': /* Host Name (virtual host) */
321 host_name = strdup (optarg);
322 if (host_name[0] == '[') {
323 if ((p = strstr (host_name, "]:")) != NULL) /* [IPv6]:port */
324 server_port = atoi (p + 2);
325 } else if ((p = strchr (host_name, ':')) != NULL
326 && strchr (++p, ':') == NULL) /* IPv4:port or host:port */
327 server_port = atoi (p);
328 break;
329 case 'I': /* Server IP-address */
330 server_address = strdup (optarg);
331 break;
332 case 'u': /* URL path */
333 server_url = strdup (optarg);
334 server_url_length = strlen (server_url);
335 break;
336 case 'p': /* Server port */
337 if (!is_intnonneg (optarg))
338 usage2 (_("Invalid port number"), optarg);
339 else {
340 server_port = atoi (optarg);
341 specify_port = TRUE;
342 }
343 break;
344 case 'a': /* authorization info */
345 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
346 user_auth[MAX_INPUT_BUFFER - 1] = 0;
347 break;
348 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
349 if (! http_post_data)
350 http_post_data = strdup (optarg);
351 if (! http_method)
352 http_method = strdup("POST");
353 break;
354 case 'j': /* Set HTTP method */
355 if (http_method)
356 free(http_method);
357 http_method = strdup (optarg);
358 break;
359 case 's': /* string or substring */
360 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
361 string_expect[MAX_INPUT_BUFFER - 1] = 0;
362 break;
363 case 'e': /* string or substring */
364 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
365 server_expect[MAX_INPUT_BUFFER - 1] = 0;
366 server_expect_yn = 1;
367 break;
368 case 'T': /* Content-type */
369 asprintf (&http_content_type, "%s", optarg);
370 break;
371 case 'l': /* linespan */
372 cflags &= ~REG_NEWLINE;
373 break;
374 case 'R': /* regex */
375 cflags |= REG_ICASE;
376 case 'r': /* regex */
377 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
378 regexp[MAX_RE_SIZE - 1] = 0;
379 errcode = regcomp (&preg, regexp, cflags);
380 if (errcode != 0) {
381 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
382 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
383 return ERROR;
384 }
385 break;
386 case INVERT_REGEX:
387 invert_regex = 1;
388 break;
389 case '4':
390 address_family = AF_INET;
391 break;
392 case '6':
393 #ifdef USE_IPV6
394 address_family = AF_INET6;
395 #else
396 usage4 (_("IPv6 support not available"));
397 #endif
398 break;
399 case 'v': /* verbose */
400 verbose = TRUE;
401 break;
402 case 'm': /* min_page_length */
403 {
404 char *tmp;
405 if (strchr(optarg, ':') != (char *)NULL) {
406 /* range, so get two values, min:max */
407 tmp = strtok(optarg, ":");
408 if (tmp == NULL) {
409 printf("Bad format: try \"-m min:max\"\n");
410 exit (STATE_WARNING);
411 } else
412 min_page_len = atoi(tmp);
414 tmp = strtok(NULL, ":");
415 if (tmp == NULL) {
416 printf("Bad format: try \"-m min:max\"\n");
417 exit (STATE_WARNING);
418 } else
419 max_page_len = atoi(tmp);
420 } else
421 min_page_len = atoi (optarg);
422 break;
423 }
424 case 'N': /* no-body */
425 no_body = TRUE;
426 break;
427 case 'M': /* max-age */
428 {
429 int L = strlen(optarg);
430 if (L && optarg[L-1] == 'm')
431 maximum_age = atoi (optarg) * 60;
432 else if (L && optarg[L-1] == 'h')
433 maximum_age = atoi (optarg) * 60 * 60;
434 else if (L && optarg[L-1] == 'd')
435 maximum_age = atoi (optarg) * 60 * 60 * 24;
436 else if (L && (optarg[L-1] == 's' ||
437 isdigit (optarg[L-1])))
438 maximum_age = atoi (optarg);
439 else {
440 fprintf (stderr, "unparsable max-age: %s\n", optarg);
441 exit (STATE_WARNING);
442 }
443 }
444 break;
445 }
446 }
448 c = optind;
450 if (server_address == NULL && c < argc)
451 server_address = strdup (argv[c++]);
453 if (host_name == NULL && c < argc)
454 host_name = strdup (argv[c++]);
456 if (server_address == NULL) {
457 if (host_name == NULL)
458 usage4 (_("You must specify a server address or host name"));
459 else
460 server_address = strdup (host_name);
461 }
463 if (check_critical_time && critical_time>(double)socket_timeout)
464 socket_timeout = (int)critical_time + 1;
466 if (http_method == NULL)
467 http_method = strdup ("GET");
469 return TRUE;
470 }
474 /* Returns 1 if we're done processing the document body; 0 to keep going */
475 static int
476 document_headers_done (char *full_page)
477 {
478 const char *body;
480 for (body = full_page; *body; body++) {
481 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
482 break;
483 }
485 if (!*body)
486 return 0; /* haven't read end of headers yet */
488 full_page[body - full_page] = 0;
489 return 1;
490 }
492 static time_t
493 parse_time_string (const char *string)
494 {
495 struct tm tm;
496 time_t t;
497 memset (&tm, 0, sizeof(tm));
499 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
501 if (isupper (string[0]) && /* Tue */
502 islower (string[1]) &&
503 islower (string[2]) &&
504 ',' == string[3] &&
505 ' ' == string[4] &&
506 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
507 isdigit (string[6]) &&
508 ' ' == string[7] &&
509 isupper (string[8]) && /* Dec */
510 islower (string[9]) &&
511 islower (string[10]) &&
512 ' ' == string[11] &&
513 isdigit (string[12]) && /* 2001 */
514 isdigit (string[13]) &&
515 isdigit (string[14]) &&
516 isdigit (string[15]) &&
517 ' ' == string[16] &&
518 isdigit (string[17]) && /* 02: */
519 isdigit (string[18]) &&
520 ':' == string[19] &&
521 isdigit (string[20]) && /* 59: */
522 isdigit (string[21]) &&
523 ':' == string[22] &&
524 isdigit (string[23]) && /* 03 */
525 isdigit (string[24]) &&
526 ' ' == string[25] &&
527 'G' == string[26] && /* GMT */
528 'M' == string[27] && /* GMT */
529 'T' == string[28]) {
531 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
532 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
533 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
534 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
535 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
536 !strncmp (string+8, "Feb", 3) ? 1 :
537 !strncmp (string+8, "Mar", 3) ? 2 :
538 !strncmp (string+8, "Apr", 3) ? 3 :
539 !strncmp (string+8, "May", 3) ? 4 :
540 !strncmp (string+8, "Jun", 3) ? 5 :
541 !strncmp (string+8, "Jul", 3) ? 6 :
542 !strncmp (string+8, "Aug", 3) ? 7 :
543 !strncmp (string+8, "Sep", 3) ? 8 :
544 !strncmp (string+8, "Oct", 3) ? 9 :
545 !strncmp (string+8, "Nov", 3) ? 10 :
546 !strncmp (string+8, "Dec", 3) ? 11 :
547 -1);
548 tm.tm_year = ((1000 * (string[12]-'0') +
549 100 * (string[13]-'0') +
550 10 * (string[14]-'0') +
551 (string[15]-'0'))
552 - 1900);
554 tm.tm_isdst = 0; /* GMT is never in DST, right? */
556 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
557 return 0;
559 /*
560 This is actually wrong: we need to subtract the local timezone
561 offset from GMT from this value. But, that's ok in this usage,
562 because we only comparing these two GMT dates against each other,
563 so it doesn't matter what time zone we parse them in.
564 */
566 t = mktime (&tm);
567 if (t == (time_t) -1) t = 0;
569 if (verbose) {
570 const char *s = string;
571 while (*s && *s != '\r' && *s != '\n')
572 fputc (*s++, stdout);
573 printf (" ==> %lu\n", (unsigned long) t);
574 }
576 return t;
578 } else {
579 return 0;
580 }
581 }
583 /* Checks if the server 'reply' is one of the expected 'statuscodes' */
584 static int
585 expected_statuscode (const char *reply, const char *statuscodes)
586 {
587 char *expected, *code;
588 int result = 0;
590 if ((expected = strdup (statuscodes)) == NULL)
591 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
593 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
594 if (strstr (reply, code) != NULL) {
595 result = 1;
596 break;
597 }
599 free (expected);
600 return result;
601 }
603 static void
604 check_document_dates (const char *headers)
605 {
606 const char *s;
607 char *server_date = 0;
608 char *document_date = 0;
610 s = headers;
611 while (*s) {
612 const char *field = s;
613 const char *value = 0;
615 /* Find the end of the header field */
616 while (*s && !isspace(*s) && *s != ':')
617 s++;
619 /* Remember the header value, if any. */
620 if (*s == ':')
621 value = ++s;
623 /* Skip to the end of the header, including continuation lines. */
624 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
625 s++;
627 /* Avoid stepping over end-of-string marker */
628 if (*s)
629 s++;
631 /* Process this header. */
632 if (value && value > field+2) {
633 char *ff = (char *) malloc (value-field);
634 char *ss = ff;
635 while (field < value-1)
636 *ss++ = tolower(*field++);
637 *ss++ = 0;
639 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
640 const char *e;
641 while (*value && isspace (*value))
642 value++;
643 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
644 ;
645 ss = (char *) malloc (e - value + 1);
646 strncpy (ss, value, e - value);
647 ss[e - value] = 0;
648 if (!strcmp (ff, "date")) {
649 if (server_date) free (server_date);
650 server_date = ss;
651 } else {
652 if (document_date) free (document_date);
653 document_date = ss;
654 }
655 }
656 free (ff);
657 }
658 }
660 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
661 if (!server_date || !*server_date) {
662 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Server date unknown\n"));
663 } else if (!document_date || !*document_date) {
664 die (STATE_CRITICAL, _("HTTP CRITICAL - Document modification date unknown\n"));
665 } else {
666 time_t srv_data = parse_time_string (server_date);
667 time_t doc_data = parse_time_string (document_date);
669 if (srv_data <= 0) {
670 die (STATE_CRITICAL, _("HTTP CRITICAL - Server date \"%100s\" unparsable"), server_date);
671 } else if (doc_data <= 0) {
672 die (STATE_CRITICAL, _("HTTP CRITICAL - Document date \"%100s\" unparsable"), document_date);
673 } else if (doc_data > srv_data + 30) {
674 die (STATE_CRITICAL, _("HTTP CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
675 } else if (doc_data < srv_data - maximum_age) {
676 int n = (srv_data - doc_data);
677 if (n > (60 * 60 * 24 * 2))
678 die (STATE_CRITICAL,
679 _("HTTP CRITICAL - Last modified %.1f days ago\n"),
680 ((float) n) / (60 * 60 * 24));
681 else
682 die (STATE_CRITICAL,
683 _("HTTP CRITICAL - Last modified %d:%02d:%02d ago\n"),
684 n / (60 * 60), (n / 60) % 60, n % 60);
685 }
687 free (server_date);
688 free (document_date);
689 }
690 }
692 int
693 get_content_length (const char *headers)
694 {
695 const char *s;
696 int content_length = 0;
698 s = headers;
699 while (*s) {
700 const char *field = s;
701 const char *value = 0;
703 /* Find the end of the header field */
704 while (*s && !isspace(*s) && *s != ':')
705 s++;
707 /* Remember the header value, if any. */
708 if (*s == ':')
709 value = ++s;
711 /* Skip to the end of the header, including continuation lines. */
712 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
713 s++;
714 s++;
716 /* Process this header. */
717 if (value && value > field+2) {
718 char *ff = (char *) malloc (value-field);
719 char *ss = ff;
720 while (field < value-1)
721 *ss++ = tolower(*field++);
722 *ss++ = 0;
724 if (!strcmp (ff, "content-length")) {
725 const char *e;
726 while (*value && isspace (*value))
727 value++;
728 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
729 ;
730 ss = (char *) malloc (e - value + 1);
731 strncpy (ss, value, e - value);
732 ss[e - value] = 0;
733 content_length = atoi(ss);
734 free (ss);
735 }
736 free (ff);
737 }
738 }
739 return (content_length);
740 }
742 char *
743 prepend_slash (char *path)
744 {
745 char *newpath;
747 if (path[0] == '/')
748 return path;
750 if ((newpath = malloc (strlen(path) + 2)) == NULL)
751 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
752 newpath[0] = '/';
753 strcpy (newpath + 1, path);
754 free (path);
755 return newpath;
756 }
758 int
759 check_http (void)
760 {
761 char *msg;
762 char *status_line;
763 char *status_code;
764 char *header;
765 char *page;
766 char *auth;
767 int http_status;
768 int i = 0;
769 size_t pagesize = 0;
770 char *full_page;
771 char *buf;
772 char *pos;
773 long microsec;
774 double elapsed_time;
775 int page_len = 0;
776 int result = STATE_UNKNOWN;
778 /* try to connect to the host at the given port number */
779 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
780 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
781 #ifdef HAVE_SSL
782 if (use_ssl == TRUE) {
783 np_net_ssl_init(sd);
784 if (check_cert == TRUE) {
785 result = np_net_ssl_check_cert(days_till_exp);
786 np_net_ssl_cleanup();
787 if (sd) close(sd);
788 return result;
789 }
790 }
791 #endif /* HAVE_SSL */
793 asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
795 /* tell HTTP/1.1 servers not to keep the connection alive */
796 asprintf (&buf, "%sConnection: close\r\n", buf);
798 /* optionally send the host header info */
799 if (host_name) {
800 /*
801 * Specify the port only if we're using a non-default port (see RFC 2616,
802 * 14.23). Some server applications/configurations cause trouble if the
803 * (default) port is explicitly specified in the "Host:" header line.
804 */
805 if ((use_ssl == FALSE && server_port == HTTP_PORT) ||
806 (use_ssl == TRUE && server_port == HTTPS_PORT))
807 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
808 else
809 asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
810 }
812 /* optionally send any other header tag */
813 if (http_opt_headers_count) {
814 for (i = 0; i < http_opt_headers_count ; i++) {
815 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
816 asprintf (&buf, "%s%s\r\n", buf, pos);
817 }
818 free(http_opt_headers);
819 }
821 /* optionally send the authentication info */
822 if (strlen(user_auth)) {
823 base64_encode_alloc (user_auth, strlen (user_auth), &auth);
824 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
825 }
827 /* either send http POST data (any data, not only POST)*/
828 if (http_post_data) {
829 if (http_content_type) {
830 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
831 } else {
832 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
833 }
835 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
836 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
837 }
838 else {
839 /* or just a newline so the server knows we're done with the request */
840 asprintf (&buf, "%s%s", buf, CRLF);
841 }
843 if (verbose) printf ("%s\n", buf);
844 my_send (buf, strlen (buf));
846 /* fetch the page */
847 full_page = strdup("");
848 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
849 buffer[i] = '\0';
850 asprintf (&full_page, "%s%s", full_page, buffer);
851 pagesize += i;
853 if (no_body && document_headers_done (full_page)) {
854 i = 0;
855 break;
856 }
857 }
859 if (i < 0 && errno != ECONNRESET) {
860 #ifdef HAVE_SSL
861 /*
862 if (use_ssl) {
863 sslerr=SSL_get_error(ssl, i);
864 if ( sslerr == SSL_ERROR_SSL ) {
865 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
866 } else {
867 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
868 }
869 }
870 else {
871 */
872 #endif
873 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
874 #ifdef HAVE_SSL
875 /* XXX
876 }
877 */
878 #endif
879 }
881 /* return a CRITICAL status if we couldn't read any data */
882 if (pagesize == (size_t) 0)
883 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
885 /* close the connection */
886 #ifdef HAVE_SSL
887 np_net_ssl_cleanup();
888 #endif
889 if (sd) close(sd);
891 /* reset the alarm */
892 alarm (0);
894 /* leave full_page untouched so we can free it later */
895 page = full_page;
897 if (verbose)
898 printf ("%s://%s:%d%s is %d characters\n",
899 use_ssl ? "https" : "http", server_address,
900 server_port, server_url, (int)pagesize);
902 /* find status line and null-terminate it */
903 status_line = page;
904 page += (size_t) strcspn (page, "\r\n");
905 pos = page;
906 page += (size_t) strspn (page, "\r\n");
907 status_line[strcspn(status_line, "\r\n")] = 0;
908 strip (status_line);
909 if (verbose)
910 printf ("STATUS: %s\n", status_line);
912 /* find header info and null-terminate it */
913 header = page;
914 while (strcspn (page, "\r\n") > 0) {
915 page += (size_t) strcspn (page, "\r\n");
916 pos = page;
917 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
918 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
919 page += (size_t) 2;
920 else
921 page += (size_t) 1;
922 }
923 page += (size_t) strspn (page, "\r\n");
924 header[pos - header] = 0;
925 if (verbose)
926 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
927 (no_body ? " [[ skipped ]]" : page));
929 /* make sure the status line matches the response we are looking for */
930 if (!expected_statuscode (status_line, server_expect)) {
931 if (server_port == HTTP_PORT)
932 asprintf (&msg,
933 _("Invalid HTTP response received from host: %s\n"),
934 status_line);
935 else
936 asprintf (&msg,
937 _("Invalid HTTP response received from host on port %d: %s\n"),
938 server_port, status_line);
939 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
940 }
942 /* Exit here if server_expect was set by user and not default */
943 if ( server_expect_yn ) {
944 asprintf (&msg,
945 _("HTTP OK: Status line output matched \"%s\"\n"),
946 server_expect);
947 if (verbose)
948 printf ("%s\n",msg);
949 }
950 else {
951 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
952 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
953 /* Status-Code = 3 DIGITS */
955 status_code = strchr (status_line, ' ') + sizeof (char);
956 if (strspn (status_code, "1234567890") != 3)
957 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
959 http_status = atoi (status_code);
961 /* check the return code */
963 if (http_status >= 600 || http_status < 100)
964 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
966 /* server errors result in a critical state */
967 else if (http_status >= 500)
968 die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
970 /* client errors result in a warning state */
971 else if (http_status >= 400)
972 die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
974 /* check redirected page if specified */
975 else if (http_status >= 300) {
977 if (onredirect == STATE_DEPENDENT)
978 redir (header, status_line);
979 else if (onredirect == STATE_UNKNOWN)
980 printf (_("HTTP UNKNOWN"));
981 else if (onredirect == STATE_OK)
982 printf (_("HTTP OK"));
983 else if (onredirect == STATE_WARNING)
984 printf (_("HTTP WARNING"));
985 else if (onredirect == STATE_CRITICAL)
986 printf (_("HTTP CRITICAL"));
987 microsec = deltime (tv);
988 elapsed_time = (double)microsec / 1.0e6;
989 die (onredirect,
990 _(" - %s - %.3f second response time %s|%s %s\n"),
991 status_line, elapsed_time,
992 (display_html ? "</A>" : ""),
993 perfd_time (elapsed_time), perfd_size (pagesize));
994 } /* end if (http_status >= 300) */
996 } /* end else (server_expect_yn) */
998 if (maximum_age >= 0) {
999 check_document_dates (header);
1000 }
1002 /* check elapsed time */
1003 microsec = deltime (tv);
1004 elapsed_time = (double)microsec / 1.0e6;
1005 asprintf (&msg,
1006 _(" - %s - %.3f second response time %s|%s %s\n"),
1007 status_line, elapsed_time,
1008 (display_html ? "</A>" : ""),
1009 perfd_time (elapsed_time), perfd_size (pagesize));
1010 if (check_critical_time == TRUE && elapsed_time > critical_time)
1011 die (STATE_CRITICAL, "HTTP %s: %s", _("CRITICAL"), msg);
1012 if (check_warning_time == TRUE && elapsed_time > warning_time)
1013 die (STATE_WARNING, "HTTP %s: %s", _("WARNING"), msg);
1015 /* Page and Header content checks go here */
1016 /* these checks should be last */
1018 if (strlen (string_expect)) {
1019 if (strstr (page, string_expect)) {
1020 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1021 status_line, elapsed_time,
1022 (display_html ? "</A>" : ""),
1023 perfd_time (elapsed_time), perfd_size (pagesize));
1024 exit (STATE_OK);
1025 }
1026 else {
1027 printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
1028 (display_html ? "</A>" : ""),
1029 perfd_time (elapsed_time), perfd_size (pagesize));
1030 exit (STATE_CRITICAL);
1031 }
1032 }
1034 if (strlen (regexp)) {
1035 errcode = regexec (&preg, page, REGS, pmatch, 0);
1036 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1037 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1038 status_line, elapsed_time,
1039 (display_html ? "</A>" : ""),
1040 perfd_time (elapsed_time), perfd_size (pagesize));
1041 exit (STATE_OK);
1042 }
1043 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1044 if (invert_regex == 0)
1045 msg = strdup(_("pattern not found"));
1046 else
1047 msg = strdup(_("pattern found"));
1048 printf (("%s - %s%s|%s %s\n"),
1049 _("HTTP CRITICAL"),
1050 msg,
1051 (display_html ? "</A>" : ""),
1052 perfd_time (elapsed_time), perfd_size (pagesize));
1053 exit (STATE_CRITICAL);
1054 }
1055 else {
1056 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1057 printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
1058 exit (STATE_CRITICAL);
1059 }
1060 }
1062 /* make sure the page is of an appropriate size */
1063 /* page_len = get_content_length(header); */
1064 page_len = pagesize;
1065 if ((max_page_len > 0) && (page_len > max_page_len)) {
1066 printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1067 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1068 exit (STATE_WARNING);
1069 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1070 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1071 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1072 exit (STATE_WARNING);
1073 }
1074 /* We only get here if all tests have been passed */
1075 asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1076 status_line, page_len, elapsed_time,
1077 (display_html ? "</A>" : ""),
1078 perfd_time (elapsed_time), perfd_size (page_len));
1079 die (STATE_OK, "%s", msg);
1080 return STATE_UNKNOWN;
1081 }
1085 /* per RFC 2396 */
1086 #define URI_HTTP "%5[HTPShtps]"
1087 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1088 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1089 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1090 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1091 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1092 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1093 #define HD4 URI_HTTP "://" URI_HOST
1094 #define HD5 URI_PATH
1096 void
1097 redir (char *pos, char *status_line)
1098 {
1099 int i = 0;
1100 char *x;
1101 char xx[2];
1102 char type[6];
1103 char *addr;
1104 char *url;
1106 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1107 if (addr == NULL)
1108 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1110 url = malloc (strcspn (pos, "\r\n"));
1111 if (url == NULL)
1112 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
1114 while (pos) {
1115 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1116 if (i == 0) {
1117 pos += (size_t) strcspn (pos, "\r\n");
1118 pos += (size_t) strspn (pos, "\r\n");
1119 if (strlen(pos) == 0)
1120 die (STATE_UNKNOWN,
1121 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1122 status_line, (display_html ? "</A>" : ""));
1123 continue;
1124 }
1126 pos += i;
1127 pos += strspn (pos, " \t");
1129 /*
1130 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1131 * preceding each extra line with at least one SP or HT.''
1132 */
1133 for (; (i = strspn (pos, "\r\n")); pos += i) {
1134 pos += i;
1135 if (!(i = strspn (pos, " \t"))) {
1136 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1137 display_html ? "</A>" : "");
1138 }
1139 }
1141 url = realloc (url, strcspn (pos, "\r\n") + 1);
1142 if (url == NULL)
1143 die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1145 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1146 if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
1147 url = prepend_slash (url);
1148 use_ssl = server_type_check (type);
1149 }
1151 /* URI_HTTP URI_HOST URI_PATH */
1152 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1153 url = prepend_slash (url);
1154 use_ssl = server_type_check (type);
1155 i = server_port_check (use_ssl);
1156 }
1158 /* URI_HTTP URI_HOST URI_PORT */
1159 else if (sscanf (pos, HD3, type, addr, &i) == 3) {
1160 strcpy (url, HTTP_URL);
1161 use_ssl = server_type_check (type);
1162 }
1164 /* URI_HTTP URI_HOST */
1165 else if (sscanf (pos, HD4, type, addr) == 2) {
1166 strcpy (url, HTTP_URL);
1167 use_ssl = server_type_check (type);
1168 i = server_port_check (use_ssl);
1169 }
1171 /* URI_PATH */
1172 else if (sscanf (pos, HD5, url) == 1) {
1173 /* relative url */
1174 if ((url[0] != '/')) {
1175 if ((x = strrchr(server_url, '/')))
1176 *x = '\0';
1177 asprintf (&url, "%s/%s", server_url, url);
1178 }
1179 i = server_port;
1180 strcpy (type, server_type);
1181 strcpy (addr, host_name ? host_name : server_address);
1182 }
1184 else {
1185 die (STATE_UNKNOWN,
1186 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1187 pos, (display_html ? "</A>" : ""));
1188 }
1190 break;
1192 } /* end while (pos) */
1194 if (++redir_depth > max_depth)
1195 die (STATE_WARNING,
1196 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1197 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1199 if (server_port==i &&
1200 !strcmp(server_address, addr) &&
1201 (host_name && !strcmp(host_name, addr)) &&
1202 !strcmp(server_url, url))
1203 die (STATE_WARNING,
1204 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1205 type, addr, i, url, (display_html ? "</A>" : ""));
1207 strcpy (server_type, type);
1209 free (host_name);
1210 host_name = strdup (addr);
1212 free (server_address);
1213 server_address = strdup (addr);
1215 free (server_url);
1216 server_url = url;
1218 if ((server_port = i) > MAX_PORT)
1219 die (STATE_UNKNOWN,
1220 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1221 MAX_PORT, server_type, server_address, server_port, server_url,
1222 display_html ? "</A>" : "");
1224 if (verbose)
1225 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1226 host_name ? host_name : server_address, server_port, server_url);
1228 check_http ();
1229 }
1233 int
1234 server_type_check (const char *type)
1235 {
1236 if (strcmp (type, "https"))
1237 return FALSE;
1238 else
1239 return TRUE;
1240 }
1242 int
1243 server_port_check (int ssl_flag)
1244 {
1245 if (ssl_flag)
1246 return HTTPS_PORT;
1247 else
1248 return HTTP_PORT;
1249 }
1251 char *perfd_time (double elapsed_time)
1252 {
1253 return fperfdata ("time", elapsed_time, "s",
1254 check_warning_time, warning_time,
1255 check_critical_time, critical_time,
1256 TRUE, 0, FALSE, 0);
1257 }
1261 char *perfd_size (int page_len)
1262 {
1263 return perfdata ("size", page_len, "B",
1264 (min_page_len>0?TRUE:FALSE), min_page_len,
1265 (min_page_len>0?TRUE:FALSE), 0,
1266 TRUE, 0, FALSE, 0);
1267 }
1269 void
1270 print_help (void)
1271 {
1272 print_revision (progname, revision);
1274 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1275 printf (COPYRIGHT, copyright, email);
1277 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1278 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1279 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1280 printf ("%s\n", _("certificate expiration times."));
1282 printf ("\n\n");
1284 print_usage ();
1286 printf (_("NOTE: One or both of -H and -I must be specified"));
1288 printf ("\n");
1290 printf (_(UT_HELP_VRSN));
1291 printf (_(UT_EXTRA_OPTS));
1293 printf (" %s\n", "-H, --hostname=ADDRESS");
1294 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1295 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1296 printf (" %s\n", "-I, --IP-address=ADDRESS");
1297 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1298 printf (" %s\n", "-p, --port=INTEGER");
1299 printf (" %s", _("Port number (default: "));
1300 printf ("%d)\n", HTTP_PORT);
1302 printf (_(UT_IPv46));
1304 #ifdef HAVE_SSL
1305 printf (" %s\n", "-S, --ssl");
1306 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1307 printf (" %s\n", "-C, --certificate=INTEGER");
1308 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1309 printf (" %s\n", _("(when this option is used the url is not checked.)\n"));
1310 #endif
1312 printf (" %s\n", "-e, --expect=STRING");
1313 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1314 printf (" %s", _("the first (status) line of the server response (default: "));
1315 printf ("%s)\n", HTTP_EXPECT);
1316 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1317 printf (" %s\n", "-s, --string=STRING");
1318 printf (" %s\n", _("String to expect in the content"));
1319 printf (" %s\n", "-u, --url=PATH");
1320 printf (" %s\n", _("URL to GET or POST (default: /)"));
1321 printf (" %s\n", "-P, --post=STRING");
1322 printf (" %s\n", _("URL encoded http POST data"));
1323 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)");
1324 printf (" %s\n", _("Set HTTP method."));
1325 printf (" %s\n", "-N, --no-body");
1326 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1327 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1328 printf (" %s\n", "-M, --max-age=SECONDS");
1329 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1330 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1331 printf (" %s\n", "-T, --content-type=STRING");
1332 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1334 printf (" %s\n", "-l, --linespan");
1335 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1336 printf (" %s\n", "-r, --regex, --ereg=STRING");
1337 printf (" %s\n", _("Search page for regex STRING"));
1338 printf (" %s\n", "-R, --eregi=STRING");
1339 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1340 printf (" %s\n", "--invert-regex");
1341 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1343 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1344 printf (" %s\n", _("Username:password on sites with basic authentication"));
1345 printf (" %s\n", "-A, --useragent=STRING");
1346 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1347 printf (" %s\n", "-k, --header=STRING");
1348 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1349 printf (" %s\n", "-L, --link");
1350 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1351 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1352 printf (" %s\n", _("How to handle redirected pages"));
1353 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1354 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1356 printf (_(UT_WARN_CRIT));
1358 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1360 printf (_(UT_VERBOSE));
1362 printf ("\n");
1363 printf ("%s\n", _("Notes:"));
1364 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1365 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1366 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1367 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1368 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1369 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1370 printf ("\n");
1371 printf (_(UT_EXTRA_OPTS_NOTES));
1373 #ifdef HAVE_SSL
1374 printf ("\n");
1375 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1376 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1377 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1378 printf ("\n");
1379 printf ("%s\n", _("Examples:"));
1380 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1381 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1382 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1383 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1384 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1386 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1387 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1388 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1389 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1390 printf (" %s\n", _("the certificate is expired."));
1391 #endif
1393 printf (_(UT_SUPPORT));
1395 }
1399 void
1400 print_usage (void)
1401 {
1402 printf (_("Usage:"));
1403 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1404 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1405 printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1406 printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1407 printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1408 printf (" [-k string] [-S] [-C <age>] [-T <content-type>] [-j method]\n");
1409 }