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 *full_page_new;
788 char *buf;
789 char *pos;
790 long microsec;
791 double elapsed_time;
792 int page_len = 0;
793 int result = STATE_OK;
795 /* try to connect to the host at the given port number */
796 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
797 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
798 #ifdef HAVE_SSL
799 if (use_ssl == TRUE) {
800 np_net_ssl_init_with_hostname(sd, host_name);
801 if (check_cert == TRUE) {
802 result = np_net_ssl_check_cert(days_till_exp);
803 np_net_ssl_cleanup();
804 if (sd) close(sd);
805 return result;
806 }
807 }
808 #endif /* HAVE_SSL */
810 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
812 /* tell HTTP/1.1 servers not to keep the connection alive */
813 asprintf (&buf, "%sConnection: close\r\n", buf);
815 /* optionally send the host header info */
816 if (host_name) {
817 /*
818 * Specify the port only if we're using a non-default port (see RFC 2616,
819 * 14.23). Some server applications/configurations cause trouble if the
820 * (default) port is explicitly specified in the "Host:" header line.
821 */
822 if ((use_ssl == FALSE && server_port == HTTP_PORT) ||
823 (use_ssl == TRUE && server_port == HTTPS_PORT))
824 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
825 else
826 asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
827 }
829 /* optionally send any other header tag */
830 if (http_opt_headers_count) {
831 for (i = 0; i < http_opt_headers_count ; i++) {
832 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
833 asprintf (&buf, "%s%s\r\n", buf, pos);
834 }
835 /* This cannot be free'd here because a redirection will then try to access this and segfault */
836 /* Covered in a testcase in tests/check_http.t */
837 /* free(http_opt_headers); */
838 }
840 /* optionally send the authentication info */
841 if (strlen(user_auth)) {
842 base64_encode_alloc (user_auth, strlen (user_auth), &auth);
843 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
844 }
846 /* optionally send the proxy authentication info */
847 if (strlen(proxy_auth)) {
848 base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth);
849 asprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
850 }
852 /* either send http POST data (any data, not only POST)*/
853 if (http_post_data) {
854 if (http_content_type) {
855 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
856 } else {
857 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
858 }
860 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
861 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
862 }
863 else {
864 /* or just a newline so the server knows we're done with the request */
865 asprintf (&buf, "%s%s", buf, CRLF);
866 }
868 if (verbose) printf ("%s\n", buf);
869 my_send (buf, strlen (buf));
871 /* fetch the page */
872 full_page = strdup("");
873 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
874 buffer[i] = '\0';
875 asprintf (&full_page_new, "%s%s", full_page, buffer);
876 free (full_page);
877 full_page = full_page_new;
878 pagesize += i;
880 if (no_body && document_headers_done (full_page)) {
881 i = 0;
882 break;
883 }
884 }
886 if (i < 0 && errno != ECONNRESET) {
887 #ifdef HAVE_SSL
888 /*
889 if (use_ssl) {
890 sslerr=SSL_get_error(ssl, i);
891 if ( sslerr == SSL_ERROR_SSL ) {
892 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
893 } else {
894 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
895 }
896 }
897 else {
898 */
899 #endif
900 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
901 #ifdef HAVE_SSL
902 /* XXX
903 }
904 */
905 #endif
906 }
908 /* return a CRITICAL status if we couldn't read any data */
909 if (pagesize == (size_t) 0)
910 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
912 /* close the connection */
913 #ifdef HAVE_SSL
914 np_net_ssl_cleanup();
915 #endif
916 if (sd) close(sd);
918 /* Save check time */
919 microsec = deltime (tv);
920 elapsed_time = (double)microsec / 1.0e6;
922 /* leave full_page untouched so we can free it later */
923 page = full_page;
925 if (verbose)
926 printf ("%s://%s:%d%s is %d characters\n",
927 use_ssl ? "https" : "http", server_address,
928 server_port, server_url, (int)pagesize);
930 /* find status line and null-terminate it */
931 status_line = page;
932 page += (size_t) strcspn (page, "\r\n");
933 pos = page;
934 page += (size_t) strspn (page, "\r\n");
935 status_line[strcspn(status_line, "\r\n")] = 0;
936 strip (status_line);
937 if (verbose)
938 printf ("STATUS: %s\n", status_line);
940 /* find header info and null-terminate it */
941 header = page;
942 while (strcspn (page, "\r\n") > 0) {
943 page += (size_t) strcspn (page, "\r\n");
944 pos = page;
945 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
946 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
947 page += (size_t) 2;
948 else
949 page += (size_t) 1;
950 }
951 page += (size_t) strspn (page, "\r\n");
952 header[pos - header] = 0;
953 if (verbose)
954 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
955 (no_body ? " [[ skipped ]]" : page));
957 /* make sure the status line matches the response we are looking for */
958 if (!expected_statuscode (status_line, server_expect)) {
959 if (server_port == HTTP_PORT)
960 asprintf (&msg,
961 _("Invalid HTTP response received from host: %s\n"),
962 status_line);
963 else
964 asprintf (&msg,
965 _("Invalid HTTP response received from host on port %d: %s\n"),
966 server_port, status_line);
967 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
968 }
970 /* Bypass normal status line check if server_expect was set by user and not default */
971 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
972 if ( server_expect_yn ) {
973 asprintf (&msg,
974 _("Status line output matched \"%s\" - "), server_expect);
975 if (verbose)
976 printf ("%s\n",msg);
977 }
978 else {
979 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
980 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
981 /* Status-Code = 3 DIGITS */
983 status_code = strchr (status_line, ' ') + sizeof (char);
984 if (strspn (status_code, "1234567890") != 3)
985 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
987 http_status = atoi (status_code);
989 /* check the return code */
991 if (http_status >= 600 || http_status < 100) {
992 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
993 }
994 /* server errors result in a critical state */
995 else if (http_status >= 500) {
996 asprintf (&msg, _("%s - "), status_line);
997 result = STATE_CRITICAL;
998 }
999 /* client errors result in a warning state */
1000 else if (http_status >= 400) {
1001 asprintf (&msg, _("%s - "), status_line);
1002 result = max_state_alt(STATE_WARNING, result);
1003 }
1004 /* check redirected page if specified */
1005 else if (http_status >= 300) {
1007 if (onredirect == STATE_DEPENDENT)
1008 redir (header, status_line);
1009 else
1010 result = max_state_alt(onredirect, result);
1011 asprintf (&msg, _("%s - "), status_line);
1012 } /* end if (http_status >= 300) */
1013 else {
1014 /* Print OK status anyway */
1015 asprintf (&msg, _("%s - "), status_line);
1016 }
1018 } /* end else (server_expect_yn) */
1020 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
1021 alarm (0);
1023 if (maximum_age >= 0) {
1024 result = max_state_alt(check_document_dates(header, &msg), result);
1025 }
1027 /* Page and Header content checks go here */
1029 if (strlen (string_expect)) {
1030 if (!strstr (page, string_expect)) {
1031 asprintf (&msg, _("%sstring not found, "), msg);
1032 result = 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 /* OK - No-op to avoid changing the logic around it */
1040 result = max_state_alt(STATE_OK, result);
1041 }
1042 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1043 if (invert_regex == 0)
1044 asprintf (&msg, _("%spattern not found, "), msg);
1045 else
1046 asprintf (&msg, _("%spattern found, "), msg);
1047 result = STATE_CRITICAL;
1048 }
1049 else {
1050 /* FIXME: Shouldn't that be UNKNOWN? */
1051 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1052 asprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf);
1053 result = STATE_CRITICAL;
1054 }
1055 }
1057 /* make sure the page is of an appropriate size */
1058 /* page_len = get_content_length(header); */
1059 /* FIXME: Will this work with -N ? IMHO we should use
1060 * get_content_length(header) and always check if it's different than the
1061 * returned pagesize
1062 */
1063 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1064 * it == get_content_length(header) ??
1065 */
1066 page_len = pagesize;
1067 if ((max_page_len > 0) && (page_len > max_page_len)) {
1068 asprintf (&msg, _("%spage size %d too large, "), msg, page_len);
1069 result = max_state_alt(STATE_WARNING, result);
1070 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1071 asprintf (&msg, _("%spage size %d too small, "), msg, page_len);
1072 result = max_state_alt(STATE_WARNING, result);
1073 }
1075 /* Cut-off trailing characters */
1076 if(msg[strlen(msg)-2] == ',')
1077 msg[strlen(msg)-2] = '\0';
1078 else
1079 msg[strlen(msg)-3] = '\0';
1081 /* check elapsed time */
1082 asprintf (&msg,
1083 _("%s - %d bytes in %.3f second response time %s|%s %s"),
1084 msg, page_len, elapsed_time,
1085 (display_html ? "</A>" : ""),
1086 perfd_time (elapsed_time), perfd_size (page_len));
1088 if (check_critical_time == TRUE && elapsed_time > critical_time)
1089 result = STATE_CRITICAL;
1090 if (check_warning_time == TRUE && elapsed_time > warning_time)
1091 result = max_state_alt(STATE_WARNING, result);
1093 die (result, "HTTP %s: %s\n", state_text(result), msg);
1094 /* die failed? */
1095 return STATE_UNKNOWN;
1096 }
1100 /* per RFC 2396 */
1101 #define URI_HTTP "%5[HTPShtps]"
1102 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1103 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1104 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1105 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1106 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1107 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1108 #define HD4 URI_HTTP "://" URI_HOST
1109 #define HD5 URI_PATH
1111 void
1112 redir (char *pos, char *status_line)
1113 {
1114 int i = 0;
1115 char *x;
1116 char xx[2];
1117 char type[6];
1118 char *addr;
1119 char *url;
1121 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1122 if (addr == NULL)
1123 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1125 url = malloc (strcspn (pos, "\r\n"));
1126 if (url == NULL)
1127 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1129 while (pos) {
1130 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1131 if (i == 0) {
1132 pos += (size_t) strcspn (pos, "\r\n");
1133 pos += (size_t) strspn (pos, "\r\n");
1134 if (strlen(pos) == 0)
1135 die (STATE_UNKNOWN,
1136 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1137 status_line, (display_html ? "</A>" : ""));
1138 continue;
1139 }
1141 pos += i;
1142 pos += strspn (pos, " \t");
1144 /*
1145 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1146 * preceding each extra line with at least one SP or HT.''
1147 */
1148 for (; (i = strspn (pos, "\r\n")); pos += i) {
1149 pos += i;
1150 if (!(i = strspn (pos, " \t"))) {
1151 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1152 display_html ? "</A>" : "");
1153 }
1154 }
1156 url = realloc (url, strcspn (pos, "\r\n") + 1);
1157 if (url == NULL)
1158 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1160 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1161 if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
1162 url = prepend_slash (url);
1163 use_ssl = server_type_check (type);
1164 }
1166 /* URI_HTTP URI_HOST URI_PATH */
1167 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1168 url = prepend_slash (url);
1169 use_ssl = server_type_check (type);
1170 i = server_port_check (use_ssl);
1171 }
1173 /* URI_HTTP URI_HOST URI_PORT */
1174 else if (sscanf (pos, HD3, type, addr, &i) == 3) {
1175 strcpy (url, HTTP_URL);
1176 use_ssl = server_type_check (type);
1177 }
1179 /* URI_HTTP URI_HOST */
1180 else if (sscanf (pos, HD4, type, addr) == 2) {
1181 strcpy (url, HTTP_URL);
1182 use_ssl = server_type_check (type);
1183 i = server_port_check (use_ssl);
1184 }
1186 /* URI_PATH */
1187 else if (sscanf (pos, HD5, url) == 1) {
1188 /* relative url */
1189 if ((url[0] != '/')) {
1190 if ((x = strrchr(server_url, '/')))
1191 *x = '\0';
1192 asprintf (&url, "%s/%s", server_url, url);
1193 }
1194 i = server_port;
1195 strcpy (type, server_type);
1196 strcpy (addr, host_name ? host_name : server_address);
1197 }
1199 else {
1200 die (STATE_UNKNOWN,
1201 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1202 pos, (display_html ? "</A>" : ""));
1203 }
1205 break;
1207 } /* end while (pos) */
1209 if (++redir_depth > max_depth)
1210 die (STATE_WARNING,
1211 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1212 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1214 if (server_port==i &&
1215 !strcmp(server_address, addr) &&
1216 (host_name && !strcmp(host_name, addr)) &&
1217 !strcmp(server_url, url))
1218 die (STATE_WARNING,
1219 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1220 type, addr, i, url, (display_html ? "</A>" : ""));
1222 strcpy (server_type, type);
1224 free (host_name);
1225 host_name = strdup (addr);
1227 if (!(followsticky & STICKY_HOST)) {
1228 free (server_address);
1229 server_address = strdup (addr);
1230 }
1231 if (!(followsticky & STICKY_PORT)) {
1232 server_port = i;
1233 }
1235 free (server_url);
1236 server_url = url;
1238 if (server_port > MAX_PORT)
1239 die (STATE_UNKNOWN,
1240 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1241 MAX_PORT, server_type, server_address, server_port, server_url,
1242 display_html ? "</A>" : "");
1244 if (verbose)
1245 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1246 host_name ? host_name : server_address, server_port, server_url);
1248 check_http ();
1249 }
1252 int
1253 server_type_check (const char *type)
1254 {
1255 if (strcmp (type, "https"))
1256 return FALSE;
1257 else
1258 return TRUE;
1259 }
1261 int
1262 server_port_check (int ssl_flag)
1263 {
1264 if (ssl_flag)
1265 return HTTPS_PORT;
1266 else
1267 return HTTP_PORT;
1268 }
1270 char *perfd_time (double elapsed_time)
1271 {
1272 return fperfdata ("time", elapsed_time, "s",
1273 check_warning_time, warning_time,
1274 check_critical_time, critical_time,
1275 TRUE, 0, FALSE, 0);
1276 }
1280 char *perfd_size (int page_len)
1281 {
1282 return perfdata ("size", page_len, "B",
1283 (min_page_len>0?TRUE:FALSE), min_page_len,
1284 (min_page_len>0?TRUE:FALSE), 0,
1285 TRUE, 0, FALSE, 0);
1286 }
1288 void
1289 print_help (void)
1290 {
1291 print_revision (progname, NP_VERSION);
1293 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1294 printf (COPYRIGHT, copyright, email);
1296 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1297 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1298 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1299 printf ("%s\n", _("certificate expiration times."));
1301 printf ("\n\n");
1303 print_usage ();
1305 printf (_("NOTE: One or both of -H and -I must be specified"));
1307 printf ("\n");
1309 printf (_(UT_HELP_VRSN));
1310 printf (_(UT_EXTRA_OPTS));
1312 printf (" %s\n", "-H, --hostname=ADDRESS");
1313 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1314 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1315 printf (" %s\n", "-I, --IP-address=ADDRESS");
1316 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1317 printf (" %s\n", "-p, --port=INTEGER");
1318 printf (" %s", _("Port number (default: "));
1319 printf ("%d)\n", HTTP_PORT);
1321 printf (_(UT_IPv46));
1323 #ifdef HAVE_SSL
1324 printf (" %s\n", "-S, --ssl");
1325 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1326 printf (" %s\n", "-C, --certificate=INTEGER");
1327 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1328 printf (" %s\n", _("(when this option is used the URL is not checked.)\n"));
1329 #endif
1331 printf (" %s\n", "-e, --expect=STRING");
1332 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1333 printf (" %s", _("the first (status) line of the server response (default: "));
1334 printf ("%s)\n", HTTP_EXPECT);
1335 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1336 printf (" %s\n", "-s, --string=STRING");
1337 printf (" %s\n", _("String to expect in the content"));
1338 printf (" %s\n", "-u, --url=PATH");
1339 printf (" %s\n", _("URL to GET or POST (default: /)"));
1340 printf (" %s\n", "-P, --post=STRING");
1341 printf (" %s\n", _("URL encoded http POST data"));
1342 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)");
1343 printf (" %s\n", _("Set HTTP method."));
1344 printf (" %s\n", "-N, --no-body");
1345 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1346 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1347 printf (" %s\n", "-M, --max-age=SECONDS");
1348 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1349 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1350 printf (" %s\n", "-T, --content-type=STRING");
1351 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1353 printf (" %s\n", "-l, --linespan");
1354 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1355 printf (" %s\n", "-r, --regex, --ereg=STRING");
1356 printf (" %s\n", _("Search page for regex STRING"));
1357 printf (" %s\n", "-R, --eregi=STRING");
1358 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1359 printf (" %s\n", "--invert-regex");
1360 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1362 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1363 printf (" %s\n", _("Username:password on sites with basic authentication"));
1364 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
1365 printf (" %s\n", _("Username:password on proxy-servers with basic authentication"));
1366 printf (" %s\n", "-A, --useragent=STRING");
1367 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1368 printf (" %s\n", "-k, --header=STRING");
1369 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1370 printf (" %s\n", "-L, --link");
1371 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1372 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1373 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1374 printf (" %s\n", _("specified IP address. stickyport also ensure post stays the same."));
1375 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1376 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1378 printf (_(UT_WARN_CRIT));
1380 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1382 printf (_(UT_VERBOSE));
1384 printf ("\n");
1385 printf ("%s\n", _("Notes:"));
1386 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1387 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1388 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1389 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1390 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1391 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1392 printf ("\n");
1393 printf (_(UT_EXTRA_OPTS_NOTES));
1395 #ifdef HAVE_SSL
1396 printf ("\n");
1397 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1398 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1399 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1400 printf ("\n");
1401 printf ("%s\n", _("Examples:"));
1402 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1403 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1404 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1405 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1406 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1408 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1409 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1410 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1411 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1412 printf (" %s\n", _("the certificate is expired."));
1413 #endif
1415 printf (_(UT_SUPPORT));
1417 }
1421 void
1422 print_usage (void)
1423 {
1424 printf (_("Usage:"));
1425 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1426 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-a auth]\n");
1427 printf (" [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]\n");
1428 printf (" [-e <expect>] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
1429 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1430 printf (" [-A string] [-k string] [-S] [-C <age>] [-T <content-type>] [-j method]\n");
1431 }