Code

reverting my changes from !=TRUE to == ERROR, that's not good ;-( sorry
[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                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
255                         print_usage ();
256                         exit (STATE_UNKNOWN);
257                         break;
258                 case 'h': /* help */
259                         print_help ();
260                         exit (STATE_OK);
261                         break;
262                 case 'V': /* version */
263                         print_revision (progname, revision);
264                         exit (STATE_OK);
265                         break;
266                 case 't': /* timeout period */
267                         if (!is_intnonneg (optarg))
268                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
269                         else
270                                 socket_timeout = atoi (optarg);
271                         break;
272                 case 'c': /* critical time threshold */
273                         if (!is_nonnegative (optarg))
274                                 usage2 (_("Critical threshold must be integer"), optarg);
275                         else {
276                                 critical_time = strtod (optarg, NULL);
277                                 check_critical_time = TRUE;
278                         }
279                         break;
280                 case 'w': /* warning time threshold */
281                         if (!is_nonnegative (optarg))
282                                 usage2 (_("Warning threshold must be integer"), optarg);
283                         else {
284                                 warning_time = strtod (optarg, NULL);
285                                 check_warning_time = TRUE;
286                         }
287                         break;
288                 case 'A': /* User Agent String */
289                         asprintf (&user_agent, "User-Agent: %s", optarg);
290                         break;
291                 case 'k': /* Additional headers */
292                         asprintf (&http_opt_headers, "%s", optarg);
293                         break;
294                 case 'L': /* show html link */
295                         display_html = TRUE;
296                         break;
297                 case 'n': /* do not show html link */
298                         display_html = FALSE;
299                         break;
300                 case 'S': /* use SSL */
301 #ifndef HAVE_SSL
302                         usage (_("check_http: invalid option - SSL is not available\n"));
303 #endif
304                         use_ssl = TRUE;
305                         if (specify_port == FALSE)
306                                 server_port = HTTPS_PORT;
307                         break;
308                 case 'C': /* Check SSL cert validity */
309 #ifdef HAVE_SSL
310                         if (!is_intnonneg (optarg))
311                                 usage2 (_("Invalid certificate expiration period"), optarg);
312                         else {
313                                 days_till_exp = atoi (optarg);
314                                 check_cert = TRUE;
315                         }
316 #else
317                         usage (_("Invalid option - SSL is not available\n"));
318 #endif
319                         break;
320                 case 'f': /* onredirect */
321                         if (!strcmp (optarg, "follow"))
322                                 onredirect = STATE_DEPENDENT;
323                         if (!strcmp (optarg, "unknown"))
324                                 onredirect = STATE_UNKNOWN;
325                         if (!strcmp (optarg, "ok"))
326                                 onredirect = STATE_OK;
327                         if (!strcmp (optarg, "warning"))
328                                 onredirect = STATE_WARNING;
329                         if (!strcmp (optarg, "critical"))
330                                 onredirect = STATE_CRITICAL;
331                         if (verbose)
332                                 printf(_("option f:%d \n"), onredirect);  
333                         break;
334                 /* Note: H, I, and u must be malloc'd or will fail on redirects */
335                 case 'H': /* Host Name (virtual host) */
336                         host_name = strdup (optarg);
337                         if (strstr (optarg, ":"))
338                                 sscanf (optarg, "%*[^:]:%d", &server_port);
339                         break;
340                 case 'I': /* Server IP-address */
341                         server_address = strdup (optarg);
342                         break;
343                 case 'u': /* URL path */
344                         server_url = strdup (optarg);
345                         server_url_length = strlen (server_url);
346                         break;
347                 case 'p': /* Server port */
348                         if (!is_intnonneg (optarg))
349                                 usage2 (_("Invalid port number"), optarg);
350                         else {
351                                 server_port = atoi (optarg);
352                                 specify_port = TRUE;
353                         }
354                         break;
355                 case 'a': /* authorization info */
356                         strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1);
357                         user_auth[MAX_INPUT_BUFFER - 1] = 0;
358                         break;
359                 case 'P': /* HTTP POST data in URL encoded format */
360                         if (http_method || http_post_data) break;
361                         http_method = strdup("POST");
362                         http_post_data = strdup (optarg);
363                         break;
364                 case 's': /* string or substring */
365                         strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1);
366                         string_expect[MAX_INPUT_BUFFER - 1] = 0;
367                         break;
368                 case 'e': /* string or substring */
369                         strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1);
370                         server_expect[MAX_INPUT_BUFFER - 1] = 0;
371                         server_expect_yn = 1;
372                         break;
373                 case 'T': /* Content-type */
374                         asprintf (&http_content_type, "%s", optarg);
375                         break;
376 #ifndef HAVE_REGEX_H
377                 case 'l': /* linespan */
378                 case 'r': /* linespan */
379                 case 'R': /* linespan */
380                         usage4 (_("Call for regex which was not a compiled option"));
381                         break;
382 #else
383                 case 'l': /* linespan */
384                         cflags &= ~REG_NEWLINE;
385                         break;
386                 case 'R': /* regex */
387                         cflags |= REG_ICASE;
388                 case 'r': /* regex */
389                         strncpy (regexp, optarg, MAX_RE_SIZE - 1);
390                         regexp[MAX_RE_SIZE - 1] = 0;
391                         errcode = regcomp (&preg, regexp, cflags);
392                         if (errcode != 0) {
393                                 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
394                                 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
395                                 return ERROR;
396                         }
397                         break;
398 #endif
399                 case '4':
400                         address_family = AF_INET;
401                         break;
402                 case '6':
403 #ifdef USE_IPV6
404                         address_family = AF_INET6;
405 #else
406                         usage4 (_("IPv6 support not available"));
407 #endif
408                         break;
409                 case 'v': /* verbose */
410                         verbose = TRUE;
411                         break;
412                 case 'm': /* min_page_length */
413                         min_page_len = atoi (optarg);
414                         break;
415                 case 'N': /* no-body */
416                         no_body = TRUE;
417                         break;
418                 case 'M': /* max-age */
419                   {
420                     int L = strlen(optarg);
421                     if (L && optarg[L-1] == 'm')
422                       maximum_age = atoi (optarg) * 60;
423                     else if (L && optarg[L-1] == 'h')
424                       maximum_age = atoi (optarg) * 60 * 60;
425                     else if (L && optarg[L-1] == 'd')
426                       maximum_age = atoi (optarg) * 60 * 60 * 24;
427                     else if (L && (optarg[L-1] == 's' ||
428                                    isdigit (optarg[L-1])))
429                       maximum_age = atoi (optarg);
430                     else {
431                       fprintf (stderr, "unparsable max-age: %s\n", optarg);
432                       exit (1);
433                     }
434                   }
435                   break;
436                 }
437         }
439         c = optind;
441         if (server_address == NULL && c < argc)
442                 server_address = strdup (argv[c++]);
444         if (host_name == NULL && c < argc)
445                 host_name = strdup (argv[c++]);
447         if (server_address == NULL) {
448                 if (host_name == NULL)
449                         usage4 (_("You must specify a server address or host name"));
450                 else
451                         server_address = strdup (host_name);
452         }
454         if (check_critical_time && critical_time>(double)socket_timeout)
455                 socket_timeout = (int)critical_time + 1;
457         if (http_method == NULL)
458                 http_method = strdup ("GET");
460         return TRUE;
465 /* written by lauri alanko */
466 static char *
467 base64 (const char *bin, size_t len)
470         char *buf = (char *) malloc ((len + 2) / 3 * 4 + 1);
471         size_t i = 0, j = 0;
473         char BASE64_END = '=';
474         char base64_table[64];
475         strncpy (base64_table, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 64);
477         while (j < len - 2) {
478                 buf[i++] = base64_table[bin[j] >> 2];
479                 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
480                 buf[i++] = base64_table[((bin[j + 1] & 15) << 2) | (bin[j + 2] >> 6)];
481                 buf[i++] = base64_table[bin[j + 2] & 63];
482                 j += 3;
483         }
485         switch (len - j) {
486         case 1:
487                 buf[i++] = base64_table[bin[j] >> 2];
488                 buf[i++] = base64_table[(bin[j] & 3) << 4];
489                 buf[i++] = BASE64_END;
490                 buf[i++] = BASE64_END;
491                 break;
492         case 2:
493                 buf[i++] = base64_table[bin[j] >> 2];
494                 buf[i++] = base64_table[((bin[j] & 3) << 4) | (bin[j + 1] >> 4)];
495                 buf[i++] = base64_table[(bin[j + 1] & 15) << 2];
496                 buf[i++] = BASE64_END;
497                 break;
498         case 0:
499                 break;
500         }
502         buf[i] = '\0';
503         return buf;
508 /* Returns 1 if we're done processing the document body; 0 to keep going */
509 static int
510 document_headers_done (char *full_page)
512         const char *body;
514         for (body = full_page; *body; body++) {
515                 if (!strncmp (body, "\n\n", 2) || !strncmp (body, "\n\r\n", 3))
516                         break;
517         }
519         if (!*body)
520                 return 0;  /* haven't read end of headers yet */
522         full_page[body - full_page] = 0;
523         return 1;
526 static time_t
527 parse_time_string (const char *string)
529         struct tm tm;
530         time_t t;
531         memset (&tm, 0, sizeof(tm));
533         /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
535         if (isupper (string[0])  &&  /* Tue */
536                 islower (string[1])  &&
537                 islower (string[2])  &&
538                 ',' ==   string[3]   &&
539                 ' ' ==   string[4]   &&
540                 (isdigit(string[5]) || string[5] == ' ') &&   /* 25 */
541                 isdigit (string[6])  &&
542                 ' ' ==   string[7]   &&
543                 isupper (string[8])  &&  /* Dec */
544                 islower (string[9])  &&
545                 islower (string[10]) &&
546                 ' ' ==   string[11]  &&
547                 isdigit (string[12]) &&  /* 2001 */
548                 isdigit (string[13]) &&
549                 isdigit (string[14]) &&
550                 isdigit (string[15]) &&
551                 ' ' ==   string[16]  &&
552                 isdigit (string[17]) &&  /* 02: */
553                 isdigit (string[18]) &&
554                 ':' ==   string[19]  &&
555                 isdigit (string[20]) &&  /* 59: */
556                 isdigit (string[21]) &&
557                 ':' ==   string[22]  &&
558                 isdigit (string[23]) &&  /* 03 */
559                 isdigit (string[24]) &&
560                 ' ' ==   string[25]  &&
561                 'G' ==   string[26]  &&  /* GMT */
562                 'M' ==   string[27]  &&  /* GMT */
563                 'T' ==   string[28]) {
565                 tm.tm_sec  = 10 * (string[23]-'0') + (string[24]-'0');
566                 tm.tm_min  = 10 * (string[20]-'0') + (string[21]-'0');
567                 tm.tm_hour = 10 * (string[17]-'0') + (string[18]-'0');
568                 tm.tm_mday = 10 * (string[5] == ' ' ? 0 : string[5]-'0') + (string[6]-'0');
569                 tm.tm_mon = (!strncmp (string+8, "Jan", 3) ? 0 :
570                         !strncmp (string+8, "Feb", 3) ? 1 :
571                         !strncmp (string+8, "Mar", 3) ? 2 :
572                         !strncmp (string+8, "Apr", 3) ? 3 :
573                         !strncmp (string+8, "May", 3) ? 4 :
574                         !strncmp (string+8, "Jun", 3) ? 5 :
575                         !strncmp (string+8, "Jul", 3) ? 6 :
576                         !strncmp (string+8, "Aug", 3) ? 7 :
577                         !strncmp (string+8, "Sep", 3) ? 8 :
578                         !strncmp (string+8, "Oct", 3) ? 9 :
579                         !strncmp (string+8, "Nov", 3) ? 10 :
580                         !strncmp (string+8, "Dec", 3) ? 11 :
581                         -1);
582                 tm.tm_year = ((1000 * (string[12]-'0') +
583                         100 * (string[13]-'0') +
584                         10 * (string[14]-'0') +
585                         (string[15]-'0'))
586                         - 1900);
588                 tm.tm_isdst = 0;  /* GMT is never in DST, right? */
590                 if (tm.tm_mon < 0 || tm.tm_mday < 1 || tm.tm_mday > 31)
591                         return 0;
593                 /* 
594                 This is actually wrong: we need to subtract the local timezone
595                 offset from GMT from this value.  But, that's ok in this usage,
596                 because we only comparing these two GMT dates against each other,
597                 so it doesn't matter what time zone we parse them in.
598                 */
600                 t = mktime (&tm);
601                 if (t == (time_t) -1) t = 0;
603                 if (verbose) {
604                         const char *s = string;
605                         while (*s && *s != '\r' && *s != '\n')
606                         fputc (*s++, stdout);
607                         printf (" ==> %lu\n", (unsigned long) t);
608                 }
610                 return t;
612         } else {
613                 return 0;
614         }
619 static void
620 check_document_dates (const char *headers)
622         const char *s;
623         char *server_date = 0;
624         char *document_date = 0;
626         s = headers;
627         while (*s) {
628                 const char *field = s;
629                 const char *value = 0;
631                 /* Find the end of the header field */
632                 while (*s && !isspace(*s) && *s != ':')
633                         s++;
635                 /* Remember the header value, if any. */
636                 if (*s == ':')
637                         value = ++s;
639                 /* Skip to the end of the header, including continuation lines. */
640                 while (*s && !(*s == '\n' && (s[1] != ' ' && s[1] != '\t')))
641                         s++;
642                 s++;
644                 /* Process this header. */
645                 if (value && value > field+2) {
646                         char *ff = (char *) malloc (value-field);
647                         char *ss = ff;
648                         while (field < value-1)
649                                 *ss++ = tolower(*field++);
650                         *ss++ = 0;
652                         if (!strcmp (ff, "date") || !strcmp (ff, "last-modified")) {
653                                 const char *e;
654                                 while (*value && isspace (*value))
655                                         value++;
656                                 for (e = value; *e && *e != '\r' && *e != '\n'; e++)
657                                         ;
658                                 ss = (char *) malloc (e - value + 1);
659                                 strncpy (ss, value, e - value);
660                                 ss[e - value] = 0;
661                                 if (!strcmp (ff, "date")) {
662                                         if (server_date) free (server_date);
663                                         server_date = ss;
664                                 } else {
665                                         if (document_date) free (document_date);
666                                         document_date = ss;
667                                 }
668                         }
669                         free (ff);
670                 }
671         }
673         /* Done parsing the body.  Now check the dates we (hopefully) parsed.  */
674         if (!server_date || !*server_date) {
675                 die (STATE_UNKNOWN, _("Server date unknown\n"));
676         } else if (!document_date || !*document_date) {
677                 die (STATE_CRITICAL, _("Document modification date unknown\n"));
678         } else {
679                 time_t sd = parse_time_string (server_date);
680                 time_t dd = parse_time_string (document_date);
682                 if (sd <= 0) {
683                         die (STATE_CRITICAL, _("CRITICAL - Server date \"%100s\" unparsable"), server_date);
684                 } else if (dd <= 0) {
685                         die (STATE_CRITICAL, _("CRITICAL - Document date \"%100s\" unparsable"), document_date);
686                 } else if (dd > sd + 30) {
687                         die (STATE_CRITICAL, _("CRITICAL - Document is %d seconds in the future\n"), dd - sd);
688                 } else if (dd < sd - maximum_age) {
689                 int n = (sd - dd);
690                 if (n > (60 * 60 * 24 * 2))
691                         die (STATE_CRITICAL,
692                           _("CRITICAL - Last modified %.1f days ago\n"),
693                           ((float) n) / (60 * 60 * 24));
694         else
695                 die (STATE_CRITICAL,
696                     _("CRITICAL - Last modified %d:%02d:%02d ago\n"),
697                     n / (60 * 60), (n / 60) % 60, n % 60);
698     }
700     free (server_date);
701     free (document_date);
702   }
707 int
708 check_http (void)
710         char *msg;
711         char *status_line;
712         char *status_code;
713         char *header;
714         char *page;
715         char *auth;
716         int http_status;
717         int i = 0;
718         size_t pagesize = 0;
719         char *full_page;
720         char *buf;
721         char *pos;
722         long microsec;
723         double elapsed_time;
724         int page_len = 0;
725 #ifdef HAVE_SSL
726         int sslerr;
727 #endif
729         /* try to connect to the host at the given port number */
730 #ifdef HAVE_SSL
731         if (use_ssl == TRUE) {
733                 if (connect_SSL () != OK) {
734                         die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
735                 }
737                 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
738                         X509_free (server_cert);
739                 }
740                 else {
741                         printf (_("CRITICAL - Cannot retrieve server certificate.\n"));
742                         return STATE_CRITICAL;
743                 }
745         }
746         else {
747 #endif
748                 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK)
749                         die (STATE_CRITICAL, _("Unable to open TCP socket\n"));
750 #ifdef HAVE_SSL
751         }
752 #endif
754         asprintf (&buf, "%s %s HTTP/1.0\r\n%s\r\n", http_method, server_url, user_agent);
756         /* optionally send the host header info */
757         if (host_name)
758                 asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
760         /* optionally send any other header tag */
761         if (http_opt_headers) {
762                 for ((pos = strtok(http_opt_headers, INPUT_DELIMITER)); pos; (pos = strtok(NULL, INPUT_DELIMITER)))
763                         asprintf (&buf, "%s%s\r\n", buf, pos);
764         }
766         /* optionally send the authentication info */
767         if (strlen(user_auth)) {
768                 auth = base64 (user_auth, strlen (user_auth));
769                 asprintf (&buf, "%sAuthorization: Basic %s\r\n", buf, auth);
770         }
772         /* either send http POST data */
773         if (http_post_data) {
774                 if (http_content_type) {
775                         asprintf (&buf, "%sContent-Type: %s\r\n", buf, http_content_type);
776                 } else {
777                         asprintf (&buf, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf);
778                 }
779                 asprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, strlen (http_post_data));
780                 asprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
781         }
782         else {
783                 /* or just a newline so the server knows we're done with the request */
784                 asprintf (&buf, "%s%s", buf, CRLF);
785         }
787         if (verbose)
788                 printf ("%s\n", buf);
790 #ifdef HAVE_SSL
791         if (use_ssl == TRUE) {
792                 if (SSL_write (ssl, buf, (int)strlen(buf)) == -1) {
793                         ERR_print_errors_fp (stderr);
794                         return STATE_CRITICAL;
795                 }
796         }
797         else {
798 #endif
799                 send (sd, buf, strlen (buf), 0);
800 #ifdef HAVE_SSL
801         }
802 #endif
804         /* fetch the page */
805         full_page = strdup("");
806         while ((i = my_recv ()) > 0) {
807                 buffer[i] = '\0';
808                 asprintf (&full_page, "%s%s", full_page, buffer);
809                 pagesize += i;
811                 if (no_body && document_headers_done (full_page)) {
812                   i = 0;
813                   break;
814                 }
815         }
817         if (i < 0 && errno != ECONNRESET) {
818 #ifdef HAVE_SSL
819                 if (use_ssl) {
820                         sslerr=SSL_get_error(ssl, i);
821                         if ( sslerr == SSL_ERROR_SSL ) {
822                                 die (STATE_WARNING, _("Client Certificate Required\n"));
823                         } else {
824                                 die (STATE_CRITICAL, _("Error on receive\n"));
825                         }
826                 }
827                 else {
828 #endif
829                         die (STATE_CRITICAL, _("Error on receive\n"));
830 #ifdef HAVE_SSL
831                 }
832 #endif
833         }
835         /* return a CRITICAL status if we couldn't read any data */
836         if (pagesize == (size_t) 0)
837                 die (STATE_CRITICAL, _("No data received %s\n"), timestamp);
839         /* close the connection */
840         my_close ();
842         /* reset the alarm */
843         alarm (0);
845         /* leave full_page untouched so we can free it later */
846         page = full_page;
848         if (verbose)
849                 printf ("%s://%s:%d%s is %d characters\n",
850                         use_ssl ? "https" : "http", server_address,
851                         server_port, server_url, pagesize);
853         /* find status line and null-terminate it */
854         status_line = page;
855         page += (size_t) strcspn (page, "\r\n");
856         pos = page;
857         page += (size_t) strspn (page, "\r\n");
858         status_line[strcspn(status_line, "\r\n")] = 0;
859         strip (status_line);
860         if (verbose)
861                 printf ("STATUS: %s\n", status_line);
863         /* find header info and null-terminate it */
864         header = page;
865         while (strcspn (page, "\r\n") > 0) {
866                 page += (size_t) strcspn (page, "\r\n");
867                 pos = page;
868                 if ((strspn (page, "\r") == 1 && strspn (page, "\r\n") >= 2) ||
869                     (strspn (page, "\n") == 1 && strspn (page, "\r\n") >= 2))
870                         page += (size_t) 2;
871                 else
872                         page += (size_t) 1;
873         }
874         page += (size_t) strspn (page, "\r\n");
875         header[pos - header] = 0;
876         if (verbose)
877                 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
878                 (no_body ? "  [[ skipped ]]" : page));
880         /* make sure the status line matches the response we are looking for */
881         if (!strstr (status_line, server_expect)) {
882                 if (server_port == HTTP_PORT)
883                         asprintf (&msg,
884                             _("Invalid HTTP response received from host\n"));
885                 else
886                         asprintf (&msg,
887                                   _("Invalid HTTP response received from host on port %d\n"),
888                                   server_port);
889                 die (STATE_CRITICAL, "%s", msg);
890         }
892         /* Exit here if server_expect was set by user and not default */
893         if ( server_expect_yn  )  {
894                 asprintf (&msg,
895                           _("HTTP OK: Status line output matched \"%s\"\n"),
896                           server_expect);
897                 if (verbose)
898                         printf ("%s\n",msg);
899         }
900         else {
901                 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
902                 /* HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
903     /* Status-Code = 3 DIGITS */
905                 status_code = strchr (status_line, ' ') + sizeof (char);
906                 if (strspn (status_code, "1234567890") != 3)
907                         die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
909                 http_status = atoi (status_code);
911                 /* check the return code */
913                 if (http_status >= 600 || http_status < 100)
914                         die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line);
916                 /* server errors result in a critical state */
917                 else if (http_status >= 500)
918                         die (STATE_CRITICAL, _("HTTP CRITICAL: %s\n"), status_line);
920                 /* client errors result in a warning state */
921                 else if (http_status >= 400)
922                         die (STATE_WARNING, _("HTTP WARNING: %s\n"), status_line);
924                 /* check redirected page if specified */
925                 else if (http_status >= 300) {
927                         if (onredirect == STATE_DEPENDENT)
928                                 redir (header, status_line);
929                         else if (onredirect == STATE_UNKNOWN)
930                                 printf (_("UNKNOWN"));
931                         else if (onredirect == STATE_OK)
932                                 printf (_("OK"));
933                         else if (onredirect == STATE_WARNING)
934                                 printf (_("WARNING"));
935                         else if (onredirect == STATE_CRITICAL)
936                                 printf (_("CRITICAL"));
937                         microsec = deltime (tv);
938                         elapsed_time = (double)microsec / 1.0e6;
939                         die (onredirect,
940                              _(" - %s - %.3f second response time %s%s|%s %s\n"),
941                              status_line, elapsed_time, timestamp,
942                              (display_html ? "</A>" : ""),
943                                          perfd_time (elapsed_time), perfd_size (pagesize));
944                 } /* end if (http_status >= 300) */
946         } /* end else (server_expect_yn)  */
947                 
948         if (maximum_age >= 0) {
949           check_document_dates (header);
950         }
952         /* check elapsed time */
953         microsec = deltime (tv);
954         elapsed_time = (double)microsec / 1.0e6;
955         asprintf (&msg,
956                   _("HTTP WARNING: %s - %.3f second response time %s%s|%s %s\n"),
957                   status_line, elapsed_time, timestamp,
958                   (display_html ? "</A>" : ""),
959                                                 perfd_time (elapsed_time), perfd_size (pagesize));
960         if (check_critical_time == TRUE && elapsed_time > critical_time)
961                 die (STATE_CRITICAL, "%s", msg);
962         if (check_warning_time == TRUE && elapsed_time > warning_time)
963                 die (STATE_WARNING, "%s", msg);
965         /* Page and Header content checks go here */
966         /* these checks should be last */
968         if (strlen (string_expect)) {
969                 if (strstr (page, string_expect)) {
970                         printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
971                                 status_line, elapsed_time,
972                                 timestamp, (display_html ? "</A>" : ""),
973                                 perfd_time (elapsed_time), perfd_size (pagesize));
974                         exit (STATE_OK);
975                 }
976                 else {
977                         printf (_("CRITICAL - string not found%s|%s %s\n"),
978                                 (display_html ? "</A>" : ""),
979                                 perfd_time (elapsed_time), perfd_size (pagesize));
980                         exit (STATE_CRITICAL);
981                 }
982         }
983 #ifdef HAVE_REGEX_H
984         if (strlen (regexp)) {
985                 errcode = regexec (&preg, page, REGS, pmatch, 0);
986                 if (errcode == 0) {
987                         printf (_("HTTP OK %s - %.3f second response time %s%s|%s %s\n"),
988                                 status_line, elapsed_time,
989                                 timestamp, (display_html ? "</A>" : ""),
990                                 perfd_time (elapsed_time), perfd_size (pagesize));
991                         exit (STATE_OK);
992                 }
993                 else {
994                         if (errcode == REG_NOMATCH) {
995                                 printf (_("CRITICAL - pattern not found%s|%s %s\n"),
996                                         (display_html ? "</A>" : ""),
997                                         perfd_time (elapsed_time), perfd_size (pagesize));
998                                 exit (STATE_CRITICAL);
999                         }
1000                         else {
1001                                 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1002                                 printf (_("CRITICAL - Execute Error: %s\n"), errbuf);
1003                                 exit (STATE_CRITICAL);
1004                         }
1005                 }
1006         }
1007 #endif
1009         /* make sure the page is of an appropriate size */
1010         page_len = strlen (page);
1011         if ((min_page_len > 0) && (page_len < min_page_len)) {
1012                 printf (_("HTTP WARNING: page size %d too small%s|%s\n"),
1013                         page_len, (display_html ? "</A>" : ""), perfd_size (page_len) );
1014                 exit (STATE_WARNING);
1015         }
1016         /* We only get here if all tests have been passed */
1017         asprintf (&msg, _("HTTP OK %s - %d bytes in %.3f seconds %s%s|%s %s\n"),
1018                   status_line, page_len, elapsed_time,
1019                   timestamp, (display_html ? "</A>" : ""),
1020                                                 perfd_time (elapsed_time), perfd_size (page_len));
1021         die (STATE_OK, "%s", msg);
1022         return STATE_UNKNOWN;
1027 /* per RFC 2396 */
1028 #define HDR_LOCATION "%*[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]: "
1029 #define URI_HTTP "%[HTPShtps]://"
1030 #define URI_HOST "%[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1031 #define URI_PORT ":%[0123456789]"
1032 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1033 #define HD1 URI_HTTP URI_HOST URI_PORT URI_PATH
1034 #define HD2 URI_HTTP URI_HOST URI_PATH
1035 #define HD3 URI_HTTP URI_HOST URI_PORT
1036 #define HD4 URI_HTTP URI_HOST
1037 #define HD5 URI_PATH
1039 void
1040 redir (char *pos, char *status_line)
1042         int i = 0;
1043         char *x;
1044         char xx[2];
1045         char type[6];
1046         char *addr;
1047         char port[6];
1048         char *url;
1050         addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
1051         if (addr == NULL)
1052                 die (STATE_UNKNOWN, _("Could not allocate addr\n"));
1053         
1054         url = malloc (strcspn (pos, "\r\n"));
1055         if (url == NULL)
1056                 die (STATE_UNKNOWN, _("Could not allocate url\n"));
1058         while (pos) {
1060                 if (sscanf (pos, "%[Ll]%*[Oo]%*[Cc]%*[Aa]%*[Tt]%*[Ii]%*[Oo]%*[Nn]:%n", xx, &i) < 1) {
1062                         pos += (size_t) strcspn (pos, "\r\n");
1063                         pos += (size_t) strspn (pos, "\r\n");
1064                         if (strlen(pos) == 0) 
1065                                 die (STATE_UNKNOWN,
1066                                                  _("UNKNOWN - Could not find redirect location - %s%s\n"),
1067                                                  status_line, (display_html ? "</A>" : ""));
1068                         continue;
1069                 }
1071                 pos += i;
1072                 pos += strspn (pos, " \t\r\n");
1074                 url = realloc (url, strcspn (pos, "\r\n"));
1075                 if (url == NULL)
1076                         die (STATE_UNKNOWN, _("could not allocate url\n"));
1078                 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1079                 if (sscanf (pos, HD1, type, addr, port, url) == 4) {
1080                         use_ssl = server_type_check (type);
1081                         i = atoi (port);
1082                 }
1084                 /* URI_HTTP URI_HOST URI_PATH */
1085                 else if (sscanf (pos, HD2, type, addr, url) == 3 ) { 
1086                         use_ssl = server_type_check (type);
1087                         i = server_port_check (use_ssl);
1088                 }
1090                 /* URI_HTTP URI_HOST URI_PORT */
1091                 else if(sscanf (pos, HD3, type, addr, port) == 3) {
1092                         strcpy (url, HTTP_URL);
1093                         use_ssl = server_type_check (type);
1094                         i = atoi (port);
1095                 }
1097                 /* URI_HTTP URI_HOST */
1098                 else if(sscanf (pos, HD4, type, addr) == 2) {
1099                         strcpy (url, HTTP_URL);
1100                         use_ssl = server_type_check (type);
1101                         i = server_port_check (use_ssl);
1102                 }
1104                 /* URI_PATH */
1105                 else if (sscanf (pos, HD5, url) == 1) {
1106                         /* relative url */
1107                         if ((url[0] != '/')) {
1108                                 if ((x = strrchr(server_url, '/')))
1109                                         *x = '\0';
1110                                 asprintf (&url, "%s/%s", server_url, url);
1111                         }
1112                         i = server_port;
1113                         strcpy (type, server_type);
1114                         strcpy (addr, host_name);
1115                 }                                       
1117                 else {
1118                         die (STATE_UNKNOWN,
1119                                          _("UNKNOWN - Could not parse redirect location - %s%s\n"),
1120                                          pos, (display_html ? "</A>" : ""));
1121                 }
1123                 break;
1125         } /* end while (pos) */
1127         if (++redir_depth > max_depth)
1128                 die (STATE_WARNING,
1129                      _("WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1130                      max_depth, type, addr, i, url, (display_html ? "</A>" : ""));
1132         if (server_port==i &&
1133             !strcmp(server_address, addr) &&
1134             (host_name && !strcmp(host_name, addr)) &&
1135             !strcmp(server_url, url))
1136                 die (STATE_WARNING,
1137                      _("WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1138                      type, addr, i, url, (display_html ? "</A>" : ""));
1140         server_port = i;
1141         strcpy (server_type, type);
1143         free (host_name);
1144         host_name = strdup (addr);
1146         free (server_address);
1147         server_address = strdup (addr);
1149         free (server_url);
1150         server_url = strdup (url);
1152         check_http ();
1157 int
1158 server_type_check (const char *type)
1160         if (strcmp (type, "https"))
1161                 return FALSE;
1162         else
1163                 return TRUE;
1166 int
1167 server_port_check (int ssl_flag)
1169         if (ssl_flag)
1170                 return HTTPS_PORT;
1171         else
1172                 return HTTP_PORT;
1177 #ifdef HAVE_SSL
1178 int connect_SSL (void)
1180         SSL_METHOD *meth;
1182         asprintf (&randbuff, "%s", "qwertyuiopasdfghjklqwertyuiopasdfghjkl");
1183         RAND_seed (randbuff, (int)strlen(randbuff));
1184         if (verbose)
1185                 printf(_("SSL seeding: %s\n"), (RAND_status()==1 ? _("OK") : _("Failed")) );
1187         /* Initialize SSL context */
1188         SSLeay_add_ssl_algorithms ();
1189         meth = SSLv23_client_method ();
1190         SSL_load_error_strings ();
1191         if ((ctx = SSL_CTX_new (meth)) == NULL) {
1192                 printf (_("CRITICAL -  Cannot create SSL context.\n"));
1193                 return STATE_CRITICAL;
1194         }
1196         /* Initialize alarm signal handling */
1197         signal (SIGALRM, socket_timeout_alarm_handler);
1199         /* Set socket timeout */
1200         alarm (socket_timeout);
1202         /* Save start time */
1203         gettimeofday (&tv, NULL);
1205         /* Make TCP connection */
1206         if (my_tcp_connect (server_address, server_port, &sd) == STATE_OK) {
1207                 /* Do the SSL handshake */
1208                 if ((ssl = SSL_new (ctx)) != NULL) {
1209                         SSL_set_cipher_list(ssl, "ALL");
1210                         SSL_set_fd (ssl, sd);
1211                         if (SSL_connect (ssl) != -1)
1212                                 return OK;
1213                         ERR_print_errors_fp (stderr);
1214                 }
1215                 else {
1216                         printf (_("CRITICAL - Cannot initiate SSL handshake.\n"));
1217                 }
1218                 SSL_free (ssl);
1219         }
1221         SSL_CTX_free (ctx);
1222         close (sd);
1224         return STATE_CRITICAL;
1226 #endif
1230 #ifdef HAVE_SSL
1231 int
1232 check_certificate (X509 ** certificate)
1234         ASN1_STRING *tm;
1235         int offset;
1236         struct tm stamp;
1237         int days_left;
1240         /* Retrieve timestamp of certificate */
1241         tm = X509_get_notAfter (*certificate);
1243         /* Generate tm structure to process timestamp */
1244         if (tm->type == V_ASN1_UTCTIME) {
1245                 if (tm->length < 10) {
1246                         printf (_("CRITICAL - Wrong time format in certificate.\n"));
1247                         return STATE_CRITICAL;
1248                 }
1249                 else {
1250                         stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
1251                         if (stamp.tm_year < 50)
1252                                 stamp.tm_year += 100;
1253                         offset = 0;
1254                 }
1255         }
1256         else {
1257                 if (tm->length < 12) {
1258                         printf (_("CRITICAL - Wrong time format in certificate.\n"));
1259                         return STATE_CRITICAL;
1260                 }
1261                 else {
1262                         stamp.tm_year =
1263                                 (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
1264                                 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
1265                         stamp.tm_year -= 1900;
1266                         offset = 2;
1267                 }
1268         }
1269         stamp.tm_mon =
1270                 (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
1271         stamp.tm_mday =
1272                 (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
1273         stamp.tm_hour =
1274                 (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
1275         stamp.tm_min =
1276                 (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
1277         stamp.tm_sec = 0;
1278         stamp.tm_isdst = -1;
1280         days_left = (mktime (&stamp) - time (NULL)) / 86400;
1281         snprintf
1282                 (timestamp, 17, "%02d/%02d/%04d %02d:%02d",
1283                  stamp.tm_mon + 1,
1284                  stamp.tm_mday, stamp.tm_year + 1900, stamp.tm_hour, stamp.tm_min);
1286         if (days_left > 0 && days_left <= days_till_exp) {
1287                 printf (_("WARNING - Certificate expires in %d day(s) (%s).\n"), days_left, timestamp);
1288                 return STATE_WARNING;
1289         }
1290         if (days_left < 0) {
1291                 printf (_("CRITICAL - Certificate expired on %s.\n"), timestamp);
1292                 return STATE_CRITICAL;
1293         }
1295         if (days_left == 0) {
1296                 printf (_("WARNING - Certificate expires today (%s).\n"), timestamp);
1297                 return STATE_WARNING;
1298         }
1300         printf (_("OK - Certificate will expire on %s.\n"), timestamp);
1302         return STATE_OK;
1304 #endif
1308 char *perfd_time (double elapsed_time)
1310         return fperfdata ("time", elapsed_time, "s",
1311                   check_warning_time, warning_time,
1312                   check_critical_time, critical_time,
1313                                                                          TRUE, 0, FALSE, 0);
1318 char *perfd_size (int page_len)
1320         return perfdata ("size", page_len, "B",
1321                   (min_page_len>0?TRUE:FALSE), min_page_len,
1322                   (min_page_len>0?TRUE:FALSE), 0,
1323                   TRUE, 0, FALSE, 0);
1328 int
1329 my_recv (void)
1331         int i;
1332 #ifdef HAVE_SSL
1333         if (use_ssl) {
1334                 i = SSL_read (ssl, buffer, MAX_INPUT_BUFFER - 1);
1335         }
1336         else {
1337                 i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1338         }
1339 #else
1340         i = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0);
1341 #endif
1342         return i;
1347 int
1348 my_close (void)
1350 #ifdef HAVE_SSL
1351         if (use_ssl == TRUE) {
1352                 SSL_shutdown (ssl);
1353                 SSL_free (ssl);
1354                 SSL_CTX_free (ctx);
1355                 return 0;
1356         }
1357         else {
1358 #endif
1359                 return close (sd);
1360 #ifdef HAVE_SSL
1361         }
1362 #endif
1367 void
1368 print_help (void)
1370         print_revision (progname, revision);
1372         printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1373         printf (COPYRIGHT, copyright, email);
1375         printf (_("\
1376 This plugin tests the HTTP service on the specified host. It can test\n\
1377 normal (http) and secure (https) servers, follow redirects, search for\n\
1378 strings and regular expressions, check connection times, and report on\n\
1379 certificate expiration times.\n\n"));
1381         print_usage ();
1383         printf (_("NOTE: One or both of -H and -I must be specified\n"));
1385         printf (_(UT_HELP_VRSN));
1387         printf (_("\
1388  -H, --hostname=ADDRESS\n\
1389     Host name argument for servers using host headers (virtual host)\n\
1390     Append a port to include it in the header (eg: example.com:5000)\n\
1391  -I, --IP-address=ADDRESS\n\
1392    IP address or name (use numeric address if possible to bypass DNS lookup).\n\
1393  -p, --port=INTEGER\n\
1394    Port number (default: %d)\n"), HTTP_PORT);
1396         printf (_(UT_IPv46));
1398 #ifdef HAVE_SSL
1399         printf (_("\
1400  -S, --ssl\n\
1401     Connect via SSL\n\
1402  -C, --certificate=INTEGER\n\
1403     Minimum number of days a certificate has to be valid.\n\
1404     (when this option is used the url is not checked.)\n"));
1405 #endif
1407         printf (_("\
1408  -e, --expect=STRING\n\
1409    String to expect in first (status) line of server response (default: %s)\n\
1410    If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)\n\
1411  -s, --string=STRING\n\
1412    String to expect in the content\n\
1413  -u, --url=PATH\n\
1414    URL to GET or POST (default: /)\n\
1415  -P, --post=STRING\n\
1416    URL encoded http POST data\n\
1417  -N, --no-body\n\
1418    Don't wait for document body: stop reading after headers.\n\
1419    (Note that this still does an HTTP GET or POST, not a HEAD.)\n\
1420  -M, --max-age=SECONDS\n\
1421    Warn if document is more than SECONDS old. the number can also be of \n\
1422    the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.\n\
1423  -T, --content-type=STRING\n\
1424    specify Content-Type header media type when POSTing\n"), HTTP_EXPECT);
1426 #ifdef HAVE_REGEX_H
1427         printf (_("\
1428  -l, --linespan\n\
1429     Allow regex to span newlines (must precede -r or -R)\n\
1430  -r, --regex, --ereg=STRING\n\
1431     Search page for regex STRING\n\
1432  -R, --eregi=STRING\n\
1433     Search page for case-insensitive regex STRING\n"));
1434 #endif
1436         printf (_("\
1437  -a, --authorization=AUTH_PAIR\n\
1438    Username:password on sites with basic authentication\n\
1439  -A, --useragent=STRING\n\
1440    String to be sent in http header as \"User Agent\"\n\
1441  -k, --header=STRING\n\
1442    Any other tags to be sent in http header, separated by semicolon\n\
1443  -L, --link=URL\n\
1444    Wrap output in HTML link (obsoleted by urlize)\n\
1445  -f, --onredirect=<ok|warning|critical|follow>\n\
1446    How to handle redirected pages\n\
1447  -m, --min=INTEGER\n\
1448    Minimum page size required (bytes)\n"));
1450         printf (_(UT_WARN_CRIT));
1452         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
1454         printf (_(UT_VERBOSE));
1456                                         printf (_("\
1457 This plugin will attempt to open an HTTP connection with the host. Successful\n\
1458 connects return STATE_OK, refusals and timeouts return STATE_CRITICAL, other\n\
1459 errors return STATE_UNKNOWN.  Successful connects, but incorrect reponse\n\
1460 messages from the host result in STATE_WARNING return values.  If you are\n\
1461 checking a virtual server that uses 'host headers' you must supply the FQDN\n\
1462 (fully qualified domain name) as the [host_name] argument.\n"));
1464 #ifdef HAVE_SSL
1465         printf (_("\n\
1466 This plugin can also check whether an SSL enabled web server is able to\n\
1467 serve content (optionally within a specified time) or whether the X509 \n\
1468 certificate is still valid for the specified number of days.\n"));
1469         printf (_("\n\
1470 CHECK CONTENT: check_http -w 5 -c 10 --ssl www.verisign.com\n\n\
1471 When the 'www.verisign.com' server returns its content within 5 seconds, a\n\
1472 STATE_OK will be returned. When the server returns its content but exceeds\n\
1473 the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,\n\
1474 a STATE_CRITICAL will be returned.\n\n"));
1476         printf (_("\
1477 CHECK CERTIFICATE: check_http www.verisign.com -C 14\n\n\
1478 When the certificate of 'www.verisign.com' is valid for more than 14 days, a\n\
1479 STATE_OK is returned. When the certificate is still valid, but for less than\n\
1480 14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when\n\
1481 the certificate is expired.\n"));
1482 #endif
1484         printf (_(UT_SUPPORT));
1490 void
1491 print_usage (void)
1493         printf (_("\
1494 Usage: %s -H <vhost> | -I <IP-address>) [-u <uri>] [-p <port>]\n\
1495                   [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L]\n\
1496                   [-a auth] [-f <ok | warn | critcal | follow>] [-e <expect>]\n\
1497                   [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n\
1498                   [-P string] [-m min_pg_size] [-4|-6] [-N] [-M <age>]\n\
1499                                                                         [-A string] [-k string]\n"), progname);