Code

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