From 99206dab7aa272e5c16c672dca81e6044ac7a4eb Mon Sep 17 00:00:00 2001
From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>
Date: Thu, 11 Sep 2025 13:44:55 +0200
Subject: check_curl: refactoring to modularize code
---
plugins/check_curl.c | 1055 +++++++++++++++++++++--------------------
plugins/check_curl.d/config.h | 78 +--
2 files changed, 594 insertions(+), 539 deletions(-)
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index 485a8744..f3cf7422 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -129,6 +129,9 @@ typedef struct {
bool put_buf_initialized;
curlhelp_read_curlbuf put_buf;
CURL *curl;
+
+ struct curl_slist *header_list;
+ struct curl_slist *host;
} check_curl_global_state;
static char errbuf[MAX_INPUT_BUFFER];
@@ -152,8 +155,7 @@ static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*
static void handle_curl_option_return_code(CURLcode res, const char *option);
static mp_state_enum check_http(check_curl_config /*config*/, check_curl_working_state workingState,
- int redir_depth, struct curl_slist *header_list,
- check_curl_global_state global_state);
+ int redir_depth);
typedef struct {
int redir_depth;
@@ -162,8 +164,7 @@ typedef struct {
check_curl_global_state curl_state;
} redir_wrapper;
static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/,
- int redir_depth, check_curl_working_state working_state,
- check_curl_global_state global_state);
+ int redir_depth, check_curl_working_state working_state);
static char *perfd_time(double elapsed_time, thresholds * /*thlds*/, long /*socket_timeout*/);
static char *perfd_time_connect(double elapsed_time_connect, long /*socket_timeout*/);
@@ -172,371 +173,169 @@ static char *perfd_time_firstbyte(double elapsed_time_firstbyte, long /*socket_t
static char *perfd_time_headers(double elapsed_time_headers, long /*socket_timeout*/);
static char *perfd_time_transfer(double elapsed_time_transfer, long /*socket_timeout*/);
static char *perfd_size(size_t page_len, int /*min_page_len*/);
+
static void print_help(void);
void print_usage(void);
+
static void print_curl_version(void);
+
static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/);
static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
void * /*stream*/);
static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
+
static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/,
size_t /*datalen*/);
static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
void * /*stream*/);
static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
+
static curlhelp_ssl_library curlhelp_get_ssl_library(void);
static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
+
int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
+
static char *get_header_value(const struct phr_header *headers, size_t nof_headers,
const char *header);
static mp_state_enum check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/,
char (*msg)[DEFAULT_BUFFER_SIZE], int /*maximum_age*/);
static size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
const curlhelp_write_curlbuf *body_buf);
+static int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family);
-#if defined(HAVE_SSL) && defined(USE_OPENSSL)
-mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
- int days_till_exp_crit);
-#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
-
-static void test_file(char * /*path*/);
-
-int main(int argc, char **argv) {
- setlocale(LC_ALL, "");
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-
- /* Parse extra opts if any */
- argv = np_extra_opts(&argc, argv, progname);
-
- /* parse arguments */
- check_curl_config_wrapper tmp_config = process_arguments(argc, argv);
- if (tmp_config.errorcode == ERROR) {
- usage4(_("Could not parse arguments"));
- }
-
- const check_curl_config config = tmp_config.config;
-
- /* set defaults */
- if (strlen(config.user_agent) == 0) {
- snprintf(config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
- progname, NP_VERSION, VERSION, curl_version());
- }
-
- if (config.display_html) {
- printf("",
- config.initial_config.use_ssl ? "https" : "http",
- config.initial_config.host_name ? config.initial_config.host_name
- : config.initial_config.server_address,
- config.initial_config.virtualPort ? config.initial_config.virtualPort
- : config.initial_config.serverPort,
- config.initial_config.server_url);
- }
-
- check_curl_global_state global_state = {
- .curl_global_initialized = false,
- .curl_easy_initialized = false,
- .body_buf_initialized = false,
- .body_buf = {},
- .header_buf_initialized = false,
- .header_buf = {},
- .status_line_initialized = false,
- .status_line = {},
- .put_buf_initialized = false,
- .put_buf = {},
- .curl = NULL,
- };
-
- check_curl_working_state working_state = config.initial_config;
- struct curl_slist *header_list = NULL;
+// typedef struct {
+// int errorcode;
+// } check_curl_evaluation_wrapper;
+// check_curl_evaluation_wrapper check_curl_evaluate(check_curl_config config,
+// mp_check overall[static 1]) {}
- exit((int)check_http(config, working_state, 0, header_list, global_state));
-}
+CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm);
-#ifdef HAVE_SSL
-# ifdef USE_OPENSSL
-int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
- (void)preverify_ok;
- /* TODO: we get all certificates of the chain, so which ones
- * should we test?
- * 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:");
- printf("* issuer:\n");
- X509_NAME *issuer = X509_get_issuer_name(cert);
- X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
- printf("* curl verify_callback:\n* subject:\n");
- X509_NAME *subject = X509_get_subject_name(cert);
- X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
- puts("");
- }
- return 1;
-}
-
-CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
- (void)curl; // ignore unused parameter
- (void)parm; // ignore unused parameter
- if (add_sslctx_verify_fun) {
- SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
- }
-
- // workaround for issue:
- // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
- // see discussion https://github.com/openssl/openssl/discussions/22690
-# ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
- SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
-# endif
-
- return CURLE_OK;
-}
-# endif /* USE_OPENSSL */
-#endif /* HAVE_SSL */
-
-/* returns a string "HTTP/1.x" or "HTTP/2" */
-static char *string_statuscode(int major, int minor) {
- static char buf[10];
-
- switch (major) {
- case 1:
- snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
- break;
- case 2:
- case 3:
- snprintf(buf, sizeof(buf), "HTTP/%d", major);
- break;
- default:
- /* assuming here HTTP/N with N>=4 */
- snprintf(buf, sizeof(buf), "HTTP/%d", major);
- break;
- }
-
- return buf;
-}
-
-/* Checks if the server 'reply' is one of the expected 'statuscodes' */
-static bool expected_statuscode(const char *reply, const char *statuscodes) {
- char *expected;
-
- if ((expected = strdup(statuscodes)) == NULL) {
- die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
- }
-
- bool result = false;
- for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
- if (strstr(reply, code) != NULL) {
- result = true;
- break;
- }
- }
-
- free(expected);
- return result;
-}
-
-void handle_curl_option_return_code(CURLcode res, const char *option) {
- if (res != CURLE_OK) {
- snprintf(msg, DEFAULT_BUFFER_SIZE,
- _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res,
- curl_easy_strerror(res));
- die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
- }
-}
-
-int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) {
- struct addrinfo hints = {
- .ai_family = addr_family,
- .ai_socktype = SOCK_STREAM,
- .ai_flags = AI_CANONNAME,
+typedef struct {
+ int errorcode;
+ check_curl_global_state curl_state;
+} check_curl_configure_curl_wrapper;
+check_curl_configure_curl_wrapper
+check_curl_configure_curl(const check_curl_static_curl_config config,
+ check_curl_working_state working_state, bool check_cert,
+ bool on_redirect_dependent, int follow_method, int max_depth) {
+ check_curl_configure_curl_wrapper result = {
+ .errorcode = OK,
+ .curl_state =
+ {
+ .curl_global_initialized = false,
+ .curl_easy_initialized = false,
+ .curl = NULL,
+
+ .body_buf_initialized = false,
+ .body_buf = {},
+ .header_buf_initialized = false,
+ .header_buf = {},
+ .status_line_initialized = false,
+ .status_line = {},
+ .put_buf_initialized = false,
+ .put_buf = {},
+
+ .header_list = NULL,
+ .host = NULL,
+ },
};
- struct addrinfo *result;
- int errcode = getaddrinfo(host, NULL, &hints, &result);
- if (errcode != 0) {
- return errcode;
- }
-
- strcpy(buf, "");
- struct addrinfo *res = result;
-
- size_t buflen_remaining = buflen - 1;
- size_t addrstr_len;
- char addrstr[100];
- void *ptr = {0};
- while (res) {
- 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, addrstr, 100);
- if (verbose >= 1) {
- printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4,
- addrstr);
- }
-
- // Append all IPs to buf as a comma-separated string
- addrstr_len = strlen(addrstr);
- if (buflen_remaining > addrstr_len + 1) {
- if (buf[0] != '\0') {
- strncat(buf, ",", buflen_remaining);
- buflen_remaining -= 1;
- }
- strncat(buf, addrstr, buflen_remaining);
- buflen_remaining -= addrstr_len;
- }
-
- res = res->ai_next;
- }
-
- freeaddrinfo(result);
-
- return 0;
-}
-
-static void cleanup(check_curl_global_state global_state) {
- if (global_state.status_line_initialized) {
- curlhelp_free_statusline(&global_state.status_line);
- }
- global_state.status_line_initialized = false;
-
- if (global_state.curl_easy_initialized) {
- curl_easy_cleanup(global_state.curl);
- }
- global_state.curl_easy_initialized = false;
-
- if (global_state.curl_global_initialized) {
- curl_global_cleanup();
- }
- global_state.curl_global_initialized = false;
-
- if (global_state.body_buf_initialized) {
- curlhelp_freewritebuffer(&global_state.body_buf);
- }
- global_state.body_buf_initialized = false;
-
- if (global_state.header_buf_initialized) {
- curlhelp_freewritebuffer(&global_state.header_buf);
- }
- global_state.header_buf_initialized = false;
-
- if (global_state.put_buf_initialized) {
- curlhelp_freereadbuffer(&global_state.put_buf);
- }
- global_state.put_buf_initialized = false;
-}
-
-mp_state_enum check_http(const check_curl_config config, check_curl_working_state workingState,
- int redir_depth, struct curl_slist *header_list,
- check_curl_global_state global_state) {
-
- // =======================
- // Initialisation for curl
- // =======================
- /* initialize curl */
if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
}
- global_state.curl_global_initialized = true;
+ result.curl_state.curl_global_initialized = true;
- if ((global_state.curl = curl_easy_init()) == NULL) {
+ if ((result.curl_state.curl = curl_easy_init()) == NULL) {
die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
}
- global_state.curl_easy_initialized = true;
+ result.curl_state.curl_easy_initialized = true;
if (verbose >= 1) {
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_VERBOSE, 1),
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1),
"CURLOPT_VERBOSE");
}
-
/* print everything on stdout like check_http would do */
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_STDERR, stdout),
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_STDERR, stdout),
"CURLOPT_STDERR");
if (config.automatic_decompression) {
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_ACCEPT_ENCODING, ""),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_ACCEPT_ENCODING, ""),
"CURLOPT_ACCEPT_ENCODING");
#else
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ENCODING, ""),
- "CURLOPT_ENCODING");
+ handle_curl_option_return_code(
+ curl_easy_setopt(result.curl_state.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(&global_state.body_buf) < 0) {
+ if (curlhelp_initwritebuffer(&result.curl_state.body_buf) < 0) {
die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
}
- global_state.body_buf_initialized = true;
- handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_write_callback),
- "CURLOPT_WRITEFUNCTION");
- handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_WRITEDATA, (void *)&global_state.body_buf),
- "CURLOPT_WRITEDATA");
+ result.curl_state.body_buf_initialized = true;
+
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEFUNCTION,
+ curlhelp_buffer_write_callback),
+ "CURLOPT_WRITEFUNCTION");
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEDATA,
+ (void *)&result.curl_state.body_buf),
+ "CURLOPT_WRITEDATA");
/* initialize buffer for header of the answer */
- if (curlhelp_initwritebuffer(&global_state.header_buf) < 0) {
+ if (curlhelp_initwritebuffer(&result.curl_state.header_buf) < 0) {
die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
}
- global_state.header_buf_initialized = true;
+ result.curl_state.header_buf_initialized = true;
- handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_write_callback),
- "CURLOPT_HEADERFUNCTION");
- handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_WRITEHEADER, (void *)&global_state.header_buf),
- "CURLOPT_WRITEHEADER");
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_HEADERFUNCTION,
+ curlhelp_buffer_write_callback),
+ "CURLOPT_HEADERFUNCTION");
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEHEADER,
+ (void *)&result.curl_state.header_buf),
+ "CURLOPT_WRITEHEADER");
/* set the error buffer */
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ERRORBUFFER, errbuf),
- "CURLOPT_ERRORBUFFER");
+ handle_curl_option_return_code(
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_ERRORBUFFER, errbuf),
+ "CURLOPT_ERRORBUFFER");
/* set timeouts */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout),
"CURLOPT_CONNECTTIMEOUT");
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_TIMEOUT, config.socket_timeout),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_TIMEOUT, config.socket_timeout),
"CURLOPT_TIMEOUT");
/* enable haproxy protocol */
if (config.haproxy_protocol) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L),
"CURLOPT_HAPROXYPROTOCOL");
}
// 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
- struct curl_slist *host = NULL;
char dnscache[DEFAULT_BUFFER_SIZE];
char addrstr[DEFAULT_BUFFER_SIZE / 2];
- if (workingState.use_ssl && workingState.host_name != NULL) {
+ if (working_state.use_ssl && working_state.host_name != NULL) {
int res;
- if ((res = lookup_host(workingState.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2,
+ if ((res = lookup_host(working_state.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2,
config.sin_family)) != 0) {
snprintf(msg, DEFAULT_BUFFER_SIZE,
_("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
- workingState.server_address, res, gai_strerror(res));
+ working_state.server_address, res, gai_strerror(res));
die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
}
- snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", workingState.host_name,
- workingState.serverPort, addrstr);
- host = curl_slist_append(NULL, dnscache);
- curl_easy_setopt(global_state.curl, CURLOPT_RESOLVE, host);
+ snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", working_state.host_name,
+ working_state.serverPort, addrstr);
+ result.curl_state.host = curl_slist_append(NULL, dnscache);
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_RESOLVE, result.curl_state.host);
if (verbose >= 1) {
printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
}
@@ -544,72 +343,71 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
// If server_address is an IPv6 address it must be surround by square brackets
struct in6_addr tmp_in_addr;
- if (inet_pton(AF_INET6, workingState.server_address, &tmp_in_addr) == 1) {
- char *new_server_address = malloc(strlen(workingState.server_address) + 3);
+ if (inet_pton(AF_INET6, working_state.server_address, &tmp_in_addr) == 1) {
+ char *new_server_address = malloc(strlen(working_state.server_address) + 3);
if (new_server_address == NULL) {
die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
}
- snprintf(new_server_address, strlen(workingState.server_address) + 3, "[%s]",
- workingState.server_address);
- free(workingState.server_address);
- workingState.server_address = new_server_address;
+ snprintf(new_server_address, strlen(working_state.server_address) + 3, "[%s]",
+ working_state.server_address);
+ working_state.server_address = new_server_address;
}
/* compose URL: use the address we want to connect to, set Host: header later */
char url[DEFAULT_BUFFER_SIZE];
- snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", workingState.use_ssl ? "https" : "http",
- (workingState.use_ssl & (workingState.host_name != NULL))
- ? workingState.host_name
- : workingState.server_address,
- workingState.serverPort, workingState.server_url);
+ snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", working_state.use_ssl ? "https" : "http",
+ (working_state.use_ssl & (working_state.host_name != NULL))
+ ? working_state.host_name
+ : working_state.server_address,
+ working_state.serverPort, working_state.server_url);
if (verbose >= 1) {
printf("* curl CURLOPT_URL: %s\n", url);
}
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_URL, url),
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, url),
"CURLOPT_URL");
/* extract proxy information for legacy proxy https requests */
- if (!strcmp(workingState.http_method, "CONNECT") ||
- strstr(workingState.server_url, "http") == workingState.server_url) {
+ if (!strcmp(working_state.http_method, "CONNECT") ||
+ strstr(working_state.server_url, "http") == working_state.server_url) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_PROXY, workingState.server_address),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXY, working_state.server_address),
"CURLOPT_PROXY");
- handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_PROXYPORT, (long)workingState.serverPort),
- "CURLOPT_PROXYPORT");
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYPORT,
+ (long)working_state.serverPort),
+ "CURLOPT_PROXYPORT");
if (verbose >= 2) {
- printf("* curl CURLOPT_PROXY: %s:%d\n", workingState.server_address,
- workingState.serverPort);
+ printf("* curl CURLOPT_PROXY: %s:%d\n", working_state.server_address,
+ working_state.serverPort);
}
- workingState.http_method = "GET";
+ working_state.http_method = "GET";
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_URL, workingState.server_url),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, working_state.server_url),
"CURLOPT_URL");
}
/* disable body for HEAD request */
- if (workingState.http_method && !strcmp(workingState.http_method, "HEAD")) {
- workingState.no_body = true;
+ if (working_state.http_method && !strcmp(working_state.http_method, "HEAD")) {
+ working_state.no_body = true;
}
/* set HTTP protocol version */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version),
"CURLOPT_HTTP_VERSION");
/* set HTTP method */
- if (workingState.http_method) {
- if (!strcmp(workingState.http_method, "POST")) {
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POST, 1),
- "CURLOPT_POST");
- } else if (!strcmp(workingState.http_method, "PUT")) {
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_UPLOAD, 1),
- "CURLOPT_UPLOAD");
+ if (working_state.http_method) {
+ if (!strcmp(working_state.http_method, "POST")) {
+ handle_curl_option_return_code(
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1), "CURLOPT_POST");
+ } else if (!strcmp(working_state.http_method, "PUT")) {
+ handle_curl_option_return_code(
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
} else {
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl,
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
CURLOPT_CUSTOMREQUEST,
- workingState.http_method),
+ working_state.http_method),
"CURLOPT_CUSTOMREQUEST");
}
}
@@ -627,67 +425,71 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
/* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in
* anyway */
char http_header[DEFAULT_BUFFER_SIZE];
- if (workingState.host_name != NULL && force_host_header == NULL) {
- if ((workingState.virtualPort != HTTP_PORT && !workingState.use_ssl) ||
- (workingState.virtualPort != HTTPS_PORT && workingState.use_ssl)) {
- snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", workingState.host_name,
- workingState.virtualPort);
+ if (working_state.host_name != NULL && force_host_header == NULL) {
+ if ((working_state.virtualPort != HTTP_PORT && !working_state.use_ssl) ||
+ (working_state.virtualPort != HTTPS_PORT && working_state.use_ssl)) {
+ snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", working_state.host_name,
+ working_state.virtualPort);
} else {
- snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", workingState.host_name);
+ snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", working_state.host_name);
}
- header_list = curl_slist_append(header_list, http_header);
+ result.curl_state.header_list =
+ curl_slist_append(result.curl_state.header_list, http_header);
}
/* always close connection, be nice to servers */
snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
- header_list = curl_slist_append(header_list, http_header);
+ result.curl_state.header_list = curl_slist_append(result.curl_state.header_list, http_header);
/* attach additional headers supplied by the user */
/* optionally send any other header tag */
if (config.http_opt_headers_count) {
for (size_t i = 0; i < config.http_opt_headers_count; i++) {
- header_list = curl_slist_append(header_list, config.http_opt_headers[i]);
+ result.curl_state.header_list =
+ curl_slist_append(result.curl_state.header_list, config.http_opt_headers[i]);
}
}
/* set HTTP headers */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER");
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTPHEADER, result.curl_state.header_list),
+ "CURLOPT_HTTPHEADER");
#ifdef LIBCURL_FEATURE_SSL
/* set SSL version, warn about insecure or unsupported versions */
- if (workingState.use_ssl) {
+ if (working_state.use_ssl) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSLVERSION, config.ssl_version),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLVERSION, config.ssl_version),
"CURLOPT_SSLVERSION");
}
/* client certificate and key to present to server (SSL) */
if (config.client_cert) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSLCERT, config.client_cert),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLCERT, config.client_cert),
"CURLOPT_SSLCERT");
}
if (config.client_privkey) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSLKEY, config.client_privkey),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLKEY, config.client_privkey),
"CURLOPT_SSLKEY");
}
if (config.ca_cert) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_CAINFO, config.ca_cert), "CURLOPT_CAINFO");
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_CAINFO, config.ca_cert),
+ "CURLOPT_CAINFO");
}
if (config.ca_cert || config.verify_peer_and_host) {
/* per default if we have a CA verify both the peer and the
* hostname in the certificate, can be switched off later */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 1),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1),
"CURLOPT_SSL_VERIFYPEER");
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 2),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2),
"CURLOPT_SSL_VERIFYHOST");
} else {
/* backward-compatible behaviour, be tolerant in checks
@@ -695,10 +497,10 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
* to be less tolerant about ssl verfications
*/
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 0),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0),
"CURLOPT_SSL_VERIFYPEER");
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 0),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0),
"CURLOPT_SSL_VERIFYHOST");
}
@@ -706,7 +508,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
curlhelp_ssl_library ssl_library = curlhelp_get_ssl_library();
/* try hard to get a stack of certificates to verify against */
- if (config.check_cert) {
+ if (check_cert) {
# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
/* inform curl to report back certificates */
switch (ssl_library) {
@@ -722,14 +524,14 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
/* libcurl is built with OpenSSL, monitoring plugins, so falling
* back to manually extracting certificate information */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
break;
case CURLHELP_SSL_LIBRARY_NSS:
# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
/* NSS: support for CERTINFO is implemented since 7.34.0 */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
die(STATE_CRITICAL,
"HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
@@ -742,7 +544,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
/* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
die(STATE_CRITICAL,
"HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
@@ -775,10 +577,10 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
# if LIBCURL_VERSION_NUM >= \
MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
// ssl ctx function is not available with all ssl backends
- if (curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) !=
+ if (curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) !=
CURLE_UNKNOWN_OPTION) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun),
"CURLOPT_SSL_CTX_FUNCTION");
}
# endif
@@ -786,23 +588,22 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
/* set default or user-given user agent identification */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_USERAGENT, config.user_agent),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_USERAGENT, config.user_agent),
"CURLOPT_USERAGENT");
/* proxy-authentication */
if (strcmp(config.proxy_auth, "")) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth),
"CURLOPT_PROXYUSERPWD");
}
/* authentication */
if (strcmp(config.user_auth, "")) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_USERPWD, config.user_auth),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_USERPWD, config.user_auth),
"CURLOPT_USERPWD");
}
-
/* TODO: parameter auth method, bitfield of following methods:
* CURLAUTH_BASIC (default)
* CURLAUTH_DIGEST
@@ -820,26 +621,26 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
*/
/* handle redirections */
- if (config.onredirect == STATE_DEPENDENT) {
- if (config.followmethod == FOLLOW_LIBCURL) {
+ if (on_redirect_dependent) {
+ if (follow_method == FOLLOW_LIBCURL) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_FOLLOWLOCATION, 1),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1),
"CURLOPT_FOLLOWLOCATION");
/* default -1 is infinite, not good, could lead to zombie plugins!
Setting it to one bigger than maximal limit to handle errors nicely below
*/
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_MAXREDIRS, config.max_depth + 1),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_MAXREDIRS, max_depth + 1),
"CURLOPT_MAXREDIRS");
/* for now allow only http and https (we are a http(s) check plugin in the end) */
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
"CURLOPT_REDIR_PROTOCOLS_STR");
#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl,
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
CURLOPT_REDIR_PROTOCOLS,
CURLPROTO_HTTP | CURLPROTO_HTTPS),
"CURLOPT_REDIRECT_PROTOCOLS");
@@ -854,70 +655,72 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
option here is nice like for expected page size?
*/
} else {
- /* old style redirection is handled below */
+ /* old style redirection*/
}
}
-
/* no-body */
- if (workingState.no_body) {
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_NOBODY, 1),
+ if (working_state.no_body) {
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1),
"CURLOPT_NOBODY");
}
/* IPv4 or IPv6 forced DNS resolution */
if (config.sin_family == AF_UNSPEC) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
"CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
} else if (config.sin_family == AF_INET) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
"CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
}
#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
else if (config.sin_family == AF_INET6) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
"CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
}
#endif
/* either send http POST data (any data, not only POST)*/
- if (!strcmp(workingState.http_method, "POST") || !strcmp(workingState.http_method, "PUT")) {
+ if (!strcmp(working_state.http_method, "POST") || !strcmp(working_state.http_method, "PUT")) {
/* set content of payload for POST and PUT */
if (config.http_content_type) {
snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s",
config.http_content_type);
- header_list = curl_slist_append(header_list, http_header);
+ result.curl_state.header_list =
+ curl_slist_append(result.curl_state.header_list, http_header);
}
/* NULL indicates "HTTP Continue" in libcurl, provide an empty string
* in case of no POST/PUT data */
- if (!workingState.http_post_data) {
- workingState.http_post_data = "";
+ if (!working_state.http_post_data) {
+ working_state.http_post_data = "";
}
- if (!strcmp(workingState.http_method, "POST")) {
+
+ if (!strcmp(working_state.http_method, "POST")) {
/* POST method, set payload with CURLOPT_POSTFIELDS */
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POSTFIELDS,
- workingState.http_post_data),
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
+ CURLOPT_POSTFIELDS,
+ working_state.http_post_data),
"CURLOPT_POSTFIELDS");
- } else if (!strcmp(workingState.http_method, "PUT")) {
+ } else if (!strcmp(working_state.http_method, "PUT")) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_READFUNCTION,
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_READFUNCTION,
(curl_read_callback)curlhelp_buffer_read_callback),
"CURLOPT_READFUNCTION");
- if (curlhelp_initreadbuffer(&global_state.put_buf, workingState.http_post_data,
- strlen(workingState.http_post_data)) < 0) {
+ if (curlhelp_initreadbuffer(&result.curl_state.put_buf, working_state.http_post_data,
+ strlen(working_state.http_post_data)) < 0) {
die(STATE_UNKNOWN,
"HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
}
- global_state.put_buf_initialized = true;
-
- handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_READDATA,
- (void *)&global_state.put_buf),
+ result.curl_state.put_buf_initialized = true;
+ handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl,
+ CURLOPT_READDATA,
+ (void *)&result.curl_state.put_buf),
"CURLOPT_READDATA");
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_INFILESIZE,
- (curl_off_t)strlen(workingState.http_post_data)),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_INFILESIZE,
+ (curl_off_t)strlen(working_state.http_post_data)),
"CURLOPT_INFILESIZE");
}
}
@@ -927,35 +730,267 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
/* enable reading cookies from a file, and if the filename is an empty string, only
* enable the curl cookie engine */
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file),
"CURLOPT_COOKIEFILE");
/* now enable saving cookies to a file, but only if the filename is not an empty string,
* since writing it would fail */
if (*config.cookie_jar_file) {
handle_curl_option_return_code(
- curl_easy_setopt(global_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file),
+ curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file),
"CURLOPT_COOKIEJAR");
}
}
+ return result;
+}
+
+#if defined(HAVE_SSL) && defined(USE_OPENSSL)
+mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
+ int days_till_exp_crit);
+#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
+
+static void test_file(char * /*path*/);
+
+int main(int argc, char **argv) {
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ /* Parse extra opts if any */
+ argv = np_extra_opts(&argc, argv, progname);
+
+ /* parse arguments */
+ check_curl_config_wrapper tmp_config = process_arguments(argc, argv);
+ if (tmp_config.errorcode == ERROR) {
+ usage4(_("Could not parse arguments"));
+ }
+
+ const check_curl_config config = tmp_config.config;
+
+ if (config.display_html) {
+ printf("",
+ config.initial_config.use_ssl ? "https" : "http",
+ config.initial_config.host_name ? config.initial_config.host_name
+ : config.initial_config.server_address,
+ config.initial_config.virtualPort ? config.initial_config.virtualPort
+ : config.initial_config.serverPort,
+ config.initial_config.server_url);
+ }
+
+ check_curl_working_state working_state = config.initial_config;
+
+ exit((int)check_http(config, working_state, 0));
+}
+
+#ifdef HAVE_SSL
+# ifdef USE_OPENSSL
+int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
+ (void)preverify_ok;
+ /* TODO: we get all certificates of the chain, so which ones
+ * should we test?
+ * 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:");
+ printf("* issuer:\n");
+ X509_NAME *issuer = X509_get_issuer_name(cert);
+ X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
+ printf("* curl verify_callback:\n* subject:\n");
+ X509_NAME *subject = X509_get_subject_name(cert);
+ X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
+ puts("");
+ }
+ return 1;
+}
+
+CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
+ (void)curl; // ignore unused parameter
+ (void)parm; // ignore unused parameter
+ if (add_sslctx_verify_fun) {
+ SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
+ }
+
+ // workaround for issue:
+ // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
+ // see discussion https://github.com/openssl/openssl/discussions/22690
+# ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
+ SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
+# endif
+
+ return CURLE_OK;
+}
+# endif /* USE_OPENSSL */
+#endif /* HAVE_SSL */
+
+/* returns a string "HTTP/1.x" or "HTTP/2" */
+static char *string_statuscode(int major, int minor) {
+ static char buf[10];
+
+ switch (major) {
+ case 1:
+ snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
+ break;
+ case 2:
+ case 3:
+ snprintf(buf, sizeof(buf), "HTTP/%d", major);
+ break;
+ default:
+ /* assuming here HTTP/N with N>=4 */
+ snprintf(buf, sizeof(buf), "HTTP/%d", major);
+ break;
+ }
+
+ return buf;
+}
+
+/* Checks if the server 'reply' is one of the expected 'statuscodes' */
+static bool expected_statuscode(const char *reply, const char *statuscodes) {
+ char *expected;
+
+ if ((expected = strdup(statuscodes)) == NULL) {
+ die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
+ }
+
+ bool result = false;
+ for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
+ if (strstr(reply, code) != NULL) {
+ result = true;
+ break;
+ }
+ }
+
+ free(expected);
+ return result;
+}
+
+void handle_curl_option_return_code(CURLcode res, const char *option) {
+ if (res != CURLE_OK) {
+ snprintf(msg, DEFAULT_BUFFER_SIZE,
+ _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res,
+ curl_easy_strerror(res));
+ die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
+ }
+}
+
+int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) {
+ struct addrinfo hints = {
+ .ai_family = addr_family,
+ .ai_socktype = SOCK_STREAM,
+ .ai_flags = AI_CANONNAME,
+ };
+
+ struct addrinfo *result;
+ int errcode = getaddrinfo(host, NULL, &hints, &result);
+ if (errcode != 0) {
+ return errcode;
+ }
+
+ strcpy(buf, "");
+ struct addrinfo *res = result;
+
+ size_t buflen_remaining = buflen - 1;
+ size_t addrstr_len;
+ char addrstr[100];
+ void *ptr = {0};
+ while (res) {
+ 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, addrstr, 100);
+ if (verbose >= 1) {
+ printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4,
+ addrstr);
+ }
+
+ // Append all IPs to buf as a comma-separated string
+ addrstr_len = strlen(addrstr);
+ if (buflen_remaining > addrstr_len + 1) {
+ if (buf[0] != '\0') {
+ strncat(buf, ",", buflen_remaining);
+ buflen_remaining -= 1;
+ }
+ strncat(buf, addrstr, buflen_remaining);
+ buflen_remaining -= addrstr_len;
+ }
+
+ res = res->ai_next;
+ }
+
+ freeaddrinfo(result);
+
+ return 0;
+}
+
+static void cleanup(check_curl_global_state global_state) {
+ if (global_state.status_line_initialized) {
+ curlhelp_free_statusline(&global_state.status_line);
+ }
+ global_state.status_line_initialized = false;
+
+ if (global_state.curl_easy_initialized) {
+ curl_easy_cleanup(global_state.curl);
+ }
+ global_state.curl_easy_initialized = false;
+
+ if (global_state.curl_global_initialized) {
+ curl_global_cleanup();
+ }
+ global_state.curl_global_initialized = false;
+
+ if (global_state.body_buf_initialized) {
+ curlhelp_freewritebuffer(&global_state.body_buf);
+ }
+ global_state.body_buf_initialized = false;
+
+ if (global_state.header_buf_initialized) {
+ curlhelp_freewritebuffer(&global_state.header_buf);
+ }
+ global_state.header_buf_initialized = false;
+
+ if (global_state.put_buf_initialized) {
+ curlhelp_freereadbuffer(&global_state.put_buf);
+ }
+ global_state.put_buf_initialized = false;
+
+ if (global_state.header_list) {
+ curl_slist_free_all(global_state.header_list);
+ }
+
+ if (global_state.host) {
+ curl_slist_free_all(global_state.host);
+ }
+}
+
+mp_state_enum check_http(const check_curl_config config, check_curl_working_state workingState,
+ int redir_depth) {
+
+ // =======================
+ // Initialisation for curl
+ // =======================
+ check_curl_configure_curl_wrapper conf_curl_struct = check_curl_configure_curl(
+ config.curl_config, workingState, config.check_cert, config.on_redirect_dependent,
+ config.followmethod, config.max_depth);
+
+ check_curl_global_state curl_state = conf_curl_struct.curl_state;
// ==============
// do the request
// ==============
- CURLcode res = curl_easy_perform(global_state.curl);
+ CURLcode res = curl_easy_perform(curl_state.curl);
if (verbose >= 2 && workingState.http_post_data) {
printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data);
}
- /* free header and server IP resolve lists, we don't need it anymore */
- curl_slist_free_all(header_list);
- header_list = NULL;
-
- if (host) {
- curl_slist_free_all(host);
- host = NULL;
- }
-
/* Curl errors, result in critical Nagios state */
if (res != CURLE_OK) {
snprintf(msg, DEFAULT_BUFFER_SIZE,
@@ -969,7 +1004,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
// ==========
mp_state_enum result_ssl = STATE_OK;
- /* certificate checks */
+/* certificate checks */
#ifdef LIBCURL_FEATURE_SSL
if (workingState.use_ssl) {
if (config.check_cert) {
@@ -992,7 +1027,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
cert_ptr_union cert_ptr = {0};
cert_ptr.to_info = NULL;
- res = curl_easy_getinfo(global_state.curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
+ res = curl_easy_getinfo(curl_state.curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
if (!res && cert_ptr.to_info) {
# ifdef USE_OPENSSL
/* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert
@@ -1066,54 +1101,55 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
*/
double total_time;
handle_curl_option_return_code(
- curl_easy_getinfo(global_state.curl, CURLINFO_TOTAL_TIME, &total_time),
+ curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time),
"CURLINFO_TOTAL_TIME");
- size_t page_len = get_content_length(&global_state.header_buf, &global_state.body_buf);
+ size_t page_len = get_content_length(&curl_state.header_buf, &curl_state.body_buf);
char perfstring[DEFAULT_BUFFER_SIZE];
if (config.show_extended_perfdata) {
double time_connect;
handle_curl_option_return_code(
- curl_easy_getinfo(global_state.curl, CURLINFO_CONNECT_TIME, &time_connect),
+ curl_easy_getinfo(curl_state.curl, CURLINFO_CONNECT_TIME, &time_connect),
"CURLINFO_CONNECT_TIME");
double time_appconnect;
handle_curl_option_return_code(
- curl_easy_getinfo(global_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect),
+ curl_easy_getinfo(curl_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect),
"CURLINFO_APPCONNECT_TIME");
double time_headers;
handle_curl_option_return_code(
- curl_easy_getinfo(global_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers),
+ curl_easy_getinfo(curl_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers),
"CURLINFO_PRETRANSFER_TIME");
double time_firstbyte;
handle_curl_option_return_code(
- curl_easy_getinfo(global_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
+ curl_easy_getinfo(curl_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
"CURLINFO_STARTTRANSFER_TIME");
- snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s",
- perfd_time(total_time, config.thlds, config.socket_timeout),
- perfd_size(page_len, config.min_page_len),
- perfd_time_connect(time_connect, config.socket_timeout),
- workingState.use_ssl
- ? perfd_time_ssl(time_appconnect - time_connect, config.socket_timeout)
- : "",
- perfd_time_headers(time_headers - time_appconnect, config.socket_timeout),
- perfd_time_firstbyte(time_firstbyte - time_headers, config.socket_timeout),
- perfd_time_transfer(total_time - time_firstbyte, config.socket_timeout));
+ snprintf(
+ perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s",
+ perfd_time(total_time, config.thlds, config.curl_config.socket_timeout),
+ perfd_size(page_len, config.min_page_len),
+ perfd_time_connect(time_connect, config.curl_config.socket_timeout),
+ workingState.use_ssl
+ ? perfd_time_ssl(time_appconnect - time_connect, config.curl_config.socket_timeout)
+ : "",
+ perfd_time_headers(time_headers - time_appconnect, config.curl_config.socket_timeout),
+ perfd_time_firstbyte(time_firstbyte - time_headers, config.curl_config.socket_timeout),
+ perfd_time_transfer(total_time - time_firstbyte, config.curl_config.socket_timeout));
} else {
snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s",
- perfd_time(total_time, config.thlds, config.socket_timeout),
+ perfd_time(total_time, config.thlds, config.curl_config.socket_timeout),
perfd_size(page_len, config.min_page_len));
}
/* return a CRITICAL status if we couldn't read any data */
- if (strlen(global_state.header_buf.buf) == 0 && strlen(global_state.body_buf.buf) == 0) {
+ if (strlen(curl_state.header_buf.buf) == 0 && strlen(curl_state.body_buf.buf) == 0) {
die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
}
/* get status line of answer, check sanity of HTTP code */
- if (curlhelp_parse_statusline(global_state.header_buf.buf, &global_state.status_line) < 0) {
+ if (curlhelp_parse_statusline(curl_state.header_buf.buf, &curl_state.status_line) < 0) {
snprintf(msg, DEFAULT_BUFFER_SIZE,
"Unparsable status line in %.3g seconds response time|%s\n", total_time,
perfstring);
@@ -1121,12 +1157,12 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
* line */
die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x unknown - %s", msg);
}
- global_state.status_line_initialized = true;
+ curl_state.status_line_initialized = true;
/* get result code from cURL */
long httpReturnCode;
handle_curl_option_return_code(
- curl_easy_getinfo(global_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode),
+ curl_easy_getinfo(curl_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode),
"CURLINFO_RESPONSE_CODE");
if (verbose >= 2) {
printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", httpReturnCode);
@@ -1134,28 +1170,28 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
/* print status line, header, body if verbose */
if (verbose >= 2) {
- printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", global_state.header_buf.buf,
- (workingState.no_body ? " [[ skipped ]]" : global_state.body_buf.buf));
+ printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", curl_state.header_buf.buf,
+ (workingState.no_body ? " [[ skipped ]]" : curl_state.body_buf.buf));
}
/* make sure the status line matches the response we are looking for */
- if (!expected_statuscode(global_state.status_line.first_line, config.server_expect.string)) {
+ if (!expected_statuscode(curl_state.status_line.first_line, config.server_expect.string)) {
if (workingState.serverPort == HTTP_PORT) {
snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"),
- global_state.status_line.first_line);
+ curl_state.status_line.first_line);
} else {
snprintf(msg, DEFAULT_BUFFER_SIZE,
_("Invalid HTTP response received from host on port %d: %s\n"),
- workingState.serverPort, global_state.status_line.first_line);
+ workingState.serverPort, curl_state.status_line.first_line);
}
die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "",
- config.show_body ? global_state.body_buf.buf : "");
+ config.show_body ? curl_state.body_buf.buf : "");
}
mp_state_enum result = STATE_OK;
if (config.server_expect.is_present) {
snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "),
- config.server_expect);
+ config.server_expect.string);
if (verbose) {
printf("%s\n", msg);
}
@@ -1164,7 +1200,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
/* illegal return codes result in a critical state */
if (httpReturnCode >= 600 || httpReturnCode < 100) {
die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"),
- global_state.status_line.http_code, global_state.status_line.msg);
+ curl_state.status_line.http_code, curl_state.status_line.msg);
/* server errors result in a critical state */
} else if (httpReturnCode >= 500) {
result = STATE_CRITICAL;
@@ -1173,25 +1209,25 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
result = STATE_WARNING;
/* check redirected page if specified */
} else if (httpReturnCode >= 300) {
- if (config.onredirect == STATE_DEPENDENT) {
+ if (config.on_redirect_dependent) {
if (config.followmethod == FOLLOW_LIBCURL) {
- httpReturnCode = global_state.status_line.http_code;
+ httpReturnCode = curl_state.status_line.http_code;
} else {
/* old check_http style redirection, if we come
* back here, we are in the same status as with
* the libcurl method
*/
- redir_wrapper redir_result = redir(&global_state.header_buf, config,
- redir_depth, workingState, global_state);
- check_http(config, redir_result.working_state, redir_result.redir_depth,
- header_list, redir_result.curl_state);
+ redir_wrapper redir_result =
+ redir(&curl_state.header_buf, config, redir_depth, workingState);
+ cleanup(curl_state);
+ check_http(config, redir_result.working_state, redir_result.redir_depth);
}
} else {
/* this is a specific code in the command line to
* be returned when a redirection is encountered
*/
}
- result = max_state_alt(config.onredirect, result);
+ result = max_state_alt(config.on_redirect_result_state, result);
/* all other codes are considered ok */
} else {
result = STATE_OK;
@@ -1201,7 +1237,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
/* libcurl redirection internally, handle error states here */
if (config.followmethod == FOLLOW_LIBCURL) {
handle_curl_option_return_code(
- curl_easy_getinfo(global_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth),
+ curl_easy_getinfo(curl_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth),
"CURLINFO_REDIRECT_COUNT");
if (verbose >= 2) {
@@ -1216,22 +1252,21 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
}
/* check status codes, set exit status accordingly */
- if (global_state.status_line.http_code != httpReturnCode) {
+ if (curl_state.status_line.http_code != httpReturnCode) {
die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
- string_statuscode(global_state.status_line.http_major,
- global_state.status_line.http_minor),
- global_state.status_line.http_code, global_state.status_line.msg, httpReturnCode);
+ string_statuscode(curl_state.status_line.http_major, curl_state.status_line.http_minor),
+ curl_state.status_line.http_code, curl_state.status_line.msg, httpReturnCode);
}
if (config.maximum_age >= 0) {
result = max_state_alt(
- check_document_dates(&global_state.header_buf, &msg, config.maximum_age), result);
+ check_document_dates(&curl_state.header_buf, &msg, config.maximum_age), result);
}
/* Page and Header content checks go here */
if (strlen(config.header_expect)) {
- if (!strstr(global_state.header_buf.buf, config.header_expect)) {
+ if (!strstr(curl_state.header_buf.buf, config.header_expect)) {
char output_header_search[30] = "";
strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search));
@@ -1254,7 +1289,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
}
if (strlen(config.string_expect)) {
- if (!strstr(global_state.body_buf.buf, config.string_expect)) {
+ if (!strstr(curl_state.body_buf.buf, config.string_expect)) {
char output_string_search[30] = "";
strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search));
@@ -1278,7 +1313,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
if (strlen(config.regexp)) {
regmatch_t pmatch[REGS];
- int errcode = regexec(&config.compiled_regex, global_state.body_buf.buf, REGS, pmatch, 0);
+ int errcode = regexec(&config.compiled_regex, curl_state.body_buf.buf, REGS, pmatch, 0);
if ((errcode == 0 && !config.invert_regex) ||
(errcode == REG_NOMATCH && config.invert_regex)) {
/* OK - No-op to avoid changing the logic around it */
@@ -1344,11 +1379,10 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat
die((int)max_state_alt(result, result_ssl),
"HTTP %s: %s %d %s%s%s - %zu bytes in %.3f second response time %s|%s\n%s%s",
state_text(result),
- string_statuscode(global_state.status_line.http_major, global_state.status_line.http_minor),
- global_state.status_line.http_code, global_state.status_line.msg,
- strlen(msg) > 0 ? " - " : "", msg, page_len, total_time,
- (config.display_html ? "" : ""), perfstring,
- (config.show_body ? global_state.body_buf.buf : ""), (config.show_body ? "\n" : ""));
+ string_statuscode(curl_state.status_line.http_major, curl_state.status_line.http_minor),
+ curl_state.status_line.http_code, curl_state.status_line.msg, strlen(msg) > 0 ? " - " : "",
+ msg, page_len, total_time, (config.display_html ? "" : ""), perfstring,
+ (config.show_body ? curl_state.body_buf.buf : ""), (config.show_body ? "\n" : ""));
return max_state_alt(result, result_ssl);
}
@@ -1375,8 +1409,7 @@ char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
}
redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config,
- int redir_depth, check_curl_working_state working_state,
- check_curl_global_state global_state) {
+ int redir_depth, check_curl_working_state working_state) {
curlhelp_statusline status_line;
struct phr_header headers[255];
size_t msglen;
@@ -1533,8 +1566,6 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config
* attached to the URL in Location
*/
- cleanup(global_state);
-
redir_wrapper result = {
.redir_depth = redir_depth,
.working_state = working_state,
@@ -1673,7 +1704,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
if (!is_intnonneg(optarg)) {
usage2(_("Timeout interval must be a positive integer"), optarg);
} else {
- result.config.socket_timeout = (int)strtol(optarg, NULL, 10);
+ result.config.curl_config.socket_timeout = (int)strtol(optarg, NULL, 10);
}
break;
case 'c': /* critical time threshold */
@@ -1724,12 +1755,12 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
}
break;
case 'a': /* authorization info */
- strncpy(result.config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
- result.config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
+ strncpy(result.config.curl_config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
+ result.config.curl_config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
break;
case 'b': /* proxy-authorization info */
- strncpy(result.config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
- result.config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
+ strncpy(result.config.curl_config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
+ result.config.curl_config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
break;
case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
if (!result.config.initial_config.http_post_data) {
@@ -1746,19 +1777,20 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
result.config.initial_config.http_method = strdup(optarg);
break;
case 'A': /* useragent */
- strncpy(result.config.user_agent, optarg, DEFAULT_BUFFER_SIZE);
- result.config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
+ strncpy(result.config.curl_config.user_agent, optarg, DEFAULT_BUFFER_SIZE);
+ result.config.curl_config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
break;
case 'k': /* Additional headers */
- if (result.config.http_opt_headers_count == 0) {
- result.config.http_opt_headers =
- malloc(sizeof(char *) * (++result.config.http_opt_headers_count));
+ if (result.config.curl_config.http_opt_headers_count == 0) {
+ result.config.curl_config.http_opt_headers =
+ malloc(sizeof(char *) * (++result.config.curl_config.http_opt_headers_count));
} else {
- result.config.http_opt_headers =
- realloc(result.config.http_opt_headers,
- sizeof(char *) * (++result.config.http_opt_headers_count));
+ result.config.curl_config.http_opt_headers =
+ realloc(result.config.curl_config.http_opt_headers,
+ sizeof(char *) * (++result.config.curl_config.http_opt_headers_count));
}
- result.config.http_opt_headers[result.config.http_opt_headers_count - 1] = optarg;
+ result.config.curl_config
+ .http_opt_headers[result.config.curl_config.http_opt_headers_count - 1] = optarg;
break;
case 'L': /* show html link */
result.config.display_html = true;
@@ -1805,7 +1837,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
usage4(_("Invalid option - SSL is not available"));
#endif
test_file(optarg);
- result.config.client_cert = optarg;
+ result.config.curl_config.client_cert = optarg;
enable_tls = true;
break;
case 'K': /* use client private key */
@@ -1813,7 +1845,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
usage4(_("Invalid option - SSL is not available"));
#endif
test_file(optarg);
- result.config.client_privkey = optarg;
+ result.config.curl_config.client_privkey = optarg;
enable_tls = true;
break;
case CA_CERT_OPTION: /* use CA chain file */
@@ -1821,14 +1853,14 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
usage4(_("Invalid option - SSL is not available"));
#endif
test_file(optarg);
- result.config.ca_cert = optarg;
+ result.config.curl_config.ca_cert = optarg;
enable_tls = true;
break;
case 'D': /* verify peer certificate & host */
#ifndef LIBCURL_FEATURE_SSL
usage4(_("Invalid option - SSL is not available"));
#endif
- result.config.verify_peer_and_host = true;
+ result.config.curl_config.verify_peer_and_host = true;
enable_tls = true;
break;
case 'S': /* use SSL */
@@ -1852,36 +1884,44 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
break;
case 'f': /* onredirect */
if (!strcmp(optarg, "ok")) {
- result.config.onredirect = STATE_OK;
+ result.config.on_redirect_result_state = STATE_OK;
+ result.config.on_redirect_dependent = false;
} else if (!strcmp(optarg, "warning")) {
- result.config.onredirect = STATE_WARNING;
+ result.config.on_redirect_result_state = STATE_WARNING;
+ result.config.on_redirect_dependent = false;
} else if (!strcmp(optarg, "critical")) {
- result.config.onredirect = STATE_CRITICAL;
+ result.config.on_redirect_result_state = STATE_CRITICAL;
+ result.config.on_redirect_dependent = false;
} else if (!strcmp(optarg, "unknown")) {
- result.config.onredirect = STATE_UNKNOWN;
+ result.config.on_redirect_result_state = STATE_UNKNOWN;
+ result.config.on_redirect_dependent = false;
} else if (!strcmp(optarg, "follow")) {
- result.config.onredirect = STATE_DEPENDENT;
+ result.config.on_redirect_dependent = true;
} else if (!strcmp(optarg, "stickyport")) {
- result.config.onredirect = STATE_DEPENDENT,
+ result.config.on_redirect_dependent = true;
result.config.followmethod = FOLLOW_HTTP_CURL,
result.config.followsticky = STICKY_HOST | STICKY_PORT;
} else if (!strcmp(optarg, "sticky")) {
- result.config.onredirect = STATE_DEPENDENT,
+ result.config.on_redirect_dependent = true;
result.config.followmethod = FOLLOW_HTTP_CURL,
result.config.followsticky = STICKY_HOST;
} else if (!strcmp(optarg, "follow")) {
- result.config.onredirect = STATE_DEPENDENT,
+ result.config.on_redirect_dependent = true;
result.config.followmethod = FOLLOW_HTTP_CURL,
result.config.followsticky = STICKY_NONE;
} else if (!strcmp(optarg, "curl")) {
- result.config.onredirect = STATE_DEPENDENT,
+ result.config.on_redirect_dependent = true;
result.config.followmethod = FOLLOW_LIBCURL;
} else {
usage2(_("Invalid onredirect option"), optarg);
}
if (verbose >= 2) {
- printf(_("* Following redirects set to %s\n"),
- state_text(result.config.onredirect));
+ if (result.config.on_redirect_dependent) {
+ printf(_("* Following redirects\n"));
+ } else {
+ printf(_("* Following redirects set to state %s\n"),
+ state_text(result.config.on_redirect_result_state));
+ }
}
break;
case 'd': /* string or substring */
@@ -1898,7 +1938,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
result.config.server_expect.is_present = true;
break;
case 'T': /* Content-type */
- result.config.http_content_type = strdup(optarg);
+ result.config.curl_config.http_content_type = strdup(optarg);
break;
case 'l': /* linespan */
cflags &= ~REG_NEWLINE;
@@ -1933,11 +1973,11 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
}
break;
case '4':
- result.config.sin_family = AF_INET;
+ result.config.curl_config.sin_family = AF_INET;
break;
case '6':
#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
- result.config.sin_family = AF_INET6;
+ result.config.curl_config.sin_family = AF_INET6;
#else
usage4(_("IPv6 support not available"));
#endif
@@ -1997,30 +2037,33 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
result.config.show_body = true;
break;
case HTTP_VERSION_OPTION:
- result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
+ result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_NONE;
if (strcmp(optarg, "1.0") == 0) {
- result.config.curl_http_version = CURL_HTTP_VERSION_1_0;
+ result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_0;
} else if (strcmp(optarg, "1.1") == 0) {
- result.config.curl_http_version = CURL_HTTP_VERSION_1_1;
+ result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_1;
} else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
- result.config.curl_http_version = CURL_HTTP_VERSION_2_0;
+ result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_2_0;
#else
result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
+ } else if ((strcmp(optarg, "3") == 0)) {
+ // TODO find out which libcurl version starts supporting HTTP 3
+ result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_3;
} else {
fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
exit(STATE_WARNING);
}
break;
case AUTOMATIC_DECOMPRESSION:
- result.config.automatic_decompression = true;
+ result.config.curl_config.automatic_decompression = true;
break;
case COOKIE_JAR:
- result.config.cookie_jar_file = optarg;
+ result.config.curl_config.cookie_jar_file = optarg;
break;
case HAPROXY_PROTOCOL:
- result.config.haproxy_protocol = true;
+ result.config.curl_config.haproxy_protocol = true;
break;
case '?':
/* print short usage statement if args not parsable */
@@ -2035,7 +2078,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
/* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
* Only set if it's non-zero. This helps when we include multiple
* parameters, like -S and -C combinations */
- result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
+ result.config.curl_config.ssl_version = CURL_SSLVERSION_DEFAULT;
if (tls_option_optarg != NULL) {
char *plus_ptr = strchr(optarg, '+');
if (plus_ptr) {
@@ -2044,30 +2087,30 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
}
if (optarg[0] == '2') {
- result.config.ssl_version = CURL_SSLVERSION_SSLv2;
+ result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv2;
} else if (optarg[0] == '3') {
- result.config.ssl_version = CURL_SSLVERSION_SSLv3;
+ result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv3;
} else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) {
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
- result.config.ssl_version = CURL_SSLVERSION_TLSv1_0;
+ result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_0;
#else
result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
} else if (!strcmp(optarg, "1.1")) {
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
- result.config.ssl_version = CURL_SSLVERSION_TLSv1_1;
+ result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_1;
#else
result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
} else if (!strcmp(optarg, "1.2")) {
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
- result.config.ssl_version = CURL_SSLVERSION_TLSv1_2;
+ result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_2;
#else
result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
} else if (!strcmp(optarg, "1.3")) {
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
- result.config.ssl_version = CURL_SSLVERSION_TLSv1_3;
+ result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_3;
#else
result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
@@ -2078,35 +2121,35 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
}
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
if (got_plus) {
- switch (result.config.ssl_version) {
+ switch (result.config.curl_config.ssl_version) {
case CURL_SSLVERSION_TLSv1_3:
- result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
+ result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
break;
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_0:
- result.config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
+ result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
break;
}
} else {
- switch (result.config.ssl_version) {
+ switch (result.config.curl_config.ssl_version) {
case CURL_SSLVERSION_TLSv1_3:
- result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
+ result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
break;
case CURL_SSLVERSION_TLSv1_2:
- result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
+ result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
break;
case CURL_SSLVERSION_TLSv1_1:
- result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
+ result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
break;
case CURL_SSLVERSION_TLSv1_0:
- result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
+ result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
break;
}
}
#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
if (verbose >= 2) {
- printf(_("* Set SSL/TLS version to %d\n"), result.config.ssl_version);
+ printf(_("* Set SSL/TLS version to %d\n"), result.config.curl_config.ssl_version);
}
if (!specify_port) {
result.config.initial_config.serverPort = HTTPS_PORT;
@@ -2135,18 +2178,18 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
set_thresholds(&result.config.thlds, warning_thresholds, critical_thresholds);
if (critical_thresholds &&
- result.config.thlds->critical->end > (double)result.config.socket_timeout) {
- result.config.socket_timeout = (int)result.config.thlds->critical->end + 1;
+ result.config.thlds->critical->end > (double)result.config.curl_config.socket_timeout) {
+ result.config.curl_config.socket_timeout = (int)result.config.thlds->critical->end + 1;
}
if (verbose >= 2) {
- printf("* Socket timeout set to %ld seconds\n", result.config.socket_timeout);
+ printf("* Socket timeout set to %ld seconds\n", result.config.curl_config.socket_timeout);
}
if (result.config.initial_config.http_method == NULL) {
result.config.initial_config.http_method = strdup("GET");
}
- if (result.config.client_cert && !result.config.client_privkey) {
+ if (result.config.curl_config.client_cert && !result.config.curl_config.client_privkey) {
usage4(_("If you use a client certificate you must also specify a private key file"));
}
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h
index 7566b19c..be25d1bb 100644
--- a/plugins/check_curl.d/config.h
+++ b/plugins/check_curl.d/config.h
@@ -65,27 +65,32 @@ check_curl_working_state check_curl_working_state_init() {
}
typedef struct {
- check_curl_working_state initial_config;
- sa_family_t sin_family;
-
bool automatic_decompression;
bool haproxy_protocol;
+ long socket_timeout;
+ sa_family_t sin_family;
+ int curl_http_version;
+ char **http_opt_headers;
+ size_t http_opt_headers_count;
+ int ssl_version;
char *client_cert;
char *client_privkey;
char *ca_cert;
- int ssl_version;
+ bool verify_peer_and_host;
char user_agent[DEFAULT_BUFFER_SIZE];
- char **http_opt_headers;
- size_t http_opt_headers_count;
- int max_depth;
- char *http_content_type;
- long socket_timeout;
- char user_auth[MAX_INPUT_BUFFER];
char proxy_auth[MAX_INPUT_BUFFER];
+ char user_auth[MAX_INPUT_BUFFER];
+ char *http_content_type;
+ char *cookie_jar_file;
+} check_curl_static_curl_config;
+
+typedef struct {
+ check_curl_working_state initial_config;
+
+ check_curl_static_curl_config curl_config;
+ int max_depth;
int followmethod;
int followsticky;
- int curl_http_version;
- char *cookie_jar_file;
int maximum_age;
@@ -97,7 +102,6 @@ typedef struct {
mp_state_enum state_regex;
bool invert_regex;
- bool verify_peer_and_host;
bool check_cert;
bool continue_after_check_cert;
int days_till_exp_warn;
@@ -111,7 +115,8 @@ typedef struct {
} server_expect;
char string_expect[MAX_INPUT_BUFFER];
char header_expect[MAX_INPUT_BUFFER];
- mp_state_enum onredirect;
+ mp_state_enum on_redirect_result_state;
+ bool on_redirect_dependent;
bool show_extended_perfdata;
bool show_body;
@@ -122,33 +127,35 @@ check_curl_config check_curl_config_init() {
check_curl_config tmp = {
.initial_config = check_curl_working_state_init(),
- .sin_family = AF_UNSPEC,
-
- .automatic_decompression = false,
- .haproxy_protocol = false,
- .client_cert = NULL,
- .client_privkey = NULL,
- .ca_cert = NULL,
- .ssl_version = CURL_SSLVERSION_DEFAULT,
- .user_agent = {'\0'},
- .http_opt_headers = NULL,
- .http_opt_headers_count = 0,
+ .curl_config =
+ {
+ .automatic_decompression = false,
+ .socket_timeout = DEFAULT_SOCKET_TIMEOUT,
+ .haproxy_protocol = false,
+ .sin_family = AF_UNSPEC,
+ .curl_http_version = CURL_HTTP_VERSION_NONE,
+ .http_opt_headers = NULL,
+ .http_opt_headers_count = 0,
+ .ssl_version = CURL_SSLVERSION_DEFAULT,
+ .client_cert = NULL,
+ .client_privkey = NULL,
+ .ca_cert = NULL,
+ .verify_peer_and_host = false,
+ .user_agent = {'\0'},
+ .proxy_auth = "",
+ .user_auth = "",
+ .http_content_type = NULL,
+ .cookie_jar_file = NULL,
+ },
.max_depth = DEFAULT_MAX_REDIRS,
- .http_content_type = NULL,
- .socket_timeout = DEFAULT_SOCKET_TIMEOUT,
- .user_auth = "",
- .proxy_auth = "",
.followmethod = FOLLOW_HTTP_CURL,
.followsticky = STICKY_NONE,
- .curl_http_version = CURL_HTTP_VERSION_NONE,
- .cookie_jar_file = NULL,
.maximum_age = -1,
.regexp = {},
.compiled_regex = {},
.state_regex = STATE_CRITICAL,
.invert_regex = false,
- .verify_peer_and_host = false,
.check_cert = false,
.continue_after_check_cert = false,
.days_till_exp_warn = 0,
@@ -163,11 +170,16 @@ check_curl_config check_curl_config_init() {
},
.string_expect = "",
.header_expect = "",
- .onredirect = STATE_OK,
+ .on_redirect_result_state = STATE_OK,
+ .on_redirect_dependent = true,
.show_extended_perfdata = false,
.show_body = false,
.display_html = false,
};
+
+ snprintf(tmp.curl_config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
+ "check_curl", NP_VERSION, VERSION, curl_version());
+
return tmp;
}
--
cgit v1.2.3-74-g34f1