summaryrefslogtreecommitdiffstats
path: root/plugins/check_curl.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_curl.c')
-rw-r--r--plugins/check_curl.c591
1 files changed, 410 insertions, 181 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index 5990b95b..d0871c48 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -37,6 +37,7 @@ const char *progname = "check_curl";
37const char *copyright = "2006-2019"; 37const char *copyright = "2006-2019";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include <stdbool.h>
40#include <ctype.h> 41#include <ctype.h>
41 42
42#include "common.h" 43#include "common.h"
@@ -54,6 +55,7 @@ const char *email = "devel@monitoring-plugins.org";
54#include "uriparser/Uri.h" 55#include "uriparser/Uri.h"
55 56
56#include <arpa/inet.h> 57#include <arpa/inet.h>
58#include <netinet/in.h>
57 59
58#if defined(HAVE_SSL) && defined(USE_OPENSSL) 60#if defined(HAVE_SSL) && defined(USE_OPENSSL)
59#include <openssl/opensslv.h> 61#include <openssl/opensslv.h>
@@ -66,13 +68,13 @@ const char *email = "devel@monitoring-plugins.org";
66#define DEFAULT_BUFFER_SIZE 2048 68#define DEFAULT_BUFFER_SIZE 2048
67#define DEFAULT_SERVER_URL "/" 69#define DEFAULT_SERVER_URL "/"
68#define HTTP_EXPECT "HTTP/" 70#define HTTP_EXPECT "HTTP/"
69#define DEFAULT_MAX_REDIRS 15
70#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN 71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
71enum { 72enum {
72 MAX_IPV4_HOSTLENGTH = 255, 73 MAX_IPV4_HOSTLENGTH = 255,
73 HTTP_PORT = 80, 74 HTTP_PORT = 80,
74 HTTPS_PORT = 443, 75 HTTPS_PORT = 443,
75 MAX_PORT = 65535 76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15
76}; 78};
77 79
78enum { 80enum {
@@ -131,14 +133,14 @@ regmatch_t pmatch[REGS];
131char regexp[MAX_RE_SIZE]; 133char regexp[MAX_RE_SIZE];
132int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; 134int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
133int errcode; 135int errcode;
134int invert_regex = 0; 136bool invert_regex = false;
135 137
136char *server_address = NULL; 138char *server_address = NULL;
137char *host_name = NULL; 139char *host_name = NULL;
138char *server_url = 0; 140char *server_url = 0;
139char server_ip[DEFAULT_BUFFER_SIZE]; 141char server_ip[DEFAULT_BUFFER_SIZE];
140struct curl_slist *server_ips = NULL; 142struct curl_slist *server_ips = NULL;
141int specify_port = FALSE; 143bool specify_port = false;
142unsigned short server_port = HTTP_PORT; 144unsigned short server_port = HTTP_PORT;
143unsigned short virtual_port = 0; 145unsigned short virtual_port = 0;
144int host_name_length; 146int host_name_length;
@@ -150,8 +152,8 @@ int days_till_exp_warn, days_till_exp_crit;
150thresholds *thlds; 152thresholds *thlds;
151char user_agent[DEFAULT_BUFFER_SIZE]; 153char user_agent[DEFAULT_BUFFER_SIZE];
152int verbose = 0; 154int verbose = 0;
153int show_extended_perfdata = FALSE; 155bool show_extended_perfdata = false;
154int show_body = FALSE; 156bool show_body = false;
155int min_page_len = 0; 157int min_page_len = 0;
156int max_page_len = 0; 158int max_page_len = 0;
157int redir_depth = 0; 159int redir_depth = 0;
@@ -160,10 +162,16 @@ char *http_method = NULL;
160char *http_post_data = NULL; 162char *http_post_data = NULL;
161char *http_content_type = NULL; 163char *http_content_type = NULL;
162CURL *curl; 164CURL *curl;
165bool curl_global_initialized = false;
166bool curl_easy_initialized = false;
163struct curl_slist *header_list = NULL; 167struct curl_slist *header_list = NULL;
168bool body_buf_initialized = false;
164curlhelp_write_curlbuf body_buf; 169curlhelp_write_curlbuf body_buf;
170bool header_buf_initialized = false;
165curlhelp_write_curlbuf header_buf; 171curlhelp_write_curlbuf header_buf;
172bool status_line_initialized = false;
166curlhelp_statusline status_line; 173curlhelp_statusline status_line;
174bool put_buf_initialized = false;
167curlhelp_read_curlbuf put_buf; 175curlhelp_read_curlbuf put_buf;
168char http_header[DEFAULT_BUFFER_SIZE]; 176char http_header[DEFAULT_BUFFER_SIZE];
169long code; 177long code;
@@ -173,7 +181,7 @@ double time_connect;
173double time_appconnect; 181double time_appconnect;
174double time_headers; 182double time_headers;
175double time_firstbyte; 183double time_firstbyte;
176char errbuf[CURL_ERROR_SIZE+1]; 184char errbuf[MAX_INPUT_BUFFER];
177CURLcode res; 185CURLcode res;
178char url[DEFAULT_BUFFER_SIZE]; 186char url[DEFAULT_BUFFER_SIZE];
179char msg[DEFAULT_BUFFER_SIZE]; 187char msg[DEFAULT_BUFFER_SIZE];
@@ -186,13 +194,14 @@ char user_auth[MAX_INPUT_BUFFER] = "";
186char proxy_auth[MAX_INPUT_BUFFER] = ""; 194char proxy_auth[MAX_INPUT_BUFFER] = "";
187char **http_opt_headers; 195char **http_opt_headers;
188int http_opt_headers_count = 0; 196int http_opt_headers_count = 0;
189int display_html = FALSE; 197bool display_html = false;
190int onredirect = STATE_OK; 198int onredirect = STATE_OK;
191int followmethod = FOLLOW_HTTP_CURL; 199int followmethod = FOLLOW_HTTP_CURL;
192int followsticky = STICKY_NONE; 200int followsticky = STICKY_NONE;
193int use_ssl = FALSE; 201bool use_ssl = false;
194int use_sni = TRUE; 202bool use_sni = true;
195int check_cert = FALSE; 203bool check_cert = false;
204bool continue_after_check_cert = false;
196typedef union { 205typedef union {
197 struct curl_slist* to_info; 206 struct curl_slist* to_info;
198 struct curl_certinfo* to_certinfo; 207 struct curl_certinfo* to_certinfo;
@@ -202,19 +211,20 @@ int ssl_version = CURL_SSLVERSION_DEFAULT;
202char *client_cert = NULL; 211char *client_cert = NULL;
203char *client_privkey = NULL; 212char *client_privkey = NULL;
204char *ca_cert = NULL; 213char *ca_cert = NULL;
205int verify_peer_and_host = FALSE; 214bool verify_peer_and_host = false;
206int is_openssl_callback = FALSE; 215bool is_openssl_callback = false;
207#if defined(HAVE_SSL) && defined(USE_OPENSSL) 216#if defined(HAVE_SSL) && defined(USE_OPENSSL)
208X509 *cert = NULL; 217X509 *cert = NULL;
209#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
210int no_body = FALSE; 219bool no_body = false;
211int maximum_age = -1; 220int maximum_age = -1;
212int address_family = AF_UNSPEC; 221int address_family = AF_UNSPEC;
213curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 222curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
214int curl_http_version = CURL_HTTP_VERSION_NONE; 223int curl_http_version = CURL_HTTP_VERSION_NONE;
215int automatic_decompression = FALSE; 224bool automatic_decompression = false;
225char *cookie_jar_file = NULL;
216 226
217int process_arguments (int, char**); 227bool process_arguments (int, char**);
218void handle_curl_option_return_code (CURLcode res, const char* option); 228void handle_curl_option_return_code (CURLcode res, const char* option);
219int check_http (void); 229int check_http (void);
220void redir (curlhelp_write_curlbuf*); 230void redir (curlhelp_write_curlbuf*);
@@ -234,7 +244,7 @@ void curlhelp_freewritebuffer (curlhelp_write_curlbuf*);
234int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t); 244int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t);
235int curlhelp_buffer_read_callback (void *, size_t , size_t , void *); 245int curlhelp_buffer_read_callback (void *, size_t , size_t , void *);
236void curlhelp_freereadbuffer (curlhelp_read_curlbuf *); 246void curlhelp_freereadbuffer (curlhelp_read_curlbuf *);
237curlhelp_ssl_library curlhelp_get_ssl_library (CURL*); 247curlhelp_ssl_library curlhelp_get_ssl_library ();
238const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library); 248const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library);
239int net_noopenssl_check_certificate (cert_ptr_union*, int, int); 249int net_noopenssl_check_certificate (cert_ptr_union*, int, int);
240 250
@@ -268,10 +278,10 @@ main (int argc, char **argv)
268 progname, NP_VERSION, VERSION, curl_version()); 278 progname, NP_VERSION, VERSION, curl_version());
269 279
270 /* parse arguments */ 280 /* parse arguments */
271 if (process_arguments (argc, argv) == ERROR) 281 if (process_arguments (argc, argv) == false)
272 usage4 (_("Could not parse arguments")); 282 usage4 (_("Could not parse arguments"));
273 283
274 if (display_html == TRUE) 284 if (display_html)
275 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 285 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">",
276 use_ssl ? "https" : "http", 286 use_ssl ? "https" : "http",
277 host_name ? host_name : server_address, 287 host_name ? host_name : server_address,
@@ -287,6 +297,7 @@ main (int argc, char **argv)
287 297
288int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) 298int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
289{ 299{
300 (void) preverify_ok;
290 /* TODO: we get all certificates of the chain, so which ones 301 /* TODO: we get all certificates of the chain, so which ones
291 * should we test? 302 * should we test?
292 * TODO: is the last certificate always the server certificate? 303 * TODO: is the last certificate always the server certificate?
@@ -311,6 +322,8 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
311 322
312CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) 323CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm)
313{ 324{
325 (void) curl; // ignore unused parameter
326 (void) parm; // ignore unused parameter
314 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback); 327 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
315 328
316 return CURLE_OK; 329 return CURLE_OK;
@@ -365,8 +378,12 @@ void
365handle_curl_option_return_code (CURLcode res, const char* option) 378handle_curl_option_return_code (CURLcode res, const char* option)
366{ 379{
367 if (res != CURLE_OK) { 380 if (res != CURLE_OK) {
368 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Error while setting cURL option '%s': cURL returned %d - %s"), 381 snprintf (msg,
369 option, res, curl_easy_strerror(res)); 382 DEFAULT_BUFFER_SIZE,
383 _("Error while setting cURL option '%s': cURL returned %d - %s"),
384 option,
385 res,
386 curl_easy_strerror(res));
370 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 387 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
371 } 388 }
372} 389}
@@ -375,8 +392,11 @@ int
375lookup_host (const char *host, char *buf, size_t buflen) 392lookup_host (const char *host, char *buf, size_t buflen)
376{ 393{
377 struct addrinfo hints, *res, *result; 394 struct addrinfo hints, *res, *result;
395 char addrstr[100];
396 size_t addrstr_len;
378 int errcode; 397 int errcode;
379 void *ptr; 398 void *ptr;
399 size_t buflen_remaining = buflen - 1;
380 400
381 memset (&hints, 0, sizeof (hints)); 401 memset (&hints, 0, sizeof (hints));
382 hints.ai_family = address_family; 402 hints.ai_family = address_family;
@@ -386,31 +406,62 @@ lookup_host (const char *host, char *buf, size_t buflen)
386 errcode = getaddrinfo (host, NULL, &hints, &result); 406 errcode = getaddrinfo (host, NULL, &hints, &result);
387 if (errcode != 0) 407 if (errcode != 0)
388 return errcode; 408 return errcode;
389 409
410 strcpy(buf, "");
390 res = result; 411 res = result;
391 412
392 while (res) { 413 while (res) {
393 inet_ntop (res->ai_family, res->ai_addr->sa_data, buf, buflen); 414 switch (res->ai_family) {
394 switch (res->ai_family) { 415 case AF_INET:
395 case AF_INET: 416 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
396 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr; 417 break;
397 break; 418 case AF_INET6:
398 case AF_INET6: 419 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
399 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; 420 break;
400 break;
401 } 421 }
402 inet_ntop (res->ai_family, ptr, buf, buflen); 422
403 if (verbose >= 1) 423 inet_ntop (res->ai_family, ptr, addrstr, 100);
424 if (verbose >= 1) {
404 printf ("* getaddrinfo IPv%d address: %s\n", 425 printf ("* getaddrinfo IPv%d address: %s\n",
405 res->ai_family == PF_INET6 ? 6 : 4, buf); 426 res->ai_family == PF_INET6 ? 6 : 4, addrstr);
427 }
428
429 // Append all IPs to buf as a comma-separated string
430 addrstr_len = strlen(addrstr);
431 if (buflen_remaining > addrstr_len + 1) {
432 if (buf[0] != '\0') {
433 strncat(buf, ",", buflen_remaining);
434 buflen_remaining -= 1;
435 }
436 strncat(buf, addrstr, buflen_remaining);
437 buflen_remaining -= addrstr_len;
438 }
439
406 res = res->ai_next; 440 res = res->ai_next;
407 } 441 }
408 442
409 freeaddrinfo(result); 443 freeaddrinfo(result);
410 444
411 return 0; 445 return 0;
412} 446}
413 447
448static void
449cleanup (void)
450{
451 if (status_line_initialized) curlhelp_free_statusline(&status_line);
452 status_line_initialized = false;
453 if (curl_easy_initialized) curl_easy_cleanup (curl);
454 curl_easy_initialized = false;
455 if (curl_global_initialized) curl_global_cleanup ();
456 curl_global_initialized = false;
457 if (body_buf_initialized) curlhelp_freewritebuffer (&body_buf);
458 body_buf_initialized = false;
459 if (header_buf_initialized) curlhelp_freewritebuffer (&header_buf);
460 header_buf_initialized = false;
461 if (put_buf_initialized) curlhelp_freereadbuffer (&put_buf);
462 put_buf_initialized = false;
463}
464
414int 465int
415check_http (void) 466check_http (void)
416{ 467{
@@ -419,18 +470,24 @@ check_http (void)
419 int i; 470 int i;
420 char *force_host_header = NULL; 471 char *force_host_header = NULL;
421 struct curl_slist *host = NULL; 472 struct curl_slist *host = NULL;
422 char addrstr[100]; 473 char addrstr[DEFAULT_BUFFER_SIZE/2];
423 char dnscache[DEFAULT_BUFFER_SIZE]; 474 char dnscache[DEFAULT_BUFFER_SIZE];
424 475
425 /* initialize curl */ 476 /* initialize curl */
426 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) 477 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK)
427 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 478 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
479 curl_global_initialized = true;
428 480
429 if ((curl = curl_easy_init()) == NULL) 481 if ((curl = curl_easy_init()) == NULL) {
430 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); 482 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
483 }
484 curl_easy_initialized = true;
431 485
486 /* register cleanup function to shut down libcurl properly */
487 atexit (cleanup);
488
432 if (verbose >= 1) 489 if (verbose >= 1)
433 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, TRUE), "CURLOPT_VERBOSE"); 490 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
434 491
435 /* print everything on stdout like check_http would do */ 492 /* print everything on stdout like check_http would do */
436 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); 493 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
@@ -445,12 +502,14 @@ check_http (void)
445 /* initialize buffer for body of the answer */ 502 /* initialize buffer for body of the answer */
446 if (curlhelp_initwritebuffer(&body_buf) < 0) 503 if (curlhelp_initwritebuffer(&body_buf) < 0)
447 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); 504 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
505 body_buf_initialized = true;
448 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION"); 506 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION");
449 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA"); 507 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
450 508
451 /* initialize buffer for header of the answer */ 509 /* initialize buffer for header of the answer */
452 if (curlhelp_initwritebuffer( &header_buf ) < 0) 510 if (curlhelp_initwritebuffer( &header_buf ) < 0)
453 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" ); 511 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" );
512 header_buf_initialized = true;
454 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION"); 513 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION");
455 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER"); 514 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
456 515
@@ -463,10 +522,14 @@ check_http (void)
463 522
464 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy 523 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy
465 if(use_ssl && host_name != NULL) { 524 if(use_ssl && host_name != NULL) {
466 if ( (res=lookup_host (server_address, addrstr, 100)) != 0) { 525 if ( (res=lookup_host (server_address, addrstr, DEFAULT_BUFFER_SIZE/2)) != 0) {
467 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), 526 snprintf (msg,
468 server_address, res, gai_strerror (res)); 527 DEFAULT_BUFFER_SIZE,
469 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 528 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"),
529 server_address,
530 res,
531 gai_strerror (res));
532 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
470 } 533 }
471 snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr); 534 snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
472 host = curl_slist_append(NULL, dnscache); 535 host = curl_slist_append(NULL, dnscache);
@@ -475,10 +538,22 @@ check_http (void)
475 printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache); 538 printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache);
476 } 539 }
477 540
541 // If server_address is an IPv6 address it must be surround by square brackets
542 struct in6_addr tmp_in_addr;
543 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
544 char *new_server_address = malloc(strlen(server_address) + 3);
545 if (new_server_address == NULL) {
546 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
547 }
548 snprintf(new_server_address, strlen(server_address)+3, "[%s]", server_address);
549 free(server_address);
550 server_address = new_server_address;
551 }
552
478 /* compose URL: use the address we want to connect to, set Host: header later */ 553 /* compose URL: use the address we want to connect to, set Host: header later */
479 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", 554 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s",
480 use_ssl ? "https" : "http", 555 use_ssl ? "https" : "http",
481 use_ssl & host_name != NULL ? host_name : server_address, 556 ( use_ssl & ( host_name != NULL ) ) ? host_name : server_address,
482 server_port, 557 server_port,
483 server_url 558 server_url
484 ); 559 );
@@ -499,7 +574,7 @@ check_http (void)
499 574
500 /* disable body for HEAD request */ 575 /* disable body for HEAD request */
501 if (http_method && !strcmp (http_method, "HEAD" )) { 576 if (http_method && !strcmp (http_method, "HEAD" )) {
502 no_body = TRUE; 577 no_body = true;
503 } 578 }
504 579
505 /* set HTTP protocol version */ 580 /* set HTTP protocol version */
@@ -554,7 +629,7 @@ check_http (void)
554 629
555#ifdef LIBCURL_FEATURE_SSL 630#ifdef LIBCURL_FEATURE_SSL
556 631
557 /* set SSL version, warn about unsecure or unsupported versions */ 632 /* set SSL version, warn about insecure or unsupported versions */
558 if (use_ssl) { 633 if (use_ssl) {
559 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 634 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
560 } 635 }
@@ -582,7 +657,7 @@ check_http (void)
582 } 657 }
583 658
584 /* detect SSL library used by libcurl */ 659 /* detect SSL library used by libcurl */
585 ssl_library = curlhelp_get_ssl_library (curl); 660 ssl_library = curlhelp_get_ssl_library ();
586 661
587 /* try hard to get a stack of certificates to verify against */ 662 /* try hard to get a stack of certificates to verify against */
588 if (check_cert) { 663 if (check_cert) {
@@ -596,7 +671,7 @@ check_http (void)
596#ifdef USE_OPENSSL 671#ifdef USE_OPENSSL
597 /* libcurl and monitoring plugins built with OpenSSL, good */ 672 /* libcurl and monitoring plugins built with OpenSSL, good */
598 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 673 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
599 is_openssl_callback = TRUE; 674 is_openssl_callback = true;
600#else /* USE_OPENSSL */ 675#else /* USE_OPENSSL */
601#endif /* USE_OPENSSL */ 676#endif /* USE_OPENSSL */
602 /* libcurl is built with OpenSSL, monitoring plugins, so falling 677 /* libcurl is built with OpenSSL, monitoring plugins, so falling
@@ -675,9 +750,11 @@ check_http (void)
675 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS"); 750 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS");
676 751
677 /* for now allow only http and https (we are a http(s) check plugin in the end) */ 752 /* for now allow only http and https (we are a http(s) check plugin in the end) */
678#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) 753#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
754 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR");
755#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
679 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS"); 756 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS");
680#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) */ 757#endif
681 758
682 /* TODO: handle the following aspects of redirection, make them 759 /* TODO: handle the following aspects of redirection, make them
683 * command line options too later: 760 * command line options too later:
@@ -721,11 +798,19 @@ check_http (void)
721 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS"); 798 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS");
722 } else if (!strcmp(http_method, "PUT")) { 799 } else if (!strcmp(http_method, "PUT")) {
723 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION"); 800 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION");
724 curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)); 801 if (curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)) < 0)
802 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
803 put_buf_initialized = true;
725 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); 804 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
726 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE"); 805 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE");
727 } 806 }
728 } 807 }
808
809 /* cookie handling */
810 if (cookie_jar_file != NULL) {
811 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
812 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
813 }
729 814
730 /* do the request */ 815 /* do the request */
731 res = curl_easy_perform(curl); 816 res = curl_easy_perform(curl);
@@ -736,25 +821,34 @@ check_http (void)
736 /* free header and server IP resolve lists, we don't need it anymore */ 821 /* free header and server IP resolve lists, we don't need it anymore */
737 curl_slist_free_all (header_list); header_list = NULL; 822 curl_slist_free_all (header_list); header_list = NULL;
738 curl_slist_free_all (server_ips); server_ips = NULL; 823 curl_slist_free_all (server_ips); server_ips = NULL;
824 if (host) {
825 curl_slist_free_all (host); host = NULL;
826 }
739 827
740 /* Curl errors, result in critical Nagios state */ 828 /* Curl errors, result in critical Nagios state */
741 if (res != CURLE_OK) { 829 if (res != CURLE_OK) {
742 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), 830 snprintf (msg,
743 server_port, res, errbuf[0] ? errbuf : curl_easy_strerror(res)); 831 DEFAULT_BUFFER_SIZE,
744 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 832 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"),
833 server_port,
834 res,
835 errbuf[0] ? errbuf : curl_easy_strerror(res));
836 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
745 } 837 }
746 838
747 /* certificate checks */ 839 /* certificate checks */
748#ifdef LIBCURL_FEATURE_SSL 840#ifdef LIBCURL_FEATURE_SSL
749 if (use_ssl == TRUE) { 841 if (use_ssl) {
750 if (check_cert == TRUE) { 842 if (check_cert) {
751 if (is_openssl_callback) { 843 if (is_openssl_callback) {
752#ifdef USE_OPENSSL 844#ifdef USE_OPENSSL
753 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 845 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
754 * and we actually have OpenSSL in the monitoring tools 846 * and we actually have OpenSSL in the monitoring tools
755 */ 847 */
756 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 848 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
757 return result; 849 if (!continue_after_check_cert) {
850 return result;
851 }
758#else /* USE_OPENSSL */ 852#else /* USE_OPENSSL */
759 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n"); 853 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
760#endif /* USE_OPENSSL */ 854#endif /* USE_OPENSSL */
@@ -782,30 +876,41 @@ check_http (void)
782 } 876 }
783GOT_FIRST_CERT: 877GOT_FIRST_CERT:
784 if (!raw_cert) { 878 if (!raw_cert) {
785 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates from CERTINFO information - certificate data was empty")); 879 snprintf (msg,
786 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 880 DEFAULT_BUFFER_SIZE,
881 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
882 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
787 } 883 }
788 BIO* cert_BIO = BIO_new (BIO_s_mem()); 884 BIO* cert_BIO = BIO_new (BIO_s_mem());
789 BIO_write (cert_BIO, raw_cert, strlen(raw_cert)); 885 BIO_write (cert_BIO, raw_cert, strlen(raw_cert));
790 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL); 886 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL);
791 if (!cert) { 887 if (!cert) {
792 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot read certificate from CERTINFO information - BIO error")); 888 snprintf (msg,
793 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 889 DEFAULT_BUFFER_SIZE,
890 _("Cannot read certificate from CERTINFO information - BIO error"));
891 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
794 } 892 }
795 BIO_free (cert_BIO); 893 BIO_free (cert_BIO);
796 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 894 result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
797 return result; 895 if (!continue_after_check_cert) {
896 return result;
897 }
798#else /* USE_OPENSSL */ 898#else /* USE_OPENSSL */
799 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal, 899 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
800 * so we use the libcurl CURLINFO data 900 * so we use the libcurl CURLINFO data
801 */ 901 */
802 result = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit); 902 result = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
803 return result; 903 if (!continue_after_check_cert) {
904 return result;
905 }
804#endif /* USE_OPENSSL */ 906#endif /* USE_OPENSSL */
805 } else { 907 } else {
806 snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), 908 snprintf (msg,
807 res, curl_easy_strerror(res)); 909 DEFAULT_BUFFER_SIZE,
808 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 910 _("Cannot retrieve certificates - cURL returned %d - %s"),
911 res,
912 curl_easy_strerror(res));
913 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
809 } 914 }
810 } 915 }
811 } 916 }
@@ -826,7 +931,7 @@ GOT_FIRST_CERT:
826 perfd_time(total_time), 931 perfd_time(total_time),
827 perfd_size(page_len), 932 perfd_size(page_len),
828 perfd_time_connect(time_connect), 933 perfd_time_connect(time_connect),
829 use_ssl == TRUE ? perfd_time_ssl (time_appconnect-time_connect) : "", 934 use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "",
830 perfd_time_headers(time_headers - time_appconnect), 935 perfd_time_headers(time_headers - time_appconnect),
831 perfd_time_firstbyte(time_firstbyte - time_headers), 936 perfd_time_firstbyte(time_firstbyte - time_headers),
832 perfd_time_transfer(total_time-time_firstbyte) 937 perfd_time_transfer(total_time-time_firstbyte)
@@ -844,11 +949,15 @@ GOT_FIRST_CERT:
844 949
845 /* get status line of answer, check sanity of HTTP code */ 950 /* get status line of answer, check sanity of HTTP code */
846 if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) { 951 if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) {
847 snprintf (msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", 952 snprintf (msg,
848 total_time, perfstring); 953 DEFAULT_BUFFER_SIZE,
954 "Unparsable status line in %.3g seconds response time|%s\n",
955 total_time,
956 perfstring);
849 /* we cannot know the major/minor version here for sure as we cannot parse the first line */ 957 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
850 die (STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg); 958 die (STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
851 } 959 }
960 status_line_initialized = true;
852 961
853 /* get result code from cURL */ 962 /* get result code from cURL */
854 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE"); 963 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
@@ -864,9 +973,16 @@ GOT_FIRST_CERT:
864 /* make sure the status line matches the response we are looking for */ 973 /* make sure the status line matches the response we are looking for */
865 if (!expected_statuscode(status_line.first_line, server_expect)) { 974 if (!expected_statuscode(status_line.first_line, server_expect)) {
866 if (server_port == HTTP_PORT) 975 if (server_port == HTTP_PORT)
867 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line); 976 snprintf(msg,
977 DEFAULT_BUFFER_SIZE,
978 _("Invalid HTTP response received from host: %s\n"),
979 status_line.first_line);
868 else 980 else
869 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port, status_line.first_line); 981 snprintf(msg,
982 DEFAULT_BUFFER_SIZE,
983 _("Invalid HTTP response received from host on port %d: %s\n"),
984 server_port,
985 status_line.first_line);
870 die (STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, 986 die (STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg,
871 show_body ? "\n" : "", 987 show_body ? "\n" : "",
872 show_body ? body_buf.buf : ""); 988 show_body ? body_buf.buf : "");
@@ -902,7 +1018,7 @@ GOT_FIRST_CERT:
902 } 1018 }
903 } else { 1019 } else {
904 /* this is a specific code in the command line to 1020 /* this is a specific code in the command line to
905 * be returned when a redirection is encoutered 1021 * be returned when a redirection is encountered
906 */ 1022 */
907 } 1023 }
908 result = max_state_alt (onredirect, result); 1024 result = max_state_alt (onredirect, result);
@@ -939,64 +1055,119 @@ GOT_FIRST_CERT:
939 1055
940 if (strlen (header_expect)) { 1056 if (strlen (header_expect)) {
941 if (!strstr (header_buf.buf, header_expect)) { 1057 if (!strstr (header_buf.buf, header_expect)) {
1058
942 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search)); 1059 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search));
1060
943 if(output_header_search[sizeof(output_header_search)-1]!='\0') { 1061 if(output_header_search[sizeof(output_header_search)-1]!='\0') {
944 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4); 1062 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4);
945 } 1063 }
946 snprintf (msg, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1064
947 result = STATE_CRITICAL; 1065 char tmp[DEFAULT_BUFFER_SIZE];
1066
1067 snprintf (tmp,
1068 DEFAULT_BUFFER_SIZE,
1069 _("%sheader '%s' not found on '%s://%s:%d%s', "),
1070 msg,
1071 output_header_search,
1072 use_ssl ? "https" : "http",
1073 host_name ? host_name : server_address,
1074 server_port,
1075 server_url);
1076
1077 strcpy(msg, tmp);
1078
1079 result = STATE_CRITICAL;
948 } 1080 }
949 } 1081 }
950 1082
951 if (strlen (string_expect)) { 1083 if (strlen (string_expect)) {
952 if (!strstr (body_buf.buf, string_expect)) { 1084 if (!strstr (body_buf.buf, string_expect)) {
1085
953 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 1086 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search));
1087
954 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1088 if(output_string_search[sizeof(output_string_search)-1]!='\0') {
955 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1089 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4);
956 } 1090 }
957 snprintf (msg, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search, use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url); 1091
958 result = STATE_CRITICAL; 1092 char tmp[DEFAULT_BUFFER_SIZE];
1093
1094 snprintf (tmp,
1095 DEFAULT_BUFFER_SIZE,
1096 _("%sstring '%s' not found on '%s://%s:%d%s', "),
1097 msg,
1098 output_string_search,
1099 use_ssl ? "https" : "http",
1100 host_name ? host_name : server_address,
1101 server_port,
1102 server_url);
1103
1104 strcpy(msg, tmp);
1105
1106 result = STATE_CRITICAL;
959 } 1107 }
960 } 1108 }
961 1109
962 if (strlen (regexp)) { 1110 if (strlen (regexp)) {
963 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0); 1111 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0);
964 if ((errcode == 0 && invert_regex == 0) || (errcode == REG_NOMATCH && invert_regex == 1)) { 1112 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
965 /* OK - No-op to avoid changing the logic around it */ 1113 /* OK - No-op to avoid changing the logic around it */
966 result = max_state_alt(STATE_OK, result); 1114 result = max_state_alt(STATE_OK, result);
967 } 1115 }
968 else if ((errcode == REG_NOMATCH && invert_regex == 0) || (errcode == 0 && invert_regex == 1)) { 1116 else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
969 if (invert_regex == 0) 1117 if (!invert_regex) {
970 snprintf (msg, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1118 char tmp[DEFAULT_BUFFER_SIZE];
971 else 1119
972 snprintf (msg, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1120 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
973 result = STATE_CRITICAL; 1121 strcpy(msg, tmp);
974 } 1122
975 else { 1123 } else {
976 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1124 char tmp[DEFAULT_BUFFER_SIZE];
977 snprintf (msg, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); 1125
978 result = STATE_UNKNOWN; 1126 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
979 } 1127 strcpy(msg, tmp);
1128
1129 }
1130 result = STATE_CRITICAL;
1131 } else {
1132 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1133
1134 char tmp[DEFAULT_BUFFER_SIZE];
1135
1136 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf);
1137 strcpy(msg, tmp);
1138 result = STATE_UNKNOWN;
1139 }
980 } 1140 }
981 1141
982 /* make sure the page is of an appropriate size */ 1142 /* make sure the page is of an appropriate size */
983 if ((max_page_len > 0) && (page_len > max_page_len)) { 1143 if ((max_page_len > 0) && (page_len > max_page_len)) {
984 snprintf (msg, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 1144 char tmp[DEFAULT_BUFFER_SIZE];
985 result = max_state_alt(STATE_WARNING, result); 1145
986 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1146 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
987 snprintf (msg, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 1147
988 result = max_state_alt(STATE_WARNING, result); 1148 strcpy(msg, tmp);
989 } 1149
1150 result = max_state_alt(STATE_WARNING, result);
1151
1152 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1153 char tmp[DEFAULT_BUFFER_SIZE];
1154
1155 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
1156 strcpy(msg, tmp);
1157 result = max_state_alt(STATE_WARNING, result);
1158 }
990 1159
991 /* -w, -c: check warning and critical level */ 1160 /* -w, -c: check warning and critical level */
992 result = max_state_alt(get_status(total_time, thlds), result); 1161 result = max_state_alt(get_status(total_time, thlds), result);
993 1162
994 /* Cut-off trailing characters */ 1163 /* Cut-off trailing characters */
995 if(msg[strlen(msg)-2] == ',') 1164 if (strlen(msg) >= 2) {
996 msg[strlen(msg)-2] = '\0'; 1165 if(msg[strlen(msg)-2] == ',')
997 else 1166 msg[strlen(msg)-2] = '\0';
998 msg[strlen(msg)-3] = '\0'; 1167 else
999 1168 msg[strlen(msg)-3] = '\0';
1169 }
1170
1000 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 1171 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */
1001 die (result, "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", 1172 die (result, "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s",
1002 state_text(result), string_statuscode (status_line.http_major, status_line.http_minor), 1173 state_text(result), string_statuscode (status_line.http_major, status_line.http_minor),
@@ -1008,16 +1179,6 @@ GOT_FIRST_CERT:
1008 (show_body ? body_buf.buf : ""), 1179 (show_body ? body_buf.buf : ""),
1009 (show_body ? "\n" : "") ); 1180 (show_body ? "\n" : "") );
1010 1181
1011 /* proper cleanup after die? */
1012 curlhelp_free_statusline(&status_line);
1013 curl_easy_cleanup (curl);
1014 curl_global_cleanup ();
1015 curlhelp_freewritebuffer (&body_buf);
1016 curlhelp_freewritebuffer (&header_buf);
1017 if (!strcmp (http_method, "PUT")) {
1018 curlhelp_freereadbuffer (&put_buf);
1019 }
1020
1021 return result; 1182 return result;
1022} 1183}
1023 1184
@@ -1054,7 +1215,7 @@ redir (curlhelp_write_curlbuf* header_buf)
1054 char *new_url; 1215 char *new_url;
1055 1216
1056 int res = phr_parse_response (header_buf->buf, header_buf->buflen, 1217 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
1057 &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen, 1218 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
1058 headers, &nof_headers, 0); 1219 headers, &nof_headers, 0);
1059 1220
1060 location = get_header_value (headers, nof_headers, "location"); 1221 location = get_header_value (headers, nof_headers, "location");
@@ -1113,7 +1274,10 @@ redir (curlhelp_write_curlbuf* header_buf)
1113 } 1274 }
1114 } 1275 }
1115 1276
1116 use_ssl = !uri_strcmp (uri.scheme, "https"); 1277 if (!uri_strcmp (uri.scheme, "https"))
1278 use_ssl = true;
1279 else
1280 use_ssl = false;
1117 1281
1118 /* we do a sloppy test here only, because uriparser would have failed 1282 /* we do a sloppy test here only, because uriparser would have failed
1119 * above, if the port would be invalid, we just check for MAX_PORT 1283 * above, if the port would be invalid, we just check for MAX_PORT
@@ -1188,6 +1352,7 @@ redir (curlhelp_write_curlbuf* header_buf)
1188 * attached to the URL in Location 1352 * attached to the URL in Location
1189 */ 1353 */
1190 1354
1355 cleanup ();
1191 check_http (); 1356 check_http ();
1192} 1357}
1193 1358
@@ -1200,7 +1365,7 @@ test_file (char *path)
1200 usage2 (_("file does not exist or is not readable"), path); 1365 usage2 (_("file does not exist or is not readable"), path);
1201} 1366}
1202 1367
1203int 1368bool
1204process_arguments (int argc, char **argv) 1369process_arguments (int argc, char **argv)
1205{ 1370{
1206 char *p; 1371 char *p;
@@ -1210,9 +1375,12 @@ process_arguments (int argc, char **argv)
1210 enum { 1375 enum {
1211 INVERT_REGEX = CHAR_MAX + 1, 1376 INVERT_REGEX = CHAR_MAX + 1,
1212 SNI_OPTION, 1377 SNI_OPTION,
1378 MAX_REDIRS_OPTION,
1379 CONTINUE_AFTER_CHECK_CERT,
1213 CA_CERT_OPTION, 1380 CA_CERT_OPTION,
1214 HTTP_VERSION_OPTION, 1381 HTTP_VERSION_OPTION,
1215 AUTOMATIC_DECOMPRESSION 1382 AUTOMATIC_DECOMPRESSION,
1383 COOKIE_JAR
1216 }; 1384 };
1217 1385
1218 int option = 0; 1386 int option = 0;
@@ -1243,6 +1411,7 @@ process_arguments (int argc, char **argv)
1243 {"private-key", required_argument, 0, 'K'}, 1411 {"private-key", required_argument, 0, 'K'},
1244 {"ca-cert", required_argument, 0, CA_CERT_OPTION}, 1412 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1245 {"verify-cert", no_argument, 0, 'D'}, 1413 {"verify-cert", no_argument, 0, 'D'},
1414 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1246 {"useragent", required_argument, 0, 'A'}, 1415 {"useragent", required_argument, 0, 'A'},
1247 {"header", required_argument, 0, 'k'}, 1416 {"header", required_argument, 0, 'k'},
1248 {"no-body", no_argument, 0, 'N'}, 1417 {"no-body", no_argument, 0, 'N'},
@@ -1254,13 +1423,15 @@ process_arguments (int argc, char **argv)
1254 {"use-ipv6", no_argument, 0, '6'}, 1423 {"use-ipv6", no_argument, 0, '6'},
1255 {"extended-perfdata", no_argument, 0, 'E'}, 1424 {"extended-perfdata", no_argument, 0, 'E'},
1256 {"show-body", no_argument, 0, 'B'}, 1425 {"show-body", no_argument, 0, 'B'},
1426 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1257 {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, 1427 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1258 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, 1428 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1429 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1259 {0, 0, 0, 0} 1430 {0, 0, 0, 0}
1260 }; 1431 };
1261 1432
1262 if (argc < 2) 1433 if (argc < 2)
1263 return ERROR; 1434 return false;
1264 1435
1265 /* support check_http compatible arguments */ 1436 /* support check_http compatible arguments */
1266 for (c = 1; c < argc; c++) { 1437 for (c = 1; c < argc; c++) {
@@ -1340,7 +1511,7 @@ process_arguments (int argc, char **argv)
1340 if( strtol(optarg, NULL, 10) > MAX_PORT) 1511 if( strtol(optarg, NULL, 10) > MAX_PORT)
1341 usage2 (_("Invalid port number, supplied port number is too big"), optarg); 1512 usage2 (_("Invalid port number, supplied port number is too big"), optarg);
1342 server_port = (unsigned short)strtol(optarg, NULL, 10); 1513 server_port = (unsigned short)strtol(optarg, NULL, 10);
1343 specify_port = TRUE; 1514 specify_port = true;
1344 } 1515 }
1345 break; 1516 break;
1346 case 'a': /* authorization info */ 1517 case 'a': /* authorization info */
@@ -1374,10 +1545,10 @@ process_arguments (int argc, char **argv)
1374 http_opt_headers[http_opt_headers_count - 1] = optarg; 1545 http_opt_headers[http_opt_headers_count - 1] = optarg;
1375 break; 1546 break;
1376 case 'L': /* show html link */ 1547 case 'L': /* show html link */
1377 display_html = TRUE; 1548 display_html = true;
1378 break; 1549 break;
1379 case 'n': /* do not show html link */ 1550 case 'n': /* do not show html link */
1380 display_html = FALSE; 1551 display_html = false;
1381 break; 1552 break;
1382 case 'C': /* Check SSL cert validity */ 1553 case 'C': /* Check SSL cert validity */
1383#ifdef LIBCURL_FEATURE_SSL 1554#ifdef LIBCURL_FEATURE_SSL
@@ -1398,9 +1569,14 @@ process_arguments (int argc, char **argv)
1398 usage2 (_("Invalid certificate expiration period"), optarg); 1569 usage2 (_("Invalid certificate expiration period"), optarg);
1399 days_till_exp_warn = atoi (optarg); 1570 days_till_exp_warn = atoi (optarg);
1400 } 1571 }
1401 check_cert = TRUE; 1572 check_cert = true;
1402 goto enable_ssl; 1573 goto enable_ssl;
1403#endif 1574#endif
1575 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1576#ifdef HAVE_SSL
1577 continue_after_check_cert = true;
1578 break;
1579#endif
1404 case 'J': /* use client certificate */ 1580 case 'J': /* use client certificate */
1405#ifdef LIBCURL_FEATURE_SSL 1581#ifdef LIBCURL_FEATURE_SSL
1406 test_file(optarg); 1582 test_file(optarg);
@@ -1421,13 +1597,13 @@ process_arguments (int argc, char **argv)
1421#endif 1597#endif
1422#ifdef LIBCURL_FEATURE_SSL 1598#ifdef LIBCURL_FEATURE_SSL
1423 case 'D': /* verify peer certificate & host */ 1599 case 'D': /* verify peer certificate & host */
1424 verify_peer_and_host = TRUE; 1600 verify_peer_and_host = true;
1425 goto enable_ssl; 1601 break;
1426#endif 1602#endif
1427 case 'S': /* use SSL */ 1603 case 'S': /* use SSL */
1428#ifdef LIBCURL_FEATURE_SSL 1604#ifdef LIBCURL_FEATURE_SSL
1429 enable_ssl: 1605 enable_ssl:
1430 use_ssl = TRUE; 1606 use_ssl = true;
1431 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1607 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1432 * Only set if it's non-zero. This helps when we include multiple 1608 * Only set if it's non-zero. This helps when we include multiple
1433 * parameters, like -S and -C combinations */ 1609 * parameters, like -S and -C combinations */
@@ -1501,17 +1677,24 @@ process_arguments (int argc, char **argv)
1501#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1677#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1502 if (verbose >= 2) 1678 if (verbose >= 2)
1503 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1679 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1504 if (specify_port == FALSE) 1680 if (!specify_port)
1505 server_port = HTTPS_PORT; 1681 server_port = HTTPS_PORT;
1506 break; 1682 break;
1507#else /* LIBCURL_FEATURE_SSL */ 1683#else /* LIBCURL_FEATURE_SSL */
1508 /* -C -J and -K fall through to here without SSL */ 1684 /* -C -J and -K fall through to here without SSL */
1509 usage4 (_("Invalid option - SSL is not available")); 1685 usage4 (_("Invalid option - SSL is not available"));
1510 break; 1686 break;
1511 case SNI_OPTION: /* --sni is parsed, but ignored, the default is TRUE with libcurl */ 1687 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1512 use_sni = TRUE; 1688 use_sni = true;
1513 break; 1689 break;
1514#endif /* LIBCURL_FEATURE_SSL */ 1690#endif /* LIBCURL_FEATURE_SSL */
1691 case MAX_REDIRS_OPTION:
1692 if (!is_intnonneg (optarg))
1693 usage2 (_("Invalid max_redirs count"), optarg);
1694 else {
1695 max_depth = atoi (optarg);
1696 }
1697 break;
1515 case 'f': /* onredirect */ 1698 case 'f': /* onredirect */
1516 if (!strcmp (optarg, "ok")) 1699 if (!strcmp (optarg, "ok"))
1517 onredirect = STATE_OK; 1700 onredirect = STATE_OK;
@@ -1556,6 +1739,7 @@ process_arguments (int argc, char **argv)
1556 break; 1739 break;
1557 case 'R': /* regex */ 1740 case 'R': /* regex */
1558 cflags |= REG_ICASE; 1741 cflags |= REG_ICASE;
1742 // fall through
1559 case 'r': /* regex */ 1743 case 'r': /* regex */
1560 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 1744 strncpy (regexp, optarg, MAX_RE_SIZE - 1);
1561 regexp[MAX_RE_SIZE - 1] = 0; 1745 regexp[MAX_RE_SIZE - 1] = 0;
@@ -1563,11 +1747,11 @@ process_arguments (int argc, char **argv)
1563 if (errcode != 0) { 1747 if (errcode != 0) {
1564 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1748 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1565 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 1749 printf (_("Could Not Compile Regular Expression: %s"), errbuf);
1566 return ERROR; 1750 return false;
1567 } 1751 }
1568 break; 1752 break;
1569 case INVERT_REGEX: 1753 case INVERT_REGEX:
1570 invert_regex = 1; 1754 invert_regex = true;
1571 break; 1755 break;
1572 case '4': 1756 case '4':
1573 address_family = AF_INET; 1757 address_family = AF_INET;
@@ -1602,7 +1786,7 @@ process_arguments (int argc, char **argv)
1602 break; 1786 break;
1603 } 1787 }
1604 case 'N': /* no-body */ 1788 case 'N': /* no-body */
1605 no_body = TRUE; 1789 no_body = true;
1606 break; 1790 break;
1607 case 'M': /* max-age */ 1791 case 'M': /* max-age */
1608 { 1792 {
@@ -1625,10 +1809,10 @@ process_arguments (int argc, char **argv)
1625 } 1809 }
1626 break; 1810 break;
1627 case 'E': /* show extended perfdata */ 1811 case 'E': /* show extended perfdata */
1628 show_extended_perfdata = TRUE; 1812 show_extended_perfdata = true;
1629 break; 1813 break;
1630 case 'B': /* print body content after status line */ 1814 case 'B': /* print body content after status line */
1631 show_body = TRUE; 1815 show_body = true;
1632 break; 1816 break;
1633 case HTTP_VERSION_OPTION: 1817 case HTTP_VERSION_OPTION:
1634 curl_http_version = CURL_HTTP_VERSION_NONE; 1818 curl_http_version = CURL_HTTP_VERSION_NONE;
@@ -1643,12 +1827,15 @@ process_arguments (int argc, char **argv)
1643 curl_http_version = CURL_HTTP_VERSION_NONE; 1827 curl_http_version = CURL_HTTP_VERSION_NONE;
1644#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1828#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1645 } else { 1829 } else {
1646 fprintf (stderr, "unkown http-version parameter: %s\n", optarg); 1830 fprintf (stderr, "unknown http-version parameter: %s\n", optarg);
1647 exit (STATE_WARNING); 1831 exit (STATE_WARNING);
1648 } 1832 }
1649 break; 1833 break;
1650 case AUTOMATIC_DECOMPRESSION: 1834 case AUTOMATIC_DECOMPRESSION:
1651 automatic_decompression = TRUE; 1835 automatic_decompression = true;
1836 break;
1837 case COOKIE_JAR:
1838 cookie_jar_file = optarg;
1652 break; 1839 break;
1653 case '?': 1840 case '?':
1654 /* print short usage statement if args not parsable */ 1841 /* print short usage statement if args not parsable */
@@ -1689,52 +1876,52 @@ process_arguments (int argc, char **argv)
1689 virtual_port = server_port; 1876 virtual_port = server_port;
1690 else { 1877 else {
1691 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT)) 1878 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1692 if(specify_port == FALSE) 1879 if(!specify_port)
1693 server_port = virtual_port; 1880 server_port = virtual_port;
1694 } 1881 }
1695 1882
1696 return TRUE; 1883 return true;
1697} 1884}
1698 1885
1699char *perfd_time (double elapsed_time) 1886char *perfd_time (double elapsed_time)
1700{ 1887{
1701 return fperfdata ("time", elapsed_time, "s", 1888 return fperfdata ("time", elapsed_time, "s",
1702 thlds->warning?TRUE:FALSE, thlds->warning?thlds->warning->end:0, 1889 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1703 thlds->critical?TRUE:FALSE, thlds->critical?thlds->critical->end:0, 1890 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1704 TRUE, 0, TRUE, socket_timeout); 1891 true, 0, true, socket_timeout);
1705} 1892}
1706 1893
1707char *perfd_time_connect (double elapsed_time_connect) 1894char *perfd_time_connect (double elapsed_time_connect)
1708{ 1895{
1709 return fperfdata ("time_connect", elapsed_time_connect, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1896 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1710} 1897}
1711 1898
1712char *perfd_time_ssl (double elapsed_time_ssl) 1899char *perfd_time_ssl (double elapsed_time_ssl)
1713{ 1900{
1714 return fperfdata ("time_ssl", elapsed_time_ssl, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1901 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1715} 1902}
1716 1903
1717char *perfd_time_headers (double elapsed_time_headers) 1904char *perfd_time_headers (double elapsed_time_headers)
1718{ 1905{
1719 return fperfdata ("time_headers", elapsed_time_headers, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1906 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1720} 1907}
1721 1908
1722char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1909char *perfd_time_firstbyte (double elapsed_time_firstbyte)
1723{ 1910{
1724 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1911 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1725} 1912}
1726 1913
1727char *perfd_time_transfer (double elapsed_time_transfer) 1914char *perfd_time_transfer (double elapsed_time_transfer)
1728{ 1915{
1729 return fperfdata ("time_transfer", elapsed_time_transfer, "s", FALSE, 0, FALSE, 0, FALSE, 0, TRUE, socket_timeout); 1916 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1730} 1917}
1731 1918
1732char *perfd_size (int page_len) 1919char *perfd_size (int page_len)
1733{ 1920{
1734 return perfdata ("size", page_len, "B", 1921 return perfdata ("size", page_len, "B",
1735 (min_page_len>0?TRUE:FALSE), min_page_len, 1922 (min_page_len>0?true:false), min_page_len,
1736 (min_page_len>0?TRUE:FALSE), 0, 1923 (min_page_len>0?true:false), 0,
1737 TRUE, 0, FALSE, 0); 1924 true, 0, false, 0);
1738} 1925}
1739 1926
1740void 1927void
@@ -1791,7 +1978,11 @@ print_help (void)
1791#endif 1978#endif
1792 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1979 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
1793 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443")); 1980 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443"));
1794 printf (" %s\n", _("(when this option is used the URL is not checked.)")); 1981 printf (" %s\n", _("(when this option is used the URL is not checked by default. You can use"));
1982 printf (" %s\n", _(" --continue-after-certificate to override this behavior)"));
1983 printf (" %s\n", "--continue-after-certificate");
1984 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
1985 printf (" %s\n", _("Does nothing unless -C is used."));
1795 printf (" %s\n", "-J, --client-cert=FILE"); 1986 printf (" %s\n", "-J, --client-cert=FILE");
1796 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1987 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)"));
1797 printf (" %s\n", _("to be used in establishing the SSL session")); 1988 printf (" %s\n", _("to be used in establishing the SSL session"));
@@ -1854,6 +2045,9 @@ print_help (void)
1854 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 2045 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
1855 printf (" %s\n", _("follow uses the old redirection algorithm of check_http.")); 2046 printf (" %s\n", _("follow uses the old redirection algorithm of check_http."));
1856 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl.")); 2047 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
2048 printf (" %s\n", "--max-redirs=INTEGER");
2049 printf (" %s", _("Maximal number of redirects (default: "));
2050 printf ("%d)\n", DEFAULT_MAX_REDIRS);
1857 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 2051 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
1858 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 2052 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
1859 printf ("\n"); 2053 printf ("\n");
@@ -1862,6 +2056,8 @@ print_help (void)
1862 printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); 2056 printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
1863 printf (" %s\n", "--enable-automatic-decompression"); 2057 printf (" %s\n", "--enable-automatic-decompression");
1864 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); 2058 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2059 printf (" %s\n", "---cookie-jar=FILE");
2060 printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
1865 printf ("\n"); 2061 printf ("\n");
1866 2062
1867 printf (UT_WARN_CRIT); 2063 printf (UT_WARN_CRIT);
@@ -1941,12 +2137,13 @@ print_usage (void)
1941 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 2137 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname);
1942 printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n"); 2138 printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
1943 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 2139 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
1944 printf (" [-b proxy_auth] [-f <ok|warning|critcal|follow|sticky|stickyport|curl>]\n"); 2140 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
1945 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 2141 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
1946 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 2142 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
1947 printf (" [-A string] [-k string] [-S <version>] [--sni]\n"); 2143 printf (" [-A string] [-k string] [-S <version>] [--sni]\n");
1948 printf (" [-T <content-type>] [-j method]\n"); 2144 printf (" [-T <content-type>] [-j method]\n");
1949 printf (" [--http-version=<version>]\n"); 2145 printf (" [--http-version=<version>] [--enable-automatic-decompression]\n");
2146 printf (" [--cookie-jar=<cookie jar file>\n");
1950 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname); 2147 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
1951 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n"); 2148 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
1952 printf ("\n"); 2149 printf ("\n");
@@ -1980,9 +2177,12 @@ curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *s
1980 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream; 2177 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
1981 2178
1982 while (buf->bufsize < buf->buflen + size * nmemb + 1) { 2179 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
1983 buf->bufsize *= buf->bufsize * 2; 2180 buf->bufsize = buf->bufsize * 2;
1984 buf->buf = (char *)realloc (buf->buf, buf->bufsize); 2181 buf->buf = (char *)realloc (buf->buf, buf->bufsize);
1985 if (buf->buf == NULL) return -1; 2182 if (buf->buf == NULL) {
2183 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2184 return -1;
2185 }
1986 } 2186 }
1987 2187
1988 memcpy (buf->buf + buf->buflen, buffer, size * nmemb); 2188 memcpy (buf->buf + buf->buflen, buffer, size * nmemb);
@@ -2103,11 +2303,10 @@ curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line)
2103 if( strchr( p, '.' ) != NULL ) { 2303 if( strchr( p, '.' ) != NULL ) {
2104 2304
2105 /* HTTP 1.x case */ 2305 /* HTTP 1.x case */
2106 char *ppp; 2306 strtok( p, "." );
2107 ppp = strtok( p, "." );
2108 status_line->http_major = (int)strtol( p, &pp, 10 ); 2307 status_line->http_major = (int)strtol( p, &pp, 10 );
2109 if( *pp != '\0' ) { free( first_line_buf ); return -1; } 2308 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2110 ppp = strtok( NULL, " " ); 2309 strtok( NULL, " " );
2111 status_line->http_minor = (int)strtol( p, &pp, 10 ); 2310 status_line->http_minor = (int)strtol( p, &pp, 10 );
2112 if( *pp != '\0' ) { free( first_line_buf ); return -1; } 2311 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2113 p += 4; /* 1.x SP */ 2312 p += 4; /* 1.x SP */
@@ -2188,43 +2387,73 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2188 size_t msglen; 2387 size_t msglen;
2189 2388
2190 int res = phr_parse_response (header_buf->buf, header_buf->buflen, 2389 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2191 &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen, 2390 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2192 headers, &nof_headers, 0); 2391 headers, &nof_headers, 0);
2193 2392
2194 server_date = get_header_value (headers, nof_headers, "date"); 2393 server_date = get_header_value (headers, nof_headers, "date");
2195 document_date = get_header_value (headers, nof_headers, "last-modified"); 2394 document_date = get_header_value (headers, nof_headers, "last-modified");
2196 2395
2197 if (!server_date || !*server_date) { 2396 if (!server_date || !*server_date) {
2198 snprintf (*msg, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg); 2397 char tmp[DEFAULT_BUFFER_SIZE];
2199 date_result = max_state_alt(STATE_UNKNOWN, date_result); 2398
2200 } else if (!document_date || !*document_date) { 2399 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
2201 snprintf (*msg, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg); 2400 strcpy(*msg, tmp);
2202 date_result = max_state_alt(STATE_CRITICAL, date_result); 2401
2402 date_result = max_state_alt(STATE_UNKNOWN, date_result);
2403
2404 } else if (!document_date || !*document_date) {
2405 char tmp[DEFAULT_BUFFER_SIZE];
2406
2407 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
2408 strcpy(*msg, tmp);
2409
2410 date_result = max_state_alt(STATE_CRITICAL, date_result);
2411
2203 } else { 2412 } else {
2204 time_t srv_data = curl_getdate (server_date, NULL); 2413 time_t srv_data = curl_getdate (server_date, NULL);
2205 time_t doc_data = curl_getdate (document_date, NULL); 2414 time_t doc_data = curl_getdate (document_date, NULL);
2206 if (verbose >= 2) 2415 if (verbose >= 2)
2207 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 2416 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2208 if (srv_data <= 0) { 2417 if (srv_data <= 0) {
2209 snprintf (*msg, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 2418 char tmp[DEFAULT_BUFFER_SIZE];
2210 date_result = max_state_alt(STATE_CRITICAL, date_result); 2419
2211 } else if (doc_data <= 0) { 2420 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
2212 snprintf (*msg, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 2421 strcpy(*msg, tmp);
2213 date_result = max_state_alt(STATE_CRITICAL, date_result); 2422
2214 } else if (doc_data > srv_data + 30) { 2423 date_result = max_state_alt(STATE_CRITICAL, date_result);
2215 snprintf (*msg, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 2424 } else if (doc_data <= 0) {
2216 date_result = max_state_alt(STATE_CRITICAL, date_result); 2425 char tmp[DEFAULT_BUFFER_SIZE];
2217 } else if (doc_data < srv_data - maximum_age) { 2426
2218 int n = (srv_data - doc_data); 2427 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
2219 if (n > (60 * 60 * 24 * 2)) { 2428 strcpy(*msg, tmp);
2220 snprintf (*msg, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 2429
2221 date_result = max_state_alt(STATE_CRITICAL, date_result); 2430 date_result = max_state_alt(STATE_CRITICAL, date_result);
2222 } else { 2431 } else if (doc_data > srv_data + 30) {
2223 snprintf (*msg, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 2432 char tmp[DEFAULT_BUFFER_SIZE];
2224 date_result = max_state_alt(STATE_CRITICAL, date_result); 2433
2225 } 2434 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
2226 } 2435 strcpy(*msg, tmp);
2227 } 2436
2437 date_result = max_state_alt(STATE_CRITICAL, date_result);
2438 } else if (doc_data < srv_data - maximum_age) {
2439 int n = (srv_data - doc_data);
2440 if (n > (60 * 60 * 24 * 2)) {
2441 char tmp[DEFAULT_BUFFER_SIZE];
2442
2443 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24));
2444 strcpy(*msg, tmp);
2445
2446 date_result = max_state_alt(STATE_CRITICAL, date_result);
2447 } else {
2448 char tmp[DEFAULT_BUFFER_SIZE];
2449
2450 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
2451 strcpy(*msg, tmp);
2452
2453 date_result = max_state_alt(STATE_CRITICAL, date_result);
2454 }
2455 }
2456 }
2228 2457
2229 if (server_date) free (server_date); 2458 if (server_date) free (server_date);
2230 if (document_date) free (document_date); 2459 if (document_date) free (document_date);
@@ -2246,7 +2475,7 @@ get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_wri
2246 curlhelp_statusline status_line; 2475 curlhelp_statusline status_line;
2247 2476
2248 int res = phr_parse_response (header_buf->buf, header_buf->buflen, 2477 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2249 &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen, 2478 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2250 headers, &nof_headers, 0); 2479 headers, &nof_headers, 0);
2251 2480
2252 content_length_s = get_header_value (headers, nof_headers, "content-length"); 2481 content_length_s = get_header_value (headers, nof_headers, "content-length");
@@ -2266,7 +2495,7 @@ get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_wri
2266 2495
2267/* TODO: is there a better way in libcurl to check for the SSL library? */ 2496/* TODO: is there a better way in libcurl to check for the SSL library? */
2268curlhelp_ssl_library 2497curlhelp_ssl_library
2269curlhelp_get_ssl_library (CURL* curl) 2498curlhelp_get_ssl_library ()
2270{ 2499{
2271 curl_version_info_data* version_data; 2500 curl_version_info_data* version_data;
2272 char *ssl_version; 2501 char *ssl_version;