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