1 /*****************************************************************************
3 * Nagios check_http plugin
6 * Copyright (c) 1999-2013 Nagios Plugins Development Team
10 * This file contains the check_http plugin
12 * This plugin tests the HTTP service on the specified host. It can test
13 * normal (http) and secure (https) servers, follow redirects, search for
14 * strings and regular expressions, check connection times, and report on
15 * certificate expiration times.
18 * This program is free software: you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation, either version 3 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 *****************************************************************************/
34 /* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
36 const char *progname
= "check_http";
37 const char *copyright
= "1999-2013";
38 const char *email
= "nagiosplug-devel@lists.sourceforge.net";
50 #define HTTP_EXPECT "HTTP/1."
52 MAX_IPV4_HOSTLENGTH
= 255,
59 int check_cert
= FALSE
;
61 int days_till_exp_warn
, days_till_exp_crit
;
64 # define my_recv(buf, len) ((use_ssl) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
65 # define my_send(buf, len) ((use_ssl) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
66 #else /* ifndef HAVE_SSL */
67 # define my_recv(buf, len) read(sd, buf, len)
68 # define my_send(buf, len) send(sd, buf, len, 0)
79 regmatch_t pmatch
[REGS
];
80 char regexp
[MAX_RE_SIZE
];
81 char errbuf
[MAX_INPUT_BUFFER
];
82 int cflags
= REG_NOSUB
| REG_EXTENDED
| REG_NEWLINE
;
87 struct timeval tv_temp
;
92 int specify_port
= FALSE
;
93 int server_port
= HTTP_PORT
;
94 char server_port_text
[6] = "";
95 char server_type
[6] = "http";
100 int server_url_length
;
101 int server_expect_yn
= 0;
102 char server_expect
[MAX_INPUT_BUFFER
] = HTTP_EXPECT
;
103 char header_expect
[MAX_INPUT_BUFFER
] = "";
104 char string_expect
[MAX_INPUT_BUFFER
] = "";
105 char output_header_search
[30] = "";
106 char output_string_search
[30] = "";
107 char *warning_thresholds
= NULL
;
108 char *critical_thresholds
= NULL
;
110 char user_auth
[MAX_INPUT_BUFFER
] = "";
111 char proxy_auth
[MAX_INPUT_BUFFER
] = "";
112 int display_html
= FALSE
;
113 char **http_opt_headers
;
114 int http_opt_headers_count
= 0;
115 int onredirect
= STATE_OK
;
116 int followsticky
= STICKY_NONE
;
120 int show_extended_perfdata
= FALSE
;
122 int min_page_len
= 0;
123 int max_page_len
= 0;
127 char *http_post_data
;
128 char *http_content_type
;
129 char buffer
[MAX_INPUT_BUFFER
];
130 char *client_cert
= NULL
;
131 char *client_privkey
= NULL
;
133 int process_arguments (int, char **);
134 int check_http (void);
135 void redir (char *pos
, char *status_line
);
136 int server_type_check(const char *type
);
137 int server_port_check(int ssl_flag
);
138 char *perfd_time (double microsec
);
139 char *perfd_time_connect (double microsec
);
140 char *perfd_time_ssl (double microsec
);
141 char *perfd_time_firstbyte (double microsec
);
142 char *perfd_time_headers (double microsec
);
143 char *perfd_time_transfer (double microsec
);
144 char *perfd_size (int page_len
);
145 void print_help (void);
146 void print_usage (void);
149 main (int argc
, char **argv
)
151 int result
= STATE_UNKNOWN
;
153 setlocale (LC_ALL
, "");
154 bindtextdomain (PACKAGE
, LOCALEDIR
);
155 textdomain (PACKAGE
);
157 /* Set default URL. Must be malloced for subsequent realloc if --onredirect=follow */
158 server_url
= strdup(HTTP_URL
);
159 server_url_length
= strlen(server_url
);
160 xasprintf (&user_agent
, "User-Agent: check_http/v%s (nagios-plugins %s)",
161 NP_VERSION
, VERSION
);
163 /* Parse extra opts if any */
164 argv
=np_extra_opts (&argc
, argv
, progname
);
166 if (process_arguments (argc
, argv
) == ERROR
)
167 usage4 (_("Could not parse arguments"));
169 if (display_html
== TRUE
)
170 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
171 use_ssl
? "https" : "http", host_name
? host_name
: server_address
,
172 server_port
, server_url
);
174 /* initialize alarm signal handling, set socket timeout, start timer */
175 (void) signal (SIGALRM
, socket_timeout_alarm_handler
);
176 (void) alarm (socket_timeout
);
177 gettimeofday (&tv
, NULL
);
179 result
= check_http ();
183 /* check whether a file exists */
185 test_file (char *path
)
187 if (access(path
, R_OK
) == 0)
189 usage2 (_("file does not exist or is not readable"), path
);
192 /* process command-line arguments */
194 process_arguments (int argc
, char **argv
)
201 INVERT_REGEX
= CHAR_MAX
+ 1,
206 static struct option longopts
[] = {
208 {"link", no_argument
, 0, 'L'},
209 {"nohtml", no_argument
, 0, 'n'},
210 {"ssl", optional_argument
, 0, 'S'},
211 {"sni", no_argument
, 0, SNI_OPTION
},
212 {"post", required_argument
, 0, 'P'},
213 {"method", required_argument
, 0, 'j'},
214 {"IP-address", required_argument
, 0, 'I'},
215 {"url", required_argument
, 0, 'u'},
216 {"port", required_argument
, 0, 'p'},
217 {"authorization", required_argument
, 0, 'a'},
218 {"proxy-authorization", required_argument
, 0, 'b'},
219 {"header-string", required_argument
, 0, 'd'},
220 {"string", required_argument
, 0, 's'},
221 {"expect", required_argument
, 0, 'e'},
222 {"regex", required_argument
, 0, 'r'},
223 {"ereg", required_argument
, 0, 'r'},
224 {"eregi", required_argument
, 0, 'R'},
225 {"linespan", no_argument
, 0, 'l'},
226 {"onredirect", required_argument
, 0, 'f'},
227 {"certificate", required_argument
, 0, 'C'},
228 {"client-cert", required_argument
, 0, 'J'},
229 {"private-key", required_argument
, 0, 'K'},
230 {"useragent", required_argument
, 0, 'A'},
231 {"header", required_argument
, 0, 'k'},
232 {"no-body", no_argument
, 0, 'N'},
233 {"max-age", required_argument
, 0, 'M'},
234 {"content-type", required_argument
, 0, 'T'},
235 {"pagesize", required_argument
, 0, 'm'},
236 {"invert-regex", no_argument
, NULL
, INVERT_REGEX
},
237 {"use-ipv4", no_argument
, 0, '4'},
238 {"use-ipv6", no_argument
, 0, '6'},
239 {"extended-perfdata", no_argument
, 0, 'E'},
246 for (c
= 1; c
< argc
; c
++) {
247 if (strcmp ("-to", argv
[c
]) == 0)
248 strcpy (argv
[c
], "-t");
249 if (strcmp ("-hn", argv
[c
]) == 0)
250 strcpy (argv
[c
], "-H");
251 if (strcmp ("-wt", argv
[c
]) == 0)
252 strcpy (argv
[c
], "-w");
253 if (strcmp ("-ct", argv
[c
]) == 0)
254 strcpy (argv
[c
], "-c");
255 if (strcmp ("-nohtml", argv
[c
]) == 0)
256 strcpy (argv
[c
], "-n");
260 c
= getopt_long (argc
, argv
, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:nlLS::m:M:N:E", longopts
, &option
);
261 if (c
== -1 || c
== EOF
)
265 case '?': /* usage */
272 case 'V': /* version */
273 print_revision (progname
, NP_VERSION
);
276 case 't': /* timeout period */
277 if (!is_intnonneg (optarg
))
278 usage2 (_("Timeout interval must be a positive integer"), optarg
);
280 socket_timeout
= atoi (optarg
);
282 case 'c': /* critical time threshold */
283 critical_thresholds
= optarg
;
285 case 'w': /* warning time threshold */
286 warning_thresholds
= optarg
;
288 case 'A': /* User Agent String */
289 xasprintf (&user_agent
, "User-Agent: %s", optarg
);
291 case 'k': /* Additional headers */
292 if (http_opt_headers_count
== 0)
293 http_opt_headers
= malloc (sizeof (char *) * (++http_opt_headers_count
));
295 http_opt_headers
= realloc (http_opt_headers
, sizeof (char *) * (++http_opt_headers_count
));
296 http_opt_headers
[http_opt_headers_count
- 1] = optarg
;
297 /* xasprintf (&http_opt_headers, "%s", optarg); */
299 case 'L': /* show html link */
302 case 'n': /* do not show html link */
303 display_html
= FALSE
;
305 case 'C': /* Check SSL cert validity */
307 if ((temp
=strchr(optarg
,','))!=NULL
) {
309 if (!is_intnonneg (optarg
))
310 usage2 (_("Invalid certificate expiration period"), optarg
);
311 days_till_exp_warn
= atoi(optarg
);
314 if (!is_intnonneg (temp
))
315 usage2 (_("Invalid certificate expiration period"), temp
);
316 days_till_exp_crit
= atoi (temp
);
319 days_till_exp_crit
=0;
320 if (!is_intnonneg (optarg
))
321 usage2 (_("Invalid certificate expiration period"), optarg
);
322 days_till_exp_warn
= atoi (optarg
);
327 case 'J': /* use client certificate */
330 client_cert
= optarg
;
333 case 'K': /* use client private key */
336 client_privkey
= optarg
;
339 case 'S': /* use SSL */
343 if (optarg
== NULL
|| c
!= 'S')
346 ssl_version
= atoi(optarg
);
347 if (ssl_version
< 1 || ssl_version
> 3)
348 usage4 (_("Invalid option - Valid values for SSL Version are 1 (TLSv1), 2 (SSLv2) or 3 (SSLv3)"));
350 if (specify_port
== FALSE
)
351 server_port
= HTTPS_PORT
;
353 /* -C -J and -K fall through to here without SSL */
354 usage4 (_("Invalid option - SSL is not available"));
360 case 'f': /* onredirect */
361 if (!strcmp (optarg
, "stickyport"))
362 onredirect
= STATE_DEPENDENT
, followsticky
= STICKY_HOST
|STICKY_PORT
;
363 else if (!strcmp (optarg
, "sticky"))
364 onredirect
= STATE_DEPENDENT
, followsticky
= STICKY_HOST
;
365 else if (!strcmp (optarg
, "follow"))
366 onredirect
= STATE_DEPENDENT
, followsticky
= STICKY_NONE
;
367 else if (!strcmp (optarg
, "unknown"))
368 onredirect
= STATE_UNKNOWN
;
369 else if (!strcmp (optarg
, "ok"))
370 onredirect
= STATE_OK
;
371 else if (!strcmp (optarg
, "warning"))
372 onredirect
= STATE_WARNING
;
373 else if (!strcmp (optarg
, "critical"))
374 onredirect
= STATE_CRITICAL
;
375 else usage2 (_("Invalid onredirect option"), optarg
);
377 printf(_("option f:%d \n"), onredirect
);
379 /* Note: H, I, and u must be malloc'd or will fail on redirects */
380 case 'H': /* Host Name (virtual host) */
381 host_name
= strdup (optarg
);
382 if (host_name
[0] == '[') {
383 if ((p
= strstr (host_name
, "]:")) != NULL
) /* [IPv6]:port */
384 server_port
= atoi (p
+ 2);
385 } else if ((p
= strchr (host_name
, ':')) != NULL
386 && strchr (++p
, ':') == NULL
) /* IPv4:port or host:port */
387 server_port
= atoi (p
);
389 case 'I': /* Server IP-address */
390 server_address
= strdup (optarg
);
392 case 'u': /* URL path */
393 server_url
= strdup (optarg
);
394 server_url_length
= strlen (server_url
);
396 case 'p': /* Server port */
397 if (!is_intnonneg (optarg
))
398 usage2 (_("Invalid port number"), optarg
);
400 server_port
= atoi (optarg
);
404 case 'a': /* authorization info */
405 strncpy (user_auth
, optarg
, MAX_INPUT_BUFFER
- 1);
406 user_auth
[MAX_INPUT_BUFFER
- 1] = 0;
408 case 'b': /* proxy-authorization info */
409 strncpy (proxy_auth
, optarg
, MAX_INPUT_BUFFER
- 1);
410 proxy_auth
[MAX_INPUT_BUFFER
- 1] = 0;
412 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
413 if (! http_post_data
)
414 http_post_data
= strdup (optarg
);
416 http_method
= strdup("POST");
418 case 'j': /* Set HTTP method */
421 http_method
= strdup (optarg
);
423 case 'd': /* string or substring */
424 strncpy (header_expect
, optarg
, MAX_INPUT_BUFFER
- 1);
425 header_expect
[MAX_INPUT_BUFFER
- 1] = 0;
427 case 's': /* string or substring */
428 strncpy (string_expect
, optarg
, MAX_INPUT_BUFFER
- 1);
429 string_expect
[MAX_INPUT_BUFFER
- 1] = 0;
431 case 'e': /* string or substring */
432 strncpy (server_expect
, optarg
, MAX_INPUT_BUFFER
- 1);
433 server_expect
[MAX_INPUT_BUFFER
- 1] = 0;
434 server_expect_yn
= 1;
436 case 'T': /* Content-type */
437 xasprintf (&http_content_type
, "%s", optarg
);
439 case 'l': /* linespan */
440 cflags
&= ~REG_NEWLINE
;
442 case 'R': /* regex */
444 case 'r': /* regex */
445 strncpy (regexp
, optarg
, MAX_RE_SIZE
- 1);
446 regexp
[MAX_RE_SIZE
- 1] = 0;
447 errcode
= regcomp (&preg
, regexp
, cflags
);
449 (void) regerror (errcode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
450 printf (_("Could Not Compile Regular Expression: %s"), errbuf
);
458 address_family
= AF_INET
;
462 address_family
= AF_INET6
;
464 usage4 (_("IPv6 support not available"));
467 case 'v': /* verbose */
470 case 'm': /* min_page_length */
473 if (strchr(optarg
, ':') != (char *)NULL
) {
474 /* range, so get two values, min:max */
475 tmp
= strtok(optarg
, ":");
477 printf("Bad format: try \"-m min:max\"\n");
478 exit (STATE_WARNING
);
480 min_page_len
= atoi(tmp
);
482 tmp
= strtok(NULL
, ":");
484 printf("Bad format: try \"-m min:max\"\n");
485 exit (STATE_WARNING
);
487 max_page_len
= atoi(tmp
);
489 min_page_len
= atoi (optarg
);
492 case 'N': /* no-body */
495 case 'M': /* max-age */
497 int L
= strlen(optarg
);
498 if (L
&& optarg
[L
-1] == 'm')
499 maximum_age
= atoi (optarg
) * 60;
500 else if (L
&& optarg
[L
-1] == 'h')
501 maximum_age
= atoi (optarg
) * 60 * 60;
502 else if (L
&& optarg
[L
-1] == 'd')
503 maximum_age
= atoi (optarg
) * 60 * 60 * 24;
504 else if (L
&& (optarg
[L
-1] == 's' ||
505 isdigit (optarg
[L
-1])))
506 maximum_age
= atoi (optarg
);
508 fprintf (stderr
, "unparsable max-age: %s\n", optarg
);
509 exit (STATE_WARNING
);
513 case 'E': /* show extended perfdata */
514 show_extended_perfdata
= TRUE
;
521 if (server_address
== NULL
&& c
< argc
)
522 server_address
= strdup (argv
[c
++]);
524 if (host_name
== NULL
&& c
< argc
)
525 host_name
= strdup (argv
[c
++]);
527 if (server_address
== NULL
) {
528 if (host_name
== NULL
)
529 usage4 (_("You must specify a server address or host name"));
531 server_address
= strdup (host_name
);
534 set_thresholds(&thlds
, warning_thresholds
, critical_thresholds
);
536 if (critical_thresholds
&& thlds
->critical
->end
>(double)socket_timeout
)
537 socket_timeout
= (int)thlds
->critical
->end
+ 1;
539 if (http_method
== NULL
)
540 http_method
= strdup ("GET");
542 if (client_cert
&& !client_privkey
)
543 usage4 (_("If you use a client certificate you must also specify a private key file"));
550 /* Returns 1 if we're done processing the document body; 0 to keep going */
552 document_headers_done (char *full_page
)
556 for (body
= full_page
; *body
; body
++) {
557 if (!strncmp (body
, "\n\n", 2) || !strncmp (body
, "\n\r\n", 3))
562 return 0; /* haven't read end of headers yet */
564 full_page
[body
- full_page
] = 0;
569 parse_time_string (const char *string
)
573 memset (&tm
, 0, sizeof(tm
));
575 /* Like this: Tue, 25 Dec 2001 02:59:03 GMT */
577 if (isupper (string
[0]) && /* Tue */
578 islower (string
[1]) &&
579 islower (string
[2]) &&
582 (isdigit(string
[5]) || string
[5] == ' ') && /* 25 */
583 isdigit (string
[6]) &&
585 isupper (string
[8]) && /* Dec */
586 islower (string
[9]) &&
587 islower (string
[10]) &&
589 isdigit (string
[12]) && /* 2001 */
590 isdigit (string
[13]) &&
591 isdigit (string
[14]) &&
592 isdigit (string
[15]) &&
594 isdigit (string
[17]) && /* 02: */
595 isdigit (string
[18]) &&
597 isdigit (string
[20]) && /* 59: */
598 isdigit (string
[21]) &&
600 isdigit (string
[23]) && /* 03 */
601 isdigit (string
[24]) &&
603 'G' == string
[26] && /* GMT */
604 'M' == string
[27] && /* GMT */
607 tm
.tm_sec
= 10 * (string
[23]-'0') + (string
[24]-'0');
608 tm
.tm_min
= 10 * (string
[20]-'0') + (string
[21]-'0');
609 tm
.tm_hour
= 10 * (string
[17]-'0') + (string
[18]-'0');
610 tm
.tm_mday
= 10 * (string
[5] == ' ' ? 0 : string
[5]-'0') + (string
[6]-'0');
611 tm
.tm_mon
= (!strncmp (string
+8, "Jan", 3) ? 0 :
612 !strncmp (string
+8, "Feb", 3) ? 1 :
613 !strncmp (string
+8, "Mar", 3) ? 2 :
614 !strncmp (string
+8, "Apr", 3) ? 3 :
615 !strncmp (string
+8, "May", 3) ? 4 :
616 !strncmp (string
+8, "Jun", 3) ? 5 :
617 !strncmp (string
+8, "Jul", 3) ? 6 :
618 !strncmp (string
+8, "Aug", 3) ? 7 :
619 !strncmp (string
+8, "Sep", 3) ? 8 :
620 !strncmp (string
+8, "Oct", 3) ? 9 :
621 !strncmp (string
+8, "Nov", 3) ? 10 :
622 !strncmp (string
+8, "Dec", 3) ? 11 :
624 tm
.tm_year
= ((1000 * (string
[12]-'0') +
625 100 * (string
[13]-'0') +
626 10 * (string
[14]-'0') +
630 tm
.tm_isdst
= 0; /* GMT is never in DST, right? */
632 if (tm
.tm_mon
< 0 || tm
.tm_mday
< 1 || tm
.tm_mday
> 31)
636 This is actually wrong: we need to subtract the local timezone
637 offset from GMT from this value. But, that's ok in this usage,
638 because we only comparing these two GMT dates against each other,
639 so it doesn't matter what time zone we parse them in.
643 if (t
== (time_t) -1) t
= 0;
646 const char *s
= string
;
647 while (*s
&& *s
!= '\r' && *s
!= '\n')
648 fputc (*s
++, stdout
);
649 printf (" ==> %lu\n", (unsigned long) t
);
659 /* Checks if the server 'reply' is one of the expected 'statuscodes' */
661 expected_statuscode (const char *reply
, const char *statuscodes
)
663 char *expected
, *code
;
666 if ((expected
= strdup (statuscodes
)) == NULL
)
667 die (STATE_UNKNOWN
, _("HTTP UNKNOWN - Memory allocation error\n"));
669 for (code
= strtok (expected
, ","); code
!= NULL
; code
= strtok (NULL
, ","))
670 if (strstr (reply
, code
) != NULL
) {
680 check_document_dates (const char *headers
, char **msg
)
683 char *server_date
= 0;
684 char *document_date
= 0;
685 int date_result
= STATE_OK
;
689 const char *field
= s
;
690 const char *value
= 0;
692 /* Find the end of the header field */
693 while (*s
&& !isspace(*s
) && *s
!= ':')
696 /* Remember the header value, if any. */
700 /* Skip to the end of the header, including continuation lines. */
701 while (*s
&& !(*s
== '\n' && (s
[1] != ' ' && s
[1] != '\t')))
704 /* Avoid stepping over end-of-string marker */
708 /* Process this header. */
709 if (value
&& value
> field
+2) {
710 char *ff
= (char *) malloc (value
-field
);
712 while (field
< value
-1)
713 *ss
++ = tolower(*field
++);
716 if (!strcmp (ff
, "date") || !strcmp (ff
, "last-modified")) {
718 while (*value
&& isspace (*value
))
720 for (e
= value
; *e
&& *e
!= '\r' && *e
!= '\n'; e
++)
722 ss
= (char *) malloc (e
- value
+ 1);
723 strncpy (ss
, value
, e
- value
);
725 if (!strcmp (ff
, "date")) {
726 if (server_date
) free (server_date
);
729 if (document_date
) free (document_date
);
737 /* Done parsing the body. Now check the dates we (hopefully) parsed. */
738 if (!server_date
|| !*server_date
) {
739 xasprintf (msg
, _("%sServer date unknown, "), *msg
);
740 date_result
= max_state_alt(STATE_UNKNOWN
, date_result
);
741 } else if (!document_date
|| !*document_date
) {
742 xasprintf (msg
, _("%sDocument modification date unknown, "), *msg
);
743 date_result
= max_state_alt(STATE_CRITICAL
, date_result
);
745 time_t srv_data
= parse_time_string (server_date
);
746 time_t doc_data
= parse_time_string (document_date
);
749 xasprintf (msg
, _("%sServer date \"%100s\" unparsable, "), *msg
, server_date
);
750 date_result
= max_state_alt(STATE_CRITICAL
, date_result
);
751 } else if (doc_data
<= 0) {
752 xasprintf (msg
, _("%sDocument date \"%100s\" unparsable, "), *msg
, document_date
);
753 date_result
= max_state_alt(STATE_CRITICAL
, date_result
);
754 } else if (doc_data
> srv_data
+ 30) {
755 xasprintf (msg
, _("%sDocument is %d seconds in the future, "), *msg
, (int)doc_data
- (int)srv_data
);
756 date_result
= max_state_alt(STATE_CRITICAL
, date_result
);
757 } else if (doc_data
< srv_data
- maximum_age
) {
758 int n
= (srv_data
- doc_data
);
759 if (n
> (60 * 60 * 24 * 2)) {
760 xasprintf (msg
, _("%sLast modified %.1f days ago, "), *msg
, ((float) n
) / (60 * 60 * 24));
761 date_result
= max_state_alt(STATE_CRITICAL
, date_result
);
763 xasprintf (msg
, _("%sLast modified %d:%02d:%02d ago, "), *msg
, n
/ (60 * 60), (n
/ 60) % 60, n
% 60);
764 date_result
= max_state_alt(STATE_CRITICAL
, date_result
);
768 free (document_date
);
774 get_content_length (const char *headers
)
777 int content_length
= 0;
781 const char *field
= s
;
782 const char *value
= 0;
784 /* Find the end of the header field */
785 while (*s
&& !isspace(*s
) && *s
!= ':')
788 /* Remember the header value, if any. */
792 /* Skip to the end of the header, including continuation lines. */
793 while (*s
&& !(*s
== '\n' && (s
[1] != ' ' && s
[1] != '\t')))
796 /* Avoid stepping over end-of-string marker */
800 /* Process this header. */
801 if (value
&& value
> field
+2) {
802 char *ff
= (char *) malloc (value
-field
);
804 while (field
< value
-1)
805 *ss
++ = tolower(*field
++);
808 if (!strcmp (ff
, "content-length")) {
810 while (*value
&& isspace (*value
))
812 for (e
= value
; *e
&& *e
!= '\r' && *e
!= '\n'; e
++)
814 ss
= (char *) malloc (e
- value
+ 1);
815 strncpy (ss
, value
, e
- value
);
817 content_length
= atoi(ss
);
823 return (content_length
);
827 prepend_slash (char *path
)
834 if ((newpath
= malloc (strlen(path
) + 2)) == NULL
)
835 die (STATE_UNKNOWN
, _("HTTP UNKNOWN - Memory allocation error\n"));
837 strcpy (newpath
+ 1, path
);
859 double elapsed_time
= 0.0;
860 long microsec_connect
= 0L;
861 double elapsed_time_connect
= 0.0;
862 long microsec_ssl
= 0L;
863 double elapsed_time_ssl
= 0.0;
864 long microsec_firstbyte
= 0L;
865 double elapsed_time_firstbyte
= 0.0;
866 long microsec_headers
= 0L;
867 double elapsed_time_headers
= 0.0;
868 long microsec_transfer
= 0L;
869 double elapsed_time_transfer
= 0.0;
871 int result
= STATE_OK
;
873 /* try to connect to the host at the given port number */
874 gettimeofday (&tv_temp
, NULL
);
875 if (my_tcp_connect (server_address
, server_port
, &sd
) != STATE_OK
)
876 die (STATE_CRITICAL
, _("HTTP CRITICAL - Unable to open TCP socket\n"));
877 microsec_connect
= deltime (tv_temp
);
879 elapsed_time_connect
= (double)microsec_connect
/ 1.0e6
;
880 if (use_ssl
== TRUE
) {
881 gettimeofday (&tv_temp
, NULL
);
882 result
= np_net_ssl_init_with_hostname_version_and_cert(sd
, (use_sni
? host_name
: NULL
), ssl_version
, client_cert
, client_privkey
);
883 if (result
!= STATE_OK
)
884 die (STATE_CRITICAL
, NULL
);
885 microsec_ssl
= deltime (tv_temp
);
886 elapsed_time_ssl
= (double)microsec_ssl
/ 1.0e6
;
887 if (check_cert
== TRUE
) {
888 result
= np_net_ssl_check_cert(days_till_exp_warn
, days_till_exp_crit
);
889 np_net_ssl_cleanup();
894 #endif /* HAVE_SSL */
896 xasprintf (&buf
, "%s %s %s\r\n%s\r\n", http_method
, server_url
, host_name
? "HTTP/1.1" : "HTTP/1.0", user_agent
);
898 /* tell HTTP/1.1 servers not to keep the connection alive */
899 xasprintf (&buf
, "%sConnection: close\r\n", buf
);
901 /* optionally send the host header info */
904 * Specify the port only if we're using a non-default port (see RFC 2616,
905 * 14.23). Some server applications/configurations cause trouble if the
906 * (default) port is explicitly specified in the "Host:" header line.
908 if ((use_ssl
== FALSE
&& server_port
== HTTP_PORT
) ||
909 (use_ssl
== TRUE
&& server_port
== HTTPS_PORT
))
910 xasprintf (&buf
, "%sHost: %s\r\n", buf
, host_name
);
912 xasprintf (&buf
, "%sHost: %s:%d\r\n", buf
, host_name
, server_port
);
915 /* optionally send any other header tag */
916 if (http_opt_headers_count
) {
917 for (i
= 0; i
< http_opt_headers_count
; i
++) {
918 xasprintf (&buf
, "%s%s\r\n", buf
, http_opt_headers
[i
]);
920 /* This cannot be free'd here because a redirection will then try to access this and segfault */
921 /* Covered in a testcase in tests/check_http.t */
922 /* free(http_opt_headers); */
925 /* optionally send the authentication info */
926 if (strlen(user_auth
)) {
927 base64_encode_alloc (user_auth
, strlen (user_auth
), &auth
);
928 xasprintf (&buf
, "%sAuthorization: Basic %s\r\n", buf
, auth
);
931 /* optionally send the proxy authentication info */
932 if (strlen(proxy_auth
)) {
933 base64_encode_alloc (proxy_auth
, strlen (proxy_auth
), &auth
);
934 xasprintf (&buf
, "%sProxy-Authorization: Basic %s\r\n", buf
, auth
);
937 /* either send http POST data (any data, not only POST)*/
938 if (http_post_data
) {
939 if (http_content_type
) {
940 xasprintf (&buf
, "%sContent-Type: %s\r\n", buf
, http_content_type
);
942 xasprintf (&buf
, "%sContent-Type: application/x-www-form-urlencoded\r\n", buf
);
945 xasprintf (&buf
, "%sContent-Length: %i\r\n\r\n", buf
, (int)strlen (http_post_data
));
946 xasprintf (&buf
, "%s%s%s", buf
, http_post_data
, CRLF
);
949 /* or just a newline so the server knows we're done with the request */
950 xasprintf (&buf
, "%s%s", buf
, CRLF
);
953 if (verbose
) printf ("%s\n", buf
);
954 gettimeofday (&tv_temp
, NULL
);
955 my_send (buf
, strlen (buf
));
956 microsec_headers
= deltime (tv_temp
);
957 elapsed_time_headers
= (double)microsec_headers
/ 1.0e6
;
960 full_page
= strdup("");
961 gettimeofday (&tv_temp
, NULL
);
962 while ((i
= my_recv (buffer
, MAX_INPUT_BUFFER
-1)) > 0) {
963 if ((i
>= 1) && (elapsed_time_firstbyte
<= 0.000001)) {
964 microsec_firstbyte
= deltime (tv_temp
);
965 elapsed_time_firstbyte
= (double)microsec_firstbyte
/ 1.0e6
;
968 xasprintf (&full_page_new
, "%s%s", full_page
, buffer
);
970 full_page
= full_page_new
;
973 if (no_body
&& document_headers_done (full_page
)) {
978 microsec_transfer
= deltime (tv_temp
);
979 elapsed_time_transfer
= (double)microsec_transfer
/ 1.0e6
;
981 if (i
< 0 && errno
!= ECONNRESET
) {
985 sslerr=SSL_get_error(ssl, i);
986 if ( sslerr == SSL_ERROR_SSL ) {
987 die (STATE_WARNING, _("HTTP WARNING - Client Certificate Required\n"));
989 die (STATE_CRITICAL, _("HTTP CRITICAL - Error on receive\n"));
995 die (STATE_CRITICAL
, _("HTTP CRITICAL - Error on receive\n"));
1003 /* return a CRITICAL status if we couldn't read any data */
1004 if (pagesize
== (size_t) 0)
1005 die (STATE_CRITICAL
, _("HTTP CRITICAL - No data received from host\n"));
1007 /* close the connection */
1009 np_net_ssl_cleanup();
1013 /* Save check time */
1014 microsec
= deltime (tv
);
1015 elapsed_time
= (double)microsec
/ 1.0e6
;
1017 /* leave full_page untouched so we can free it later */
1021 printf ("%s://%s:%d%s is %d characters\n",
1022 use_ssl
? "https" : "http", server_address
,
1023 server_port
, server_url
, (int)pagesize
);
1025 /* find status line and null-terminate it */
1027 page
+= (size_t) strcspn (page
, "\r\n");
1029 page
+= (size_t) strspn (page
, "\r\n");
1030 status_line
[strcspn(status_line
, "\r\n")] = 0;
1031 strip (status_line
);
1033 printf ("STATUS: %s\n", status_line
);
1035 /* find header info and null-terminate it */
1037 while (strcspn (page
, "\r\n") > 0) {
1038 page
+= (size_t) strcspn (page
, "\r\n");
1040 if ((strspn (page
, "\r") == 1 && strspn (page
, "\r\n") >= 2) ||
1041 (strspn (page
, "\n") == 1 && strspn (page
, "\r\n") >= 2))
1046 page
+= (size_t) strspn (page
, "\r\n");
1047 header
[pos
- header
] = 0;
1049 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header
,
1050 (no_body
? " [[ skipped ]]" : page
));
1052 /* make sure the status line matches the response we are looking for */
1053 if (!expected_statuscode (status_line
, server_expect
)) {
1054 if (server_port
== HTTP_PORT
)
1056 _("Invalid HTTP response received from host: %s\n"),
1060 _("Invalid HTTP response received from host on port %d: %s\n"),
1061 server_port
, status_line
);
1062 die (STATE_CRITICAL
, "HTTP CRITICAL - %s", msg
);
1065 /* Bypass normal status line check if server_expect was set by user and not default */
1066 /* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
1067 if ( server_expect_yn
) {
1069 _("Status line output matched \"%s\" - "), server_expect
);
1071 printf ("%s\n",msg
);
1074 /* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF */
1075 /* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
1076 /* Status-Code = 3 DIGITS */
1078 status_code
= strchr (status_line
, ' ') + sizeof (char);
1079 if (strspn (status_code
, "1234567890") != 3)
1080 die (STATE_CRITICAL
, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line
);
1082 http_status
= atoi (status_code
);
1084 /* check the return code */
1086 if (http_status
>= 600 || http_status
< 100) {
1087 die (STATE_CRITICAL
, _("HTTP CRITICAL: Invalid Status (%s)\n"), status_line
);
1089 /* server errors result in a critical state */
1090 else if (http_status
>= 500) {
1091 xasprintf (&msg
, _("%s - "), status_line
);
1092 result
= STATE_CRITICAL
;
1094 /* client errors result in a warning state */
1095 else if (http_status
>= 400) {
1096 xasprintf (&msg
, _("%s - "), status_line
);
1097 result
= max_state_alt(STATE_WARNING
, result
);
1099 /* check redirected page if specified */
1100 else if (http_status
>= 300) {
1102 if (onredirect
== STATE_DEPENDENT
)
1103 redir (header
, status_line
);
1105 result
= max_state_alt(onredirect
, result
);
1106 xasprintf (&msg
, _("%s - "), status_line
);
1107 } /* end if (http_status >= 300) */
1109 /* Print OK status anyway */
1110 xasprintf (&msg
, _("%s - "), status_line
);
1113 } /* end else (server_expect_yn) */
1115 /* reset the alarm - must be called *after* redir or we'll never die on redirects! */
1118 if (maximum_age
>= 0) {
1119 result
= max_state_alt(check_document_dates(header
, &msg
), result
);
1122 /* Page and Header content checks go here */
1123 if (strlen (header_expect
)) {
1124 if (!strstr (header
, header_expect
)) {
1125 strncpy(&output_header_search
[0],header_expect
,sizeof(output_header_search
));
1126 if(output_header_search
[sizeof(output_header_search
)-1]!='\0') {
1127 bcopy("...",&output_header_search
[sizeof(output_header_search
)-4],4);
1129 xasprintf (&msg
, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg
, output_header_search
, use_ssl
? "https" : "http", host_name
? host_name
: server_address
, server_port
, server_url
);
1130 result
= STATE_CRITICAL
;
1135 if (strlen (string_expect
)) {
1136 if (!strstr (page
, string_expect
)) {
1137 strncpy(&output_string_search
[0],string_expect
,sizeof(output_string_search
));
1138 if(output_string_search
[sizeof(output_string_search
)-1]!='\0') {
1139 bcopy("...",&output_string_search
[sizeof(output_string_search
)-4],4);
1141 xasprintf (&msg
, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg
, output_string_search
, use_ssl
? "https" : "http", host_name
? host_name
: server_address
, server_port
, server_url
);
1142 result
= STATE_CRITICAL
;
1146 if (strlen (regexp
)) {
1147 errcode
= regexec (&preg
, page
, REGS
, pmatch
, 0);
1148 if ((errcode
== 0 && invert_regex
== 0) || (errcode
== REG_NOMATCH
&& invert_regex
== 1)) {
1149 /* OK - No-op to avoid changing the logic around it */
1150 result
= max_state_alt(STATE_OK
, result
);
1152 else if ((errcode
== REG_NOMATCH
&& invert_regex
== 0) || (errcode
== 0 && invert_regex
== 1)) {
1153 if (invert_regex
== 0)
1154 xasprintf (&msg
, _("%spattern not found, "), msg
);
1156 xasprintf (&msg
, _("%spattern found, "), msg
);
1157 result
= STATE_CRITICAL
;
1160 /* FIXME: Shouldn't that be UNKNOWN? */
1161 regerror (errcode
, &preg
, errbuf
, MAX_INPUT_BUFFER
);
1162 xasprintf (&msg
, _("%sExecute Error: %s, "), msg
, errbuf
);
1163 result
= STATE_CRITICAL
;
1167 /* make sure the page is of an appropriate size */
1168 /* page_len = get_content_length(header); */
1169 /* FIXME: Will this work with -N ? IMHO we should use
1170 * get_content_length(header) and always check if it's different than the
1173 /* FIXME: IIRC pagesize returns headers - shouldn't we make
1174 * it == get_content_length(header) ??
1176 page_len
= pagesize
;
1177 if ((max_page_len
> 0) && (page_len
> max_page_len
)) {
1178 xasprintf (&msg
, _("%spage size %d too large, "), msg
, page_len
);
1179 result
= max_state_alt(STATE_WARNING
, result
);
1180 } else if ((min_page_len
> 0) && (page_len
< min_page_len
)) {
1181 xasprintf (&msg
, _("%spage size %d too small, "), msg
, page_len
);
1182 result
= max_state_alt(STATE_WARNING
, result
);
1185 /* Cut-off trailing characters */
1186 if(msg
[strlen(msg
)-2] == ',')
1187 msg
[strlen(msg
)-2] = '\0';
1189 msg
[strlen(msg
)-3] = '\0';
1191 /* check elapsed time */
1192 if (show_extended_perfdata
)
1194 _("%s - %d bytes in %.3f second response time %s|%s %s %s %s %s %s %s"),
1195 msg
, page_len
, elapsed_time
,
1196 (display_html
? "</A>" : ""),
1197 perfd_time (elapsed_time
),
1198 perfd_size (page_len
),
1199 perfd_time_connect (elapsed_time_connect
),
1200 use_ssl
== TRUE
? perfd_time_ssl (elapsed_time_ssl
) : "",
1201 perfd_time_headers (elapsed_time_headers
),
1202 perfd_time_firstbyte (elapsed_time_firstbyte
),
1203 perfd_time_transfer (elapsed_time_transfer
));
1206 _("%s - %d bytes in %.3f second response time %s|%s %s"),
1207 msg
, page_len
, elapsed_time
,
1208 (display_html
? "</A>" : ""),
1209 perfd_time (elapsed_time
),
1210 perfd_size (page_len
));
1212 result
= max_state_alt(get_status(elapsed_time
, thlds
), result
);
1214 die (result
, "HTTP %s: %s\n", state_text(result
), msg
);
1216 return STATE_UNKNOWN
;
1222 #define URI_HTTP "%5[HTPShtps]"
1223 #define URI_HOST "%255[-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1224 #define URI_PORT "%6d" /* MAX_PORT's width is 5 chars, 6 to detect overflow */
1225 #define URI_PATH "%[-_.!~*'();/?:@&=+$,%#abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]"
1226 #define HD1 URI_HTTP "://" URI_HOST ":" URI_PORT "/" URI_PATH
1227 #define HD2 URI_HTTP "://" URI_HOST "/" URI_PATH
1228 #define HD3 URI_HTTP "://" URI_HOST ":" URI_PORT
1229 #define HD4 URI_HTTP "://" URI_HOST
1230 #define HD5 URI_PATH
1233 redir (char *pos
, char *status_line
)
1242 addr
= malloc (MAX_IPV4_HOSTLENGTH
+ 1);
1244 die (STATE_UNKNOWN
, _("HTTP UNKNOWN - Could not allocate addr\n"));
1246 url
= malloc (strcspn (pos
, "\r\n"));
1248 die (STATE_UNKNOWN
, _("HTTP UNKNOWN - Could not allocate URL\n"));
1251 sscanf (pos
, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx
, &i
);
1253 pos
+= (size_t) strcspn (pos
, "\r\n");
1254 pos
+= (size_t) strspn (pos
, "\r\n");
1255 if (strlen(pos
) == 0)
1257 _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
1258 status_line
, (display_html
? "</A>" : ""));
1263 pos
+= strspn (pos
, " \t");
1266 * RFC 2616 (4.2): ``Header fields can be extended over multiple lines by
1267 * preceding each extra line with at least one SP or HT.''
1269 for (; (i
= strspn (pos
, "\r\n")); pos
+= i
) {
1271 if (!(i
= strspn (pos
, " \t"))) {
1272 die (STATE_UNKNOWN
, _("HTTP UNKNOWN - Empty redirect location%s\n"),
1273 display_html
? "</A>" : "");
1277 url
= realloc (url
, strcspn (pos
, "\r\n") + 1);
1279 die (STATE_UNKNOWN
, _("HTTP UNKNOWN - Could not allocate URL\n"));
1281 /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
1282 if (sscanf (pos
, HD1
, type
, addr
, &i
, url
) == 4) {
1283 url
= prepend_slash (url
);
1284 use_ssl
= server_type_check (type
);
1287 /* URI_HTTP URI_HOST URI_PATH */
1288 else if (sscanf (pos
, HD2
, type
, addr
, url
) == 3 ) {
1289 url
= prepend_slash (url
);
1290 use_ssl
= server_type_check (type
);
1291 i
= server_port_check (use_ssl
);
1294 /* URI_HTTP URI_HOST URI_PORT */
1295 else if (sscanf (pos
, HD3
, type
, addr
, &i
) == 3) {
1296 strcpy (url
, HTTP_URL
);
1297 use_ssl
= server_type_check (type
);
1300 /* URI_HTTP URI_HOST */
1301 else if (sscanf (pos
, HD4
, type
, addr
) == 2) {
1302 strcpy (url
, HTTP_URL
);
1303 use_ssl
= server_type_check (type
);
1304 i
= server_port_check (use_ssl
);
1308 else if (sscanf (pos
, HD5
, url
) == 1) {
1310 if ((url
[0] != '/')) {
1311 if ((x
= strrchr(server_url
, '/')))
1313 xasprintf (&url
, "%s/%s", server_url
, url
);
1316 strcpy (type
, server_type
);
1317 strcpy (addr
, host_name
? host_name
: server_address
);
1322 _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
1323 pos
, (display_html
? "</A>" : ""));
1328 } /* end while (pos) */
1330 if (++redir_depth
> max_depth
)
1332 _("HTTP WARNING - maximum redirection depth %d exceeded - %s://%s:%d%s%s\n"),
1333 max_depth
, type
, addr
, i
, url
, (display_html
? "</A>" : ""));
1335 if (server_port
==i
&&
1336 !strcmp(server_address
, addr
) &&
1337 (host_name
&& !strcmp(host_name
, addr
)) &&
1338 !strcmp(server_url
, url
))
1340 _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1341 type
, addr
, i
, url
, (display_html
? "</A>" : ""));
1343 strcpy (server_type
, type
);
1346 host_name
= strdup (addr
);
1348 if (!(followsticky
& STICKY_HOST
)) {
1349 free (server_address
);
1350 server_address
= strdup (addr
);
1352 if (!(followsticky
& STICKY_PORT
)) {
1359 if (server_port
> MAX_PORT
)
1361 _("HTTP UNKNOWN - Redirection to port above %d - %s://%s:%d%s%s\n"),
1362 MAX_PORT
, server_type
, server_address
, server_port
, server_url
,
1363 display_html
? "</A>" : "");
1366 printf (_("Redirection to %s://%s:%d%s\n"), server_type
,
1367 host_name
? host_name
: server_address
, server_port
, server_url
);
1374 server_type_check (const char *type
)
1376 if (strcmp (type
, "https"))
1383 server_port_check (int ssl_flag
)
1391 char *perfd_time (double elapsed_time
)
1393 return fperfdata ("time", elapsed_time
, "s",
1394 thlds
->warning
?TRUE
:FALSE
, thlds
->warning
?thlds
->warning
->end
:0,
1395 thlds
->critical
?TRUE
:FALSE
, thlds
->critical
?thlds
->critical
->end
:0,
1399 char *perfd_time_connect (double elapsed_time_connect
)
1401 return fperfdata ("time_connect", elapsed_time_connect
, "s", FALSE
, 0, FALSE
, 0, FALSE
, 0, FALSE
, 0);
1404 char *perfd_time_ssl (double elapsed_time_ssl
)
1406 return fperfdata ("time_ssl", elapsed_time_ssl
, "s", FALSE
, 0, FALSE
, 0, FALSE
, 0, FALSE
, 0);
1409 char *perfd_time_headers (double elapsed_time_headers
)
1411 return fperfdata ("time_headers", elapsed_time_headers
, "s", FALSE
, 0, FALSE
, 0, FALSE
, 0, FALSE
, 0);
1414 char *perfd_time_firstbyte (double elapsed_time_firstbyte
)
1416 return fperfdata ("time_firstbyte", elapsed_time_firstbyte
, "s", FALSE
, 0, FALSE
, 0, FALSE
, 0, FALSE
, 0);
1419 char *perfd_time_transfer (double elapsed_time_transfer
)
1421 return fperfdata ("time_transfer", elapsed_time_transfer
, "s", FALSE
, 0, FALSE
, 0, FALSE
, 0, FALSE
, 0);
1424 char *perfd_size (int page_len
)
1426 return perfdata ("size", page_len
, "B",
1427 (min_page_len
>0?TRUE
:FALSE
), min_page_len
,
1428 (min_page_len
>0?TRUE
:FALSE
), 0,
1435 print_revision (progname
, NP_VERSION
);
1437 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1438 printf (COPYRIGHT
, copyright
, email
);
1440 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1441 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1442 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1443 printf ("%s\n", _("certificate expiration times."));
1449 printf (_("NOTE: One or both of -H and -I must be specified"));
1453 printf (UT_HELP_VRSN
);
1454 printf (UT_EXTRA_OPTS
);
1456 printf (" %s\n", "-H, --hostname=ADDRESS");
1457 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1458 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1459 printf (" %s\n", "-I, --IP-address=ADDRESS");
1460 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1461 printf (" %s\n", "-p, --port=INTEGER");
1462 printf (" %s", _("Port number (default: "));
1463 printf ("%d)\n", HTTP_PORT
);
1468 printf (" %s\n", "-S, --ssl=VERSION");
1469 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1470 printf (" %s\n", _("auto-negotiation (1 = TLSv1, 2 = SSLv2, 3 = SSLv3)."));
1471 printf (" %s\n", "--sni");
1472 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1473 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1474 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1475 printf (" %s\n", _("(when this option is used the URL is not checked.)"));
1476 printf (" %s\n", "-J, --client-cert=FILE");
1477 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1478 printf (" %s\n", _("to be used in establishing the SSL session"));
1479 printf (" %s\n", "-K, --private-key=FILE");
1480 printf (" %s\n", _("Name of file containing the private key (PEM format)"));
1481 printf (" %s\n", _("matching the client certificate"));
1484 printf (" %s\n", "-e, --expect=STRING");
1485 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1486 printf (" %s", _("the first (status) line of the server response (default: "));
1487 printf ("%s)\n", HTTP_EXPECT
);
1488 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1489 printf (" %s\n", "-d, --header-string=STRING");
1490 printf (" %s\n", _("String to expect in the response headers"));
1491 printf (" %s\n", "-s, --string=STRING");
1492 printf (" %s\n", _("String to expect in the content"));
1493 printf (" %s\n", "-u, --url=PATH");
1494 printf (" %s\n", _("URL to GET or POST (default: /)"));
1495 printf (" %s\n", "-P, --post=STRING");
1496 printf (" %s\n", _("URL encoded http POST data"));
1497 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE)");
1498 printf (" %s\n", _("Set HTTP method."));
1499 printf (" %s\n", "-N, --no-body");
1500 printf (" %s\n", _("Don't wait for document body: stop reading after headers."));
1501 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
1502 printf (" %s\n", "-M, --max-age=SECONDS");
1503 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
1504 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
1505 printf (" %s\n", "-T, --content-type=STRING");
1506 printf (" %s\n", _("specify Content-Type header media type when POSTing\n"));
1508 printf (" %s\n", "-l, --linespan");
1509 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
1510 printf (" %s\n", "-r, --regex, --ereg=STRING");
1511 printf (" %s\n", _("Search page for regex STRING"));
1512 printf (" %s\n", "-R, --eregi=STRING");
1513 printf (" %s\n", _("Search page for case-insensitive regex STRING"));
1514 printf (" %s\n", "--invert-regex");
1515 printf (" %s\n", _("Return CRITICAL if found, OK if not\n"));
1517 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
1518 printf (" %s\n", _("Username:password on sites with basic authentication"));
1519 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
1520 printf (" %s\n", _("Username:password on proxy-servers with basic authentication"));
1521 printf (" %s\n", "-A, --useragent=STRING");
1522 printf (" %s\n", _("String to be sent in http header as \"User Agent\""));
1523 printf (" %s\n", "-k, --header=STRING");
1524 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
1525 printf (" %s\n", "-E, --extended-perfdata");
1526 printf (" %s\n", _("Print additional performance data"));
1527 printf (" %s\n", "-L, --link");
1528 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
1529 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport>");
1530 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
1531 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1532 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1533 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1535 printf (UT_WARN_CRIT
);
1537 printf (UT_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
1539 printf (UT_VERBOSE
);
1542 printf ("%s\n", _("Notes:"));
1543 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
1544 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
1545 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect reponse"));
1546 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
1547 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
1548 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
1552 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
1553 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
1554 printf (" %s\n", _("certificate is still valid for the specified number of days."));
1556 printf (" %s\n", _("Please note that this plugin does not check if the presented server"));
1557 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
1558 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
1560 printf ("%s\n", _("Examples:"));
1561 printf (" %s\n\n", "CHECK CONTENT: check_http -w 5 -c 10 --ssl -H www.verisign.com");
1562 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
1563 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
1564 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
1565 printf (" %s\n", _("a STATE_CRITICAL will be returned."));
1567 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 14");
1568 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
1569 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1570 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
1571 printf (" %s\n", _("the certificate is expired."));
1573 printf (" %s\n\n", "CHECK CERTIFICATE: check_http -H www.verisign.com -C 30,14");
1574 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
1575 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
1576 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
1577 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
1581 printf (UT_SUPPORT
);
1590 printf ("%s\n", _("Usage:"));
1591 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname
);
1592 printf (" [-J <client certificate file>] [-K <private key>]\n");
1593 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
1594 printf (" [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]\n");
1595 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
1596 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1597 printf (" [-A string] [-k string] [-S <version>] [--sni] [-C <warn_age>[,<crit_age>]]\n");
1598 printf (" [-T <content-type>] [-j method]\n");