New upstream version 2.3.2

This commit is contained in:
Jan Wagner 2022-10-19 17:24:24 +02:00
parent 09f4277f49
commit 21323d25dd
104 changed files with 34386 additions and 7430 deletions

View file

@ -55,18 +55,24 @@ const char *email = "devel@monitoring-plugins.org";
#include <arpa/inet.h>
#if defined(HAVE_SSL) && defined(USE_OPENSSL)
#include <openssl/opensslv.h>
#endif
#include <netdb.h>
#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
#define DEFAULT_BUFFER_SIZE 2048
#define DEFAULT_SERVER_URL "/"
#define HTTP_EXPECT "HTTP/"
#define DEFAULT_MAX_REDIRS 15
#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
enum {
MAX_IPV4_HOSTLENGTH = 255,
HTTP_PORT = 80,
HTTPS_PORT = 443,
MAX_PORT = 65535
MAX_PORT = 65535,
DEFAULT_MAX_REDIRS = 15
};
enum {
@ -187,6 +193,7 @@ int followsticky = STICKY_NONE;
int use_ssl = FALSE;
int use_sni = TRUE;
int check_cert = FALSE;
int continue_after_check_cert = FALSE;
typedef union {
struct curl_slist* to_info;
struct curl_certinfo* to_certinfo;
@ -206,6 +213,7 @@ int maximum_age = -1;
int address_family = AF_UNSPEC;
curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
int curl_http_version = CURL_HTTP_VERSION_NONE;
int automatic_decompression = FALSE;
int process_arguments (int, char**);
void handle_curl_option_return_code (CURLcode res, const char* option);
@ -285,6 +293,20 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
* TODO: is the last certificate always the server certificate?
*/
cert = X509_STORE_CTX_get_current_cert(x509_ctx);
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
X509_up_ref(cert);
#endif
if (verbose>=2) {
puts("* SSL verify callback with certificate:");
X509_NAME *subject, *issuer;
printf("* issuer:\n");
issuer = X509_get_issuer_name( cert );
X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
printf("* curl verify_callback:\n* subject:\n");
subject = X509_get_subject_name( cert );
X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
puts("");
}
return 1;
}
@ -350,6 +372,46 @@ handle_curl_option_return_code (CURLcode res, const char* option)
}
}
int
lookup_host (const char *host, char *buf, size_t buflen)
{
struct addrinfo hints, *res, *result;
int errcode;
void *ptr;
memset (&hints, 0, sizeof (hints));
hints.ai_family = address_family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;
errcode = getaddrinfo (host, NULL, &hints, &result);
if (errcode != 0)
return errcode;
res = result;
while (res) {
inet_ntop (res->ai_family, res->ai_addr->sa_data, buf, buflen);
switch (res->ai_family) {
case AF_INET:
ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
break;
case AF_INET6:
ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
break;
}
inet_ntop (res->ai_family, ptr, buf, buflen);
if (verbose >= 1)
printf ("* getaddrinfo IPv%d address: %s\n",
res->ai_family == PF_INET6 ? 6 : 4, buf);
res = res->ai_next;
}
freeaddrinfo(result);
return 0;
}
int
check_http (void)
{
@ -357,6 +419,9 @@ check_http (void)
int page_len = 0;
int i;
char *force_host_header = NULL;
struct curl_slist *host = NULL;
char addrstr[100];
char dnscache[DEFAULT_BUFFER_SIZE];
/* initialize curl */
if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK)
@ -371,6 +436,13 @@ check_http (void)
/* print everything on stdout like check_http would do */
handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
if (automatic_decompression)
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
#else
handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
/* initialize buffer for body of the answer */
if (curlhelp_initwritebuffer(&body_buf) < 0)
die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
@ -392,9 +464,12 @@ check_http (void)
// fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy
if(use_ssl && host_name != NULL) {
struct curl_slist *host = NULL;
char dnscache[DEFAULT_BUFFER_SIZE];
snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, server_address);
if ( (res=lookup_host (server_address, addrstr, 100)) != 0) {
snprintf (msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
server_address, res, gai_strerror (res));
die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
}
snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
host = curl_slist_append(NULL, dnscache);
curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
if (verbose>=1)
@ -680,7 +755,9 @@ check_http (void)
* and we actually have OpenSSL in the monitoring tools
*/
result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
return result;
if (continue_after_check_cert == FALSE) {
return result;
}
#else /* USE_OPENSSL */
die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
#endif /* USE_OPENSSL */
@ -720,13 +797,17 @@ GOT_FIRST_CERT:
}
BIO_free (cert_BIO);
result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
return result;
if (continue_after_check_cert == FALSE) {
return result;
}
#else /* USE_OPENSSL */
/* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
* so we use the libcurl CURLINFO data
*/
result = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
return result;
if (continue_after_check_cert == FALSE) {
return result;
}
#endif /* USE_OPENSSL */
} else {
snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"),
@ -959,8 +1040,8 @@ char*
uri_string (const UriTextRangeA range, char* buf, size_t buflen)
{
if (!range.first) return "(null)";
strncpy (buf, range.first, max (buflen, range.afterLast - range.first));
buf[max (buflen, range.afterLast - range.first)] = '\0';
strncpy (buf, range.first, max (buflen-1, range.afterLast - range.first));
buf[max (buflen-1, range.afterLast - range.first)] = '\0';
buf[range.afterLast - range.first] = '\0';
return buf;
}
@ -980,7 +1061,7 @@ redir (curlhelp_write_curlbuf* header_buf)
char *new_url;
int res = phr_parse_response (header_buf->buf, header_buf->buflen,
&status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
&status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
headers, &nof_headers, 0);
location = get_header_value (headers, nof_headers, "location");
@ -1080,8 +1161,8 @@ redir (curlhelp_write_curlbuf* header_buf)
!strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
(host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) &&
!strcmp(server_url, new_url))
die (STATE_WARNING,
_("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
die (STATE_CRITICAL,
_("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : ""));
/* set new values for redirected request */
@ -1136,8 +1217,11 @@ process_arguments (int argc, char **argv)
enum {
INVERT_REGEX = CHAR_MAX + 1,
SNI_OPTION,
MAX_REDIRS_OPTION,
CONTINUE_AFTER_CHECK_CERT,
CA_CERT_OPTION,
HTTP_VERSION_OPTION
HTTP_VERSION_OPTION,
AUTOMATIC_DECOMPRESSION
};
int option = 0;
@ -1168,6 +1252,7 @@ process_arguments (int argc, char **argv)
{"private-key", required_argument, 0, 'K'},
{"ca-cert", required_argument, 0, CA_CERT_OPTION},
{"verify-cert", no_argument, 0, 'D'},
{"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
{"useragent", required_argument, 0, 'A'},
{"header", required_argument, 0, 'k'},
{"no-body", no_argument, 0, 'N'},
@ -1179,7 +1264,9 @@ process_arguments (int argc, char **argv)
{"use-ipv6", no_argument, 0, '6'},
{"extended-perfdata", no_argument, 0, 'E'},
{"show-body", no_argument, 0, 'B'},
{"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
{"http-version", required_argument, 0, HTTP_VERSION_OPTION},
{"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
{0, 0, 0, 0}
};
@ -1324,6 +1411,11 @@ process_arguments (int argc, char **argv)
}
check_cert = TRUE;
goto enable_ssl;
#endif
case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
#ifdef HAVE_SSL
continue_after_check_cert = TRUE;
break;
#endif
case 'J': /* use client certificate */
#ifdef LIBCURL_FEATURE_SSL
@ -1346,7 +1438,7 @@ process_arguments (int argc, char **argv)
#ifdef LIBCURL_FEATURE_SSL
case 'D': /* verify peer certificate & host */
verify_peer_and_host = TRUE;
goto enable_ssl;
break;
#endif
case 'S': /* use SSL */
#ifdef LIBCURL_FEATURE_SSL
@ -1436,6 +1528,13 @@ process_arguments (int argc, char **argv)
use_sni = TRUE;
break;
#endif /* LIBCURL_FEATURE_SSL */
case MAX_REDIRS_OPTION:
if (!is_intnonneg (optarg))
usage2 (_("Invalid max_redirs count"), optarg);
else {
max_depth = atoi (optarg);
}
break;
case 'f': /* onredirect */
if (!strcmp (optarg, "ok"))
onredirect = STATE_OK;
@ -1571,6 +1670,9 @@ process_arguments (int argc, char **argv)
exit (STATE_WARNING);
}
break;
case AUTOMATIC_DECOMPRESSION:
automatic_decompression = TRUE;
break;
case '?':
/* print short usage statement if args not parsable */
usage5 ();
@ -1712,7 +1814,11 @@ print_help (void)
#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.)"));
printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use"));
printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
printf (" %s\n", "--continue-after-certificate");
printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
printf (" %s\n", _("Does nothing unless -C is used."));
printf (" %s\n", "-J, --client-cert=FILE");
printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
printf (" %s\n", _("to be used in establishing the SSL session"));
@ -1775,12 +1881,17 @@ print_help (void)
printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
printf (" %s\n", _("follow uses the old redirection algorithm of check_http."));
printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
printf (" %s\n", "--max-redirs=INTEGER");
printf (" %s", _("Maximal number of redirects (default: "));
printf ("%d)\n", DEFAULT_MAX_REDIRS);
printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
printf ("\n");
printf (" %s\n", "--http-version=VERSION");
printf (" %s\n", _("Connect via specific HTTP protocol."));
printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
printf (" %s\n", "--enable-automatic-decompression");
printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
printf ("\n");
printf (UT_WARN_CRIT);
@ -1995,7 +2106,7 @@ curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line)
char *first_line_buf;
/* find last start of a new header */
start = strrstr2 (buf, "\r\nHTTP");
start = strrstr2 (buf, "\r\nHTTP/");
if (start != NULL) {
start += 2;
buf = start;
@ -2107,7 +2218,7 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
size_t msglen;
int res = phr_parse_response (header_buf->buf, header_buf->buflen,
&status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
&status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
headers, &nof_headers, 0);
server_date = get_header_value (headers, nof_headers, "date");
@ -2165,7 +2276,7 @@ get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_wri
curlhelp_statusline status_line;
int res = phr_parse_response (header_buf->buf, header_buf->buflen,
&status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
&status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
headers, &nof_headers, 0);
content_length_s = get_header_value (headers, nof_headers, "content-length");