|
|
@@ -3,7 +3,7 @@
|
|
|
* Nagios check_http plugin
|
|
|
*
|
|
|
* License: GPL
|
|
|
-* Copyright (c) 1999-2017 Nagios Plugins Development Team
|
|
|
+* Copyright (c) 1999-2014 Nagios Plugins Development Team
|
|
|
*
|
|
|
* Description:
|
|
|
*
|
|
|
@@ -34,7 +34,7 @@
|
|
|
/* splint -I. -I../../plugins -I../../lib/ -I/usr/kerberos/include/ ../../plugins/check_http.c */
|
|
|
|
|
|
const char *progname = "check_http";
|
|
|
-const char *copyright = "1999-2017";
|
|
|
+const char *copyright = "1999-2014";
|
|
|
const char *email = "devel@nagios-plugins.org";
|
|
|
|
|
|
#include "common.h"
|
|
|
@@ -146,6 +146,9 @@ char *perfd_size (int page_len);
|
|
|
void print_help (void);
|
|
|
void print_usage (void);
|
|
|
|
|
|
+extern int check_hostname;
|
|
|
+
|
|
|
+
|
|
|
int
|
|
|
main (int argc, char **argv)
|
|
|
{
|
|
|
@@ -200,7 +203,8 @@ process_arguments (int argc, char **argv)
|
|
|
|
|
|
enum {
|
|
|
INVERT_REGEX = CHAR_MAX + 1,
|
|
|
- SNI_OPTION
|
|
|
+ SNI_OPTION,
|
|
|
+ VERIFY_HOST
|
|
|
};
|
|
|
|
|
|
int option = 0;
|
|
|
@@ -210,6 +214,7 @@ process_arguments (int argc, char **argv)
|
|
|
{"nohtml", no_argument, 0, 'n'},
|
|
|
{"ssl", optional_argument, 0, 'S'},
|
|
|
{"sni", no_argument, 0, SNI_OPTION},
|
|
|
+ {"verify-host", no_argument, 0, VERIFY_HOST},
|
|
|
{"post", required_argument, 0, 'P'},
|
|
|
{"method", required_argument, 0, 'j'},
|
|
|
{"IP-address", required_argument, 0, 'I'},
|
|
|
@@ -368,6 +373,9 @@ process_arguments (int argc, char **argv)
|
|
|
case SNI_OPTION:
|
|
|
use_sni = TRUE;
|
|
|
break;
|
|
|
+ case VERIFY_HOST:
|
|
|
+ check_hostname = 1;
|
|
|
+ break;
|
|
|
case 'f': /* onredirect */
|
|
|
if (!strcmp (optarg, "stickyport"))
|
|
|
onredirect = STATE_DEPENDENT, followsticky = STICKY_HOST|STICKY_PORT;
|
|
|
@@ -671,7 +679,20 @@ parse_time_string (const char *string)
|
|
|
static int
|
|
|
expected_statuscode (const char *reply, const char *statuscodes)
|
|
|
{
|
|
|
- return strstr( statuscodes, reply )!= 0;
|
|
|
+ char *expected, *code;
|
|
|
+ int result = 0;
|
|
|
+
|
|
|
+ if ((expected = strdup (statuscodes)) == NULL)
|
|
|
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
|
|
|
+
|
|
|
+ for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ","))
|
|
|
+ if (strstr (reply, code) != NULL) {
|
|
|
+ result = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ free (expected);
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
int chunk_header(char **buf)
|
|
|
@@ -681,14 +702,12 @@ int chunk_header(char **buf)
|
|
|
if (lth <= 0)
|
|
|
return lth;
|
|
|
|
|
|
- while (**buf != '\r' && **buf != '\n')
|
|
|
+ while (**buf !='\0' && **buf != '\r' && **buf != '\n')
|
|
|
++*buf;
|
|
|
|
|
|
// soak up the leading CRLF
|
|
|
- if (**buf && **buf == '\r' && *(++*buf) && **buf == '\n')
|
|
|
+ while (**buf != '\0' && (**buf == '\r' || **buf == '\n'))
|
|
|
++*buf;
|
|
|
- else
|
|
|
- die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse chunked body, invalid format\n"));
|
|
|
|
|
|
return lth;
|
|
|
}
|
|
|
@@ -711,7 +730,7 @@ decode_chunked_page (const char *raw, char *dst)
|
|
|
dst_pos += chunksize;
|
|
|
*dst_pos = '\0';
|
|
|
|
|
|
- if (*raw_pos && *raw_pos == '\r' && *(++raw_pos) && *raw_pos == '\n')
|
|
|
+ while (*raw_pos && (*raw_pos == '\r' || *raw_pos == '\n'))
|
|
|
raw_pos++;
|
|
|
}
|
|
|
|
|
|
@@ -736,8 +755,11 @@ header_value (const char *headers, const char *header)
|
|
|
while (*s && isspace(*s)) s++;
|
|
|
|
|
|
value_end = strchr(s, '\r');
|
|
|
+ if (!value_end)
|
|
|
+ value_end = strchr(s, '\n');
|
|
|
if (!value_end) {
|
|
|
- die (STATE_UNKNOWN, _("HTTP_UNKNOWN - Failed to parse response headers\n"));
|
|
|
+ // Turns out there's no newline after the header... So it's at the end!
|
|
|
+ value_end = s + strlen(s);
|
|
|
}
|
|
|
|
|
|
value_size = value_end - s;
|
|
|
@@ -967,7 +989,6 @@ check_http (void)
|
|
|
long microsec_transfer = 0L;
|
|
|
double elapsed_time_transfer = 0.0;
|
|
|
int page_len = 0;
|
|
|
- char * space_code;
|
|
|
int result = STATE_OK;
|
|
|
char *force_host_header = NULL;
|
|
|
int bad_response = FALSE;
|
|
|
@@ -990,12 +1011,8 @@ check_http (void)
|
|
|
asprintf (&buf, "%s %s:%d HTTP/1.1\r\n%s\r\n", http_method, host_name, HTTPS_PORT, user_agent);
|
|
|
asprintf (&buf, "%sProxy-Connection: keep-alive\r\n", buf);
|
|
|
asprintf (&buf, "%sHost: %s\r\n", buf, host_name);
|
|
|
-
|
|
|
- /* added so this first header has the proxy info */
|
|
|
- if (strlen(proxy_auth)) {
|
|
|
- base64_encode_alloc (proxy_auth, strlen (proxy_auth), &auth);
|
|
|
- xasprintf (&buf, "%sProxy-Authorization: Basic %s\r\n", buf, auth);
|
|
|
- }
|
|
|
+ /* we finished our request, send empty line with CRLF */
|
|
|
+ asprintf (&buf, "%s%s", buf, CRLF);
|
|
|
if (verbose) printf ("%s\n", buf);
|
|
|
send(sd, buf, strlen (buf), 0);
|
|
|
buf[0]='\0';
|
|
|
@@ -1016,10 +1033,12 @@ check_http (void)
|
|
|
microsec_ssl = deltime (tv_temp);
|
|
|
elapsed_time_ssl = (double)microsec_ssl / 1.0e6;
|
|
|
if (check_cert == TRUE) {
|
|
|
- result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
|
|
|
- if (sd) close(sd);
|
|
|
- np_net_ssl_cleanup();
|
|
|
- return result;
|
|
|
+ result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit);
|
|
|
+ if (result != STATE_OK) {
|
|
|
+ if (sd) close(sd);
|
|
|
+ np_net_ssl_cleanup();
|
|
|
+ return result;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
#endif /* HAVE_SSL */
|
|
|
@@ -1054,16 +1073,14 @@ check_http (void)
|
|
|
* (default) port is explicitly specified in the "Host:" header line.
|
|
|
*/
|
|
|
if ((use_ssl == FALSE && server_port == HTTP_PORT) ||
|
|
|
- (use_ssl == TRUE && server_port == HTTPS_PORT)
|
|
|
- || ( strcmp(http_method, "CONNECT") == 0 ) ) // grg-- if through a proxy, don't include the port number
|
|
|
+ (use_ssl == TRUE && server_port == HTTPS_PORT))
|
|
|
xasprintf (&buf, "%sHost: %s\r\n", buf, host_name);
|
|
|
else
|
|
|
xasprintf (&buf, "%sHost: %s:%d\r\n", buf, host_name, server_port);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* Inform server we accept any MIME type response
|
|
|
-
|
|
|
+ /* Inform server we accept any MIME type response
|
|
|
* TODO: Take an arguement to determine what type(s) to accept,
|
|
|
* so that we can alert if a response is of an invalid type.
|
|
|
*/
|
|
|
@@ -1103,40 +1120,41 @@ check_http (void)
|
|
|
}
|
|
|
|
|
|
xasprintf (&buf, "%sContent-Length: %i\r\n\r\n", buf, (int)strlen (http_post_data));
|
|
|
- //xasprintf (&buf, "%s%s%s", buf, http_post_data, CRLF); // grg: do not append extra CRLF, for HTTP 1.1 compliance
|
|
|
- xasprintf (&buf, "%s%s", buf, http_post_data); // NOTE: TODO: We should not be using strings at all!! Data can be binary!!
|
|
|
+ xasprintf (&buf, "%s%s%s", buf, http_post_data, CRLF);
|
|
|
}
|
|
|
else {
|
|
|
/* or just a newline so the server knows we're done with the request */
|
|
|
- // xasprintf (&buf, "%s%s", buf, CRLF); // grg: do not append extra CRLF, for HTTP 1.1 compliance
|
|
|
+ xasprintf (&buf, "%s%s", buf, CRLF);
|
|
|
}
|
|
|
|
|
|
- if (verbose) printf ("%s\n", buf); // grg: leave extra CRLF to keep sccreen readable...
|
|
|
+ if (verbose) printf ("%s\n", buf);
|
|
|
gettimeofday (&tv_temp, NULL);
|
|
|
my_send (buf, strlen (buf));
|
|
|
microsec_headers = deltime (tv_temp);
|
|
|
elapsed_time_headers = (double)microsec_headers / 1.0e6;
|
|
|
|
|
|
/* fetch the page */
|
|
|
-
|
|
|
full_page = strdup("");
|
|
|
gettimeofday (&tv_temp, NULL);
|
|
|
-
|
|
|
while ((i = my_recv (buffer, MAX_INPUT_BUFFER-1)) > 0) {
|
|
|
if ((i >= 1) && (elapsed_time_firstbyte <= 0.000001)) {
|
|
|
microsec_firstbyte = deltime (tv_temp);
|
|
|
elapsed_time_firstbyte = (double)microsec_firstbyte / 1.0e6;
|
|
|
}
|
|
|
buffer[i] = '\0';
|
|
|
- xasprintf (&full_page_new, "%s%s", full_page, buffer);
|
|
|
- free (full_page);
|
|
|
+ /* xasprintf (&full_page_new, "%s%s", full_page, buffer); */
|
|
|
+ if ((full_page_new = realloc(full_page, pagesize + i + 1)) == NULL)
|
|
|
+ die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate memory for full_page\n"));
|
|
|
+
|
|
|
+ memmove(&full_page_new[pagesize], buffer, i);
|
|
|
+ /*free (full_page);*/
|
|
|
full_page = full_page_new;
|
|
|
pagesize += i;
|
|
|
|
|
|
- if (no_body && document_headers_done (full_page)) {
|
|
|
- i = 0;
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (no_body && document_headers_done (full_page)) {
|
|
|
+ i = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
microsec_transfer = deltime (tv_temp);
|
|
|
elapsed_time_transfer = (double)microsec_transfer / 1.0e6;
|
|
|
@@ -1185,12 +1203,12 @@ check_http (void)
|
|
|
use_ssl ? "https" : "http", server_address,
|
|
|
server_port, server_url, (int)pagesize);
|
|
|
|
|
|
- /* find status line ( 200 OK HTTP/1.0 ) and null-terminate it */
|
|
|
+ /* find status line and null-terminate it */
|
|
|
page += (size_t) strcspn (page, "\r\n");
|
|
|
- save_char = *page;
|
|
|
- *page = '\0';
|
|
|
- status_line = strdup(pos);
|
|
|
- *page = save_char;
|
|
|
+ save_char = *page;
|
|
|
+ *page = '\0';
|
|
|
+ status_line = strdup(pos);
|
|
|
+ *page = save_char;
|
|
|
pos = page;
|
|
|
|
|
|
strip (status_line);
|
|
|
@@ -1200,7 +1218,7 @@ check_http (void)
|
|
|
/* find header info and null-terminate it */
|
|
|
header = page;
|
|
|
for (;;) {
|
|
|
- if (!strncmp(page, "\r\n\r\n", 4) || !strncmp(page, "\n\n", 2))
|
|
|
+ if (!*page || !strncmp(page, "\r\n\r\n", 4) || !strncmp(page, "\n\n", 2))
|
|
|
break;
|
|
|
while (*page == '\r' || *page == '\n') { ++page; }
|
|
|
page += (size_t) strcspn (page, "\r\n");
|
|
|
@@ -1229,8 +1247,7 @@ check_http (void)
|
|
|
server_port, status_line);
|
|
|
bad_response = TRUE;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
/* Bypass normal status line check if server_expect was set by user and not default */
|
|
|
/* NOTE: After this if/else block msg *MUST* be an asprintf-allocated string */
|
|
|
if ( !bad_response ) {
|
|
|
@@ -1247,7 +1264,6 @@ check_http (void)
|
|
|
/* HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT */
|
|
|
/* Status-Code = 3 DIGITS */
|
|
|
|
|
|
- space_code = strchr (status_line, ' ');
|
|
|
status_code = strchr (status_line, ' ') + sizeof (char);
|
|
|
if (strspn (status_code, "1234567890") != 3)
|
|
|
die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status Line (%s)\n"), status_line);
|
|
|
@@ -1262,12 +1278,14 @@ check_http (void)
|
|
|
/* server errors result in a critical state */
|
|
|
else if (http_status >= 500) {
|
|
|
xasprintf (&msg, _("%s%s - "), msg, status_line);
|
|
|
- result = STATE_CRITICAL;
|
|
|
+ if (bad_response || !server_expect_yn)
|
|
|
+ result = STATE_CRITICAL;
|
|
|
}
|
|
|
/* client errors result in a warning state */
|
|
|
else if (http_status >= 400) {
|
|
|
xasprintf (&msg, _("%s%s - "), msg, status_line);
|
|
|
- result = max_state_alt(STATE_WARNING, result);
|
|
|
+ if (bad_response || !server_expect_yn)
|
|
|
+ result = max_state_alt(STATE_WARNING, result);
|
|
|
}
|
|
|
/* check redirected page if specified */
|
|
|
else if (http_status >= 300) {
|
|
|
@@ -1662,6 +1680,10 @@ print_help (void)
|
|
|
printf (" %s\n", _("1.2 = TLSv1.2). With a '+' suffix, newer versions are also accepted."));
|
|
|
printf (" %s\n", "--sni");
|
|
|
printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
|
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
+ printf (" %s\n", "--verify-host");
|
|
|
+ printf (" %s\n", _("Verify SSL certificate is for the -H hostname (with --sni and -S)"));
|
|
|
+#endif
|
|
|
printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
|
|
|
printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
|
|
|
printf (" %s\n", _("(when this option is used the URL is not checked.)"));
|
|
|
@@ -1796,6 +1818,11 @@ print_usage (void)
|
|
|
printf (" [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport>]\n");
|
|
|
printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
|
|
|
printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
|
|
|
- printf (" [-A string] [-k string] [-S <version>] [--sni] [-C <warn_age>[,<crit_age>]]\n");
|
|
|
- printf (" [-T <content-type>] [-j method]\n");
|
|
|
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
+ printf (" [-A string] [-k string] [-S <version>] [--sni] [--verify-host]\n");
|
|
|
+ printf (" [-C <warn_age>[,<crit_age>]] [-T <content-type>] [-j method]\n");
|
|
|
+#else
|
|
|
+ printf (" [-A string] [-k string] [-S <version>] [--sni] [-C <warn_age>[,<crit_age>]]\n");
|
|
|
+ printf (" [-T <content-type>] [-j method]\n");
|
|
|
+#endif
|
|
|
}
|