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