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