Code

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