Code

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