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 /* This cannot be free'd here because a redirection will then try to access this and segfault */
819 /* Covered in a testcase in tests/check_http.t */
820 /* free(http_opt_headers); */
821 }
823 /* optionally send the authentication info */
824 if (strlen(user_auth)) {
825 base64_encode_alloc (user_auth, strlen (user_auth), &auth);
826 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
827 }
829 /* either send http POST data (any data, not only POST)*/
830 if (http_post_data) {
831 if (http_content_type) {
832 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
833 } else {
834 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
835 }
837 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
838 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
839 }
840 else {
841 /* or just a newline so the server knows we're done with the request */
842 asprintf (&buf, "%s%s", buf, CRLF);
843 }
845 if (verbose) printf ("%s\n", buf);
846 my_send (buf, strlen (buf));
848 /* fetch the page */
849 full_page = strdup("");
850 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
851 buffer[i] = '\0';
852 asprintf (&full_page, "%s%s", full_page, buffer);
853 pagesize += i;
855 if (no_body && document_headers_done (full_page)) {
856 i = 0;
857 break;
858 }
859 }
861 if (i < 0 && errno != ECONNRESET) {
862 #ifdef HAVE_SSL
863 /*
864 if (use_ssl) {
865 sslerr=SSL_get_error(ssl, i);
866 if ( sslerr == SSL_ERROR_SSL ) {
867 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
868 } else {
869 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
870 }
871 }
872 else {
873 */
874 #endif
875 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
876 #ifdef HAVE_SSL
877 /* XXX
878 }
879 */
880 #endif
881 }
883 /* return a CRITICAL status if we couldn't read any data */
884 if (pagesize == (size_t) 0)
885 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
887 /* close the connection */
888 #ifdef HAVE_SSL
889 np_net_ssl_cleanup();
890 #endif
891 if (sd) close(sd);
893 /* reset the alarm */
894 alarm (0);
896 /* leave full_page untouched so we can free it later */
897 page = full_page;
899 if (verbose)
900 printf ("%s://%s:%d%s is %d characters\n",
901 use_ssl ? "https" : "http", server_address,
902 server_port, server_url, (int)pagesize);
904 /* find status line and null-terminate it */
905 status_line = page;
906 page += (size_t) strcspn (page, "\r\n");
907 pos = page;
908 page += (size_t) strspn (page, "\r\n");
909 status_line[strcspn(status_line, "\r\n")] = 0;
910 strip (status_line);
911 if (verbose)
912 printf ("STATUS: %s\n", status_line);
914 /* find header info and null-terminate it */
915 header = page;
916 while (strcspn (page, "\r\n") > 0) {
917 page += (size_t) strcspn (page, "\r\n");
918 pos = page;
919 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
920 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
921 page += (size_t) 2;
922 else
923 page += (size_t) 1;
924 }
925 page += (size_t) strspn (page, "\r\n");
926 header[pos - header] = 0;
927 if (verbose)
928 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
929 (no_body ? " [[ skipped ]]" : page));
931 /* make sure the status line matches the response we are looking for */
932 if (!expected_statuscode (status_line, server_expect)) {
933 if (server_port == HTTP_PORT)
934 asprintf (&msg,
935 _("Invalid HTTP response received from host: %s\n"),
936 status_line);
937 else
938 asprintf (&msg,
939 _("Invalid HTTP response received from host on port %d: %s\n"),
940 server_port, status_line);
941 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
942 }
944 /* Exit here if server_expect was set by user and not default */
945 if ( server_expect_yn ) {
946 asprintf (&msg,
947 _("HTTP OK: Status line output matched \"%s\"\n"),
948 server_expect);
949 if (verbose)
950 printf ("%s\n",msg);
951 }
952 else {
953 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
954 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
955 /* Status-Code = 3 DIGITS */
957 status_code = strchr (status_line, ' ') + sizeof (char);
958 if (strspn (status_code, "1234567890") != 3)
959 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
961 http_status = atoi (status_code);
963 /* check the return code */
965 if (http_status >= 600 || http_status < 100)
966 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
968 /* server errors result in a critical state */
969 else if (http_status >= 500)
970 die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
972 /* client errors result in a warning state */
973 else if (http_status >= 400)
974 die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
976 /* check redirected page if specified */
977 else if (http_status >= 300) {
979 if (onredirect == STATE_DEPENDENT)
980 redir (header, status_line);
981 else if (onredirect == STATE_UNKNOWN)
982 printf (_("HTTP UNKNOWN"));
983 else if (onredirect == STATE_OK)
984 printf (_("HTTP OK"));
985 else if (onredirect == STATE_WARNING)
986 printf (_("HTTP WARNING"));
987 else if (onredirect == STATE_CRITICAL)
988 printf (_("HTTP CRITICAL"));
989 microsec = deltime (tv);
990 elapsed_time = (double)microsec / 1.0e6;
991 die (onredirect,
992 _(" - %s - %.3f second response time %s|%s %s\n"),
993 status_line, elapsed_time,
994 (display_html ? "</A>" : ""),
995 perfd_time (elapsed_time), perfd_size (pagesize));
996 } /* end if (http_status >= 300) */
998 } /* end else (server_expect_yn) */
1000 if (maximum_age >= 0) {
1001 check_document_dates (header);
1002 }
1004 /* check elapsed time */
1005 microsec = deltime (tv);
1006 elapsed_time = (double)microsec / 1.0e6;
1007 asprintf (&msg,
1008 _(" - %s - %.3f second response time %s|%s %s\n"),
1009 status_line, elapsed_time,
1010 (display_html ? "</A>" : ""),
1011 perfd_time (elapsed_time), perfd_size (pagesize));
1012 if (check_critical_time == TRUE && elapsed_time > critical_time)
1013 die (STATE_CRITICAL, "HTTP %s: %s", _("CRITICAL"), msg);
1014 if (check_warning_time == TRUE && elapsed_time > warning_time)
1015 die (STATE_WARNING, "HTTP %s: %s", _("WARNING"), msg);
1017 /* Page and Header content checks go here */
1018 /* these checks should be last */
1020 if (strlen (string_expect)) {
1021 if (strstr (page, string_expect)) {
1022 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1023 status_line, elapsed_time,
1024 (display_html ? "</A>" : ""),
1025 perfd_time (elapsed_time), perfd_size (pagesize));
1026 exit (STATE_OK);
1027 }
1028 else {
1029 printf (_("HTTP CRITICAL - string not found%s|%s %s\n"),
1030 (display_html ? "</A>" : ""),
1031 perfd_time (elapsed_time), perfd_size (pagesize));
1032 exit (STATE_CRITICAL);
1033 }
1034 }
1036 if (strlen (regexp)) {
1037 errcode = regexec (&preg, page, REGS, pmatch, 0);
1038 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1039 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1040 status_line, elapsed_time,
1041 (display_html ? "</A>" : ""),
1042 perfd_time (elapsed_time), perfd_size (pagesize));
1043 exit (STATE_OK);
1044 }
1045 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1046 if (invert_regex == 0)
1047 msg = strdup(_("pattern not found"));
1048 else
1049 msg = strdup(_("pattern found"));
1050 printf (("%s - %s%s|%s %s\n"),
1051 _("HTTP CRITICAL"),
1052 msg,
1053 (display_html ? "</A>" : ""),
1054 perfd_time (elapsed_time), perfd_size (pagesize));
1055 exit (STATE_CRITICAL);
1056 }
1057 else {
1058 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1059 printf (_("HTTP CRITICAL - Execute Error: %s\n"), errbuf);
1060 exit (STATE_CRITICAL);
1061 }
1062 }
1064 /* make sure the page is of an appropriate size */
1065 /* page_len = get_content_length(header); */
1066 page_len = pagesize;
1067 if ((max_page_len > 0) && (page_len > max_page_len)) {
1068 printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1069 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1070 exit (STATE_WARNING);
1071 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1072 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1073 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1074 exit (STATE_WARNING);
1075 }
1076 /* We only get here if all tests have been passed */
1077 asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1078 status_line, page_len, elapsed_time,
1079 (display_html ? "</A>" : ""),
1080 perfd_time (elapsed_time), perfd_size (page_len));
1081 die (STATE_OK, "%s", msg);
1082 return STATE_UNKNOWN;
1083 }
1087 /* per RFC 2396 */
1088 #define URI_HTTP "%5[HTPShtps]"
1089 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1090 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1091 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1092 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1093 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1094 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1095 #define HD4 URI_HTTP "://" URI_HOST
1096 #define HD5 URI_PATH
1098 void
1099 redir (char *pos, char *status_line)
1100 {
1101 int i = 0;
1102 char *x;
1103 char xx[2];
1104 char type[6];
1105 char *addr;
1106 char *url;
1108 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1109 if (addr == NULL)
1110 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1112 url = malloc (strcspn (pos, "\r\n"));
1113 if (url == NULL)
1114 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate url\n"));
1116 while (pos) {
1117 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1118 if (i == 0) {
1119 pos += (size_t) strcspn (pos, "\r\n");
1120 pos += (size_t) strspn (pos, "\r\n");
1121 if (strlen(pos) == 0)
1122 die (STATE_UNKNOWN,
1123 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1124 status_line, (display_html ? "</A>" : ""));
1125 continue;
1126 }
1128 pos += i;
1129 pos += strspn (pos, " \t");
1131 /*
1132 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1133 * preceding each extra line with at least one SP or HT.''
1134 */
1135 for (; (i = strspn (pos, "\r\n")); pos += i) {
1136 pos += i;
1137 if (!(i = strspn (pos, " \t"))) {
1138 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1139 display_html ? "</A>" : "");
1140 }
1141 }
1143 url = realloc (url, strcspn (pos, "\r\n") + 1);
1144 if (url == NULL)
1145 die (STATE_UNKNOWN, _("HTTP UNKNOWN - could not allocate url\n"));
1147 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1148 if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
1149 url = prepend_slash (url);
1150 use_ssl = server_type_check (type);
1151 }
1153 /* URI_HTTP URI_HOST URI_PATH */
1154 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1155 url = prepend_slash (url);
1156 use_ssl = server_type_check (type);
1157 i = server_port_check (use_ssl);
1158 }
1160 /* URI_HTTP URI_HOST URI_PORT */
1161 else if (sscanf (pos, HD3, type, addr, &i) == 3) {
1162 strcpy (url, HTTP_URL);
1163 use_ssl = server_type_check (type);
1164 }
1166 /* URI_HTTP URI_HOST */
1167 else if (sscanf (pos, HD4, type, addr) == 2) {
1168 strcpy (url, HTTP_URL);
1169 use_ssl = server_type_check (type);
1170 i = server_port_check (use_ssl);
1171 }
1173 /* URI_PATH */
1174 else if (sscanf (pos, HD5, url) == 1) {
1175 /* relative url */
1176 if ((url[0] != '/')) {
1177 if ((x = strrchr(server_url, '/')))
1178 *x = '\0';
1179 asprintf (&url, "%s/%s", server_url, url);
1180 }
1181 i = server_port;
1182 strcpy (type, server_type);
1183 strcpy (addr, host_name ? host_name : server_address);
1184 }
1186 else {
1187 die (STATE_UNKNOWN,
1188 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1189 pos, (display_html ? "</A>" : ""));
1190 }
1192 break;
1194 } /* end while (pos) */
1196 if (++redir_depth > max_depth)
1197 die (STATE_WARNING,
1198 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1199 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1201 if (server_port==i &&
1202 !strcmp(server_address, addr) &&
1203 (host_name && !strcmp(host_name, addr)) &&
1204 !strcmp(server_url, url))
1205 die (STATE_WARNING,
1206 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1207 type, addr, i, url, (display_html ? "</A>" : ""));
1209 strcpy (server_type, type);
1211 free (host_name);
1212 host_name = strdup (addr);
1214 free (server_address);
1215 server_address = strdup (addr);
1217 free (server_url);
1218 server_url = url;
1220 if ((server_port = i) > MAX_PORT)
1221 die (STATE_UNKNOWN,
1222 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1223 MAX_PORT, server_type, server_address, server_port, server_url,
1224 display_html ? "</A>" : "");
1226 if (verbose)
1227 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1228 host_name ? host_name : server_address, server_port, server_url);
1230 check_http ();
1231 }
1235 int
1236 server_type_check (const char *type)
1237 {
1238 if (strcmp (type, "https"))
1239 return FALSE;
1240 else
1241 return TRUE;
1242 }
1244 int
1245 server_port_check (int ssl_flag)
1246 {
1247 if (ssl_flag)
1248 return HTTPS_PORT;
1249 else
1250 return HTTP_PORT;
1251 }
1253 char *perfd_time (double elapsed_time)
1254 {
1255 return fperfdata ("time", elapsed_time, "s",
1256 check_warning_time, warning_time,
1257 check_critical_time, critical_time,
1258 TRUE, 0, FALSE, 0);
1259 }
1263 char *perfd_size (int page_len)
1264 {
1265 return perfdata ("size", page_len, "B",
1266 (min_page_len>0?TRUE:FALSE), min_page_len,
1267 (min_page_len>0?TRUE:FALSE), 0,
1268 TRUE, 0, FALSE, 0);
1269 }
1271 void
1272 print_help (void)
1273 {
1274 print_revision (progname, revision);
1276 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1277 printf (COPYRIGHT, copyright, email);
1279 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1280 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1281 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1282 printf ("%s\n", _("certificate expiration times."));
1284 printf ("\n\n");
1286 print_usage ();
1288 printf (_("NOTE: One or both of -H and -I must be specified"));
1290 printf ("\n");
1292 printf (_(UT_HELP_VRSN));
1293 printf (_(UT_EXTRA_OPTS));
1295 printf (" %s\n", "-H, --hostname=ADDRESS");
1296 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1297 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1298 printf (" %s\n", "-I, --IP-address=ADDRESS");
1299 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1300 printf (" %s\n", "-p, --port=INTEGER");
1301 printf (" %s", _("Port number (default: "));
1302 printf ("%d)\n", HTTP_PORT);
1304 printf (_(UT_IPv46));
1306 #ifdef HAVE_SSL
1307 printf (" %s\n", "-S, --ssl");
1308 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1309 printf (" %s\n", "-C, --certificate=INTEGER");
1310 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1311 printf (" %s\n", _("(when this option is used the url is not checked.)\n"));
1312 #endif
1314 printf (" %s\n", "-e, --expect=STRING");
1315 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1316 printf (" %s", _("the first (status) line of the server response (default: "));
1317 printf ("%s)\n", HTTP_EXPECT);
1318 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1319 printf (" %s\n", "-s, --string=STRING");
1320 printf (" %s\n", _("String to expect in the content"));
1321 printf (" %s\n", "-u, --url=PATH");
1322 printf (" %s\n", _("URL to GET or POST (default: /)"));
1323 printf (" %s\n", "-P, --post=STRING");
1324 printf (" %s\n", _("URL encoded http POST data"));
1325 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)");
1326 printf (" %s\n", _("Set HTTP method."));
1327 printf (" %s\n", "-N, --no-body");
1328 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1329 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1330 printf (" %s\n", "-M, --max-age=SECONDS");
1331 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1332 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1333 printf (" %s\n", "-T, --content-type=STRING");
1334 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1336 printf (" %s\n", "-l, --linespan");
1337 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1338 printf (" %s\n", "-r, --regex, --ereg=STRING");
1339 printf (" %s\n", _("Search page for regex STRING"));
1340 printf (" %s\n", "-R, --eregi=STRING");
1341 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1342 printf (" %s\n", "--invert-regex");
1343 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1345 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1346 printf (" %s\n", _("Username:password on sites with basic authentication"));
1347 printf (" %s\n", "-A, --useragent=STRING");
1348 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1349 printf (" %s\n", "-k, --header=STRING");
1350 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1351 printf (" %s\n", "-L, --link");
1352 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1353 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1354 printf (" %s\n", _("How to handle redirected pages"));
1355 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1356 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1358 printf (_(UT_WARN_CRIT));
1360 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1362 printf (_(UT_VERBOSE));
1364 printf ("\n");
1365 printf ("%s\n", _("Notes:"));
1366 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1367 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1368 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1369 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1370 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1371 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1372 printf ("\n");
1373 printf (_(UT_EXTRA_OPTS_NOTES));
1375 #ifdef HAVE_SSL
1376 printf ("\n");
1377 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1378 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1379 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1380 printf ("\n");
1381 printf ("%s\n", _("Examples:"));
1382 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1383 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1384 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1385 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1386 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1388 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1389 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1390 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1391 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1392 printf (" %s\n", _("the certificate is expired."));
1393 #endif
1395 printf (_(UT_SUPPORT));
1397 }
1401 void
1402 print_usage (void)
1403 {
1404 printf (_("Usage:"));
1405 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1406 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1407 printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1408 printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1409 printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1410 printf (" [-k string] [-S] [-C <age>] [-T <content-type>] [-j method]\n");
1411 }