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 int display_html = FALSE;
109 char **http_opt_headers;
110 int http_opt_headers_count = 0;
111 int onredirect = STATE_OK;
112 int followsticky = STICKY_NONE;
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/v%s (nagios-plugins %s)",
148 NP_VERSION, 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, NP_VERSION);
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, "stickyport"))
307 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT;
308 if (!strcmp (optarg, "sticky"))
309 onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST;
310 if (!strcmp (optarg, "follow"))
311 onredirect = STATE_DEPENDENT, followsticky = STICKY_NONE;
312 if (!strcmp (optarg, "unknown"))
313 onredirect = STATE_UNKNOWN;
314 if (!strcmp (optarg, "ok"))
315 onredirect = STATE_OK;
316 if (!strcmp (optarg, "warning"))
317 onredirect = STATE_WARNING;
318 if (!strcmp (optarg, "critical"))
319 onredirect = STATE_CRITICAL;
320 if (verbose)
321 printf(_("option f:%d \n"), onredirect);
322 break;
323 /* Note: H, I, and u must be malloc'd or will fail on redirects */
324 case 'H': /* Host Name (virtual host) */
325 host_name = strdup (optarg);
326 if (host_name[0] == '[') {
327 if ((p = strstr (host_name, "]:")) != NULL) /* [IPv6]:port */
328 server_port = atoi (p + 2);
329 } else if ((p = strchr (host_name, ':')) != NULL
330 && strchr (++p, ':') == NULL) /* IPv4:port or host:port */
331 server_port = atoi (p);
332 break;
333 case 'I': /* Server IP-address */
334 server_address = strdup (optarg);
335 break;
336 case 'u': /* URL path */
337 server_url = strdup (optarg);
338 server_url_length = strlen (server_url);
339 break;
340 case 'p': /* Server port */
341 if (!is_intnonneg (optarg))
342 usage2 (_("Invalid port number"), optarg);
343 else {
344 server_port = atoi (optarg);
345 specify_port = TRUE;
346 }
347 break;
348 case 'a': /* authorization info */
349 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
350 user_auth[MAX_INPUT_BUFFER - 1] = 0;
351 break;
352 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
353 if (! http_post_data)
354 http_post_data = strdup (optarg);
355 if (! http_method)
356 http_method = strdup("POST");
357 break;
358 case 'j': /* Set HTTP method */
359 if (http_method)
360 free(http_method);
361 http_method = strdup (optarg);
362 break;
363 case 's': /* string or substring */
364 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
365 string_expect[MAX_INPUT_BUFFER - 1] = 0;
366 break;
367 case 'e': /* string or substring */
368 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
369 server_expect[MAX_INPUT_BUFFER - 1] = 0;
370 server_expect_yn = 1;
371 break;
372 case 'T': /* Content-type */
373 asprintf (&http_content_type, "%s", optarg);
374 break;
375 case 'l': /* linespan */
376 cflags &= ~REG_NEWLINE;
377 break;
378 case 'R': /* regex */
379 cflags |= REG_ICASE;
380 case 'r': /* regex */
381 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
382 regexp[MAX_RE_SIZE - 1] = 0;
383 errcode = regcomp (&preg, regexp, cflags);
384 if (errcode != 0) {
385 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
386 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
387 return ERROR;
388 }
389 break;
390 case INVERT_REGEX:
391 invert_regex = 1;
392 break;
393 case '4':
394 address_family = AF_INET;
395 break;
396 case '6':
397 #ifdef USE_IPV6
398 address_family = AF_INET6;
399 #else
400 usage4 (_("IPv6 support not available"));
401 #endif
402 break;
403 case 'v': /* verbose */
404 verbose = TRUE;
405 break;
406 case 'm': /* min_page_length */
407 {
408 char *tmp;
409 if (strchr(optarg, ':') != (char *)NULL) {
410 /* range, so get two values, min:max */
411 tmp = strtok(optarg, ":");
412 if (tmp == NULL) {
413 printf("Bad format: try \"-m min:max\"\n");
414 exit (STATE_WARNING);
415 } else
416 min_page_len = atoi(tmp);
418 tmp = strtok(NULL, ":");
419 if (tmp == NULL) {
420 printf("Bad format: try \"-m min:max\"\n");
421 exit (STATE_WARNING);
422 } else
423 max_page_len = atoi(tmp);
424 } else
425 min_page_len = atoi (optarg);
426 break;
427 }
428 case 'N': /* no-body */
429 no_body = TRUE;
430 break;
431 case 'M': /* max-age */
432 {
433 int L = strlen(optarg);
434 if (L && optarg[L-1] == 'm')
435 maximum_age = atoi (optarg) * 60;
436 else if (L && optarg[L-1] == 'h')
437 maximum_age = atoi (optarg) * 60 * 60;
438 else if (L && optarg[L-1] == 'd')
439 maximum_age = atoi (optarg) * 60 * 60 * 24;
440 else if (L && (optarg[L-1] == 's' ||
441 isdigit (optarg[L-1])))
442 maximum_age = atoi (optarg);
443 else {
444 fprintf (stderr, "unparsable max-age: %s\n", optarg);
445 exit (STATE_WARNING);
446 }
447 }
448 break;
449 }
450 }
452 c = optind;
454 if (server_address == NULL && c < argc)
455 server_address = strdup (argv[c++]);
457 if (host_name == NULL && c < argc)
458 host_name = strdup (argv[c++]);
460 if (server_address == NULL) {
461 if (host_name == NULL)
462 usage4 (_("You must specify a server address or host name"));
463 else
464 server_address = strdup (host_name);
465 }
467 if (check_critical_time && critical_time>(double)socket_timeout)
468 socket_timeout = (int)critical_time + 1;
470 if (http_method == NULL)
471 http_method = strdup ("GET");
473 return TRUE;
474 }
478 /* Returns 1 if we're done processing the document body; 0 to keep going */
479 static int
480 document_headers_done (char *full_page)
481 {
482 const char *body;
484 for (body = full_page; *body; body++) {
485 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
486 break;
487 }
489 if (!*body)
490 return 0; /* haven't read end of headers yet */
492 full_page[body - full_page] = 0;
493 return 1;
494 }
496 static time_t
497 parse_time_string (const char *string)
498 {
499 struct tm tm;
500 time_t t;
501 memset (&tm, 0, sizeof(tm));
503 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
505 if (isupper (string[0]) && /* Tue */
506 islower (string[1]) &&
507 islower (string[2]) &&
508 ',' == string[3] &&
509 ' ' == string[4] &&
510 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
511 isdigit (string[6]) &&
512 ' ' == string[7] &&
513 isupper (string[8]) && /* Dec */
514 islower (string[9]) &&
515 islower (string[10]) &&
516 ' ' == string[11] &&
517 isdigit (string[12]) && /* 2001 */
518 isdigit (string[13]) &&
519 isdigit (string[14]) &&
520 isdigit (string[15]) &&
521 ' ' == string[16] &&
522 isdigit (string[17]) && /* 02: */
523 isdigit (string[18]) &&
524 ':' == string[19] &&
525 isdigit (string[20]) && /* 59: */
526 isdigit (string[21]) &&
527 ':' == string[22] &&
528 isdigit (string[23]) && /* 03 */
529 isdigit (string[24]) &&
530 ' ' == string[25] &&
531 'G' == string[26] && /* GMT */
532 'M' == string[27] && /* GMT */
533 'T' == string[28]) {
535 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
536 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
537 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
538 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
539 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
540 !strncmp (string+8, "Feb", 3) ? 1 :
541 !strncmp (string+8, "Mar", 3) ? 2 :
542 !strncmp (string+8, "Apr", 3) ? 3 :
543 !strncmp (string+8, "May", 3) ? 4 :
544 !strncmp (string+8, "Jun", 3) ? 5 :
545 !strncmp (string+8, "Jul", 3) ? 6 :
546 !strncmp (string+8, "Aug", 3) ? 7 :
547 !strncmp (string+8, "Sep", 3) ? 8 :
548 !strncmp (string+8, "Oct", 3) ? 9 :
549 !strncmp (string+8, "Nov", 3) ? 10 :
550 !strncmp (string+8, "Dec", 3) ? 11 :
551 -1);
552 tm.tm_year = ((1000 * (string[12]-'0') +
553 100 * (string[13]-'0') +
554 10 * (string[14]-'0') +
555 (string[15]-'0'))
556 - 1900);
558 tm.tm_isdst = 0; /* GMT is never in DST, right? */
560 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
561 return 0;
563 /*
564 This is actually wrong: we need to subtract the local timezone
565 offset from GMT from this value. But, that's ok in this usage,
566 because we only comparing these two GMT dates against each other,
567 so it doesn't matter what time zone we parse them in.
568 */
570 t = mktime (&tm);
571 if (t == (time_t) -1) t = 0;
573 if (verbose) {
574 const char *s = string;
575 while (*s && *s != '\r' && *s != '\n')
576 fputc (*s++, stdout);
577 printf (" ==> %lu\n", (unsigned long) t);
578 }
580 return t;
582 } else {
583 return 0;
584 }
585 }
587 /* Checks if the server 'reply' is one of the expected 'statuscodes' */
588 static int
589 expected_statuscode (const char *reply, const char *statuscodes)
590 {
591 char *expected, *code;
592 int result = 0;
594 if ((expected = strdup (statuscodes)) == NULL)
595 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
597 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
598 if (strstr (reply, code) != NULL) {
599 result = 1;
600 break;
601 }
603 free (expected);
604 return result;
605 }
607 static int
608 check_document_dates (const char *headers, char **msg)
609 {
610 const char *s;
611 char *server_date = 0;
612 char *document_date = 0;
613 int date_result = STATE_OK;
615 s = headers;
616 while (*s) {
617 const char *field = s;
618 const char *value = 0;
620 /* Find the end of the header field */
621 while (*s && !isspace(*s) && *s != ':')
622 s++;
624 /* Remember the header value, if any. */
625 if (*s == ':')
626 value = ++s;
628 /* Skip to the end of the header, including continuation lines. */
629 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
630 s++;
632 /* Avoid stepping over end-of-string marker */
633 if (*s)
634 s++;
636 /* Process this header. */
637 if (value && value > field+2) {
638 char *ff = (char *) malloc (value-field);
639 char *ss = ff;
640 while (field < value-1)
641 *ss++ = tolower(*field++);
642 *ss++ = 0;
644 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
645 const char *e;
646 while (*value && isspace (*value))
647 value++;
648 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
649 ;
650 ss = (char *) malloc (e - value + 1);
651 strncpy (ss, value, e - value);
652 ss[e - value] = 0;
653 if (!strcmp (ff, "date")) {
654 if (server_date) free (server_date);
655 server_date = ss;
656 } else {
657 if (document_date) free (document_date);
658 document_date = ss;
659 }
660 }
661 free (ff);
662 }
663 }
665 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
666 if (!server_date || !*server_date) {
667 asprintf (msg, _("%sServer date unknown, "), *msg);
668 date_result = max_state_alt(STATE_UNKNOWN, date_result);
669 } else if (!document_date || !*document_date) {
670 asprintf (msg, _("%sDocument modification date unknown, "), *msg);
671 date_result = max_state_alt(STATE_CRITICAL, date_result);
672 } else {
673 time_t srv_data = parse_time_string (server_date);
674 time_t doc_data = parse_time_string (document_date);
676 if (srv_data <= 0) {
677 asprintf (msg, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
678 date_result = max_state_alt(STATE_CRITICAL, date_result);
679 } else if (doc_data <= 0) {
680 asprintf (msg, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
681 date_result = max_state_alt(STATE_CRITICAL, date_result);
682 } else if (doc_data > srv_data + 30) {
683 asprintf (msg, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
684 date_result = max_state_alt(STATE_CRITICAL, date_result);
685 } else if (doc_data < srv_data - maximum_age) {
686 int n = (srv_data - doc_data);
687 if (n > (60 * 60 * 24 * 2)) {
688 asprintf (msg, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24));
689 date_result = max_state_alt(STATE_CRITICAL, date_result);
690 } else {
691 asprintf (msg, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
692 date_result = max_state_alt(STATE_CRITICAL, date_result);
693 }
694 }
695 free (server_date);
696 free (document_date);
697 }
698 return date_result;
699 }
701 int
702 get_content_length (const char *headers)
703 {
704 const char *s;
705 int content_length = 0;
707 s = headers;
708 while (*s) {
709 const char *field = s;
710 const char *value = 0;
712 /* Find the end of the header field */
713 while (*s && !isspace(*s) && *s != ':')
714 s++;
716 /* Remember the header value, if any. */
717 if (*s == ':')
718 value = ++s;
720 /* Skip to the end of the header, including continuation lines. */
721 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
722 s++;
723 s++;
725 /* Process this header. */
726 if (value && value > field+2) {
727 char *ff = (char *) malloc (value-field);
728 char *ss = ff;
729 while (field < value-1)
730 *ss++ = tolower(*field++);
731 *ss++ = 0;
733 if (!strcmp (ff, "content-length")) {
734 const char *e;
735 while (*value && isspace (*value))
736 value++;
737 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
738 ;
739 ss = (char *) malloc (e - value + 1);
740 strncpy (ss, value, e - value);
741 ss[e - value] = 0;
742 content_length = atoi(ss);
743 free (ss);
744 }
745 free (ff);
746 }
747 }
748 return (content_length);
749 }
751 char *
752 prepend_slash (char *path)
753 {
754 char *newpath;
756 if (path[0] == '/')
757 return path;
759 if ((newpath = malloc (strlen(path) + 2)) == NULL)
760 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
761 newpath[0] = '/';
762 strcpy (newpath + 1, path);
763 free (path);
764 return newpath;
765 }
767 int
768 check_http (void)
769 {
770 char *msg;
771 char *status_line;
772 char *status_code;
773 char *header;
774 char *page;
775 char *auth;
776 int http_status;
777 int i = 0;
778 size_t pagesize = 0;
779 char *full_page;
780 char *buf;
781 char *pos;
782 long microsec;
783 double elapsed_time;
784 int page_len = 0;
785 int result = STATE_OK;
787 /* try to connect to the host at the given port number */
788 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
789 die (STATE_CRITICAL, _("HTTP CRITICAL - Unable to open TCP socket\n"));
790 #ifdef HAVE_SSL
791 if (use_ssl == TRUE) {
792 np_net_ssl_init(sd);
793 if (check_cert == TRUE) {
794 result = np_net_ssl_check_cert(days_till_exp);
795 np_net_ssl_cleanup();
796 if (sd) close(sd);
797 return result;
798 }
799 }
800 #endif /* HAVE_SSL */
802 asprintf (&buf, "%s %s %s\r\n%s\r\n", http_method, server_url, host_name ? "HTTP/1.1" : "HTTP/1.0", user_agent);
804 /* tell HTTP/1.1 servers not to keep the connection alive */
805 asprintf (&buf, "%sConnection: close\r\n", buf);
807 /* optionally send the host header info */
808 if (host_name) {
809 /*
810 * Specify the port only if we're using a non-default port (see RFC 2616,
811 * 14.23). Some server applications/configurations cause trouble if the
812 * (default) port is explicitly specified in the "Host:" header line.
813 */
814 if ((use_ssl == FALSE && server_port == HTTP_PORT) ||
815 (use_ssl == TRUE && server_port == HTTPS_PORT))
816 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
817 else
818 asprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
819 }
821 /* optionally send any other header tag */
822 if (http_opt_headers_count) {
823 for (i = 0; i < http_opt_headers_count ; i++) {
824 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
825 asprintf (&buf, "%s%s\r\n", buf, pos);
826 }
827 /* This cannot be free'd here because a redirection will then try to access this and segfault */
828 /* Covered in a testcase in tests/check_http.t */
829 /* free(http_opt_headers); */
830 }
832 /* optionally send the authentication info */
833 if (strlen(user_auth)) {
834 base64_encode_alloc (user_auth, strlen (user_auth), &auth);
835 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
836 }
838 /* either send http POST data (any data, not only POST)*/
839 if (http_post_data) {
840 if (http_content_type) {
841 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
842 } else {
843 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
844 }
846 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
847 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
848 }
849 else {
850 /* or just a newline so the server knows we're done with the request */
851 asprintf (&buf, "%s%s", buf, CRLF);
852 }
854 if (verbose) printf ("%s\n", buf);
855 my_send (buf, strlen (buf));
857 /* fetch the page */
858 full_page = strdup("");
859 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
860 buffer[i] = '\0';
861 asprintf (&full_page, "%s%s", full_page, buffer);
862 pagesize += i;
864 if (no_body && document_headers_done (full_page)) {
865 i = 0;
866 break;
867 }
868 }
870 if (i < 0 && errno != ECONNRESET) {
871 #ifdef HAVE_SSL
872 /*
873 if (use_ssl) {
874 sslerr=SSL_get_error(ssl, i);
875 if ( sslerr == SSL_ERROR_SSL ) {
876 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
877 } else {
878 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
879 }
880 }
881 else {
882 */
883 #endif
884 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
885 #ifdef HAVE_SSL
886 /* XXX
887 }
888 */
889 #endif
890 }
892 /* return a CRITICAL status if we couldn't read any data */
893 if (pagesize == (size_t) 0)
894 die (STATE_CRITICAL, _("HTTP CRITICAL - No data received from host\n"));
896 /* close the connection */
897 #ifdef HAVE_SSL
898 np_net_ssl_cleanup();
899 #endif
900 if (sd) close(sd);
902 /* Save check time */
903 microsec = deltime (tv);
904 elapsed_time = (double)microsec / 1.0e6;
906 /* leave full_page untouched so we can free it later */
907 page = full_page;
909 if (verbose)
910 printf ("%s://%s:%d%s is %d characters\n",
911 use_ssl ? "https" : "http", server_address,
912 server_port, server_url, (int)pagesize);
914 /* find status line and null-terminate it */
915 status_line = page;
916 page += (size_t) strcspn (page, "\r\n");
917 pos = page;
918 page += (size_t) strspn (page, "\r\n");
919 status_line[strcspn(status_line, "\r\n")] = 0;
920 strip (status_line);
921 if (verbose)
922 printf ("STATUS: %s\n", status_line);
924 /* find header info and null-terminate it */
925 header = page;
926 while (strcspn (page, "\r\n") > 0) {
927 page += (size_t) strcspn (page, "\r\n");
928 pos = page;
929 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
930 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
931 page += (size_t) 2;
932 else
933 page += (size_t) 1;
934 }
935 page += (size_t) strspn (page, "\r\n");
936 header[pos - header] = 0;
937 if (verbose)
938 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
939 (no_body ? " [[ skipped ]]" : page));
941 /* make sure the status line matches the response we are looking for */
942 if (!expected_statuscode (status_line, server_expect)) {
943 if (server_port == HTTP_PORT)
944 asprintf (&msg,
945 _("Invalid HTTP response received from host: %s\n"),
946 status_line);
947 else
948 asprintf (&msg,
949 _("Invalid HTTP response received from host on port %d: %s\n"),
950 server_port, status_line);
951 die (STATE_CRITICAL, "HTTP CRITICAL - %s", msg);
952 }
954 /* Bypass normal status line check if server_expect was set by user and not default */
955 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
956 if ( server_expect_yn ) {
957 asprintf (&msg,
958 _("Status line output matched \"%s\" - "), server_expect);
959 if (verbose)
960 printf ("%s\n",msg);
961 }
962 else {
963 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
964 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
965 /* Status-Code = 3 DIGITS */
967 status_code = strchr (status_line, ' ') + sizeof (char);
968 if (strspn (status_code, "1234567890") != 3)
969 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
971 http_status = atoi (status_code);
973 /* check the return code */
975 if (http_status >= 600 || http_status < 100) {
976 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
977 }
978 /* server errors result in a critical state */
979 else if (http_status >= 500) {
980 asprintf (&msg, _("%s - "), status_line);
981 result = STATE_CRITICAL;
982 }
983 /* client errors result in a warning state */
984 else if (http_status >= 400) {
985 asprintf (&msg, _("%s - "), status_line);
986 result = max_state_alt(STATE_WARNING, result);
987 }
988 /* check redirected page if specified */
989 else if (http_status >= 300) {
991 if (onredirect == STATE_DEPENDENT)
992 redir (header, status_line);
993 else
994 result = max_state_alt(onredirect, result);
995 asprintf (&msg, _("%s - "), status_line);
996 } /* end if (http_status >= 300) */
997 else {
998 /* Print OK status anyway */
999 asprintf (&msg, _("%s - "), status_line);
1000 }
1002 } /* end else (server_expect_yn) */
1004 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
1005 alarm (0);
1007 if (maximum_age >= 0) {
1008 result = max_state_alt(check_document_dates(header, &msg), result);
1009 }
1011 /* Page and Header content checks go here */
1013 if (strlen (string_expect)) {
1014 if (!strstr (page, string_expect)) {
1015 asprintf (&msg, _("%sstring not found, "), msg);
1016 result = STATE_CRITICAL;
1017 }
1018 }
1020 if (strlen (regexp)) {
1021 errcode = regexec (&preg, page, REGS, pmatch, 0);
1022 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1023 /* OK - No-op to avoid changing the logic around it */
1024 result = max_state_alt(STATE_OK, result);
1025 }
1026 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1027 if (invert_regex == 0)
1028 asprintf (&msg, _("%spattern not found, "), msg);
1029 else
1030 asprintf (&msg, _("%spattern found, "), msg);
1031 result = STATE_CRITICAL;
1032 }
1033 else {
1034 /* FIXME: Shouldn't that be UNKNOWN? */
1035 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1036 asprintf (&msg, _("%sExecute Error: %s, "), msg, errbuf);
1037 result = STATE_CRITICAL;
1038 }
1039 }
1041 /* make sure the page is of an appropriate size */
1042 /* page_len = get_content_length(header); */
1043 /* FIXME: Will this work with -N ? IMHO we should use
1044 * get_content_length(header) and always check if it's different than the
1045 * returned pagesize
1046 */
1047 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1048 * it == get_content_length(header) ??
1049 */
1050 page_len = pagesize;
1051 if ((max_page_len > 0) && (page_len > max_page_len)) {
1052 asprintf (&msg, _("%spage size %d too large, "), msg, page_len);
1053 result = max_state_alt(STATE_WARNING, result);
1054 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1055 asprintf (&msg, _("%spage size %d too small, "), msg, page_len);
1056 result = max_state_alt(STATE_WARNING, result);
1057 }
1059 /* Cut-off trailing characters */
1060 if(msg[strlen(msg)-2] == ',')
1061 msg[strlen(msg)-2] = '\0';
1062 else
1063 msg[strlen(msg)-3] = '\0';
1065 /* check elapsed time */
1066 asprintf (&msg,
1067 _("%s - %d bytes in %.3f second response time %s|%s %s"),
1068 msg, page_len, elapsed_time,
1069 (display_html ? "</A>" : ""),
1070 perfd_time (elapsed_time), perfd_size (page_len));
1072 if (check_critical_time == TRUE && elapsed_time > critical_time)
1073 result = STATE_CRITICAL;
1074 if (check_warning_time == TRUE && elapsed_time > warning_time)
1075 result = max_state_alt(STATE_WARNING, result);
1077 die (result, "HTTP %s: %s\n", state_text(result), msg);
1078 /* die failed? */
1079 return STATE_UNKNOWN;
1080 }
1084 /* per RFC 2396 */
1085 #define URI_HTTP "%5[HTPShtps]"
1086 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1087 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1088 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1089 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1090 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1091 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1092 #define HD4 URI_HTTP "://" URI_HOST
1093 #define HD5 URI_PATH
1095 void
1096 redir (char *pos, char *status_line)
1097 {
1098 int i = 0;
1099 char *x;
1100 char xx[2];
1101 char type[6];
1102 char *addr;
1103 char *url;
1105 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1106 if (addr == NULL)
1107 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
1109 url = malloc (strcspn (pos, "\r\n"));
1110 if (url == NULL)
1111 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1113 while (pos) {
1114 sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
1115 if (i == 0) {
1116 pos += (size_t) strcspn (pos, "\r\n");
1117 pos += (size_t) strspn (pos, "\r\n");
1118 if (strlen(pos) == 0)
1119 die (STATE_UNKNOWN,
1120 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1121 status_line, (display_html ? "</A>" : ""));
1122 continue;
1123 }
1125 pos += i;
1126 pos += strspn (pos, " \t");
1128 /*
1129 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1130 * preceding each extra line with at least one SP or HT.''
1131 */
1132 for (; (i = strspn (pos, "\r\n")); pos += i) {
1133 pos += i;
1134 if (!(i = strspn (pos, " \t"))) {
1135 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1136 display_html ? "</A>" : "");
1137 }
1138 }
1140 url = realloc (url, strcspn (pos, "\r\n") + 1);
1141 if (url == NULL)
1142 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1144 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1145 if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
1146 url = prepend_slash (url);
1147 use_ssl = server_type_check (type);
1148 }
1150 /* URI_HTTP URI_HOST URI_PATH */
1151 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1152 url = prepend_slash (url);
1153 use_ssl = server_type_check (type);
1154 i = server_port_check (use_ssl);
1155 }
1157 /* URI_HTTP URI_HOST URI_PORT */
1158 else if (sscanf (pos, HD3, type, addr, &i) == 3) {
1159 strcpy (url, HTTP_URL);
1160 use_ssl = server_type_check (type);
1161 }
1163 /* URI_HTTP URI_HOST */
1164 else if (sscanf (pos, HD4, type, addr) == 2) {
1165 strcpy (url, HTTP_URL);
1166 use_ssl = server_type_check (type);
1167 i = server_port_check (use_ssl);
1168 }
1170 /* URI_PATH */
1171 else if (sscanf (pos, HD5, url) == 1) {
1172 /* relative url */
1173 if ((url[0] != '/')) {
1174 if ((x = strrchr(server_url, '/')))
1175 *x = '\0';
1176 asprintf (&url, "%s/%s", server_url, url);
1177 }
1178 i = server_port;
1179 strcpy (type, server_type);
1180 strcpy (addr, host_name ? host_name : server_address);
1181 }
1183 else {
1184 die (STATE_UNKNOWN,
1185 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1186 pos, (display_html ? "</A>" : ""));
1187 }
1189 break;
1191 } /* end while (pos) */
1193 if (++redir_depth > max_depth)
1194 die (STATE_WARNING,
1195 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1196 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1198 if (server_port==i &&
1199 !strcmp(server_address, addr) &&
1200 (host_name && !strcmp(host_name, addr)) &&
1201 !strcmp(server_url, url))
1202 die (STATE_WARNING,
1203 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1204 type, addr, i, url, (display_html ? "</A>" : ""));
1206 strcpy (server_type, type);
1208 free (host_name);
1209 host_name = strdup (addr);
1211 if (!(followsticky & STICKY_HOST)) {
1212 free (server_address);
1213 server_address = strdup (addr);
1214 }
1215 if (!(followsticky & STICKY_PORT)) {
1216 server_port = i;
1217 }
1219 free (server_url);
1220 server_url = url;
1222 if (server_port > MAX_PORT)
1223 die (STATE_UNKNOWN,
1224 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1225 MAX_PORT, server_type, server_address, server_port, server_url,
1226 display_html ? "</A>" : "");
1228 if (verbose)
1229 printf (_("Redirection to %s://%s:%d%s\n"), server_type,
1230 host_name ? host_name : server_address, server_port, server_url);
1232 check_http ();
1233 }
1236 int
1237 server_type_check (const char *type)
1238 {
1239 if (strcmp (type, "https"))
1240 return FALSE;
1241 else
1242 return TRUE;
1243 }
1245 int
1246 server_port_check (int ssl_flag)
1247 {
1248 if (ssl_flag)
1249 return HTTPS_PORT;
1250 else
1251 return HTTP_PORT;
1252 }
1254 char *perfd_time (double elapsed_time)
1255 {
1256 return fperfdata ("time", elapsed_time, "s",
1257 check_warning_time, warning_time,
1258 check_critical_time, critical_time,
1259 TRUE, 0, FALSE, 0);
1260 }
1264 char *perfd_size (int page_len)
1265 {
1266 return perfdata ("size", page_len, "B",
1267 (min_page_len>0?TRUE:FALSE), min_page_len,
1268 (min_page_len>0?TRUE:FALSE), 0,
1269 TRUE, 0, FALSE, 0);
1270 }
1272 void
1273 print_help (void)
1274 {
1275 print_revision (progname, NP_VERSION);
1277 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1278 printf (COPYRIGHT, copyright, email);
1280 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1281 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1282 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1283 printf ("%s\n", _("certificate expiration times."));
1285 printf ("\n\n");
1287 print_usage ();
1289 printf (_("NOTE: One or both of -H and -I must be specified"));
1291 printf ("\n");
1293 printf (_(UT_HELP_VRSN));
1294 printf (_(UT_EXTRA_OPTS));
1296 printf (" %s\n", "-H, --hostname=ADDRESS");
1297 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1298 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1299 printf (" %s\n", "-I, --IP-address=ADDRESS");
1300 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1301 printf (" %s\n", "-p, --port=INTEGER");
1302 printf (" %s", _("Port number (default: "));
1303 printf ("%d)\n", HTTP_PORT);
1305 printf (_(UT_IPv46));
1307 #ifdef HAVE_SSL
1308 printf (" %s\n", "-S, --ssl");
1309 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1310 printf (" %s\n", "-C, --certificate=INTEGER");
1311 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1312 printf (" %s\n", _("(when this option is used the URL is not checked.)\n"));
1313 #endif
1315 printf (" %s\n", "-e, --expect=STRING");
1316 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1317 printf (" %s", _("the first (status) line of the server response (default: "));
1318 printf ("%s)\n", HTTP_EXPECT);
1319 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1320 printf (" %s\n", "-s, --string=STRING");
1321 printf (" %s\n", _("String to expect in the content"));
1322 printf (" %s\n", "-u, --url=PATH");
1323 printf (" %s\n", _("URL to GET or POST (default: /)"));
1324 printf (" %s\n", "-P, --post=STRING");
1325 printf (" %s\n", _("URL encoded http POST data"));
1326 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)");
1327 printf (" %s\n", _("Set HTTP method."));
1328 printf (" %s\n", "-N, --no-body");
1329 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1330 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1331 printf (" %s\n", "-M, --max-age=SECONDS");
1332 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1333 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1334 printf (" %s\n", "-T, --content-type=STRING");
1335 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1337 printf (" %s\n", "-l, --linespan");
1338 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1339 printf (" %s\n", "-r, --regex, --ereg=STRING");
1340 printf (" %s\n", _("Search page for regex STRING"));
1341 printf (" %s\n", "-R, --eregi=STRING");
1342 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1343 printf (" %s\n", "--invert-regex");
1344 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1346 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1347 printf (" %s\n", _("Username:password on sites with basic authentication"));
1348 printf (" %s\n", "-A, --useragent=STRING");
1349 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1350 printf (" %s\n", "-k, --header=STRING");
1351 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1352 printf (" %s\n", "-L, --link");
1353 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1354 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1355 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1356 printf (" %s\n", _("specified IP address. stickyport also ensure post stays the same."));
1357 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1358 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1360 printf (_(UT_WARN_CRIT));
1362 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1364 printf (_(UT_VERBOSE));
1366 printf ("\n");
1367 printf ("%s\n", _("Notes:"));
1368 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1369 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1370 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1371 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1372 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1373 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1374 printf ("\n");
1375 printf (_(UT_EXTRA_OPTS_NOTES));
1377 #ifdef HAVE_SSL
1378 printf ("\n");
1379 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1380 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1381 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1382 printf ("\n");
1383 printf ("%s\n", _("Examples:"));
1384 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1385 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1386 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1387 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1388 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1390 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1391 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1392 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1393 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1394 printf (" %s\n", _("the certificate is expired."));
1395 #endif
1397 printf (_(UT_SUPPORT));
1399 }
1403 void
1404 print_usage (void)
1405 {
1406 printf (_("Usage:"));
1407 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1408 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1409 printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1410 printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1411 printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string]\n");
1412 printf (" [-k string] [-S] [-C <age>] [-T <content-type>] [-j method]\n");
1413 }