Code

6e76706277d702712a92bfa3e34656b9fcb29bf5
[nagiosplug.git] / plugins / check_http.c
1 /******************************************************************************
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; either version 2 of the License, or
6  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  GNU General Public License for more details.
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  $Id$
18  
19 ******************************************************************************/
20 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
22 const char *progname = "check_http";
23 const char *revision = "$Revision$";
24 const char *copyright = "1999-2004";
25 const char *email = "nagiosplug-devel@lists.sourceforge.net";
27 #include "common.h"
28 #include "netutils.h"
29 #include "utils.h"
31 #define INPUT_DELIMITER ";"
33 #define HTTP_EXPECT "HTTP/1."
34 enum {
35         MAX_IPV4_HOSTLENGTH = 255,
36         HTTP_PORT = 80,
37         HTTPS_PORT = 443
38 };
40 #ifdef HAVE_SSL_H
41 #include <rsa.h>
42 #include <crypto.h>
43 #include <x509.h>
44 #include <pem.h>
45 #include <ssl.h>
46 #include <err.h>
47 #include <rand.h>
48 #else
49 # ifdef HAVE_OPENSSL_SSL_H
50 # include <openssl/rsa.h>
51 # include <openssl/crypto.h>
52 # include <openssl/x509.h>
53 # include <openssl/pem.h>
54 # include <openssl/ssl.h>
55 # include <openssl/err.h>
56 # include <openssl/rand.h>
57 # endif
58 #endif
60 #ifdef HAVE_SSL
61 int check_cert = FALSE;
62 int days_till_exp;
63 char *randbuff;
64 SSL_CTX *ctx;
65 SSL *ssl;
66 X509 *server_cert;
67 int connect_SSL (void);
68 int check_certificate (X509 **);
69 #endif
70 int no_body = FALSE;
71 int maximum_age = -1;
73 #ifdef HAVE_REGEX_H
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 #endif
87 struct timeval tv;
89 #define HTTP_URL "/"
90 #define CRLF "\r\n"
92 char timestamp[17] = "";
93 int specify_port = FALSE;
94 int server_port = HTTP_PORT;
95 char server_port_text[6] = "";
96 char server_type[6] = "http";
97 char *server_address;
98 char *host_name;
99 char *server_url;
100 char *user_agent;
101 int server_url_length;
102 int server_expect_yn = 0;
103 char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
104 char string_expect[MAX_INPUT_BUFFER] = "";
105 double warning_time = 0;
106 int check_warning_time = FALSE;
107 double critical_time = 0;
108 int check_critical_time = FALSE;
109 char user_auth[MAX_INPUT_BUFFER] = "";
110 int display_html = FALSE;
111 char *http_opt_headers;
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 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 int my_recv (void);
133 int my_close (void);
134 void print_help (void);
135 void print_usage (void);
137 int
138 main (int argc, char **argv)
140         int result = STATE_UNKNOWN;
142         /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
143         server_url = strdup(HTTP_URL);
144         server_url_length = strlen(server_url);
145         asprintf (&user_agent, "User-Agent: check_http/%s (nagios-plugins %s)",
146                   clean_revstring (revision), VERSION);
148         if (process_arguments (argc, argv) == ERROR)
149                 usage4 (_("Could not parse arguments"));
151         if (strstr (timestamp, ":")) {
152                 if (strstr (server_url, "?"))
153                         asprintf (&server_url, "%s&%s", server_url, timestamp);
154                 else
155                         asprintf (&server_url, "%s?%s", server_url, timestamp);
156         }
158         if (display_html == TRUE)
159                 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 
160                         use_ssl ? "https" : "http", host_name,
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 #ifdef HAVE_SSL
169         if (use_ssl && check_cert == TRUE) {
170                 if (connect_SSL () != OK)
171                         die (STATE_CRITICAL, _("HTTP CRITICAL - Could not make SSL connection\n"));
172                 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
173                         result = check_certificate (&server_cert);
174                         X509_free (server_cert);
175                 }
176                 else {
177                         printf (_("CRITICAL - Cannot retrieve server certificate.\n"));
178                         result = STATE_CRITICAL;
179                 }
180                 SSL_shutdown (ssl);
181                 SSL_free (ssl);
182                 SSL_CTX_free (ctx);
183                 close (sd);
184         }
185         else {
186                 result = check_http ();
187         }
188 #else
189         result = check_http ();
190 #endif
191         return result;
196 /* process command-line arguments */
197 int
198 process_arguments (int argc, char **argv)
200         int c = 1;
202         int option = 0;
203         static struct option longopts[] = {
204                 STD_LONG_OPTS,
205                 {"file",required_argument,0,'F'},
206                 {"link", no_argument, 0, 'L'},
207                 {"nohtml", no_argument, 0, 'n'},
208                 {"ssl", no_argument, 0, 'S'},
209                 {"verbose", no_argument, 0, 'v'},
210                 {"post", required_argument, 0, 'P'},
211                 {"IP-address", required_argument, 0, 'I'},
212                 {"url", required_argument, 0, 'u'},
213                 {"string", required_argument, 0, 's'},
214                 {"regex", required_argument, 0, 'r'},
215                 {"ereg", required_argument, 0, 'r'},
216                 {"eregi", required_argument, 0, 'R'},
217                 {"linespan", no_argument, 0, 'l'},
218                 {"onredirect", required_argument, 0, 'f'},
219                 {"certificate", required_argument, 0, 'C'},
220                 {"useragent", required_argument, 0, 'A'},
221                 {"header", required_argument, 0, 'k'},
222                 {"no-body", no_argument, 0, 'N'},
223                 {"max-age", required_argument, 0, 'M'},
224                 {"content-type", required_argument, 0, 'T'},
225                 {"min", required_argument, 0, 'm'},
226                 {"use-ipv4", no_argument, 0, '4'},
227                 {"use-ipv6", no_argument, 0, '6'},
228                 {0, 0, 0, 0}
229         };
231         if (argc < 2)
232                 return ERROR;
234         for (c = 1; c < argc; c++) {
235                 if (strcmp ("-to", argv[c]) == 0)
236                         strcpy (argv[c], "-t");
237                 if (strcmp ("-hn", argv[c]) == 0)
238                         strcpy (argv[c], "-H");
239                 if (strcmp ("-wt", argv[c]) == 0)
240                         strcpy (argv[c], "-w");
241                 if (strcmp ("-ct", argv[c]) == 0)
242                         strcpy (argv[c], "-c");
243                 if (strcmp ("-nohtml", argv[c]) == 0)
244                         strcpy (argv[c], "-n");
245         }
247         while (1) {
248                 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);
249                 if (c == -1 || c == EOF)
250                         break;
252                 switch (c) {
253                 case '?': /* usage */
254                         usage2 (_("Unknown argument"), optarg);
255                         break;
256                 case 'h': /* help */
257                         print_help ();
258                         exit (STATE_OK);
259                         break;
260                 case 'V': /* version */
261                         print_revision (progname, revision);
262                         exit (STATE_OK);
263                         break;
264                 case 't': /* timeout period */
265                         if (!is_intnonneg (optarg))
266                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
267                         else
268                                 socket_timeout = atoi (optarg);
269                         break;
270                 case 'c': /* critical time threshold */
271                         if (!is_nonnegative (optarg))
272                                 usage2 (_("Critical threshold must be integer"), optarg);
273                         else {
274                                 critical_time = strtod (optarg, NULL);
275                                 check_critical_time = TRUE;
276                         }
277                         break;
278                 case 'w': /* warning time threshold */
279                         if (!is_nonnegative (optarg))
280                                 usage2 (_("Warning threshold must be integer"), optarg);
281                         else {
282                                 warning_time = strtod (optarg, NULL);
283                                 check_warning_time = TRUE;
284                         }
285                         break;
286                 case 'A': /* User Agent String */
287                         asprintf (&user_agent, "User-Agent: %s", optarg);
288                         break;
289                 case 'k': /* Additional headers */
290                         asprintf (&http_opt_headers, "%s", optarg);
291                         break;
292                 case 'L': /* show html link */
293                         display_html = TRUE;
294                         break;
295                 case 'n': /* do not show html link */
296                         display_html = FALSE;
297                         break;
298                 case 'S': /* use SSL */
299 #ifndef HAVE_SSL
300                         usage4 (_("Invalid option - SSL is not available"));
301 #endif
302                         use_ssl = TRUE;
303                         if (specify_port == FALSE)
304                                 server_port = HTTPS_PORT;
305                         break;
306                 case 'C': /* Check SSL cert validity */
307 #ifdef HAVE_SSL
308                         if (!is_intnonneg (optarg))
309                                 usage2 (_("Invalid certificate expiration period"), optarg);
310                         else {
311                                 days_till_exp = atoi (optarg);
312                                 check_cert = TRUE;
313                         }
314 #else
315                         usage4 (_("Invalid option - SSL is not available"));
316 #endif
317                         break;
318                 case 'f': /* onredirect */
319                         if (!strcmp (optarg, "follow"))
320                                 onredirect = STATE_DEPENDENT;
321                         if (!strcmp (optarg, "unknown"))
322                                 onredirect = STATE_UNKNOWN;
323                         if (!strcmp (optarg, "ok"))
324                                 onredirect = STATE_OK;
325                         if (!strcmp (optarg, "warning"))
326                                 onredirect = STATE_WARNING;
327                         if (!strcmp (optarg, "critical"))
328                                 onredirect = STATE_CRITICAL;
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 (strstr (optarg, ":"))
336                                 sscanf (optarg, "%*[^:]:%d", &server_port);
337                         break;
338                 case 'I': /* Server IP-address */
339                         server_address = strdup (optarg);
340                         break;
341                 case 'u': /* URL path */
342                         server_url = strdup (optarg);
343                         server_url_length = strlen (server_url);
344                         break;
345                 case 'p': /* Server port */
346                         if (!is_intnonneg (optarg))
347                                 usage2 (_("Invalid port number"), optarg);
348                         else {
349                                 server_port = atoi (optarg);
350                                 specify_port = TRUE;
351                         }
352                         break;
353                 case 'a': /* authorization info */
354                         strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
355                         user_auth[MAX_INPUT_BUFFER - 1] = 0;
356                         break;
357                 case 'P': /* HTTP POST data in URL encoded format */
358                         if (http_method || http_post_data) break;
359                         http_method = strdup("POST");
360                         http_post_data = strdup (optarg);
361                         break;
362                 case 's': /* string or substring */
363                         strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
364                         string_expect[MAX_INPUT_BUFFER - 1] = 0;
365                         break;
366                 case 'e': /* string or substring */
367                         strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
368                         server_expect[MAX_INPUT_BUFFER - 1] = 0;
369                         server_expect_yn = 1;
370                         break;
371                 case 'T': /* Content-type */
372                         asprintf (&http_content_type, "%s", optarg);
373                         break;
374 #ifndef HAVE_REGEX_H
375                 case 'l': /* linespan */
376                 case 'r': /* linespan */
377                 case 'R': /* linespan */
378                         usage4 (_("Call for regex which was not a compiled option"));
379                         break;
380 #else
381                 case 'l': /* linespan */
382                         cflags &= ~REG_NEWLINE;
383                         break;
384                 case 'R': /* regex */
385                         cflags |= REG_ICASE;
386                 case 'r': /* regex */
387                         strncpy (regexp, optarg, MAX_RE_SIZE - 1);
388                         regexp[MAX_RE_SIZE - 1] = 0;
389                         errcode = regcomp (&preg, regexp, cflags);
390                         if (errcode != 0) {
391                                 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
392                                 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
393                                 return ERROR;
394                         }
395                         break;
396 #endif
397                 case '4':
398                         address_family = AF_INET;
399                         break;
400                 case '6':
401 #ifdef USE_IPV6
402                         address_family = AF_INET6;
403 #else
404                         usage4 (_("IPv6 support not available"));
405 #endif
406                         break;
407                 case 'v': /* verbose */
408                         verbose = TRUE;
409                         break;
410                 case 'm': /* min_page_length */
411                         min_page_len = atoi (optarg);
412                         break;
413                 case 'N': /* no-body */
414                         no_body = TRUE;
415                         break;
416                 case 'M': /* max-age */
417                   {
418                     int L = strlen(optarg);
419                     if (L && optarg[L-1] == 'm')
420                       maximum_age = atoi (optarg) * 60;
421                     else if (L && optarg[L-1] == 'h')
422                       maximum_age = atoi (optarg) * 60 * 60;
423                     else if (L && optarg[L-1] == 'd')
424                       maximum_age = atoi (optarg) * 60 * 60 * 24;
425                     else if (L && (optarg[L-1] == 's' ||
426                                    isdigit (optarg[L-1])))
427                       maximum_age = atoi (optarg);
428                     else {
429                       fprintf (stderr, "unparsable max-age: %s\n", optarg);
430                       exit (1);
431                     }
432                   }
433                   break;
434                 }
435         }
437         c = optind;
439         if (server_address == NULL && c < argc)
440                 server_address = strdup (argv[c++]);
442         if (host_name == NULL && c < argc)
443                 host_name = strdup (argv[c++]);
445         if (server_address == NULL) {
446                 if (host_name == NULL)
447                         usage4 (_("You must specify a server address or host name"));
448                 else
449                         server_address = strdup (host_name);
450         }
452         if (check_critical_time && critical_time>(double)socket_timeout)
453                 socket_timeout = (int)critical_time + 1;
455         if (http_method == NULL)
456                 http_method = strdup ("GET");
458         return TRUE;
463 /* written by lauri alanko */
464 static char *
465 base64 (const char *bin, size_t len)
468         char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
469         size_t i = 0, j = 0;
471         char BASE64_END = '=';
472         char base64_table[64];
473         strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
475         while (j < len - 2) {
476                 buf[i++] = base64_table[bin[j] >> 2];
477                 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
478                 buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
479                 buf[i++] = base64_table[bin[j + 2] & 63];
480                 j += 3;
481         }
483         switch (len - j) {
484         case 1:
485                 buf[i++] = base64_table[bin[j] >> 2];
486                 buf[i++] = base64_table[(bin[j] & 3) << 4];
487                 buf[i++] = BASE64_END;
488                 buf[i++] = BASE64_END;
489                 break;
490         case 2:
491                 buf[i++] = base64_table[bin[j] >> 2];
492                 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
493                 buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
494                 buf[i++] = BASE64_END;
495                 break;
496         case 0:
497                 break;
498         }
500         buf[i] = '\0';
501         return buf;
506 /* Returns 1 if we're done processing the document body; 0 to keep going */
507 static int
508 document_headers_done (char *full_page)
510         const char *body;
512         for (body = full_page; *body; body++) {
513                 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
514                         break;
515         }
517         if (!*body)
518                 return 0;  /* haven't read end of headers yet */
520         full_page[body - full_page] = 0;
521         return 1;
524 static time_t
525 parse_time_string (const char *string)
527         struct tm tm;
528         time_t t;
529         memset (&tm, 0, sizeof(tm));
531         /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
533         if (isupper (string[0])  &&  /* Tue */
534                 islower (string[1])  &&
535                 islower (string[2])  &&
536                 ',' ==   string[3]   &&
537                 ' ' ==   string[4]   &&
538                 (isdigit(string[5]) || string[5] == ' ') &&   /* 25 */
539                 isdigit (string[6])  &&
540                 ' ' ==   string[7]   &&
541                 isupper (string[8])  &&  /* Dec */
542                 islower (string[9])  &&
543                 islower (string[10]) &&
544                 ' ' ==   string[11]  &&
545                 isdigit (string[12]) &&  /* 2001 */
546                 isdigit (string[13]) &&
547                 isdigit (string[14]) &&
548                 isdigit (string[15]) &&
549                 ' ' ==   string[16]  &&
550                 isdigit (string[17]) &&  /* 02: */
551                 isdigit (string[18]) &&
552                 ':' ==   string[19]  &&
553                 isdigit (string[20]) &&  /* 59: */
554                 isdigit (string[21]) &&
555                 ':' ==   string[22]  &&
556                 isdigit (string[23]) &&  /* 03 */
557                 isdigit (string[24]) &&
558                 ' ' ==   string[25]  &&
559                 'G' ==   string[26]  &&  /* GMT */
560                 'M' ==   string[27]  &&  /* GMT */
561                 'T' ==   string[28]) {
563                 tm.tm_sec  = 10 * (string[23]-'0') + (string[24]-'0');
564                 tm.tm_min  = 10 * (string[20]-'0') + (string[21]-'0');
565                 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
566                 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
567                 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
568                         !strncmp (string+8, "Feb", 3) ? 1 :
569                         !strncmp (string+8, "Mar", 3) ? 2 :
570                         !strncmp (string+8, "Apr", 3) ? 3 :
571                         !strncmp (string+8, "May", 3) ? 4 :
572                         !strncmp (string+8, "Jun", 3) ? 5 :
573                         !strncmp (string+8, "Jul", 3) ? 6 :
574                         !strncmp (string+8, "Aug", 3) ? 7 :
575                         !strncmp (string+8, "Sep", 3) ? 8 :
576                         !strncmp (string+8, "Oct", 3) ? 9 :
577                         !strncmp (string+8, "Nov", 3) ? 10 :
578                         !strncmp (string+8, "Dec", 3) ? 11 :
579                         -1);
580                 tm.tm_year = ((1000 * (string[12]-'0') +
581                         100 * (string[13]-'0') +
582                         10 * (string[14]-'0') +
583                         (string[15]-'0'))
584                         - 1900);
586                 tm.tm_isdst = 0;  /* GMT is never in DST, right? */
588                 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
589                         return 0;
591                 /* 
592                 This is actually wrong: we need to subtract the local timezone
593                 offset from GMT from this value.  But, that's ok in this usage,
594                 because we only comparing these two GMT dates against each other,
595                 so it doesn't matter what time zone we parse them in.
596                 */
598                 t = mktime (&tm);
599                 if (t == (time_t) -1) t = 0;
601                 if (verbose) {
602                         const char *s = string;
603                         while (*s && *s != '\r' && *s != '\n')
604                         fputc (*s++, stdout);
605                         printf (" ==> %lu\n", (unsigned long) t);
606                 }
608                 return t;
610         } else {
611                 return 0;
612         }
617 static void
618 check_document_dates (const char *headers)
620         const char *s;
621         char *server_date = 0;
622         char *document_date = 0;
624         s = headers;
625         while (*s) {
626                 const char *field = s;
627                 const char *value = 0;
629                 /* Find the end of the header field */
630                 while (*s && !isspace(*s) && *s != ':')
631                         s++;
633                 /* Remember the header value, if any. */
634                 if (*s == ':')
635                         value = ++s;
637                 /* Skip to the end of the header, including continuation lines. */
638                 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
639                         s++;
640                 s++;
642                 /* Process this header. */
643                 if (value && value > field+2) {
644                         char *ff = (char *) malloc (value-field);
645                         char *ss = ff;
646                         while (field < value-1)
647                                 *ss++ = tolower(*field++);
648                         *ss++ = 0;
650                         if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
651                                 const char *e;
652                                 while (*value && isspace (*value))
653                                         value++;
654                                 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
655                                         ;
656                                 ss = (char *) malloc (e - value + 1);
657                                 strncpy (ss, value, e - value);
658                                 ss[e - value] = 0;
659                                 if (!strcmp (ff, "date")) {
660                                         if (server_date) free (server_date);
661                                         server_date = ss;
662                                 } else {
663                                         if (document_date) free (document_date);
664                                         document_date = ss;
665                                 }
666                         }
667                         free (ff);
668                 }
669         }
671         /* Done parsing the body.  Now check the dates we (hopefully) parsed.  */
672         if (!server_date || !*server_date) {
673                 die (STATE_UNKNOWN, _("Server date unknown\n"));
674         } else if (!document_date || !*document_date) {
675                 die (STATE_CRITICAL, _("Document modification date unknown\n"));
676         } else {
677                 time_t srv_data = parse_time_string (server_date);
678                 time_t doc_data = parse_time_string (document_date);
680                 if (srv_data <= 0) {
681                         die (STATE_CRITICAL, _("CRITICAL - Server date \"%100s\" unparsable"), server_date);
682                 } else if (doc_data <= 0) {
683                         die (STATE_CRITICAL, _("CRITICAL - Document date \"%100s\" unparsable"), document_date);
684                 } else if (doc_data > srv_data + 30) {
685                         die (STATE_CRITICAL, _("CRITICAL - Document is %d seconds in the future\n"), (int)doc_data - (int)srv_data);
686                 } else if (doc_data < srv_data - maximum_age) {
687                 int n = (srv_data - doc_data);
688                 if (n > (60 * 60 * 24 * 2))
689                         die (STATE_CRITICAL,
690                           _("CRITICAL - Last modified %.1f days ago\n"),
691                           ((float) n) / (60 * 60 * 24));
692         else
693                 die (STATE_CRITICAL,
694                     _("CRITICAL - Last modified %d:%02d:%02d ago\n"),
695                     n / (60 * 60), (n / 60) % 60, n % 60);
696     }
698     free (server_date);
699     free (document_date);
700   }
705 int
706 check_http (void)
708         char *msg;
709         char *status_line;
710         char *status_code;
711         char *header;
712         char *page;
713         char *auth;
714         int http_status;
715         int i = 0;
716         size_t pagesize = 0;
717         char *full_page;
718         char *buf;
719         char *pos;
720         long microsec;
721         double elapsed_time;
722         int page_len = 0;
723 #ifdef HAVE_SSL
724         int sslerr;
725 #endif
727         /* try to connect to the host at the given port number */
728 #ifdef HAVE_SSL
729         if (use_ssl == TRUE) {
731                 if (connect_SSL () != OK) {
732                         die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
733                 }
735                 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
736                         X509_free (server_cert);
737                 }
738                 else {
739                         printf (_("CRITICAL - Cannot retrieve server certificate.\n"));
740                         return STATE_CRITICAL;
741                 }
743         }
744         else {
745 #endif
746                 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
747                         die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
748 #ifdef HAVE_SSL
749         }
750 #endif
752         asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
754         /* optionally send the host header info */
755         if (host_name)
756                 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
758         /* optionally send any other header tag */
759         if (http_opt_headers) {
760                 for ((pos = strtok(http_opt_headers, INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
761                         asprintf (&buf, "%s%s\r\n", buf, pos);
762         }
764         /* optionally send the authentication info */
765         if (strlen(user_auth)) {
766                 auth = base64 (user_auth, strlen (user_auth));
767                 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
768         }
770         /* either send http POST data */
771         if (http_post_data) {
772                 if (http_content_type) {
773                         asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
774                 } else {
775                         asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
776                 }
777                 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, strlen (http_post_data));
778                 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
779         }
780         else {
781                 /* or just a newline so the server knows we're done with the request */
782                 asprintf (&buf, "%s%s", buf, CRLF);
783         }
785         if (verbose)
786                 printf ("%s\n", buf);
788 #ifdef HAVE_SSL
789         if (use_ssl == TRUE) {
790                 if (SSL_write (ssl, buf, (int)strlen(buf)) == -1) {
791                         ERR_print_errors_fp (stderr);
792                         return STATE_CRITICAL;
793                 }
794         }
795         else {
796 #endif
797                 send (sd, buf, strlen (buf), 0);
798 #ifdef HAVE_SSL
799         }
800 #endif
802         /* fetch the page */
803         full_page = strdup("");
804         while ((i = my_recv ()) > 0) {
805                 buffer[i] = '\0';
806                 asprintf (&full_page, "%s%s", full_page, buffer);
807                 pagesize += i;
809                 if (no_body && document_headers_done (full_page)) {
810                   i = 0;
811                   break;
812                 }
813         }
815         if (i < 0 && errno != ECONNRESET) {
816 #ifdef HAVE_SSL
817                 if (use_ssl) {
818                         sslerr=SSL_get_error(ssl, i);
819                         if ( sslerr == SSL_ERROR_SSL ) {
820                                 die (STATE_WARNING, _("Client Certificate Required\n"));
821                         } else {
822                                 die (STATE_CRITICAL, _("Error on receive\n"));
823                         }
824                 }
825                 else {
826 #endif
827                         die (STATE_CRITICAL, _("Error on receive\n"));
828 #ifdef HAVE_SSL
829                 }
830 #endif
831         }
833         /* return a CRITICAL status if we couldn't read any data */
834         if (pagesize == (size_t) 0)
835                 die (STATE_CRITICAL, _("No data received %s\n"), timestamp);
837         /* close the connection */
838         my_close ();
840         /* reset the alarm */
841         alarm (0);
843         /* leave full_page untouched so we can free it later */
844         page = full_page;
846         if (verbose)
847                 printf ("%s://%s:%d%s is %d characters\n",
848                         use_ssl ? "https" : "http", server_address,
849                         server_port, server_url, pagesize);
851         /* find status line and null-terminate it */
852         status_line = page;
853         page += (size_t) strcspn (page, "\r\n");
854         pos = page;
855         page += (size_t) strspn (page, "\r\n");
856         status_line[strcspn(status_line, "\r\n")] = 0;
857         strip (status_line);
858         if (verbose)
859                 printf ("STATUS: %s\n", status_line);
861         /* find header info and null-terminate it */
862         header = page;
863         while (strcspn (page, "\r\n") > 0) {
864                 page += (size_t) strcspn (page, "\r\n");
865                 pos = page;
866                 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
867                     (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
868                         page += (size_t) 2;
869                 else
870                         page += (size_t) 1;
871         }
872         page += (size_t) strspn (page, "\r\n");
873         header[pos - header] = 0;
874         if (verbose)
875                 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
876                 (no_body ? "  [[ skipped ]]" : page));
878         /* make sure the status line matches the response we are looking for */
879         if (!strstr (status_line, server_expect)) {
880                 if (server_port == HTTP_PORT)
881                         asprintf (&msg,
882                             _("Invalid HTTP response received from host\n"));
883                 else
884                         asprintf (&msg,
885                                   _("Invalid HTTP response received from host on port %d\n"),
886                                   server_port);
887                 die (STATE_CRITICAL, "%s", msg);
888         }
890         /* Exit here if server_expect was set by user and not default */
891         if ( server_expect_yn  )  {
892                 asprintf (&msg,
893                           _("HTTP OK: Status line output matched \"%s\"\n"),
894                           server_expect);
895                 if (verbose)
896                         printf ("%s\n",msg);
897         }
898         else {
899                 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
900                 /* HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
901     /* Status-Code = 3 DIGITS */
903                 status_code = strchr (status_line, ' ') + sizeof (char);
904                 if (strspn (status_code, "1234567890") != 3)
905                         die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
907                 http_status = atoi (status_code);
909                 /* check the return code */
911                 if (http_status >= 600 || http_status < 100)
912                         die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
914                 /* server errors result in a critical state */
915                 else if (http_status >= 500)
916                         die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
918                 /* client errors result in a warning state */
919                 else if (http_status >= 400)
920                         die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
922                 /* check redirected page if specified */
923                 else if (http_status >= 300) {
925                         if (onredirect == STATE_DEPENDENT)
926                                 redir (header, status_line);
927                         else if (onredirect == STATE_UNKNOWN)
928                                 printf (_("UNKNOWN"));
929                         else if (onredirect == STATE_OK)
930                                 printf (_("OK"));
931                         else if (onredirect == STATE_WARNING)
932                                 printf (_("WARNING"));
933                         else if (onredirect == STATE_CRITICAL)
934                                 printf (_("CRITICAL"));
935                         microsec = deltime (tv);
936                         elapsed_time = (double)microsec / 1.0e6;
937                         die (onredirect,
938                              _(" - %s - %.3f second response time %s%s|%s %s\n"),
939                              status_line, elapsed_time, timestamp,
940                              (display_html ? "</A>" : ""),
941                                          perfd_time (elapsed_time), perfd_size (pagesize));
942                 } /* end if (http_status >= 300) */
944         } /* end else (server_expect_yn)  */
945                 
946         if (maximum_age >= 0) {
947           check_document_dates (header);
948         }
950         /* check elapsed time */
951         microsec = deltime (tv);
952         elapsed_time = (double)microsec / 1.0e6;
953         asprintf (&msg,
954                   _("HTTP WARNING: %s - %.3f second response time %s%s|%s %s\n"),
955                   status_line, elapsed_time, timestamp,
956                   (display_html ? "</A>" : ""),
957                                                 perfd_time (elapsed_time), perfd_size (pagesize));
958         if (check_critical_time == TRUE && elapsed_time > critical_time)
959                 die (STATE_CRITICAL, "%s", msg);
960         if (check_warning_time == TRUE && elapsed_time > warning_time)
961                 die (STATE_WARNING, "%s", msg);
963         /* Page and Header content checks go here */
964         /* these checks should be last */
966         if (strlen (string_expect)) {
967                 if (strstr (page, string_expect)) {
968                         printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
969                                 status_line, elapsed_time,
970                                 timestamp, (display_html ? "</A>" : ""),
971                                 perfd_time (elapsed_time), perfd_size (pagesize));
972                         exit (STATE_OK);
973                 }
974                 else {
975                         printf (_("CRITICAL - string not found%s|%s %s\n"),
976                                 (display_html ? "</A>" : ""),
977                                 perfd_time (elapsed_time), perfd_size (pagesize));
978                         exit (STATE_CRITICAL);
979                 }
980         }
981 #ifdef HAVE_REGEX_H
982         if (strlen (regexp)) {
983                 errcode = regexec (&preg, page, REGS, pmatch, 0);
984                 if (errcode == 0) {
985                         printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
986                                 status_line, elapsed_time,
987                                 timestamp, (display_html ? "</A>" : ""),
988                                 perfd_time (elapsed_time), perfd_size (pagesize));
989                         exit (STATE_OK);
990                 }
991                 else {
992                         if (errcode == REG_NOMATCH) {
993                                 printf (_("CRITICAL - pattern not found%s|%s %s\n"),
994                                         (display_html ? "</A>" : ""),
995                                         perfd_time (elapsed_time), perfd_size (pagesize));
996                                 exit (STATE_CRITICAL);
997                         }
998                         else {
999                                 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1000                                 printf (_("CRITICAL - Execute Error: %s\n"), errbuf);
1001                                 exit (STATE_CRITICAL);
1002                         }
1003                 }
1004         }
1005 #endif
1007         /* make sure the page is of an appropriate size */
1008         page_len = strlen (page);
1009         if ((min_page_len > 0) && (page_len < min_page_len)) {
1010                 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1011                         page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1012                 exit (STATE_WARNING);
1013         }
1014         /* We only get here if all tests have been passed */
1015         asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s%s|%s %s\n"),
1016                   status_line, page_len, elapsed_time,
1017                   timestamp, (display_html ? "</A>" : ""),
1018                                                 perfd_time (elapsed_time), perfd_size (page_len));
1019         die (STATE_OK, "%s", msg);
1020         return STATE_UNKNOWN;
1025 /* per RFC 2396 */
1026 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1027 #define URI_HTTP "%[HTPShtps]://"
1028 #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1029 #define URI_PORT ":%[0123456789]"
1030 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1031 #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
1032 #define HD2 URI_HTTP URI_HOST URI_PATH
1033 #define HD3 URI_HTTP URI_HOST URI_PORT
1034 #define HD4 URI_HTTP URI_HOST
1035 #define HD5 URI_PATH
1037 void
1038 redir (char *pos, char *status_line)
1040         int i = 0;
1041         char *x;
1042         char xx[2];
1043         char type[6];
1044         char *addr;
1045         char port[6];
1046         char *url;
1048         addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1049         if (addr == NULL)
1050                 die (STATE_UNKNOWN, _("Could not allocate addr\n"));
1051         
1052         url = malloc (strcspn (pos, "\r\n"));
1053         if (url == NULL)
1054                 die (STATE_UNKNOWN, _("Could not allocate url\n"));
1056         while (pos) {
1058                 if (sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i) < 1) {
1060                         pos += (size_t) strcspn (pos, "\r\n");
1061                         pos += (size_t) strspn (pos, "\r\n");
1062                         if (strlen(pos) == 0) 
1063                                 die (STATE_UNKNOWN,
1064                                                  _("UNKNOWN - Could not find redirect location - %s%s\n"),
1065                                                  status_line, (display_html ? "</A>" : ""));
1066                         continue;
1067                 }
1069                 pos += i;
1070                 pos += strspn (pos, " \t\r\n");
1072                 url = realloc (url, strcspn (pos, "\r\n"));
1073                 if (url == NULL)
1074                         die (STATE_UNKNOWN, _("could not allocate url\n"));
1076                 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1077                 if (sscanf (pos, HD1, type, addr, port, url) == 4) {
1078                         use_ssl = server_type_check (type);
1079                         i = atoi (port);
1080                 }
1082                 /* URI_HTTP URI_HOST URI_PATH */
1083                 else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 
1084                         use_ssl = server_type_check (type);
1085                         i = server_port_check (use_ssl);
1086                 }
1088                 /* URI_HTTP URI_HOST URI_PORT */
1089                 else if(sscanf (pos, HD3, type, addr, port) == 3) {
1090                         strcpy (url, HTTP_URL);
1091                         use_ssl = server_type_check (type);
1092                         i = atoi (port);
1093                 }
1095                 /* URI_HTTP URI_HOST */
1096                 else if(sscanf (pos, HD4, type, addr) == 2) {
1097                         strcpy (url, HTTP_URL);
1098                         use_ssl = server_type_check (type);
1099                         i = server_port_check (use_ssl);
1100                 }
1102                 /* URI_PATH */
1103                 else if (sscanf (pos, HD5, url) == 1) {
1104                         /* relative url */
1105                         if ((url[0] != '/')) {
1106                                 if ((x = strrchr(server_url, '/')))
1107                                         *x = '\0';
1108                                 asprintf (&url, "%s/%s", server_url, url);
1109                         }
1110                         i = server_port;
1111                         strcpy (type, server_type);
1112                         strcpy (addr, host_name);
1113                 }                                       
1115                 else {
1116                         die (STATE_UNKNOWN,
1117                                          _("UNKNOWN - Could not parse redirect location - %s%s\n"),
1118                                          pos, (display_html ? "</A>" : ""));
1119                 }
1121                 break;
1123         } /* end while (pos) */
1125         if (++redir_depth > max_depth)
1126                 die (STATE_WARNING,
1127                      _("WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1128                      max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1130         if (server_port==i &&
1131             !strcmp(server_address, addr) &&
1132             (host_name && !strcmp(host_name, addr)) &&
1133             !strcmp(server_url, url))
1134                 die (STATE_WARNING,
1135                      _("WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1136                      type, addr, i, url, (display_html ? "</A>" : ""));
1138         server_port = i;
1139         strcpy (server_type, type);
1141         free (host_name);
1142         host_name = strdup (addr);
1144         free (server_address);
1145         server_address = strdup (addr);
1147         free (server_url);
1148         server_url = strdup (url);
1150         check_http ();
1155 int
1156 server_type_check (const char *type)
1158         if (strcmp (type, "https"))
1159                 return FALSE;
1160         else
1161                 return TRUE;
1164 int
1165 server_port_check (int ssl_flag)
1167         if (ssl_flag)
1168                 return HTTPS_PORT;
1169         else
1170                 return HTTP_PORT;
1175 #ifdef HAVE_SSL
1176 int connect_SSL (void)
1178         SSL_METHOD *meth;
1180         asprintf (&randbuff, "%s", "qwertyuiopasdfghjklqwertyuiopasdfghjkl");
1181         RAND_seed (randbuff, (int)strlen(randbuff));
1182         if (verbose)
1183                 printf(_("SSL seeding: %s\n"), (RAND_status()==1 ? _("OK") : _("Failed")) );
1185         /* Initialize SSL context */
1186         SSLeay_add_ssl_algorithms ();
1187         meth = SSLv23_client_method ();
1188         SSL_load_error_strings ();
1189         if ((ctx = SSL_CTX_new (meth)) == NULL) {
1190                 printf (_("CRITICAL -  Cannot create SSL context.\n"));
1191                 return STATE_CRITICAL;
1192         }
1194         /* Initialize alarm signal handling */
1195         signal (SIGALRM, socket_timeout_alarm_handler);
1197         /* Set socket timeout */
1198         alarm (socket_timeout);
1200         /* Save start time */
1201         gettimeofday (&tv, NULL);
1203         /* Make TCP connection */
1204         if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK) {
1205                 /* Do the SSL handshake */
1206                 if ((ssl = SSL_new (ctx)) != NULL) {
1207                         SSL_set_cipher_list(ssl, "ALL");
1208                         SSL_set_fd (ssl, sd);
1209                         if (SSL_connect (ssl) != -1)
1210                                 return OK;
1211                         ERR_print_errors_fp (stderr);
1212                 }
1213                 else {
1214                         printf (_("CRITICAL - Cannot initiate SSL handshake.\n"));
1215                 }
1216                 SSL_free (ssl);
1217         }
1219         SSL_CTX_free (ctx);
1220         close (sd);
1222         return STATE_CRITICAL;
1224 #endif
1228 #ifdef HAVE_SSL
1229 int
1230 check_certificate (X509 ** certificate)
1232         ASN1_STRING *tm;
1233         int offset;
1234         struct tm stamp;
1235         int days_left;
1238         /* Retrieve timestamp of certificate */
1239         tm = X509_get_notAfter (*certificate);
1241         /* Generate tm structure to process timestamp */
1242         if (tm->type == V_ASN1_UTCTIME) {
1243                 if (tm->length < 10) {
1244                         printf (_("CRITICAL - Wrong time format in certificate.\n"));
1245                         return STATE_CRITICAL;
1246                 }
1247                 else {
1248                         stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
1249                         if (stamp.tm_year < 50)
1250                                 stamp.tm_year += 100;
1251                         offset = 0;
1252                 }
1253         }
1254         else {
1255                 if (tm->length < 12) {
1256                         printf (_("CRITICAL - Wrong time format in certificate.\n"));
1257                         return STATE_CRITICAL;
1258                 }
1259                 else {
1260                         stamp.tm_year =
1261                                 (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
1262                                 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
1263                         stamp.tm_year -= 1900;
1264                         offset = 2;
1265                 }
1266         }
1267         stamp.tm_mon =
1268                 (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
1269         stamp.tm_mday =
1270                 (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
1271         stamp.tm_hour =
1272                 (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
1273         stamp.tm_min =
1274                 (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
1275         stamp.tm_sec = 0;
1276         stamp.tm_isdst = -1;
1278         days_left = (mktime (&stamp) - time (NULL)) / 86400;
1279         snprintf
1280                 (timestamp, 17, "%02d/%02d/%04d %02d:%02d",
1281                  stamp.tm_mon + 1,
1282                  stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_hour, stamp.tm_min);
1284         if (days_left > 0 && days_left <= days_till_exp) {
1285                 printf (_("WARNING - Certificate expires in %d day(s) (%s).\n"), days_left, timestamp);
1286                 return STATE_WARNING;
1287         }
1288         if (days_left < 0) {
1289                 printf (_("CRITICAL - Certificate expired on %s.\n"), timestamp);
1290                 return STATE_CRITICAL;
1291         }
1293         if (days_left == 0) {
1294                 printf (_("WARNING - Certificate expires today (%s).\n"), timestamp);
1295                 return STATE_WARNING;
1296         }
1298         printf (_("OK - Certificate will expire on %s.\n"), timestamp);
1300         return STATE_OK;
1302 #endif
1306 char *perfd_time (double elapsed_time)
1308         return fperfdata ("time", elapsed_time, "s",
1309                   check_warning_time, warning_time,
1310                   check_critical_time, critical_time,
1311                                                                          TRUE, 0, FALSE, 0);
1316 char *perfd_size (int page_len)
1318         return perfdata ("size", page_len, "B",
1319                   (min_page_len>0?TRUE:FALSE), min_page_len,
1320                   (min_page_len>0?TRUE:FALSE), 0,
1321                   TRUE, 0, FALSE, 0);
1326 int
1327 my_recv (void)
1329         int i;
1330 #ifdef HAVE_SSL
1331         if (use_ssl) {
1332                 i = SSL_read (ssl, buffer, MAX_INPUT_BUFFER - 1);
1333         }
1334         else {
1335                 i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1336         }
1337 #else
1338         i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1339 #endif
1340         return i;
1345 int
1346 my_close (void)
1348 #ifdef HAVE_SSL
1349         if (use_ssl == TRUE) {
1350                 SSL_shutdown (ssl);
1351                 SSL_free (ssl);
1352                 SSL_CTX_free (ctx);
1353                 return 0;
1354         }
1355         else {
1356 #endif
1357                 return close (sd);
1358 #ifdef HAVE_SSL
1359         }
1360 #endif
1365 void
1366 print_help (void)
1368         print_revision (progname, revision);
1370         printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1371         printf (COPYRIGHT, copyright, email);
1373         printf (_("\
1374 This plugin tests the HTTP service on the specified host. It can test\n\
1375 normal (http) and secure (https) servers, follow redirects, search for\n\
1376 strings and regular expressions, check connection times, and report on\n\
1377 certificate expiration times.\n\n"));
1379         print_usage ();
1381         printf (_("NOTE: One or both of -H and -I must be specified\n"));
1383         printf (_(UT_HELP_VRSN));
1385         printf (_("\
1386  -H, --hostname=ADDRESS\n\
1387     Host name argument for servers using host headers (virtual host)\n\
1388     Append a port to include it in the header (eg: example.com:5000)\n\
1389  -I, --IP-address=ADDRESS\n\
1390    IP address or name (use numeric address if possible to bypass DNS lookup).\n\
1391  -p, --port=INTEGER\n\
1392    Port number (default: %d)\n"), HTTP_PORT);
1394         printf (_(UT_IPv46));
1396 #ifdef HAVE_SSL
1397         printf (_("\
1398  -S, --ssl\n\
1399     Connect via SSL\n\
1400  -C, --certificate=INTEGER\n\
1401     Minimum number of days a certificate has to be valid.\n\
1402     (when this option is used the url is not checked.)\n"));
1403 #endif
1405         printf (_("\
1406  -e, --expect=STRING\n\
1407    String to expect in first (status) line of server response (default: %s)\n\
1408    If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)\n\
1409  -s, --string=STRING\n\
1410    String to expect in the content\n\
1411  -u, --url=PATH\n\
1412    URL to GET or POST (default: /)\n\
1413  -P, --post=STRING\n\
1414    URL encoded http POST data\n\
1415  -N, --no-body\n\
1416    Don't wait for document body: stop reading after headers.\n\
1417    (Note that this still does an HTTP GET or POST, not a HEAD.)\n\
1418  -M, --max-age=SECONDS\n\
1419    Warn if document is more than SECONDS old. the number can also be of \n\
1420    the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.\n\
1421  -T, --content-type=STRING\n\
1422    specify Content-Type header media type when POSTing\n"), HTTP_EXPECT);
1424 #ifdef HAVE_REGEX_H
1425         printf (_("\
1426  -l, --linespan\n\
1427     Allow regex to span newlines (must precede -r or -R)\n\
1428  -r, --regex, --ereg=STRING\n\
1429     Search page for regex STRING\n\
1430  -R, --eregi=STRING\n\
1431     Search page for case-insensitive regex STRING\n"));
1432 #endif
1434         printf (_("\
1435  -a, --authorization=AUTH_PAIR\n\
1436    Username:password on sites with basic authentication\n\
1437  -A, --useragent=STRING\n\
1438    String to be sent in http header as \"User Agent\"\n\
1439  -k, --header=STRING\n\
1440    Any other tags to be sent in http header, separated by semicolon\n\
1441  -L, --link=URL\n\
1442    Wrap output in HTML link (obsoleted by urlize)\n\
1443  -f, --onredirect=<ok|warning|critical|follow>\n\
1444    How to handle redirected pages\n\
1445  -m, --min=INTEGER\n\
1446    Minimum page size required (bytes)\n"));
1448         printf (_(UT_WARN_CRIT));
1450         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1452         printf (_(UT_VERBOSE));
1454                                         printf (_("\
1455 This plugin will attempt to open an HTTP connection with the host. Successful\n\
1456 connects return STATE_OK, refusals and timeouts return STATE_CRITICAL, other\n\
1457 errors return STATE_UNKNOWN.  Successful connects, but incorrect reponse\n\
1458 messages from the host result in STATE_WARNING return values.  If you are\n\
1459 checking a virtual server that uses 'host headers' you must supply the FQDN\n\
1460 (fully qualified domain name) as the [host_name] argument.\n"));
1462 #ifdef HAVE_SSL
1463         printf (_("\n\
1464 This plugin can also check whether an SSL enabled web server is able to\n\
1465 serve content (optionally within a specified time) or whether the X509 \n\
1466 certificate is still valid for the specified number of days.\n"));
1467         printf (_("\n\
1468 CHECK CONTENT: check_http -w 5 -c 10 --ssl www.verisign.com\n\n\
1469 When the 'www.verisign.com' server returns its content within 5 seconds, a\n\
1470 STATE_OK will be returned. When the server returns its content but exceeds\n\
1471 the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,\n\
1472 a STATE_CRITICAL will be returned.\n\n"));
1474         printf (_("\
1475 CHECK CERTIFICATE: check_http www.verisign.com -C 14\n\n\
1476 When the certificate of 'www.verisign.com' is valid for more than 14 days, a\n\
1477 STATE_OK is returned. When the certificate is still valid, but for less than\n\
1478 14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when\n\
1479 the certificate is expired.\n"));
1480 #endif
1482         printf (_(UT_SUPPORT));
1488 void
1489 print_usage (void)
1491         printf ("\
1492 Usage: %s -H <vhost> | -I <IP-address>) [-u <uri>] [-p <port>]\n\
1493                   [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\
1494                   [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\
1495                   [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\
1496                   [-P string] [-m min_pg_size] [-4|-6] [-N] [-M <age>]\n\
1497                   [-A string] [-k string]\n", progname);