summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-03-11 02:02:27 +0100
committerLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-03-11 02:02:27 +0100
commitf25a4000b6ffbe0fff1d749ff334b36c77ddc6a2 (patch)
treeadf1152a6c69583e44d3d4e41088eb57217c774f
parentaa137f7d4adb8ebbbdd3a4c71cd28824d6fcfaca (diff)
downloadmonitoring-plugins-f25a4000b6ffbe0fff1d749ff334b36c77ddc6a2.tar.gz
Refactor check_curl
-rw-r--r--plugins/Makefile.am3
-rw-r--r--plugins/check_curl.c993
-rw-r--r--plugins/check_curl.d/config.h141
3 files changed, 607 insertions, 530 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 41487131..ce00c392 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -57,7 +57,8 @@ EXTRA_DIST = t \
57 check_apt.d \ 57 check_apt.d \
58 check_by_ssh.d \ 58 check_by_ssh.d \
59 check_smtp.d \ 59 check_smtp.d \
60 check_dig.d 60 check_dig.d \
61 check_curl.d
61 62
62PLUGINHDRS = common.h 63PLUGINHDRS = common.h
63 64
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index cf755316..4806bf14 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -37,6 +37,9 @@ const char *progname = "check_curl";
37const char *copyright = "2006-2024"; 37const char *copyright = "2006-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include "check_curl.d/config.h"
41#include "states.h"
42#include "thresholds.h"
40#include <stdbool.h> 43#include <stdbool.h>
41#include <ctype.h> 44#include <ctype.h>
42 45
@@ -65,27 +68,9 @@ const char *email = "devel@monitoring-plugins.org";
65 68
66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major) * 0x10000 + (minor) * 0x100 + (patch)) 69#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major) * 0x10000 + (minor) * 0x100 + (patch))
67 70
68#define DEFAULT_BUFFER_SIZE 2048 71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
69#define DEFAULT_SERVER_URL "/"
70#define HTTP_EXPECT "HTTP/"
71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
72enum { 72enum {
73 MAX_IPV4_HOSTLENGTH = 255, 73 MAX_IPV4_HOSTLENGTH = 255,
74 HTTP_PORT = 80,
75 HTTPS_PORT = 443,
76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15
78};
79
80enum {
81 STICKY_NONE = 0,
82 STICKY_HOST = 1,
83 STICKY_PORT = 2
84};
85
86enum {
87 FOLLOW_HTTP_CURL = 0,
88 FOLLOW_LIBCURL = 1
89}; 74};
90 75
91/* for buffers for header and body */ 76/* for buffers for header and body */
@@ -125,46 +110,14 @@ typedef enum curlhelp_ssl_library {
125 110
126enum { 111enum {
127 REGS = 2, 112 REGS = 2,
128 MAX_RE_SIZE = 1024
129}; 113};
114
130#include "regex.h" 115#include "regex.h"
131static regex_t preg; 116
132static regmatch_t pmatch[REGS]; 117// Globals
133static char regexp[MAX_RE_SIZE];
134static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
135static int errcode;
136static bool invert_regex = false;
137static int state_regex = STATE_CRITICAL;
138
139static char *server_address = NULL;
140static char *host_name = NULL;
141static char *server_url = 0;
142static struct curl_slist *server_ips = NULL;
143static bool specify_port = false;
144static unsigned short server_port = HTTP_PORT;
145static unsigned short virtual_port = 0;
146static int host_name_length;
147static char output_header_search[30] = "";
148static char output_string_search[30] = "";
149static char *warning_thresholds = NULL;
150static char *critical_thresholds = NULL;
151static int days_till_exp_warn, days_till_exp_crit;
152static thresholds *thlds;
153static char user_agent[DEFAULT_BUFFER_SIZE];
154static int verbose = 0;
155static bool show_extended_perfdata = false;
156static bool show_body = false;
157static int min_page_len = 0;
158static int max_page_len = 0;
159static int redir_depth = 0;
160static int max_depth = DEFAULT_MAX_REDIRS;
161static char *http_method = NULL;
162static char *http_post_data = NULL;
163static char *http_content_type = NULL;
164static CURL *curl;
165static bool curl_global_initialized = false; 118static bool curl_global_initialized = false;
166static bool curl_easy_initialized = false; 119static bool curl_easy_initialized = false;
167static struct curl_slist *header_list = NULL; 120static int verbose = 0;
168static bool body_buf_initialized = false; 121static bool body_buf_initialized = false;
169static curlhelp_write_curlbuf body_buf; 122static curlhelp_write_curlbuf body_buf;
170static bool header_buf_initialized = false; 123static bool header_buf_initialized = false;
@@ -173,69 +126,45 @@ static bool status_line_initialized = false;
173static curlhelp_statusline status_line; 126static curlhelp_statusline status_line;
174static bool put_buf_initialized = false; 127static bool put_buf_initialized = false;
175static curlhelp_read_curlbuf put_buf; 128static curlhelp_read_curlbuf put_buf;
176static char http_header[DEFAULT_BUFFER_SIZE]; 129
130static struct curl_slist *server_ips = NULL; // TODO maybe unused
131static int redir_depth = 0; // Maybe global
132static CURL *curl;
133static struct curl_slist *header_list = NULL;
177static long code; 134static long code;
178static long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
179static double total_time;
180static double time_connect;
181static double time_appconnect;
182static double time_headers;
183static double time_firstbyte;
184static char errbuf[MAX_INPUT_BUFFER]; 135static char errbuf[MAX_INPUT_BUFFER];
185static CURLcode res;
186static char url[DEFAULT_BUFFER_SIZE];
187static char msg[DEFAULT_BUFFER_SIZE]; 136static char msg[DEFAULT_BUFFER_SIZE];
188static char perfstring[DEFAULT_BUFFER_SIZE];
189static char header_expect[MAX_INPUT_BUFFER] = "";
190static char string_expect[MAX_INPUT_BUFFER] = "";
191static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
192static int server_expect_yn = 0;
193static char user_auth[MAX_INPUT_BUFFER] = "";
194static char proxy_auth[MAX_INPUT_BUFFER] = "";
195static char **http_opt_headers;
196static int http_opt_headers_count = 0;
197static bool display_html = false;
198static int onredirect = STATE_OK;
199static int followmethod = FOLLOW_HTTP_CURL;
200static int followsticky = STICKY_NONE;
201static bool use_ssl = false;
202static bool check_cert = false;
203static bool continue_after_check_cert = false;
204typedef union { 137typedef union {
205 struct curl_slist *to_info; 138 struct curl_slist *to_info;
206 struct curl_certinfo *to_certinfo; 139 struct curl_certinfo *to_certinfo;
207} cert_ptr_union; 140} cert_ptr_union;
208static cert_ptr_union cert_ptr; 141static cert_ptr_union cert_ptr;
209static int ssl_version = CURL_SSLVERSION_DEFAULT;
210static char *client_cert = NULL;
211static char *client_privkey = NULL;
212static char *ca_cert = NULL;
213static bool verify_peer_and_host = false;
214static bool is_openssl_callback = false; 142static bool is_openssl_callback = false;
215static bool add_sslctx_verify_fun = false; 143static bool add_sslctx_verify_fun = false;
144
216#if defined(HAVE_SSL) && defined(USE_OPENSSL) 145#if defined(HAVE_SSL) && defined(USE_OPENSSL)
217static X509 *cert = NULL; 146static X509 *cert = NULL;
218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 147#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
219static bool no_body = false; 148
220static int maximum_age = -1;
221static int address_family = AF_UNSPEC; 149static int address_family = AF_UNSPEC;
222static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 150static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
223static int curl_http_version = CURL_HTTP_VERSION_NONE;
224static bool automatic_decompression = false;
225static char *cookie_jar_file = NULL;
226static bool haproxy_protocol = false;
227 151
228static bool process_arguments(int /*argc*/, char ** /*argv*/); 152typedef struct {
153 int errorcode;
154 check_curl_config config;
155} check_curl_config_wrapper;
156static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
157
229static void handle_curl_option_return_code(CURLcode res, const char *option); 158static void handle_curl_option_return_code(CURLcode res, const char *option);
230static int check_http(void); 159static mp_state_enum check_http(check_curl_config /*config*/);
231static void redir(curlhelp_write_curlbuf * /*header_buf*/); 160static void redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/);
232static char *perfd_time(double elapsed_time); 161static char *perfd_time(double elapsed_time, thresholds * /*thlds*/, long /*socket_timeout*/);
233static char *perfd_time_connect(double elapsed_time_connect); 162static char *perfd_time_connect(double elapsed_time_connect, long /*socket_timeout*/);
234static char *perfd_time_ssl(double elapsed_time_ssl); 163static char *perfd_time_ssl(double elapsed_time_ssl, long /*socket_timeout*/);
235static char *perfd_time_firstbyte(double elapsed_time_firstbyte); 164static char *perfd_time_firstbyte(double elapsed_time_firstbyte, long /*socket_timeout*/);
236static char *perfd_time_headers(double elapsed_time_headers); 165static char *perfd_time_headers(double elapsed_time_headers, long /*socket_timeout*/);
237static char *perfd_time_transfer(double elapsed_time_transfer); 166static char *perfd_time_transfer(double elapsed_time_transfer, long /*socket_timeout*/);
238static char *perfd_size(int page_len); 167static char *perfd_size(int page_len, int /*min_page_len*/);
239static void print_help(void); 168static void print_help(void);
240void print_usage(void); 169void print_usage(void);
241static void print_curl_version(void); 170static void print_curl_version(void);
@@ -252,7 +181,7 @@ int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
252static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/); 181static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
253static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/); 182static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
254static char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header); 183static char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
255static int check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, char (*msg)[DEFAULT_BUFFER_SIZE]); 184static int check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, char (*msg)[DEFAULT_BUFFER_SIZE], int /*maximum_age*/);
256static int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf); 185static int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf);
257 186
258#if defined(HAVE_SSL) && defined(USE_OPENSSL) 187#if defined(HAVE_SSL) && defined(USE_OPENSSL)
@@ -262,8 +191,6 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
262static void test_file(char * /*path*/); 191static void test_file(char * /*path*/);
263 192
264int main(int argc, char **argv) { 193int main(int argc, char **argv) {
265 int result = STATE_UNKNOWN;
266
267 setlocale(LC_ALL, ""); 194 setlocale(LC_ALL, "");
268 bindtextdomain(PACKAGE, LOCALEDIR); 195 bindtextdomain(PACKAGE, LOCALEDIR);
269 textdomain(PACKAGE); 196 textdomain(PACKAGE);
@@ -271,21 +198,27 @@ int main(int argc, char **argv) {
271 /* Parse extra opts if any */ 198 /* Parse extra opts if any */
272 argv = np_extra_opts(&argc, argv, progname); 199 argv = np_extra_opts(&argc, argv, progname);
273 200
274 /* set defaults */
275 snprintf(user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", progname, NP_VERSION, VERSION, curl_version());
276
277 /* parse arguments */ 201 /* parse arguments */
278 if (process_arguments(argc, argv) == false) { 202 check_curl_config_wrapper tmp_config = process_arguments(argc, argv);
203 if (tmp_config.errorcode == ERROR) {
279 usage4(_("Could not parse arguments")); 204 usage4(_("Could not parse arguments"));
280 } 205 }
281 206
282 if (display_html) { 207 const check_curl_config config = tmp_config.config;
283 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http", host_name ? host_name : server_address, 208
284 virtual_port ? virtual_port : server_port, server_url); 209 /* set defaults */
210 if (config.user_agent == NULL) {
211 snprintf(config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", progname, NP_VERSION, VERSION,
212 curl_version());
285 } 213 }
286 214
287 result = check_http(); 215 if (config.display_html) {
288 return result; 216 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", config.use_ssl ? "https" : "http",
217 config.host_name ? config.host_name : config.server_address, config.virtual_port ? config.virtual_port : config.server_port,
218 config.server_url);
219 }
220
221 exit(check_http(config));
289} 222}
290 223
291#ifdef HAVE_SSL 224#ifdef HAVE_SSL
@@ -360,13 +293,13 @@ static char *string_statuscode(int major, int minor) {
360/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 293/* Checks if the server 'reply' is one of the expected 'statuscodes' */
361static int expected_statuscode(const char *reply, const char *statuscodes) { 294static int expected_statuscode(const char *reply, const char *statuscodes) {
362 char *expected; 295 char *expected;
363 char *code;
364 int result = 0;
365 296
366 if ((expected = strdup(statuscodes)) == NULL) { 297 if ((expected = strdup(statuscodes)) == NULL) {
367 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 298 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
368 } 299 }
369 300
301 char *code;
302 int result = 0;
370 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) { 303 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
371 if (strstr(reply, code) != NULL) { 304 if (strstr(reply, code) != NULL) {
372 result = 1; 305 result = 1;
@@ -387,26 +320,25 @@ void handle_curl_option_return_code(CURLcode res, const char *option) {
387} 320}
388 321
389int lookup_host(const char *host, char *buf, size_t buflen) { 322int lookup_host(const char *host, char *buf, size_t buflen) {
390 struct addrinfo hints, *res, *result; 323 struct addrinfo hints;
391 char addrstr[100];
392 size_t addrstr_len;
393 int errcode;
394 void *ptr = {0};
395 size_t buflen_remaining = buflen - 1;
396
397 memset(&hints, 0, sizeof(hints)); 324 memset(&hints, 0, sizeof(hints));
398 hints.ai_family = address_family; 325 hints.ai_family = address_family;
399 hints.ai_socktype = SOCK_STREAM; 326 hints.ai_socktype = SOCK_STREAM;
400 hints.ai_flags |= AI_CANONNAME; 327 hints.ai_flags |= AI_CANONNAME;
401 328
402 errcode = getaddrinfo(host, NULL, &hints, &result); 329 struct addrinfo *result;
330 int errcode = getaddrinfo(host, NULL, &hints, &result);
403 if (errcode != 0) { 331 if (errcode != 0) {
404 return errcode; 332 return errcode;
405 } 333 }
406 334
407 strcpy(buf, ""); 335 strcpy(buf, "");
408 res = result; 336 struct addrinfo *res = result;
409 337
338 size_t buflen_remaining = buflen - 1;
339 size_t addrstr_len;
340 char addrstr[100];
341 void *ptr = {0};
410 while (res) { 342 while (res) {
411 switch (res->ai_family) { 343 switch (res->ai_family) {
412 case AF_INET: 344 case AF_INET:
@@ -468,16 +400,7 @@ static void cleanup(void) {
468 put_buf_initialized = false; 400 put_buf_initialized = false;
469} 401}
470 402
471int check_http(void) { 403mp_state_enum check_http(check_curl_config config) {
472 int result = STATE_OK;
473 int result_ssl = STATE_OK;
474 int page_len = 0;
475 int i;
476 char *force_host_header = NULL;
477 struct curl_slist *host = NULL;
478 char addrstr[DEFAULT_BUFFER_SIZE / 2];
479 char dnscache[DEFAULT_BUFFER_SIZE];
480
481 /* initialize curl */ 404 /* initialize curl */
482 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { 405 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
483 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 406 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
@@ -499,7 +422,7 @@ int check_http(void) {
499 /* print everything on stdout like check_http would do */ 422 /* print everything on stdout like check_http would do */
500 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); 423 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
501 424
502 if (automatic_decompression) 425 if (config.automatic_decompression)
503#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) 426#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
504 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING"); 427 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
505#else 428#else
@@ -528,23 +451,27 @@ int check_http(void) {
528 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER"); 451 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
529 452
530 /* set timeouts */ 453 /* set timeouts */
531 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT"); 454 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout), "CURLOPT_CONNECTTIMEOUT");
532 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT"); 455 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, config.socket_timeout), "CURLOPT_TIMEOUT");
533 456
534 /* enable haproxy protocol */ 457 /* enable haproxy protocol */
535 if (haproxy_protocol) { 458 if (config.haproxy_protocol) {
536 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL"); 459 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL");
537 } 460 }
538 461
539 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we 462 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we
540 // use the host_name later on to make SNI happy 463 // use the host_name later on to make SNI happy
541 if (use_ssl && host_name != NULL) { 464 struct curl_slist *host = NULL;
542 if ((res = lookup_host(server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) { 465 char dnscache[DEFAULT_BUFFER_SIZE];
543 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), server_address, res, 466 char addrstr[DEFAULT_BUFFER_SIZE / 2];
544 gai_strerror(res)); 467 if (config.use_ssl && config.host_name != NULL) {
468 CURLcode res;
469 if ((res = lookup_host(config.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) {
470 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
471 config.server_address, res, gai_strerror(res));
545 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 472 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
546 } 473 }
547 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr); 474 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", config.host_name, config.server_port, addrstr);
548 host = curl_slist_append(NULL, dnscache); 475 host = curl_slist_append(NULL, dnscache);
549 curl_easy_setopt(curl, CURLOPT_RESOLVE, host); 476 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
550 if (verbose >= 1) { 477 if (verbose >= 1) {
@@ -554,19 +481,21 @@ int check_http(void) {
554 481
555 // If server_address is an IPv6 address it must be surround by square brackets 482 // If server_address is an IPv6 address it must be surround by square brackets
556 struct in6_addr tmp_in_addr; 483 struct in6_addr tmp_in_addr;
557 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) { 484 if (inet_pton(AF_INET6, config.server_address, &tmp_in_addr) == 1) {
558 char *new_server_address = malloc(strlen(server_address) + 3); 485 char *new_server_address = malloc(strlen(config.server_address) + 3);
559 if (new_server_address == NULL) { 486 if (new_server_address == NULL) {
560 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); 487 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
561 } 488 }
562 snprintf(new_server_address, strlen(server_address) + 3, "[%s]", server_address); 489 snprintf(new_server_address, strlen(config.server_address) + 3, "[%s]", config.server_address);
563 free(server_address); 490 free(config.server_address);
564 server_address = new_server_address; 491 config.server_address = new_server_address;
565 } 492 }
566 493
567 /* compose URL: use the address we want to connect to, set Host: header later */ 494 /* compose URL: use the address we want to connect to, set Host: header later */
568 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", use_ssl ? "https" : "http", 495 char url[DEFAULT_BUFFER_SIZE];
569 (use_ssl & (host_name != NULL)) ? host_name : server_address, server_port, server_url); 496 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", config.use_ssl ? "https" : "http",
497 (config.use_ssl & (config.host_name != NULL)) ? config.host_name : config.server_address, config.server_port,
498 config.server_url);
570 499
571 if (verbose >= 1) { 500 if (verbose >= 1) {
572 printf("* curl CURLOPT_URL: %s\n", url); 501 printf("* curl CURLOPT_URL: %s\n", url);
@@ -574,50 +503,52 @@ int check_http(void) {
574 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL"); 503 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL");
575 504
576 /* extract proxy information for legacy proxy https requests */ 505 /* extract proxy information for legacy proxy https requests */
577 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) { 506 if (!strcmp(config.http_method, "CONNECT") || strstr(config.server_url, "http") == config.server_url) {
578 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY"); 507 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, config.server_address), "CURLOPT_PROXY");
579 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT"); 508 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)config.server_port), "CURLOPT_PROXYPORT");
580 if (verbose >= 2) { 509 if (verbose >= 2) {
581 printf("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port); 510 printf("* curl CURLOPT_PROXY: %s:%d\n", config.server_address, config.server_port);
582 } 511 }
583 http_method = "GET"; 512 config.http_method = "GET";
584 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, server_url), "CURLOPT_URL"); 513 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, config.server_url), "CURLOPT_URL");
585 } 514 }
586 515
587 /* disable body for HEAD request */ 516 /* disable body for HEAD request */
588 if (http_method && !strcmp(http_method, "HEAD")) { 517 if (config.http_method && !strcmp(config.http_method, "HEAD")) {
589 no_body = true; 518 config.no_body = true;
590 } 519 }
591 520
592 /* set HTTP protocol version */ 521 /* set HTTP protocol version */
593 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION"); 522 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, config.curl_http_version), "CURLOPT_HTTP_VERSION");
594 523
595 /* set HTTP method */ 524 /* set HTTP method */
596 if (http_method) { 525 if (config.http_method) {
597 if (!strcmp(http_method, "POST")) { 526 if (!strcmp(config.http_method, "POST")) {
598 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST"); 527 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST");
599 } else if (!strcmp(http_method, "PUT")) { 528 } else if (!strcmp(config.http_method, "PUT")) {
600 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); 529 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
601 } else { 530 } else {
602 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST"); 531 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, config.http_method), "CURLOPT_CUSTOMREQUEST");
603 } 532 }
604 } 533 }
605 534
535 char *force_host_header = NULL;
606 /* check if Host header is explicitly set in options */ 536 /* check if Host header is explicitly set in options */
607 if (http_opt_headers_count) { 537 if (config.http_opt_headers_count) {
608 for (i = 0; i < http_opt_headers_count; i++) { 538 for (int i = 0; i < config.http_opt_headers_count; i++) {
609 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 539 if (strncmp(config.http_opt_headers[i], "Host:", 5) == 0) {
610 force_host_header = http_opt_headers[i]; 540 force_host_header = config.http_opt_headers[i];
611 } 541 }
612 } 542 }
613 } 543 }
614 544
615 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */ 545 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */
616 if (host_name != NULL && force_host_header == NULL) { 546 char http_header[DEFAULT_BUFFER_SIZE];
617 if ((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) { 547 if (config.host_name != NULL && force_host_header == NULL) {
618 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port); 548 if ((config.virtual_port != HTTP_PORT && !config.use_ssl) || (config.virtual_port != HTTPS_PORT && config.use_ssl)) {
549 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", config.host_name, config.virtual_port);
619 } else { 550 } else {
620 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); 551 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", config.host_name);
621 } 552 }
622 header_list = curl_slist_append(header_list, http_header); 553 header_list = curl_slist_append(header_list, http_header);
623 } 554 }
@@ -628,9 +559,9 @@ int check_http(void) {
628 559
629 /* attach additional headers supplied by the user */ 560 /* attach additional headers supplied by the user */
630 /* optionally send any other header tag */ 561 /* optionally send any other header tag */
631 if (http_opt_headers_count) { 562 if (config.http_opt_headers_count) {
632 for (i = 0; i < http_opt_headers_count; i++) { 563 for (int i = 0; i < config.http_opt_headers_count; i++) {
633 header_list = curl_slist_append(header_list, http_opt_headers[i]); 564 header_list = curl_slist_append(header_list, config.http_opt_headers[i]);
634 } 565 }
635 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 566 /* This cannot be free'd here because a redirection will then try to access this and segfault */
636 /* Covered in a testcase in tests/check_http.t */ 567 /* Covered in a testcase in tests/check_http.t */
@@ -643,21 +574,21 @@ int check_http(void) {
643#ifdef LIBCURL_FEATURE_SSL 574#ifdef LIBCURL_FEATURE_SSL
644 575
645 /* set SSL version, warn about insecure or unsupported versions */ 576 /* set SSL version, warn about insecure or unsupported versions */
646 if (use_ssl) { 577 if (config.use_ssl) {
647 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 578 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLVERSION, config.ssl_version), "CURLOPT_SSLVERSION");
648 } 579 }
649 580
650 /* client certificate and key to present to server (SSL) */ 581 /* client certificate and key to present to server (SSL) */
651 if (client_cert) { 582 if (config.client_cert) {
652 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT"); 583 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, config.client_cert), "CURLOPT_SSLCERT");
653 } 584 }
654 if (client_privkey) { 585 if (config.client_privkey) {
655 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY"); 586 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, config.client_privkey), "CURLOPT_SSLKEY");
656 } 587 }
657 if (ca_cert) { 588 if (config.ca_cert) {
658 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); 589 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, config.ca_cert), "CURLOPT_CAINFO");
659 } 590 }
660 if (ca_cert || verify_peer_and_host) { 591 if (config.ca_cert || config.verify_peer_and_host) {
661 /* per default if we have a CA verify both the peer and the 592 /* per default if we have a CA verify both the peer and the
662 * hostname in the certificate, can be switched off later */ 593 * hostname in the certificate, can be switched off later */
663 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER"); 594 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
@@ -675,7 +606,7 @@ int check_http(void) {
675 ssl_library = curlhelp_get_ssl_library(); 606 ssl_library = curlhelp_get_ssl_library();
676 607
677 /* try hard to get a stack of certificates to verify against */ 608 /* try hard to get a stack of certificates to verify against */
678 if (check_cert) { 609 if (config.check_cert) {
679# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) 610# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
680 /* inform curl to report back certificates */ 611 /* inform curl to report back certificates */
681 switch (ssl_library) { 612 switch (ssl_library) {
@@ -740,16 +671,16 @@ int check_http(void) {
740#endif /* LIBCURL_FEATURE_SSL */ 671#endif /* LIBCURL_FEATURE_SSL */
741 672
742 /* set default or user-given user agent identification */ 673 /* set default or user-given user agent identification */
743 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); 674 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, config.user_agent), "CURLOPT_USERAGENT");
744 675
745 /* proxy-authentication */ 676 /* proxy-authentication */
746 if (strcmp(proxy_auth, "")) { 677 if (strcmp(config.proxy_auth, "")) {
747 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD"); 678 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, config.proxy_auth), "CURLOPT_PROXYUSERPWD");
748 } 679 }
749 680
750 /* authentication */ 681 /* authentication */
751 if (strcmp(user_auth, "")) { 682 if (strcmp(config.user_auth, "")) {
752 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD"); 683 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, config.user_auth), "CURLOPT_USERPWD");
753 } 684 }
754 685
755 /* TODO: parameter auth method, bitfield of following methods: 686 /* TODO: parameter auth method, bitfield of following methods:
@@ -768,14 +699,14 @@ int check_http(void) {
768 */ 699 */
769 700
770 /* handle redirections */ 701 /* handle redirections */
771 if (onredirect == STATE_DEPENDENT) { 702 if (config.onredirect == STATE_DEPENDENT) {
772 if (followmethod == FOLLOW_LIBCURL) { 703 if (config.followmethod == FOLLOW_LIBCURL) {
773 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION"); 704 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
774 705
775 /* default -1 is infinite, not good, could lead to zombie plugins! 706 /* default -1 is infinite, not good, could lead to zombie plugins!
776 Setting it to one bigger than maximal limit to handle errors nicely below 707 Setting it to one bigger than maximal limit to handle errors nicely below
777 */ 708 */
778 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_depth + 1), "CURLOPT_MAXREDIRS"); 709 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_MAXREDIRS, config.max_depth + 1), "CURLOPT_MAXREDIRS");
779 710
780 /* for now allow only http and https (we are a http(s) check plugin in the end) */ 711 /* for now allow only http and https (we are a http(s) check plugin in the end) */
781#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) 712#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
@@ -799,7 +730,7 @@ int check_http(void) {
799 } 730 }
800 731
801 /* no-body */ 732 /* no-body */
802 if (no_body) { 733 if (config.no_body) {
803 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY"); 734 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
804 } 735 }
805 736
@@ -819,48 +750,48 @@ int check_http(void) {
819#endif 750#endif
820 751
821 /* either send http POST data (any data, not only POST)*/ 752 /* either send http POST data (any data, not only POST)*/
822 if (!strcmp(http_method, "POST") || !strcmp(http_method, "PUT")) { 753 if (!strcmp(config.http_method, "POST") || !strcmp(config.http_method, "PUT")) {
823 /* set content of payload for POST and PUT */ 754 /* set content of payload for POST and PUT */
824 if (http_content_type) { 755 if (config.http_content_type) {
825 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type); 756 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", config.http_content_type);
826 header_list = curl_slist_append(header_list, http_header); 757 header_list = curl_slist_append(header_list, http_header);
827 } 758 }
828 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string 759 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
829 * in case of no POST/PUT data */ 760 * in case of no POST/PUT data */
830 if (!http_post_data) { 761 if (!config.http_post_data) {
831 http_post_data = ""; 762 config.http_post_data = "";
832 } 763 }
833 if (!strcmp(http_method, "POST")) { 764 if (!strcmp(config.http_method, "POST")) {
834 /* POST method, set payload with CURLOPT_POSTFIELDS */ 765 /* POST method, set payload with CURLOPT_POSTFIELDS */
835 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS"); 766 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, config.http_post_data), "CURLOPT_POSTFIELDS");
836 } else if (!strcmp(http_method, "PUT")) { 767 } else if (!strcmp(config.http_method, "PUT")) {
837 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), 768 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback),
838 "CURLOPT_READFUNCTION"); 769 "CURLOPT_READFUNCTION");
839 if (curlhelp_initreadbuffer(&put_buf, http_post_data, strlen(http_post_data)) < 0) { 770 if (curlhelp_initreadbuffer(&put_buf, config.http_post_data, strlen(config.http_post_data)) < 0) {
840 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); 771 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
841 } 772 }
842 put_buf_initialized = true; 773 put_buf_initialized = true;
843 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); 774 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
844 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_INFILESIZE, (curl_off_t)strlen(http_post_data)), 775 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_INFILESIZE, (curl_off_t)strlen(config.http_post_data)),
845 "CURLOPT_INFILESIZE"); 776 "CURLOPT_INFILESIZE");
846 } 777 }
847 } 778 }
848 779
849 /* cookie handling */ 780 /* cookie handling */
850 if (cookie_jar_file != NULL) { 781 if (config.cookie_jar_file != NULL) {
851 /* enable reading cookies from a file, and if the filename is an empty string, only enable the curl cookie engine */ 782 /* enable reading cookies from a file, and if the filename is an empty string, only enable the curl cookie engine */
852 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE"); 783 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, config.cookie_jar_file), "CURLOPT_COOKIEFILE");
853 /* now enable saving cookies to a file, but only if the filename is not an empty string, since writing it would fail */ 784 /* now enable saving cookies to a file, but only if the filename is not an empty string, since writing it would fail */
854 if (*cookie_jar_file) { 785 if (*config.cookie_jar_file) {
855 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR"); 786 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, config.cookie_jar_file), "CURLOPT_COOKIEJAR");
856 } 787 }
857 } 788 }
858 789
859 /* do the request */ 790 /* do the request */
860 res = curl_easy_perform(curl); 791 CURLcode res = curl_easy_perform(curl);
861 792
862 if (verbose >= 2 && http_post_data) { 793 if (verbose >= 2 && config.http_post_data) {
863 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data); 794 printf("**** REQUEST CONTENT ****\n%s\n", config.http_post_data);
864 } 795 }
865 796
866 /* free header and server IP resolve lists, we don't need it anymore */ 797 /* free header and server IP resolve lists, we don't need it anymore */
@@ -875,22 +806,23 @@ int check_http(void) {
875 806
876 /* Curl errors, result in critical Nagios state */ 807 /* Curl errors, result in critical Nagios state */
877 if (res != CURLE_OK) { 808 if (res != CURLE_OK) {
878 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), server_port, 809 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"),
879 res, errbuf[0] ? errbuf : curl_easy_strerror(res)); 810 config.server_port, res, errbuf[0] ? errbuf : curl_easy_strerror(res));
880 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 811 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
881 } 812 }
882 813
814 int result_ssl = STATE_OK;
883 /* certificate checks */ 815 /* certificate checks */
884#ifdef LIBCURL_FEATURE_SSL 816#ifdef LIBCURL_FEATURE_SSL
885 if (use_ssl) { 817 if (config.use_ssl) {
886 if (check_cert) { 818 if (config.check_cert) {
887 if (is_openssl_callback) { 819 if (is_openssl_callback) {
888# ifdef USE_OPENSSL 820# ifdef USE_OPENSSL
889 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 821 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
890 * and we actually have OpenSSL in the monitoring tools 822 * and we actually have OpenSSL in the monitoring tools
891 */ 823 */
892 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 824 result_ssl = np_net_ssl_check_certificate(cert, config.days_till_exp_warn, config.days_till_exp_crit);
893 if (!continue_after_check_cert) { 825 if (!config.continue_after_check_cert) {
894 return result_ssl; 826 return result_ssl;
895 } 827 }
896# else /* USE_OPENSSL */ 828# else /* USE_OPENSSL */
@@ -898,7 +830,6 @@ int check_http(void) {
898 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n"); 830 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
899# endif /* USE_OPENSSL */ 831# endif /* USE_OPENSSL */
900 } else { 832 } else {
901 int i;
902 struct curl_slist *slist; 833 struct curl_slist *slist;
903 834
904 cert_ptr.to_info = NULL; 835 cert_ptr.to_info = NULL;
@@ -909,7 +840,7 @@ int check_http(void) {
909 * We only check the first certificate and assume it's the one of the server 840 * We only check the first certificate and assume it's the one of the server
910 */ 841 */
911 const char *raw_cert = NULL; 842 const char *raw_cert = NULL;
912 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { 843 for (int i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
913 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { 844 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
914 if (verbose >= 2) { 845 if (verbose >= 2) {
915 printf("%d ** %s\n", i, slist->data); 846 printf("%d ** %s\n", i, slist->data);
@@ -934,8 +865,8 @@ int check_http(void) {
934 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 865 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
935 } 866 }
936 BIO_free(cert_BIO); 867 BIO_free(cert_BIO);
937 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 868 result_ssl = np_net_ssl_check_certificate(cert, config.days_till_exp_warn, config.days_till_exp_crit);
938 if (!continue_after_check_cert) { 869 if (!config.continue_after_check_cert) {
939 return result_ssl; 870 return result_ssl;
940 } 871 }
941# else /* USE_OPENSSL */ 872# else /* USE_OPENSSL */
@@ -960,20 +891,30 @@ int check_http(void) {
960 /* we got the data and we executed the request in a given time, so we can append 891 /* we got the data and we executed the request in a given time, so we can append
961 * performance data to the answer always 892 * performance data to the answer always
962 */ 893 */
894 double total_time;
963 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME"); 895 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME");
964 page_len = get_content_length(&header_buf, &body_buf); 896 int page_len = get_content_length(&header_buf, &body_buf);
965 if (show_extended_perfdata) { 897 char perfstring[DEFAULT_BUFFER_SIZE];
898 if (config.show_extended_perfdata) {
899 double time_connect;
966 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME"); 900 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME");
901 double time_appconnect;
967 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME"); 902 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME");
903 double time_headers;
968 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME"); 904 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME");
905 double time_firstbyte;
969 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), 906 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
970 "CURLINFO_STARTTRANSFER_TIME"); 907 "CURLINFO_STARTTRANSFER_TIME");
971 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time), perfd_size(page_len), 908
972 perfd_time_connect(time_connect), use_ssl ? perfd_time_ssl(time_appconnect - time_connect) : "", 909 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time, config.thlds, config.socket_timeout),
973 perfd_time_headers(time_headers - time_appconnect), perfd_time_firstbyte(time_firstbyte - time_headers), 910 perfd_size(page_len, config.min_page_len), perfd_time_connect(time_connect, config.socket_timeout),
974 perfd_time_transfer(total_time - time_firstbyte)); 911 config.use_ssl ? perfd_time_ssl(time_appconnect - time_connect, config.socket_timeout) : "",
912 perfd_time_headers(time_headers - time_appconnect, config.socket_timeout),
913 perfd_time_firstbyte(time_firstbyte - time_headers, config.socket_timeout),
914 perfd_time_transfer(total_time - time_firstbyte, config.socket_timeout));
975 } else { 915 } else {
976 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time), perfd_size(page_len)); 916 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time, config.thlds, config.socket_timeout),
917 perfd_size(page_len, config.min_page_len));
977 } 918 }
978 919
979 /* return a CRITICAL status if we couldn't read any data */ 920 /* return a CRITICAL status if we couldn't read any data */
@@ -997,22 +938,23 @@ int check_http(void) {
997 938
998 /* print status line, header, body if verbose */ 939 /* print status line, header, body if verbose */
999 if (verbose >= 2) { 940 if (verbose >= 2) {
1000 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (no_body ? " [[ skipped ]]" : body_buf.buf)); 941 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (config.no_body ? " [[ skipped ]]" : body_buf.buf));
1001 } 942 }
1002 943
1003 /* make sure the status line matches the response we are looking for */ 944 /* make sure the status line matches the response we are looking for */
1004 if (!expected_statuscode(status_line.first_line, server_expect)) { 945 if (!expected_statuscode(status_line.first_line, config.server_expect)) {
1005 if (server_port == HTTP_PORT) { 946 if (config.server_port == HTTP_PORT) {
1006 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line); 947 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line);
1007 } else { 948 } else {
1008 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port, 949 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), config.server_port,
1009 status_line.first_line); 950 status_line.first_line);
1010 } 951 }
1011 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : ""); 952 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "", config.show_body ? body_buf.buf : "");
1012 } 953 }
1013 954
1014 if (server_expect_yn) { 955 int result = STATE_OK;
1015 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect); 956 if (config.server_expect_yn) {
957 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), config.server_expect);
1016 if (verbose) { 958 if (verbose) {
1017 printf("%s\n", msg); 959 printf("%s\n", msg);
1018 } 960 }
@@ -1029,22 +971,22 @@ int check_http(void) {
1029 result = STATE_WARNING; 971 result = STATE_WARNING;
1030 /* check redirected page if specified */ 972 /* check redirected page if specified */
1031 } else if (code >= 300) { 973 } else if (code >= 300) {
1032 if (onredirect == STATE_DEPENDENT) { 974 if (config.onredirect == STATE_DEPENDENT) {
1033 if (followmethod == FOLLOW_LIBCURL) { 975 if (config.followmethod == FOLLOW_LIBCURL) {
1034 code = status_line.http_code; 976 code = status_line.http_code;
1035 } else { 977 } else {
1036 /* old check_http style redirection, if we come 978 /* old check_http style redirection, if we come
1037 * back here, we are in the same status as with 979 * back here, we are in the same status as with
1038 * the libcurl method 980 * the libcurl method
1039 */ 981 */
1040 redir(&header_buf); 982 redir(&header_buf, config);
1041 } 983 }
1042 } else { 984 } else {
1043 /* this is a specific code in the command line to 985 /* this is a specific code in the command line to
1044 * be returned when a redirection is encountered 986 * be returned when a redirection is encountered
1045 */ 987 */
1046 } 988 }
1047 result = max_state_alt(onredirect, result); 989 result = max_state_alt(config.onredirect, result);
1048 /* all other codes are considered ok */ 990 /* all other codes are considered ok */
1049 } else { 991 } else {
1050 result = STATE_OK; 992 result = STATE_OK;
@@ -1052,13 +994,13 @@ int check_http(void) {
1052 } 994 }
1053 995
1054 /* libcurl redirection internally, handle error states here */ 996 /* libcurl redirection internally, handle error states here */
1055 if (followmethod == FOLLOW_LIBCURL) { 997 if (config.followmethod == FOLLOW_LIBCURL) {
1056 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT"); 998 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1057 if (verbose >= 2) { 999 if (verbose >= 2) {
1058 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); 1000 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1059 } 1001 }
1060 if (redir_depth > max_depth) { 1002 if (redir_depth > config.max_depth) {
1061 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", max_depth); 1003 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", config.max_depth);
1062 die(STATE_WARNING, "HTTP WARNING - %s", msg); 1004 die(STATE_WARNING, "HTTP WARNING - %s", msg);
1063 } 1005 }
1064 } 1006 }
@@ -1069,16 +1011,17 @@ int check_http(void) {
1069 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code); 1011 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code);
1070 } 1012 }
1071 1013
1072 if (maximum_age >= 0) { 1014 if (config.maximum_age >= 0) {
1073 result = max_state_alt(check_document_dates(&header_buf, &msg), result); 1015 result = max_state_alt(check_document_dates(&header_buf, &msg, config.maximum_age), result);
1074 } 1016 }
1075 1017
1076 /* Page and Header content checks go here */ 1018 /* Page and Header content checks go here */
1077 1019
1078 if (strlen(header_expect)) { 1020 if (strlen(config.header_expect)) {
1079 if (!strstr(header_buf.buf, header_expect)) { 1021 if (!strstr(header_buf.buf, config.header_expect)) {
1080 1022
1081 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search)); 1023 char output_header_search[30] = "";
1024 strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search));
1082 1025
1083 if (output_header_search[sizeof(output_header_search) - 1] != '\0') { 1026 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1084 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4); 1027 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
@@ -1087,7 +1030,8 @@ int check_http(void) {
1087 char tmp[DEFAULT_BUFFER_SIZE]; 1030 char tmp[DEFAULT_BUFFER_SIZE];
1088 1031
1089 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search, 1032 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search,
1090 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1033 config.use_ssl ? "https" : "http", config.host_name ? config.host_name : config.server_address, config.server_port,
1034 config.server_url);
1091 1035
1092 strcpy(msg, tmp); 1036 strcpy(msg, tmp);
1093 1037
@@ -1095,10 +1039,11 @@ int check_http(void) {
1095 } 1039 }
1096 } 1040 }
1097 1041
1098 if (strlen(string_expect)) { 1042 if (strlen(config.string_expect)) {
1099 if (!strstr(body_buf.buf, string_expect)) { 1043 if (!strstr(body_buf.buf, config.string_expect)) {
1100 1044
1101 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search)); 1045 char output_string_search[30] = "";
1046 strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search));
1102 1047
1103 if (output_string_search[sizeof(output_string_search) - 1] != '\0') { 1048 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1104 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4); 1049 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
@@ -1107,7 +1052,8 @@ int check_http(void) {
1107 char tmp[DEFAULT_BUFFER_SIZE]; 1052 char tmp[DEFAULT_BUFFER_SIZE];
1108 1053
1109 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, 1054 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search,
1110 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1055 config.use_ssl ? "https" : "http", config.host_name ? config.host_name : config.server_address, config.server_port,
1056 config.server_url);
1111 1057
1112 strcpy(msg, tmp); 1058 strcpy(msg, tmp);
1113 1059
@@ -1115,13 +1061,15 @@ int check_http(void) {
1115 } 1061 }
1116 } 1062 }
1117 1063
1118 if (strlen(regexp)) { 1064 if (strlen(config.regexp)) {
1119 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0); 1065 regex_t preg;
1120 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) { 1066 regmatch_t pmatch[REGS];
1067 int errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0);
1068 if ((errcode == 0 && !config.invert_regex) || (errcode == REG_NOMATCH && config.invert_regex)) {
1121 /* OK - No-op to avoid changing the logic around it */ 1069 /* OK - No-op to avoid changing the logic around it */
1122 result = max_state_alt(STATE_OK, result); 1070 result = max_state_alt(STATE_OK, result);
1123 } else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) { 1071 } else if ((errcode == REG_NOMATCH && !config.invert_regex) || (errcode == 0 && config.invert_regex)) {
1124 if (!invert_regex) { 1072 if (!config.invert_regex) {
1125 char tmp[DEFAULT_BUFFER_SIZE]; 1073 char tmp[DEFAULT_BUFFER_SIZE];
1126 1074
1127 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1075 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
@@ -1133,7 +1081,7 @@ int check_http(void) {
1133 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1081 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1134 strcpy(msg, tmp); 1082 strcpy(msg, tmp);
1135 } 1083 }
1136 result = state_regex; 1084 result = config.state_regex;
1137 } else { 1085 } else {
1138 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1086 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1139 1087
@@ -1146,7 +1094,7 @@ int check_http(void) {
1146 } 1094 }
1147 1095
1148 /* make sure the page is of an appropriate size */ 1096 /* make sure the page is of an appropriate size */
1149 if ((max_page_len > 0) && (page_len > max_page_len)) { 1097 if ((config.max_page_len > 0) && (page_len > config.max_page_len)) {
1150 char tmp[DEFAULT_BUFFER_SIZE]; 1098 char tmp[DEFAULT_BUFFER_SIZE];
1151 1099
1152 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 1100 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
@@ -1155,7 +1103,7 @@ int check_http(void) {
1155 1103
1156 result = max_state_alt(STATE_WARNING, result); 1104 result = max_state_alt(STATE_WARNING, result);
1157 1105
1158 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1106 } else if ((config.min_page_len > 0) && (page_len < config.min_page_len)) {
1159 char tmp[DEFAULT_BUFFER_SIZE]; 1107 char tmp[DEFAULT_BUFFER_SIZE];
1160 1108
1161 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 1109 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
@@ -1164,7 +1112,7 @@ int check_http(void) {
1164 } 1112 }
1165 1113
1166 /* -w, -c: check warning and critical level */ 1114 /* -w, -c: check warning and critical level */
1167 result = max_state_alt(get_status(total_time, thlds), result); 1115 result = max_state_alt(get_status(total_time, config.thlds), result);
1168 1116
1169 /* Cut-off trailing characters */ 1117 /* Cut-off trailing characters */
1170 if (strlen(msg) >= 2) { 1118 if (strlen(msg) >= 2) {
@@ -1178,8 +1126,8 @@ int check_http(void) {
1178 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 1126 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */
1179 die(max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", state_text(result), 1127 die(max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", state_text(result),
1180 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, 1128 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg,
1181 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, (display_html ? "</A>" : ""), perfstring, (show_body ? body_buf.buf : ""), 1129 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, (config.display_html ? "</A>" : ""), perfstring,
1182 (show_body ? "\n" : "")); 1130 (config.show_body ? body_buf.buf : ""), (config.show_body ? "\n" : ""));
1183 1131
1184 return max_state_alt(result, result_ssl); 1132 return max_state_alt(result, result_ssl);
1185} 1133}
@@ -1204,18 +1152,11 @@ char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1204 return buf; 1152 return buf;
1205} 1153}
1206 1154
1207void redir(curlhelp_write_curlbuf *header_buf) { 1155void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config) {
1208 char *location = NULL;
1209 curlhelp_statusline status_line; 1156 curlhelp_statusline status_line;
1210 struct phr_header headers[255]; 1157 struct phr_header headers[255];
1211 size_t nof_headers = 255;
1212 size_t msglen; 1158 size_t msglen;
1213 char buf[DEFAULT_BUFFER_SIZE]; 1159 size_t nof_headers = 255;
1214 char ipstr[INET_ADDR_MAX_SIZE];
1215 int new_port;
1216 char *new_host;
1217 char *new_url;
1218
1219 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor, 1160 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
1220 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0); 1161 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
1221 1162
@@ -1223,15 +1164,15 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1223 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 1164 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1224 } 1165 }
1225 1166
1226 location = get_header_value(headers, nof_headers, "location"); 1167 char *location = get_header_value(headers, nof_headers, "location");
1227 1168
1228 if (verbose >= 2) { 1169 if (verbose >= 2) {
1229 printf(_("* Seen redirect location %s\n"), location); 1170 printf(_("* Seen redirect location %s\n"), location);
1230 } 1171 }
1231 1172
1232 if (++redir_depth > max_depth) { 1173 if (++redir_depth > config.max_depth) {
1233 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), max_depth, location, 1174 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), config.max_depth, location,
1234 (display_html ? "</A>" : "")); 1175 (config.display_html ? "</A>" : ""));
1235 } 1176 }
1236 1177
1237 UriParserStateA state; 1178 UriParserStateA state;
@@ -1239,12 +1180,15 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1239 state.uri = &uri; 1180 state.uri = &uri;
1240 if (uriParseUriA(&state, location) != URI_SUCCESS) { 1181 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1241 if (state.errorCode == URI_ERROR_SYNTAX) { 1182 if (state.errorCode == URI_ERROR_SYNTAX) {
1242 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location, (display_html ? "</A>" : "")); 1183 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location,
1184 (config.display_html ? "</A>" : ""));
1243 } else if (state.errorCode == URI_ERROR_MALLOC) { 1185 } else if (state.errorCode == URI_ERROR_MALLOC) {
1244 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1186 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1245 } 1187 }
1246 } 1188 }
1247 1189
1190 char ipstr[INET_ADDR_MAX_SIZE];
1191 char buf[DEFAULT_BUFFER_SIZE];
1248 if (verbose >= 2) { 1192 if (verbose >= 2) {
1249 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE)); 1193 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1250 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1194 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
@@ -1274,35 +1218,34 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1274 } 1218 }
1275 1219
1276 if (uri.scheme.first) { 1220 if (uri.scheme.first) {
1277 if (!uri_strcmp(uri.scheme, "https")) { 1221 config.use_ssl = (bool)(!uri_strcmp(uri.scheme, "https"));
1278 use_ssl = true;
1279 } else {
1280 use_ssl = false;
1281 }
1282 } 1222 }
1283 1223
1284 /* we do a sloppy test here only, because uriparser would have failed 1224 /* we do a sloppy test here only, because uriparser would have failed
1285 * above, if the port would be invalid, we just check for MAX_PORT 1225 * above, if the port would be invalid, we just check for MAX_PORT
1286 */ 1226 */
1227 int new_port;
1287 if (uri.portText.first) { 1228 if (uri.portText.first) {
1288 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1229 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1289 } else { 1230 } else {
1290 new_port = HTTP_PORT; 1231 new_port = HTTP_PORT;
1291 if (use_ssl) { 1232 if (config.use_ssl) {
1292 new_port = HTTPS_PORT; 1233 new_port = HTTPS_PORT;
1293 } 1234 }
1294 } 1235 }
1295 if (new_port > MAX_PORT) { 1236 if (new_port > MAX_PORT) {
1296 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location, display_html ? "</A>" : ""); 1237 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location,
1238 config.display_html ? "</A>" : "");
1297 } 1239 }
1298 1240
1299 /* by RFC 7231 relative URLs in Location should be taken relative to 1241 /* by RFC 7231 relative URLs in Location should be taken relative to
1300 * the original URL, so we try to form a new absolute URL here 1242 * the original URL, so we try to form a new absolute URL here
1301 */ 1243 */
1244 char *new_host;
1302 if (!uri.scheme.first && !uri.hostText.first) { 1245 if (!uri.scheme.first && !uri.hostText.first) {
1303 new_host = strdup(host_name ? host_name : server_address); 1246 new_host = strdup(config.host_name ? config.host_name : config.server_address);
1304 new_port = server_port; 1247 new_port = config.server_port;
1305 if (use_ssl) { 1248 if (config.use_ssl) {
1306 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE); 1249 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1307 } 1250 }
1308 } else { 1251 } else {
@@ -1311,7 +1254,7 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1311 1254
1312 /* compose new path */ 1255 /* compose new path */
1313 /* TODO: handle fragments and query part of URL */ 1256 /* TODO: handle fragments and query part of URL */
1314 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); 1257 char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1315 if (uri.pathHead) { 1258 if (uri.pathHead) {
1316 const UriPathSegmentA *p = uri.pathHead; 1259 const UriPathSegmentA *p = uri.pathHead;
1317 for (; p; p = p->next) { 1260 for (; p; p = p->next) {
@@ -1320,37 +1263,37 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1320 } 1263 }
1321 } 1264 }
1322 1265
1323 if (server_port == new_port && !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && 1266 if (config.server_port == new_port && !strncmp(config.server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1324 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, new_url)) { 1267 (config.host_name && !strncmp(config.host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(config.server_url, new_url)) {
1325 die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), use_ssl ? "https" : "http", 1268 die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), config.use_ssl ? "https" : "http",
1326 new_host, new_port, new_url, (display_html ? "</A>" : "")); 1269 new_host, new_port, new_url, (config.display_html ? "</A>" : ""));
1327 } 1270 }
1328 1271
1329 /* set new values for redirected request */ 1272 /* set new values for redirected request */
1330 1273
1331 if (!(followsticky & STICKY_HOST)) { 1274 if (!(config.followsticky & STICKY_HOST)) {
1332 free(server_address); 1275 free(config.server_address);
1333 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); 1276 config.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1334 } 1277 }
1335 if (!(followsticky & STICKY_PORT)) { 1278 if (!(config.followsticky & STICKY_PORT)) {
1336 server_port = (unsigned short)new_port; 1279 config.server_port = (unsigned short)new_port;
1337 } 1280 }
1338 1281
1339 free(host_name); 1282 free(config.host_name);
1340 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); 1283 config.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1341 1284
1342 /* reset virtual port */ 1285 /* reset virtual port */
1343 virtual_port = server_port; 1286 config.virtual_port = config.server_port;
1344 1287
1345 free(new_host); 1288 free(new_host);
1346 free(server_url); 1289 free(config.server_url);
1347 server_url = new_url; 1290 config.server_url = new_url;
1348 1291
1349 uriFreeUriMembersA(&uri); 1292 uriFreeUriMembersA(&uri);
1350 1293
1351 if (verbose) { 1294 if (verbose) {
1352 printf(_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, 1295 printf(_("Redirection to %s://%s:%d%s\n"), config.use_ssl ? "https" : "http",
1353 server_url); 1296 config.host_name ? config.host_name : config.server_address, config.server_port, config.server_url);
1354 } 1297 }
1355 1298
1356 /* TODO: the hash component MUST be taken from the original URL and 1299 /* TODO: the hash component MUST be taken from the original URL and
@@ -1358,7 +1301,7 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1358 */ 1301 */
1359 1302
1360 cleanup(); 1303 cleanup();
1361 check_http(); 1304 check_http(config);
1362} 1305}
1363 1306
1364/* check whether a file exists */ 1307/* check whether a file exists */
@@ -1369,11 +1312,7 @@ void test_file(char *path) {
1369 usage2(_("file does not exist or is not readable"), path); 1312 usage2(_("file does not exist or is not readable"), path);
1370} 1313}
1371 1314
1372bool process_arguments(int argc, char **argv) { 1315check_curl_config_wrapper process_arguments(int argc, char **argv) {
1373 char *p;
1374 int c = 1;
1375 char *temp;
1376
1377 enum { 1316 enum {
1378 INVERT_REGEX = CHAR_MAX + 1, 1317 INVERT_REGEX = CHAR_MAX + 1,
1379 SNI_OPTION, 1318 SNI_OPTION,
@@ -1387,8 +1326,6 @@ bool process_arguments(int argc, char **argv) {
1387 STATE_REGEX 1326 STATE_REGEX
1388 }; 1327 };
1389 1328
1390 int option = 0;
1391 int got_plus = 0;
1392 static struct option longopts[] = {STD_LONG_OPTS, 1329 static struct option longopts[] = {STD_LONG_OPTS,
1393 {"link", no_argument, 0, 'L'}, 1330 {"link", no_argument, 0, 'L'},
1394 {"nohtml", no_argument, 0, 'n'}, 1331 {"nohtml", no_argument, 0, 'n'},
@@ -1434,38 +1371,48 @@ bool process_arguments(int argc, char **argv) {
1434 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 1371 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1435 {0, 0, 0, 0}}; 1372 {0, 0, 0, 0}};
1436 1373
1374 check_curl_config_wrapper result = {
1375 .errorcode = OK,
1376 .config = check_curl_config_init(),
1377 };
1378
1437 if (argc < 2) { 1379 if (argc < 2) {
1438 return false; 1380 result.errorcode = ERROR;
1381 return result;
1439 } 1382 }
1440 1383
1441 /* support check_http compatible arguments */ 1384 /* support check_http compatible arguments */
1442 for (c = 1; c < argc; c++) { 1385 for (int index = 1; index < argc; index++) {
1443 if (strcmp("-to", argv[c]) == 0) { 1386 if (strcmp("-to", argv[index]) == 0) {
1444 strcpy(argv[c], "-t"); 1387 strcpy(argv[index], "-t");
1445 } 1388 }
1446 if (strcmp("-hn", argv[c]) == 0) { 1389 if (strcmp("-hn", argv[index]) == 0) {
1447 strcpy(argv[c], "-H"); 1390 strcpy(argv[index], "-H");
1448 } 1391 }
1449 if (strcmp("-wt", argv[c]) == 0) { 1392 if (strcmp("-wt", argv[index]) == 0) {
1450 strcpy(argv[c], "-w"); 1393 strcpy(argv[index], "-w");
1451 } 1394 }
1452 if (strcmp("-ct", argv[c]) == 0) { 1395 if (strcmp("-ct", argv[index]) == 0) {
1453 strcpy(argv[c], "-c"); 1396 strcpy(argv[index], "-c");
1454 } 1397 }
1455 if (strcmp("-nohtml", argv[c]) == 0) { 1398 if (strcmp("-nohtml", argv[index]) == 0) {
1456 strcpy(argv[c], "-n"); 1399 strcpy(argv[index], "-n");
1457 } 1400 }
1458 } 1401 }
1459 1402
1460 server_url = strdup(DEFAULT_SERVER_URL); 1403 int option = 0;
1461 1404 char *warning_thresholds = NULL;
1462 while (1) { 1405 char *critical_thresholds = NULL;
1463 c = getopt_long(argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option); 1406 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
1464 if (c == -1 || c == EOF || c == 1) { 1407 bool specify_port = false;
1408
1409 while (true) {
1410 int option_index = getopt_long(argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option);
1411 if (option_index == -1 || option_index == EOF || option_index == 1) {
1465 break; 1412 break;
1466 } 1413 }
1467 1414
1468 switch (c) { 1415 switch (option_index) {
1469 case 'h': 1416 case 'h':
1470 print_help(); 1417 print_help();
1471 exit(STATE_UNKNOWN); 1418 exit(STATE_UNKNOWN);
@@ -1482,7 +1429,7 @@ bool process_arguments(int argc, char **argv) {
1482 if (!is_intnonneg(optarg)) { 1429 if (!is_intnonneg(optarg)) {
1483 usage2(_("Timeout interval must be a positive integer"), optarg); 1430 usage2(_("Timeout interval must be a positive integer"), optarg);
1484 } else { 1431 } else {
1485 socket_timeout = (int)strtol(optarg, NULL, 10); 1432 result.config.socket_timeout = (int)strtol(optarg, NULL, 10);
1486 } 1433 }
1487 break; 1434 break;
1488 case 'c': /* critical time threshold */ 1435 case 'c': /* critical time threshold */
@@ -1492,28 +1439,30 @@ bool process_arguments(int argc, char **argv) {
1492 warning_thresholds = optarg; 1439 warning_thresholds = optarg;
1493 break; 1440 break;
1494 case 'H': /* virtual host */ 1441 case 'H': /* virtual host */
1495 host_name = strdup(optarg); 1442 result.config.host_name = strdup(optarg);
1496 if (host_name[0] == '[') { 1443 char *p;
1497 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */ 1444 int host_name_length;
1498 virtual_port = atoi(p + 2); 1445 if (result.config.host_name[0] == '[') {
1446 if ((p = strstr(result.config.host_name, "]:")) != NULL) { /* [IPv6]:port */
1447 result.config.virtual_port = atoi(p + 2);
1499 /* cut off the port */ 1448 /* cut off the port */
1500 host_name_length = strlen(host_name) - strlen(p) - 1; 1449 host_name_length = strlen(result.config.host_name) - strlen(p) - 1;
1501 free(host_name); 1450 free(result.config.host_name);
1502 host_name = strndup(optarg, host_name_length); 1451 result.config.host_name = strndup(optarg, host_name_length);
1503 } 1452 }
1504 } else if ((p = strchr(host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */ 1453 } else if ((p = strchr(result.config.host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
1505 virtual_port = atoi(p); 1454 result.config.virtual_port = atoi(p);
1506 /* cut off the port */ 1455 /* cut off the port */
1507 host_name_length = strlen(host_name) - strlen(p) - 1; 1456 host_name_length = strlen(result.config.host_name) - strlen(p) - 1;
1508 free(host_name); 1457 free(result.config.host_name);
1509 host_name = strndup(optarg, host_name_length); 1458 result.config.host_name = strndup(optarg, host_name_length);
1510 } 1459 }
1511 break; 1460 break;
1512 case 'I': /* internet address */ 1461 case 'I': /* internet address */
1513 server_address = strdup(optarg); 1462 result.config.server_address = strdup(optarg);
1514 break; 1463 break;
1515 case 'u': /* URL path */ 1464 case 'u': /* URL path */
1516 server_url = strdup(optarg); 1465 result.config.server_url = strdup(optarg);
1517 break; 1466 break;
1518 case 'p': /* Server port */ 1467 case 'p': /* Server port */
1519 if (!is_intnonneg(optarg)) { 1468 if (!is_intnonneg(optarg)) {
@@ -1522,144 +1471,148 @@ bool process_arguments(int argc, char **argv) {
1522 if (strtol(optarg, NULL, 10) > MAX_PORT) { 1471 if (strtol(optarg, NULL, 10) > MAX_PORT) {
1523 usage2(_("Invalid port number, supplied port number is too big"), optarg); 1472 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1524 } 1473 }
1525 server_port = (unsigned short)strtol(optarg, NULL, 10); 1474 result.config.server_port = (unsigned short)strtol(optarg, NULL, 10);
1526 specify_port = true; 1475 specify_port = true;
1527 } 1476 }
1528 break; 1477 break;
1529 case 'a': /* authorization info */ 1478 case 'a': /* authorization info */
1530 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1); 1479 strncpy(result.config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
1531 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1480 result.config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
1532 break; 1481 break;
1533 case 'b': /* proxy-authorization info */ 1482 case 'b': /* proxy-authorization info */
1534 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1483 strncpy(result.config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1535 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1484 result.config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1536 break; 1485 break;
1537 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 1486 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1538 if (!http_post_data) { 1487 if (!result.config.http_post_data) {
1539 http_post_data = strdup(optarg); 1488 result.config.http_post_data = strdup(optarg);
1540 } 1489 }
1541 if (!http_method) { 1490 if (!result.config.http_method) {
1542 http_method = strdup("POST"); 1491 result.config.http_method = strdup("POST");
1543 } 1492 }
1544 break; 1493 break;
1545 case 'j': /* Set HTTP method */ 1494 case 'j': /* Set HTTP method */
1546 if (http_method) { 1495 if (result.config.http_method) {
1547 free(http_method); 1496 free(result.config.http_method);
1548 } 1497 }
1549 http_method = strdup(optarg); 1498 result.config.http_method = strdup(optarg);
1550 break; 1499 break;
1551 case 'A': /* useragent */ 1500 case 'A': /* useragent */
1552 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE); 1501 strncpy(result.config.user_agent, optarg, DEFAULT_BUFFER_SIZE);
1553 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0'; 1502 result.config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1554 break; 1503 break;
1555 case 'k': /* Additional headers */ 1504 case 'k': /* Additional headers */
1556 if (http_opt_headers_count == 0) { 1505 if (result.config.http_opt_headers_count == 0) {
1557 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count)); 1506 result.config.http_opt_headers = malloc(sizeof(char *) * (++result.config.http_opt_headers_count));
1558 } else { 1507 } else {
1559 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count)); 1508 result.config.http_opt_headers =
1509 realloc(result.config.http_opt_headers, sizeof(char *) * (++result.config.http_opt_headers_count));
1560 } 1510 }
1561 http_opt_headers[http_opt_headers_count - 1] = optarg; 1511 result.config.http_opt_headers[result.config.http_opt_headers_count - 1] = optarg;
1562 break; 1512 break;
1563 case 'L': /* show html link */ 1513 case 'L': /* show html link */
1564 display_html = true; 1514 result.config.display_html = true;
1565 break; 1515 break;
1566 case 'n': /* do not show html link */ 1516 case 'n': /* do not show html link */
1567 display_html = false; 1517 result.config.display_html = false;
1568 break; 1518 break;
1569 case 'C': /* Check SSL cert validity */ 1519 case 'C': /* Check SSL cert validity */
1570#ifdef LIBCURL_FEATURE_SSL 1520#ifdef LIBCURL_FEATURE_SSL
1521 char *temp;
1571 if ((temp = strchr(optarg, ',')) != NULL) { 1522 if ((temp = strchr(optarg, ',')) != NULL) {
1572 *temp = '\0'; 1523 *temp = '\0';
1573 if (!is_intnonneg(optarg)) { 1524 if (!is_intnonneg(optarg)) {
1574 usage2(_("Invalid certificate expiration period"), optarg); 1525 usage2(_("Invalid certificate expiration period"), optarg);
1575 } 1526 }
1576 days_till_exp_warn = atoi(optarg); 1527 result.config.days_till_exp_warn = atoi(optarg);
1577 *temp = ','; 1528 *temp = ',';
1578 temp++; 1529 temp++;
1579 if (!is_intnonneg(temp)) { 1530 if (!is_intnonneg(temp)) {
1580 usage2(_("Invalid certificate expiration period"), temp); 1531 usage2(_("Invalid certificate expiration period"), temp);
1581 } 1532 }
1582 days_till_exp_crit = atoi(temp); 1533 result.config.days_till_exp_crit = atoi(temp);
1583 } else { 1534 } else {
1584 days_till_exp_crit = 0; 1535 result.config.days_till_exp_crit = 0;
1585 if (!is_intnonneg(optarg)) { 1536 if (!is_intnonneg(optarg)) {
1586 usage2(_("Invalid certificate expiration period"), optarg); 1537 usage2(_("Invalid certificate expiration period"), optarg);
1587 } 1538 }
1588 days_till_exp_warn = atoi(optarg); 1539 result.config.days_till_exp_warn = atoi(optarg);
1589 } 1540 }
1590 check_cert = true; 1541 result.config.check_cert = true;
1591 goto enable_ssl; 1542 goto enable_ssl;
1592#endif 1543#endif
1593 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 1544 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1594#ifdef HAVE_SSL 1545#ifdef HAVE_SSL
1595 continue_after_check_cert = true; 1546 result.config.continue_after_check_cert = true;
1596 break; 1547 break;
1597#endif 1548#endif
1598 case 'J': /* use client certificate */ 1549 case 'J': /* use client certificate */
1599#ifdef LIBCURL_FEATURE_SSL 1550#ifdef LIBCURL_FEATURE_SSL
1600 test_file(optarg); 1551 test_file(optarg);
1601 client_cert = optarg; 1552 result.config.client_cert = optarg;
1602 goto enable_ssl; 1553 goto enable_ssl;
1603#endif 1554#endif
1604 case 'K': /* use client private key */ 1555 case 'K': /* use client private key */
1605#ifdef LIBCURL_FEATURE_SSL 1556#ifdef LIBCURL_FEATURE_SSL
1606 test_file(optarg); 1557 test_file(optarg);
1607 client_privkey = optarg; 1558 result.config.client_privkey = optarg;
1608 goto enable_ssl; 1559 goto enable_ssl;
1609#endif 1560#endif
1610#ifdef LIBCURL_FEATURE_SSL 1561#ifdef LIBCURL_FEATURE_SSL
1611 case CA_CERT_OPTION: /* use CA chain file */ 1562 case CA_CERT_OPTION: /* use CA chain file */
1612 test_file(optarg); 1563 test_file(optarg);
1613 ca_cert = optarg; 1564 result.config.ca_cert = optarg;
1614 goto enable_ssl; 1565 goto enable_ssl;
1615#endif 1566#endif
1616#ifdef LIBCURL_FEATURE_SSL 1567#ifdef LIBCURL_FEATURE_SSL
1617 case 'D': /* verify peer certificate & host */ 1568 case 'D': /* verify peer certificate & host */
1618 verify_peer_and_host = true; 1569 result.config.verify_peer_and_host = true;
1619 break; 1570 break;
1620#endif 1571#endif
1621 case 'S': /* use SSL */ 1572 case 'S': /* use SSL */
1622#ifdef LIBCURL_FEATURE_SSL 1573#ifdef LIBCURL_FEATURE_SSL
1574 {
1623 enable_ssl: 1575 enable_ssl:
1624 use_ssl = true; 1576 bool got_plus = false;
1577 result.config.use_ssl = true;
1625 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1578 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1626 * Only set if it's non-zero. This helps when we include multiple 1579 * Only set if it's non-zero. This helps when we include multiple
1627 * parameters, like -S and -C combinations */ 1580 * parameters, like -S and -C combinations */
1628 ssl_version = CURL_SSLVERSION_DEFAULT; 1581 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1629 if (c == 'S' && optarg != NULL) { 1582 if (option_index == 'S' && optarg != NULL) {
1630 char *plus_ptr = strchr(optarg, '+'); 1583 char *plus_ptr = strchr(optarg, '+');
1631 if (plus_ptr) { 1584 if (plus_ptr) {
1632 got_plus = 1; 1585 got_plus = true;
1633 *plus_ptr = '\0'; 1586 *plus_ptr = '\0';
1634 } 1587 }
1635 1588
1636 if (optarg[0] == '2') { 1589 if (optarg[0] == '2') {
1637 ssl_version = CURL_SSLVERSION_SSLv2; 1590 result.config.ssl_version = CURL_SSLVERSION_SSLv2;
1638 } else if (optarg[0] == '3') { 1591 } else if (optarg[0] == '3') {
1639 ssl_version = CURL_SSLVERSION_SSLv3; 1592 result.config.ssl_version = CURL_SSLVERSION_SSLv3;
1640 } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) 1593 } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0"))
1641# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1594# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1642 ssl_version = CURL_SSLVERSION_TLSv1_0; 1595 result.config.ssl_version = CURL_SSLVERSION_TLSv1_0;
1643# else 1596# else
1644 ssl_version = CURL_SSLVERSION_DEFAULT; 1597 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1645# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1598# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1646 else if (!strcmp(optarg, "1.1")) 1599 else if (!strcmp(optarg, "1.1"))
1647# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1648 ssl_version = CURL_SSLVERSION_TLSv1_1; 1601 result.config.ssl_version = CURL_SSLVERSION_TLSv1_1;
1649# else 1602# else
1650 ssl_version = CURL_SSLVERSION_DEFAULT; 1603 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1651# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1604# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1652 else if (!strcmp(optarg, "1.2")) 1605 else if (!strcmp(optarg, "1.2"))
1653# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1606# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1654 ssl_version = CURL_SSLVERSION_TLSv1_2; 1607 result.config.ssl_version = CURL_SSLVERSION_TLSv1_2;
1655# else 1608# else
1656 ssl_version = CURL_SSLVERSION_DEFAULT; 1609 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1657# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1610# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1658 else if (!strcmp(optarg, "1.3")) 1611 else if (!strcmp(optarg, "1.3"))
1659# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1612# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1660 ssl_version = CURL_SSLVERSION_TLSv1_3; 1613 result.config.ssl_version = CURL_SSLVERSION_TLSv1_3;
1661# else 1614# else
1662 ssl_version = CURL_SSLVERSION_DEFAULT; 1615 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1663# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ 1616# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1664 else { 1617 else {
1665 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)")); 1618 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
@@ -1667,40 +1620,40 @@ bool process_arguments(int argc, char **argv) {
1667 } 1620 }
1668# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) 1621# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1669 if (got_plus) { 1622 if (got_plus) {
1670 switch (ssl_version) { 1623 switch (result.config.ssl_version) {
1671 case CURL_SSLVERSION_TLSv1_3: 1624 case CURL_SSLVERSION_TLSv1_3:
1672 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1625 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1673 break; 1626 break;
1674 case CURL_SSLVERSION_TLSv1_2: 1627 case CURL_SSLVERSION_TLSv1_2:
1675 case CURL_SSLVERSION_TLSv1_1: 1628 case CURL_SSLVERSION_TLSv1_1:
1676 case CURL_SSLVERSION_TLSv1_0: 1629 case CURL_SSLVERSION_TLSv1_0:
1677 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; 1630 result.config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1678 break; 1631 break;
1679 } 1632 }
1680 } else { 1633 } else {
1681 switch (ssl_version) { 1634 switch (result.config.ssl_version) {
1682 case CURL_SSLVERSION_TLSv1_3: 1635 case CURL_SSLVERSION_TLSv1_3:
1683 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1636 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1684 break; 1637 break;
1685 case CURL_SSLVERSION_TLSv1_2: 1638 case CURL_SSLVERSION_TLSv1_2:
1686 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; 1639 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1687 break; 1640 break;
1688 case CURL_SSLVERSION_TLSv1_1: 1641 case CURL_SSLVERSION_TLSv1_1:
1689 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; 1642 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1690 break; 1643 break;
1691 case CURL_SSLVERSION_TLSv1_0: 1644 case CURL_SSLVERSION_TLSv1_0:
1692 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; 1645 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1693 break; 1646 break;
1694 } 1647 }
1695 } 1648 }
1696# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1649# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1697 if (verbose >= 2) { 1650 if (verbose >= 2) {
1698 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1651 printf(_("* Set SSL/TLS version to %d\n"), result.config.ssl_version);
1699 } 1652 }
1700 if (!specify_port) { 1653 if (!specify_port) {
1701 server_port = HTTPS_PORT; 1654 result.config.server_port = HTTPS_PORT;
1702 } 1655 }
1703 break; 1656 } break;
1704#else /* LIBCURL_FEATURE_SSL */ 1657#else /* LIBCURL_FEATURE_SSL */
1705 /* -C -J and -K fall through to here without SSL */ 1658 /* -C -J and -K fall through to here without SSL */
1706 usage4(_("Invalid option - SSL is not available")); 1659 usage4(_("Invalid option - SSL is not available"));
@@ -1713,50 +1666,53 @@ bool process_arguments(int argc, char **argv) {
1713 if (!is_intnonneg(optarg)) { 1666 if (!is_intnonneg(optarg)) {
1714 usage2(_("Invalid max_redirs count"), optarg); 1667 usage2(_("Invalid max_redirs count"), optarg);
1715 } else { 1668 } else {
1716 max_depth = atoi(optarg); 1669 result.config.max_depth = atoi(optarg);
1717 } 1670 }
1718 break; 1671 break;
1719 case 'f': /* onredirect */ 1672 case 'f': /* onredirect */
1720 if (!strcmp(optarg, "ok")) { 1673 if (!strcmp(optarg, "ok")) {
1721 onredirect = STATE_OK; 1674 result.config.onredirect = STATE_OK;
1722 } else if (!strcmp(optarg, "warning")) { 1675 } else if (!strcmp(optarg, "warning")) {
1723 onredirect = STATE_WARNING; 1676 result.config.onredirect = STATE_WARNING;
1724 } else if (!strcmp(optarg, "critical")) { 1677 } else if (!strcmp(optarg, "critical")) {
1725 onredirect = STATE_CRITICAL; 1678 result.config.onredirect = STATE_CRITICAL;
1726 } else if (!strcmp(optarg, "unknown")) { 1679 } else if (!strcmp(optarg, "unknown")) {
1727 onredirect = STATE_UNKNOWN; 1680 result.config.onredirect = STATE_UNKNOWN;
1728 } else if (!strcmp(optarg, "follow")) { 1681 } else if (!strcmp(optarg, "follow")) {
1729 onredirect = STATE_DEPENDENT; 1682 result.config.onredirect = STATE_DEPENDENT;
1730 } else if (!strcmp(optarg, "stickyport")) { 1683 } else if (!strcmp(optarg, "stickyport")) {
1731 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT; 1684 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_HTTP_CURL,
1685 result.config.followsticky = STICKY_HOST | STICKY_PORT;
1732 } else if (!strcmp(optarg, "sticky")) { 1686 } else if (!strcmp(optarg, "sticky")) {
1733 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1687 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_HTTP_CURL,
1688 result.config.followsticky = STICKY_HOST;
1734 } else if (!strcmp(optarg, "follow")) { 1689 } else if (!strcmp(optarg, "follow")) {
1735 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1690 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_HTTP_CURL,
1691 result.config.followsticky = STICKY_NONE;
1736 } else if (!strcmp(optarg, "curl")) { 1692 } else if (!strcmp(optarg, "curl")) {
1737 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1693 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_LIBCURL;
1738 } else { 1694 } else {
1739 usage2(_("Invalid onredirect option"), optarg); 1695 usage2(_("Invalid onredirect option"), optarg);
1740 } 1696 }
1741 if (verbose >= 2) { 1697 if (verbose >= 2) {
1742 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1698 printf(_("* Following redirects set to %s\n"), state_text(result.config.onredirect));
1743 } 1699 }
1744 break; 1700 break;
1745 case 'd': /* string or substring */ 1701 case 'd': /* string or substring */
1746 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1); 1702 strncpy(result.config.header_expect, optarg, MAX_INPUT_BUFFER - 1);
1747 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1703 result.config.header_expect[MAX_INPUT_BUFFER - 1] = 0;
1748 break; 1704 break;
1749 case 's': /* string or substring */ 1705 case 's': /* string or substring */
1750 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1); 1706 strncpy(result.config.string_expect, optarg, MAX_INPUT_BUFFER - 1);
1751 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1707 result.config.string_expect[MAX_INPUT_BUFFER - 1] = 0;
1752 break; 1708 break;
1753 case 'e': /* string or substring */ 1709 case 'e': /* string or substring */
1754 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1); 1710 strncpy(result.config.server_expect, optarg, MAX_INPUT_BUFFER - 1);
1755 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1711 result.config.server_expect[MAX_INPUT_BUFFER - 1] = 0;
1756 server_expect_yn = 1; 1712 result.config.server_expect_yn = true;
1757 break; 1713 break;
1758 case 'T': /* Content-type */ 1714 case 'T': /* Content-type */
1759 http_content_type = strdup(optarg); 1715 result.config.http_content_type = strdup(optarg);
1760 break; 1716 break;
1761 case 'l': /* linespan */ 1717 case 'l': /* linespan */
1762 cflags &= ~REG_NEWLINE; 1718 cflags &= ~REG_NEWLINE;
@@ -1765,23 +1721,25 @@ bool process_arguments(int argc, char **argv) {
1765 cflags |= REG_ICASE; 1721 cflags |= REG_ICASE;
1766 // fall through 1722 // fall through
1767 case 'r': /* regex */ 1723 case 'r': /* regex */
1768 strncpy(regexp, optarg, MAX_RE_SIZE - 1); 1724 strncpy(result.config.regexp, optarg, MAX_RE_SIZE - 1);
1769 regexp[MAX_RE_SIZE - 1] = 0; 1725 result.config.regexp[MAX_RE_SIZE - 1] = 0;
1770 errcode = regcomp(&preg, regexp, cflags); 1726 regex_t preg;
1727 int errcode = regcomp(&preg, result.config.regexp, cflags);
1771 if (errcode != 0) { 1728 if (errcode != 0) {
1772 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1729 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1773 printf(_("Could Not Compile Regular Expression: %s"), errbuf); 1730 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1774 return false; 1731 result.errorcode = ERROR;
1732 return result;
1775 } 1733 }
1776 break; 1734 break;
1777 case INVERT_REGEX: 1735 case INVERT_REGEX:
1778 invert_regex = true; 1736 result.config.invert_regex = true;
1779 break; 1737 break;
1780 case STATE_REGEX: 1738 case STATE_REGEX:
1781 if (!strcasecmp(optarg, "critical")) { 1739 if (!strcasecmp(optarg, "critical")) {
1782 state_regex = STATE_CRITICAL; 1740 result.config.state_regex = STATE_CRITICAL;
1783 } else if (!strcasecmp(optarg, "warning")) { 1741 } else if (!strcasecmp(optarg, "warning")) {
1784 state_regex = STATE_WARNING; 1742 result.config.state_regex = STATE_WARNING;
1785 } else { 1743 } else {
1786 usage2(_("Invalid state-regex option"), optarg); 1744 usage2(_("Invalid state-regex option"), optarg);
1787 } 1745 }
@@ -1806,7 +1764,7 @@ bool process_arguments(int argc, char **argv) {
1806 printf("Bad format: try \"-m min:max\"\n"); 1764 printf("Bad format: try \"-m min:max\"\n");
1807 exit(STATE_WARNING); 1765 exit(STATE_WARNING);
1808 } else { 1766 } else {
1809 min_page_len = atoi(tmp); 1767 result.config.min_page_len = atoi(tmp);
1810 } 1768 }
1811 1769
1812 tmp = strtok(NULL, ":"); 1770 tmp = strtok(NULL, ":");
@@ -1814,52 +1772,52 @@ bool process_arguments(int argc, char **argv) {
1814 printf("Bad format: try \"-m min:max\"\n"); 1772 printf("Bad format: try \"-m min:max\"\n");
1815 exit(STATE_WARNING); 1773 exit(STATE_WARNING);
1816 } else { 1774 } else {
1817 max_page_len = atoi(tmp); 1775 result.config.max_page_len = atoi(tmp);
1818 } 1776 }
1819 } else { 1777 } else {
1820 min_page_len = atoi(optarg); 1778 result.config.min_page_len = atoi(optarg);
1821 } 1779 }
1822 break; 1780 break;
1823 } 1781 }
1824 case 'N': /* no-body */ 1782 case 'N': /* no-body */
1825 no_body = true; 1783 result.config.no_body = true;
1826 break; 1784 break;
1827 case 'M': /* max-age */ 1785 case 'M': /* max-age */
1828 { 1786 {
1829 int L = strlen(optarg); 1787 size_t option_length = strlen(optarg);
1830 if (L && optarg[L - 1] == 'm') { 1788 if (option_length && optarg[option_length - 1] == 'm') {
1831 maximum_age = atoi(optarg) * 60; 1789 result.config.maximum_age = atoi(optarg) * 60;
1832 } else if (L && optarg[L - 1] == 'h') { 1790 } else if (option_length && optarg[option_length - 1] == 'h') {
1833 maximum_age = atoi(optarg) * 60 * 60; 1791 result.config.maximum_age = atoi(optarg) * 60 * 60;
1834 } else if (L && optarg[L - 1] == 'd') { 1792 } else if (option_length && optarg[option_length - 1] == 'd') {
1835 maximum_age = atoi(optarg) * 60 * 60 * 24; 1793 result.config.maximum_age = atoi(optarg) * 60 * 60 * 24;
1836 } else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1]))) { 1794 } else if (option_length && (optarg[option_length - 1] == 's' || isdigit(optarg[option_length - 1]))) {
1837 maximum_age = atoi(optarg); 1795 result.config.maximum_age = atoi(optarg);
1838 } else { 1796 } else {
1839 fprintf(stderr, "unparsable max-age: %s\n", optarg); 1797 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1840 exit(STATE_WARNING); 1798 exit(STATE_WARNING);
1841 } 1799 }
1842 if (verbose >= 2) { 1800 if (verbose >= 2) {
1843 printf("* Maximal age of document set to %d seconds\n", maximum_age); 1801 printf("* Maximal age of document set to %d seconds\n", result.config.maximum_age);
1844 } 1802 }
1845 } break; 1803 } break;
1846 case 'E': /* show extended perfdata */ 1804 case 'E': /* show extended perfdata */
1847 show_extended_perfdata = true; 1805 result.config.show_extended_perfdata = true;
1848 break; 1806 break;
1849 case 'B': /* print body content after status line */ 1807 case 'B': /* print body content after status line */
1850 show_body = true; 1808 result.config.show_body = true;
1851 break; 1809 break;
1852 case HTTP_VERSION_OPTION: 1810 case HTTP_VERSION_OPTION:
1853 curl_http_version = CURL_HTTP_VERSION_NONE; 1811 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1854 if (strcmp(optarg, "1.0") == 0) { 1812 if (strcmp(optarg, "1.0") == 0) {
1855 curl_http_version = CURL_HTTP_VERSION_1_0; 1813 result.config.curl_http_version = CURL_HTTP_VERSION_1_0;
1856 } else if (strcmp(optarg, "1.1") == 0) { 1814 } else if (strcmp(optarg, "1.1") == 0) {
1857 curl_http_version = CURL_HTTP_VERSION_1_1; 1815 result.config.curl_http_version = CURL_HTTP_VERSION_1_1;
1858 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) { 1816 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1859#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) 1817#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1860 curl_http_version = CURL_HTTP_VERSION_2_0; 1818 result.config.curl_http_version = CURL_HTTP_VERSION_2_0;
1861#else 1819#else
1862 curl_http_version = CURL_HTTP_VERSION_NONE; 1820 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1863#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1821#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1864 } else { 1822 } else {
1865 fprintf(stderr, "unknown http-version parameter: %s\n", optarg); 1823 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
@@ -1867,13 +1825,13 @@ bool process_arguments(int argc, char **argv) {
1867 } 1825 }
1868 break; 1826 break;
1869 case AUTOMATIC_DECOMPRESSION: 1827 case AUTOMATIC_DECOMPRESSION:
1870 automatic_decompression = true; 1828 result.config.automatic_decompression = true;
1871 break; 1829 break;
1872 case COOKIE_JAR: 1830 case COOKIE_JAR:
1873 cookie_jar_file = optarg; 1831 result.config.cookie_jar_file = optarg;
1874 break; 1832 break;
1875 case HAPROXY_PROTOCOL: 1833 case HAPROXY_PROTOCOL:
1876 haproxy_protocol = true; 1834 result.config.haproxy_protocol = true;
1877 break; 1835 break;
1878 case '?': 1836 case '?':
1879 /* print short usage statement if args not parsable */ 1837 /* print short usage statement if args not parsable */
@@ -1882,82 +1840,82 @@ bool process_arguments(int argc, char **argv) {
1882 } 1840 }
1883 } 1841 }
1884 1842
1885 c = optind; 1843 int c = optind;
1886 1844
1887 if (server_address == NULL && c < argc) { 1845 if (result.config.server_address == NULL && c < argc) {
1888 server_address = strdup(argv[c++]); 1846 result.config.server_address = strdup(argv[c++]);
1889 } 1847 }
1890 1848
1891 if (host_name == NULL && c < argc) { 1849 if (result.config.host_name == NULL && c < argc) {
1892 host_name = strdup(argv[c++]); 1850 result.config.host_name = strdup(argv[c++]);
1893 } 1851 }
1894 1852
1895 if (server_address == NULL) { 1853 if (result.config.server_address == NULL) {
1896 if (host_name == NULL) { 1854 if (result.config.host_name == NULL) {
1897 usage4(_("You must specify a server address or host name")); 1855 usage4(_("You must specify a server address or host name"));
1898 } else { 1856 } else {
1899 server_address = strdup(host_name); 1857 result.config.server_address = strdup(result.config.host_name);
1900 } 1858 }
1901 } 1859 }
1902 1860
1903 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 1861 set_thresholds(&result.config.thlds, warning_thresholds, critical_thresholds);
1904 1862
1905 if (critical_thresholds && thlds->critical->end > (double)socket_timeout) { 1863 if (critical_thresholds && result.config.thlds->critical->end > (double)result.config.socket_timeout) {
1906 socket_timeout = (int)thlds->critical->end + 1; 1864 result.config.socket_timeout = (int)result.config.thlds->critical->end + 1;
1907 } 1865 }
1908 if (verbose >= 2) { 1866 if (verbose >= 2) {
1909 printf("* Socket timeout set to %ld seconds\n", socket_timeout); 1867 printf("* Socket timeout set to %ld seconds\n", result.config.socket_timeout);
1910 } 1868 }
1911 1869
1912 if (http_method == NULL) { 1870 if (result.config.http_method == NULL) {
1913 http_method = strdup("GET"); 1871 result.config.http_method = strdup("GET");
1914 } 1872 }
1915 1873
1916 if (client_cert && !client_privkey) { 1874 if (result.config.client_cert && !result.config.client_privkey) {
1917 usage4(_("If you use a client certificate you must also specify a private key file")); 1875 usage4(_("If you use a client certificate you must also specify a private key file"));
1918 } 1876 }
1919 1877
1920 if (virtual_port == 0) { 1878 if (result.config.virtual_port == 0) {
1921 virtual_port = server_port; 1879 result.config.virtual_port = result.config.server_port;
1922 } else { 1880 } else {
1923 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT)) { 1881 if ((result.config.use_ssl && result.config.server_port == HTTPS_PORT) ||
1882 (!result.config.use_ssl && result.config.server_port == HTTP_PORT)) {
1924 if (!specify_port) { 1883 if (!specify_port) {
1925 server_port = virtual_port; 1884 result.config.server_port = result.config.virtual_port;
1926 } 1885 }
1927 } 1886 }
1928 } 1887 }
1929 1888
1930 return true; 1889 return result;
1931} 1890}
1932 1891
1933char *perfd_time(double elapsed_time) { 1892char *perfd_time(double elapsed_time, thresholds *thlds, long socket_timeout) {
1934 return fperfdata("time", elapsed_time, "s", thlds->warning ? true : false, thlds->warning ? thlds->warning->end : 0, 1893 return fperfdata("time", elapsed_time, "s", thlds->warning, thlds->warning ? thlds->warning->end : 0, thlds->critical,
1935 thlds->critical ? true : false, thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout); 1894 thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1936} 1895}
1937 1896
1938char *perfd_time_connect(double elapsed_time_connect) { 1897char *perfd_time_connect(double elapsed_time_connect, long socket_timeout) {
1939 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1898 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1940} 1899}
1941 1900
1942char *perfd_time_ssl(double elapsed_time_ssl) { 1901char *perfd_time_ssl(double elapsed_time_ssl, long socket_timeout) {
1943 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1902 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1944} 1903}
1945 1904
1946char *perfd_time_headers(double elapsed_time_headers) { 1905char *perfd_time_headers(double elapsed_time_headers, long socket_timeout) {
1947 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1906 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1948} 1907}
1949 1908
1950char *perfd_time_firstbyte(double elapsed_time_firstbyte) { 1909char *perfd_time_firstbyte(double elapsed_time_firstbyte, long socket_timeout) {
1951 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1910 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1952} 1911}
1953 1912
1954char *perfd_time_transfer(double elapsed_time_transfer) { 1913char *perfd_time_transfer(double elapsed_time_transfer, long socket_timeout) {
1955 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout); 1914 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1956} 1915}
1957 1916
1958char *perfd_size(int page_len) { 1917char *perfd_size(int page_len, int min_page_len) {
1959 return perfdata("size", page_len, "B", (min_page_len > 0 ? true : false), min_page_len, (min_page_len > 0 ? true : false), 0, true, 0, 1918 return perfdata("size", page_len, "B", (min_page_len > 0), min_page_len, (min_page_len > 0), 0, true, 0, false, 0);
1960 false, 0);
1961} 1919}
1962 1920
1963void print_help(void) { 1921void print_help(void) {
@@ -2259,11 +2217,6 @@ void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2259/* TODO: where to put this, it's actually part of sstrings2 (logically)? 2217/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2260 */ 2218 */
2261const char *strrstr2(const char *haystack, const char *needle) { 2219const char *strrstr2(const char *haystack, const char *needle) {
2262 int counter;
2263 size_t len;
2264 const char *prev_pos;
2265 const char *pos;
2266
2267 if (haystack == NULL || needle == NULL) { 2220 if (haystack == NULL || needle == NULL) {
2268 return NULL; 2221 return NULL;
2269 } 2222 }
@@ -2272,10 +2225,10 @@ const char *strrstr2(const char *haystack, const char *needle) {
2272 return NULL; 2225 return NULL;
2273 } 2226 }
2274 2227
2275 counter = 0; 2228 int counter = 0;
2276 prev_pos = NULL; 2229 const char *prev_pos = NULL;
2277 pos = haystack; 2230 const char *pos = haystack;
2278 len = strlen(needle); 2231 size_t len = strlen(needle);
2279 for (;;) { 2232 for (;;) {
2280 pos = strstr(pos, needle); 2233 pos = strstr(pos, needle);
2281 if (pos == NULL) { 2234 if (pos == NULL) {
@@ -2294,37 +2247,29 @@ const char *strrstr2(const char *haystack, const char *needle) {
2294} 2247}
2295 2248
2296int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) { 2249int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
2297 char *first_line_end;
2298 char *p;
2299 size_t first_line_len;
2300 char *pp;
2301 const char *start;
2302 char *first_line_buf;
2303
2304 /* find last start of a new header */ 2250 /* find last start of a new header */
2305 start = strrstr2(buf, "\r\nHTTP/"); 2251 const char *start = strrstr2(buf, "\r\nHTTP/");
2306 if (start != NULL) { 2252 if (start != NULL) {
2307 start += 2; 2253 start += 2;
2308 buf = start; 2254 buf = start;
2309 } 2255 }
2310 2256
2311 first_line_end = strstr(buf, "\r\n"); 2257 char *first_line_end = strstr(buf, "\r\n");
2312 if (first_line_end == NULL) { 2258 if (first_line_end == NULL) {
2313 return -1; 2259 return -1;
2314 } 2260 }
2315 2261
2316 first_line_len = (size_t)(first_line_end - buf); 2262 size_t first_line_len = (size_t)(first_line_end - buf);
2317 status_line->first_line = (char *)malloc(first_line_len + 1); 2263 status_line->first_line = (char *)malloc(first_line_len + 1);
2318 if (status_line->first_line == NULL) { 2264 if (status_line->first_line == NULL) {
2319 return -1; 2265 return -1;
2320 } 2266 }
2321 memcpy(status_line->first_line, buf, first_line_len); 2267 memcpy(status_line->first_line, buf, first_line_len);
2322 status_line->first_line[first_line_len] = '\0'; 2268 status_line->first_line[first_line_len] = '\0';
2323 first_line_buf = strdup(status_line->first_line); 2269 char *first_line_buf = strdup(status_line->first_line);
2324 2270
2325 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */ 2271 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2326 2272 char *p = strtok(first_line_buf, "/");
2327 p = strtok(first_line_buf, "/");
2328 if (p == NULL) { 2273 if (p == NULL) {
2329 free(first_line_buf); 2274 free(first_line_buf);
2330 return -1; 2275 return -1;
@@ -2339,6 +2284,8 @@ int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line)
2339 free(first_line_buf); 2284 free(first_line_buf);
2340 return -1; 2285 return -1;
2341 } 2286 }
2287
2288 char *pp;
2342 if (strchr(p, '.') != NULL) { 2289 if (strchr(p, '.') != NULL) {
2343 2290
2344 /* HTTP 1.x case */ 2291 /* HTTP 1.x case */
@@ -2418,15 +2365,11 @@ char *get_header_value(const struct phr_header *headers, const size_t nof_header
2418 return NULL; 2365 return NULL;
2419} 2366}
2420 2367
2421int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) { 2368int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE], int maximum_age) {
2422 char *server_date = NULL;
2423 char *document_date = NULL;
2424 int date_result = STATE_OK;
2425 curlhelp_statusline status_line;
2426 struct phr_header headers[255]; 2369 struct phr_header headers[255];
2427 size_t nof_headers = 255; 2370 size_t nof_headers = 255;
2371 curlhelp_statusline status_line;
2428 size_t msglen; 2372 size_t msglen;
2429
2430 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor, 2373 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2431 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0); 2374 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2432 2375
@@ -2434,9 +2377,10 @@ int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[D
2434 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2377 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2435 } 2378 }
2436 2379
2437 server_date = get_header_value(headers, nof_headers, "date"); 2380 char *server_date = get_header_value(headers, nof_headers, "date");
2438 document_date = get_header_value(headers, nof_headers, "last-modified"); 2381 char *document_date = get_header_value(headers, nof_headers, "last-modified");
2439 2382
2383 int date_result = STATE_OK;
2440 if (!server_date || !*server_date) { 2384 if (!server_date || !*server_date) {
2441 char tmp[DEFAULT_BUFFER_SIZE]; 2385 char tmp[DEFAULT_BUFFER_SIZE];
2442 2386
@@ -2511,13 +2455,10 @@ int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[D
2511} 2455}
2512 2456
2513int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf) { 2457int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf) {
2514 size_t content_length = 0;
2515 struct phr_header headers[255]; 2458 struct phr_header headers[255];
2516 size_t nof_headers = 255; 2459 size_t nof_headers = 255;
2517 size_t msglen; 2460 size_t msglen;
2518 char *content_length_s = NULL;
2519 curlhelp_statusline status_line; 2461 curlhelp_statusline status_line;
2520
2521 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor, 2462 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2522 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0); 2463 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2523 2464
@@ -2525,12 +2466,13 @@ int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_
2525 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2466 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2526 } 2467 }
2527 2468
2528 content_length_s = get_header_value(headers, nof_headers, "content-length"); 2469 char *content_length_s = get_header_value(headers, nof_headers, "content-length");
2529 if (!content_length_s) { 2470 if (!content_length_s) {
2530 return header_buf->buflen + body_buf->buflen; 2471 return header_buf->buflen + body_buf->buflen;
2531 } 2472 }
2473
2532 content_length_s += strspn(content_length_s, " \t"); 2474 content_length_s += strspn(content_length_s, " \t");
2533 content_length = atoi(content_length_s); 2475 size_t content_length = atoi(content_length_s);
2534 if (content_length != body_buf->buflen) { 2476 if (content_length != body_buf->buflen) {
2535 /* TODO: should we warn if the actual and the reported body length don't match? */ 2477 /* TODO: should we warn if the actual and the reported body length don't match? */
2536 } 2478 }
@@ -2544,22 +2486,19 @@ int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_
2544 2486
2545/* TODO: is there a better way in libcurl to check for the SSL library? */ 2487/* TODO: is there a better way in libcurl to check for the SSL library? */
2546curlhelp_ssl_library curlhelp_get_ssl_library(void) { 2488curlhelp_ssl_library curlhelp_get_ssl_library(void) {
2547 curl_version_info_data *version_data;
2548 char *ssl_version;
2549 char *library;
2550 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 2489 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2551 2490
2552 version_data = curl_version_info(CURLVERSION_NOW); 2491 curl_version_info_data *version_data = curl_version_info(CURLVERSION_NOW);
2553 if (version_data == NULL) { 2492 if (version_data == NULL) {
2554 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2493 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2555 } 2494 }
2556 2495
2557 ssl_version = strdup(version_data->ssl_version); 2496 char *ssl_version = strdup(version_data->ssl_version);
2558 if (ssl_version == NULL) { 2497 if (ssl_version == NULL) {
2559 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2498 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2560 } 2499 }
2561 2500
2562 library = strtok(ssl_version, "/"); 2501 char *library = strtok(ssl_version, "/");
2563 if (library == NULL) { 2502 if (library == NULL) {
2564 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2503 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2565 } 2504 }
@@ -2602,21 +2541,18 @@ const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2602#ifdef LIBCURL_FEATURE_SSL 2541#ifdef LIBCURL_FEATURE_SSL
2603# ifndef USE_OPENSSL 2542# ifndef USE_OPENSSL
2604time_t parse_cert_date(const char *s) { 2543time_t parse_cert_date(const char *s) {
2605 struct tm tm;
2606 time_t date;
2607 char *res;
2608
2609 if (!s) { 2544 if (!s) {
2610 return -1; 2545 return -1;
2611 } 2546 }
2612 2547
2613 /* Jan 17 14:25:12 2020 GMT */ 2548 /* Jan 17 14:25:12 2020 GMT */
2614 res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm); 2549 struct tm tm;
2550 char *res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2615 /* Sep 11 12:00:00 2020 GMT */ 2551 /* Sep 11 12:00:00 2020 GMT */
2616 if (res == NULL) { 2552 if (res == NULL) {
2617 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm); 2553 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2618 } 2554 }
2619 date = mktime(&tm); 2555 time_t date = mktime(&tm);
2620 2556
2621 return date; 2557 return date;
2622} 2558}
@@ -2625,7 +2561,6 @@ time_t parse_cert_date(const char *s) {
2625 * OpenSSL could be this function 2561 * OpenSSL could be this function
2626 */ 2562 */
2627int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) { 2563int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) {
2628 int i;
2629 struct curl_slist *slist; 2564 struct curl_slist *slist;
2630 int cname_found = 0; 2565 int cname_found = 0;
2631 char *start_date_str = NULL; 2566 char *start_date_str = NULL;
@@ -2643,7 +2578,7 @@ int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_
2643 printf("**** REQUEST CERTIFICATES ****\n"); 2578 printf("**** REQUEST CERTIFICATES ****\n");
2644 } 2579 }
2645 2580
2646 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 2581 for (int i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
2647 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) { 2582 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2648 /* find first common name in subject, 2583 /* find first common name in subject,
2649 * TODO: check alternative subjects for 2584 * TODO: check alternative subjects for
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h
new file mode 100644
index 00000000..9085fbbb
--- /dev/null
+++ b/plugins/check_curl.d/config.h
@@ -0,0 +1,141 @@
1#pragma once
2
3#include "../../config.h"
4#include "common.h"
5#include "states.h"
6#include "thresholds.h"
7#include <stddef.h>
8#include <string.h>
9#include "curl/curl.h"
10
11enum {
12 MAX_RE_SIZE = 1024,
13 HTTP_PORT = 80,
14 HTTPS_PORT = 443,
15 MAX_PORT = 65535,
16 DEFAULT_MAX_REDIRS = 15
17};
18
19enum {
20 FOLLOW_HTTP_CURL = 0,
21 FOLLOW_LIBCURL = 1
22};
23
24enum {
25 STICKY_NONE = 0,
26 STICKY_HOST = 1,
27 STICKY_PORT = 2
28};
29
30#define HTTP_EXPECT "HTTP/"
31#define DEFAULT_BUFFER_SIZE 2048
32#define DEFAULT_SERVER_URL "/"
33
34typedef struct {
35 char *server_address;
36 unsigned short server_port;
37 unsigned short virtual_port;
38 char *host_name;
39 char *server_url;
40
41 bool automatic_decompression;
42 bool haproxy_protocol;
43 char *client_cert;
44 char *client_privkey;
45 char *ca_cert;
46 bool use_ssl;
47 int ssl_version;
48 char *http_method;
49 char user_agent[DEFAULT_BUFFER_SIZE];
50 char **http_opt_headers;
51 int http_opt_headers_count;
52 char *http_post_data;
53 int max_depth;
54 char *http_content_type;
55 long socket_timeout;
56 char user_auth[MAX_INPUT_BUFFER];
57 char proxy_auth[MAX_INPUT_BUFFER];
58 int followmethod;
59 int followsticky;
60 bool no_body;
61 int curl_http_version;
62 char *cookie_jar_file;
63
64 int maximum_age;
65 char regexp[MAX_RE_SIZE];
66 int state_regex;
67 bool invert_regex;
68 bool verify_peer_and_host;
69 bool check_cert;
70 bool continue_after_check_cert;
71 int days_till_exp_warn;
72 int days_till_exp_crit;
73 thresholds *thlds;
74 int min_page_len;
75 int max_page_len;
76 char server_expect[MAX_INPUT_BUFFER];
77 bool server_expect_yn;
78 char string_expect[MAX_INPUT_BUFFER];
79 char header_expect[MAX_INPUT_BUFFER];
80 int onredirect;
81
82 bool show_extended_perfdata;
83 bool show_body;
84 bool display_html;
85} check_curl_config;
86
87check_curl_config check_curl_config_init() {
88 check_curl_config tmp = {
89 .server_address = NULL,
90 .server_port = HTTP_PORT,
91 .virtual_port = 0,
92 .host_name = NULL,
93 .server_url = strdup(DEFAULT_SERVER_URL),
94
95 .automatic_decompression = false,
96 .haproxy_protocol = false,
97 .client_cert = NULL,
98 .client_privkey = NULL,
99 .ca_cert = NULL,
100 .use_ssl = false,
101 .ssl_version = CURL_SSLVERSION_DEFAULT,
102 .http_method = NULL,
103 .user_agent = {},
104 .http_opt_headers = NULL,
105 .http_opt_headers_count = 0,
106 .http_post_data = NULL,
107 .max_depth = DEFAULT_MAX_REDIRS,
108 .http_content_type = NULL,
109 .socket_timeout = DEFAULT_SOCKET_TIMEOUT,
110 .user_auth = "",
111 .proxy_auth = "",
112 .followmethod = FOLLOW_HTTP_CURL,
113 .followsticky = STICKY_NONE,
114 .no_body = false,
115 .curl_http_version = CURL_HTTP_VERSION_NONE,
116 .cookie_jar_file = NULL,
117
118 .maximum_age = -1,
119 .regexp = {},
120 .state_regex = STATE_CRITICAL,
121 .invert_regex = false,
122 .verify_peer_and_host = false,
123 .check_cert = false,
124 .continue_after_check_cert = false,
125 .days_till_exp_warn = 0,
126 .days_till_exp_crit = 0,
127 .thlds = NULL,
128 .min_page_len = 0,
129 .max_page_len = 0,
130 .server_expect = HTTP_EXPECT,
131 .server_expect_yn = false,
132 .string_expect = "",
133 .header_expect = "",
134 .onredirect = STATE_OK,
135
136 .show_extended_perfdata = false,
137 .show_body = false,
138 .display_html = false,
139 };
140 return tmp;
141}