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