summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am3
-rw-r--r--plugins/check_curl.c1342
-rw-r--r--plugins/check_curl.d/config.h141
3 files changed, 838 insertions, 648 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index be650089..3ce24325 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -58,7 +58,8 @@ EXTRA_DIST = t \
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_cluster.d 61 check_cluster.d \
62 check_curl.d
62 63
63PLUGINHDRS = common.h 64PLUGINHDRS = common.h
64 65
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index 748201e8..4806bf14 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -32,11 +32,14 @@
32 * 32 *
33 * 33 *
34 *****************************************************************************/ 34 *****************************************************************************/
35const char *progname = "check_curl";
36 35
36const 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
@@ -63,29 +66,11 @@ const char *email = "devel@monitoring-plugins.org";
63 66
64#include <netdb.h> 67#include <netdb.h>
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,19 +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"));
205 }
280 206
281 if (display_html) 207 const check_curl_config config = tmp_config.config;
282 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http", host_name ? host_name : server_address,
283 virtual_port ? virtual_port : server_port, server_url);
284 208
285 result = check_http(); 209 /* set defaults */
286 return result; 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());
213 }
214
215 if (config.display_html) {
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));
287} 222}
288 223
289#ifdef HAVE_SSL 224#ifdef HAVE_SSL
@@ -358,17 +293,19 @@ static char *string_statuscode(int major, int minor) {
358/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 293/* Checks if the server 'reply' is one of the expected 'statuscodes' */
359static int expected_statuscode(const char *reply, const char *statuscodes) { 294static int expected_statuscode(const char *reply, const char *statuscodes) {
360 char *expected; 295 char *expected;
361 char *code;
362 int result = 0;
363 296
364 if ((expected = strdup(statuscodes)) == NULL) 297 if ((expected = strdup(statuscodes)) == NULL) {
365 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 298 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
299 }
366 300
367 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) 301 char *code;
302 int result = 0;
303 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
368 if (strstr(reply, code) != NULL) { 304 if (strstr(reply, code) != NULL) {
369 result = 1; 305 result = 1;
370 break; 306 break;
371 } 307 }
308 }
372 309
373 free(expected); 310 free(expected);
374 return result; 311 return result;
@@ -383,25 +320,25 @@ void handle_curl_option_return_code(CURLcode res, const char *option) {
383} 320}
384 321
385int lookup_host(const char *host, char *buf, size_t buflen) { 322int lookup_host(const char *host, char *buf, size_t buflen) {
386 struct addrinfo hints, *res, *result; 323 struct addrinfo hints;
387 char addrstr[100];
388 size_t addrstr_len;
389 int errcode;
390 void *ptr = {0};
391 size_t buflen_remaining = buflen - 1;
392
393 memset(&hints, 0, sizeof(hints)); 324 memset(&hints, 0, sizeof(hints));
394 hints.ai_family = address_family; 325 hints.ai_family = address_family;
395 hints.ai_socktype = SOCK_STREAM; 326 hints.ai_socktype = SOCK_STREAM;
396 hints.ai_flags |= AI_CANONNAME; 327 hints.ai_flags |= AI_CANONNAME;
397 328
398 errcode = getaddrinfo(host, NULL, &hints, &result); 329 struct addrinfo *result;
399 if (errcode != 0) 330 int errcode = getaddrinfo(host, NULL, &hints, &result);
331 if (errcode != 0) {
400 return errcode; 332 return errcode;
333 }
401 334
402 strcpy(buf, ""); 335 strcpy(buf, "");
403 res = result; 336 struct addrinfo *res = result;
404 337
338 size_t buflen_remaining = buflen - 1;
339 size_t addrstr_len;
340 char addrstr[100];
341 void *ptr = {0};
405 while (res) { 342 while (res) {
406 switch (res->ai_family) { 343 switch (res->ai_family) {
407 case AF_INET: 344 case AF_INET:
@@ -437,39 +374,37 @@ int lookup_host(const char *host, char *buf, size_t buflen) {
437} 374}
438 375
439static void cleanup(void) { 376static void cleanup(void) {
440 if (status_line_initialized) 377 if (status_line_initialized) {
441 curlhelp_free_statusline(&status_line); 378 curlhelp_free_statusline(&status_line);
379 }
442 status_line_initialized = false; 380 status_line_initialized = false;
443 if (curl_easy_initialized) 381 if (curl_easy_initialized) {
444 curl_easy_cleanup(curl); 382 curl_easy_cleanup(curl);
383 }
445 curl_easy_initialized = false; 384 curl_easy_initialized = false;
446 if (curl_global_initialized) 385 if (curl_global_initialized) {
447 curl_global_cleanup(); 386 curl_global_cleanup();
387 }
448 curl_global_initialized = false; 388 curl_global_initialized = false;
449 if (body_buf_initialized) 389 if (body_buf_initialized) {
450 curlhelp_freewritebuffer(&body_buf); 390 curlhelp_freewritebuffer(&body_buf);
391 }
451 body_buf_initialized = false; 392 body_buf_initialized = false;
452 if (header_buf_initialized) 393 if (header_buf_initialized) {
453 curlhelp_freewritebuffer(&header_buf); 394 curlhelp_freewritebuffer(&header_buf);
395 }
454 header_buf_initialized = false; 396 header_buf_initialized = false;
455 if (put_buf_initialized) 397 if (put_buf_initialized) {
456 curlhelp_freereadbuffer(&put_buf); 398 curlhelp_freereadbuffer(&put_buf);
399 }
457 put_buf_initialized = false; 400 put_buf_initialized = false;
458} 401}
459 402
460int check_http(void) { 403mp_state_enum check_http(check_curl_config config) {
461 int result = STATE_OK;
462 int result_ssl = STATE_OK;
463 int page_len = 0;
464 int i;
465 char *force_host_header = NULL;
466 struct curl_slist *host = NULL;
467 char addrstr[DEFAULT_BUFFER_SIZE / 2];
468 char dnscache[DEFAULT_BUFFER_SIZE];
469
470 /* initialize curl */ 404 /* initialize curl */
471 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) 405 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
472 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 406 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
407 }
473 curl_global_initialized = true; 408 curl_global_initialized = true;
474 409
475 if ((curl = curl_easy_init()) == NULL) { 410 if ((curl = curl_easy_init()) == NULL) {
@@ -480,13 +415,14 @@ int check_http(void) {
480 /* register cleanup function to shut down libcurl properly */ 415 /* register cleanup function to shut down libcurl properly */
481 atexit(cleanup); 416 atexit(cleanup);
482 417
483 if (verbose >= 1) 418 if (verbose >= 1) {
484 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE"); 419 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
420 }
485 421
486 /* print everything on stdout like check_http would do */ 422 /* print everything on stdout like check_http would do */
487 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");
488 424
489 if (automatic_decompression) 425 if (config.automatic_decompression)
490#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) 426#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
491 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");
492#else 428#else
@@ -494,16 +430,18 @@ int check_http(void) {
494#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ 430#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
495 431
496 /* initialize buffer for body of the answer */ 432 /* initialize buffer for body of the answer */
497 if (curlhelp_initwritebuffer(&body_buf) < 0) 433 if (curlhelp_initwritebuffer(&body_buf) < 0) {
498 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); 434 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
435 }
499 body_buf_initialized = true; 436 body_buf_initialized = true;
500 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), 437 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
501 "CURLOPT_WRITEFUNCTION"); 438 "CURLOPT_WRITEFUNCTION");
502 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA"); 439 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
503 440
504 /* initialize buffer for header of the answer */ 441 /* initialize buffer for header of the answer */
505 if (curlhelp_initwritebuffer(&header_buf) < 0) 442 if (curlhelp_initwritebuffer(&header_buf) < 0) {
506 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n"); 443 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
444 }
507 header_buf_initialized = true; 445 header_buf_initialized = true;
508 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), 446 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
509 "CURLOPT_HEADERFUNCTION"); 447 "CURLOPT_HEADERFUNCTION");
@@ -513,92 +451,104 @@ int check_http(void) {
513 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");
514 452
515 /* set timeouts */ 453 /* set timeouts */
516 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");
517 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");
518 456
519 /* enable haproxy protocol */ 457 /* enable haproxy protocol */
520 if (haproxy_protocol) { 458 if (config.haproxy_protocol) {
521 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");
522 } 460 }
523 461
524 // 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
525 // use the host_name later on to make SNI happy 463 // use the host_name later on to make SNI happy
526 if (use_ssl && host_name != NULL) { 464 struct curl_slist *host = NULL;
527 if ((res = lookup_host(server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) { 465 char dnscache[DEFAULT_BUFFER_SIZE];
528 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];
529 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));
530 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 472 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
531 } 473 }
532 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);
533 host = curl_slist_append(NULL, dnscache); 475 host = curl_slist_append(NULL, dnscache);
534 curl_easy_setopt(curl, CURLOPT_RESOLVE, host); 476 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
535 if (verbose >= 1) 477 if (verbose >= 1) {
536 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache); 478 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
479 }
537 } 480 }
538 481
539 // 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
540 struct in6_addr tmp_in_addr; 483 struct in6_addr tmp_in_addr;
541 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) { 484 if (inet_pton(AF_INET6, config.server_address, &tmp_in_addr) == 1) {
542 char *new_server_address = malloc(strlen(server_address) + 3); 485 char *new_server_address = malloc(strlen(config.server_address) + 3);
543 if (new_server_address == NULL) { 486 if (new_server_address == NULL) {
544 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); 487 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
545 } 488 }
546 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);
547 free(server_address); 490 free(config.server_address);
548 server_address = new_server_address; 491 config.server_address = new_server_address;
549 } 492 }
550 493
551 /* 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 */
552 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", use_ssl ? "https" : "http", 495 char url[DEFAULT_BUFFER_SIZE];
553 (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);
554 499
555 if (verbose >= 1) 500 if (verbose >= 1) {
556 printf("* curl CURLOPT_URL: %s\n", url); 501 printf("* curl CURLOPT_URL: %s\n", url);
502 }
557 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");
558 504
559 /* extract proxy information for legacy proxy https requests */ 505 /* extract proxy information for legacy proxy https requests */
560 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) {
561 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");
562 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");
563 if (verbose >= 2) 509 if (verbose >= 2) {
564 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);
565 http_method = "GET"; 511 }
566 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, server_url), "CURLOPT_URL"); 512 config.http_method = "GET";
513 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, config.server_url), "CURLOPT_URL");
567 } 514 }
568 515
569 /* disable body for HEAD request */ 516 /* disable body for HEAD request */
570 if (http_method && !strcmp(http_method, "HEAD")) { 517 if (config.http_method && !strcmp(config.http_method, "HEAD")) {
571 no_body = true; 518 config.no_body = true;
572 } 519 }
573 520
574 /* set HTTP protocol version */ 521 /* set HTTP protocol version */
575 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");
576 523
577 /* set HTTP method */ 524 /* set HTTP method */
578 if (http_method) { 525 if (config.http_method) {
579 if (!strcmp(http_method, "POST")) 526 if (!strcmp(config.http_method, "POST")) {
580 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");
581 else if (!strcmp(http_method, "PUT")) 528 } else if (!strcmp(config.http_method, "PUT")) {
582 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");
583 else 530 } else {
584 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");
532 }
585 } 533 }
586 534
535 char *force_host_header = NULL;
587 /* check if Host header is explicitly set in options */ 536 /* check if Host header is explicitly set in options */
588 if (http_opt_headers_count) { 537 if (config.http_opt_headers_count) {
589 for (i = 0; i < http_opt_headers_count; i++) { 538 for (int i = 0; i < config.http_opt_headers_count; i++) {
590 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 539 if (strncmp(config.http_opt_headers[i], "Host:", 5) == 0) {
591 force_host_header = http_opt_headers[i]; 540 force_host_header = config.http_opt_headers[i];
592 } 541 }
593 } 542 }
594 } 543 }
595 544
596 /* 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 */
597 if (host_name != NULL && force_host_header == NULL) { 546 char http_header[DEFAULT_BUFFER_SIZE];
598 if ((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) { 547 if (config.host_name != NULL && force_host_header == NULL) {
599 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);
600 } else { 550 } else {
601 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); 551 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", config.host_name);
602 } 552 }
603 header_list = curl_slist_append(header_list, http_header); 553 header_list = curl_slist_append(header_list, http_header);
604 } 554 }
@@ -609,9 +559,9 @@ int check_http(void) {
609 559
610 /* attach additional headers supplied by the user */ 560 /* attach additional headers supplied by the user */
611 /* optionally send any other header tag */ 561 /* optionally send any other header tag */
612 if (http_opt_headers_count) { 562 if (config.http_opt_headers_count) {
613 for (i = 0; i < http_opt_headers_count; i++) { 563 for (int i = 0; i < config.http_opt_headers_count; i++) {
614 header_list = curl_slist_append(header_list, http_opt_headers[i]); 564 header_list = curl_slist_append(header_list, config.http_opt_headers[i]);
615 } 565 }
616 /* 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 */
617 /* Covered in a testcase in tests/check_http.t */ 567 /* Covered in a testcase in tests/check_http.t */
@@ -624,19 +574,21 @@ int check_http(void) {
624#ifdef LIBCURL_FEATURE_SSL 574#ifdef LIBCURL_FEATURE_SSL
625 575
626 /* set SSL version, warn about insecure or unsupported versions */ 576 /* set SSL version, warn about insecure or unsupported versions */
627 if (use_ssl) { 577 if (config.use_ssl) {
628 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");
629 } 579 }
630 580
631 /* client certificate and key to present to server (SSL) */ 581 /* client certificate and key to present to server (SSL) */
632 if (client_cert) 582 if (config.client_cert) {
633 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");
634 if (client_privkey) 584 }
635 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY"); 585 if (config.client_privkey) {
636 if (ca_cert) { 586 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, config.client_privkey), "CURLOPT_SSLKEY");
637 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); 587 }
638 } 588 if (config.ca_cert) {
639 if (ca_cert || verify_peer_and_host) { 589 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, config.ca_cert), "CURLOPT_CAINFO");
590 }
591 if (config.ca_cert || config.verify_peer_and_host) {
640 /* 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
641 * hostname in the certificate, can be switched off later */ 593 * hostname in the certificate, can be switched off later */
642 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");
@@ -654,7 +606,7 @@ int check_http(void) {
654 ssl_library = curlhelp_get_ssl_library(); 606 ssl_library = curlhelp_get_ssl_library();
655 607
656 /* try hard to get a stack of certificates to verify against */ 608 /* try hard to get a stack of certificates to verify against */
657 if (check_cert) { 609 if (config.check_cert) {
658# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) 610# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
659 /* inform curl to report back certificates */ 611 /* inform curl to report back certificates */
660 switch (ssl_library) { 612 switch (ssl_library) {
@@ -700,32 +652,36 @@ int check_http(void) {
700 } 652 }
701# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 653# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
702 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */ 654 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
703 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) 655 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) {
704 add_sslctx_verify_fun = true; 656 add_sslctx_verify_fun = true;
705 else 657 } else {
706 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl " 658 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl "
707 "too old and has no CURLOPT_CERTINFO)\n"); 659 "too old and has no CURLOPT_CERTINFO)\n");
660 }
708# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 661# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
709 } 662 }
710 663
711# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */ 664# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
712 // ssl ctx function is not available with all ssl backends 665 // ssl ctx function is not available with all ssl backends
713 if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION) 666 if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION) {
714 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 667 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
668 }
715# endif 669# endif
716 670
717#endif /* LIBCURL_FEATURE_SSL */ 671#endif /* LIBCURL_FEATURE_SSL */
718 672
719 /* set default or user-given user agent identification */ 673 /* set default or user-given user agent identification */
720 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");
721 675
722 /* proxy-authentication */ 676 /* proxy-authentication */
723 if (strcmp(proxy_auth, "")) 677 if (strcmp(config.proxy_auth, "")) {
724 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");
679 }
725 680
726 /* authentication */ 681 /* authentication */
727 if (strcmp(user_auth, "")) 682 if (strcmp(config.user_auth, "")) {
728 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");
684 }
729 685
730 /* TODO: parameter auth method, bitfield of following methods: 686 /* TODO: parameter auth method, bitfield of following methods:
731 * CURLAUTH_BASIC (default) 687 * CURLAUTH_BASIC (default)
@@ -743,14 +699,14 @@ int check_http(void) {
743 */ 699 */
744 700
745 /* handle redirections */ 701 /* handle redirections */
746 if (onredirect == STATE_DEPENDENT) { 702 if (config.onredirect == STATE_DEPENDENT) {
747 if (followmethod == FOLLOW_LIBCURL) { 703 if (config.followmethod == FOLLOW_LIBCURL) {
748 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");
749 705
750 /* default -1 is infinite, not good, could lead to zombie plugins! 706 /* default -1 is infinite, not good, could lead to zombie plugins!
751 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
752 */ 708 */
753 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");
754 710
755 /* 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) */
756#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) 712#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
@@ -774,62 +730,69 @@ int check_http(void) {
774 } 730 }
775 731
776 /* no-body */ 732 /* no-body */
777 if (no_body) 733 if (config.no_body) {
778 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");
735 }
779 736
780 /* IPv4 or IPv6 forced DNS resolution */ 737 /* IPv4 or IPv6 forced DNS resolution */
781 if (address_family == AF_UNSPEC) 738 if (address_family == AF_UNSPEC) {
782 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), 739 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
783 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); 740 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
784 else if (address_family == AF_INET) 741 } else if (address_family == AF_INET) {
785 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), 742 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
786 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); 743 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
744 }
787#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) 745#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
788 else if (address_family == AF_INET6) 746 else if (address_family == AF_INET6) {
789 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), 747 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
790 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); 748 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
749 }
791#endif 750#endif
792 751
793 /* either send http POST data (any data, not only POST)*/ 752 /* either send http POST data (any data, not only POST)*/
794 if (!strcmp(http_method, "POST") || !strcmp(http_method, "PUT")) { 753 if (!strcmp(config.http_method, "POST") || !strcmp(config.http_method, "PUT")) {
795 /* set content of payload for POST and PUT */ 754 /* set content of payload for POST and PUT */
796 if (http_content_type) { 755 if (config.http_content_type) {
797 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);
798 header_list = curl_slist_append(header_list, http_header); 757 header_list = curl_slist_append(header_list, http_header);
799 } 758 }
800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string 759 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
801 * in case of no POST/PUT data */ 760 * in case of no POST/PUT data */
802 if (!http_post_data) 761 if (!config.http_post_data) {
803 http_post_data = ""; 762 config.http_post_data = "";
804 if (!strcmp(http_method, "POST")) { 763 }
764 if (!strcmp(config.http_method, "POST")) {
805 /* POST method, set payload with CURLOPT_POSTFIELDS */ 765 /* POST method, set payload with CURLOPT_POSTFIELDS */
806 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");
807 } else if (!strcmp(http_method, "PUT")) { 767 } else if (!strcmp(config.http_method, "PUT")) {
808 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),
809 "CURLOPT_READFUNCTION"); 769 "CURLOPT_READFUNCTION");
810 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) {
811 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");
772 }
812 put_buf_initialized = true; 773 put_buf_initialized = true;
813 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");
814 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)),
815 "CURLOPT_INFILESIZE"); 776 "CURLOPT_INFILESIZE");
816 } 777 }
817 } 778 }
818 779
819 /* cookie handling */ 780 /* cookie handling */
820 if (cookie_jar_file != NULL) { 781 if (config.cookie_jar_file != NULL) {
821 /* 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 */
822 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");
823 /* 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 */
824 if (*cookie_jar_file) 785 if (*config.cookie_jar_file) {
825 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");
787 }
826 } 788 }
827 789
828 /* do the request */ 790 /* do the request */
829 res = curl_easy_perform(curl); 791 CURLcode res = curl_easy_perform(curl);
830 792
831 if (verbose >= 2 && http_post_data) 793 if (verbose >= 2 && config.http_post_data) {
832 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data); 794 printf("**** REQUEST CONTENT ****\n%s\n", config.http_post_data);
795 }
833 796
834 /* 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 */
835 curl_slist_free_all(header_list); 798 curl_slist_free_all(header_list);
@@ -843,22 +806,23 @@ int check_http(void) {
843 806
844 /* Curl errors, result in critical Nagios state */ 807 /* Curl errors, result in critical Nagios state */
845 if (res != CURLE_OK) { 808 if (res != CURLE_OK) {
846 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"),
847 res, errbuf[0] ? errbuf : curl_easy_strerror(res)); 810 config.server_port, res, errbuf[0] ? errbuf : curl_easy_strerror(res));
848 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 811 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
849 } 812 }
850 813
814 int result_ssl = STATE_OK;
851 /* certificate checks */ 815 /* certificate checks */
852#ifdef LIBCURL_FEATURE_SSL 816#ifdef LIBCURL_FEATURE_SSL
853 if (use_ssl) { 817 if (config.use_ssl) {
854 if (check_cert) { 818 if (config.check_cert) {
855 if (is_openssl_callback) { 819 if (is_openssl_callback) {
856# ifdef USE_OPENSSL 820# ifdef USE_OPENSSL
857 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 821 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
858 * and we actually have OpenSSL in the monitoring tools 822 * and we actually have OpenSSL in the monitoring tools
859 */ 823 */
860 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);
861 if (!continue_after_check_cert) { 825 if (!config.continue_after_check_cert) {
862 return result_ssl; 826 return result_ssl;
863 } 827 }
864# else /* USE_OPENSSL */ 828# else /* USE_OPENSSL */
@@ -866,7 +830,6 @@ int check_http(void) {
866 "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");
867# endif /* USE_OPENSSL */ 831# endif /* USE_OPENSSL */
868 } else { 832 } else {
869 int i;
870 struct curl_slist *slist; 833 struct curl_slist *slist;
871 834
872 cert_ptr.to_info = NULL; 835 cert_ptr.to_info = NULL;
@@ -877,10 +840,11 @@ int check_http(void) {
877 * 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
878 */ 841 */
879 const char *raw_cert = NULL; 842 const char *raw_cert = NULL;
880 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++) {
881 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) {
882 if (verbose >= 2) 845 if (verbose >= 2) {
883 printf("%d ** %s\n", i, slist->data); 846 printf("%d ** %s\n", i, slist->data);
847 }
884 if (strncmp(slist->data, "Cert:", 5) == 0) { 848 if (strncmp(slist->data, "Cert:", 5) == 0) {
885 raw_cert = &slist->data[5]; 849 raw_cert = &slist->data[5];
886 goto GOT_FIRST_CERT; 850 goto GOT_FIRST_CERT;
@@ -901,8 +865,8 @@ int check_http(void) {
901 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 865 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
902 } 866 }
903 BIO_free(cert_BIO); 867 BIO_free(cert_BIO);
904 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);
905 if (!continue_after_check_cert) { 869 if (!config.continue_after_check_cert) {
906 return result_ssl; 870 return result_ssl;
907 } 871 }
908# else /* USE_OPENSSL */ 872# else /* USE_OPENSSL */
@@ -927,25 +891,36 @@ int check_http(void) {
927 /* 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
928 * performance data to the answer always 892 * performance data to the answer always
929 */ 893 */
894 double total_time;
930 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");
931 page_len = get_content_length(&header_buf, &body_buf); 896 int page_len = get_content_length(&header_buf, &body_buf);
932 if (show_extended_perfdata) { 897 char perfstring[DEFAULT_BUFFER_SIZE];
898 if (config.show_extended_perfdata) {
899 double time_connect;
933 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;
934 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;
935 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;
936 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),
937 "CURLINFO_STARTTRANSFER_TIME"); 907 "CURLINFO_STARTTRANSFER_TIME");
938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time), perfd_size(page_len), 908
939 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),
940 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),
941 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));
942 } else { 915 } else {
943 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));
944 } 918 }
945 919
946 /* return a CRITICAL status if we couldn't read any data */ 920 /* return a CRITICAL status if we couldn't read any data */
947 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) 921 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) {
948 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); 922 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
923 }
949 924
950 /* get status line of answer, check sanity of HTTP code */ 925 /* get status line of answer, check sanity of HTTP code */
951 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) { 926 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) {
@@ -957,28 +932,32 @@ int check_http(void) {
957 932
958 /* get result code from cURL */ 933 /* get result code from cURL */
959 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE"); 934 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
960 if (verbose >= 2) 935 if (verbose >= 2) {
961 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code); 936 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
937 }
962 938
963 /* print status line, header, body if verbose */ 939 /* print status line, header, body if verbose */
964 if (verbose >= 2) { 940 if (verbose >= 2) {
965 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));
966 } 942 }
967 943
968 /* 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 */
969 if (!expected_statuscode(status_line.first_line, server_expect)) { 945 if (!expected_statuscode(status_line.first_line, config.server_expect)) {
970 if (server_port == HTTP_PORT) 946 if (config.server_port == HTTP_PORT) {
971 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);
972 else 948 } else {
973 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,
974 status_line.first_line); 950 status_line.first_line);
975 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : ""); 951 }
952 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "", config.show_body ? body_buf.buf : "");
976 } 953 }
977 954
978 if (server_expect_yn) { 955 int result = STATE_OK;
979 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect); 956 if (config.server_expect_yn) {
980 if (verbose) 957 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), config.server_expect);
958 if (verbose) {
981 printf("%s\n", msg); 959 printf("%s\n", msg);
960 }
982 result = STATE_OK; 961 result = STATE_OK;
983 } else { 962 } else {
984 /* illegal return codes result in a critical state */ 963 /* illegal return codes result in a critical state */
@@ -992,22 +971,22 @@ int check_http(void) {
992 result = STATE_WARNING; 971 result = STATE_WARNING;
993 /* check redirected page if specified */ 972 /* check redirected page if specified */
994 } else if (code >= 300) { 973 } else if (code >= 300) {
995 if (onredirect == STATE_DEPENDENT) { 974 if (config.onredirect == STATE_DEPENDENT) {
996 if (followmethod == FOLLOW_LIBCURL) { 975 if (config.followmethod == FOLLOW_LIBCURL) {
997 code = status_line.http_code; 976 code = status_line.http_code;
998 } else { 977 } else {
999 /* old check_http style redirection, if we come 978 /* old check_http style redirection, if we come
1000 * back here, we are in the same status as with 979 * back here, we are in the same status as with
1001 * the libcurl method 980 * the libcurl method
1002 */ 981 */
1003 redir(&header_buf); 982 redir(&header_buf, config);
1004 } 983 }
1005 } else { 984 } else {
1006 /* this is a specific code in the command line to 985 /* this is a specific code in the command line to
1007 * be returned when a redirection is encountered 986 * be returned when a redirection is encountered
1008 */ 987 */
1009 } 988 }
1010 result = max_state_alt(onredirect, result); 989 result = max_state_alt(config.onredirect, result);
1011 /* all other codes are considered ok */ 990 /* all other codes are considered ok */
1012 } else { 991 } else {
1013 result = STATE_OK; 992 result = STATE_OK;
@@ -1015,12 +994,13 @@ int check_http(void) {
1015 } 994 }
1016 995
1017 /* libcurl redirection internally, handle error states here */ 996 /* libcurl redirection internally, handle error states here */
1018 if (followmethod == FOLLOW_LIBCURL) { 997 if (config.followmethod == FOLLOW_LIBCURL) {
1019 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");
1020 if (verbose >= 2) 999 if (verbose >= 2) {
1021 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); 1000 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1022 if (redir_depth > max_depth) { 1001 }
1023 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", max_depth); 1002 if (redir_depth > config.max_depth) {
1003 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", config.max_depth);
1024 die(STATE_WARNING, "HTTP WARNING - %s", msg); 1004 die(STATE_WARNING, "HTTP WARNING - %s", msg);
1025 } 1005 }
1026 } 1006 }
@@ -1031,16 +1011,17 @@ int check_http(void) {
1031 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);
1032 } 1012 }
1033 1013
1034 if (maximum_age >= 0) { 1014 if (config.maximum_age >= 0) {
1035 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);
1036 } 1016 }
1037 1017
1038 /* Page and Header content checks go here */ 1018 /* Page and Header content checks go here */
1039 1019
1040 if (strlen(header_expect)) { 1020 if (strlen(config.header_expect)) {
1041 if (!strstr(header_buf.buf, header_expect)) { 1021 if (!strstr(header_buf.buf, config.header_expect)) {
1042 1022
1043 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));
1044 1025
1045 if (output_header_search[sizeof(output_header_search) - 1] != '\0') { 1026 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1046 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4); 1027 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
@@ -1049,7 +1030,8 @@ int check_http(void) {
1049 char tmp[DEFAULT_BUFFER_SIZE]; 1030 char tmp[DEFAULT_BUFFER_SIZE];
1050 1031
1051 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,
1052 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);
1053 1035
1054 strcpy(msg, tmp); 1036 strcpy(msg, tmp);
1055 1037
@@ -1057,10 +1039,11 @@ int check_http(void) {
1057 } 1039 }
1058 } 1040 }
1059 1041
1060 if (strlen(string_expect)) { 1042 if (strlen(config.string_expect)) {
1061 if (!strstr(body_buf.buf, string_expect)) { 1043 if (!strstr(body_buf.buf, config.string_expect)) {
1062 1044
1063 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));
1064 1047
1065 if (output_string_search[sizeof(output_string_search) - 1] != '\0') { 1048 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1066 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4); 1049 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
@@ -1069,7 +1052,8 @@ int check_http(void) {
1069 char tmp[DEFAULT_BUFFER_SIZE]; 1052 char tmp[DEFAULT_BUFFER_SIZE];
1070 1053
1071 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,
1072 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);
1073 1057
1074 strcpy(msg, tmp); 1058 strcpy(msg, tmp);
1075 1059
@@ -1077,13 +1061,15 @@ int check_http(void) {
1077 } 1061 }
1078 } 1062 }
1079 1063
1080 if (strlen(regexp)) { 1064 if (strlen(config.regexp)) {
1081 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0); 1065 regex_t preg;
1082 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)) {
1083 /* OK - No-op to avoid changing the logic around it */ 1069 /* OK - No-op to avoid changing the logic around it */
1084 result = max_state_alt(STATE_OK, result); 1070 result = max_state_alt(STATE_OK, result);
1085 } 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)) {
1086 if (!invert_regex) { 1072 if (!config.invert_regex) {
1087 char tmp[DEFAULT_BUFFER_SIZE]; 1073 char tmp[DEFAULT_BUFFER_SIZE];
1088 1074
1089 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1075 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
@@ -1095,7 +1081,7 @@ int check_http(void) {
1095 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1081 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1096 strcpy(msg, tmp); 1082 strcpy(msg, tmp);
1097 } 1083 }
1098 result = state_regex; 1084 result = config.state_regex;
1099 } else { 1085 } else {
1100 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1086 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1101 1087
@@ -1108,7 +1094,7 @@ int check_http(void) {
1108 } 1094 }
1109 1095
1110 /* make sure the page is of an appropriate size */ 1096 /* make sure the page is of an appropriate size */
1111 if ((max_page_len > 0) && (page_len > max_page_len)) { 1097 if ((config.max_page_len > 0) && (page_len > config.max_page_len)) {
1112 char tmp[DEFAULT_BUFFER_SIZE]; 1098 char tmp[DEFAULT_BUFFER_SIZE];
1113 1099
1114 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);
@@ -1117,7 +1103,7 @@ int check_http(void) {
1117 1103
1118 result = max_state_alt(STATE_WARNING, result); 1104 result = max_state_alt(STATE_WARNING, result);
1119 1105
1120 } 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)) {
1121 char tmp[DEFAULT_BUFFER_SIZE]; 1107 char tmp[DEFAULT_BUFFER_SIZE];
1122 1108
1123 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);
@@ -1126,54 +1112,51 @@ int check_http(void) {
1126 } 1112 }
1127 1113
1128 /* -w, -c: check warning and critical level */ 1114 /* -w, -c: check warning and critical level */
1129 result = max_state_alt(get_status(total_time, thlds), result); 1115 result = max_state_alt(get_status(total_time, config.thlds), result);
1130 1116
1131 /* Cut-off trailing characters */ 1117 /* Cut-off trailing characters */
1132 if (strlen(msg) >= 2) { 1118 if (strlen(msg) >= 2) {
1133 if (msg[strlen(msg) - 2] == ',') 1119 if (msg[strlen(msg) - 2] == ',') {
1134 msg[strlen(msg) - 2] = '\0'; 1120 msg[strlen(msg) - 2] = '\0';
1135 else 1121 } else {
1136 msg[strlen(msg) - 3] = '\0'; 1122 msg[strlen(msg) - 3] = '\0';
1123 }
1137 } 1124 }
1138 1125
1139 /* 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); */
1140 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),
1141 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,
1142 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,
1143 (show_body ? "\n" : "")); 1130 (config.show_body ? body_buf.buf : ""), (config.show_body ? "\n" : ""));
1144 1131
1145 return max_state_alt(result, result_ssl); 1132 return max_state_alt(result, result_ssl);
1146} 1133}
1147 1134
1148int uri_strcmp(const UriTextRangeA range, const char *s) { 1135int uri_strcmp(const UriTextRangeA range, const char *s) {
1149 if (!range.first) 1136 if (!range.first) {
1150 return -1; 1137 return -1;
1151 if ((size_t)(range.afterLast - range.first) < strlen(s)) 1138 }
1139 if ((size_t)(range.afterLast - range.first) < strlen(s)) {
1152 return -1; 1140 return -1;
1141 }
1153 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s))); 1142 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s)));
1154} 1143}
1155 1144
1156char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { 1145char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1157 if (!range.first) 1146 if (!range.first) {
1158 return "(null)"; 1147 return "(null)";
1148 }
1159 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first))); 1149 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first)));
1160 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0'; 1150 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0';
1161 buf[range.afterLast - range.first] = '\0'; 1151 buf[range.afterLast - range.first] = '\0';
1162 return buf; 1152 return buf;
1163} 1153}
1164 1154
1165void redir(curlhelp_write_curlbuf *header_buf) { 1155void redir(curlhelp_write_curlbuf *header_buf, check_curl_config config) {
1166 char *location = NULL;
1167 curlhelp_statusline status_line; 1156 curlhelp_statusline status_line;
1168 struct phr_header headers[255]; 1157 struct phr_header headers[255];
1169 size_t nof_headers = 255;
1170 size_t msglen; 1158 size_t msglen;
1171 char buf[DEFAULT_BUFFER_SIZE]; 1159 size_t nof_headers = 255;
1172 char ipstr[INET_ADDR_MAX_SIZE];
1173 int new_port;
1174 char *new_host;
1175 char *new_url;
1176
1177 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,
1178 &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);
1179 1162
@@ -1181,26 +1164,31 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1181 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 1164 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1182 } 1165 }
1183 1166
1184 location = get_header_value(headers, nof_headers, "location"); 1167 char *location = get_header_value(headers, nof_headers, "location");
1185 1168
1186 if (verbose >= 2) 1169 if (verbose >= 2) {
1187 printf(_("* Seen redirect location %s\n"), location); 1170 printf(_("* Seen redirect location %s\n"), location);
1171 }
1188 1172
1189 if (++redir_depth > max_depth) 1173 if (++redir_depth > config.max_depth) {
1190 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,
1191 (display_html ? "</A>" : "")); 1175 (config.display_html ? "</A>" : ""));
1176 }
1192 1177
1193 UriParserStateA state; 1178 UriParserStateA state;
1194 UriUriA uri; 1179 UriUriA uri;
1195 state.uri = &uri; 1180 state.uri = &uri;
1196 if (uriParseUriA(&state, location) != URI_SUCCESS) { 1181 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1197 if (state.errorCode == URI_ERROR_SYNTAX) { 1182 if (state.errorCode == URI_ERROR_SYNTAX) {
1198 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>" : ""));
1199 } else if (state.errorCode == URI_ERROR_MALLOC) { 1185 } else if (state.errorCode == URI_ERROR_MALLOC) {
1200 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1186 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1201 } 1187 }
1202 } 1188 }
1203 1189
1190 char ipstr[INET_ADDR_MAX_SIZE];
1191 char buf[DEFAULT_BUFFER_SIZE];
1204 if (verbose >= 2) { 1192 if (verbose >= 2) {
1205 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));
1206 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));
@@ -1230,40 +1218,43 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1230 } 1218 }
1231 1219
1232 if (uri.scheme.first) { 1220 if (uri.scheme.first) {
1233 if (!uri_strcmp(uri.scheme, "https")) 1221 config.use_ssl = (bool)(!uri_strcmp(uri.scheme, "https"));
1234 use_ssl = true;
1235 else
1236 use_ssl = false;
1237 } 1222 }
1238 1223
1239 /* 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
1240 * 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
1241 */ 1226 */
1227 int new_port;
1242 if (uri.portText.first) { 1228 if (uri.portText.first) {
1243 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1229 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1244 } else { 1230 } else {
1245 new_port = HTTP_PORT; 1231 new_port = HTTP_PORT;
1246 if (use_ssl) 1232 if (config.use_ssl) {
1247 new_port = HTTPS_PORT; 1233 new_port = HTTPS_PORT;
1234 }
1235 }
1236 if (new_port > MAX_PORT) {
1237 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location,
1238 config.display_html ? "</A>" : "");
1248 } 1239 }
1249 if (new_port > MAX_PORT)
1250 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location, display_html ? "</A>" : "");
1251 1240
1252 /* 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
1253 * 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
1254 */ 1243 */
1244 char *new_host;
1255 if (!uri.scheme.first && !uri.hostText.first) { 1245 if (!uri.scheme.first && !uri.hostText.first) {
1256 new_host = strdup(host_name ? host_name : server_address); 1246 new_host = strdup(config.host_name ? config.host_name : config.server_address);
1257 new_port = server_port; 1247 new_port = config.server_port;
1258 if (use_ssl) 1248 if (config.use_ssl) {
1259 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE); 1249 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1250 }
1260 } else { 1251 } else {
1261 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1252 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1262 } 1253 }
1263 1254
1264 /* compose new path */ 1255 /* compose new path */
1265 /* TODO: handle fragments and query part of URL */ 1256 /* TODO: handle fragments and query part of URL */
1266 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); 1257 char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1267 if (uri.pathHead) { 1258 if (uri.pathHead) {
1268 const UriPathSegmentA *p = uri.pathHead; 1259 const UriPathSegmentA *p = uri.pathHead;
1269 for (; p; p = p->next) { 1260 for (; p; p = p->next) {
@@ -1272,57 +1263,56 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1272 } 1263 }
1273 } 1264 }
1274 1265
1275 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) &&
1276 (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)) {
1277 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",
1278 new_host, new_port, new_url, (display_html ? "</A>" : "")); 1269 new_host, new_port, new_url, (config.display_html ? "</A>" : ""));
1270 }
1279 1271
1280 /* set new values for redirected request */ 1272 /* set new values for redirected request */
1281 1273
1282 if (!(followsticky & STICKY_HOST)) { 1274 if (!(config.followsticky & STICKY_HOST)) {
1283 free(server_address); 1275 free(config.server_address);
1284 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); 1276 config.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1285 } 1277 }
1286 if (!(followsticky & STICKY_PORT)) { 1278 if (!(config.followsticky & STICKY_PORT)) {
1287 server_port = (unsigned short)new_port; 1279 config.server_port = (unsigned short)new_port;
1288 } 1280 }
1289 1281
1290 free(host_name); 1282 free(config.host_name);
1291 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); 1283 config.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1292 1284
1293 /* reset virtual port */ 1285 /* reset virtual port */
1294 virtual_port = server_port; 1286 config.virtual_port = config.server_port;
1295 1287
1296 free(new_host); 1288 free(new_host);
1297 free(server_url); 1289 free(config.server_url);
1298 server_url = new_url; 1290 config.server_url = new_url;
1299 1291
1300 uriFreeUriMembersA(&uri); 1292 uriFreeUriMembersA(&uri);
1301 1293
1302 if (verbose) 1294 if (verbose) {
1303 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",
1304 server_url); 1296 config.host_name ? config.host_name : config.server_address, config.server_port, config.server_url);
1297 }
1305 1298
1306 /* 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
1307 * attached to the URL in Location 1300 * attached to the URL in Location
1308 */ 1301 */
1309 1302
1310 cleanup(); 1303 cleanup();
1311 check_http(); 1304 check_http(config);
1312} 1305}
1313 1306
1314/* check whether a file exists */ 1307/* check whether a file exists */
1315void test_file(char *path) { 1308void test_file(char *path) {
1316 if (access(path, R_OK) == 0) 1309 if (access(path, R_OK) == 0) {
1317 return; 1310 return;
1311 }
1318 usage2(_("file does not exist or is not readable"), path); 1312 usage2(_("file does not exist or is not readable"), path);
1319} 1313}
1320 1314
1321bool process_arguments(int argc, char **argv) { 1315check_curl_config_wrapper process_arguments(int argc, char **argv) {
1322 char *p;
1323 int c = 1;
1324 char *temp;
1325
1326 enum { 1316 enum {
1327 INVERT_REGEX = CHAR_MAX + 1, 1317 INVERT_REGEX = CHAR_MAX + 1,
1328 SNI_OPTION, 1318 SNI_OPTION,
@@ -1336,8 +1326,6 @@ bool process_arguments(int argc, char **argv) {
1336 STATE_REGEX 1326 STATE_REGEX
1337 }; 1327 };
1338 1328
1339 int option = 0;
1340 int got_plus = 0;
1341 static struct option longopts[] = {STD_LONG_OPTS, 1329 static struct option longopts[] = {STD_LONG_OPTS,
1342 {"link", no_argument, 0, 'L'}, 1330 {"link", no_argument, 0, 'L'},
1343 {"nohtml", no_argument, 0, 'n'}, 1331 {"nohtml", no_argument, 0, 'n'},
@@ -1383,31 +1371,48 @@ bool process_arguments(int argc, char **argv) {
1383 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 1371 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1384 {0, 0, 0, 0}}; 1372 {0, 0, 0, 0}};
1385 1373
1386 if (argc < 2) 1374 check_curl_config_wrapper result = {
1387 return false; 1375 .errorcode = OK,
1376 .config = check_curl_config_init(),
1377 };
1378
1379 if (argc < 2) {
1380 result.errorcode = ERROR;
1381 return result;
1382 }
1388 1383
1389 /* support check_http compatible arguments */ 1384 /* support check_http compatible arguments */
1390 for (c = 1; c < argc; c++) { 1385 for (int index = 1; index < argc; index++) {
1391 if (strcmp("-to", argv[c]) == 0) 1386 if (strcmp("-to", argv[index]) == 0) {
1392 strcpy(argv[c], "-t"); 1387 strcpy(argv[index], "-t");
1393 if (strcmp("-hn", argv[c]) == 0) 1388 }
1394 strcpy(argv[c], "-H"); 1389 if (strcmp("-hn", argv[index]) == 0) {
1395 if (strcmp("-wt", argv[c]) == 0) 1390 strcpy(argv[index], "-H");
1396 strcpy(argv[c], "-w"); 1391 }
1397 if (strcmp("-ct", argv[c]) == 0) 1392 if (strcmp("-wt", argv[index]) == 0) {
1398 strcpy(argv[c], "-c"); 1393 strcpy(argv[index], "-w");
1399 if (strcmp("-nohtml", argv[c]) == 0) 1394 }
1400 strcpy(argv[c], "-n"); 1395 if (strcmp("-ct", argv[index]) == 0) {
1401 } 1396 strcpy(argv[index], "-c");
1402 1397 }
1403 server_url = strdup(DEFAULT_SERVER_URL); 1398 if (strcmp("-nohtml", argv[index]) == 0) {
1404 1399 strcpy(argv[index], "-n");
1405 while (1) { 1400 }
1406 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); 1401 }
1407 if (c == -1 || c == EOF || c == 1) 1402
1403 int option = 0;
1404 char *warning_thresholds = NULL;
1405 char *critical_thresholds = NULL;
1406 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
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) {
1408 break; 1412 break;
1413 }
1409 1414
1410 switch (c) { 1415 switch (option_index) {
1411 case 'h': 1416 case 'h':
1412 print_help(); 1417 print_help();
1413 exit(STATE_UNKNOWN); 1418 exit(STATE_UNKNOWN);
@@ -1421,10 +1426,11 @@ bool process_arguments(int argc, char **argv) {
1421 verbose++; 1426 verbose++;
1422 break; 1427 break;
1423 case 't': /* timeout period */ 1428 case 't': /* timeout period */
1424 if (!is_intnonneg(optarg)) 1429 if (!is_intnonneg(optarg)) {
1425 usage2(_("Timeout interval must be a positive integer"), optarg); 1430 usage2(_("Timeout interval must be a positive integer"), optarg);
1426 else 1431 } else {
1427 socket_timeout = (int)strtol(optarg, NULL, 10); 1432 result.config.socket_timeout = (int)strtol(optarg, NULL, 10);
1433 }
1428 break; 1434 break;
1429 case 'c': /* critical time threshold */ 1435 case 'c': /* critical time threshold */
1430 critical_thresholds = optarg; 1436 critical_thresholds = optarg;
@@ -1433,204 +1439,221 @@ bool process_arguments(int argc, char **argv) {
1433 warning_thresholds = optarg; 1439 warning_thresholds = optarg;
1434 break; 1440 break;
1435 case 'H': /* virtual host */ 1441 case 'H': /* virtual host */
1436 host_name = strdup(optarg); 1442 result.config.host_name = strdup(optarg);
1437 if (host_name[0] == '[') { 1443 char *p;
1438 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */ 1444 int host_name_length;
1439 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);
1440 /* cut off the port */ 1448 /* cut off the port */
1441 host_name_length = strlen(host_name) - strlen(p) - 1; 1449 host_name_length = strlen(result.config.host_name) - strlen(p) - 1;
1442 free(host_name); 1450 free(result.config.host_name);
1443 host_name = strndup(optarg, host_name_length); 1451 result.config.host_name = strndup(optarg, host_name_length);
1444 } 1452 }
1445 } 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 */
1446 virtual_port = atoi(p); 1454 result.config.virtual_port = atoi(p);
1447 /* cut off the port */ 1455 /* cut off the port */
1448 host_name_length = strlen(host_name) - strlen(p) - 1; 1456 host_name_length = strlen(result.config.host_name) - strlen(p) - 1;
1449 free(host_name); 1457 free(result.config.host_name);
1450 host_name = strndup(optarg, host_name_length); 1458 result.config.host_name = strndup(optarg, host_name_length);
1451 } 1459 }
1452 break; 1460 break;
1453 case 'I': /* internet address */ 1461 case 'I': /* internet address */
1454 server_address = strdup(optarg); 1462 result.config.server_address = strdup(optarg);
1455 break; 1463 break;
1456 case 'u': /* URL path */ 1464 case 'u': /* URL path */
1457 server_url = strdup(optarg); 1465 result.config.server_url = strdup(optarg);
1458 break; 1466 break;
1459 case 'p': /* Server port */ 1467 case 'p': /* Server port */
1460 if (!is_intnonneg(optarg)) 1468 if (!is_intnonneg(optarg)) {
1461 usage2(_("Invalid port number, expecting a non-negative number"), optarg); 1469 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
1462 else { 1470 } else {
1463 if (strtol(optarg, NULL, 10) > MAX_PORT) 1471 if (strtol(optarg, NULL, 10) > MAX_PORT) {
1464 usage2(_("Invalid port number, supplied port number is too big"), optarg); 1472 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1465 server_port = (unsigned short)strtol(optarg, NULL, 10); 1473 }
1474 result.config.server_port = (unsigned short)strtol(optarg, NULL, 10);
1466 specify_port = true; 1475 specify_port = true;
1467 } 1476 }
1468 break; 1477 break;
1469 case 'a': /* authorization info */ 1478 case 'a': /* authorization info */
1470 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1); 1479 strncpy(result.config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
1471 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1480 result.config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
1472 break; 1481 break;
1473 case 'b': /* proxy-authorization info */ 1482 case 'b': /* proxy-authorization info */
1474 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1483 strncpy(result.config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1475 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1484 result.config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1476 break; 1485 break;
1477 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 */
1478 if (!http_post_data) 1487 if (!result.config.http_post_data) {
1479 http_post_data = strdup(optarg); 1488 result.config.http_post_data = strdup(optarg);
1480 if (!http_method) 1489 }
1481 http_method = strdup("POST"); 1490 if (!result.config.http_method) {
1491 result.config.http_method = strdup("POST");
1492 }
1482 break; 1493 break;
1483 case 'j': /* Set HTTP method */ 1494 case 'j': /* Set HTTP method */
1484 if (http_method) 1495 if (result.config.http_method) {
1485 free(http_method); 1496 free(result.config.http_method);
1486 http_method = strdup(optarg); 1497 }
1498 result.config.http_method = strdup(optarg);
1487 break; 1499 break;
1488 case 'A': /* useragent */ 1500 case 'A': /* useragent */
1489 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE); 1501 strncpy(result.config.user_agent, optarg, DEFAULT_BUFFER_SIZE);
1490 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0'; 1502 result.config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1491 break; 1503 break;
1492 case 'k': /* Additional headers */ 1504 case 'k': /* Additional headers */
1493 if (http_opt_headers_count == 0) 1505 if (result.config.http_opt_headers_count == 0) {
1494 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));
1495 else 1507 } else {
1496 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count)); 1508 result.config.http_opt_headers =
1497 http_opt_headers[http_opt_headers_count - 1] = optarg; 1509 realloc(result.config.http_opt_headers, sizeof(char *) * (++result.config.http_opt_headers_count));
1510 }
1511 result.config.http_opt_headers[result.config.http_opt_headers_count - 1] = optarg;
1498 break; 1512 break;
1499 case 'L': /* show html link */ 1513 case 'L': /* show html link */
1500 display_html = true; 1514 result.config.display_html = true;
1501 break; 1515 break;
1502 case 'n': /* do not show html link */ 1516 case 'n': /* do not show html link */
1503 display_html = false; 1517 result.config.display_html = false;
1504 break; 1518 break;
1505 case 'C': /* Check SSL cert validity */ 1519 case 'C': /* Check SSL cert validity */
1506#ifdef LIBCURL_FEATURE_SSL 1520#ifdef LIBCURL_FEATURE_SSL
1521 char *temp;
1507 if ((temp = strchr(optarg, ',')) != NULL) { 1522 if ((temp = strchr(optarg, ',')) != NULL) {
1508 *temp = '\0'; 1523 *temp = '\0';
1509 if (!is_intnonneg(optarg)) 1524 if (!is_intnonneg(optarg)) {
1510 usage2(_("Invalid certificate expiration period"), optarg); 1525 usage2(_("Invalid certificate expiration period"), optarg);
1511 days_till_exp_warn = atoi(optarg); 1526 }
1527 result.config.days_till_exp_warn = atoi(optarg);
1512 *temp = ','; 1528 *temp = ',';
1513 temp++; 1529 temp++;
1514 if (!is_intnonneg(temp)) 1530 if (!is_intnonneg(temp)) {
1515 usage2(_("Invalid certificate expiration period"), temp); 1531 usage2(_("Invalid certificate expiration period"), temp);
1516 days_till_exp_crit = atoi(temp); 1532 }
1533 result.config.days_till_exp_crit = atoi(temp);
1517 } else { 1534 } else {
1518 days_till_exp_crit = 0; 1535 result.config.days_till_exp_crit = 0;
1519 if (!is_intnonneg(optarg)) 1536 if (!is_intnonneg(optarg)) {
1520 usage2(_("Invalid certificate expiration period"), optarg); 1537 usage2(_("Invalid certificate expiration period"), optarg);
1521 days_till_exp_warn = atoi(optarg); 1538 }
1539 result.config.days_till_exp_warn = atoi(optarg);
1522 } 1540 }
1523 check_cert = true; 1541 result.config.check_cert = true;
1524 goto enable_ssl; 1542 goto enable_ssl;
1525#endif 1543#endif
1526 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 */
1527#ifdef HAVE_SSL 1545#ifdef HAVE_SSL
1528 continue_after_check_cert = true; 1546 result.config.continue_after_check_cert = true;
1529 break; 1547 break;
1530#endif 1548#endif
1531 case 'J': /* use client certificate */ 1549 case 'J': /* use client certificate */
1532#ifdef LIBCURL_FEATURE_SSL 1550#ifdef LIBCURL_FEATURE_SSL
1533 test_file(optarg); 1551 test_file(optarg);
1534 client_cert = optarg; 1552 result.config.client_cert = optarg;
1535 goto enable_ssl; 1553 goto enable_ssl;
1536#endif 1554#endif
1537 case 'K': /* use client private key */ 1555 case 'K': /* use client private key */
1538#ifdef LIBCURL_FEATURE_SSL 1556#ifdef LIBCURL_FEATURE_SSL
1539 test_file(optarg); 1557 test_file(optarg);
1540 client_privkey = optarg; 1558 result.config.client_privkey = optarg;
1541 goto enable_ssl; 1559 goto enable_ssl;
1542#endif 1560#endif
1543#ifdef LIBCURL_FEATURE_SSL 1561#ifdef LIBCURL_FEATURE_SSL
1544 case CA_CERT_OPTION: /* use CA chain file */ 1562 case CA_CERT_OPTION: /* use CA chain file */
1545 test_file(optarg); 1563 test_file(optarg);
1546 ca_cert = optarg; 1564 result.config.ca_cert = optarg;
1547 goto enable_ssl; 1565 goto enable_ssl;
1548#endif 1566#endif
1549#ifdef LIBCURL_FEATURE_SSL 1567#ifdef LIBCURL_FEATURE_SSL
1550 case 'D': /* verify peer certificate & host */ 1568 case 'D': /* verify peer certificate & host */
1551 verify_peer_and_host = true; 1569 result.config.verify_peer_and_host = true;
1552 break; 1570 break;
1553#endif 1571#endif
1554 case 'S': /* use SSL */ 1572 case 'S': /* use SSL */
1555#ifdef LIBCURL_FEATURE_SSL 1573#ifdef LIBCURL_FEATURE_SSL
1574 {
1556 enable_ssl: 1575 enable_ssl:
1557 use_ssl = true; 1576 bool got_plus = false;
1577 result.config.use_ssl = true;
1558 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1578 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1559 * 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
1560 * parameters, like -S and -C combinations */ 1580 * parameters, like -S and -C combinations */
1561 ssl_version = CURL_SSLVERSION_DEFAULT; 1581 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1562 if (c == 'S' && optarg != NULL) { 1582 if (option_index == 'S' && optarg != NULL) {
1563 char *plus_ptr = strchr(optarg, '+'); 1583 char *plus_ptr = strchr(optarg, '+');
1564 if (plus_ptr) { 1584 if (plus_ptr) {
1565 got_plus = 1; 1585 got_plus = true;
1566 *plus_ptr = '\0'; 1586 *plus_ptr = '\0';
1567 } 1587 }
1568 1588
1569 if (optarg[0] == '2') 1589 if (optarg[0] == '2') {
1570 ssl_version = CURL_SSLVERSION_SSLv2; 1590 result.config.ssl_version = CURL_SSLVERSION_SSLv2;
1571 else if (optarg[0] == '3') 1591 } else if (optarg[0] == '3') {
1572 ssl_version = CURL_SSLVERSION_SSLv3; 1592 result.config.ssl_version = CURL_SSLVERSION_SSLv3;
1573 else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) 1593 } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0"))
1574# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1594# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1575 ssl_version = CURL_SSLVERSION_TLSv1_0; 1595 result.config.ssl_version = CURL_SSLVERSION_TLSv1_0;
1576# else 1596# else
1577 ssl_version = CURL_SSLVERSION_DEFAULT; 1597 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1578# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1598# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1579 else if (!strcmp(optarg, "1.1")) 1599 else if (!strcmp(optarg, "1.1"))
1580# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1581 ssl_version = CURL_SSLVERSION_TLSv1_1; 1601 result.config.ssl_version = CURL_SSLVERSION_TLSv1_1;
1582# else 1602# else
1583 ssl_version = CURL_SSLVERSION_DEFAULT; 1603 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1584# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1604# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1585 else if (!strcmp(optarg, "1.2")) 1605 else if (!strcmp(optarg, "1.2"))
1586# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1606# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1587 ssl_version = CURL_SSLVERSION_TLSv1_2; 1607 result.config.ssl_version = CURL_SSLVERSION_TLSv1_2;
1588# else 1608# else
1589 ssl_version = CURL_SSLVERSION_DEFAULT; 1609 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1590# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1610# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1591 else if (!strcmp(optarg, "1.3")) 1611 else if (!strcmp(optarg, "1.3"))
1592# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1612# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1593 ssl_version = CURL_SSLVERSION_TLSv1_3; 1613 result.config.ssl_version = CURL_SSLVERSION_TLSv1_3;
1594# else 1614# else
1595 ssl_version = CURL_SSLVERSION_DEFAULT; 1615 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1596# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ 1616# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1597 else 1617 else {
1598 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)"));
1619 }
1599 } 1620 }
1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) 1621# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1601 if (got_plus) { 1622 if (got_plus) {
1602 switch (ssl_version) { 1623 switch (result.config.ssl_version) {
1603 case CURL_SSLVERSION_TLSv1_3: 1624 case CURL_SSLVERSION_TLSv1_3:
1604 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1625 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1605 break; 1626 break;
1606 case CURL_SSLVERSION_TLSv1_2: 1627 case CURL_SSLVERSION_TLSv1_2:
1607 case CURL_SSLVERSION_TLSv1_1: 1628 case CURL_SSLVERSION_TLSv1_1:
1608 case CURL_SSLVERSION_TLSv1_0: 1629 case CURL_SSLVERSION_TLSv1_0:
1609 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; 1630 result.config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1610 break; 1631 break;
1611 } 1632 }
1612 } else { 1633 } else {
1613 switch (ssl_version) { 1634 switch (result.config.ssl_version) {
1614 case CURL_SSLVERSION_TLSv1_3: 1635 case CURL_SSLVERSION_TLSv1_3:
1615 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1636 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1616 break; 1637 break;
1617 case CURL_SSLVERSION_TLSv1_2: 1638 case CURL_SSLVERSION_TLSv1_2:
1618 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; 1639 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1619 break; 1640 break;
1620 case CURL_SSLVERSION_TLSv1_1: 1641 case CURL_SSLVERSION_TLSv1_1:
1621 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; 1642 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1622 break; 1643 break;
1623 case CURL_SSLVERSION_TLSv1_0: 1644 case CURL_SSLVERSION_TLSv1_0:
1624 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; 1645 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1625 break; 1646 break;
1626 } 1647 }
1627 } 1648 }
1628# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1649# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1629 if (verbose >= 2) 1650 if (verbose >= 2) {
1630 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1651 printf(_("* Set SSL/TLS version to %d\n"), result.config.ssl_version);
1631 if (!specify_port) 1652 }
1632 server_port = HTTPS_PORT; 1653 if (!specify_port) {
1633 break; 1654 result.config.server_port = HTTPS_PORT;
1655 }
1656 } break;
1634#else /* LIBCURL_FEATURE_SSL */ 1657#else /* LIBCURL_FEATURE_SSL */
1635 /* -C -J and -K fall through to here without SSL */ 1658 /* -C -J and -K fall through to here without SSL */
1636 usage4(_("Invalid option - SSL is not available")); 1659 usage4(_("Invalid option - SSL is not available"));
@@ -1640,51 +1663,56 @@ bool process_arguments(int argc, char **argv) {
1640 break; 1663 break;
1641#endif /* LIBCURL_FEATURE_SSL */ 1664#endif /* LIBCURL_FEATURE_SSL */
1642 case MAX_REDIRS_OPTION: 1665 case MAX_REDIRS_OPTION:
1643 if (!is_intnonneg(optarg)) 1666 if (!is_intnonneg(optarg)) {
1644 usage2(_("Invalid max_redirs count"), optarg); 1667 usage2(_("Invalid max_redirs count"), optarg);
1645 else { 1668 } else {
1646 max_depth = atoi(optarg); 1669 result.config.max_depth = atoi(optarg);
1647 } 1670 }
1648 break; 1671 break;
1649 case 'f': /* onredirect */ 1672 case 'f': /* onredirect */
1650 if (!strcmp(optarg, "ok")) 1673 if (!strcmp(optarg, "ok")) {
1651 onredirect = STATE_OK; 1674 result.config.onredirect = STATE_OK;
1652 else if (!strcmp(optarg, "warning")) 1675 } else if (!strcmp(optarg, "warning")) {
1653 onredirect = STATE_WARNING; 1676 result.config.onredirect = STATE_WARNING;
1654 else if (!strcmp(optarg, "critical")) 1677 } else if (!strcmp(optarg, "critical")) {
1655 onredirect = STATE_CRITICAL; 1678 result.config.onredirect = STATE_CRITICAL;
1656 else if (!strcmp(optarg, "unknown")) 1679 } else if (!strcmp(optarg, "unknown")) {
1657 onredirect = STATE_UNKNOWN; 1680 result.config.onredirect = STATE_UNKNOWN;
1658 else if (!strcmp(optarg, "follow")) 1681 } else if (!strcmp(optarg, "follow")) {
1659 onredirect = STATE_DEPENDENT; 1682 result.config.onredirect = STATE_DEPENDENT;
1660 else if (!strcmp(optarg, "stickyport")) 1683 } else if (!strcmp(optarg, "stickyport")) {
1661 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT; 1684 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_HTTP_CURL,
1662 else if (!strcmp(optarg, "sticky")) 1685 result.config.followsticky = STICKY_HOST | STICKY_PORT;
1663 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1686 } else if (!strcmp(optarg, "sticky")) {
1664 else if (!strcmp(optarg, "follow")) 1687 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_HTTP_CURL,
1665 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1688 result.config.followsticky = STICKY_HOST;
1666 else if (!strcmp(optarg, "curl")) 1689 } else if (!strcmp(optarg, "follow")) {
1667 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1690 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_HTTP_CURL,
1668 else 1691 result.config.followsticky = STICKY_NONE;
1692 } else if (!strcmp(optarg, "curl")) {
1693 result.config.onredirect = STATE_DEPENDENT, result.config.followmethod = FOLLOW_LIBCURL;
1694 } else {
1669 usage2(_("Invalid onredirect option"), optarg); 1695 usage2(_("Invalid onredirect option"), optarg);
1670 if (verbose >= 2) 1696 }
1671 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1697 if (verbose >= 2) {
1698 printf(_("* Following redirects set to %s\n"), state_text(result.config.onredirect));
1699 }
1672 break; 1700 break;
1673 case 'd': /* string or substring */ 1701 case 'd': /* string or substring */
1674 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1); 1702 strncpy(result.config.header_expect, optarg, MAX_INPUT_BUFFER - 1);
1675 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1703 result.config.header_expect[MAX_INPUT_BUFFER - 1] = 0;
1676 break; 1704 break;
1677 case 's': /* string or substring */ 1705 case 's': /* string or substring */
1678 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1); 1706 strncpy(result.config.string_expect, optarg, MAX_INPUT_BUFFER - 1);
1679 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1707 result.config.string_expect[MAX_INPUT_BUFFER - 1] = 0;
1680 break; 1708 break;
1681 case 'e': /* string or substring */ 1709 case 'e': /* string or substring */
1682 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1); 1710 strncpy(result.config.server_expect, optarg, MAX_INPUT_BUFFER - 1);
1683 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1711 result.config.server_expect[MAX_INPUT_BUFFER - 1] = 0;
1684 server_expect_yn = 1; 1712 result.config.server_expect_yn = true;
1685 break; 1713 break;
1686 case 'T': /* Content-type */ 1714 case 'T': /* Content-type */
1687 http_content_type = strdup(optarg); 1715 result.config.http_content_type = strdup(optarg);
1688 break; 1716 break;
1689 case 'l': /* linespan */ 1717 case 'l': /* linespan */
1690 cflags &= ~REG_NEWLINE; 1718 cflags &= ~REG_NEWLINE;
@@ -1693,25 +1721,28 @@ bool process_arguments(int argc, char **argv) {
1693 cflags |= REG_ICASE; 1721 cflags |= REG_ICASE;
1694 // fall through 1722 // fall through
1695 case 'r': /* regex */ 1723 case 'r': /* regex */
1696 strncpy(regexp, optarg, MAX_RE_SIZE - 1); 1724 strncpy(result.config.regexp, optarg, MAX_RE_SIZE - 1);
1697 regexp[MAX_RE_SIZE - 1] = 0; 1725 result.config.regexp[MAX_RE_SIZE - 1] = 0;
1698 errcode = regcomp(&preg, regexp, cflags); 1726 regex_t preg;
1727 int errcode = regcomp(&preg, result.config.regexp, cflags);
1699 if (errcode != 0) { 1728 if (errcode != 0) {
1700 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1729 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1701 printf(_("Could Not Compile Regular Expression: %s"), errbuf); 1730 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1702 return false; 1731 result.errorcode = ERROR;
1732 return result;
1703 } 1733 }
1704 break; 1734 break;
1705 case INVERT_REGEX: 1735 case INVERT_REGEX:
1706 invert_regex = true; 1736 result.config.invert_regex = true;
1707 break; 1737 break;
1708 case STATE_REGEX: 1738 case STATE_REGEX:
1709 if (!strcasecmp(optarg, "critical")) 1739 if (!strcasecmp(optarg, "critical")) {
1710 state_regex = STATE_CRITICAL; 1740 result.config.state_regex = STATE_CRITICAL;
1711 else if (!strcasecmp(optarg, "warning")) 1741 } else if (!strcasecmp(optarg, "warning")) {
1712 state_regex = STATE_WARNING; 1742 result.config.state_regex = STATE_WARNING;
1713 else 1743 } else {
1714 usage2(_("Invalid state-regex option"), optarg); 1744 usage2(_("Invalid state-regex option"), optarg);
1745 }
1715 break; 1746 break;
1716 case '4': 1747 case '4':
1717 address_family = AF_INET; 1748 address_family = AF_INET;
@@ -1732,57 +1763,61 @@ bool process_arguments(int argc, char **argv) {
1732 if (tmp == NULL) { 1763 if (tmp == NULL) {
1733 printf("Bad format: try \"-m min:max\"\n"); 1764 printf("Bad format: try \"-m min:max\"\n");
1734 exit(STATE_WARNING); 1765 exit(STATE_WARNING);
1735 } else 1766 } else {
1736 min_page_len = atoi(tmp); 1767 result.config.min_page_len = atoi(tmp);
1768 }
1737 1769
1738 tmp = strtok(NULL, ":"); 1770 tmp = strtok(NULL, ":");
1739 if (tmp == NULL) { 1771 if (tmp == NULL) {
1740 printf("Bad format: try \"-m min:max\"\n"); 1772 printf("Bad format: try \"-m min:max\"\n");
1741 exit(STATE_WARNING); 1773 exit(STATE_WARNING);
1742 } else 1774 } else {
1743 max_page_len = atoi(tmp); 1775 result.config.max_page_len = atoi(tmp);
1744 } else 1776 }
1745 min_page_len = atoi(optarg); 1777 } else {
1778 result.config.min_page_len = atoi(optarg);
1779 }
1746 break; 1780 break;
1747 } 1781 }
1748 case 'N': /* no-body */ 1782 case 'N': /* no-body */
1749 no_body = true; 1783 result.config.no_body = true;
1750 break; 1784 break;
1751 case 'M': /* max-age */ 1785 case 'M': /* max-age */
1752 { 1786 {
1753 int L = strlen(optarg); 1787 size_t option_length = strlen(optarg);
1754 if (L && optarg[L - 1] == 'm') 1788 if (option_length && optarg[option_length - 1] == 'm') {
1755 maximum_age = atoi(optarg) * 60; 1789 result.config.maximum_age = atoi(optarg) * 60;
1756 else if (L && optarg[L - 1] == 'h') 1790 } else if (option_length && optarg[option_length - 1] == 'h') {
1757 maximum_age = atoi(optarg) * 60 * 60; 1791 result.config.maximum_age = atoi(optarg) * 60 * 60;
1758 else if (L && optarg[L - 1] == 'd') 1792 } else if (option_length && optarg[option_length - 1] == 'd') {
1759 maximum_age = atoi(optarg) * 60 * 60 * 24; 1793 result.config.maximum_age = atoi(optarg) * 60 * 60 * 24;
1760 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]))) {
1761 maximum_age = atoi(optarg); 1795 result.config.maximum_age = atoi(optarg);
1762 else { 1796 } else {
1763 fprintf(stderr, "unparsable max-age: %s\n", optarg); 1797 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1764 exit(STATE_WARNING); 1798 exit(STATE_WARNING);
1765 } 1799 }
1766 if (verbose >= 2) 1800 if (verbose >= 2) {
1767 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);
1802 }
1768 } break; 1803 } break;
1769 case 'E': /* show extended perfdata */ 1804 case 'E': /* show extended perfdata */
1770 show_extended_perfdata = true; 1805 result.config.show_extended_perfdata = true;
1771 break; 1806 break;
1772 case 'B': /* print body content after status line */ 1807 case 'B': /* print body content after status line */
1773 show_body = true; 1808 result.config.show_body = true;
1774 break; 1809 break;
1775 case HTTP_VERSION_OPTION: 1810 case HTTP_VERSION_OPTION:
1776 curl_http_version = CURL_HTTP_VERSION_NONE; 1811 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1777 if (strcmp(optarg, "1.0") == 0) { 1812 if (strcmp(optarg, "1.0") == 0) {
1778 curl_http_version = CURL_HTTP_VERSION_1_0; 1813 result.config.curl_http_version = CURL_HTTP_VERSION_1_0;
1779 } else if (strcmp(optarg, "1.1") == 0) { 1814 } else if (strcmp(optarg, "1.1") == 0) {
1780 curl_http_version = CURL_HTTP_VERSION_1_1; 1815 result.config.curl_http_version = CURL_HTTP_VERSION_1_1;
1781 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) { 1816 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1782#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) 1817#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1783 curl_http_version = CURL_HTTP_VERSION_2_0; 1818 result.config.curl_http_version = CURL_HTTP_VERSION_2_0;
1784#else 1819#else
1785 curl_http_version = CURL_HTTP_VERSION_NONE; 1820 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1786#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1821#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1787 } else { 1822 } else {
1788 fprintf(stderr, "unknown http-version parameter: %s\n", optarg); 1823 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
@@ -1790,13 +1825,13 @@ bool process_arguments(int argc, char **argv) {
1790 } 1825 }
1791 break; 1826 break;
1792 case AUTOMATIC_DECOMPRESSION: 1827 case AUTOMATIC_DECOMPRESSION:
1793 automatic_decompression = true; 1828 result.config.automatic_decompression = true;
1794 break; 1829 break;
1795 case COOKIE_JAR: 1830 case COOKIE_JAR:
1796 cookie_jar_file = optarg; 1831 result.config.cookie_jar_file = optarg;
1797 break; 1832 break;
1798 case HAPROXY_PROTOCOL: 1833 case HAPROXY_PROTOCOL:
1799 haproxy_protocol = true; 1834 result.config.haproxy_protocol = true;
1800 break; 1835 break;
1801 case '?': 1836 case '?':
1802 /* print short usage statement if args not parsable */ 1837 /* print short usage statement if args not parsable */
@@ -1805,73 +1840,82 @@ bool process_arguments(int argc, char **argv) {
1805 } 1840 }
1806 } 1841 }
1807 1842
1808 c = optind; 1843 int c = optind;
1809 1844
1810 if (server_address == NULL && c < argc) 1845 if (result.config.server_address == NULL && c < argc) {
1811 server_address = strdup(argv[c++]); 1846 result.config.server_address = strdup(argv[c++]);
1847 }
1812 1848
1813 if (host_name == NULL && c < argc) 1849 if (result.config.host_name == NULL && c < argc) {
1814 host_name = strdup(argv[c++]); 1850 result.config.host_name = strdup(argv[c++]);
1851 }
1815 1852
1816 if (server_address == NULL) { 1853 if (result.config.server_address == NULL) {
1817 if (host_name == NULL) 1854 if (result.config.host_name == NULL) {
1818 usage4(_("You must specify a server address or host name")); 1855 usage4(_("You must specify a server address or host name"));
1819 else 1856 } else {
1820 server_address = strdup(host_name); 1857 result.config.server_address = strdup(result.config.host_name);
1858 }
1821 } 1859 }
1822 1860
1823 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 1861 set_thresholds(&result.config.thlds, warning_thresholds, critical_thresholds);
1824 1862
1825 if (critical_thresholds && thlds->critical->end > (double)socket_timeout) 1863 if (critical_thresholds && result.config.thlds->critical->end > (double)result.config.socket_timeout) {
1826 socket_timeout = (int)thlds->critical->end + 1; 1864 result.config.socket_timeout = (int)result.config.thlds->critical->end + 1;
1827 if (verbose >= 2) 1865 }
1828 printf("* Socket timeout set to %ld seconds\n", socket_timeout); 1866 if (verbose >= 2) {
1867 printf("* Socket timeout set to %ld seconds\n", result.config.socket_timeout);
1868 }
1829 1869
1830 if (http_method == NULL) 1870 if (result.config.http_method == NULL) {
1831 http_method = strdup("GET"); 1871 result.config.http_method = strdup("GET");
1872 }
1832 1873
1833 if (client_cert && !client_privkey) 1874 if (result.config.client_cert && !result.config.client_privkey) {
1834 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"));
1876 }
1835 1877
1836 if (virtual_port == 0) 1878 if (result.config.virtual_port == 0) {
1837 virtual_port = server_port; 1879 result.config.virtual_port = result.config.server_port;
1838 else { 1880 } else {
1839 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) ||
1840 if (!specify_port) 1882 (!result.config.use_ssl && result.config.server_port == HTTP_PORT)) {
1841 server_port = virtual_port; 1883 if (!specify_port) {
1884 result.config.server_port = result.config.virtual_port;
1885 }
1886 }
1842 } 1887 }
1843 1888
1844 return true; 1889 return result;
1845} 1890}
1846 1891
1847char *perfd_time(double elapsed_time) { 1892char *perfd_time(double elapsed_time, thresholds *thlds, long socket_timeout) {
1848 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,
1849 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);
1850} 1895}
1851 1896
1852char *perfd_time_connect(double elapsed_time_connect) { 1897char *perfd_time_connect(double elapsed_time_connect, long socket_timeout) {
1853 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);
1854} 1899}
1855 1900
1856char *perfd_time_ssl(double elapsed_time_ssl) { 1901char *perfd_time_ssl(double elapsed_time_ssl, long socket_timeout) {
1857 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);
1858} 1903}
1859 1904
1860char *perfd_time_headers(double elapsed_time_headers) { 1905char *perfd_time_headers(double elapsed_time_headers, long socket_timeout) {
1861 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);
1862} 1907}
1863 1908
1864char *perfd_time_firstbyte(double elapsed_time_firstbyte) { 1909char *perfd_time_firstbyte(double elapsed_time_firstbyte, long socket_timeout) {
1865 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);
1866} 1911}
1867 1912
1868char *perfd_time_transfer(double elapsed_time_transfer) { 1913char *perfd_time_transfer(double elapsed_time_transfer, long socket_timeout) {
1869 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);
1870} 1915}
1871 1916
1872char *perfd_size(int page_len) { 1917char *perfd_size(int page_len, int min_page_len) {
1873 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);
1874 false, 0);
1875} 1919}
1876 1920
1877void print_help(void) { 1921void print_help(void) {
@@ -2113,8 +2157,9 @@ int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) {
2113 buf->bufsize = DEFAULT_BUFFER_SIZE; 2157 buf->bufsize = DEFAULT_BUFFER_SIZE;
2114 buf->buflen = 0; 2158 buf->buflen = 0;
2115 buf->buf = (char *)malloc((size_t)buf->bufsize); 2159 buf->buf = (char *)malloc((size_t)buf->bufsize);
2116 if (buf->buf == NULL) 2160 if (buf->buf == NULL) {
2117 return -1; 2161 return -1;
2162 }
2118 return 0; 2163 return 0;
2119} 2164}
2120 2165
@@ -2156,8 +2201,9 @@ void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
2156int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) { 2201int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) {
2157 buf->buflen = datalen; 2202 buf->buflen = datalen;
2158 buf->buf = (char *)malloc((size_t)buf->buflen); 2203 buf->buf = (char *)malloc((size_t)buf->buflen);
2159 if (buf->buf == NULL) 2204 if (buf->buf == NULL) {
2160 return -1; 2205 return -1;
2206 }
2161 memcpy(buf->buf, data, datalen); 2207 memcpy(buf->buf, data, datalen);
2162 buf->pos = 0; 2208 buf->pos = 0;
2163 return 0; 2209 return 0;
@@ -2171,66 +2217,59 @@ void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2171/* 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)?
2172 */ 2218 */
2173const char *strrstr2(const char *haystack, const char *needle) { 2219const char *strrstr2(const char *haystack, const char *needle) {
2174 int counter; 2220 if (haystack == NULL || needle == NULL) {
2175 size_t len;
2176 const char *prev_pos;
2177 const char *pos;
2178
2179 if (haystack == NULL || needle == NULL)
2180 return NULL; 2221 return NULL;
2222 }
2181 2223
2182 if (haystack[0] == '\0' || needle[0] == '\0') 2224 if (haystack[0] == '\0' || needle[0] == '\0') {
2183 return NULL; 2225 return NULL;
2226 }
2184 2227
2185 counter = 0; 2228 int counter = 0;
2186 prev_pos = NULL; 2229 const char *prev_pos = NULL;
2187 pos = haystack; 2230 const char *pos = haystack;
2188 len = strlen(needle); 2231 size_t len = strlen(needle);
2189 for (;;) { 2232 for (;;) {
2190 pos = strstr(pos, needle); 2233 pos = strstr(pos, needle);
2191 if (pos == NULL) { 2234 if (pos == NULL) {
2192 if (counter == 0) 2235 if (counter == 0) {
2193 return NULL; 2236 return NULL;
2237 }
2194 return prev_pos; 2238 return prev_pos;
2195 } 2239 }
2196 counter++; 2240 counter++;
2197 prev_pos = pos; 2241 prev_pos = pos;
2198 pos += len; 2242 pos += len;
2199 if (*pos == '\0') 2243 if (*pos == '\0') {
2200 return prev_pos; 2244 return prev_pos;
2245 }
2201 } 2246 }
2202} 2247}
2203 2248
2204int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) { 2249int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
2205 char *first_line_end;
2206 char *p;
2207 size_t first_line_len;
2208 char *pp;
2209 const char *start;
2210 char *first_line_buf;
2211
2212 /* find last start of a new header */ 2250 /* find last start of a new header */
2213 start = strrstr2(buf, "\r\nHTTP/"); 2251 const char *start = strrstr2(buf, "\r\nHTTP/");
2214 if (start != NULL) { 2252 if (start != NULL) {
2215 start += 2; 2253 start += 2;
2216 buf = start; 2254 buf = start;
2217 } 2255 }
2218 2256
2219 first_line_end = strstr(buf, "\r\n"); 2257 char *first_line_end = strstr(buf, "\r\n");
2220 if (first_line_end == NULL) 2258 if (first_line_end == NULL) {
2221 return -1; 2259 return -1;
2260 }
2222 2261
2223 first_line_len = (size_t)(first_line_end - buf); 2262 size_t first_line_len = (size_t)(first_line_end - buf);
2224 status_line->first_line = (char *)malloc(first_line_len + 1); 2263 status_line->first_line = (char *)malloc(first_line_len + 1);
2225 if (status_line->first_line == NULL) 2264 if (status_line->first_line == NULL) {
2226 return -1; 2265 return -1;
2266 }
2227 memcpy(status_line->first_line, buf, first_line_len); 2267 memcpy(status_line->first_line, buf, first_line_len);
2228 status_line->first_line[first_line_len] = '\0'; 2268 status_line->first_line[first_line_len] = '\0';
2229 first_line_buf = strdup(status_line->first_line); 2269 char *first_line_buf = strdup(status_line->first_line);
2230 2270
2231 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */ 2271 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2232 2272 char *p = strtok(first_line_buf, "/");
2233 p = strtok(first_line_buf, "/");
2234 if (p == NULL) { 2273 if (p == NULL) {
2235 free(first_line_buf); 2274 free(first_line_buf);
2236 return -1; 2275 return -1;
@@ -2245,6 +2284,8 @@ int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line)
2245 free(first_line_buf); 2284 free(first_line_buf);
2246 return -1; 2285 return -1;
2247 } 2286 }
2287
2288 char *pp;
2248 if (strchr(p, '.') != NULL) { 2289 if (strchr(p, '.') != NULL) {
2249 2290
2250 /* HTTP 1.x case */ 2291 /* HTTP 1.x case */
@@ -2324,15 +2365,11 @@ char *get_header_value(const struct phr_header *headers, const size_t nof_header
2324 return NULL; 2365 return NULL;
2325} 2366}
2326 2367
2327int 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) {
2328 char *server_date = NULL;
2329 char *document_date = NULL;
2330 int date_result = STATE_OK;
2331 curlhelp_statusline status_line;
2332 struct phr_header headers[255]; 2369 struct phr_header headers[255];
2333 size_t nof_headers = 255; 2370 size_t nof_headers = 255;
2371 curlhelp_statusline status_line;
2334 size_t msglen; 2372 size_t msglen;
2335
2336 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,
2337 &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);
2338 2375
@@ -2340,9 +2377,10 @@ int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[D
2340 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2377 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2341 } 2378 }
2342 2379
2343 server_date = get_header_value(headers, nof_headers, "date"); 2380 char *server_date = get_header_value(headers, nof_headers, "date");
2344 document_date = get_header_value(headers, nof_headers, "last-modified"); 2381 char *document_date = get_header_value(headers, nof_headers, "last-modified");
2345 2382
2383 int date_result = STATE_OK;
2346 if (!server_date || !*server_date) { 2384 if (!server_date || !*server_date) {
2347 char tmp[DEFAULT_BUFFER_SIZE]; 2385 char tmp[DEFAULT_BUFFER_SIZE];
2348 2386
@@ -2362,8 +2400,9 @@ int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[D
2362 } else { 2400 } else {
2363 time_t srv_data = curl_getdate(server_date, NULL); 2401 time_t srv_data = curl_getdate(server_date, NULL);
2364 time_t doc_data = curl_getdate(document_date, NULL); 2402 time_t doc_data = curl_getdate(document_date, NULL);
2365 if (verbose >= 2) 2403 if (verbose >= 2) {
2366 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 2404 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2405 }
2367 if (srv_data <= 0) { 2406 if (srv_data <= 0) {
2368 char tmp[DEFAULT_BUFFER_SIZE]; 2407 char tmp[DEFAULT_BUFFER_SIZE];
2369 2408
@@ -2405,22 +2444,21 @@ int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[D
2405 } 2444 }
2406 } 2445 }
2407 2446
2408 if (server_date) 2447 if (server_date) {
2409 free(server_date); 2448 free(server_date);
2410 if (document_date) 2449 }
2450 if (document_date) {
2411 free(document_date); 2451 free(document_date);
2452 }
2412 2453
2413 return date_result; 2454 return date_result;
2414} 2455}
2415 2456
2416int 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) {
2417 size_t content_length = 0;
2418 struct phr_header headers[255]; 2458 struct phr_header headers[255];
2419 size_t nof_headers = 255; 2459 size_t nof_headers = 255;
2420 size_t msglen; 2460 size_t msglen;
2421 char *content_length_s = NULL;
2422 curlhelp_statusline status_line; 2461 curlhelp_statusline status_line;
2423
2424 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,
2425 &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);
2426 2464
@@ -2428,52 +2466,56 @@ int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_
2428 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2466 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2429 } 2467 }
2430 2468
2431 content_length_s = get_header_value(headers, nof_headers, "content-length"); 2469 char *content_length_s = get_header_value(headers, nof_headers, "content-length");
2432 if (!content_length_s) { 2470 if (!content_length_s) {
2433 return header_buf->buflen + body_buf->buflen; 2471 return header_buf->buflen + body_buf->buflen;
2434 } 2472 }
2473
2435 content_length_s += strspn(content_length_s, " \t"); 2474 content_length_s += strspn(content_length_s, " \t");
2436 content_length = atoi(content_length_s); 2475 size_t content_length = atoi(content_length_s);
2437 if (content_length != body_buf->buflen) { 2476 if (content_length != body_buf->buflen) {
2438 /* 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? */
2439 } 2478 }
2440 2479
2441 if (content_length_s) 2480 if (content_length_s) {
2442 free(content_length_s); 2481 free(content_length_s);
2482 }
2443 2483
2444 return header_buf->buflen + body_buf->buflen; 2484 return header_buf->buflen + body_buf->buflen;
2445} 2485}
2446 2486
2447/* 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? */
2448curlhelp_ssl_library curlhelp_get_ssl_library(void) { 2488curlhelp_ssl_library curlhelp_get_ssl_library(void) {
2449 curl_version_info_data *version_data;
2450 char *ssl_version;
2451 char *library;
2452 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 2489 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2453 2490
2454 version_data = curl_version_info(CURLVERSION_NOW); 2491 curl_version_info_data *version_data = curl_version_info(CURLVERSION_NOW);
2455 if (version_data == NULL) 2492 if (version_data == NULL) {
2456 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2493 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2494 }
2457 2495
2458 ssl_version = strdup(version_data->ssl_version); 2496 char *ssl_version = strdup(version_data->ssl_version);
2459 if (ssl_version == NULL) 2497 if (ssl_version == NULL) {
2460 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2498 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2499 }
2461 2500
2462 library = strtok(ssl_version, "/"); 2501 char *library = strtok(ssl_version, "/");
2463 if (library == NULL) 2502 if (library == NULL) {
2464 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2503 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2504 }
2465 2505
2466 if (strcmp(library, "OpenSSL") == 0) 2506 if (strcmp(library, "OpenSSL") == 0) {
2467 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL; 2507 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2468 else if (strcmp(library, "LibreSSL") == 0) 2508 } else if (strcmp(library, "LibreSSL") == 0) {
2469 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL; 2509 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2470 else if (strcmp(library, "GnuTLS") == 0) 2510 } else if (strcmp(library, "GnuTLS") == 0) {
2471 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS; 2511 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2472 else if (strcmp(library, "NSS") == 0) 2512 } else if (strcmp(library, "NSS") == 0) {
2473 ssl_library = CURLHELP_SSL_LIBRARY_NSS; 2513 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2514 }
2474 2515
2475 if (verbose >= 2) 2516 if (verbose >= 2) {
2476 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library); 2517 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
2518 }
2477 2519
2478 free(ssl_version); 2520 free(ssl_version);
2479 2521
@@ -2499,19 +2541,18 @@ const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2499#ifdef LIBCURL_FEATURE_SSL 2541#ifdef LIBCURL_FEATURE_SSL
2500# ifndef USE_OPENSSL 2542# ifndef USE_OPENSSL
2501time_t parse_cert_date(const char *s) { 2543time_t parse_cert_date(const char *s) {
2502 struct tm tm; 2544 if (!s) {
2503 time_t date;
2504 char *res;
2505
2506 if (!s)
2507 return -1; 2545 return -1;
2546 }
2508 2547
2509 /* Jan 17 14:25:12 2020 GMT */ 2548 /* Jan 17 14:25:12 2020 GMT */
2510 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);
2511 /* Sep 11 12:00:00 2020 GMT */ 2551 /* Sep 11 12:00:00 2020 GMT */
2512 if (res == NULL) 2552 if (res == NULL) {
2513 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm); 2553 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2514 date = mktime(&tm); 2554 }
2555 time_t date = mktime(&tm);
2515 2556
2516 return date; 2557 return date;
2517} 2558}
@@ -2520,7 +2561,6 @@ time_t parse_cert_date(const char *s) {
2520 * OpenSSL could be this function 2561 * OpenSSL could be this function
2521 */ 2562 */
2522int 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) {
2523 int i;
2524 struct curl_slist *slist; 2564 struct curl_slist *slist;
2525 int cname_found = 0; 2565 int cname_found = 0;
2526 char *start_date_str = NULL; 2566 char *start_date_str = NULL;
@@ -2534,10 +2574,11 @@ int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_
2534 char timestamp[50] = ""; 2574 char timestamp[50] = "";
2535 int status = STATE_UNKNOWN; 2575 int status = STATE_UNKNOWN;
2536 2576
2537 if (verbose >= 2) 2577 if (verbose >= 2) {
2538 printf("**** REQUEST CERTIFICATES ****\n"); 2578 printf("**** REQUEST CERTIFICATES ****\n");
2579 }
2539 2580
2540 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++) {
2541 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) {
2542 /* find first common name in subject, 2583 /* find first common name in subject,
2543 * TODO: check alternative subjects for 2584 * TODO: check alternative subjects for
@@ -2563,14 +2604,16 @@ int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_
2563 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) { 2604 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2564 goto HAVE_FIRST_CERT; 2605 goto HAVE_FIRST_CERT;
2565 } 2606 }
2566 if (verbose >= 2) 2607 if (verbose >= 2) {
2567 printf("%d ** %s\n", i, slist->data); 2608 printf("%d ** %s\n", i, slist->data);
2609 }
2568 } 2610 }
2569 } 2611 }
2570HAVE_FIRST_CERT: 2612HAVE_FIRST_CERT:
2571 2613
2572 if (verbose >= 2) 2614 if (verbose >= 2) {
2573 printf("**** REQUEST CERTIFICATES ****\n"); 2615 printf("**** REQUEST CERTIFICATES ****\n");
2616 }
2574 2617
2575 if (!cname_found) { 2618 if (!cname_found) {
2576 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject.")); 2619 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
@@ -2597,42 +2640,47 @@ HAVE_FIRST_CERT:
2597 setenv("TZ", "GMT", 1); 2640 setenv("TZ", "GMT", 1);
2598 tzset(); 2641 tzset();
2599 strftime(timestamp, 50, "%c %z", localtime(&end_date)); 2642 strftime(timestamp, 50, "%c %z", localtime(&end_date));
2600 if (tz) 2643 if (tz) {
2601 setenv("TZ", tz, 1); 2644 setenv("TZ", tz, 1);
2602 else 2645 } else {
2603 unsetenv("TZ"); 2646 unsetenv("TZ");
2647 }
2604 tzset(); 2648 tzset();
2605 2649
2606 if (days_left > 0 && days_left <= days_till_exp_warn) { 2650 if (days_left > 0 && days_left <= days_till_exp_warn) {
2607 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", 2651 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL",
2608 host_name, days_left, timestamp); 2652 host_name, days_left, timestamp);
2609 if (days_left > days_till_exp_crit) 2653 if (days_left > days_till_exp_crit) {
2610 status = STATE_WARNING; 2654 status = STATE_WARNING;
2611 else 2655 } else {
2612 status = STATE_CRITICAL; 2656 status = STATE_CRITICAL;
2657 }
2613 } else if (days_left == 0 && time_left > 0) { 2658 } else if (days_left == 0 && time_left > 0) {
2614 if (time_left >= 3600) 2659 if (time_left >= 3600) {
2615 time_remaining = (int)time_left / 3600; 2660 time_remaining = (int)time_left / 3600;
2616 else 2661 } else {
2617 time_remaining = (int)time_left / 60; 2662 time_remaining = (int)time_left / 60;
2663 }
2618 2664
2619 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, 2665 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2620 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp); 2666 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
2621 2667
2622 if (days_left > days_till_exp_crit) 2668 if (days_left > days_till_exp_crit) {
2623 status = STATE_WARNING; 2669 status = STATE_WARNING;
2624 else 2670 } else {
2625 status = STATE_CRITICAL; 2671 status = STATE_CRITICAL;
2672 }
2626 } else if (time_left < 0) { 2673 } else if (time_left < 0) {
2627 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 2674 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2628 status = STATE_CRITICAL; 2675 status = STATE_CRITICAL;
2629 } else if (days_left == 0) { 2676 } else if (days_left == 0) {
2630 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, 2677 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2631 timestamp); 2678 timestamp);
2632 if (days_left > days_till_exp_crit) 2679 if (days_left > days_till_exp_crit) {
2633 status = STATE_WARNING; 2680 status = STATE_WARNING;
2634 else 2681 } else {
2635 status = STATE_CRITICAL; 2682 status = STATE_CRITICAL;
2683 }
2636 } else { 2684 } else {
2637 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp); 2685 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp);
2638 status = STATE_OK; 2686 status = STATE_OK;
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}