summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am2
-rw-r--r--plugins/check_curl.c2299
-rw-r--r--plugins/check_curl.d/config.h160
3 files changed, 1490 insertions, 971 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index deae938d..1f24d923 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -92,6 +92,8 @@ EXTRA_DIST = t \
92 check_ntp_time.d \ 92 check_ntp_time.d \
93 check_dig.d \ 93 check_dig.d \
94 check_cluster.d \ 94 check_cluster.d \
95 check_curl.d \
96 check_cluster.d \
95 check_ups.d \ 97 check_ups.d \
96 check_fping.d 98 check_fping.d
97 99
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index 748201e8..76dcbfd8 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
@@ -50,7 +53,7 @@ const char *email = "devel@monitoring-plugins.org";
50#include "curl/curl.h" 53#include "curl/curl.h"
51#include "curl/easy.h" 54#include "curl/easy.h"
52 55
53#include "picohttpparser.h" 56#include "./picohttpparser/picohttpparser.h"
54 57
55#include "uriparser/Uri.h" 58#include "uriparser/Uri.h"
56 59
@@ -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,125 +110,91 @@ 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; 118static int verbose = 0;
155static bool show_extended_perfdata = false; 119
156static bool show_body = false; 120typedef struct {
157static int min_page_len = 0; 121 bool curl_global_initialized;
158static int max_page_len = 0; 122 bool curl_easy_initialized;
159static int redir_depth = 0; 123 bool body_buf_initialized;
160static int max_depth = DEFAULT_MAX_REDIRS; 124 curlhelp_write_curlbuf body_buf;
161static char *http_method = NULL; 125 bool header_buf_initialized;
162static char *http_post_data = NULL; 126 curlhelp_write_curlbuf header_buf;
163static char *http_content_type = NULL; 127 bool status_line_initialized;
164static CURL *curl; 128 curlhelp_statusline status_line;
165static bool curl_global_initialized = false; 129 bool put_buf_initialized;
166static bool curl_easy_initialized = false; 130 curlhelp_read_curlbuf put_buf;
167static struct curl_slist *header_list = NULL; 131 CURL *curl;
168static bool body_buf_initialized = false; 132} check_curl_global_state;
169static curlhelp_write_curlbuf body_buf; 133
170static bool header_buf_initialized = false; 134check_curl_global_state global_state = {
171static curlhelp_write_curlbuf header_buf; 135 .curl_global_initialized = false,
172static bool status_line_initialized = false; 136 .curl_easy_initialized = false,
173static curlhelp_statusline status_line; 137 .body_buf_initialized = false,
174static bool put_buf_initialized = false; 138 .body_buf = {},
175static curlhelp_read_curlbuf put_buf; 139 .header_buf_initialized = false,
176static char http_header[DEFAULT_BUFFER_SIZE]; 140 .header_buf = {},
177static long code; 141 .status_line_initialized = false,
178static long socket_timeout = DEFAULT_SOCKET_TIMEOUT; 142 .status_line = {},
179static double total_time; 143 .put_buf_initialized = false,
180static double time_connect; 144 .put_buf = {},
181static double time_appconnect; 145 .curl = NULL,
182static double time_headers; 146};
183static double time_firstbyte; 147
148static long httpReturnCode;
184static char errbuf[MAX_INPUT_BUFFER]; 149static char errbuf[MAX_INPUT_BUFFER];
185static CURLcode res;
186static char url[DEFAULT_BUFFER_SIZE];
187static char msg[DEFAULT_BUFFER_SIZE]; 150static 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 { 151typedef union {
205 struct curl_slist *to_info; 152 struct curl_slist *to_info;
206 struct curl_certinfo *to_certinfo; 153 struct curl_certinfo *to_certinfo;
207} cert_ptr_union; 154} cert_ptr_union;
208static 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; 155static bool is_openssl_callback = false;
215static bool add_sslctx_verify_fun = false; 156static bool add_sslctx_verify_fun = false;
157
216#if defined(HAVE_SSL) && defined(USE_OPENSSL) 158#if defined(HAVE_SSL) && defined(USE_OPENSSL)
217static X509 *cert = NULL; 159static X509 *cert = NULL;
218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 160#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
219static bool no_body = false; 161
220static int maximum_age = -1; 162typedef struct {
221static int address_family = AF_UNSPEC; 163 int errorcode;
222static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 164 check_curl_config config;
223static int curl_http_version = CURL_HTTP_VERSION_NONE; 165} check_curl_config_wrapper;
224static bool automatic_decompression = false; 166static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
225static char *cookie_jar_file = NULL; 167
226static bool haproxy_protocol = false;
227
228static bool process_arguments(int /*argc*/, char ** /*argv*/);
229static void handle_curl_option_return_code(CURLcode res, const char *option); 168static void handle_curl_option_return_code(CURLcode res, const char *option);
230static int check_http(void); 169static mp_state_enum check_http(check_curl_config /*config*/, check_curl_working_state workingState,
231static void redir(curlhelp_write_curlbuf * /*header_buf*/); 170 int redir_depth, struct curl_slist *header_list);
232static char *perfd_time(double elapsed_time); 171
233static char *perfd_time_connect(double elapsed_time_connect); 172typedef struct {
234static char *perfd_time_ssl(double elapsed_time_ssl); 173 int redir_depth;
235static char *perfd_time_firstbyte(double elapsed_time_firstbyte); 174 check_curl_working_state working_state;
236static char *perfd_time_headers(double elapsed_time_headers); 175 int error_code;
237static char *perfd_time_transfer(double elapsed_time_transfer); 176} redir_wrapper;
238static char *perfd_size(int page_len); 177static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/,
178 int redir_depth, check_curl_working_state working_state);
179
180static char *perfd_time(double elapsed_time, thresholds * /*thlds*/, long /*socket_timeout*/);
181static char *perfd_time_connect(double elapsed_time_connect, long /*socket_timeout*/);
182static char *perfd_time_ssl(double elapsed_time_ssl, long /*socket_timeout*/);
183static char *perfd_time_firstbyte(double elapsed_time_firstbyte, long /*socket_timeout*/);
184static char *perfd_time_headers(double elapsed_time_headers, long /*socket_timeout*/);
185static char *perfd_time_transfer(double elapsed_time_transfer, long /*socket_timeout*/);
186static char *perfd_size(size_t page_len, int /*min_page_len*/);
239static void print_help(void); 187static void print_help(void);
240void print_usage(void); 188void print_usage(void);
241static void print_curl_version(void); 189static void print_curl_version(void);
242static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/); 190static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/);
243static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/); 191static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
192 void * /*stream*/);
244static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/); 193static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
245static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/, size_t /*datalen*/); 194static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/,
246static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/); 195 size_t /*datalen*/);
196static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
197 void * /*stream*/);
247static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/); 198static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
248static curlhelp_ssl_library curlhelp_get_ssl_library(void); 199static curlhelp_ssl_library curlhelp_get_ssl_library(void);
249static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/); 200static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
@@ -251,9 +202,12 @@ int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
251 202
252static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/); 203static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
253static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/); 204static 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); 205static char *get_header_value(const struct phr_header *headers, size_t nof_headers,
255static int check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, char (*msg)[DEFAULT_BUFFER_SIZE]); 206 const char *header);
256static int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf); 207static mp_state_enum check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/,
208 char (*msg)[DEFAULT_BUFFER_SIZE], int /*maximum_age*/);
209static size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
210 const curlhelp_write_curlbuf *body_buf);
257 211
258#if defined(HAVE_SSL) && defined(USE_OPENSSL) 212#if defined(HAVE_SSL) && defined(USE_OPENSSL)
259int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit); 213int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit);
@@ -262,8 +216,6 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
262static void test_file(char * /*path*/); 216static void test_file(char * /*path*/);
263 217
264int main(int argc, char **argv) { 218int main(int argc, char **argv) {
265 int result = STATE_UNKNOWN;
266
267 setlocale(LC_ALL, ""); 219 setlocale(LC_ALL, "");
268 bindtextdomain(PACKAGE, LOCALEDIR); 220 bindtextdomain(PACKAGE, LOCALEDIR);
269 textdomain(PACKAGE); 221 textdomain(PACKAGE);
@@ -271,19 +223,36 @@ int main(int argc, char **argv) {
271 /* Parse extra opts if any */ 223 /* Parse extra opts if any */
272 argv = np_extra_opts(&argc, argv, progname); 224 argv = np_extra_opts(&argc, argv, progname);
273 225
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 */ 226 /* parse arguments */
278 if (process_arguments(argc, argv) == false) 227 check_curl_config_wrapper tmp_config = process_arguments(argc, argv);
228 if (tmp_config.errorcode == ERROR) {
279 usage4(_("Could not parse arguments")); 229 usage4(_("Could not parse arguments"));
230 }
280 231
281 if (display_html) 232 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 233
285 result = check_http(); 234 /* set defaults */
286 return result; 235 if (strlen(config.user_agent) == 0) {
236 snprintf(config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)",
237 progname, NP_VERSION, VERSION, curl_version());
238 }
239
240 if (config.display_html) {
241 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
242 config.initial_config.use_ssl ? "https" : "http",
243 config.initial_config.host_name ? config.initial_config.host_name
244 : config.initial_config.server_address,
245 config.initial_config.virtualPort ? config.initial_config.virtualPort
246 : config.initial_config.serverPort,
247 config.initial_config.server_url);
248 }
249
250 int redir_depth = 0;
251
252 check_curl_working_state working_state = config.initial_config;
253 struct curl_slist *header_list = NULL;
254
255 exit((int)check_http(config, working_state, redir_depth, header_list));
287} 256}
288 257
289#ifdef HAVE_SSL 258#ifdef HAVE_SSL
@@ -301,13 +270,11 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
301# endif 270# endif
302 if (verbose >= 2) { 271 if (verbose >= 2) {
303 puts("* SSL verify callback with certificate:"); 272 puts("* SSL verify callback with certificate:");
304 X509_NAME *subject;
305 X509_NAME *issuer;
306 printf("* issuer:\n"); 273 printf("* issuer:\n");
307 issuer = X509_get_issuer_name(cert); 274 X509_NAME *issuer = X509_get_issuer_name(cert);
308 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); 275 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
309 printf("* curl verify_callback:\n* subject:\n"); 276 printf("* curl verify_callback:\n* subject:\n");
310 subject = X509_get_subject_name(cert); 277 X509_NAME *subject = X509_get_subject_name(cert);
311 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); 278 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
312 puts(""); 279 puts("");
313 } 280 }
@@ -356,19 +323,20 @@ static char *string_statuscode(int major, int minor) {
356} 323}
357 324
358/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 325/* Checks if the server 'reply' is one of the expected 'statuscodes' */
359static int expected_statuscode(const char *reply, const char *statuscodes) { 326static bool expected_statuscode(const char *reply, const char *statuscodes) {
360 char *expected; 327 char *expected;
361 char *code;
362 int result = 0;
363 328
364 if ((expected = strdup(statuscodes)) == NULL) 329 if ((expected = strdup(statuscodes)) == NULL) {
365 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 330 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
331 }
366 332
367 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) 333 bool result = false;
334 for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) {
368 if (strstr(reply, code) != NULL) { 335 if (strstr(reply, code) != NULL) {
369 result = 1; 336 result = true;
370 break; 337 break;
371 } 338 }
339 }
372 340
373 free(expected); 341 free(expected);
374 return result; 342 return result;
@@ -376,32 +344,33 @@ static int expected_statuscode(const char *reply, const char *statuscodes) {
376 344
377void handle_curl_option_return_code(CURLcode res, const char *option) { 345void handle_curl_option_return_code(CURLcode res, const char *option) {
378 if (res != CURLE_OK) { 346 if (res != CURLE_OK) {
379 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res, 347 snprintf(msg, DEFAULT_BUFFER_SIZE,
348 _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res,
380 curl_easy_strerror(res)); 349 curl_easy_strerror(res));
381 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 350 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
382 } 351 }
383} 352}
384 353
385int lookup_host(const char *host, char *buf, size_t buflen) { 354int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) {
386 struct addrinfo hints, *res, *result; 355 struct addrinfo hints = {
387 char addrstr[100]; 356 .ai_family = addr_family,
388 size_t addrstr_len; 357 .ai_socktype = SOCK_STREAM,
389 int errcode; 358 .ai_flags = AI_CANONNAME,
390 void *ptr = {0}; 359 };
391 size_t buflen_remaining = buflen - 1;
392
393 memset(&hints, 0, sizeof(hints));
394 hints.ai_family = address_family;
395 hints.ai_socktype = SOCK_STREAM;
396 hints.ai_flags |= AI_CANONNAME;
397 360
398 errcode = getaddrinfo(host, NULL, &hints, &result); 361 struct addrinfo *result;
399 if (errcode != 0) 362 int errcode = getaddrinfo(host, NULL, &hints, &result);
363 if (errcode != 0) {
400 return errcode; 364 return errcode;
365 }
401 366
402 strcpy(buf, ""); 367 strcpy(buf, "");
403 res = result; 368 struct addrinfo *res = result;
404 369
370 size_t buflen_remaining = buflen - 1;
371 size_t addrstr_len;
372 char addrstr[100];
373 void *ptr = {0};
405 while (res) { 374 while (res) {
406 switch (res->ai_family) { 375 switch (res->ai_family) {
407 case AF_INET: 376 case AF_INET:
@@ -414,7 +383,8 @@ int lookup_host(const char *host, char *buf, size_t buflen) {
414 383
415 inet_ntop(res->ai_family, ptr, addrstr, 100); 384 inet_ntop(res->ai_family, ptr, addrstr, 100);
416 if (verbose >= 1) { 385 if (verbose >= 1) {
417 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr); 386 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4,
387 addrstr);
418 } 388 }
419 389
420 // Append all IPs to buf as a comma-separated string 390 // Append all IPs to buf as a comma-separated string
@@ -437,168 +407,232 @@ int lookup_host(const char *host, char *buf, size_t buflen) {
437} 407}
438 408
439static void cleanup(void) { 409static void cleanup(void) {
440 if (status_line_initialized) 410 if (global_state.status_line_initialized) {
441 curlhelp_free_statusline(&status_line); 411 curlhelp_free_statusline(&global_state.status_line);
442 status_line_initialized = false; 412 }
443 if (curl_easy_initialized) 413 global_state.status_line_initialized = false;
444 curl_easy_cleanup(curl); 414
445 curl_easy_initialized = false; 415 if (global_state.curl_easy_initialized) {
446 if (curl_global_initialized) 416 curl_easy_cleanup(global_state.curl);
417 }
418 global_state.curl_easy_initialized = false;
419
420 if (global_state.curl_global_initialized) {
447 curl_global_cleanup(); 421 curl_global_cleanup();
448 curl_global_initialized = false; 422 }
449 if (body_buf_initialized) 423 global_state.curl_global_initialized = false;
450 curlhelp_freewritebuffer(&body_buf);
451 body_buf_initialized = false;
452 if (header_buf_initialized)
453 curlhelp_freewritebuffer(&header_buf);
454 header_buf_initialized = false;
455 if (put_buf_initialized)
456 curlhelp_freereadbuffer(&put_buf);
457 put_buf_initialized = false;
458}
459 424
460int check_http(void) { 425 if (global_state.body_buf_initialized) {
461 int result = STATE_OK; 426 curlhelp_freewritebuffer(&global_state.body_buf);
462 int result_ssl = STATE_OK; 427 }
463 int page_len = 0; 428 global_state.body_buf_initialized = false;
464 int i; 429
465 char *force_host_header = NULL; 430 if (global_state.header_buf_initialized) {
466 struct curl_slist *host = NULL; 431 curlhelp_freewritebuffer(&global_state.header_buf);
467 char addrstr[DEFAULT_BUFFER_SIZE / 2]; 432 }
468 char dnscache[DEFAULT_BUFFER_SIZE]; 433 global_state.header_buf_initialized = false;
434
435 if (global_state.put_buf_initialized) {
436 curlhelp_freereadbuffer(&global_state.put_buf);
437 }
438 global_state.put_buf_initialized = false;
439}
469 440
441mp_state_enum check_http(const check_curl_config config, check_curl_working_state workingState,
442 int redir_depth, struct curl_slist *header_list) {
470 /* initialize curl */ 443 /* initialize curl */
471 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) 444 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) {
472 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 445 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
473 curl_global_initialized = true; 446 }
447 global_state.curl_global_initialized = true;
474 448
475 if ((curl = curl_easy_init()) == NULL) { 449 if ((global_state.curl = curl_easy_init()) == NULL) {
476 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); 450 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
477 } 451 }
478 curl_easy_initialized = true; 452 global_state.curl_easy_initialized = true;
479 453
480 /* register cleanup function to shut down libcurl properly */ 454 /* register cleanup function to shut down libcurl properly */
481 atexit(cleanup); 455 atexit(cleanup);
482 456
483 if (verbose >= 1) 457 if (verbose >= 1) {
484 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE"); 458 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_VERBOSE, 1),
459 "CURLOPT_VERBOSE");
460 }
485 461
486 /* print everything on stdout like check_http would do */ 462 /* print everything on stdout like check_http would do */
487 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); 463 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_STDERR, stdout),
464 "CURLOPT_STDERR");
488 465
489 if (automatic_decompression) 466 if (config.automatic_decompression) {
490#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) 467#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"); 468 handle_curl_option_return_code(
469 curl_easy_setopt(global_state.curl, CURLOPT_ACCEPT_ENCODING, ""),
470 "CURLOPT_ACCEPT_ENCODING");
492#else 471#else
493 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING"); 472 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ENCODING, ""),
473 "CURLOPT_ENCODING");
494#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ 474#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
475 }
495 476
496 /* initialize buffer for body of the answer */ 477 /* initialize buffer for body of the answer */
497 if (curlhelp_initwritebuffer(&body_buf) < 0) 478 if (curlhelp_initwritebuffer(&global_state.body_buf) < 0) {
498 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); 479 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
499 body_buf_initialized = true; 480 }
500 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), 481 global_state.body_buf_initialized = true;
501 "CURLOPT_WRITEFUNCTION"); 482 handle_curl_option_return_code(
502 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA"); 483 curl_easy_setopt(global_state.curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_write_callback),
484 "CURLOPT_WRITEFUNCTION");
485 handle_curl_option_return_code(
486 curl_easy_setopt(global_state.curl, CURLOPT_WRITEDATA, (void *)&global_state.body_buf),
487 "CURLOPT_WRITEDATA");
503 488
504 /* initialize buffer for header of the answer */ 489 /* initialize buffer for header of the answer */
505 if (curlhelp_initwritebuffer(&header_buf) < 0) 490 if (curlhelp_initwritebuffer(&global_state.header_buf) < 0) {
506 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n"); 491 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
507 header_buf_initialized = true; 492 }
508 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), 493 global_state.header_buf_initialized = true;
509 "CURLOPT_HEADERFUNCTION"); 494
510 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER"); 495 handle_curl_option_return_code(
496 curl_easy_setopt(global_state.curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_write_callback),
497 "CURLOPT_HEADERFUNCTION");
498 handle_curl_option_return_code(
499 curl_easy_setopt(global_state.curl, CURLOPT_WRITEHEADER, (void *)&global_state.header_buf),
500 "CURLOPT_WRITEHEADER");
511 501
512 /* set the error buffer */ 502 /* set the error buffer */
513 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER"); 503 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ERRORBUFFER, errbuf),
504 "CURLOPT_ERRORBUFFER");
514 505
515 /* set timeouts */ 506 /* set timeouts */
516 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT"); 507 handle_curl_option_return_code(
517 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT"); 508 curl_easy_setopt(global_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout),
509 "CURLOPT_CONNECTTIMEOUT");
510 handle_curl_option_return_code(
511 curl_easy_setopt(global_state.curl, CURLOPT_TIMEOUT, config.socket_timeout),
512 "CURLOPT_TIMEOUT");
518 513
519 /* enable haproxy protocol */ 514 /* enable haproxy protocol */
520 if (haproxy_protocol) { 515 if (config.haproxy_protocol) {
521 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL"); 516 handle_curl_option_return_code(
517 curl_easy_setopt(global_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L),
518 "CURLOPT_HAPROXYPROTOCOL");
522 } 519 }
523 520
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 521 // fill dns resolve cache to make curl connect to the given server_address instead of the
525 // use the host_name later on to make SNI happy 522 // host_name, only required for ssl, because we use the host_name later on to make SNI happy
526 if (use_ssl && host_name != NULL) { 523 struct curl_slist *host = NULL;
527 if ((res = lookup_host(server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) { 524 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, 525 char addrstr[DEFAULT_BUFFER_SIZE / 2];
529 gai_strerror(res)); 526 if (workingState.use_ssl && workingState.host_name != NULL) {
527 int res;
528 if ((res = lookup_host(workingState.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2,
529 config.sin_family)) != 0) {
530 snprintf(msg, DEFAULT_BUFFER_SIZE,
531 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
532 workingState.server_address, res, gai_strerror(res));
530 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 533 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
531 } 534 }
532 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr); 535 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", workingState.host_name,
536 workingState.serverPort, addrstr);
533 host = curl_slist_append(NULL, dnscache); 537 host = curl_slist_append(NULL, dnscache);
534 curl_easy_setopt(curl, CURLOPT_RESOLVE, host); 538 curl_easy_setopt(global_state.curl, CURLOPT_RESOLVE, host);
535 if (verbose >= 1) 539 if (verbose >= 1) {
536 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache); 540 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
541 }
537 } 542 }
538 543
539 // If server_address is an IPv6 address it must be surround by square brackets 544 // If server_address is an IPv6 address it must be surround by square brackets
540 struct in6_addr tmp_in_addr; 545 struct in6_addr tmp_in_addr;
541 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) { 546 if (inet_pton(AF_INET6, workingState.server_address, &tmp_in_addr) == 1) {
542 char *new_server_address = malloc(strlen(server_address) + 3); 547 char *new_server_address = malloc(strlen(workingState.server_address) + 3);
543 if (new_server_address == NULL) { 548 if (new_server_address == NULL) {
544 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); 549 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
545 } 550 }
546 snprintf(new_server_address, strlen(server_address) + 3, "[%s]", server_address); 551 snprintf(new_server_address, strlen(workingState.server_address) + 3, "[%s]",
547 free(server_address); 552 workingState.server_address);
548 server_address = new_server_address; 553 free(workingState.server_address);
554 workingState.server_address = new_server_address;
549 } 555 }
550 556
551 /* compose URL: use the address we want to connect to, set Host: header later */ 557 /* 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", 558 char url[DEFAULT_BUFFER_SIZE];
553 (use_ssl & (host_name != NULL)) ? host_name : server_address, server_port, server_url); 559 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", workingState.use_ssl ? "https" : "http",
554 560 (workingState.use_ssl & (workingState.host_name != NULL))
555 if (verbose >= 1) 561 ? workingState.host_name
562 : workingState.server_address,
563 workingState.serverPort, workingState.server_url);
564
565 if (verbose >= 1) {
556 printf("* curl CURLOPT_URL: %s\n", url); 566 printf("* curl CURLOPT_URL: %s\n", url);
557 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL"); 567 }
568 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_URL, url),
569 "CURLOPT_URL");
558 570
559 /* extract proxy information for legacy proxy https requests */ 571 /* extract proxy information for legacy proxy https requests */
560 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) { 572 if (!strcmp(workingState.http_method, "CONNECT") ||
561 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY"); 573 strstr(workingState.server_url, "http") == workingState.server_url) {
562 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT"); 574 handle_curl_option_return_code(
563 if (verbose >= 2) 575 curl_easy_setopt(global_state.curl, CURLOPT_PROXY, workingState.server_address),
564 printf("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port); 576 "CURLOPT_PROXY");
565 http_method = "GET"; 577 handle_curl_option_return_code(
566 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, server_url), "CURLOPT_URL"); 578 curl_easy_setopt(global_state.curl, CURLOPT_PROXYPORT, (long)workingState.serverPort),
579 "CURLOPT_PROXYPORT");
580 if (verbose >= 2) {
581 printf("* curl CURLOPT_PROXY: %s:%d\n", workingState.server_address,
582 workingState.serverPort);
583 }
584 workingState.http_method = "GET";
585 handle_curl_option_return_code(
586 curl_easy_setopt(global_state.curl, CURLOPT_URL, workingState.server_url),
587 "CURLOPT_URL");
567 } 588 }
568 589
569 /* disable body for HEAD request */ 590 /* disable body for HEAD request */
570 if (http_method && !strcmp(http_method, "HEAD")) { 591 if (workingState.http_method && !strcmp(workingState.http_method, "HEAD")) {
571 no_body = true; 592 workingState.no_body = true;
572 } 593 }
573 594
574 /* set HTTP protocol version */ 595 /* set HTTP protocol version */
575 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION"); 596 handle_curl_option_return_code(
597 curl_easy_setopt(global_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version),
598 "CURLOPT_HTTP_VERSION");
576 599
577 /* set HTTP method */ 600 /* set HTTP method */
578 if (http_method) { 601 if (workingState.http_method) {
579 if (!strcmp(http_method, "POST")) 602 if (!strcmp(workingState.http_method, "POST")) {
580 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST"); 603 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POST, 1),
581 else if (!strcmp(http_method, "PUT")) 604 "CURLOPT_POST");
582 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); 605 } else if (!strcmp(workingState.http_method, "PUT")) {
583 else 606 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_UPLOAD, 1),
584 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST"); 607 "CURLOPT_UPLOAD");
608 } else {
609 handle_curl_option_return_code(curl_easy_setopt(global_state.curl,
610 CURLOPT_CUSTOMREQUEST,
611 workingState.http_method),
612 "CURLOPT_CUSTOMREQUEST");
613 }
585 } 614 }
586 615
616 char *force_host_header = NULL;
587 /* check if Host header is explicitly set in options */ 617 /* check if Host header is explicitly set in options */
588 if (http_opt_headers_count) { 618 if (config.http_opt_headers_count) {
589 for (i = 0; i < http_opt_headers_count; i++) { 619 for (size_t i = 0; i < config.http_opt_headers_count; i++) {
590 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 620 if (strncmp(config.http_opt_headers[i], "Host:", 5) == 0) {
591 force_host_header = http_opt_headers[i]; 621 force_host_header = config.http_opt_headers[i];
592 } 622 }
593 } 623 }
594 } 624 }
595 625
596 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */ 626 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in
597 if (host_name != NULL && force_host_header == NULL) { 627 * anyway */
598 if ((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) { 628 char http_header[DEFAULT_BUFFER_SIZE];
599 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port); 629 if (workingState.host_name != NULL && force_host_header == NULL) {
630 if ((workingState.virtualPort != HTTP_PORT && !workingState.use_ssl) ||
631 (workingState.virtualPort != HTTPS_PORT && workingState.use_ssl)) {
632 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", workingState.host_name,
633 workingState.virtualPort);
600 } else { 634 } else {
601 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); 635 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", workingState.host_name);
602 } 636 }
603 header_list = curl_slist_append(header_list, http_header); 637 header_list = curl_slist_append(header_list, http_header);
604 } 638 }
@@ -609,52 +643,70 @@ int check_http(void) {
609 643
610 /* attach additional headers supplied by the user */ 644 /* attach additional headers supplied by the user */
611 /* optionally send any other header tag */ 645 /* optionally send any other header tag */
612 if (http_opt_headers_count) { 646 if (config.http_opt_headers_count) {
613 for (i = 0; i < http_opt_headers_count; i++) { 647 for (size_t i = 0; i < config.http_opt_headers_count; i++) {
614 header_list = curl_slist_append(header_list, http_opt_headers[i]); 648 header_list = curl_slist_append(header_list, config.http_opt_headers[i]);
615 } 649 }
616 /* 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 */
618 /* free(http_opt_headers); */
619 } 650 }
620 651
621 /* set HTTP headers */ 652 /* set HTTP headers */
622 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER"); 653 handle_curl_option_return_code(
654 curl_easy_setopt(global_state.curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER");
623 655
624#ifdef LIBCURL_FEATURE_SSL 656#ifdef LIBCURL_FEATURE_SSL
625 657
626 /* set SSL version, warn about insecure or unsupported versions */ 658 /* set SSL version, warn about insecure or unsupported versions */
627 if (use_ssl) { 659 if (workingState.use_ssl) {
628 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 660 handle_curl_option_return_code(
661 curl_easy_setopt(global_state.curl, CURLOPT_SSLVERSION, config.ssl_version),
662 "CURLOPT_SSLVERSION");
629 } 663 }
630 664
631 /* client certificate and key to present to server (SSL) */ 665 /* client certificate and key to present to server (SSL) */
632 if (client_cert) 666 if (config.client_cert) {
633 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT"); 667 handle_curl_option_return_code(
634 if (client_privkey) 668 curl_easy_setopt(global_state.curl, CURLOPT_SSLCERT, config.client_cert),
635 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY"); 669 "CURLOPT_SSLCERT");
636 if (ca_cert) { 670 }
637 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); 671
638 } 672 if (config.client_privkey) {
639 if (ca_cert || verify_peer_and_host) { 673 handle_curl_option_return_code(
674 curl_easy_setopt(global_state.curl, CURLOPT_SSLKEY, config.client_privkey),
675 "CURLOPT_SSLKEY");
676 }
677
678 if (config.ca_cert) {
679 handle_curl_option_return_code(
680 curl_easy_setopt(global_state.curl, CURLOPT_CAINFO, config.ca_cert), "CURLOPT_CAINFO");
681 }
682
683 if (config.ca_cert || config.verify_peer_and_host) {
640 /* per default if we have a CA verify both the peer and the 684 /* per default if we have a CA verify both the peer and the
641 * hostname in the certificate, can be switched off later */ 685 * 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"); 686 handle_curl_option_return_code(
643 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST"); 687 curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 1),
688 "CURLOPT_SSL_VERIFYPEER");
689 handle_curl_option_return_code(
690 curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 2),
691 "CURLOPT_SSL_VERIFYHOST");
644 } else { 692 } else {
645 /* backward-compatible behaviour, be tolerant in checks 693 /* backward-compatible behaviour, be tolerant in checks
646 * TODO: depending on more options have aspects we want 694 * TODO: depending on more options have aspects we want
647 * to be less tolerant about ssl verfications 695 * to be less tolerant about ssl verfications
648 */ 696 */
649 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); 697 handle_curl_option_return_code(
650 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); 698 curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 0),
699 "CURLOPT_SSL_VERIFYPEER");
700 handle_curl_option_return_code(
701 curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 0),
702 "CURLOPT_SSL_VERIFYHOST");
651 } 703 }
652 704
653 /* detect SSL library used by libcurl */ 705 /* detect SSL library used by libcurl */
654 ssl_library = curlhelp_get_ssl_library(); 706 curlhelp_ssl_library ssl_library = curlhelp_get_ssl_library();
655 707
656 /* try hard to get a stack of certificates to verify against */ 708 /* try hard to get a stack of certificates to verify against */
657 if (check_cert) { 709 if (config.check_cert) {
658# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) 710# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
659 /* inform curl to report back certificates */ 711 /* inform curl to report back certificates */
660 switch (ssl_library) { 712 switch (ssl_library) {
@@ -669,15 +721,19 @@ int check_http(void) {
669# endif /* USE_OPENSSL */ 721# endif /* USE_OPENSSL */
670 /* libcurl is built with OpenSSL, monitoring plugins, so falling 722 /* libcurl is built with OpenSSL, monitoring plugins, so falling
671 * back to manually extracting certificate information */ 723 * back to manually extracting certificate information */
672 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 724 handle_curl_option_return_code(
725 curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
673 break; 726 break;
674 727
675 case CURLHELP_SSL_LIBRARY_NSS: 728 case CURLHELP_SSL_LIBRARY_NSS:
676# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 729# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
677 /* NSS: support for CERTINFO is implemented since 7.34.0 */ 730 /* NSS: support for CERTINFO is implemented since 7.34.0 */
678 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 731 handle_curl_option_return_code(
732 curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
679# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 733# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
680 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", 734 die(STATE_CRITICAL,
735 "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
736 "'%s' is too old)\n",
681 curlhelp_get_ssl_library_string(ssl_library)); 737 curlhelp_get_ssl_library_string(ssl_library));
682# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 738# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
683 break; 739 break;
@@ -685,47 +741,68 @@ int check_http(void) {
685 case CURLHELP_SSL_LIBRARY_GNUTLS: 741 case CURLHELP_SSL_LIBRARY_GNUTLS:
686# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) 742# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
687 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */ 743 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
688 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 744 handle_curl_option_return_code(
745 curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
689# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 746# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
690 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", 747 die(STATE_CRITICAL,
748 "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library "
749 "'%s' is too old)\n",
691 curlhelp_get_ssl_library_string(ssl_library)); 750 curlhelp_get_ssl_library_string(ssl_library));
692# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 751# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
693 break; 752 break;
694 753
695 case CURLHELP_SSL_LIBRARY_UNKNOWN: 754 case CURLHELP_SSL_LIBRARY_UNKNOWN:
696 default: 755 default:
697 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", 756 die(STATE_CRITICAL,
757 "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must "
758 "implement first)\n",
698 curlhelp_get_ssl_library_string(ssl_library)); 759 curlhelp_get_ssl_library_string(ssl_library));
699 break; 760 break;
700 } 761 }
701# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 762# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
702 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */ 763 /* 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) 764 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL ||
765 ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) {
704 add_sslctx_verify_fun = true; 766 add_sslctx_verify_fun = true;
705 else 767 } else {
706 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl " 768 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no "
769 "CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl "
707 "too old and has no CURLOPT_CERTINFO)\n"); 770 "too old and has no CURLOPT_CERTINFO)\n");
771 }
708# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 772# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
709 } 773 }
710 774
711# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */ 775# if LIBCURL_VERSION_NUM >= \
776 MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
712 // ssl ctx function is not available with all ssl backends 777 // ssl ctx function is not available with all ssl backends
713 if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION) 778 if (curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) !=
714 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 779 CURLE_UNKNOWN_OPTION) {
780 handle_curl_option_return_code(
781 curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun),
782 "CURLOPT_SSL_CTX_FUNCTION");
783 }
715# endif 784# endif
716 785
717#endif /* LIBCURL_FEATURE_SSL */ 786#endif /* LIBCURL_FEATURE_SSL */
718 787
719 /* set default or user-given user agent identification */ 788 /* set default or user-given user agent identification */
720 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); 789 handle_curl_option_return_code(
790 curl_easy_setopt(global_state.curl, CURLOPT_USERAGENT, config.user_agent),
791 "CURLOPT_USERAGENT");
721 792
722 /* proxy-authentication */ 793 /* proxy-authentication */
723 if (strcmp(proxy_auth, "")) 794 if (strcmp(config.proxy_auth, "")) {
724 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD"); 795 handle_curl_option_return_code(
796 curl_easy_setopt(global_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth),
797 "CURLOPT_PROXYUSERPWD");
798 }
725 799
726 /* authentication */ 800 /* authentication */
727 if (strcmp(user_auth, "")) 801 if (strcmp(config.user_auth, "")) {
728 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD"); 802 handle_curl_option_return_code(
803 curl_easy_setopt(global_state.curl, CURLOPT_USERPWD, config.user_auth),
804 "CURLOPT_USERPWD");
805 }
729 806
730 /* TODO: parameter auth method, bitfield of following methods: 807 /* TODO: parameter auth method, bitfield of following methods:
731 * CURLAUTH_BASIC (default) 808 * CURLAUTH_BASIC (default)
@@ -739,25 +816,33 @@ int check_http(void) {
739 * CURLAUTH_ANYSAFE: most secure, without BASIC 816 * CURLAUTH_ANYSAFE: most secure, without BASIC
740 * or CURLAUTH_ANY: most secure, even BASIC if necessary 817 * or CURLAUTH_ANY: most secure, even BASIC if necessary
741 * 818 *
742 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH"); 819 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH,
820 * (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
743 */ 821 */
744 822
745 /* handle redirections */ 823 /* handle redirections */
746 if (onredirect == STATE_DEPENDENT) { 824 if (config.onredirect == STATE_DEPENDENT) {
747 if (followmethod == FOLLOW_LIBCURL) { 825 if (config.followmethod == FOLLOW_LIBCURL) {
748 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION"); 826 handle_curl_option_return_code(
827 curl_easy_setopt(global_state.curl, CURLOPT_FOLLOWLOCATION, 1),
828 "CURLOPT_FOLLOWLOCATION");
749 829
750 /* default -1 is infinite, not good, could lead to zombie plugins! 830 /* 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 831 Setting it to one bigger than maximal limit to handle errors nicely below
752 */ 832 */
753 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_depth + 1), "CURLOPT_MAXREDIRS"); 833 handle_curl_option_return_code(
834 curl_easy_setopt(global_state.curl, CURLOPT_MAXREDIRS, config.max_depth + 1),
835 "CURLOPT_MAXREDIRS");
754 836
755 /* for now allow only http and https (we are a http(s) check plugin in the end) */ 837 /* 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) 838#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
757 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), 839 handle_curl_option_return_code(
758 "CURLOPT_REDIR_PROTOCOLS_STR"); 840 curl_easy_setopt(global_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
841 "CURLOPT_REDIR_PROTOCOLS_STR");
759#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) 842#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
760 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), 843 handle_curl_option_return_code(curl_easy_setopt(global_state.curl,
844 CURLOPT_REDIR_PROTOCOLS,
845 CURLPROTO_HTTP | CURLPROTO_HTTPS),
761 "CURLOPT_REDIRECT_PROTOCOLS"); 846 "CURLOPT_REDIRECT_PROTOCOLS");
762#endif 847#endif
763 848
@@ -766,7 +851,8 @@ int check_http(void) {
766 CURLOPT_POSTREDIR: method switch 851 CURLOPT_POSTREDIR: method switch
767 CURLINFO_REDIRECT_URL: custom redirect option 852 CURLINFO_REDIRECT_URL: custom redirect option
768 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols 853 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
769 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size? 854 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range
855 option here is nice like for expected page size?
770 */ 856 */
771 } else { 857 } else {
772 /* old style redirection is handled below */ 858 /* old style redirection is handled below */
@@ -774,68 +860,96 @@ int check_http(void) {
774 } 860 }
775 861
776 /* no-body */ 862 /* no-body */
777 if (no_body) 863 if (workingState.no_body) {
778 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY"); 864 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_NOBODY, 1),
865 "CURLOPT_NOBODY");
866 }
779 867
780 /* IPv4 or IPv6 forced DNS resolution */ 868 /* IPv4 or IPv6 forced DNS resolution */
781 if (address_family == AF_UNSPEC) 869 if (config.sin_family == AF_UNSPEC) {
782 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), 870 handle_curl_option_return_code(
783 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); 871 curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
784 else if (address_family == AF_INET) 872 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
785 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), 873 } else if (config.sin_family == AF_INET) {
786 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); 874 handle_curl_option_return_code(
875 curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
876 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
877 }
787#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) 878#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
788 else if (address_family == AF_INET6) 879 else if (config.sin_family == AF_INET6) {
789 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), 880 handle_curl_option_return_code(
790 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); 881 curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
882 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
883 }
791#endif 884#endif
792 885
793 /* either send http POST data (any data, not only POST)*/ 886 /* either send http POST data (any data, not only POST)*/
794 if (!strcmp(http_method, "POST") || !strcmp(http_method, "PUT")) { 887 if (!strcmp(workingState.http_method, "POST") || !strcmp(workingState.http_method, "PUT")) {
795 /* set content of payload for POST and PUT */ 888 /* set content of payload for POST and PUT */
796 if (http_content_type) { 889 if (config.http_content_type) {
797 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type); 890 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s",
891 config.http_content_type);
798 header_list = curl_slist_append(header_list, http_header); 892 header_list = curl_slist_append(header_list, http_header);
799 } 893 }
800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string 894 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
801 * in case of no POST/PUT data */ 895 * in case of no POST/PUT data */
802 if (!http_post_data) 896 if (!workingState.http_post_data) {
803 http_post_data = ""; 897 workingState.http_post_data = "";
804 if (!strcmp(http_method, "POST")) { 898 }
899 if (!strcmp(workingState.http_method, "POST")) {
805 /* POST method, set payload with CURLOPT_POSTFIELDS */ 900 /* POST method, set payload with CURLOPT_POSTFIELDS */
806 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS"); 901 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POSTFIELDS,
807 } else if (!strcmp(http_method, "PUT")) { 902 workingState.http_post_data),
808 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), 903 "CURLOPT_POSTFIELDS");
809 "CURLOPT_READFUNCTION"); 904 } else if (!strcmp(workingState.http_method, "PUT")) {
810 if (curlhelp_initreadbuffer(&put_buf, http_post_data, strlen(http_post_data)) < 0) 905 handle_curl_option_return_code(
811 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); 906 curl_easy_setopt(global_state.curl, CURLOPT_READFUNCTION,
812 put_buf_initialized = true; 907 (curl_read_callback)curlhelp_buffer_read_callback),
813 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); 908 "CURLOPT_READFUNCTION");
814 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_INFILESIZE, (curl_off_t)strlen(http_post_data)), 909 if (curlhelp_initreadbuffer(&global_state.put_buf, workingState.http_post_data,
815 "CURLOPT_INFILESIZE"); 910 strlen(workingState.http_post_data)) < 0) {
911 die(STATE_UNKNOWN,
912 "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
913 }
914 global_state.put_buf_initialized = true;
915
916 handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_READDATA,
917 (void *)&global_state.put_buf),
918 "CURLOPT_READDATA");
919 handle_curl_option_return_code(
920 curl_easy_setopt(global_state.curl, CURLOPT_INFILESIZE,
921 (curl_off_t)strlen(workingState.http_post_data)),
922 "CURLOPT_INFILESIZE");
816 } 923 }
817 } 924 }
818 925
819 /* cookie handling */ 926 /* cookie handling */
820 if (cookie_jar_file != NULL) { 927 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 */ 928 /* enable reading cookies from a file, and if the filename is an empty string, only
822 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE"); 929 * enable the curl cookie engine */
823 /* now enable saving cookies to a file, but only if the filename is not an empty string, since writing it would fail */ 930 handle_curl_option_return_code(
824 if (*cookie_jar_file) 931 curl_easy_setopt(global_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file),
825 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR"); 932 "CURLOPT_COOKIEFILE");
933 /* now enable saving cookies to a file, but only if the filename is not an empty string,
934 * since writing it would fail */
935 if (*config.cookie_jar_file) {
936 handle_curl_option_return_code(
937 curl_easy_setopt(global_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file),
938 "CURLOPT_COOKIEJAR");
939 }
826 } 940 }
827 941
828 /* do the request */ 942 /* do the request */
829 res = curl_easy_perform(curl); 943 CURLcode res = curl_easy_perform(global_state.curl);
830 944
831 if (verbose >= 2 && http_post_data) 945 if (verbose >= 2 && workingState.http_post_data) {
832 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data); 946 printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data);
947 }
833 948
834 /* free header and server IP resolve lists, we don't need it anymore */ 949 /* free header and server IP resolve lists, we don't need it anymore */
835 curl_slist_free_all(header_list); 950 curl_slist_free_all(header_list);
836 header_list = NULL; 951 header_list = NULL;
837 curl_slist_free_all(server_ips); 952
838 server_ips = NULL;
839 if (host) { 953 if (host) {
840 curl_slist_free_all(host); 954 curl_slist_free_all(host);
841 host = NULL; 955 host = NULL;
@@ -843,44 +957,50 @@ int check_http(void) {
843 957
844 /* Curl errors, result in critical Nagios state */ 958 /* Curl errors, result in critical Nagios state */
845 if (res != CURLE_OK) { 959 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, 960 snprintf(msg, DEFAULT_BUFFER_SIZE,
847 res, errbuf[0] ? errbuf : curl_easy_strerror(res)); 961 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"),
962 workingState.serverPort, res, errbuf[0] ? errbuf : curl_easy_strerror(res));
848 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 963 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
849 } 964 }
850 965
966 mp_state_enum result_ssl = STATE_OK;
851 /* certificate checks */ 967 /* certificate checks */
852#ifdef LIBCURL_FEATURE_SSL 968#ifdef LIBCURL_FEATURE_SSL
853 if (use_ssl) { 969 if (workingState.use_ssl) {
854 if (check_cert) { 970 if (config.check_cert) {
855 if (is_openssl_callback) { 971 if (is_openssl_callback) {
856# ifdef USE_OPENSSL 972# ifdef USE_OPENSSL
857 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 973 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
858 * and we actually have OpenSSL in the monitoring tools 974 * and we actually have OpenSSL in the monitoring tools
859 */ 975 */
860 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 976 result_ssl = np_net_ssl_check_certificate(cert, config.days_till_exp_warn,
861 if (!continue_after_check_cert) { 977 config.days_till_exp_crit);
978 if (!config.continue_after_check_cert) {
862 return result_ssl; 979 return result_ssl;
863 } 980 }
864# else /* USE_OPENSSL */ 981# else /* USE_OPENSSL */
865 die(STATE_CRITICAL, 982 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL "
866 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n"); 983 "callback used and not linked against OpenSSL\n");
867# endif /* USE_OPENSSL */ 984# endif /* USE_OPENSSL */
868 } else { 985 } else {
869 int i;
870 struct curl_slist *slist; 986 struct curl_slist *slist;
871 987
988 cert_ptr_union cert_ptr = {0};
872 cert_ptr.to_info = NULL; 989 cert_ptr.to_info = NULL;
873 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info); 990 res = curl_easy_getinfo(global_state.curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
874 if (!res && cert_ptr.to_info) { 991 if (!res && cert_ptr.to_info) {
875# ifdef USE_OPENSSL 992# ifdef USE_OPENSSL
876 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing 993 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert
877 * We only check the first certificate and assume it's the one of the server 994 * parsing We only check the first certificate and assume it's the one of
995 * the server
878 */ 996 */
879 const char *raw_cert = NULL; 997 const char *raw_cert = NULL;
880 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { 998 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) { 999 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist;
882 if (verbose >= 2) 1000 slist = slist->next) {
1001 if (verbose >= 2) {
883 printf("%d ** %s\n", i, slist->data); 1002 printf("%d ** %s\n", i, slist->data);
1003 }
884 if (strncmp(slist->data, "Cert:", 5) == 0) { 1004 if (strncmp(slist->data, "Cert:", 5) == 0) {
885 raw_cert = &slist->data[5]; 1005 raw_cert = &slist->data[5];
886 goto GOT_FIRST_CERT; 1006 goto GOT_FIRST_CERT;
@@ -890,32 +1010,38 @@ int check_http(void) {
890 GOT_FIRST_CERT: 1010 GOT_FIRST_CERT:
891 if (!raw_cert) { 1011 if (!raw_cert) {
892 snprintf(msg, DEFAULT_BUFFER_SIZE, 1012 snprintf(msg, DEFAULT_BUFFER_SIZE,
893 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty")); 1013 _("Cannot retrieve certificates from CERTINFO information - "
1014 "certificate data was empty"));
894 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 1015 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
895 } 1016 }
896 BIO *cert_BIO = BIO_new(BIO_s_mem()); 1017 BIO *cert_BIO = BIO_new(BIO_s_mem());
897 BIO_write(cert_BIO, raw_cert, strlen(raw_cert)); 1018 BIO_write(cert_BIO, raw_cert, (int)strlen(raw_cert));
898 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL); 1019 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
899 if (!cert) { 1020 if (!cert) {
900 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot read certificate from CERTINFO information - BIO error")); 1021 snprintf(
1022 msg, DEFAULT_BUFFER_SIZE,
1023 _("Cannot read certificate from CERTINFO information - BIO error"));
901 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 1024 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
902 } 1025 }
903 BIO_free(cert_BIO); 1026 BIO_free(cert_BIO);
904 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 1027 result_ssl = np_net_ssl_check_certificate(cert, config.days_till_exp_warn,
905 if (!continue_after_check_cert) { 1028 config.days_till_exp_crit);
1029 if (!config.continue_after_check_cert) {
906 return result_ssl; 1030 return result_ssl;
907 } 1031 }
908# else /* USE_OPENSSL */ 1032# else /* USE_OPENSSL */
909 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal, 1033 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our
910 * so we use the libcurl CURLINFO data 1034 * disposal, so we use the libcurl CURLINFO data
911 */ 1035 */
912 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit); 1036 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn,
1037 days_till_exp_crit);
913 if (!continue_after_check_cert) { 1038 if (!continue_after_check_cert) {
914 return result_ssl; 1039 return result_ssl;
915 } 1040 }
916# endif /* USE_OPENSSL */ 1041# endif /* USE_OPENSSL */
917 } else { 1042 } else {
918 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), res, 1043 snprintf(msg, DEFAULT_BUFFER_SIZE,
1044 _("Cannot retrieve certificates - cURL returned %d - %s"), res,
919 curl_easy_strerror(res)); 1045 curl_easy_strerror(res));
920 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 1046 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
921 } 1047 }
@@ -927,87 +1053,133 @@ int check_http(void) {
927 /* we got the data and we executed the request in a given time, so we can append 1053 /* we got the data and we executed the request in a given time, so we can append
928 * performance data to the answer always 1054 * performance data to the answer always
929 */ 1055 */
930 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME"); 1056 double total_time;
931 page_len = get_content_length(&header_buf, &body_buf); 1057 handle_curl_option_return_code(
932 if (show_extended_perfdata) { 1058 curl_easy_getinfo(global_state.curl, CURLINFO_TOTAL_TIME, &total_time),
933 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME"); 1059 "CURLINFO_TOTAL_TIME");
934 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME"); 1060 size_t page_len = get_content_length(&global_state.header_buf, &global_state.body_buf);
935 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME"); 1061 char perfstring[DEFAULT_BUFFER_SIZE];
936 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), 1062 if (config.show_extended_perfdata) {
937 "CURLINFO_STARTTRANSFER_TIME"); 1063 double time_connect;
938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time), perfd_size(page_len), 1064 handle_curl_option_return_code(
939 perfd_time_connect(time_connect), use_ssl ? perfd_time_ssl(time_appconnect - time_connect) : "", 1065 curl_easy_getinfo(global_state.curl, CURLINFO_CONNECT_TIME, &time_connect),
940 perfd_time_headers(time_headers - time_appconnect), perfd_time_firstbyte(time_firstbyte - time_headers), 1066 "CURLINFO_CONNECT_TIME");
941 perfd_time_transfer(total_time - time_firstbyte)); 1067
1068 double time_appconnect;
1069 handle_curl_option_return_code(
1070 curl_easy_getinfo(global_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect),
1071 "CURLINFO_APPCONNECT_TIME");
1072
1073 double time_headers;
1074 handle_curl_option_return_code(
1075 curl_easy_getinfo(global_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers),
1076 "CURLINFO_PRETRANSFER_TIME");
1077
1078 double time_firstbyte;
1079 handle_curl_option_return_code(
1080 curl_easy_getinfo(global_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
1081 "CURLINFO_STARTTRANSFER_TIME");
1082
1083 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s",
1084 perfd_time(total_time, config.thlds, config.socket_timeout),
1085 perfd_size(page_len, config.min_page_len),
1086 perfd_time_connect(time_connect, config.socket_timeout),
1087 workingState.use_ssl
1088 ? perfd_time_ssl(time_appconnect - time_connect, config.socket_timeout)
1089 : "",
1090 perfd_time_headers(time_headers - time_appconnect, config.socket_timeout),
1091 perfd_time_firstbyte(time_firstbyte - time_headers, config.socket_timeout),
1092 perfd_time_transfer(total_time - time_firstbyte, config.socket_timeout));
942 } else { 1093 } else {
943 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time), perfd_size(page_len)); 1094 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s",
1095 perfd_time(total_time, config.thlds, config.socket_timeout),
1096 perfd_size(page_len, config.min_page_len));
944 } 1097 }
945 1098
946 /* return a CRITICAL status if we couldn't read any data */ 1099 /* return a CRITICAL status if we couldn't read any data */
947 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) 1100 if (strlen(global_state.header_buf.buf) == 0 && strlen(global_state.body_buf.buf) == 0) {
948 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); 1101 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
1102 }
949 1103
950 /* get status line of answer, check sanity of HTTP code */ 1104 /* get status line of answer, check sanity of HTTP code */
951 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) { 1105 if (curlhelp_parse_statusline(global_state.header_buf.buf, &global_state.status_line) < 0) {
952 snprintf(msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", total_time, perfstring); 1106 snprintf(msg, DEFAULT_BUFFER_SIZE,
953 /* we cannot know the major/minor version here for sure as we cannot parse the first line */ 1107 "Unparsable status line in %.3g seconds response time|%s\n", total_time,
954 die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg); 1108 perfstring);
1109 /* we cannot know the major/minor version here for sure as we cannot parse the first
1110 * line */
1111 die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", httpReturnCode, msg);
955 } 1112 }
956 status_line_initialized = true; 1113 global_state.status_line_initialized = true;
957 1114
958 /* get result code from cURL */ 1115 /* get result code from cURL */
959 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE"); 1116 handle_curl_option_return_code(
960 if (verbose >= 2) 1117 curl_easy_getinfo(global_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode),
961 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code); 1118 "CURLINFO_RESPONSE_CODE");
1119 if (verbose >= 2) {
1120 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", httpReturnCode);
1121 }
962 1122
963 /* print status line, header, body if verbose */ 1123 /* print status line, header, body if verbose */
964 if (verbose >= 2) { 1124 if (verbose >= 2) {
965 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (no_body ? " [[ skipped ]]" : body_buf.buf)); 1125 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", global_state.header_buf.buf,
1126 (workingState.no_body ? " [[ skipped ]]" : global_state.body_buf.buf));
966 } 1127 }
967 1128
968 /* make sure the status line matches the response we are looking for */ 1129 /* make sure the status line matches the response we are looking for */
969 if (!expected_statuscode(status_line.first_line, server_expect)) { 1130 if (!expected_statuscode(global_state.status_line.first_line, config.server_expect)) {
970 if (server_port == HTTP_PORT) 1131 if (workingState.serverPort == HTTP_PORT) {
971 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line); 1132 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"),
972 else 1133 global_state.status_line.first_line);
973 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port, 1134 } else {
974 status_line.first_line); 1135 snprintf(msg, DEFAULT_BUFFER_SIZE,
975 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : ""); 1136 _("Invalid HTTP response received from host on port %d: %s\n"),
976 } 1137 workingState.serverPort, global_state.status_line.first_line);
977 1138 }
978 if (server_expect_yn) { 1139 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "",
979 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect); 1140 config.show_body ? global_state.body_buf.buf : "");
980 if (verbose) 1141 }
1142
1143 mp_state_enum result = STATE_OK;
1144 if (config.server_expect_yn) {
1145 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "),
1146 config.server_expect);
1147 if (verbose) {
981 printf("%s\n", msg); 1148 printf("%s\n", msg);
1149 }
982 result = STATE_OK; 1150 result = STATE_OK;
983 } else { 1151 } else {
984 /* illegal return codes result in a critical state */ 1152 /* illegal return codes result in a critical state */
985 if (code >= 600 || code < 100) { 1153 if (httpReturnCode >= 600 || httpReturnCode < 100) {
986 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg); 1154 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"),
1155 global_state.status_line.http_code, global_state.status_line.msg);
987 /* server errors result in a critical state */ 1156 /* server errors result in a critical state */
988 } else if (code >= 500) { 1157 } else if (httpReturnCode >= 500) {
989 result = STATE_CRITICAL; 1158 result = STATE_CRITICAL;
990 /* client errors result in a warning state */ 1159 /* client errors result in a warning state */
991 } else if (code >= 400) { 1160 } else if (httpReturnCode >= 400) {
992 result = STATE_WARNING; 1161 result = STATE_WARNING;
993 /* check redirected page if specified */ 1162 /* check redirected page if specified */
994 } else if (code >= 300) { 1163 } else if (httpReturnCode >= 300) {
995 if (onredirect == STATE_DEPENDENT) { 1164 if (config.onredirect == STATE_DEPENDENT) {
996 if (followmethod == FOLLOW_LIBCURL) { 1165 if (config.followmethod == FOLLOW_LIBCURL) {
997 code = status_line.http_code; 1166 httpReturnCode = global_state.status_line.http_code;
998 } else { 1167 } else {
999 /* old check_http style redirection, if we come 1168 /* old check_http style redirection, if we come
1000 * back here, we are in the same status as with 1169 * back here, we are in the same status as with
1001 * the libcurl method 1170 * the libcurl method
1002 */ 1171 */
1003 redir(&header_buf); 1172 redir_wrapper redir_result =
1173 redir(&global_state.header_buf, config, redir_depth, workingState);
1174 check_http(config, redir_result.working_state, redir_result.redir_depth,
1175 header_list);
1004 } 1176 }
1005 } else { 1177 } else {
1006 /* this is a specific code in the command line to 1178 /* this is a specific code in the command line to
1007 * be returned when a redirection is encountered 1179 * be returned when a redirection is encountered
1008 */ 1180 */
1009 } 1181 }
1010 result = max_state_alt(onredirect, result); 1182 result = max_state_alt(config.onredirect, result);
1011 /* all other codes are considered ok */ 1183 /* all other codes are considered ok */
1012 } else { 1184 } else {
1013 result = STATE_OK; 1185 result = STATE_OK;
@@ -1015,32 +1187,40 @@ int check_http(void) {
1015 } 1187 }
1016 1188
1017 /* libcurl redirection internally, handle error states here */ 1189 /* libcurl redirection internally, handle error states here */
1018 if (followmethod == FOLLOW_LIBCURL) { 1190 if (config.followmethod == FOLLOW_LIBCURL) {
1019 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT"); 1191 handle_curl_option_return_code(
1020 if (verbose >= 2) 1192 curl_easy_getinfo(global_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth),
1193 "CURLINFO_REDIRECT_COUNT");
1194 if (verbose >= 2) {
1021 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); 1195 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1022 if (redir_depth > max_depth) { 1196 }
1023 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", max_depth); 1197 if (redir_depth > config.max_depth) {
1198 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl",
1199 config.max_depth);
1024 die(STATE_WARNING, "HTTP WARNING - %s", msg); 1200 die(STATE_WARNING, "HTTP WARNING - %s", msg);
1025 } 1201 }
1026 } 1202 }
1027 1203
1028 /* check status codes, set exit status accordingly */ 1204 /* check status codes, set exit status accordingly */
1029 if (status_line.http_code != code) { 1205 if (global_state.status_line.http_code != httpReturnCode) {
1030 die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"), 1206 die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1031 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code); 1207 string_statuscode(global_state.status_line.http_major,
1208 global_state.status_line.http_minor),
1209 global_state.status_line.http_code, global_state.status_line.msg, httpReturnCode);
1032 } 1210 }
1033 1211
1034 if (maximum_age >= 0) { 1212 if (config.maximum_age >= 0) {
1035 result = max_state_alt(check_document_dates(&header_buf, &msg), result); 1213 result = max_state_alt(
1214 check_document_dates(&global_state.header_buf, &msg, config.maximum_age), result);
1036 } 1215 }
1037 1216
1038 /* Page and Header content checks go here */ 1217 /* Page and Header content checks go here */
1039 1218
1040 if (strlen(header_expect)) { 1219 if (strlen(config.header_expect)) {
1041 if (!strstr(header_buf.buf, header_expect)) { 1220 if (!strstr(global_state.header_buf.buf, config.header_expect)) {
1042 1221
1043 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search)); 1222 char output_header_search[30] = "";
1223 strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search));
1044 1224
1045 if (output_header_search[sizeof(output_header_search) - 1] != '\0') { 1225 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1046 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4); 1226 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
@@ -1048,8 +1228,10 @@ int check_http(void) {
1048 1228
1049 char tmp[DEFAULT_BUFFER_SIZE]; 1229 char tmp[DEFAULT_BUFFER_SIZE];
1050 1230
1051 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search, 1231 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "),
1052 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1232 msg, output_header_search, workingState.use_ssl ? "https" : "http",
1233 workingState.host_name ? workingState.host_name : workingState.server_address,
1234 workingState.serverPort, workingState.server_url);
1053 1235
1054 strcpy(msg, tmp); 1236 strcpy(msg, tmp);
1055 1237
@@ -1057,10 +1239,11 @@ int check_http(void) {
1057 } 1239 }
1058 } 1240 }
1059 1241
1060 if (strlen(string_expect)) { 1242 if (strlen(config.string_expect)) {
1061 if (!strstr(body_buf.buf, string_expect)) { 1243 if (!strstr(global_state.body_buf.buf, config.string_expect)) {
1062 1244
1063 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search)); 1245 char output_string_search[30] = "";
1246 strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search));
1064 1247
1065 if (output_string_search[sizeof(output_string_search) - 1] != '\0') { 1248 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1066 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4); 1249 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
@@ -1068,8 +1251,10 @@ int check_http(void) {
1068 1251
1069 char tmp[DEFAULT_BUFFER_SIZE]; 1252 char tmp[DEFAULT_BUFFER_SIZE];
1070 1253
1071 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, 1254 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "),
1072 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1255 msg, output_string_search, workingState.use_ssl ? "https" : "http",
1256 workingState.host_name ? workingState.host_name : workingState.server_address,
1257 workingState.serverPort, workingState.server_url);
1073 1258
1074 strcpy(msg, tmp); 1259 strcpy(msg, tmp);
1075 1260
@@ -1077,13 +1262,17 @@ int check_http(void) {
1077 } 1262 }
1078 } 1263 }
1079 1264
1080 if (strlen(regexp)) { 1265 if (strlen(config.regexp)) {
1081 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0); 1266 regex_t preg;
1082 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) { 1267 regmatch_t pmatch[REGS];
1268 int errcode = regexec(&preg, global_state.body_buf.buf, REGS, pmatch, 0);
1269 if ((errcode == 0 && !config.invert_regex) ||
1270 (errcode == REG_NOMATCH && config.invert_regex)) {
1083 /* OK - No-op to avoid changing the logic around it */ 1271 /* OK - No-op to avoid changing the logic around it */
1084 result = max_state_alt(STATE_OK, result); 1272 result = max_state_alt(STATE_OK, result);
1085 } else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) { 1273 } else if ((errcode == REG_NOMATCH && !config.invert_regex) ||
1086 if (!invert_regex) { 1274 (errcode == 0 && config.invert_regex)) {
1275 if (!config.invert_regex) {
1087 char tmp[DEFAULT_BUFFER_SIZE]; 1276 char tmp[DEFAULT_BUFFER_SIZE];
1088 1277
1089 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1278 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
@@ -1095,7 +1284,7 @@ int check_http(void) {
1095 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1284 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1096 strcpy(msg, tmp); 1285 strcpy(msg, tmp);
1097 } 1286 }
1098 result = state_regex; 1287 result = config.state_regex;
1099 } else { 1288 } else {
1100 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1289 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1101 1290
@@ -1108,99 +1297,109 @@ int check_http(void) {
1108 } 1297 }
1109 1298
1110 /* make sure the page is of an appropriate size */ 1299 /* make sure the page is of an appropriate size */
1111 if ((max_page_len > 0) && (page_len > max_page_len)) { 1300 if ((config.max_page_len > 0) && (page_len > config.max_page_len)) {
1112 char tmp[DEFAULT_BUFFER_SIZE]; 1301 char tmp[DEFAULT_BUFFER_SIZE];
1113 1302
1114 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 1303 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %zu too large, "), msg, page_len);
1115 1304
1116 strcpy(msg, tmp); 1305 strcpy(msg, tmp);
1117 1306
1118 result = max_state_alt(STATE_WARNING, result); 1307 result = max_state_alt(STATE_WARNING, result);
1119 1308
1120 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1309 } else if ((config.min_page_len > 0) && (page_len < config.min_page_len)) {
1121 char tmp[DEFAULT_BUFFER_SIZE]; 1310 char tmp[DEFAULT_BUFFER_SIZE];
1122 1311
1123 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 1312 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %zu too small, "), msg, page_len);
1124 strcpy(msg, tmp); 1313 strcpy(msg, tmp);
1125 result = max_state_alt(STATE_WARNING, result); 1314 result = max_state_alt(STATE_WARNING, result);
1126 } 1315 }
1127 1316
1128 /* -w, -c: check warning and critical level */ 1317 /* -w, -c: check warning and critical level */
1129 result = max_state_alt(get_status(total_time, thlds), result); 1318 result = max_state_alt(get_status(total_time, config.thlds), result);
1130 1319
1131 /* Cut-off trailing characters */ 1320 /* Cut-off trailing characters */
1132 if (strlen(msg) >= 2) { 1321 if (strlen(msg) >= 2) {
1133 if (msg[strlen(msg) - 2] == ',') 1322 if (msg[strlen(msg) - 2] == ',') {
1134 msg[strlen(msg) - 2] = '\0'; 1323 msg[strlen(msg) - 2] = '\0';
1135 else 1324 } else {
1136 msg[strlen(msg) - 3] = '\0'; 1325 msg[strlen(msg) - 3] = '\0';
1326 }
1137 } 1327 }
1138 1328
1139 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 1329 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result),
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), 1330 * msg); */
1141 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, 1331 die((int)max_state_alt(result, result_ssl),
1142 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, (display_html ? "</A>" : ""), perfstring, (show_body ? body_buf.buf : ""), 1332 "HTTP %s: %s %d %s%s%s - %zu bytes in %.3f second response time %s|%s\n%s%s",
1143 (show_body ? "\n" : "")); 1333 state_text(result),
1334 string_statuscode(global_state.status_line.http_major, global_state.status_line.http_minor),
1335 global_state.status_line.http_code, global_state.status_line.msg,
1336 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time,
1337 (config.display_html ? "</A>" : ""), perfstring,
1338 (config.show_body ? global_state.body_buf.buf : ""), (config.show_body ? "\n" : ""));
1144 1339
1145 return max_state_alt(result, result_ssl); 1340 return max_state_alt(result, result_ssl);
1146} 1341}
1147 1342
1148int uri_strcmp(const UriTextRangeA range, const char *s) { 1343int uri_strcmp(const UriTextRangeA range, const char *stringToCompare) {
1149 if (!range.first) 1344 if (!range.first) {
1150 return -1; 1345 return -1;
1151 if ((size_t)(range.afterLast - range.first) < strlen(s)) 1346 }
1347 if ((size_t)(range.afterLast - range.first) < strlen(stringToCompare)) {
1152 return -1; 1348 return -1;
1153 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s))); 1349 }
1350 return strncmp(stringToCompare, range.first,
1351 min((size_t)(range.afterLast - range.first), strlen(stringToCompare)));
1154} 1352}
1155 1353
1156char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { 1354char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1157 if (!range.first) 1355 if (!range.first) {
1158 return "(null)"; 1356 return "(null)";
1357 }
1159 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first))); 1358 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'; 1359 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0';
1161 buf[range.afterLast - range.first] = '\0'; 1360 buf[range.afterLast - range.first] = '\0';
1162 return buf; 1361 return buf;
1163} 1362}
1164 1363
1165void redir(curlhelp_write_curlbuf *header_buf) { 1364redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config,
1166 char *location = NULL; 1365 int redir_depth, check_curl_working_state working_state) {
1167 curlhelp_statusline status_line; 1366 curlhelp_statusline status_line;
1168 struct phr_header headers[255]; 1367 struct phr_header headers[255];
1169 size_t nof_headers = 255;
1170 size_t msglen; 1368 size_t msglen;
1171 char buf[DEFAULT_BUFFER_SIZE]; 1369 size_t nof_headers = 255;
1172 char ipstr[INET_ADDR_MAX_SIZE]; 1370 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
1173 int new_port; 1371 &status_line.http_minor, &status_line.http_code, &status_line.msg,
1174 char *new_host; 1372 &msglen, headers, &nof_headers, 0);
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,
1178 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
1179 1373
1180 if (res == -1) { 1374 if (res == -1) {
1181 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 1375 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1182 } 1376 }
1183 1377
1184 location = get_header_value(headers, nof_headers, "location"); 1378 char *location = get_header_value(headers, nof_headers, "location");
1185 1379
1186 if (verbose >= 2) 1380 if (verbose >= 2) {
1187 printf(_("* Seen redirect location %s\n"), location); 1381 printf(_("* Seen redirect location %s\n"), location);
1382 }
1188 1383
1189 if (++redir_depth > max_depth) 1384 if (++redir_depth > config.max_depth) {
1190 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), max_depth, location, 1385 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"),
1191 (display_html ? "</A>" : "")); 1386 config.max_depth, location, (config.display_html ? "</A>" : ""));
1387 }
1192 1388
1193 UriParserStateA state; 1389 UriParserStateA state;
1194 UriUriA uri; 1390 UriUriA uri;
1195 state.uri = &uri; 1391 state.uri = &uri;
1196 if (uriParseUriA(&state, location) != URI_SUCCESS) { 1392 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1197 if (state.errorCode == URI_ERROR_SYNTAX) { 1393 if (state.errorCode == URI_ERROR_SYNTAX) {
1198 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location, (display_html ? "</A>" : "")); 1394 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"),
1395 location, (config.display_html ? "</A>" : ""));
1199 } else if (state.errorCode == URI_ERROR_MALLOC) { 1396 } else if (state.errorCode == URI_ERROR_MALLOC) {
1200 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1397 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1201 } 1398 }
1202 } 1399 }
1203 1400
1401 char ipstr[INET_ADDR_MAX_SIZE];
1402 char buf[DEFAULT_BUFFER_SIZE];
1204 if (verbose >= 2) { 1403 if (verbose >= 2) {
1205 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE)); 1404 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)); 1405 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
@@ -1215,9 +1414,9 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1215 } 1414 }
1216 if (uri.pathHead) { 1415 if (uri.pathHead) {
1217 printf(_("** path: ")); 1416 printf(_("** path: "));
1218 const UriPathSegmentA *p = uri.pathHead; 1417 for (UriPathSegmentA *path_segment = uri.pathHead; path_segment;
1219 for (; p; p = p->next) { 1418 path_segment = path_segment->next) {
1220 printf("/%s", uri_string(p->text, buf, DEFAULT_BUFFER_SIZE)); 1419 printf("/%s", uri_string(path_segment->text, buf, DEFAULT_BUFFER_SIZE));
1221 } 1420 }
1222 puts(""); 1421 puts("");
1223 } 1422 }
@@ -1230,99 +1429,115 @@ void redir(curlhelp_write_curlbuf *header_buf) {
1230 } 1429 }
1231 1430
1232 if (uri.scheme.first) { 1431 if (uri.scheme.first) {
1233 if (!uri_strcmp(uri.scheme, "https")) 1432 working_state.use_ssl = (bool)(!uri_strcmp(uri.scheme, "https"));
1234 use_ssl = true;
1235 else
1236 use_ssl = false;
1237 } 1433 }
1238 1434
1239 /* we do a sloppy test here only, because uriparser would have failed 1435 /* 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 1436 * above, if the port would be invalid, we just check for MAX_PORT
1241 */ 1437 */
1438 int new_port;
1242 if (uri.portText.first) { 1439 if (uri.portText.first) {
1243 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1440 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1244 } else { 1441 } else {
1245 new_port = HTTP_PORT; 1442 new_port = HTTP_PORT;
1246 if (use_ssl) 1443 if (working_state.use_ssl) {
1247 new_port = HTTPS_PORT; 1444 new_port = HTTPS_PORT;
1445 }
1446 }
1447 if (new_port > MAX_PORT) {
1448 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT,
1449 location, config.display_html ? "</A>" : "");
1248 } 1450 }
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 1451
1252 /* by RFC 7231 relative URLs in Location should be taken relative to 1452 /* 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 1453 * the original URL, so we try to form a new absolute URL here
1254 */ 1454 */
1455 char *new_host;
1255 if (!uri.scheme.first && !uri.hostText.first) { 1456 if (!uri.scheme.first && !uri.hostText.first) {
1256 new_host = strdup(host_name ? host_name : server_address); 1457 new_host = strdup(working_state.host_name ? working_state.host_name
1257 new_port = server_port; 1458 : working_state.server_address);
1258 if (use_ssl) 1459 new_port = working_state.serverPort;
1460 if (working_state.use_ssl) {
1259 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE); 1461 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1462 }
1260 } else { 1463 } else {
1261 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1464 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1262 } 1465 }
1263 1466
1264 /* compose new path */ 1467 /* compose new path */
1265 /* TODO: handle fragments and query part of URL */ 1468 /* TODO: handle fragments and query part of URL */
1266 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); 1469 char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1267 if (uri.pathHead) { 1470 if (uri.pathHead) {
1268 const UriPathSegmentA *p = uri.pathHead; 1471 for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment;
1269 for (; p; p = p->next) { 1472 pathSegment = pathSegment->next) {
1270 strncat(new_url, "/", DEFAULT_BUFFER_SIZE); 1473 strncat(new_url, "/", DEFAULT_BUFFER_SIZE);
1271 strncat(new_url, uri_string(p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE - 1); 1474 strncat(new_url, uri_string(pathSegment->text, buf, DEFAULT_BUFFER_SIZE),
1475 DEFAULT_BUFFER_SIZE - 1);
1272 } 1476 }
1273 } 1477 }
1274 1478
1275 if (server_port == new_port && !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && 1479 if (working_state.serverPort == new_port &&
1276 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, new_url)) 1480 !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1277 die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), use_ssl ? "https" : "http", 1481 (working_state.host_name &&
1278 new_host, new_port, new_url, (display_html ? "</A>" : "")); 1482 !strncmp(working_state.host_name, new_host, MAX_IPV4_HOSTLENGTH)) &&
1483 !strcmp(working_state.server_url, new_url)) {
1484 die(STATE_CRITICAL,
1485 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"),
1486 working_state.use_ssl ? "https" : "http", new_host, new_port, new_url,
1487 (config.display_html ? "</A>" : ""));
1488 }
1279 1489
1280 /* set new values for redirected request */ 1490 /* set new values for redirected request */
1281 1491
1282 if (!(followsticky & STICKY_HOST)) { 1492 if (!(config.followsticky & STICKY_HOST)) {
1283 free(server_address); 1493 free(working_state.server_address);
1284 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); 1494 working_state.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1285 } 1495 }
1286 if (!(followsticky & STICKY_PORT)) { 1496 if (!(config.followsticky & STICKY_PORT)) {
1287 server_port = (unsigned short)new_port; 1497 working_state.serverPort = (unsigned short)new_port;
1288 } 1498 }
1289 1499
1290 free(host_name); 1500 free(working_state.host_name);
1291 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); 1501 working_state.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1292 1502
1293 /* reset virtual port */ 1503 /* reset virtual port */
1294 virtual_port = server_port; 1504 working_state.virtualPort = working_state.serverPort;
1295 1505
1296 free(new_host); 1506 free(new_host);
1297 free(server_url); 1507 free(working_state.server_url);
1298 server_url = new_url; 1508 working_state.server_url = new_url;
1299 1509
1300 uriFreeUriMembersA(&uri); 1510 uriFreeUriMembersA(&uri);
1301 1511
1302 if (verbose) 1512 if (verbose) {
1303 printf(_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, 1513 printf(_("Redirection to %s://%s:%d%s\n"), working_state.use_ssl ? "https" : "http",
1304 server_url); 1514 working_state.host_name ? working_state.host_name : working_state.server_address,
1515 working_state.serverPort, working_state.server_url);
1516 }
1305 1517
1306 /* TODO: the hash component MUST be taken from the original URL and 1518 /* TODO: the hash component MUST be taken from the original URL and
1307 * attached to the URL in Location 1519 * attached to the URL in Location
1308 */ 1520 */
1309 1521
1310 cleanup(); 1522 cleanup();
1311 check_http(); 1523
1524 redir_wrapper result = {
1525 .redir_depth = redir_depth,
1526 .working_state = working_state,
1527 .error_code = OK,
1528 };
1529 return result;
1312} 1530}
1313 1531
1314/* check whether a file exists */ 1532/* check whether a file exists */
1315void test_file(char *path) { 1533void test_file(char *path) {
1316 if (access(path, R_OK) == 0) 1534 if (access(path, R_OK) == 0) {
1317 return; 1535 return;
1536 }
1318 usage2(_("file does not exist or is not readable"), path); 1537 usage2(_("file does not exist or is not readable"), path);
1319} 1538}
1320 1539
1321bool process_arguments(int argc, char **argv) { 1540check_curl_config_wrapper process_arguments(int argc, char **argv) {
1322 char *p;
1323 int c = 1;
1324 char *temp;
1325
1326 enum { 1541 enum {
1327 INVERT_REGEX = CHAR_MAX + 1, 1542 INVERT_REGEX = CHAR_MAX + 1,
1328 SNI_OPTION, 1543 SNI_OPTION,
@@ -1336,78 +1551,96 @@ bool process_arguments(int argc, char **argv) {
1336 STATE_REGEX 1551 STATE_REGEX
1337 }; 1552 };
1338 1553
1339 int option = 0; 1554 static struct option longopts[] = {
1340 int got_plus = 0; 1555 STD_LONG_OPTS,
1341 static struct option longopts[] = {STD_LONG_OPTS, 1556 {"link", no_argument, 0, 'L'},
1342 {"link", no_argument, 0, 'L'}, 1557 {"nohtml", no_argument, 0, 'n'},
1343 {"nohtml", no_argument, 0, 'n'}, 1558 {"ssl", optional_argument, 0, 'S'},
1344 {"ssl", optional_argument, 0, 'S'}, 1559 {"sni", no_argument, 0, SNI_OPTION},
1345 {"sni", no_argument, 0, SNI_OPTION}, 1560 {"post", required_argument, 0, 'P'},
1346 {"post", required_argument, 0, 'P'}, 1561 {"method", required_argument, 0, 'j'},
1347 {"method", required_argument, 0, 'j'}, 1562 {"IP-address", required_argument, 0, 'I'},
1348 {"IP-address", required_argument, 0, 'I'}, 1563 {"url", required_argument, 0, 'u'},
1349 {"url", required_argument, 0, 'u'}, 1564 {"port", required_argument, 0, 'p'},
1350 {"port", required_argument, 0, 'p'}, 1565 {"authorization", required_argument, 0, 'a'},
1351 {"authorization", required_argument, 0, 'a'}, 1566 {"proxy-authorization", required_argument, 0, 'b'},
1352 {"proxy-authorization", required_argument, 0, 'b'}, 1567 {"header-string", required_argument, 0, 'd'},
1353 {"header-string", required_argument, 0, 'd'}, 1568 {"string", required_argument, 0, 's'},
1354 {"string", required_argument, 0, 's'}, 1569 {"expect", required_argument, 0, 'e'},
1355 {"expect", required_argument, 0, 'e'}, 1570 {"regex", required_argument, 0, 'r'},
1356 {"regex", required_argument, 0, 'r'}, 1571 {"ereg", required_argument, 0, 'r'},
1357 {"ereg", required_argument, 0, 'r'}, 1572 {"eregi", required_argument, 0, 'R'},
1358 {"eregi", required_argument, 0, 'R'}, 1573 {"linespan", no_argument, 0, 'l'},
1359 {"linespan", no_argument, 0, 'l'}, 1574 {"onredirect", required_argument, 0, 'f'},
1360 {"onredirect", required_argument, 0, 'f'}, 1575 {"certificate", required_argument, 0, 'C'},
1361 {"certificate", required_argument, 0, 'C'}, 1576 {"client-cert", required_argument, 0, 'J'},
1362 {"client-cert", required_argument, 0, 'J'}, 1577 {"private-key", required_argument, 0, 'K'},
1363 {"private-key", required_argument, 0, 'K'}, 1578 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1364 {"ca-cert", required_argument, 0, CA_CERT_OPTION}, 1579 {"verify-cert", no_argument, 0, 'D'},
1365 {"verify-cert", no_argument, 0, 'D'}, 1580 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1366 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 1581 {"useragent", required_argument, 0, 'A'},
1367 {"useragent", required_argument, 0, 'A'}, 1582 {"header", required_argument, 0, 'k'},
1368 {"header", required_argument, 0, 'k'}, 1583 {"no-body", no_argument, 0, 'N'},
1369 {"no-body", no_argument, 0, 'N'}, 1584 {"max-age", required_argument, 0, 'M'},
1370 {"max-age", required_argument, 0, 'M'}, 1585 {"content-type", required_argument, 0, 'T'},
1371 {"content-type", required_argument, 0, 'T'}, 1586 {"pagesize", required_argument, 0, 'm'},
1372 {"pagesize", required_argument, 0, 'm'}, 1587 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1373 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 1588 {"state-regex", required_argument, 0, STATE_REGEX},
1374 {"state-regex", required_argument, 0, STATE_REGEX}, 1589 {"use-ipv4", no_argument, 0, '4'},
1375 {"use-ipv4", no_argument, 0, '4'}, 1590 {"use-ipv6", no_argument, 0, '6'},
1376 {"use-ipv6", no_argument, 0, '6'}, 1591 {"extended-perfdata", no_argument, 0, 'E'},
1377 {"extended-perfdata", no_argument, 0, 'E'}, 1592 {"show-body", no_argument, 0, 'B'},
1378 {"show-body", no_argument, 0, 'B'}, 1593 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1379 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 1594 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1380 {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, 1595 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1381 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, 1596 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1382 {"cookie-jar", required_argument, 0, COOKIE_JAR}, 1597 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1383 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 1598 {0, 0, 0, 0}};
1384 {0, 0, 0, 0}}; 1599
1385 1600 check_curl_config_wrapper result = {
1386 if (argc < 2) 1601 .errorcode = OK,
1387 return false; 1602 .config = check_curl_config_init(),
1603 };
1604
1605 if (argc < 2) {
1606 result.errorcode = ERROR;
1607 return result;
1608 }
1388 1609
1389 /* support check_http compatible arguments */ 1610 /* support check_http compatible arguments */
1390 for (c = 1; c < argc; c++) { 1611 for (int index = 1; index < argc; index++) {
1391 if (strcmp("-to", argv[c]) == 0) 1612 if (strcmp("-to", argv[index]) == 0) {
1392 strcpy(argv[c], "-t"); 1613 strcpy(argv[index], "-t");
1393 if (strcmp("-hn", argv[c]) == 0) 1614 }
1394 strcpy(argv[c], "-H"); 1615 if (strcmp("-hn", argv[index]) == 0) {
1395 if (strcmp("-wt", argv[c]) == 0) 1616 strcpy(argv[index], "-H");
1396 strcpy(argv[c], "-w"); 1617 }
1397 if (strcmp("-ct", argv[c]) == 0) 1618 if (strcmp("-wt", argv[index]) == 0) {
1398 strcpy(argv[c], "-c"); 1619 strcpy(argv[index], "-w");
1399 if (strcmp("-nohtml", argv[c]) == 0) 1620 }
1400 strcpy(argv[c], "-n"); 1621 if (strcmp("-ct", argv[index]) == 0) {
1401 } 1622 strcpy(argv[index], "-c");
1402 1623 }
1403 server_url = strdup(DEFAULT_SERVER_URL); 1624 if (strcmp("-nohtml", argv[index]) == 0) {
1404 1625 strcpy(argv[index], "-n");
1405 while (1) { 1626 }
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); 1627 }
1407 if (c == -1 || c == EOF || c == 1) 1628
1629 int option = 0;
1630 char *warning_thresholds = NULL;
1631 char *critical_thresholds = NULL;
1632 int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
1633 bool specify_port = false;
1634
1635 while (true) {
1636 int option_index = getopt_long(
1637 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",
1638 longopts, &option);
1639 if (option_index == -1 || option_index == EOF || option_index == 1) {
1408 break; 1640 break;
1641 }
1409 1642
1410 switch (c) { 1643 switch (option_index) {
1411 case 'h': 1644 case 'h':
1412 print_help(); 1645 print_help();
1413 exit(STATE_UNKNOWN); 1646 exit(STATE_UNKNOWN);
@@ -1421,10 +1654,11 @@ bool process_arguments(int argc, char **argv) {
1421 verbose++; 1654 verbose++;
1422 break; 1655 break;
1423 case 't': /* timeout period */ 1656 case 't': /* timeout period */
1424 if (!is_intnonneg(optarg)) 1657 if (!is_intnonneg(optarg)) {
1425 usage2(_("Timeout interval must be a positive integer"), optarg); 1658 usage2(_("Timeout interval must be a positive integer"), optarg);
1426 else 1659 } else {
1427 socket_timeout = (int)strtol(optarg, NULL, 10); 1660 result.config.socket_timeout = (int)strtol(optarg, NULL, 10);
1661 }
1428 break; 1662 break;
1429 case 'c': /* critical time threshold */ 1663 case 'c': /* critical time threshold */
1430 critical_thresholds = optarg; 1664 critical_thresholds = optarg;
@@ -1433,204 +1667,228 @@ bool process_arguments(int argc, char **argv) {
1433 warning_thresholds = optarg; 1667 warning_thresholds = optarg;
1434 break; 1668 break;
1435 case 'H': /* virtual host */ 1669 case 'H': /* virtual host */
1436 host_name = strdup(optarg); 1670 result.config.initial_config.host_name = strdup(optarg);
1437 if (host_name[0] == '[') { 1671 char *tmp_string;
1438 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */ 1672 size_t host_name_length;
1439 virtual_port = atoi(p + 2); 1673 if (result.config.initial_config.host_name[0] == '[') {
1674 if ((tmp_string = strstr(result.config.initial_config.host_name, "]:")) !=
1675 NULL) { /* [IPv6]:port */
1676 result.config.initial_config.virtualPort = atoi(tmp_string + 2);
1440 /* cut off the port */ 1677 /* cut off the port */
1441 host_name_length = strlen(host_name) - strlen(p) - 1; 1678 host_name_length =
1442 free(host_name); 1679 strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1;
1443 host_name = strndup(optarg, host_name_length); 1680 free(result.config.initial_config.host_name);
1681 result.config.initial_config.host_name = strndup(optarg, host_name_length);
1444 } 1682 }
1445 } else if ((p = strchr(host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */ 1683 } else if ((tmp_string = strchr(result.config.initial_config.host_name, ':')) != NULL &&
1446 virtual_port = atoi(p); 1684 strchr(++tmp_string, ':') == NULL) { /* IPv4:port or host:port */
1685 result.config.initial_config.virtualPort = atoi(tmp_string);
1447 /* cut off the port */ 1686 /* cut off the port */
1448 host_name_length = strlen(host_name) - strlen(p) - 1; 1687 host_name_length =
1449 free(host_name); 1688 strlen(result.config.initial_config.host_name) - strlen(tmp_string) - 1;
1450 host_name = strndup(optarg, host_name_length); 1689 free(result.config.initial_config.host_name);
1690 result.config.initial_config.host_name = strndup(optarg, host_name_length);
1451 } 1691 }
1452 break; 1692 break;
1453 case 'I': /* internet address */ 1693 case 'I': /* internet address */
1454 server_address = strdup(optarg); 1694 result.config.initial_config.server_address = strdup(optarg);
1455 break; 1695 break;
1456 case 'u': /* URL path */ 1696 case 'u': /* URL path */
1457 server_url = strdup(optarg); 1697 result.config.initial_config.server_url = strdup(optarg);
1458 break; 1698 break;
1459 case 'p': /* Server port */ 1699 case 'p': /* Server port */
1460 if (!is_intnonneg(optarg)) 1700 if (!is_intnonneg(optarg)) {
1461 usage2(_("Invalid port number, expecting a non-negative number"), optarg); 1701 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
1462 else { 1702 } else {
1463 if (strtol(optarg, NULL, 10) > MAX_PORT) 1703 if (strtol(optarg, NULL, 10) > MAX_PORT) {
1464 usage2(_("Invalid port number, supplied port number is too big"), optarg); 1704 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1465 server_port = (unsigned short)strtol(optarg, NULL, 10); 1705 }
1706 result.config.initial_config.serverPort = (unsigned short)strtol(optarg, NULL, 10);
1466 specify_port = true; 1707 specify_port = true;
1467 } 1708 }
1468 break; 1709 break;
1469 case 'a': /* authorization info */ 1710 case 'a': /* authorization info */
1470 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1); 1711 strncpy(result.config.user_auth, optarg, MAX_INPUT_BUFFER - 1);
1471 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1712 result.config.user_auth[MAX_INPUT_BUFFER - 1] = 0;
1472 break; 1713 break;
1473 case 'b': /* proxy-authorization info */ 1714 case 'b': /* proxy-authorization info */
1474 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1715 strncpy(result.config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1475 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1716 result.config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1476 break; 1717 break;
1477 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 1718 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1478 if (!http_post_data) 1719 if (!result.config.initial_config.http_post_data) {
1479 http_post_data = strdup(optarg); 1720 result.config.initial_config.http_post_data = strdup(optarg);
1480 if (!http_method) 1721 }
1481 http_method = strdup("POST"); 1722 if (!result.config.initial_config.http_method) {
1723 result.config.initial_config.http_method = strdup("POST");
1724 }
1482 break; 1725 break;
1483 case 'j': /* Set HTTP method */ 1726 case 'j': /* Set HTTP method */
1484 if (http_method) 1727 if (result.config.initial_config.http_method) {
1485 free(http_method); 1728 free(result.config.initial_config.http_method);
1486 http_method = strdup(optarg); 1729 }
1730 result.config.initial_config.http_method = strdup(optarg);
1487 break; 1731 break;
1488 case 'A': /* useragent */ 1732 case 'A': /* useragent */
1489 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE); 1733 strncpy(result.config.user_agent, optarg, DEFAULT_BUFFER_SIZE);
1490 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0'; 1734 result.config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1491 break; 1735 break;
1492 case 'k': /* Additional headers */ 1736 case 'k': /* Additional headers */
1493 if (http_opt_headers_count == 0) 1737 if (result.config.http_opt_headers_count == 0) {
1494 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count)); 1738 result.config.http_opt_headers =
1495 else 1739 malloc(sizeof(char *) * (++result.config.http_opt_headers_count));
1496 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count)); 1740 } else {
1497 http_opt_headers[http_opt_headers_count - 1] = optarg; 1741 result.config.http_opt_headers =
1742 realloc(result.config.http_opt_headers,
1743 sizeof(char *) * (++result.config.http_opt_headers_count));
1744 }
1745 result.config.http_opt_headers[result.config.http_opt_headers_count - 1] = optarg;
1498 break; 1746 break;
1499 case 'L': /* show html link */ 1747 case 'L': /* show html link */
1500 display_html = true; 1748 result.config.display_html = true;
1501 break; 1749 break;
1502 case 'n': /* do not show html link */ 1750 case 'n': /* do not show html link */
1503 display_html = false; 1751 result.config.display_html = false;
1504 break; 1752 break;
1505 case 'C': /* Check SSL cert validity */ 1753 case 'C': /* Check SSL cert validity */
1506#ifdef LIBCURL_FEATURE_SSL 1754#ifdef LIBCURL_FEATURE_SSL
1755 char *temp;
1507 if ((temp = strchr(optarg, ',')) != NULL) { 1756 if ((temp = strchr(optarg, ',')) != NULL) {
1508 *temp = '\0'; 1757 *temp = '\0';
1509 if (!is_intnonneg(optarg)) 1758 if (!is_intnonneg(optarg)) {
1510 usage2(_("Invalid certificate expiration period"), optarg); 1759 usage2(_("Invalid certificate expiration period"), optarg);
1511 days_till_exp_warn = atoi(optarg); 1760 }
1761 result.config.days_till_exp_warn = atoi(optarg);
1512 *temp = ','; 1762 *temp = ',';
1513 temp++; 1763 temp++;
1514 if (!is_intnonneg(temp)) 1764 if (!is_intnonneg(temp)) {
1515 usage2(_("Invalid certificate expiration period"), temp); 1765 usage2(_("Invalid certificate expiration period"), temp);
1516 days_till_exp_crit = atoi(temp); 1766 }
1767 result.config.days_till_exp_crit = atoi(temp);
1517 } else { 1768 } else {
1518 days_till_exp_crit = 0; 1769 result.config.days_till_exp_crit = 0;
1519 if (!is_intnonneg(optarg)) 1770 if (!is_intnonneg(optarg)) {
1520 usage2(_("Invalid certificate expiration period"), optarg); 1771 usage2(_("Invalid certificate expiration period"), optarg);
1521 days_till_exp_warn = atoi(optarg); 1772 }
1773 result.config.days_till_exp_warn = atoi(optarg);
1522 } 1774 }
1523 check_cert = true; 1775 result.config.check_cert = true;
1524 goto enable_ssl; 1776 goto enable_ssl;
1525#endif 1777#endif
1526 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 1778 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1527#ifdef HAVE_SSL 1779#ifdef HAVE_SSL
1528 continue_after_check_cert = true; 1780 result.config.continue_after_check_cert = true;
1529 break; 1781 break;
1530#endif 1782#endif
1531 case 'J': /* use client certificate */ 1783 case 'J': /* use client certificate */
1532#ifdef LIBCURL_FEATURE_SSL 1784#ifdef LIBCURL_FEATURE_SSL
1533 test_file(optarg); 1785 test_file(optarg);
1534 client_cert = optarg; 1786 result.config.client_cert = optarg;
1535 goto enable_ssl; 1787 goto enable_ssl;
1536#endif 1788#endif
1537 case 'K': /* use client private key */ 1789 case 'K': /* use client private key */
1538#ifdef LIBCURL_FEATURE_SSL 1790#ifdef LIBCURL_FEATURE_SSL
1539 test_file(optarg); 1791 test_file(optarg);
1540 client_privkey = optarg; 1792 result.config.client_privkey = optarg;
1541 goto enable_ssl; 1793 goto enable_ssl;
1542#endif 1794#endif
1543#ifdef LIBCURL_FEATURE_SSL 1795#ifdef LIBCURL_FEATURE_SSL
1544 case CA_CERT_OPTION: /* use CA chain file */ 1796 case CA_CERT_OPTION: /* use CA chain file */
1545 test_file(optarg); 1797 test_file(optarg);
1546 ca_cert = optarg; 1798 result.config.ca_cert = optarg;
1547 goto enable_ssl; 1799 goto enable_ssl;
1548#endif 1800#endif
1549#ifdef LIBCURL_FEATURE_SSL 1801#ifdef LIBCURL_FEATURE_SSL
1550 case 'D': /* verify peer certificate & host */ 1802 case 'D': /* verify peer certificate & host */
1551 verify_peer_and_host = true; 1803 result.config.verify_peer_and_host = true;
1552 break; 1804 break;
1553#endif 1805#endif
1554 case 'S': /* use SSL */ 1806 case 'S': /* use SSL */
1555#ifdef LIBCURL_FEATURE_SSL 1807#ifdef LIBCURL_FEATURE_SSL
1808 {
1556 enable_ssl: 1809 enable_ssl:
1557 use_ssl = true; 1810 bool got_plus = false;
1811 result.config.initial_config.use_ssl = true;
1558 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1812 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1559 * Only set if it's non-zero. This helps when we include multiple 1813 * Only set if it's non-zero. This helps when we include multiple
1560 * parameters, like -S and -C combinations */ 1814 * parameters, like -S and -C combinations */
1561 ssl_version = CURL_SSLVERSION_DEFAULT; 1815 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1562 if (c == 'S' && optarg != NULL) { 1816 if (option_index == 'S' && optarg != NULL) {
1563 char *plus_ptr = strchr(optarg, '+'); 1817 char *plus_ptr = strchr(optarg, '+');
1564 if (plus_ptr) { 1818 if (plus_ptr) {
1565 got_plus = 1; 1819 got_plus = true;
1566 *plus_ptr = '\0'; 1820 *plus_ptr = '\0';
1567 } 1821 }
1568 1822
1569 if (optarg[0] == '2') 1823 if (optarg[0] == '2') {
1570 ssl_version = CURL_SSLVERSION_SSLv2; 1824 result.config.ssl_version = CURL_SSLVERSION_SSLv2;
1571 else if (optarg[0] == '3') 1825 } else if (optarg[0] == '3') {
1572 ssl_version = CURL_SSLVERSION_SSLv3; 1826 result.config.ssl_version = CURL_SSLVERSION_SSLv3;
1573 else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) 1827 } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) {
1574# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1828# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1575 ssl_version = CURL_SSLVERSION_TLSv1_0; 1829 result.config.ssl_version = CURL_SSLVERSION_TLSv1_0;
1576# else 1830# else
1577 ssl_version = CURL_SSLVERSION_DEFAULT; 1831 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1578# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1832# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1579 else if (!strcmp(optarg, "1.1")) 1833 } else if (!strcmp(optarg, "1.1")) {
1580# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1834# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1581 ssl_version = CURL_SSLVERSION_TLSv1_1; 1835 result.config.ssl_version = CURL_SSLVERSION_TLSv1_1;
1582# else 1836# else
1583 ssl_version = CURL_SSLVERSION_DEFAULT; 1837 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1584# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1838# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1585 else if (!strcmp(optarg, "1.2")) 1839 } else if (!strcmp(optarg, "1.2")) {
1586# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1840# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1587 ssl_version = CURL_SSLVERSION_TLSv1_2; 1841 result.config.ssl_version = CURL_SSLVERSION_TLSv1_2;
1588# else 1842# else
1589 ssl_version = CURL_SSLVERSION_DEFAULT; 1843 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1590# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1844# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1591 else if (!strcmp(optarg, "1.3")) 1845 } else if (!strcmp(optarg, "1.3")) {
1592# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1846# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1593 ssl_version = CURL_SSLVERSION_TLSv1_3; 1847 result.config.ssl_version = CURL_SSLVERSION_TLSv1_3;
1594# else 1848# else
1595 ssl_version = CURL_SSLVERSION_DEFAULT; 1849 result.config.ssl_version = CURL_SSLVERSION_DEFAULT;
1596# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ 1850# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1597 else 1851 } else {
1598 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)")); 1852 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 "
1853 "(with optional '+' suffix)"));
1854 }
1599 } 1855 }
1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) 1856# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1601 if (got_plus) { 1857 if (got_plus) {
1602 switch (ssl_version) { 1858 switch (result.config.ssl_version) {
1603 case CURL_SSLVERSION_TLSv1_3: 1859 case CURL_SSLVERSION_TLSv1_3:
1604 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1860 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1605 break; 1861 break;
1606 case CURL_SSLVERSION_TLSv1_2: 1862 case CURL_SSLVERSION_TLSv1_2:
1607 case CURL_SSLVERSION_TLSv1_1: 1863 case CURL_SSLVERSION_TLSv1_1:
1608 case CURL_SSLVERSION_TLSv1_0: 1864 case CURL_SSLVERSION_TLSv1_0:
1609 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; 1865 result.config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1610 break; 1866 break;
1611 } 1867 }
1612 } else { 1868 } else {
1613 switch (ssl_version) { 1869 switch (result.config.ssl_version) {
1614 case CURL_SSLVERSION_TLSv1_3: 1870 case CURL_SSLVERSION_TLSv1_3:
1615 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1871 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1616 break; 1872 break;
1617 case CURL_SSLVERSION_TLSv1_2: 1873 case CURL_SSLVERSION_TLSv1_2:
1618 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; 1874 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1619 break; 1875 break;
1620 case CURL_SSLVERSION_TLSv1_1: 1876 case CURL_SSLVERSION_TLSv1_1:
1621 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; 1877 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1622 break; 1878 break;
1623 case CURL_SSLVERSION_TLSv1_0: 1879 case CURL_SSLVERSION_TLSv1_0:
1624 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; 1880 result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1625 break; 1881 break;
1626 } 1882 }
1627 } 1883 }
1628# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1884# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1629 if (verbose >= 2) 1885 if (verbose >= 2) {
1630 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1886 printf(_("* Set SSL/TLS version to %d\n"), result.config.ssl_version);
1631 if (!specify_port) 1887 }
1632 server_port = HTTPS_PORT; 1888 if (!specify_port) {
1633 break; 1889 result.config.initial_config.serverPort = HTTPS_PORT;
1890 }
1891 } break;
1634#else /* LIBCURL_FEATURE_SSL */ 1892#else /* LIBCURL_FEATURE_SSL */
1635 /* -C -J and -K fall through to here without SSL */ 1893 /* -C -J and -K fall through to here without SSL */
1636 usage4(_("Invalid option - SSL is not available")); 1894 usage4(_("Invalid option - SSL is not available"));
@@ -1640,51 +1898,61 @@ bool process_arguments(int argc, char **argv) {
1640 break; 1898 break;
1641#endif /* LIBCURL_FEATURE_SSL */ 1899#endif /* LIBCURL_FEATURE_SSL */
1642 case MAX_REDIRS_OPTION: 1900 case MAX_REDIRS_OPTION:
1643 if (!is_intnonneg(optarg)) 1901 if (!is_intnonneg(optarg)) {
1644 usage2(_("Invalid max_redirs count"), optarg); 1902 usage2(_("Invalid max_redirs count"), optarg);
1645 else { 1903 } else {
1646 max_depth = atoi(optarg); 1904 result.config.max_depth = atoi(optarg);
1647 } 1905 }
1648 break; 1906 break;
1649 case 'f': /* onredirect */ 1907 case 'f': /* onredirect */
1650 if (!strcmp(optarg, "ok")) 1908 if (!strcmp(optarg, "ok")) {
1651 onredirect = STATE_OK; 1909 result.config.onredirect = STATE_OK;
1652 else if (!strcmp(optarg, "warning")) 1910 } else if (!strcmp(optarg, "warning")) {
1653 onredirect = STATE_WARNING; 1911 result.config.onredirect = STATE_WARNING;
1654 else if (!strcmp(optarg, "critical")) 1912 } else if (!strcmp(optarg, "critical")) {
1655 onredirect = STATE_CRITICAL; 1913 result.config.onredirect = STATE_CRITICAL;
1656 else if (!strcmp(optarg, "unknown")) 1914 } else if (!strcmp(optarg, "unknown")) {
1657 onredirect = STATE_UNKNOWN; 1915 result.config.onredirect = STATE_UNKNOWN;
1658 else if (!strcmp(optarg, "follow")) 1916 } else if (!strcmp(optarg, "follow")) {
1659 onredirect = STATE_DEPENDENT; 1917 result.config.onredirect = STATE_DEPENDENT;
1660 else if (!strcmp(optarg, "stickyport")) 1918 } else if (!strcmp(optarg, "stickyport")) {
1661 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT; 1919 result.config.onredirect = STATE_DEPENDENT,
1662 else if (!strcmp(optarg, "sticky")) 1920 result.config.followmethod = FOLLOW_HTTP_CURL,
1663 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1921 result.config.followsticky = STICKY_HOST | STICKY_PORT;
1664 else if (!strcmp(optarg, "follow")) 1922 } else if (!strcmp(optarg, "sticky")) {
1665 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1923 result.config.onredirect = STATE_DEPENDENT,
1666 else if (!strcmp(optarg, "curl")) 1924 result.config.followmethod = FOLLOW_HTTP_CURL,
1667 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1925 result.config.followsticky = STICKY_HOST;
1668 else 1926 } else if (!strcmp(optarg, "follow")) {
1927 result.config.onredirect = STATE_DEPENDENT,
1928 result.config.followmethod = FOLLOW_HTTP_CURL,
1929 result.config.followsticky = STICKY_NONE;
1930 } else if (!strcmp(optarg, "curl")) {
1931 result.config.onredirect = STATE_DEPENDENT,
1932 result.config.followmethod = FOLLOW_LIBCURL;
1933 } else {
1669 usage2(_("Invalid onredirect option"), optarg); 1934 usage2(_("Invalid onredirect option"), optarg);
1670 if (verbose >= 2) 1935 }
1671 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1936 if (verbose >= 2) {
1937 printf(_("* Following redirects set to %s\n"),
1938 state_text(result.config.onredirect));
1939 }
1672 break; 1940 break;
1673 case 'd': /* string or substring */ 1941 case 'd': /* string or substring */
1674 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1); 1942 strncpy(result.config.header_expect, optarg, MAX_INPUT_BUFFER - 1);
1675 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1943 result.config.header_expect[MAX_INPUT_BUFFER - 1] = 0;
1676 break; 1944 break;
1677 case 's': /* string or substring */ 1945 case 's': /* string or substring */
1678 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1); 1946 strncpy(result.config.string_expect, optarg, MAX_INPUT_BUFFER - 1);
1679 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1947 result.config.string_expect[MAX_INPUT_BUFFER - 1] = 0;
1680 break; 1948 break;
1681 case 'e': /* string or substring */ 1949 case 'e': /* string or substring */
1682 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1); 1950 strncpy(result.config.server_expect, optarg, MAX_INPUT_BUFFER - 1);
1683 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1951 result.config.server_expect[MAX_INPUT_BUFFER - 1] = 0;
1684 server_expect_yn = 1; 1952 result.config.server_expect_yn = true;
1685 break; 1953 break;
1686 case 'T': /* Content-type */ 1954 case 'T': /* Content-type */
1687 http_content_type = strdup(optarg); 1955 result.config.http_content_type = strdup(optarg);
1688 break; 1956 break;
1689 case 'l': /* linespan */ 1957 case 'l': /* linespan */
1690 cflags &= ~REG_NEWLINE; 1958 cflags &= ~REG_NEWLINE;
@@ -1693,32 +1961,35 @@ bool process_arguments(int argc, char **argv) {
1693 cflags |= REG_ICASE; 1961 cflags |= REG_ICASE;
1694 // fall through 1962 // fall through
1695 case 'r': /* regex */ 1963 case 'r': /* regex */
1696 strncpy(regexp, optarg, MAX_RE_SIZE - 1); 1964 strncpy(result.config.regexp, optarg, MAX_RE_SIZE - 1);
1697 regexp[MAX_RE_SIZE - 1] = 0; 1965 result.config.regexp[MAX_RE_SIZE - 1] = 0;
1698 errcode = regcomp(&preg, regexp, cflags); 1966 regex_t preg;
1967 int errcode = regcomp(&preg, result.config.regexp, cflags);
1699 if (errcode != 0) { 1968 if (errcode != 0) {
1700 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1969 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1701 printf(_("Could Not Compile Regular Expression: %s"), errbuf); 1970 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1702 return false; 1971 result.errorcode = ERROR;
1972 return result;
1703 } 1973 }
1704 break; 1974 break;
1705 case INVERT_REGEX: 1975 case INVERT_REGEX:
1706 invert_regex = true; 1976 result.config.invert_regex = true;
1707 break; 1977 break;
1708 case STATE_REGEX: 1978 case STATE_REGEX:
1709 if (!strcasecmp(optarg, "critical")) 1979 if (!strcasecmp(optarg, "critical")) {
1710 state_regex = STATE_CRITICAL; 1980 result.config.state_regex = STATE_CRITICAL;
1711 else if (!strcasecmp(optarg, "warning")) 1981 } else if (!strcasecmp(optarg, "warning")) {
1712 state_regex = STATE_WARNING; 1982 result.config.state_regex = STATE_WARNING;
1713 else 1983 } else {
1714 usage2(_("Invalid state-regex option"), optarg); 1984 usage2(_("Invalid state-regex option"), optarg);
1985 }
1715 break; 1986 break;
1716 case '4': 1987 case '4':
1717 address_family = AF_INET; 1988 result.config.sin_family = AF_INET;
1718 break; 1989 break;
1719 case '6': 1990 case '6':
1720#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) 1991#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
1721 address_family = AF_INET6; 1992 result.config.sin_family = AF_INET6;
1722#else 1993#else
1723 usage4(_("IPv6 support not available")); 1994 usage4(_("IPv6 support not available"));
1724#endif 1995#endif
@@ -1732,57 +2003,62 @@ bool process_arguments(int argc, char **argv) {
1732 if (tmp == NULL) { 2003 if (tmp == NULL) {
1733 printf("Bad format: try \"-m min:max\"\n"); 2004 printf("Bad format: try \"-m min:max\"\n");
1734 exit(STATE_WARNING); 2005 exit(STATE_WARNING);
1735 } else 2006 } else {
1736 min_page_len = atoi(tmp); 2007 result.config.min_page_len = atol(tmp);
2008 }
1737 2009
1738 tmp = strtok(NULL, ":"); 2010 tmp = strtok(NULL, ":");
1739 if (tmp == NULL) { 2011 if (tmp == NULL) {
1740 printf("Bad format: try \"-m min:max\"\n"); 2012 printf("Bad format: try \"-m min:max\"\n");
1741 exit(STATE_WARNING); 2013 exit(STATE_WARNING);
1742 } else 2014 } else {
1743 max_page_len = atoi(tmp); 2015 result.config.max_page_len = atol(tmp);
1744 } else 2016 }
1745 min_page_len = atoi(optarg); 2017 } else {
2018 result.config.min_page_len = atol(optarg);
2019 }
1746 break; 2020 break;
1747 } 2021 }
1748 case 'N': /* no-body */ 2022 case 'N': /* no-body */
1749 no_body = true; 2023 result.config.initial_config.no_body = true;
1750 break; 2024 break;
1751 case 'M': /* max-age */ 2025 case 'M': /* max-age */
1752 { 2026 {
1753 int L = strlen(optarg); 2027 size_t option_length = strlen(optarg);
1754 if (L && optarg[L - 1] == 'm') 2028 if (option_length && optarg[option_length - 1] == 'm') {
1755 maximum_age = atoi(optarg) * 60; 2029 result.config.maximum_age = atoi(optarg) * 60;
1756 else if (L && optarg[L - 1] == 'h') 2030 } else if (option_length && optarg[option_length - 1] == 'h') {
1757 maximum_age = atoi(optarg) * 60 * 60; 2031 result.config.maximum_age = atoi(optarg) * 60 * 60;
1758 else if (L && optarg[L - 1] == 'd') 2032 } else if (option_length && optarg[option_length - 1] == 'd') {
1759 maximum_age = atoi(optarg) * 60 * 60 * 24; 2033 result.config.maximum_age = atoi(optarg) * 60 * 60 * 24;
1760 else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1]))) 2034 } else if (option_length &&
1761 maximum_age = atoi(optarg); 2035 (optarg[option_length - 1] == 's' || isdigit(optarg[option_length - 1]))) {
1762 else { 2036 result.config.maximum_age = atoi(optarg);
2037 } else {
1763 fprintf(stderr, "unparsable max-age: %s\n", optarg); 2038 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1764 exit(STATE_WARNING); 2039 exit(STATE_WARNING);
1765 } 2040 }
1766 if (verbose >= 2) 2041 if (verbose >= 2) {
1767 printf("* Maximal age of document set to %d seconds\n", maximum_age); 2042 printf("* Maximal age of document set to %d seconds\n", result.config.maximum_age);
2043 }
1768 } break; 2044 } break;
1769 case 'E': /* show extended perfdata */ 2045 case 'E': /* show extended perfdata */
1770 show_extended_perfdata = true; 2046 result.config.show_extended_perfdata = true;
1771 break; 2047 break;
1772 case 'B': /* print body content after status line */ 2048 case 'B': /* print body content after status line */
1773 show_body = true; 2049 result.config.show_body = true;
1774 break; 2050 break;
1775 case HTTP_VERSION_OPTION: 2051 case HTTP_VERSION_OPTION:
1776 curl_http_version = CURL_HTTP_VERSION_NONE; 2052 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1777 if (strcmp(optarg, "1.0") == 0) { 2053 if (strcmp(optarg, "1.0") == 0) {
1778 curl_http_version = CURL_HTTP_VERSION_1_0; 2054 result.config.curl_http_version = CURL_HTTP_VERSION_1_0;
1779 } else if (strcmp(optarg, "1.1") == 0) { 2055 } else if (strcmp(optarg, "1.1") == 0) {
1780 curl_http_version = CURL_HTTP_VERSION_1_1; 2056 result.config.curl_http_version = CURL_HTTP_VERSION_1_1;
1781 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) { 2057 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1782#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) 2058#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1783 curl_http_version = CURL_HTTP_VERSION_2_0; 2059 result.config.curl_http_version = CURL_HTTP_VERSION_2_0;
1784#else 2060#else
1785 curl_http_version = CURL_HTTP_VERSION_NONE; 2061 result.config.curl_http_version = CURL_HTTP_VERSION_NONE;
1786#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 2062#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1787 } else { 2063 } else {
1788 fprintf(stderr, "unknown http-version parameter: %s\n", optarg); 2064 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
@@ -1790,13 +2066,13 @@ bool process_arguments(int argc, char **argv) {
1790 } 2066 }
1791 break; 2067 break;
1792 case AUTOMATIC_DECOMPRESSION: 2068 case AUTOMATIC_DECOMPRESSION:
1793 automatic_decompression = true; 2069 result.config.automatic_decompression = true;
1794 break; 2070 break;
1795 case COOKIE_JAR: 2071 case COOKIE_JAR:
1796 cookie_jar_file = optarg; 2072 result.config.cookie_jar_file = optarg;
1797 break; 2073 break;
1798 case HAPROXY_PROTOCOL: 2074 case HAPROXY_PROTOCOL:
1799 haproxy_protocol = true; 2075 result.config.haproxy_protocol = true;
1800 break; 2076 break;
1801 case '?': 2077 case '?':
1802 /* print short usage statement if args not parsable */ 2078 /* print short usage statement if args not parsable */
@@ -1805,73 +2081,93 @@ bool process_arguments(int argc, char **argv) {
1805 } 2081 }
1806 } 2082 }
1807 2083
1808 c = optind; 2084 int option_counter = optind;
1809 2085
1810 if (server_address == NULL && c < argc) 2086 if (result.config.initial_config.server_address == NULL && option_counter < argc) {
1811 server_address = strdup(argv[c++]); 2087 result.config.initial_config.server_address = strdup(argv[option_counter++]);
2088 }
1812 2089
1813 if (host_name == NULL && c < argc) 2090 if (result.config.initial_config.host_name == NULL && option_counter < argc) {
1814 host_name = strdup(argv[c++]); 2091 result.config.initial_config.host_name = strdup(argv[option_counter++]);
2092 }
1815 2093
1816 if (server_address == NULL) { 2094 if (result.config.initial_config.server_address == NULL) {
1817 if (host_name == NULL) 2095 if (result.config.initial_config.host_name == NULL) {
1818 usage4(_("You must specify a server address or host name")); 2096 usage4(_("You must specify a server address or host name"));
1819 else 2097 } else {
1820 server_address = strdup(host_name); 2098 result.config.initial_config.server_address =
2099 strdup(result.config.initial_config.host_name);
2100 }
1821 } 2101 }
1822 2102
1823 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 2103 set_thresholds(&result.config.thlds, warning_thresholds, critical_thresholds);
1824 2104
1825 if (critical_thresholds && thlds->critical->end > (double)socket_timeout) 2105 if (critical_thresholds &&
1826 socket_timeout = (int)thlds->critical->end + 1; 2106 result.config.thlds->critical->end > (double)result.config.socket_timeout) {
1827 if (verbose >= 2) 2107 result.config.socket_timeout = (int)result.config.thlds->critical->end + 1;
1828 printf("* Socket timeout set to %ld seconds\n", socket_timeout); 2108 }
2109 if (verbose >= 2) {
2110 printf("* Socket timeout set to %ld seconds\n", result.config.socket_timeout);
2111 }
1829 2112
1830 if (http_method == NULL) 2113 if (result.config.initial_config.http_method == NULL) {
1831 http_method = strdup("GET"); 2114 result.config.initial_config.http_method = strdup("GET");
2115 }
1832 2116
1833 if (client_cert && !client_privkey) 2117 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")); 2118 usage4(_("If you use a client certificate you must also specify a private key file"));
2119 }
1835 2120
1836 if (virtual_port == 0) 2121 if (result.config.initial_config.virtualPort == 0) {
1837 virtual_port = server_port; 2122 result.config.initial_config.virtualPort = result.config.initial_config.serverPort;
1838 else { 2123 } else {
1839 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT)) 2124 if ((result.config.initial_config.use_ssl &&
1840 if (!specify_port) 2125 result.config.initial_config.serverPort == HTTPS_PORT) ||
1841 server_port = virtual_port; 2126 (!result.config.initial_config.use_ssl &&
2127 result.config.initial_config.serverPort == HTTP_PORT)) {
2128 if (!specify_port) {
2129 result.config.initial_config.serverPort = result.config.initial_config.virtualPort;
2130 }
2131 }
1842 } 2132 }
1843 2133
1844 return true; 2134 return result;
1845} 2135}
1846 2136
1847char *perfd_time(double elapsed_time) { 2137char *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, 2138 return fperfdata("time", elapsed_time, "s", (thlds->warning != NULL),
1849 thlds->critical ? true : false, thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout); 2139 thlds->warning ? thlds->warning->end : 0, (thlds->critical != NULL),
2140 thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1850} 2141}
1851 2142
1852char *perfd_time_connect(double elapsed_time_connect) { 2143char *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); 2144 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true,
2145 socket_timeout);
1854} 2146}
1855 2147
1856char *perfd_time_ssl(double elapsed_time_ssl) { 2148char *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); 2149 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true,
2150 socket_timeout);
1858} 2151}
1859 2152
1860char *perfd_time_headers(double elapsed_time_headers) { 2153char *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); 2154 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true,
2155 socket_timeout);
1862} 2156}
1863 2157
1864char *perfd_time_firstbyte(double elapsed_time_firstbyte) { 2158char *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); 2159 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0,
2160 true, socket_timeout);
1866} 2161}
1867 2162
1868char *perfd_time_transfer(double elapsed_time_transfer) { 2163char *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); 2164 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0,
2165 true, socket_timeout);
1870} 2166}
1871 2167
1872char *perfd_size(int page_len) { 2168char *perfd_size(size_t 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, 2169 return perfdata("size", page_len, "B", (min_page_len > 0), min_page_len, (min_page_len > 0), 0,
1874 false, 0); 2170 true, 0, false, 0);
1875} 2171}
1876 2172
1877void print_help(void) { 2173void print_help(void) {
@@ -1885,7 +2181,8 @@ void print_help(void) {
1885 printf("%s\n", _("strings and regular expressions, check connection times, and report on")); 2181 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1886 printf("%s\n", _("certificate expiration times.")); 2182 printf("%s\n", _("certificate expiration times."));
1887 printf("\n"); 2183 printf("\n");
1888 printf("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); 2184 printf("%s\n",
2185 _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
1889 printf("%s\n", _("as possible.")); 2186 printf("%s\n", _("as possible."));
1890 2187
1891 printf("\n\n"); 2188 printf("\n\n");
@@ -1903,7 +2200,8 @@ void print_help(void) {
1903 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)")); 2200 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1904 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 2201 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1905 printf(" %s\n", "-I, --IP-address=ADDRESS"); 2202 printf(" %s\n", "-I, --IP-address=ADDRESS");
1906 printf(" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 2203 printf(" %s\n",
2204 _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1907 printf(" %s\n", "-p, --port=INTEGER"); 2205 printf(" %s\n", "-p, --port=INTEGER");
1908 printf(" %s", _("Port number (default: ")); 2206 printf(" %s", _("Port number (default: "));
1909 printf("%d)\n", HTTP_PORT); 2207 printf("%d)\n", HTTP_PORT);
@@ -1912,27 +2210,36 @@ void print_help(void) {
1912 2210
1913#ifdef LIBCURL_FEATURE_SSL 2211#ifdef LIBCURL_FEATURE_SSL
1914 printf(" %s\n", "-S, --ssl=VERSION[+]"); 2212 printf(" %s\n", "-S, --ssl=VERSION[+]");
1915 printf(" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 2213 printf(" %s\n",
2214 _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1916 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 2215 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
1917 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted.")); 2216 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are "
1918 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually disabled in libcurl")); 2217 "also accepted."));
2218 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually "
2219 "disabled in libcurl"));
1919 printf(" %s\n", "--sni"); 2220 printf(" %s\n", "--sni");
1920 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 2221 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
1921# if LIBCURL_VERSION_NUM >= 0x071801 2222# if LIBCURL_VERSION_NUM >= 0x071801
1922 printf(" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); 2223 printf(" %s\n",
2224 _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
1923 printf(" %s\n", _(" SNI only really works since TLSv1.0")); 2225 printf(" %s\n", _(" SNI only really works since TLSv1.0"));
1924# else 2226# else
1925 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); 2227 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
1926# endif 2228# endif
1927 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 2229 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1928 printf(" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443.")); 2230 printf(" %s\n",
1929 printf(" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the")); 2231 _("Minimum number of days a certificate has to be valid. Port defaults to 443."));
1930 printf(" %s\n", _("first agument's value. If there is a second argument and the certificate's")); 2232 printf(" %s\n",
2233 _("A STATE_WARNING is returned if the certificate has a validity less than the"));
2234 printf(" %s\n",
2235 _("first agument's value. If there is a second argument and the certificate's"));
1931 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned.")); 2236 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned."));
1932 printf(" %s\n", _("(When this option is used the URL is not checked by default. You can use")); 2237 printf(" %s\n",
2238 _("(When this option is used the URL is not checked by default. You can use"));
1933 printf(" %s\n", _(" --continue-after-certificate to override this behavior)")); 2239 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
1934 printf(" %s\n", "--continue-after-certificate"); 2240 printf(" %s\n", "--continue-after-certificate");
1935 printf(" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 2241 printf(" %s\n",
2242 _("Allows the HTTP check to continue after performing the certificate check."));
1936 printf(" %s\n", _("Does nothing unless -C is used.")); 2243 printf(" %s\n", _("Does nothing unless -C is used."));
1937 printf(" %s\n", "-J, --client-cert=FILE"); 2244 printf(" %s\n", "-J, --client-cert=FILE");
1938 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)")); 2245 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
@@ -1950,7 +2257,8 @@ void print_help(void) {
1950 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 2257 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
1951 printf(" %s", _("the first (status) line of the server response (default: ")); 2258 printf(" %s", _("the first (status) line of the server response (default: "));
1952 printf("%s)\n", HTTP_EXPECT); 2259 printf("%s)\n", HTTP_EXPECT);
1953 printf(" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 2260 printf(" %s\n",
2261 _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
1954 printf(" %s\n", "-d, --header-string=STRING"); 2262 printf(" %s\n", "-d, --header-string=STRING");
1955 printf(" %s\n", _("String to expect in the response headers")); 2263 printf(" %s\n", _("String to expect in the response headers"));
1956 printf(" %s\n", "-s, --string=STRING"); 2264 printf(" %s\n", "-s, --string=STRING");
@@ -1959,7 +2267,8 @@ void print_help(void) {
1959 printf(" %s\n", _("URL to GET or POST (default: /)")); 2267 printf(" %s\n", _("URL to GET or POST (default: /)"));
1960 printf(" %s\n", "-P, --post=STRING"); 2268 printf(" %s\n", "-P, --post=STRING");
1961 printf(" %s\n", _("URL decoded http POST data")); 2269 printf(" %s\n", _("URL decoded http POST data"));
1962 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)"); 2270 printf(" %s\n",
2271 "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
1963 printf(" %s\n", _("Set HTTP method.")); 2272 printf(" %s\n", _("Set HTTP method."));
1964 printf(" %s\n", "-N, --no-body"); 2273 printf(" %s\n", "-N, --no-body");
1965 printf(" %s\n", _("Don't wait for document body: stop reading after headers.")); 2274 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
@@ -1979,7 +2288,8 @@ void print_help(void) {
1979 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 2288 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1980 printf(" %s\n", _("can be changed with --state--regex)")); 2289 printf(" %s\n", _("can be changed with --state--regex)"));
1981 printf(" %s\n", "--state-regex=STATE"); 2290 printf(" %s\n", "--state-regex=STATE");
1982 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of \"critical\",\"warning\"")); 2291 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of "
2292 "\"critical\",\"warning\""));
1983 printf(" %s\n", "-a, --authorization=AUTH_PAIR"); 2293 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
1984 printf(" %s\n", _("Username:password on sites with basic authentication")); 2294 printf(" %s\n", _("Username:password on sites with basic authentication"));
1985 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 2295 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
@@ -1987,7 +2297,8 @@ void print_help(void) {
1987 printf(" %s\n", "-A, --useragent=STRING"); 2297 printf(" %s\n", "-A, --useragent=STRING");
1988 printf(" %s\n", _("String to be sent in http header as \"User Agent\"")); 2298 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
1989 printf(" %s\n", "-k, --header=STRING"); 2299 printf(" %s\n", "-k, --header=STRING");
1990 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 2300 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for "
2301 "additional headers"));
1991 printf(" %s\n", "-E, --extended-perfdata"); 2302 printf(" %s\n", "-E, --extended-perfdata");
1992 printf(" %s\n", _("Print additional performance data")); 2303 printf(" %s\n", _("Print additional performance data"));
1993 printf(" %s\n", "-B, --show-body"); 2304 printf(" %s\n", "-B, --show-body");
@@ -2003,20 +2314,25 @@ void print_help(void) {
2003 printf(" %s", _("Maximal number of redirects (default: ")); 2314 printf(" %s", _("Maximal number of redirects (default: "));
2004 printf("%d)\n", DEFAULT_MAX_REDIRS); 2315 printf("%d)\n", DEFAULT_MAX_REDIRS);
2005 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 2316 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2006 printf(" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 2317 printf(" %s\n",
2318 _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2007 printf("\n"); 2319 printf("\n");
2008 printf(" %s\n", "--http-version=VERSION"); 2320 printf(" %s\n", "--http-version=VERSION");
2009 printf(" %s\n", _("Connect via specific HTTP protocol.")); 2321 printf(" %s\n", _("Connect via specific HTTP protocol."));
2010 printf(" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); 2322 printf(" %s\n",
2323 _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
2011 printf(" %s\n", "--enable-automatic-decompression"); 2324 printf(" %s\n", "--enable-automatic-decompression");
2012 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); 2325 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2013 printf(" %s\n", "--haproxy-protocol"); 2326 printf(" %s\n", "--haproxy-protocol");
2014 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL).")); 2327 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
2015 printf(" %s\n", "--cookie-jar=FILE"); 2328 printf(" %s\n", "--cookie-jar=FILE");
2016 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested.")); 2329 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2017 printf(" %s\n", _("Specify an empty string as FILE to enable curl's cookie engine without saving")); 2330 printf(" %s\n",
2018 printf(" %s\n", _("the cookies to disk. Only enabling the engine without saving to disk requires")); 2331 _("Specify an empty string as FILE to enable curl's cookie engine without saving"));
2019 printf(" %s\n", _("handling multiple requests internally to curl, so use it with --onredirect=curl")); 2332 printf(" %s\n",
2333 _("the cookies to disk. Only enabling the engine without saving to disk requires"));
2334 printf(" %s\n",
2335 _("handling multiple requests internally to curl, so use it with --onredirect=curl"));
2020 printf("\n"); 2336 printf("\n");
2021 2337
2022 printf(UT_WARN_CRIT); 2338 printf(UT_WARN_CRIT);
@@ -2028,10 +2344,13 @@ void print_help(void) {
2028 printf("\n"); 2344 printf("\n");
2029 printf("%s\n", _("Notes:")); 2345 printf("%s\n", _("Notes:"));
2030 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 2346 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2031 printf(" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 2347 printf(" %s\n",
2032 printf(" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 2348 _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
2349 printf(" %s\n",
2350 _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
2033 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 2351 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
2034 printf(" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 2352 printf(" %s\n",
2353 _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
2035 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 2354 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2036 2355
2037#ifdef LIBCURL_FEATURE_SSL 2356#ifdef LIBCURL_FEATURE_SSL
@@ -2047,38 +2366,53 @@ void print_help(void) {
2047 printf("%s\n", _("Examples:")); 2366 printf("%s\n", _("Examples:"));
2048 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); 2367 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
2049 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 2368 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
2050 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2369 printf(" %s\n",
2051 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2370 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2371 printf(" %s\n",
2372 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2052 printf(" %s\n", _("a STATE_CRITICAL will be returned.")); 2373 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2053 printf("\n"); 2374 printf("\n");
2054 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14"); 2375 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14");
2055 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 2376 printf(" %s\n",
2056 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2377 _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
2057 printf(" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 2378 printf(" %s\n",
2379 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2380 printf(" %s\n",
2381 _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
2058 printf(" %s\n\n", _("the certificate is expired.")); 2382 printf(" %s\n\n", _("the certificate is expired."));
2059 printf("\n"); 2383 printf("\n");
2060 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14"); 2384 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14");
2061 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 2385 printf(" %s\n",
2062 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2386 _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
2387 printf(" %s\n",
2388 _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2063 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 2389 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
2064 printf(" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 2390 printf(" %s\n",
2391 _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2065#endif 2392#endif
2066 2393
2067 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 2394 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2068 printf(" %s\n", _("It is recommended to use an environment proxy like:")); 2395 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2069 printf(" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); 2396 printf(" %s\n",
2397 _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
2070 printf(" %s\n", _("legacy proxy requests in check_http style still work:")); 2398 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2071 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org")); 2399 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ "
2400 "-H www.monitoring-plugins.org"));
2072 2401
2073#ifdef LIBCURL_FEATURE_SSL 2402#ifdef LIBCURL_FEATURE_SSL
2074 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 2403 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
2075 printf(" %s\n", _("It is recommended to use an environment proxy like:")); 2404 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2076 printf(" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S")); 2405 printf(" %s\n",
2406 _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
2077 printf(" %s\n", _("legacy proxy requests in check_http style still work:")); 2407 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2078 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 2408 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j "
2079 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 2409 "CONNECT -H www.verisign.com "));
2080 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2410 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> "
2081 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2411 "-S(sl) -j CONNECT -H <webserver>"));
2412 printf(" %s\n",
2413 _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2414 printf(" %s\n",
2415 _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2082 printf(" %s\n", _("a STATE_CRITICAL will be returned.")); 2416 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2083 2417
2084#endif 2418#endif
@@ -2089,10 +2423,12 @@ void print_help(void) {
2089void print_usage(void) { 2423void print_usage(void) {
2090 printf("%s\n", _("Usage:")); 2424 printf("%s\n", _("Usage:"));
2091 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname); 2425 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
2092 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n"); 2426 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate "
2427 "file>] [-D]\n");
2093 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 2428 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2094 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n"); 2429 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2095 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 2430 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive "
2431 "regex>]\n");
2096 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 2432 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2097 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n"); 2433 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
2098 printf(" [-T <content-type>] [-j method]\n"); 2434 printf(" [-T <content-type>] [-j method]\n");
@@ -2112,9 +2448,10 @@ void print_curl_version(void) { printf("%s\n", curl_version()); }
2112int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) { 2448int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) {
2113 buf->bufsize = DEFAULT_BUFFER_SIZE; 2449 buf->bufsize = DEFAULT_BUFFER_SIZE;
2114 buf->buflen = 0; 2450 buf->buflen = 0;
2115 buf->buf = (char *)malloc((size_t)buf->bufsize); 2451 buf->buf = (char *)malloc(buf->bufsize);
2116 if (buf->buf == NULL) 2452 if (buf->buf == NULL) {
2117 return -1; 2453 return -1;
2454 }
2118 return 0; 2455 return 0;
2119} 2456}
2120 2457
@@ -2126,7 +2463,7 @@ size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, v
2126 buf->buf = (char *)realloc(buf->buf, buf->bufsize); 2463 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
2127 if (buf->buf == NULL) { 2464 if (buf->buf == NULL) {
2128 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno)); 2465 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2129 return -1; 2466 return 0;
2130 } 2467 }
2131 } 2468 }
2132 2469
@@ -2134,18 +2471,18 @@ size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, v
2134 buf->buflen += size * nmemb; 2471 buf->buflen += size * nmemb;
2135 buf->buf[buf->buflen] = '\0'; 2472 buf->buf[buf->buflen] = '\0';
2136 2473
2137 return (int)(size * nmemb); 2474 return size * nmemb;
2138} 2475}
2139 2476
2140size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) { 2477size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2141 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream; 2478 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2142 2479
2143 size_t n = min(nmemb * size, buf->buflen - buf->pos); 2480 size_t minimalSize = min(nmemb * size, buf->buflen - buf->pos);
2144 2481
2145 memcpy(buffer, buf->buf + buf->pos, n); 2482 memcpy(buffer, buf->buf + buf->pos, minimalSize);
2146 buf->pos += n; 2483 buf->pos += minimalSize;
2147 2484
2148 return (int)n; 2485 return minimalSize;
2149} 2486}
2150 2487
2151void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) { 2488void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
@@ -2155,9 +2492,10 @@ void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
2155 2492
2156int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) { 2493int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) {
2157 buf->buflen = datalen; 2494 buf->buflen = datalen;
2158 buf->buf = (char *)malloc((size_t)buf->buflen); 2495 buf->buf = (char *)malloc(buf->buflen);
2159 if (buf->buf == NULL) 2496 if (buf->buf == NULL) {
2160 return -1; 2497 return -1;
2498 }
2161 memcpy(buf->buf, data, datalen); 2499 memcpy(buf->buf, data, datalen);
2162 buf->pos = 0; 2500 buf->pos = 0;
2163 return 0; 2501 return 0;
@@ -2171,143 +2509,137 @@ void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2171/* TODO: where to put this, it's actually part of sstrings2 (logically)? 2509/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2172 */ 2510 */
2173const char *strrstr2(const char *haystack, const char *needle) { 2511const char *strrstr2(const char *haystack, const char *needle) {
2174 int counter; 2512 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; 2513 return NULL;
2514 }
2181 2515
2182 if (haystack[0] == '\0' || needle[0] == '\0') 2516 if (haystack[0] == '\0' || needle[0] == '\0') {
2183 return NULL; 2517 return NULL;
2518 }
2184 2519
2185 counter = 0; 2520 int counter = 0;
2186 prev_pos = NULL; 2521 const char *prev_pos = NULL;
2187 pos = haystack; 2522 const char *pos = haystack;
2188 len = strlen(needle); 2523 size_t len = strlen(needle);
2189 for (;;) { 2524 for (;;) {
2190 pos = strstr(pos, needle); 2525 pos = strstr(pos, needle);
2191 if (pos == NULL) { 2526 if (pos == NULL) {
2192 if (counter == 0) 2527 if (counter == 0) {
2193 return NULL; 2528 return NULL;
2529 }
2194 return prev_pos; 2530 return prev_pos;
2195 } 2531 }
2196 counter++; 2532 counter++;
2197 prev_pos = pos; 2533 prev_pos = pos;
2198 pos += len; 2534 pos += len;
2199 if (*pos == '\0') 2535 if (*pos == '\0') {
2200 return prev_pos; 2536 return prev_pos;
2537 }
2201 } 2538 }
2202} 2539}
2203 2540
2204int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) { 2541int 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 */ 2542 /* find last start of a new header */
2213 start = strrstr2(buf, "\r\nHTTP/"); 2543 const char *start = strrstr2(buf, "\r\nHTTP/");
2214 if (start != NULL) { 2544 if (start != NULL) {
2215 start += 2; 2545 start += 2;
2216 buf = start; 2546 buf = start;
2217 } 2547 }
2218 2548
2219 first_line_end = strstr(buf, "\r\n"); 2549 char *first_line_end = strstr(buf, "\r\n");
2220 if (first_line_end == NULL) 2550 if (first_line_end == NULL) {
2221 return -1; 2551 return -1;
2552 }
2222 2553
2223 first_line_len = (size_t)(first_line_end - buf); 2554 size_t first_line_len = (size_t)(first_line_end - buf);
2224 status_line->first_line = (char *)malloc(first_line_len + 1); 2555 status_line->first_line = (char *)malloc(first_line_len + 1);
2225 if (status_line->first_line == NULL) 2556 if (status_line->first_line == NULL) {
2226 return -1; 2557 return -1;
2558 }
2227 memcpy(status_line->first_line, buf, first_line_len); 2559 memcpy(status_line->first_line, buf, first_line_len);
2228 status_line->first_line[first_line_len] = '\0'; 2560 status_line->first_line[first_line_len] = '\0';
2229 first_line_buf = strdup(status_line->first_line); 2561 char *first_line_buf = strdup(status_line->first_line);
2230 2562
2231 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */ 2563 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2232 2564 char *temp_string = strtok(first_line_buf, "/");
2233 p = strtok(first_line_buf, "/"); 2565 if (temp_string == NULL) {
2234 if (p == NULL) {
2235 free(first_line_buf); 2566 free(first_line_buf);
2236 return -1; 2567 return -1;
2237 } 2568 }
2238 if (strcmp(p, "HTTP") != 0) { 2569 if (strcmp(temp_string, "HTTP") != 0) {
2239 free(first_line_buf); 2570 free(first_line_buf);
2240 return -1; 2571 return -1;
2241 } 2572 }
2242 2573
2243 p = strtok(NULL, " "); 2574 temp_string = strtok(NULL, " ");
2244 if (p == NULL) { 2575 if (temp_string == NULL) {
2245 free(first_line_buf); 2576 free(first_line_buf);
2246 return -1; 2577 return -1;
2247 } 2578 }
2248 if (strchr(p, '.') != NULL) { 2579
2580 char *temp_string_2;
2581 if (strchr(temp_string, '.') != NULL) {
2249 2582
2250 /* HTTP 1.x case */ 2583 /* HTTP 1.x case */
2251 strtok(p, "."); 2584 strtok(temp_string, ".");
2252 status_line->http_major = (int)strtol(p, &pp, 10); 2585 status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10);
2253 if (*pp != '\0') { 2586 if (*temp_string_2 != '\0') {
2254 free(first_line_buf); 2587 free(first_line_buf);
2255 return -1; 2588 return -1;
2256 } 2589 }
2257 strtok(NULL, " "); 2590 strtok(NULL, " ");
2258 status_line->http_minor = (int)strtol(p, &pp, 10); 2591 status_line->http_minor = (int)strtol(temp_string, &temp_string_2, 10);
2259 if (*pp != '\0') { 2592 if (*temp_string_2 != '\0') {
2260 free(first_line_buf); 2593 free(first_line_buf);
2261 return -1; 2594 return -1;
2262 } 2595 }
2263 p += 4; /* 1.x SP */ 2596 temp_string += 4; /* 1.x SP */
2264 } else { 2597 } else {
2265 /* HTTP 2 case */ 2598 /* HTTP 2 case */
2266 status_line->http_major = (int)strtol(p, &pp, 10); 2599 status_line->http_major = (int)strtol(temp_string, &temp_string_2, 10);
2267 status_line->http_minor = 0; 2600 status_line->http_minor = 0;
2268 p += 2; /* 2 SP */ 2601 temp_string += 2; /* 2 SP */
2269 } 2602 }
2270 2603
2271 /* status code: "404" or "404.1", then SP */ 2604 /* status code: "404" or "404.1", then SP */
2272 2605 temp_string = strtok(temp_string, " ");
2273 p = strtok(p, " "); 2606 if (temp_string == NULL) {
2274 if (p == NULL) {
2275 free(first_line_buf); 2607 free(first_line_buf);
2276 return -1; 2608 return -1;
2277 } 2609 }
2278 if (strchr(p, '.') != NULL) { 2610 if (strchr(temp_string, '.') != NULL) {
2279 char *ppp; 2611 char *ppp;
2280 ppp = strtok(p, "."); 2612 ppp = strtok(temp_string, ".");
2281 status_line->http_code = (int)strtol(ppp, &pp, 10); 2613 status_line->http_code = (int)strtol(ppp, &temp_string_2, 10);
2282 if (*pp != '\0') { 2614 if (*temp_string_2 != '\0') {
2283 free(first_line_buf); 2615 free(first_line_buf);
2284 return -1; 2616 return -1;
2285 } 2617 }
2286 ppp = strtok(NULL, ""); 2618 ppp = strtok(NULL, "");
2287 status_line->http_subcode = (int)strtol(ppp, &pp, 10); 2619 status_line->http_subcode = (int)strtol(ppp, &temp_string_2, 10);
2288 if (*pp != '\0') { 2620 if (*temp_string_2 != '\0') {
2289 free(first_line_buf); 2621 free(first_line_buf);
2290 return -1; 2622 return -1;
2291 } 2623 }
2292 p += 6; /* 400.1 SP */ 2624 temp_string += 6; /* 400.1 SP */
2293 } else { 2625 } else {
2294 status_line->http_code = (int)strtol(p, &pp, 10); 2626 status_line->http_code = (int)strtol(temp_string, &temp_string_2, 10);
2295 status_line->http_subcode = -1; 2627 status_line->http_subcode = -1;
2296 if (*pp != '\0') { 2628 if (*temp_string_2 != '\0') {
2297 free(first_line_buf); 2629 free(first_line_buf);
2298 return -1; 2630 return -1;
2299 } 2631 }
2300 p += 4; /* 400 SP */ 2632 temp_string += 4; /* 400 SP */
2301 } 2633 }
2302 2634
2303 /* Human readable message: "Not Found" CRLF */ 2635 /* Human readable message: "Not Found" CRLF */
2304 2636
2305 p = strtok(p, ""); 2637 temp_string = strtok(temp_string, "");
2306 if (p == NULL) { 2638 if (temp_string == NULL) {
2307 status_line->msg = ""; 2639 status_line->msg = "";
2308 return 0; 2640 return 0;
2309 } 2641 }
2310 status_line->msg = status_line->first_line + (p - first_line_buf); 2642 status_line->msg = status_line->first_line + (temp_string - first_line_buf);
2311 free(first_line_buf); 2643 free(first_line_buf);
2312 2644
2313 return 0; 2645 return 0;
@@ -2315,34 +2647,35 @@ int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line)
2315 2647
2316void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); } 2648void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
2317 2649
2318char *get_header_value(const struct phr_header *headers, const size_t nof_headers, const char *header) { 2650char *get_header_value(const struct phr_header *headers, const size_t nof_headers,
2651 const char *header) {
2319 for (size_t i = 0; i < nof_headers; i++) { 2652 for (size_t i = 0; i < nof_headers; i++) {
2320 if (headers[i].name != NULL && strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) { 2653 if (headers[i].name != NULL &&
2654 strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
2321 return strndup(headers[i].value, headers[i].value_len); 2655 return strndup(headers[i].value, headers[i].value_len);
2322 } 2656 }
2323 } 2657 }
2324 return NULL; 2658 return NULL;
2325} 2659}
2326 2660
2327int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) { 2661mp_state_enum check_document_dates(const curlhelp_write_curlbuf *header_buf,
2328 char *server_date = NULL; 2662 char (*msg)[DEFAULT_BUFFER_SIZE], int maximum_age) {
2329 char *document_date = NULL;
2330 int date_result = STATE_OK;
2331 curlhelp_statusline status_line;
2332 struct phr_header headers[255]; 2663 struct phr_header headers[255];
2333 size_t nof_headers = 255; 2664 size_t nof_headers = 255;
2665 curlhelp_statusline status_line;
2334 size_t msglen; 2666 size_t msglen;
2335 2667 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
2336 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor, 2668 &status_line.http_minor, &status_line.http_code, &status_line.msg,
2337 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0); 2669 &msglen, headers, &nof_headers, 0);
2338 2670
2339 if (res == -1) { 2671 if (res == -1) {
2340 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2672 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2341 } 2673 }
2342 2674
2343 server_date = get_header_value(headers, nof_headers, "date"); 2675 char *server_date = get_header_value(headers, nof_headers, "date");
2344 document_date = get_header_value(headers, nof_headers, "last-modified"); 2676 char *document_date = get_header_value(headers, nof_headers, "last-modified");
2345 2677
2678 mp_state_enum date_result = STATE_OK;
2346 if (!server_date || !*server_date) { 2679 if (!server_date || !*server_date) {
2347 char tmp[DEFAULT_BUFFER_SIZE]; 2680 char tmp[DEFAULT_BUFFER_SIZE];
2348 2681
@@ -2362,42 +2695,49 @@ int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[D
2362 } else { 2695 } else {
2363 time_t srv_data = curl_getdate(server_date, NULL); 2696 time_t srv_data = curl_getdate(server_date, NULL);
2364 time_t doc_data = curl_getdate(document_date, NULL); 2697 time_t doc_data = curl_getdate(document_date, NULL);
2365 if (verbose >= 2) 2698 if (verbose >= 2) {
2366 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 2699 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data,
2700 document_date, (int)doc_data);
2701 }
2367 if (srv_data <= 0) { 2702 if (srv_data <= 0) {
2368 char tmp[DEFAULT_BUFFER_SIZE]; 2703 char tmp[DEFAULT_BUFFER_SIZE];
2369 2704
2370 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 2705 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg,
2706 server_date);
2371 strcpy(*msg, tmp); 2707 strcpy(*msg, tmp);
2372 2708
2373 date_result = max_state_alt(STATE_CRITICAL, date_result); 2709 date_result = max_state_alt(STATE_CRITICAL, date_result);
2374 } else if (doc_data <= 0) { 2710 } else if (doc_data <= 0) {
2375 char tmp[DEFAULT_BUFFER_SIZE]; 2711 char tmp[DEFAULT_BUFFER_SIZE];
2376 2712
2377 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 2713 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg,
2714 document_date);
2378 strcpy(*msg, tmp); 2715 strcpy(*msg, tmp);
2379 2716
2380 date_result = max_state_alt(STATE_CRITICAL, date_result); 2717 date_result = max_state_alt(STATE_CRITICAL, date_result);
2381 } else if (doc_data > srv_data + 30) { 2718 } else if (doc_data > srv_data + 30) {
2382 char tmp[DEFAULT_BUFFER_SIZE]; 2719 char tmp[DEFAULT_BUFFER_SIZE];
2383 2720
2384 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 2721 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg,
2722 (int)doc_data - (int)srv_data);
2385 strcpy(*msg, tmp); 2723 strcpy(*msg, tmp);
2386 2724
2387 date_result = max_state_alt(STATE_CRITICAL, date_result); 2725 date_result = max_state_alt(STATE_CRITICAL, date_result);
2388 } else if (doc_data < srv_data - maximum_age) { 2726 } else if (doc_data < srv_data - maximum_age) {
2389 int n = (srv_data - doc_data); 2727 time_t last_modified = (srv_data - doc_data);
2390 if (n > (60 * 60 * 24 * 2)) { 2728 if (last_modified > (60 * 60 * 24 * 2)) {
2391 char tmp[DEFAULT_BUFFER_SIZE]; 2729 char tmp[DEFAULT_BUFFER_SIZE];
2392 2730
2393 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float)n) / (60 * 60 * 24)); 2731 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg,
2732 ((float)last_modified) / (60 * 60 * 24));
2394 strcpy(*msg, tmp); 2733 strcpy(*msg, tmp);
2395 2734
2396 date_result = max_state_alt(STATE_CRITICAL, date_result); 2735 date_result = max_state_alt(STATE_CRITICAL, date_result);
2397 } else { 2736 } else {
2398 char tmp[DEFAULT_BUFFER_SIZE]; 2737 char tmp[DEFAULT_BUFFER_SIZE];
2399 2738
2400 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 2739 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %ld:%02ld:%02ld ago, "), *msg,
2740 last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60);
2401 strcpy(*msg, tmp); 2741 strcpy(*msg, tmp);
2402 2742
2403 date_result = max_state_alt(STATE_CRITICAL, date_result); 2743 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2405,75 +2745,81 @@ int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[D
2405 } 2745 }
2406 } 2746 }
2407 2747
2408 if (server_date) 2748 if (server_date) {
2409 free(server_date); 2749 free(server_date);
2410 if (document_date) 2750 }
2751 if (document_date) {
2411 free(document_date); 2752 free(document_date);
2753 }
2412 2754
2413 return date_result; 2755 return date_result;
2414} 2756}
2415 2757
2416int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf) { 2758size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
2417 size_t content_length = 0; 2759 const curlhelp_write_curlbuf *body_buf) {
2418 struct phr_header headers[255]; 2760 struct phr_header headers[255];
2419 size_t nof_headers = 255; 2761 size_t nof_headers = 255;
2420 size_t msglen; 2762 size_t msglen;
2421 char *content_length_s = NULL;
2422 curlhelp_statusline status_line; 2763 curlhelp_statusline status_line;
2423 2764 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major,
2424 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor, 2765 &status_line.http_minor, &status_line.http_code, &status_line.msg,
2425 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0); 2766 &msglen, headers, &nof_headers, 0);
2426 2767
2427 if (res == -1) { 2768 if (res == -1) {
2428 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2769 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2429 } 2770 }
2430 2771
2431 content_length_s = get_header_value(headers, nof_headers, "content-length"); 2772 char *content_length_s = get_header_value(headers, nof_headers, "content-length");
2432 if (!content_length_s) { 2773 if (!content_length_s) {
2433 return header_buf->buflen + body_buf->buflen; 2774 return header_buf->buflen + body_buf->buflen;
2434 } 2775 }
2776
2435 content_length_s += strspn(content_length_s, " \t"); 2777 content_length_s += strspn(content_length_s, " \t");
2436 content_length = atoi(content_length_s); 2778 size_t content_length = atoi(content_length_s);
2437 if (content_length != body_buf->buflen) { 2779 if (content_length != body_buf->buflen) {
2438 /* TODO: should we warn if the actual and the reported body length don't match? */ 2780 /* TODO: should we warn if the actual and the reported body length don't match? */
2439 } 2781 }
2440 2782
2441 if (content_length_s) 2783 if (content_length_s) {
2442 free(content_length_s); 2784 free(content_length_s);
2785 }
2443 2786
2444 return header_buf->buflen + body_buf->buflen; 2787 return header_buf->buflen + body_buf->buflen;
2445} 2788}
2446 2789
2447/* TODO: is there a better way in libcurl to check for the SSL library? */ 2790/* TODO: is there a better way in libcurl to check for the SSL library? */
2448curlhelp_ssl_library curlhelp_get_ssl_library(void) { 2791curlhelp_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; 2792 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2453 2793
2454 version_data = curl_version_info(CURLVERSION_NOW); 2794 curl_version_info_data *version_data = curl_version_info(CURLVERSION_NOW);
2455 if (version_data == NULL) 2795 if (version_data == NULL) {
2456 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2796 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2797 }
2457 2798
2458 ssl_version = strdup(version_data->ssl_version); 2799 char *ssl_version = strdup(version_data->ssl_version);
2459 if (ssl_version == NULL) 2800 if (ssl_version == NULL) {
2460 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2801 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2802 }
2461 2803
2462 library = strtok(ssl_version, "/"); 2804 char *library = strtok(ssl_version, "/");
2463 if (library == NULL) 2805 if (library == NULL) {
2464 return CURLHELP_SSL_LIBRARY_UNKNOWN; 2806 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2807 }
2465 2808
2466 if (strcmp(library, "OpenSSL") == 0) 2809 if (strcmp(library, "OpenSSL") == 0) {
2467 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL; 2810 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2468 else if (strcmp(library, "LibreSSL") == 0) 2811 } else if (strcmp(library, "LibreSSL") == 0) {
2469 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL; 2812 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2470 else if (strcmp(library, "GnuTLS") == 0) 2813 } else if (strcmp(library, "GnuTLS") == 0) {
2471 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS; 2814 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2472 else if (strcmp(library, "NSS") == 0) 2815 } else if (strcmp(library, "NSS") == 0) {
2473 ssl_library = CURLHELP_SSL_LIBRARY_NSS; 2816 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2817 }
2474 2818
2475 if (verbose >= 2) 2819 if (verbose >= 2) {
2476 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library); 2820 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library,
2821 ssl_library);
2822 }
2477 2823
2478 free(ssl_version); 2824 free(ssl_version);
2479 2825
@@ -2499,19 +2845,18 @@ const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2499#ifdef LIBCURL_FEATURE_SSL 2845#ifdef LIBCURL_FEATURE_SSL
2500# ifndef USE_OPENSSL 2846# ifndef USE_OPENSSL
2501time_t parse_cert_date(const char *s) { 2847time_t parse_cert_date(const char *s) {
2502 struct tm tm; 2848 if (!s) {
2503 time_t date;
2504 char *res;
2505
2506 if (!s)
2507 return -1; 2849 return -1;
2850 }
2508 2851
2509 /* Jan 17 14:25:12 2020 GMT */ 2852 /* Jan 17 14:25:12 2020 GMT */
2510 res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm); 2853 struct tm tm;
2854 char *res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2511 /* Sep 11 12:00:00 2020 GMT */ 2855 /* Sep 11 12:00:00 2020 GMT */
2512 if (res == NULL) 2856 if (res == NULL) {
2513 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm); 2857 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2514 date = mktime(&tm); 2858 }
2859 time_t date = mktime(&tm);
2515 2860
2516 return date; 2861 return date;
2517} 2862}
@@ -2519,8 +2864,8 @@ time_t parse_cert_date(const char *s) {
2519/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to 2864/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2520 * OpenSSL could be this function 2865 * OpenSSL could be this function
2521 */ 2866 */
2522int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) { 2867int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn,
2523 int i; 2868 int days_till_exp_crit) {
2524 struct curl_slist *slist; 2869 struct curl_slist *slist;
2525 int cname_found = 0; 2870 int cname_found = 0;
2526 char *start_date_str = NULL; 2871 char *start_date_str = NULL;
@@ -2534,10 +2879,11 @@ int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_
2534 char timestamp[50] = ""; 2879 char timestamp[50] = "";
2535 int status = STATE_UNKNOWN; 2880 int status = STATE_UNKNOWN;
2536 2881
2537 if (verbose >= 2) 2882 if (verbose >= 2) {
2538 printf("**** REQUEST CERTIFICATES ****\n"); 2883 printf("**** REQUEST CERTIFICATES ****\n");
2884 }
2539 2885
2540 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 2886 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) { 2887 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2542 /* find first common name in subject, 2888 /* find first common name in subject,
2543 * TODO: check alternative subjects for 2889 * TODO: check alternative subjects for
@@ -2563,14 +2909,16 @@ int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_
2563 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) { 2909 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2564 goto HAVE_FIRST_CERT; 2910 goto HAVE_FIRST_CERT;
2565 } 2911 }
2566 if (verbose >= 2) 2912 if (verbose >= 2) {
2567 printf("%d ** %s\n", i, slist->data); 2913 printf("%d ** %s\n", i, slist->data);
2914 }
2568 } 2915 }
2569 } 2916 }
2570HAVE_FIRST_CERT: 2917HAVE_FIRST_CERT:
2571 2918
2572 if (verbose >= 2) 2919 if (verbose >= 2) {
2573 printf("**** REQUEST CERTIFICATES ****\n"); 2920 printf("**** REQUEST CERTIFICATES ****\n");
2921 }
2574 2922
2575 if (!cname_found) { 2923 if (!cname_found) {
2576 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject.")); 2924 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
@@ -2579,14 +2927,16 @@ HAVE_FIRST_CERT:
2579 2927
2580 start_date = parse_cert_date(start_date_str); 2928 start_date = parse_cert_date(start_date_str);
2581 if (start_date <= 0) { 2929 if (start_date <= 0) {
2582 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str); 2930 snprintf(msg, DEFAULT_BUFFER_SIZE,
2931 _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str);
2583 puts(msg); 2932 puts(msg);
2584 return STATE_WARNING; 2933 return STATE_WARNING;
2585 } 2934 }
2586 2935
2587 end_date = parse_cert_date(end_date_str); 2936 end_date = parse_cert_date(end_date_str);
2588 if (end_date <= 0) { 2937 if (end_date <= 0) {
2589 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str); 2938 snprintf(msg, DEFAULT_BUFFER_SIZE,
2939 _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str);
2590 puts(msg); 2940 puts(msg);
2591 return STATE_WARNING; 2941 return STATE_WARNING;
2592 } 2942 }
@@ -2597,42 +2947,49 @@ HAVE_FIRST_CERT:
2597 setenv("TZ", "GMT", 1); 2947 setenv("TZ", "GMT", 1);
2598 tzset(); 2948 tzset();
2599 strftime(timestamp, 50, "%c %z", localtime(&end_date)); 2949 strftime(timestamp, 50, "%c %z", localtime(&end_date));
2600 if (tz) 2950 if (tz) {
2601 setenv("TZ", tz, 1); 2951 setenv("TZ", tz, 1);
2602 else 2952 } else {
2603 unsetenv("TZ"); 2953 unsetenv("TZ");
2954 }
2604 tzset(); 2955 tzset();
2605 2956
2606 if (days_left > 0 && days_left <= days_till_exp_warn) { 2957 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", 2958 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"),
2608 host_name, days_left, timestamp); 2959 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, days_left,
2609 if (days_left > days_till_exp_crit) 2960 timestamp);
2961 if (days_left > days_till_exp_crit) {
2610 status = STATE_WARNING; 2962 status = STATE_WARNING;
2611 else 2963 } else {
2612 status = STATE_CRITICAL; 2964 status = STATE_CRITICAL;
2965 }
2613 } else if (days_left == 0 && time_left > 0) { 2966 } else if (days_left == 0 && time_left > 0) {
2614 if (time_left >= 3600) 2967 if (time_left >= 3600) {
2615 time_remaining = (int)time_left / 3600; 2968 time_remaining = (int)time_left / 3600;
2616 else 2969 } else {
2617 time_remaining = (int)time_left / 60; 2970 time_remaining = (int)time_left / 60;
2971 }
2618 2972
2619 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, 2973 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"),
2620 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp); 2974 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining,
2975 time_left >= 3600 ? "hours" : "minutes", timestamp);
2621 2976
2622 if (days_left > days_till_exp_crit) 2977 if (days_left > days_till_exp_crit) {
2623 status = STATE_WARNING; 2978 status = STATE_WARNING;
2624 else 2979 } else {
2625 status = STATE_CRITICAL; 2980 status = STATE_CRITICAL;
2981 }
2626 } else if (time_left < 0) { 2982 } else if (time_left < 0) {
2627 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 2983 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2628 status = STATE_CRITICAL; 2984 status = STATE_CRITICAL;
2629 } else if (days_left == 0) { 2985 } else if (days_left == 0) {
2630 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, 2986 printf(_("%s - Certificate '%s' just expired (%s).\n"),
2631 timestamp); 2987 (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, timestamp);
2632 if (days_left > days_till_exp_crit) 2988 if (days_left > days_till_exp_crit) {
2633 status = STATE_WARNING; 2989 status = STATE_WARNING;
2634 else 2990 } else {
2635 status = STATE_CRITICAL; 2991 status = STATE_CRITICAL;
2992 }
2636 } else { 2993 } else {
2637 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp); 2994 printf(_("OK - Certificate '%s' will expire on %s.\n"), host_name, timestamp);
2638 status = STATE_OK; 2995 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..9de68713
--- /dev/null
+++ b/plugins/check_curl.d/config.h
@@ -0,0 +1,160 @@
1#pragma once
2
3#include "../../config.h"
4#include "../common.h"
5#include "../../lib/states.h"
6#include "../../lib/thresholds.h"
7#include <stddef.h>
8#include <string.h>
9#include <sys/socket.h>
10#include "curl/curl.h"
11
12enum {
13 MAX_RE_SIZE = 1024,
14 HTTP_PORT = 80,
15 HTTPS_PORT = 443,
16 MAX_PORT = 65535,
17 DEFAULT_MAX_REDIRS = 15
18};
19
20enum {
21 FOLLOW_HTTP_CURL = 0,
22 FOLLOW_LIBCURL = 1
23};
24
25enum {
26 STICKY_NONE = 0,
27 STICKY_HOST = 1,
28 STICKY_PORT = 2
29};
30
31#define HTTP_EXPECT "HTTP/"
32#define DEFAULT_BUFFER_SIZE 2048
33#define DEFAULT_SERVER_URL "/"
34
35typedef struct {
36 char *server_address;
37 char *server_url;
38 char *host_name;
39
40 char *http_method;
41
42 char *http_post_data;
43
44 unsigned short virtualPort;
45 unsigned short serverPort;
46
47 bool use_ssl;
48 bool no_body;
49} check_curl_working_state;
50
51check_curl_working_state check_curl_working_state_init() {
52 check_curl_working_state result = {
53 .server_address = NULL,
54 .server_url = DEFAULT_SERVER_URL,
55 .host_name = NULL,
56 .http_method = NULL,
57 .http_post_data = NULL,
58 .virtualPort = 0,
59 .serverPort = 0,
60 .use_ssl = false,
61 .no_body = false,
62 };
63 return result;
64}
65
66typedef struct {
67 check_curl_working_state initial_config;
68 sa_family_t sin_family;
69
70 bool automatic_decompression;
71 bool haproxy_protocol;
72 char *client_cert;
73 char *client_privkey;
74 char *ca_cert;
75 int ssl_version;
76 char user_agent[DEFAULT_BUFFER_SIZE];
77 char **http_opt_headers;
78 size_t http_opt_headers_count;
79 int max_depth;
80 char *http_content_type;
81 long socket_timeout;
82 char user_auth[MAX_INPUT_BUFFER];
83 char proxy_auth[MAX_INPUT_BUFFER];
84 int followmethod;
85 int followsticky;
86 int curl_http_version;
87 char *cookie_jar_file;
88
89 int maximum_age;
90 char regexp[MAX_RE_SIZE];
91 mp_state_enum state_regex;
92 bool invert_regex;
93 bool verify_peer_and_host;
94 bool check_cert;
95 bool continue_after_check_cert;
96 int days_till_exp_warn;
97 int days_till_exp_crit;
98 thresholds *thlds;
99 size_t min_page_len;
100 size_t max_page_len;
101 char server_expect[MAX_INPUT_BUFFER];
102 bool server_expect_yn;
103 char string_expect[MAX_INPUT_BUFFER];
104 char header_expect[MAX_INPUT_BUFFER];
105 mp_state_enum onredirect;
106
107 bool show_extended_perfdata;
108 bool show_body;
109 bool display_html;
110} check_curl_config;
111
112check_curl_config check_curl_config_init() {
113 check_curl_config tmp = {
114 .initial_config = check_curl_working_state_init(),
115
116 .sin_family = AF_UNSPEC,
117
118 .automatic_decompression = false,
119 .haproxy_protocol = false,
120 .client_cert = NULL,
121 .client_privkey = NULL,
122 .ca_cert = NULL,
123 .ssl_version = CURL_SSLVERSION_DEFAULT,
124 .user_agent = {'\0'},
125 .http_opt_headers = NULL,
126 .http_opt_headers_count = 0,
127 .max_depth = DEFAULT_MAX_REDIRS,
128 .http_content_type = NULL,
129 .socket_timeout = DEFAULT_SOCKET_TIMEOUT,
130 .user_auth = "",
131 .proxy_auth = "",
132 .followmethod = FOLLOW_HTTP_CURL,
133 .followsticky = STICKY_NONE,
134 .curl_http_version = CURL_HTTP_VERSION_NONE,
135 .cookie_jar_file = NULL,
136
137 .maximum_age = -1,
138 .regexp = {},
139 .state_regex = STATE_CRITICAL,
140 .invert_regex = false,
141 .verify_peer_and_host = false,
142 .check_cert = false,
143 .continue_after_check_cert = false,
144 .days_till_exp_warn = 0,
145 .days_till_exp_crit = 0,
146 .thlds = NULL,
147 .min_page_len = 0,
148 .max_page_len = 0,
149 .server_expect = HTTP_EXPECT,
150 .server_expect_yn = false,
151 .string_expect = "",
152 .header_expect = "",
153 .onredirect = STATE_OK,
154
155 .show_extended_perfdata = false,
156 .show_body = false,
157 .display_html = false,
158 };
159 return tmp;
160}