1 /******************************************************************************
2 *
3 * Nagios check_http plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2006 nagios-plugins 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 * License Information:
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 $Id$
38 ******************************************************************************/
39 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
41 const char *progname = "check_http";
42 const char *revision = "$Revision$";
43 const char *copyright = "1999-2006";
44 const char *email = "nagiosplug-devel@lists.sourceforge.net";
46 #include "common.h"
47 #include "netutils.h"
48 #include "utils.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 };
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 use_ssl = FALSE;
113 int verbose = FALSE;
114 int sd;
115 int min_page_len = 0;
116 int max_page_len = 0;
117 int redir_depth = 0;
118 int max_depth = 15;
119 char *http_method;
120 char *http_post_data;
121 char *http_content_type;
122 char buffer[MAX_INPUT_BUFFER];
124 int process_arguments (int, char **);
125 static char *base64 (const char *bin, size_t len);
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 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
141 server_url = strdup(HTTP_URL);
142 server_url_length = strlen(server_url);
143 asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
144 clean_revstring (revision), VERSION);
146 if (process_arguments (argc, argv) == ERROR)
147 usage4 (_("Could not parse arguments"));
149 if (display_html == TRUE)
150 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
151 use_ssl ? "https" : "http", host_name,
152 server_port, server_url);
154 /* initialize alarm signal handling, set socket timeout, start timer */
155 (void) signal (SIGALRM, socket_timeout_alarm_handler);
156 (void) alarm (socket_timeout);
157 gettimeofday (&tv, NULL);
159 result = check_http ();
160 return result;
161 }
165 /* process command-line arguments */
166 int
167 process_arguments (int argc, char **argv)
168 {
169 int c = 1;
171 enum {
172 INVERT_REGEX = CHAR_MAX + 1
173 };
175 int option = 0;
176 static struct option longopts[] = {
177 STD_LONG_OPTS,
178 {"file",required_argument,0,'F'},
179 {"link", no_argument, 0, 'L'},
180 {"nohtml", no_argument, 0, 'n'},
181 {"ssl", no_argument, 0, 'S'},
182 {"verbose", no_argument, 0, 'v'},
183 {"post", required_argument, 0, 'P'},
184 {"IP-address", required_argument, 0, 'I'},
185 {"url", required_argument, 0, 'u'},
186 {"string", required_argument, 0, 's'},
187 {"regex", required_argument, 0, 'r'},
188 {"ereg", required_argument, 0, 'r'},
189 {"eregi", required_argument, 0, 'R'},
190 {"linespan", no_argument, 0, 'l'},
191 {"onredirect", required_argument, 0, 'f'},
192 {"certificate", required_argument, 0, 'C'},
193 {"useragent", required_argument, 0, 'A'},
194 {"header", required_argument, 0, 'k'},
195 {"no-body", no_argument, 0, 'N'},
196 {"max-age", required_argument, 0, 'M'},
197 {"content-type", required_argument, 0, 'T'},
198 {"pagesize", required_argument, 0, 'm'},
199 {"invert-regex", no_argument, NULL, INVERT_REGEX},
200 {"use-ipv4", no_argument, 0, '4'},
201 {"use-ipv6", no_argument, 0, '6'},
202 {0, 0, 0, 0}
203 };
205 if (argc < 2)
206 return ERROR;
208 for (c = 1; c < argc; c++) {
209 if (strcmp ("-to", argv[c]) == 0)
210 strcpy (argv[c], "-t");
211 if (strcmp ("-hn", argv[c]) == 0)
212 strcpy (argv[c], "-H");
213 if (strcmp ("-wt", argv[c]) == 0)
214 strcpy (argv[c], "-w");
215 if (strcmp ("-ct", argv[c]) == 0)
216 strcpy (argv[c], "-c");
217 if (strcmp ("-nohtml", argv[c]) == 0)
218 strcpy (argv[c], "-n");
219 }
221 while (1) {
222 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);
223 if (c == -1 || c == EOF)
224 break;
226 switch (c) {
227 case '?': /* usage */
228 usage2 (_("Unknown argument"), optarg);
229 break;
230 case 'h': /* help */
231 print_help ();
232 exit (STATE_OK);
233 break;
234 case 'V': /* version */
235 print_revision (progname, revision);
236 exit (STATE_OK);
237 break;
238 case 't': /* timeout period */
239 if (!is_intnonneg (optarg))
240 usage2 (_("Timeout interval must be a positive integer"), optarg);
241 else
242 socket_timeout = atoi (optarg);
243 break;
244 case 'c': /* critical time threshold */
245 if (!is_nonnegative (optarg))
246 usage2 (_("Critical threshold must be integer"), optarg);
247 else {
248 critical_time = strtod (optarg, NULL);
249 check_critical_time = TRUE;
250 }
251 break;
252 case 'w': /* warning time threshold */
253 if (!is_nonnegative (optarg))
254 usage2 (_("Warning threshold must be integer"), optarg);
255 else {
256 warning_time = strtod (optarg, NULL);
257 check_warning_time = TRUE;
258 }
259 break;
260 case 'A': /* User Agent String */
261 asprintf (&user_agent, "User-Agent: %s", optarg);
262 break;
263 case 'k': /* Additional headers */
264 if (http_opt_headers_count == 0)
265 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count));
266 else
267 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count));
268 http_opt_headers[http_opt_headers_count - 1] = optarg;
269 /* asprintf (&http_opt_headers, "%s", optarg); */
270 break;
271 case 'L': /* show html link */
272 display_html = TRUE;
273 break;
274 case 'n': /* do not show html link */
275 display_html = FALSE;
276 break;
277 case 'C': /* Check SSL cert validity */
278 #ifdef HAVE_SSL
279 if (!is_intnonneg (optarg))
280 usage2 (_("Invalid certificate expiration period"), optarg);
281 else {
282 days_till_exp = atoi (optarg);
283 check_cert = TRUE;
284 }
285 /* Fall through to -S option */
286 #endif
287 case 'S': /* use SSL */
288 #ifndef HAVE_SSL
289 usage4 (_("Invalid option - SSL is not available"));
290 #endif
291 use_ssl = TRUE;
292 if (specify_port == FALSE)
293 server_port = HTTPS_PORT;
294 break;
295 case 'f': /* onredirect */
296 if (!strcmp (optarg, "follow"))
297 onredirect = STATE_DEPENDENT;
298 if (!strcmp (optarg, "unknown"))
299 onredirect = STATE_UNKNOWN;
300 if (!strcmp (optarg, "ok"))
301 onredirect = STATE_OK;
302 if (!strcmp (optarg, "warning"))
303 onredirect = STATE_WARNING;
304 if (!strcmp (optarg, "critical"))
305 onredirect = STATE_CRITICAL;
306 if (verbose)
307 printf(_("option f:%d \n"), onredirect);
308 break;
309 /* Note: H, I, and u must be malloc'd or will fail on redirects */
310 case 'H': /* Host Name (virtual host) */
311 host_name = strdup (optarg);
312 if (strstr (optarg, ":"))
313 sscanf (optarg, "%*[^:]:%d", &server_port);
314 break;
315 case 'I': /* Server IP-address */
316 server_address = strdup (optarg);
317 break;
318 case 'u': /* URL path */
319 server_url = strdup (optarg);
320 server_url_length = strlen (server_url);
321 break;
322 case 'p': /* Server port */
323 if (!is_intnonneg (optarg))
324 usage2 (_("Invalid port number"), optarg);
325 else {
326 server_port = atoi (optarg);
327 specify_port = TRUE;
328 }
329 break;
330 case 'a': /* authorization info */
331 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
332 user_auth[MAX_INPUT_BUFFER - 1] = 0;
333 break;
334 case 'P': /* HTTP POST data in URL encoded format */
335 if (http_method || http_post_data) break;
336 http_method = strdup("POST");
337 http_post_data = strdup (optarg);
338 break;
339 case 's': /* string or substring */
340 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
341 string_expect[MAX_INPUT_BUFFER - 1] = 0;
342 break;
343 case 'e': /* string or substring */
344 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
345 server_expect[MAX_INPUT_BUFFER - 1] = 0;
346 server_expect_yn = 1;
347 break;
348 case 'T': /* Content-type */
349 asprintf (&http_content_type, "%s", optarg);
350 break;
351 case 'l': /* linespan */
352 cflags &= ~REG_NEWLINE;
353 break;
354 case 'R': /* regex */
355 cflags |= REG_ICASE;
356 case 'r': /* regex */
357 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
358 regexp[MAX_RE_SIZE - 1] = 0;
359 errcode = regcomp (&preg, regexp, cflags);
360 if (errcode != 0) {
361 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
362 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
363 return ERROR;
364 }
365 break;
366 case INVERT_REGEX:
367 invert_regex = 1;
368 break;
369 case '4':
370 address_family = AF_INET;
371 break;
372 case '6':
373 #ifdef USE_IPV6
374 address_family = AF_INET6;
375 #else
376 usage4 (_("IPv6 support not available"));
377 #endif
378 break;
379 case 'v': /* verbose */
380 verbose = TRUE;
381 break;
382 case 'm': /* min_page_length */
383 {
384 char *tmp;
385 if (strchr(optarg, ':') != (char *)NULL) {
386 /* range, so get two values, min:max */
387 tmp = strtok(optarg, ":");
388 if (tmp == NULL) {
389 printf("Bad format: try \"-m min:max\"\n");
390 exit (STATE_WARNING);
391 } else
392 min_page_len = atoi(tmp);
394 tmp = strtok(NULL, ":");
395 if (tmp == NULL) {
396 printf("Bad format: try \"-m min:max\"\n");
397 exit (STATE_WARNING);
398 } else
399 max_page_len = atoi(tmp);
400 } else
401 min_page_len = atoi (optarg);
402 break;
403 }
404 case 'N': /* no-body */
405 no_body = TRUE;
406 break;
407 case 'M': /* max-age */
408 {
409 int L = strlen(optarg);
410 if (L && optarg[L-1] == 'm')
411 maximum_age = atoi (optarg) * 60;
412 else if (L && optarg[L-1] == 'h')
413 maximum_age = atoi (optarg) * 60 * 60;
414 else if (L && optarg[L-1] == 'd')
415 maximum_age = atoi (optarg) * 60 * 60 * 24;
416 else if (L && (optarg[L-1] == 's' ||
417 isdigit (optarg[L-1])))
418 maximum_age = atoi (optarg);
419 else {
420 fprintf (stderr, "unparsable max-age: %s\n", optarg);
421 exit (STATE_WARNING);
422 }
423 }
424 break;
425 }
426 }
428 c = optind;
430 if (server_address == NULL && c < argc)
431 server_address = strdup (argv[c++]);
433 if (host_name == NULL && c < argc)
434 host_name = strdup (argv[c++]);
436 if (server_address == NULL) {
437 if (host_name == NULL)
438 usage4 (_("You must specify a server address or host name"));
439 else
440 server_address = strdup (host_name);
441 }
443 if (check_critical_time && critical_time>(double)socket_timeout)
444 socket_timeout = (int)critical_time + 1;
446 if (http_method == NULL)
447 http_method = strdup ("GET");
449 return TRUE;
450 }
454 /* written by lauri alanko */
455 static char *
456 base64 (const char *bin, size_t len)
457 {
459 char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
460 size_t i = 0, j = 0;
462 char BASE64_END = '=';
463 char base64_table[64];
464 strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
466 while (j < len - 2) {
467 buf[i++] = base64_table[bin[j] >> 2];
468 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
469 buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
470 buf[i++] = base64_table[bin[j + 2] & 63];
471 j += 3;
472 }
474 switch (len - j) {
475 case 1:
476 buf[i++] = base64_table[bin[j] >> 2];
477 buf[i++] = base64_table[(bin[j] & 3) << 4];
478 buf[i++] = BASE64_END;
479 buf[i++] = BASE64_END;
480 break;
481 case 2:
482 buf[i++] = base64_table[bin[j] >> 2];
483 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
484 buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
485 buf[i++] = BASE64_END;
486 break;
487 case 0:
488 break;
489 }
491 buf[i] = '\0';
492 return buf;
493 }
497 /* Returns 1 if we're done processing the document body; 0 to keep going */
498 static int
499 document_headers_done (char *full_page)
500 {
501 const char *body;
503 for (body = full_page; *body; body++) {
504 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
505 break;
506 }
508 if (!*body)
509 return 0; /* haven't read end of headers yet */
511 full_page[body - full_page] = 0;
512 return 1;
513 }
515 static time_t
516 parse_time_string (const char *string)
517 {
518 struct tm tm;
519 time_t t;
520 memset (&tm, 0, sizeof(tm));
522 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
524 if (isupper (string[0]) && /* Tue */
525 islower (string[1]) &&
526 islower (string[2]) &&
527 ',' == string[3] &&
528 ' ' == string[4] &&
529 (isdigit(string[5]) || string[5] == ' ') && /* 25 */
530 isdigit (string[6]) &&
531 ' ' == string[7] &&
532 isupper (string[8]) && /* Dec */
533 islower (string[9]) &&
534 islower (string[10]) &&
535 ' ' == string[11] &&
536 isdigit (string[12]) && /* 2001 */
537 isdigit (string[13]) &&
538 isdigit (string[14]) &&
539 isdigit (string[15]) &&
540 ' ' == string[16] &&
541 isdigit (string[17]) && /* 02: */
542 isdigit (string[18]) &&
543 ':' == string[19] &&
544 isdigit (string[20]) && /* 59: */
545 isdigit (string[21]) &&
546 ':' == string[22] &&
547 isdigit (string[23]) && /* 03 */
548 isdigit (string[24]) &&
549 ' ' == string[25] &&
550 'G' == string[26] && /* GMT */
551 'M' == string[27] && /* GMT */
552 'T' == string[28]) {
554 tm.tm_sec = 10 * (string[23]-'0') + (string[24]-'0');
555 tm.tm_min = 10 * (string[20]-'0') + (string[21]-'0');
556 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
557 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
558 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
559 !strncmp (string+8, "Feb", 3) ? 1 :
560 !strncmp (string+8, "Mar", 3) ? 2 :
561 !strncmp (string+8, "Apr", 3) ? 3 :
562 !strncmp (string+8, "May", 3) ? 4 :
563 !strncmp (string+8, "Jun", 3) ? 5 :
564 !strncmp (string+8, "Jul", 3) ? 6 :
565 !strncmp (string+8, "Aug", 3) ? 7 :
566 !strncmp (string+8, "Sep", 3) ? 8 :
567 !strncmp (string+8, "Oct", 3) ? 9 :
568 !strncmp (string+8, "Nov", 3) ? 10 :
569 !strncmp (string+8, "Dec", 3) ? 11 :
570 -1);
571 tm.tm_year = ((1000 * (string[12]-'0') +
572 100 * (string[13]-'0') +
573 10 * (string[14]-'0') +
574 (string[15]-'0'))
575 - 1900);
577 tm.tm_isdst = 0; /* GMT is never in DST, right? */
579 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
580 return 0;
582 /*
583 This is actually wrong: we need to subtract the local timezone
584 offset from GMT from this value. But, that's ok in this usage,
585 because we only comparing these two GMT dates against each other,
586 so it doesn't matter what time zone we parse them in.
587 */
589 t = mktime (&tm);
590 if (t == (time_t) -1) t = 0;
592 if (verbose) {
593 const char *s = string;
594 while (*s && *s != '\r' && *s != '\n')
595 fputc (*s++, stdout);
596 printf (" ==> %lu\n", (unsigned long) t);
597 }
599 return t;
601 } else {
602 return 0;
603 }
604 }
608 static void
609 check_document_dates (const char *headers)
610 {
611 const char *s;
612 char *server_date = 0;
613 char *document_date = 0;
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++;
631 s++;
633 /* Process this header. */
634 if (value && value > field+2) {
635 char *ff = (char *) malloc (value-field);
636 char *ss = ff;
637 while (field < value-1)
638 *ss++ = tolower(*field++);
639 *ss++ = 0;
641 if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
642 const char *e;
643 while (*value && isspace (*value))
644 value++;
645 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
646 ;
647 ss = (char *) malloc (e - value + 1);
648 strncpy (ss, value, e - value);
649 ss[e - value] = 0;
650 if (!strcmp (ff, "date")) {
651 if (server_date) free (server_date);
652 server_date = ss;
653 } else {
654 if (document_date) free (document_date);
655 document_date = ss;
656 }
657 }
658 free (ff);
659 }
660 }
662 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
663 if (!server_date || !*server_date) {
664 die (STATE_UNKNOWN, _("Server date unknown\n"));
665 } else if (!document_date || !*document_date) {
666 die (STATE_CRITICAL, _("Document modification date unknown\n"));
667 } else {
668 time_t srv_data = parse_time_string (server_date);
669 time_t doc_data = parse_time_string (document_date);
671 if (srv_data <= 0) {
672 die (STATE_CRITICAL, _("CRITICAL - Server date \"%100s\" unparsable"), server_date);
673 } else if (doc_data <= 0) {
674 die (STATE_CRITICAL, _("CRITICAL - Document date \"%100s\" unparsable"), document_date);
675 } else if (doc_data > srv_data + 30) {
676 die (STATE_CRITICAL, _("CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
677 } else if (doc_data < srv_data - maximum_age) {
678 int n = (srv_data - doc_data);
679 if (n > (60 * 60 * 24 * 2))
680 die (STATE_CRITICAL,
681 _("CRITICAL - Last modified %.1f days ago\n"),
682 ((float) n) / (60 * 60 * 24));
683 else
684 die (STATE_CRITICAL,
685 _("CRITICAL - Last modified %d:%02d:%02d ago\n"),
686 n / (60 * 60), (n / 60) % 60, n % 60);
687 }
689 free (server_date);
690 free (document_date);
691 }
692 }
694 int
695 get_content_length (const char *headers)
696 {
697 const char *s;
698 int content_length = 0;
700 s = headers;
701 while (*s) {
702 const char *field = s;
703 const char *value = 0;
705 /* Find the end of the header field */
706 while (*s && !isspace(*s) && *s != ':')
707 s++;
709 /* Remember the header value, if any. */
710 if (*s == ':')
711 value = ++s;
713 /* Skip to the end of the header, including continuation lines. */
714 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
715 s++;
716 s++;
718 /* Process this header. */
719 if (value && value > field+2) {
720 char *ff = (char *) malloc (value-field);
721 char *ss = ff;
722 while (field < value-1)
723 *ss++ = tolower(*field++);
724 *ss++ = 0;
726 if (!strcmp (ff, "content-length")) {
727 const char *e;
728 while (*value && isspace (*value))
729 value++;
730 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
731 ;
732 ss = (char *) malloc (e - value + 1);
733 strncpy (ss, value, e - value);
734 ss[e - value] = 0;
735 content_length = atoi(ss);
736 free (ss);
737 }
738 free (ff);
739 }
740 }
741 return (content_length);
742 }
744 int
745 check_http (void)
746 {
747 char *msg;
748 char *status_line;
749 char *status_code;
750 char *header;
751 char *page;
752 char *auth;
753 int http_status;
754 int i = 0;
755 size_t pagesize = 0;
756 char *full_page;
757 char *buf;
758 char *pos;
759 long microsec;
760 double elapsed_time;
761 int page_len = 0;
762 int result = STATE_UNKNOWN;
764 /* try to connect to the host at the given port number */
765 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
766 die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
767 #ifdef HAVE_SSL
768 if (use_ssl == TRUE) {
769 np_net_ssl_init(sd);
770 if (check_cert == TRUE) {
771 result = np_net_ssl_check_cert(days_till_exp);
772 np_net_ssl_cleanup();
773 if(sd) close(sd);
774 return result;
775 }
776 }
777 #endif /* HAVE_SSL */
779 asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
781 /* optionally send the host header info */
782 if (host_name)
783 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
785 /* optionally send any other header tag */
786 if (http_opt_headers_count) {
787 for (i = 0; i < http_opt_headers_count ; i++) {
788 for ((pos = strtok(http_opt_headers[i], INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
789 asprintf (&buf, "%s%s\r\n", buf, pos);
790 }
791 free(http_opt_headers);
792 }
794 /* optionally send the authentication info */
795 if (strlen(user_auth)) {
796 auth = base64 (user_auth, strlen (user_auth));
797 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
798 }
800 /* either send http POST data */
801 if (http_post_data) {
802 if (http_content_type) {
803 asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
804 } else {
805 asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
806 }
808 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
809 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
810 }
811 else {
812 /* or just a newline so the server knows we're done with the request */
813 asprintf (&buf, "%s%s", buf, CRLF);
814 }
816 if (verbose) printf ("%s\n", buf);
817 my_send (buf, strlen (buf));
819 /* fetch the page */
820 full_page = strdup("");
821 while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
822 buffer[i] = '\0';
823 asprintf (&full_page, "%s%s", full_page, buffer);
824 pagesize += i;
826 if (no_body && document_headers_done (full_page)) {
827 i = 0;
828 break;
829 }
830 }
832 if (i < 0 && errno != ECONNRESET) {
833 #ifdef HAVE_SSL
834 /*
835 if (use_ssl) {
836 sslerr=SSL_get_error(ssl, i);
837 if ( sslerr == SSL_ERROR_SSL ) {
838 die (STATE_WARNING, _("Client Certificate Required\n"));
839 } else {
840 die (STATE_CRITICAL, _("Error on receive\n"));
841 }
842 }
843 else {
844 */
845 #endif
846 die (STATE_CRITICAL, _("Error on receive\n"));
847 #ifdef HAVE_SSL
848 /* XXX
849 }
850 */
851 #endif
852 }
854 /* return a CRITICAL status if we couldn't read any data */
855 if (pagesize == (size_t) 0)
856 die (STATE_CRITICAL, _("No data received from host\n"));
858 /* close the connection */
859 #ifdef HAVE_SSL
860 np_net_ssl_cleanup();
861 #endif
862 if(sd) close(sd);
864 /* reset the alarm */
865 alarm (0);
867 /* leave full_page untouched so we can free it later */
868 page = full_page;
870 if (verbose)
871 printf ("%s://%s:%d%s is %d characters\n",
872 use_ssl ? "https" : "http", server_address,
873 server_port, server_url, (int)pagesize);
875 /* find status line and null-terminate it */
876 status_line = page;
877 page += (size_t) strcspn (page, "\r\n");
878 pos = page;
879 page += (size_t) strspn (page, "\r\n");
880 status_line[strcspn(status_line, "\r\n")] = 0;
881 strip (status_line);
882 if (verbose)
883 printf ("STATUS: %s\n", status_line);
885 /* find header info and null-terminate it */
886 header = page;
887 while (strcspn (page, "\r\n") > 0) {
888 page += (size_t) strcspn (page, "\r\n");
889 pos = page;
890 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
891 (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
892 page += (size_t) 2;
893 else
894 page += (size_t) 1;
895 }
896 page += (size_t) strspn (page, "\r\n");
897 header[pos - header] = 0;
898 if (verbose)
899 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
900 (no_body ? " [[ skipped ]]" : page));
902 /* make sure the status line matches the response we are looking for */
903 if (!strstr (status_line, server_expect)) {
904 if (server_port == HTTP_PORT)
905 asprintf (&msg,
906 _("Invalid HTTP response received from host\n"));
907 else
908 asprintf (&msg,
909 _("Invalid HTTP response received from host on port %d\n"),
910 server_port);
911 die (STATE_CRITICAL, "%s", msg);
912 }
914 /* Exit here if server_expect was set by user and not default */
915 if ( server_expect_yn ) {
916 asprintf (&msg,
917 _("HTTP OK: Status line output matched \"%s\"\n"),
918 server_expect);
919 if (verbose)
920 printf ("%s\n",msg);
921 }
922 else {
923 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
924 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
925 /* Status-Code = 3 DIGITS */
927 status_code = strchr (status_line, ' ') + sizeof (char);
928 if (strspn (status_code, "1234567890") != 3)
929 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
931 http_status = atoi (status_code);
933 /* check the return code */
935 if (http_status >= 600 || http_status < 100)
936 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
938 /* server errors result in a critical state */
939 else if (http_status >= 500)
940 die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
942 /* client errors result in a warning state */
943 else if (http_status >= 400)
944 die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
946 /* check redirected page if specified */
947 else if (http_status >= 300) {
949 if (onredirect == STATE_DEPENDENT)
950 redir (header, status_line);
951 else if (onredirect == STATE_UNKNOWN)
952 printf (_("UNKNOWN"));
953 else if (onredirect == STATE_OK)
954 printf (_("OK"));
955 else if (onredirect == STATE_WARNING)
956 printf (_("WARNING"));
957 else if (onredirect == STATE_CRITICAL)
958 printf (_("CRITICAL"));
959 microsec = deltime (tv);
960 elapsed_time = (double)microsec / 1.0e6;
961 die (onredirect,
962 _(" - %s - %.3f second response time %s|%s %s\n"),
963 status_line, elapsed_time,
964 (display_html ? "</A>" : ""),
965 perfd_time (elapsed_time), perfd_size (pagesize));
966 } /* end if (http_status >= 300) */
968 } /* end else (server_expect_yn) */
970 if (maximum_age >= 0) {
971 check_document_dates (header);
972 }
974 /* check elapsed time */
975 microsec = deltime (tv);
976 elapsed_time = (double)microsec / 1.0e6;
977 asprintf (&msg,
978 _("HTTP WARNING: %s - %.3f second response time %s|%s %s\n"),
979 status_line, elapsed_time,
980 (display_html ? "</A>" : ""),
981 perfd_time (elapsed_time), perfd_size (pagesize));
982 if (check_critical_time == TRUE && elapsed_time > critical_time)
983 die (STATE_CRITICAL, "%s", msg);
984 if (check_warning_time == TRUE && elapsed_time > warning_time)
985 die (STATE_WARNING, "%s", msg);
987 /* Page and Header content checks go here */
988 /* these checks should be last */
990 if (strlen (string_expect)) {
991 if (strstr (page, string_expect)) {
992 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
993 status_line, elapsed_time,
994 (display_html ? "</A>" : ""),
995 perfd_time (elapsed_time), perfd_size (pagesize));
996 exit (STATE_OK);
997 }
998 else {
999 printf (_("CRITICAL - string not found%s|%s %s\n"),
1000 (display_html ? "</A>" : ""),
1001 perfd_time (elapsed_time), perfd_size (pagesize));
1002 exit (STATE_CRITICAL);
1003 }
1004 }
1006 if (strlen (regexp)) {
1007 errcode = regexec (&preg, page, REGS, pmatch, 0);
1008 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) {
1009 printf (_("HTTP OK %s - %.3f second response time %s|%s %s\n"),
1010 status_line, elapsed_time,
1011 (display_html ? "</A>" : ""),
1012 perfd_time (elapsed_time), perfd_size (pagesize));
1013 exit (STATE_OK);
1014 }
1015 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) {
1016 if (invert_regex == 0)
1017 msg = strdup(_("pattern not found"));
1018 else
1019 msg = strdup(_("pattern found"));
1020 printf (_("%s - %s%s|%s %s\n"),
1021 _("CRITICAL"),
1022 msg,
1023 (display_html ? "</A>" : ""),
1024 perfd_time (elapsed_time), perfd_size (pagesize));
1025 exit (STATE_CRITICAL);
1026 }
1027 else {
1028 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1029 printf (_("CRITICAL - Execute Error: %s\n"), errbuf);
1030 exit (STATE_CRITICAL);
1031 }
1032 }
1034 /* make sure the page is of an appropriate size */
1035 /* page_len = get_content_length(header); */
1036 page_len = pagesize;
1037 if ((max_page_len > 0) && (page_len > max_page_len)) {
1038 printf (_("HTTP WARNING: page size %d too large%s|%s\n"),
1039 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1040 exit (STATE_WARNING);
1041 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1042 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1043 page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1044 exit (STATE_WARNING);
1045 }
1046 /* We only get here if all tests have been passed */
1047 asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s|%s %s\n"),
1048 status_line, page_len, elapsed_time,
1049 (display_html ? "</A>" : ""),
1050 perfd_time (elapsed_time), perfd_size (page_len));
1051 die (STATE_OK, "%s", msg);
1052 return STATE_UNKNOWN;
1053 }
1057 /* per RFC 2396 */
1058 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1059 #define URI_HTTP "%[HTPShtps]://"
1060 #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1061 #define URI_PORT ":%[0123456789]"
1062 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1063 #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
1064 #define HD2 URI_HTTP URI_HOST URI_PATH
1065 #define HD3 URI_HTTP URI_HOST URI_PORT
1066 #define HD4 URI_HTTP URI_HOST
1067 #define HD5 URI_PATH
1069 void
1070 redir (char *pos, char *status_line)
1071 {
1072 int i = 0;
1073 char *x;
1074 char xx[2];
1075 char type[6];
1076 char *addr;
1077 char port[6];
1078 char *url;
1080 addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1081 if (addr == NULL)
1082 die (STATE_UNKNOWN, _("Could not allocate addr\n"));
1084 url = malloc (strcspn (pos, "\r\n"));
1085 if (url == NULL)
1086 die (STATE_UNKNOWN, _("Could not allocate url\n"));
1088 while (pos) {
1089 sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i);
1090 if (i == 0) {
1091 pos += (size_t) strcspn (pos, "\r\n");
1092 pos += (size_t) strspn (pos, "\r\n");
1093 if (strlen(pos) == 0)
1094 die (STATE_UNKNOWN,
1095 _("UNKNOWN - Could not find redirect location - %s%s\n"),
1096 status_line, (display_html ? "</A>" : ""));
1097 continue;
1098 }
1100 pos += i;
1101 pos += strspn (pos, " \t\r\n");
1103 url = realloc (url, strcspn (pos, "\r\n"));
1104 if (url == NULL)
1105 die (STATE_UNKNOWN, _("could not allocate url\n"));
1107 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1108 if (sscanf (pos, HD1, type, addr, port, url) == 4) {
1109 use_ssl = server_type_check (type);
1110 i = atoi (port);
1111 }
1113 /* URI_HTTP URI_HOST URI_PATH */
1114 else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
1115 use_ssl = server_type_check (type);
1116 i = server_port_check (use_ssl);
1117 }
1119 /* URI_HTTP URI_HOST URI_PORT */
1120 else if(sscanf (pos, HD3, type, addr, port) == 3) {
1121 strcpy (url, HTTP_URL);
1122 use_ssl = server_type_check (type);
1123 i = atoi (port);
1124 }
1126 /* URI_HTTP URI_HOST */
1127 else if(sscanf (pos, HD4, type, addr) == 2) {
1128 strcpy (url, HTTP_URL);
1129 use_ssl = server_type_check (type);
1130 i = server_port_check (use_ssl);
1131 }
1133 /* URI_PATH */
1134 else if (sscanf (pos, HD5, url) == 1) {
1135 /* relative url */
1136 if ((url[0] != '/')) {
1137 if ((x = strrchr(server_url, '/')))
1138 *x = '\0';
1139 asprintf (&url, "%s/%s", server_url, url);
1140 }
1141 i = server_port;
1142 strcpy (type, server_type);
1143 strcpy (addr, host_name);
1144 }
1146 else {
1147 die (STATE_UNKNOWN,
1148 _("UNKNOWN - Could not parse redirect location - %s%s\n"),
1149 pos, (display_html ? "</A>" : ""));
1150 }
1152 break;
1154 } /* end while (pos) */
1156 if (++redir_depth > max_depth)
1157 die (STATE_WARNING,
1158 _("WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1159 max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1161 if (server_port==i &&
1162 !strcmp(server_address, addr) &&
1163 (host_name && !strcmp(host_name, addr)) &&
1164 !strcmp(server_url, url))
1165 die (STATE_WARNING,
1166 _("WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1167 type, addr, i, url, (display_html ? "</A>" : ""));
1169 server_port = i;
1170 strcpy (server_type, type);
1172 free (host_name);
1173 host_name = strdup (addr);
1175 free (server_address);
1176 server_address = strdup (addr);
1178 free (server_url);
1179 server_url = strdup (url);
1181 check_http ();
1182 }
1186 int
1187 server_type_check (const char *type)
1188 {
1189 if (strcmp (type, "https"))
1190 return FALSE;
1191 else
1192 return TRUE;
1193 }
1195 int
1196 server_port_check (int ssl_flag)
1197 {
1198 if (ssl_flag)
1199 return HTTPS_PORT;
1200 else
1201 return HTTP_PORT;
1202 }
1204 char *perfd_time (double elapsed_time)
1205 {
1206 return fperfdata ("time", elapsed_time, "s",
1207 check_warning_time, warning_time,
1208 check_critical_time, critical_time,
1209 TRUE, 0, FALSE, 0);
1210 }
1214 char *perfd_size (int page_len)
1215 {
1216 return perfdata ("size", page_len, "B",
1217 (min_page_len>0?TRUE:FALSE), min_page_len,
1218 (min_page_len>0?TRUE:FALSE), 0,
1219 TRUE, 0, FALSE, 0);
1220 }
1222 void
1223 print_help (void)
1224 {
1225 print_revision (progname, revision);
1227 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1228 printf (COPYRIGHT, copyright, email);
1230 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1231 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1232 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1233 printf ("%s\n", _("certificate expiration times."));
1235 printf ("\n\n");
1237 print_usage ();
1239 printf (_("NOTE: One or both of -H and -I must be specified"));
1241 printf ("\n");
1243 printf (_(UT_HELP_VRSN));
1245 printf (" %s\n", "-H, --hostname=ADDRESS");
1246 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1247 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1248 printf (" %s\n", "-I, --IP-address=ADDRESS");
1249 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1250 printf (" %s\n", "-p, --port=INTEGER");
1251 printf (" %s", _("Port number (default: "));
1252 printf ("%d)\n", HTTP_PORT);
1254 printf (_(UT_IPv46));
1256 #ifdef HAVE_SSL
1257 printf (" %s\n", "-S, --ssl");
1258 printf (" %s\n", _("Connect via SSL. Port defaults to 443"));
1259 printf (" %s\n", "-C, --certificate=INTEGER");
1260 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1261 printf (" %s\n", _("(when this option is used the url is not checked.)\n"));
1262 #endif
1264 printf (" %s\n", "-e, --expect=STRING");
1265 printf (" %s\n", _("String to expect in first (status) line of server response (default: "));
1266 printf ("%s\n", HTTP_EXPECT);
1267 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1268 printf (" %s\n", "-s, --string=STRING");
1269 printf (" %s\n", _("String to expect in the content"));
1270 printf (" %s\n", "-u, --url=PATH");
1271 printf (" %s\n", _("URL to GET or POST (default: /)"));
1272 printf (" %s\n," "-P, --post=STRING");
1273 printf (" %s\n", _("URL encoded http POST data"));
1274 printf (" %s\n", "-N, --no-body");
1275 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1276 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1277 printf (" %s\n", "-M, --max-age=SECONDS");
1278 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1279 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1280 printf (" %s\n", "-T, --content-type=STRING");
1281 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1283 printf (" %s\n", "-l, --linespan");
1284 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1285 printf (" %s\n", "-r, --regex, --ereg=STRING");
1286 printf (" %s\n", _("Search page for regex STRING"));
1287 printf (" %s\n", "-R, --eregi=STRING");
1288 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1289 printf (" %s\n", "--invert-regex");
1290 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1292 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1293 printf (" %s\n", _("Username:password on sites with basic authentication"));
1294 printf (" %s\n", "-A, --useragent=STRING");
1295 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1296 printf (" %s\n", "-k, --header=STRING");
1297 printf (" %s\n", _(" Any other tags to be sent in http header. Use multiple times for additional headers"));
1298 printf (" %s\n", "-L, --link=URL");
1299 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1300 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow>");
1301 printf (" %s\n", _("How to handle redirected pages"));
1302 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1303 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1305 printf (_(UT_WARN_CRIT));
1307 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1309 printf (_(UT_VERBOSE));
1311 printf (_("Notes:"));
1312 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1313 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1314 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1315 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1316 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1317 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1319 #ifdef HAVE_SSL
1320 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1321 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1322 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1323 printf (_("Examples:"));
1324 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1325 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1326 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1327 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1328 printf (" %s\n\n", _("a STATE_CRITICAL will be returned."));
1330 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1331 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1332 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1333 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1334 printf (" %s\n\n", _("the certificate is expired."));
1335 #endif
1337 printf (_(UT_SUPPORT));
1339 }
1343 void
1344 print_usage (void)
1345 {
1346 printf (_("Usage:"));
1347 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1348 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n");
1349 printf (" [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n");
1350 printf (" [-s string] [-l] [-r <regex> | -R <case-insensitive regex>] [-P string]\n");
1351 printf (" [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>] [-A string] [-k string]\n");
1352 }