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