diff options
author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-09-11 13:44:55 +0200 |
---|---|---|
committer | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-09-11 13:44:55 +0200 |
commit | 99206dab7aa272e5c16c672dca81e6044ac7a4eb (patch) | |
tree | 4741f0d1cb261a9d13ab705f71522fbbf3db059b | |
parent | 6969f5719268dec6459d9107e11a711dab3a18dd (diff) | |
download | monitoring-plugins-99206dab7aa272e5c16c672dca81e6044ac7a4eb.tar.gz |
check_curl: refactoring to modularize code
-rw-r--r-- | plugins/check_curl.c | 1055 | ||||
-rw-r--r-- | plugins/check_curl.d/config.h | 78 |
2 files changed, 594 insertions, 539 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 485a8744..f3cf7422 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c | |||
@@ -129,6 +129,9 @@ typedef struct { | |||
129 | bool put_buf_initialized; | 129 | bool put_buf_initialized; |
130 | curlhelp_read_curlbuf put_buf; | 130 | curlhelp_read_curlbuf put_buf; |
131 | CURL *curl; | 131 | CURL *curl; |
132 | |||
133 | struct curl_slist *header_list; | ||
134 | struct curl_slist *host; | ||
132 | } check_curl_global_state; | 135 | } check_curl_global_state; |
133 | 136 | ||
134 | static char errbuf[MAX_INPUT_BUFFER]; | 137 | static char errbuf[MAX_INPUT_BUFFER]; |
@@ -152,8 +155,7 @@ static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv* | |||
152 | 155 | ||
153 | static void handle_curl_option_return_code(CURLcode res, const char *option); | 156 | static void handle_curl_option_return_code(CURLcode res, const char *option); |
154 | static mp_state_enum check_http(check_curl_config /*config*/, check_curl_working_state workingState, | 157 | static mp_state_enum check_http(check_curl_config /*config*/, check_curl_working_state workingState, |
155 | int redir_depth, struct curl_slist *header_list, | 158 | int redir_depth); |
156 | check_curl_global_state global_state); | ||
157 | 159 | ||
158 | typedef struct { | 160 | typedef struct { |
159 | int redir_depth; | 161 | int redir_depth; |
@@ -162,8 +164,7 @@ typedef struct { | |||
162 | check_curl_global_state curl_state; | 164 | check_curl_global_state curl_state; |
163 | } redir_wrapper; | 165 | } redir_wrapper; |
164 | static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, | 166 | static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, |
165 | int redir_depth, check_curl_working_state working_state, | 167 | int redir_depth, check_curl_working_state working_state); |
166 | check_curl_global_state global_state); | ||
167 | 168 | ||
168 | static char *perfd_time(double elapsed_time, thresholds * /*thlds*/, long /*socket_timeout*/); | 169 | static char *perfd_time(double elapsed_time, thresholds * /*thlds*/, long /*socket_timeout*/); |
169 | static char *perfd_time_connect(double elapsed_time_connect, long /*socket_timeout*/); | 170 | static char *perfd_time_connect(double elapsed_time_connect, long /*socket_timeout*/); |
@@ -172,371 +173,169 @@ static char *perfd_time_firstbyte(double elapsed_time_firstbyte, long /*socket_t | |||
172 | static char *perfd_time_headers(double elapsed_time_headers, long /*socket_timeout*/); | 173 | static char *perfd_time_headers(double elapsed_time_headers, long /*socket_timeout*/); |
173 | static char *perfd_time_transfer(double elapsed_time_transfer, long /*socket_timeout*/); | 174 | static char *perfd_time_transfer(double elapsed_time_transfer, long /*socket_timeout*/); |
174 | static char *perfd_size(size_t page_len, int /*min_page_len*/); | 175 | static char *perfd_size(size_t page_len, int /*min_page_len*/); |
176 | |||
175 | static void print_help(void); | 177 | static void print_help(void); |
176 | void print_usage(void); | 178 | void print_usage(void); |
179 | |||
177 | static void print_curl_version(void); | 180 | static void print_curl_version(void); |
181 | |||
178 | static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/); | 182 | static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/); |
179 | static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, | 183 | static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, |
180 | void * /*stream*/); | 184 | void * /*stream*/); |
181 | static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/); | 185 | static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/); |
186 | |||
182 | static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/, | 187 | static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/, |
183 | size_t /*datalen*/); | 188 | size_t /*datalen*/); |
184 | static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, | 189 | static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, |
185 | void * /*stream*/); | 190 | void * /*stream*/); |
186 | static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/); | 191 | static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/); |
192 | |||
187 | static curlhelp_ssl_library curlhelp_get_ssl_library(void); | 193 | static curlhelp_ssl_library curlhelp_get_ssl_library(void); |
188 | static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/); | 194 | static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/); |
195 | |||
189 | int net_noopenssl_check_certificate(cert_ptr_union *, int, int); | 196 | int net_noopenssl_check_certificate(cert_ptr_union *, int, int); |
190 | 197 | ||
191 | static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/); | 198 | static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/); |
192 | static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/); | 199 | static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/); |
200 | |||
193 | static char *get_header_value(const struct phr_header *headers, size_t nof_headers, | 201 | static char *get_header_value(const struct phr_header *headers, size_t nof_headers, |
194 | const char *header); | 202 | const char *header); |
195 | static mp_state_enum check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, | 203 | static mp_state_enum check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, |
196 | char (*msg)[DEFAULT_BUFFER_SIZE], int /*maximum_age*/); | 204 | char (*msg)[DEFAULT_BUFFER_SIZE], int /*maximum_age*/); |
197 | static size_t get_content_length(const curlhelp_write_curlbuf *header_buf, | 205 | static size_t get_content_length(const curlhelp_write_curlbuf *header_buf, |
198 | const curlhelp_write_curlbuf *body_buf); | 206 | const curlhelp_write_curlbuf *body_buf); |
207 | static int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family); | ||
199 | 208 | ||
200 | #if defined(HAVE_SSL) && defined(USE_OPENSSL) | 209 | // typedef struct { |
201 | mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, | 210 | // int errorcode; |
202 | int days_till_exp_crit); | 211 | // } check_curl_evaluation_wrapper; |
203 | #endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ | 212 | // check_curl_evaluation_wrapper check_curl_evaluate(check_curl_config config, |
204 | 213 | // mp_check overall[static 1]) {} | |
205 | static void test_file(char * /*path*/); | ||
206 | |||
207 | int main(int argc, char **argv) { | ||
208 | setlocale(LC_ALL, ""); | ||
209 | bindtextdomain(PACKAGE, LOCALEDIR); | ||
210 | textdomain(PACKAGE); | ||
211 | |||
212 | /* Parse extra opts if any */ | ||
213 | argv = np_extra_opts(&argc, argv, progname); | ||
214 | |||
215 | /* parse arguments */ | ||
216 | check_curl_config_wrapper tmp_config = process_arguments(argc, argv); | ||
217 | if (tmp_config.errorcode == ERROR) { | ||
218 | usage4(_("Could not parse arguments")); | ||
219 | } | ||
220 | |||
221 | const check_curl_config config = tmp_config.config; | ||
222 | |||
223 | /* set defaults */ | ||
224 | if (strlen(config.user_agent) == 0) { | ||
225 | snprintf(config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", | ||
226 | progname, NP_VERSION, VERSION, curl_version()); | ||
227 | } | ||
228 | |||
229 | if (config.display_html) { | ||
230 | printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", | ||
231 | config.initial_config.use_ssl ? "https" : "http", | ||
232 | config.initial_config.host_name ? config.initial_config.host_name | ||
233 | : config.initial_config.server_address, | ||
234 | config.initial_config.virtualPort ? config.initial_config.virtualPort | ||
235 | : config.initial_config.serverPort, | ||
236 | config.initial_config.server_url); | ||
237 | } | ||
238 | |||
239 | check_curl_global_state global_state = { | ||
240 | .curl_global_initialized = false, | ||
241 | .curl_easy_initialized = false, | ||
242 | .body_buf_initialized = false, | ||
243 | .body_buf = {}, | ||
244 | .header_buf_initialized = false, | ||
245 | .header_buf = {}, | ||
246 | .status_line_initialized = false, | ||
247 | .status_line = {}, | ||
248 | .put_buf_initialized = false, | ||
249 | .put_buf = {}, | ||
250 | .curl = NULL, | ||
251 | }; | ||
252 | |||
253 | check_curl_working_state working_state = config.initial_config; | ||
254 | struct curl_slist *header_list = NULL; | ||
255 | 214 | ||
256 | exit((int)check_http(config, working_state, 0, header_list, global_state)); | 215 | CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm); |
257 | } | ||
258 | 216 | ||
259 | #ifdef HAVE_SSL | 217 | typedef struct { |
260 | # ifdef USE_OPENSSL | 218 | int errorcode; |
261 | int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { | 219 | check_curl_global_state curl_state; |
262 | (void)preverify_ok; | 220 | } check_curl_configure_curl_wrapper; |
263 | /* TODO: we get all certificates of the chain, so which ones | 221 | check_curl_configure_curl_wrapper |
264 | * should we test? | 222 | check_curl_configure_curl(const check_curl_static_curl_config config, |
265 | * TODO: is the last certificate always the server certificate? | 223 | check_curl_working_state working_state, bool check_cert, |
266 | */ | 224 | bool on_redirect_dependent, int follow_method, int max_depth) { |
267 | cert = X509_STORE_CTX_get_current_cert(x509_ctx); | 225 | check_curl_configure_curl_wrapper result = { |
268 | # if OPENSSL_VERSION_NUMBER >= 0x10100000L | 226 | .errorcode = OK, |
269 | X509_up_ref(cert); | 227 | .curl_state = |
270 | # endif | 228 | { |
271 | if (verbose >= 2) { | 229 | .curl_global_initialized = false, |
272 | puts("* SSL verify callback with certificate:"); | 230 | .curl_easy_initialized = false, |
273 | printf("* issuer:\n"); | 231 | .curl = NULL, |
274 | X509_NAME *issuer = X509_get_issuer_name(cert); | 232 | |
275 | X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); | 233 | .body_buf_initialized = false, |
276 | printf("* curl verify_callback:\n* subject:\n"); | 234 | .body_buf = {}, |
277 | X509_NAME *subject = X509_get_subject_name(cert); | 235 | .header_buf_initialized = false, |
278 | X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); | 236 | .header_buf = {}, |
279 | puts(""); | 237 | .status_line_initialized = false, |
280 | } | 238 | .status_line = {}, |
281 | return 1; | 239 | .put_buf_initialized = false, |
282 | } | 240 | .put_buf = {}, |
283 | 241 | ||
284 | CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) { | 242 | .header_list = NULL, |
285 | (void)curl; // ignore unused parameter | 243 | .host = NULL, |
286 | (void)parm; // ignore unused parameter | 244 | }, |
287 | if (add_sslctx_verify_fun) { | ||
288 | SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback); | ||
289 | } | ||
290 | |||
291 | // workaround for issue: | ||
292 | // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0 | ||
293 | // see discussion https://github.com/openssl/openssl/discussions/22690 | ||
294 | # ifdef SSL_OP_IGNORE_UNEXPECTED_EOF | ||
295 | SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF); | ||
296 | # endif | ||
297 | |||
298 | return CURLE_OK; | ||
299 | } | ||
300 | # endif /* USE_OPENSSL */ | ||
301 | #endif /* HAVE_SSL */ | ||
302 | |||
303 | /* returns a string "HTTP/1.x" or "HTTP/2" */ | ||
304 | static char *string_statuscode(int major, int minor) { | ||
305 | static char buf[10]; | ||
306 | |||
307 | switch (major) { | ||
308 | case 1: | ||
309 | snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor); | ||
310 | break; | ||
311 | case 2: | ||
312 | case 3: | ||
313 | snprintf(buf, sizeof(buf), "HTTP/%d", major); | ||
314 | break; | ||
315 | default: | ||
316 | /* assuming here HTTP/N with N>=4 */ | ||
317 | snprintf(buf, sizeof(buf), "HTTP/%d", major); | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | return buf; | ||
322 | } | ||
323 | |||
324 | /* Checks if the server 'reply' is one of the expected 'statuscodes' */ | ||
325 | static bool expected_statuscode(const char *reply, const char *statuscodes) { | ||
326 | char *expected; | ||
327 | |||
328 | if ((expected = strdup(statuscodes)) == NULL) { | ||
329 | die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); | ||
330 | } | ||
331 | |||
332 | bool result = false; | ||
333 | for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) { | ||
334 | if (strstr(reply, code) != NULL) { | ||
335 | result = true; | ||
336 | break; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | free(expected); | ||
341 | return result; | ||
342 | } | ||
343 | |||
344 | void handle_curl_option_return_code(CURLcode res, const char *option) { | ||
345 | if (res != CURLE_OK) { | ||
346 | snprintf(msg, DEFAULT_BUFFER_SIZE, | ||
347 | _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res, | ||
348 | curl_easy_strerror(res)); | ||
349 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) { | ||
354 | struct addrinfo hints = { | ||
355 | .ai_family = addr_family, | ||
356 | .ai_socktype = SOCK_STREAM, | ||
357 | .ai_flags = AI_CANONNAME, | ||
358 | }; | 245 | }; |
359 | 246 | ||
360 | struct addrinfo *result; | ||
361 | int errcode = getaddrinfo(host, NULL, &hints, &result); | ||
362 | if (errcode != 0) { | ||
363 | return errcode; | ||
364 | } | ||
365 | |||
366 | strcpy(buf, ""); | ||
367 | struct addrinfo *res = result; | ||
368 | |||
369 | size_t buflen_remaining = buflen - 1; | ||
370 | size_t addrstr_len; | ||
371 | char addrstr[100]; | ||
372 | void *ptr = {0}; | ||
373 | while (res) { | ||
374 | switch (res->ai_family) { | ||
375 | case AF_INET: | ||
376 | ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; | ||
377 | break; | ||
378 | case AF_INET6: | ||
379 | ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | inet_ntop(res->ai_family, ptr, addrstr, 100); | ||
384 | if (verbose >= 1) { | ||
385 | printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4, | ||
386 | addrstr); | ||
387 | } | ||
388 | |||
389 | // Append all IPs to buf as a comma-separated string | ||
390 | addrstr_len = strlen(addrstr); | ||
391 | if (buflen_remaining > addrstr_len + 1) { | ||
392 | if (buf[0] != '\0') { | ||
393 | strncat(buf, ",", buflen_remaining); | ||
394 | buflen_remaining -= 1; | ||
395 | } | ||
396 | strncat(buf, addrstr, buflen_remaining); | ||
397 | buflen_remaining -= addrstr_len; | ||
398 | } | ||
399 | |||
400 | res = res->ai_next; | ||
401 | } | ||
402 | |||
403 | freeaddrinfo(result); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static void cleanup(check_curl_global_state global_state) { | ||
409 | if (global_state.status_line_initialized) { | ||
410 | curlhelp_free_statusline(&global_state.status_line); | ||
411 | } | ||
412 | global_state.status_line_initialized = false; | ||
413 | |||
414 | if (global_state.curl_easy_initialized) { | ||
415 | curl_easy_cleanup(global_state.curl); | ||
416 | } | ||
417 | global_state.curl_easy_initialized = false; | ||
418 | |||
419 | if (global_state.curl_global_initialized) { | ||
420 | curl_global_cleanup(); | ||
421 | } | ||
422 | global_state.curl_global_initialized = false; | ||
423 | |||
424 | if (global_state.body_buf_initialized) { | ||
425 | curlhelp_freewritebuffer(&global_state.body_buf); | ||
426 | } | ||
427 | global_state.body_buf_initialized = false; | ||
428 | |||
429 | if (global_state.header_buf_initialized) { | ||
430 | curlhelp_freewritebuffer(&global_state.header_buf); | ||
431 | } | ||
432 | global_state.header_buf_initialized = false; | ||
433 | |||
434 | if (global_state.put_buf_initialized) { | ||
435 | curlhelp_freereadbuffer(&global_state.put_buf); | ||
436 | } | ||
437 | global_state.put_buf_initialized = false; | ||
438 | } | ||
439 | |||
440 | mp_state_enum check_http(const check_curl_config config, check_curl_working_state workingState, | ||
441 | int redir_depth, struct curl_slist *header_list, | ||
442 | check_curl_global_state global_state) { | ||
443 | |||
444 | // ======================= | ||
445 | // Initialisation for curl | ||
446 | // ======================= | ||
447 | /* initialize curl */ | ||
448 | if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { | 247 | if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) { |
449 | die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); | 248 | die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); |
450 | } | 249 | } |
451 | global_state.curl_global_initialized = true; | 250 | result.curl_state.curl_global_initialized = true; |
452 | 251 | ||
453 | if ((global_state.curl = curl_easy_init()) == NULL) { | 252 | if ((result.curl_state.curl = curl_easy_init()) == NULL) { |
454 | die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); | 253 | die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); |
455 | } | 254 | } |
456 | global_state.curl_easy_initialized = true; | 255 | result.curl_state.curl_easy_initialized = true; |
457 | 256 | ||
458 | if (verbose >= 1) { | 257 | if (verbose >= 1) { |
459 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_VERBOSE, 1), | 258 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1), |
460 | "CURLOPT_VERBOSE"); | 259 | "CURLOPT_VERBOSE"); |
461 | } | 260 | } |
462 | |||
463 | /* print everything on stdout like check_http would do */ | 261 | /* print everything on stdout like check_http would do */ |
464 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_STDERR, stdout), | 262 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_STDERR, stdout), |
465 | "CURLOPT_STDERR"); | 263 | "CURLOPT_STDERR"); |
466 | 264 | ||
467 | if (config.automatic_decompression) { | 265 | if (config.automatic_decompression) { |
468 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) | 266 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) |
469 | handle_curl_option_return_code( | 267 | handle_curl_option_return_code( |
470 | curl_easy_setopt(global_state.curl, CURLOPT_ACCEPT_ENCODING, ""), | 268 | curl_easy_setopt(result.curl_state.curl, CURLOPT_ACCEPT_ENCODING, ""), |
471 | "CURLOPT_ACCEPT_ENCODING"); | 269 | "CURLOPT_ACCEPT_ENCODING"); |
472 | #else | 270 | #else |
473 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ENCODING, ""), | 271 | handle_curl_option_return_code( |
474 | "CURLOPT_ENCODING"); | 272 | curl_easy_setopt(result.curl_state.curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING"); |
475 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ | 273 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ |
476 | } | 274 | } |
477 | 275 | ||
478 | /* initialize buffer for body of the answer */ | 276 | /* initialize buffer for body of the answer */ |
479 | if (curlhelp_initwritebuffer(&global_state.body_buf) < 0) { | 277 | if (curlhelp_initwritebuffer(&result.curl_state.body_buf) < 0) { |
480 | die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); | 278 | die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); |
481 | } | 279 | } |
482 | global_state.body_buf_initialized = true; | 280 | result.curl_state.body_buf_initialized = true; |
483 | handle_curl_option_return_code( | 281 | |
484 | curl_easy_setopt(global_state.curl, CURLOPT_WRITEFUNCTION, curlhelp_buffer_write_callback), | 282 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEFUNCTION, |
485 | "CURLOPT_WRITEFUNCTION"); | 283 | curlhelp_buffer_write_callback), |
486 | handle_curl_option_return_code( | 284 | "CURLOPT_WRITEFUNCTION"); |
487 | curl_easy_setopt(global_state.curl, CURLOPT_WRITEDATA, (void *)&global_state.body_buf), | 285 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEDATA, |
488 | "CURLOPT_WRITEDATA"); | 286 | (void *)&result.curl_state.body_buf), |
287 | "CURLOPT_WRITEDATA"); | ||
489 | 288 | ||
490 | /* initialize buffer for header of the answer */ | 289 | /* initialize buffer for header of the answer */ |
491 | if (curlhelp_initwritebuffer(&global_state.header_buf) < 0) { | 290 | if (curlhelp_initwritebuffer(&result.curl_state.header_buf) < 0) { |
492 | die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n"); | 291 | die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n"); |
493 | } | 292 | } |
494 | global_state.header_buf_initialized = true; | 293 | result.curl_state.header_buf_initialized = true; |
495 | 294 | ||
496 | handle_curl_option_return_code( | 295 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_HEADERFUNCTION, |
497 | curl_easy_setopt(global_state.curl, CURLOPT_HEADERFUNCTION, curlhelp_buffer_write_callback), | 296 | curlhelp_buffer_write_callback), |
498 | "CURLOPT_HEADERFUNCTION"); | 297 | "CURLOPT_HEADERFUNCTION"); |
499 | handle_curl_option_return_code( | 298 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_WRITEHEADER, |
500 | curl_easy_setopt(global_state.curl, CURLOPT_WRITEHEADER, (void *)&global_state.header_buf), | 299 | (void *)&result.curl_state.header_buf), |
501 | "CURLOPT_WRITEHEADER"); | 300 | "CURLOPT_WRITEHEADER"); |
502 | 301 | ||
503 | /* set the error buffer */ | 302 | /* set the error buffer */ |
504 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_ERRORBUFFER, errbuf), | 303 | handle_curl_option_return_code( |
505 | "CURLOPT_ERRORBUFFER"); | 304 | curl_easy_setopt(result.curl_state.curl, CURLOPT_ERRORBUFFER, errbuf), |
305 | "CURLOPT_ERRORBUFFER"); | ||
506 | 306 | ||
507 | /* set timeouts */ | 307 | /* set timeouts */ |
508 | handle_curl_option_return_code( | 308 | handle_curl_option_return_code( |
509 | curl_easy_setopt(global_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout), | 309 | curl_easy_setopt(result.curl_state.curl, CURLOPT_CONNECTTIMEOUT, config.socket_timeout), |
510 | "CURLOPT_CONNECTTIMEOUT"); | 310 | "CURLOPT_CONNECTTIMEOUT"); |
511 | handle_curl_option_return_code( | 311 | handle_curl_option_return_code( |
512 | curl_easy_setopt(global_state.curl, CURLOPT_TIMEOUT, config.socket_timeout), | 312 | curl_easy_setopt(result.curl_state.curl, CURLOPT_TIMEOUT, config.socket_timeout), |
513 | "CURLOPT_TIMEOUT"); | 313 | "CURLOPT_TIMEOUT"); |
514 | 314 | ||
515 | /* enable haproxy protocol */ | 315 | /* enable haproxy protocol */ |
516 | if (config.haproxy_protocol) { | 316 | if (config.haproxy_protocol) { |
517 | handle_curl_option_return_code( | 317 | handle_curl_option_return_code( |
518 | curl_easy_setopt(global_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L), | 318 | curl_easy_setopt(result.curl_state.curl, CURLOPT_HAPROXYPROTOCOL, 1L), |
519 | "CURLOPT_HAPROXYPROTOCOL"); | 319 | "CURLOPT_HAPROXYPROTOCOL"); |
520 | } | 320 | } |
521 | 321 | ||
522 | // fill dns resolve cache to make curl connect to the given server_address instead of the | 322 | // fill dns resolve cache to make curl connect to the given server_address instead of the |
523 | // host_name, only required for ssl, because we use the host_name later on to make SNI happy | 323 | // host_name, only required for ssl, because we use the host_name later on to make SNI happy |
524 | struct curl_slist *host = NULL; | ||
525 | char dnscache[DEFAULT_BUFFER_SIZE]; | 324 | char dnscache[DEFAULT_BUFFER_SIZE]; |
526 | char addrstr[DEFAULT_BUFFER_SIZE / 2]; | 325 | char addrstr[DEFAULT_BUFFER_SIZE / 2]; |
527 | if (workingState.use_ssl && workingState.host_name != NULL) { | 326 | if (working_state.use_ssl && working_state.host_name != NULL) { |
528 | int res; | 327 | int res; |
529 | if ((res = lookup_host(workingState.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2, | 328 | if ((res = lookup_host(working_state.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2, |
530 | config.sin_family)) != 0) { | 329 | config.sin_family)) != 0) { |
531 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 330 | snprintf(msg, DEFAULT_BUFFER_SIZE, |
532 | _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), | 331 | _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), |
533 | workingState.server_address, res, gai_strerror(res)); | 332 | working_state.server_address, res, gai_strerror(res)); |
534 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | 333 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); |
535 | } | 334 | } |
536 | snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", workingState.host_name, | 335 | snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", working_state.host_name, |
537 | workingState.serverPort, addrstr); | 336 | working_state.serverPort, addrstr); |
538 | host = curl_slist_append(NULL, dnscache); | 337 | result.curl_state.host = curl_slist_append(NULL, dnscache); |
539 | curl_easy_setopt(global_state.curl, CURLOPT_RESOLVE, host); | 338 | curl_easy_setopt(result.curl_state.curl, CURLOPT_RESOLVE, result.curl_state.host); |
540 | if (verbose >= 1) { | 339 | if (verbose >= 1) { |
541 | printf("* curl CURLOPT_RESOLVE: %s\n", dnscache); | 340 | printf("* curl CURLOPT_RESOLVE: %s\n", dnscache); |
542 | } | 341 | } |
@@ -544,72 +343,71 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
544 | 343 | ||
545 | // If server_address is an IPv6 address it must be surround by square brackets | 344 | // If server_address is an IPv6 address it must be surround by square brackets |
546 | struct in6_addr tmp_in_addr; | 345 | struct in6_addr tmp_in_addr; |
547 | if (inet_pton(AF_INET6, workingState.server_address, &tmp_in_addr) == 1) { | 346 | if (inet_pton(AF_INET6, working_state.server_address, &tmp_in_addr) == 1) { |
548 | char *new_server_address = malloc(strlen(workingState.server_address) + 3); | 347 | char *new_server_address = malloc(strlen(working_state.server_address) + 3); |
549 | if (new_server_address == NULL) { | 348 | if (new_server_address == NULL) { |
550 | die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); | 349 | die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); |
551 | } | 350 | } |
552 | snprintf(new_server_address, strlen(workingState.server_address) + 3, "[%s]", | 351 | snprintf(new_server_address, strlen(working_state.server_address) + 3, "[%s]", |
553 | workingState.server_address); | 352 | working_state.server_address); |
554 | free(workingState.server_address); | 353 | working_state.server_address = new_server_address; |
555 | workingState.server_address = new_server_address; | ||
556 | } | 354 | } |
557 | 355 | ||
558 | /* compose URL: use the address we want to connect to, set Host: header later */ | 356 | /* compose URL: use the address we want to connect to, set Host: header later */ |
559 | char url[DEFAULT_BUFFER_SIZE]; | 357 | char url[DEFAULT_BUFFER_SIZE]; |
560 | snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", workingState.use_ssl ? "https" : "http", | 358 | snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", working_state.use_ssl ? "https" : "http", |
561 | (workingState.use_ssl & (workingState.host_name != NULL)) | 359 | (working_state.use_ssl & (working_state.host_name != NULL)) |
562 | ? workingState.host_name | 360 | ? working_state.host_name |
563 | : workingState.server_address, | 361 | : working_state.server_address, |
564 | workingState.serverPort, workingState.server_url); | 362 | working_state.serverPort, working_state.server_url); |
565 | 363 | ||
566 | if (verbose >= 1) { | 364 | if (verbose >= 1) { |
567 | printf("* curl CURLOPT_URL: %s\n", url); | 365 | printf("* curl CURLOPT_URL: %s\n", url); |
568 | } | 366 | } |
569 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_URL, url), | 367 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, url), |
570 | "CURLOPT_URL"); | 368 | "CURLOPT_URL"); |
571 | 369 | ||
572 | /* extract proxy information for legacy proxy https requests */ | 370 | /* extract proxy information for legacy proxy https requests */ |
573 | if (!strcmp(workingState.http_method, "CONNECT") || | 371 | if (!strcmp(working_state.http_method, "CONNECT") || |
574 | strstr(workingState.server_url, "http") == workingState.server_url) { | 372 | strstr(working_state.server_url, "http") == working_state.server_url) { |
575 | handle_curl_option_return_code( | 373 | handle_curl_option_return_code( |
576 | curl_easy_setopt(global_state.curl, CURLOPT_PROXY, workingState.server_address), | 374 | curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXY, working_state.server_address), |
577 | "CURLOPT_PROXY"); | 375 | "CURLOPT_PROXY"); |
578 | handle_curl_option_return_code( | 376 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYPORT, |
579 | curl_easy_setopt(global_state.curl, CURLOPT_PROXYPORT, (long)workingState.serverPort), | 377 | (long)working_state.serverPort), |
580 | "CURLOPT_PROXYPORT"); | 378 | "CURLOPT_PROXYPORT"); |
581 | if (verbose >= 2) { | 379 | if (verbose >= 2) { |
582 | printf("* curl CURLOPT_PROXY: %s:%d\n", workingState.server_address, | 380 | printf("* curl CURLOPT_PROXY: %s:%d\n", working_state.server_address, |
583 | workingState.serverPort); | 381 | working_state.serverPort); |
584 | } | 382 | } |
585 | workingState.http_method = "GET"; | 383 | working_state.http_method = "GET"; |
586 | handle_curl_option_return_code( | 384 | handle_curl_option_return_code( |
587 | curl_easy_setopt(global_state.curl, CURLOPT_URL, workingState.server_url), | 385 | curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, working_state.server_url), |
588 | "CURLOPT_URL"); | 386 | "CURLOPT_URL"); |
589 | } | 387 | } |
590 | 388 | ||
591 | /* disable body for HEAD request */ | 389 | /* disable body for HEAD request */ |
592 | if (workingState.http_method && !strcmp(workingState.http_method, "HEAD")) { | 390 | if (working_state.http_method && !strcmp(working_state.http_method, "HEAD")) { |
593 | workingState.no_body = true; | 391 | working_state.no_body = true; |
594 | } | 392 | } |
595 | 393 | ||
596 | /* set HTTP protocol version */ | 394 | /* set HTTP protocol version */ |
597 | handle_curl_option_return_code( | 395 | handle_curl_option_return_code( |
598 | curl_easy_setopt(global_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version), | 396 | curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTP_VERSION, config.curl_http_version), |
599 | "CURLOPT_HTTP_VERSION"); | 397 | "CURLOPT_HTTP_VERSION"); |
600 | 398 | ||
601 | /* set HTTP method */ | 399 | /* set HTTP method */ |
602 | if (workingState.http_method) { | 400 | if (working_state.http_method) { |
603 | if (!strcmp(workingState.http_method, "POST")) { | 401 | if (!strcmp(working_state.http_method, "POST")) { |
604 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POST, 1), | 402 | handle_curl_option_return_code( |
605 | "CURLOPT_POST"); | 403 | curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1), "CURLOPT_POST"); |
606 | } else if (!strcmp(workingState.http_method, "PUT")) { | 404 | } else if (!strcmp(working_state.http_method, "PUT")) { |
607 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_UPLOAD, 1), | 405 | handle_curl_option_return_code( |
608 | "CURLOPT_UPLOAD"); | 406 | curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); |
609 | } else { | 407 | } else { |
610 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, | 408 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, |
611 | CURLOPT_CUSTOMREQUEST, | 409 | CURLOPT_CUSTOMREQUEST, |
612 | workingState.http_method), | 410 | working_state.http_method), |
613 | "CURLOPT_CUSTOMREQUEST"); | 411 | "CURLOPT_CUSTOMREQUEST"); |
614 | } | 412 | } |
615 | } | 413 | } |
@@ -627,67 +425,71 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
627 | /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in | 425 | /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in |
628 | * anyway */ | 426 | * anyway */ |
629 | char http_header[DEFAULT_BUFFER_SIZE]; | 427 | char http_header[DEFAULT_BUFFER_SIZE]; |
630 | if (workingState.host_name != NULL && force_host_header == NULL) { | 428 | if (working_state.host_name != NULL && force_host_header == NULL) { |
631 | if ((workingState.virtualPort != HTTP_PORT && !workingState.use_ssl) || | 429 | if ((working_state.virtualPort != HTTP_PORT && !working_state.use_ssl) || |
632 | (workingState.virtualPort != HTTPS_PORT && workingState.use_ssl)) { | 430 | (working_state.virtualPort != HTTPS_PORT && working_state.use_ssl)) { |
633 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", workingState.host_name, | 431 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", working_state.host_name, |
634 | workingState.virtualPort); | 432 | working_state.virtualPort); |
635 | } else { | 433 | } else { |
636 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", workingState.host_name); | 434 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", working_state.host_name); |
637 | } | 435 | } |
638 | header_list = curl_slist_append(header_list, http_header); | 436 | result.curl_state.header_list = |
437 | curl_slist_append(result.curl_state.header_list, http_header); | ||
639 | } | 438 | } |
640 | 439 | ||
641 | /* always close connection, be nice to servers */ | 440 | /* always close connection, be nice to servers */ |
642 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); | 441 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); |
643 | header_list = curl_slist_append(header_list, http_header); | 442 | result.curl_state.header_list = curl_slist_append(result.curl_state.header_list, http_header); |
644 | 443 | ||
645 | /* attach additional headers supplied by the user */ | 444 | /* attach additional headers supplied by the user */ |
646 | /* optionally send any other header tag */ | 445 | /* optionally send any other header tag */ |
647 | if (config.http_opt_headers_count) { | 446 | if (config.http_opt_headers_count) { |
648 | for (size_t i = 0; i < config.http_opt_headers_count; i++) { | 447 | for (size_t i = 0; i < config.http_opt_headers_count; i++) { |
649 | header_list = curl_slist_append(header_list, config.http_opt_headers[i]); | 448 | result.curl_state.header_list = |
449 | curl_slist_append(result.curl_state.header_list, config.http_opt_headers[i]); | ||
650 | } | 450 | } |
651 | } | 451 | } |
652 | 452 | ||
653 | /* set HTTP headers */ | 453 | /* set HTTP headers */ |
654 | handle_curl_option_return_code( | 454 | handle_curl_option_return_code( |
655 | curl_easy_setopt(global_state.curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER"); | 455 | curl_easy_setopt(result.curl_state.curl, CURLOPT_HTTPHEADER, result.curl_state.header_list), |
456 | "CURLOPT_HTTPHEADER"); | ||
656 | 457 | ||
657 | #ifdef LIBCURL_FEATURE_SSL | 458 | #ifdef LIBCURL_FEATURE_SSL |
658 | /* set SSL version, warn about insecure or unsupported versions */ | 459 | /* set SSL version, warn about insecure or unsupported versions */ |
659 | if (workingState.use_ssl) { | 460 | if (working_state.use_ssl) { |
660 | handle_curl_option_return_code( | 461 | handle_curl_option_return_code( |
661 | curl_easy_setopt(global_state.curl, CURLOPT_SSLVERSION, config.ssl_version), | 462 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLVERSION, config.ssl_version), |
662 | "CURLOPT_SSLVERSION"); | 463 | "CURLOPT_SSLVERSION"); |
663 | } | 464 | } |
664 | 465 | ||
665 | /* client certificate and key to present to server (SSL) */ | 466 | /* client certificate and key to present to server (SSL) */ |
666 | if (config.client_cert) { | 467 | if (config.client_cert) { |
667 | handle_curl_option_return_code( | 468 | handle_curl_option_return_code( |
668 | curl_easy_setopt(global_state.curl, CURLOPT_SSLCERT, config.client_cert), | 469 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLCERT, config.client_cert), |
669 | "CURLOPT_SSLCERT"); | 470 | "CURLOPT_SSLCERT"); |
670 | } | 471 | } |
671 | 472 | ||
672 | if (config.client_privkey) { | 473 | if (config.client_privkey) { |
673 | handle_curl_option_return_code( | 474 | handle_curl_option_return_code( |
674 | curl_easy_setopt(global_state.curl, CURLOPT_SSLKEY, config.client_privkey), | 475 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSLKEY, config.client_privkey), |
675 | "CURLOPT_SSLKEY"); | 476 | "CURLOPT_SSLKEY"); |
676 | } | 477 | } |
677 | 478 | ||
678 | if (config.ca_cert) { | 479 | if (config.ca_cert) { |
679 | handle_curl_option_return_code( | 480 | handle_curl_option_return_code( |
680 | curl_easy_setopt(global_state.curl, CURLOPT_CAINFO, config.ca_cert), "CURLOPT_CAINFO"); | 481 | curl_easy_setopt(result.curl_state.curl, CURLOPT_CAINFO, config.ca_cert), |
482 | "CURLOPT_CAINFO"); | ||
681 | } | 483 | } |
682 | 484 | ||
683 | if (config.ca_cert || config.verify_peer_and_host) { | 485 | if (config.ca_cert || config.verify_peer_and_host) { |
684 | /* per default if we have a CA verify both the peer and the | 486 | /* per default if we have a CA verify both the peer and the |
685 | * hostname in the certificate, can be switched off later */ | 487 | * hostname in the certificate, can be switched off later */ |
686 | handle_curl_option_return_code( | 488 | handle_curl_option_return_code( |
687 | curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 1), | 489 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1), |
688 | "CURLOPT_SSL_VERIFYPEER"); | 490 | "CURLOPT_SSL_VERIFYPEER"); |
689 | handle_curl_option_return_code( | 491 | handle_curl_option_return_code( |
690 | curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 2), | 492 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2), |
691 | "CURLOPT_SSL_VERIFYHOST"); | 493 | "CURLOPT_SSL_VERIFYHOST"); |
692 | } else { | 494 | } else { |
693 | /* backward-compatible behaviour, be tolerant in checks | 495 | /* backward-compatible behaviour, be tolerant in checks |
@@ -695,10 +497,10 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
695 | * to be less tolerant about ssl verfications | 497 | * to be less tolerant about ssl verfications |
696 | */ | 498 | */ |
697 | handle_curl_option_return_code( | 499 | handle_curl_option_return_code( |
698 | curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYPEER, 0), | 500 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0), |
699 | "CURLOPT_SSL_VERIFYPEER"); | 501 | "CURLOPT_SSL_VERIFYPEER"); |
700 | handle_curl_option_return_code( | 502 | handle_curl_option_return_code( |
701 | curl_easy_setopt(global_state.curl, CURLOPT_SSL_VERIFYHOST, 0), | 503 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0), |
702 | "CURLOPT_SSL_VERIFYHOST"); | 504 | "CURLOPT_SSL_VERIFYHOST"); |
703 | } | 505 | } |
704 | 506 | ||
@@ -706,7 +508,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
706 | curlhelp_ssl_library ssl_library = curlhelp_get_ssl_library(); | 508 | curlhelp_ssl_library ssl_library = curlhelp_get_ssl_library(); |
707 | 509 | ||
708 | /* try hard to get a stack of certificates to verify against */ | 510 | /* try hard to get a stack of certificates to verify against */ |
709 | if (config.check_cert) { | 511 | if (check_cert) { |
710 | # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) | 512 | # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) |
711 | /* inform curl to report back certificates */ | 513 | /* inform curl to report back certificates */ |
712 | switch (ssl_library) { | 514 | switch (ssl_library) { |
@@ -722,14 +524,14 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
722 | /* libcurl is built with OpenSSL, monitoring plugins, so falling | 524 | /* libcurl is built with OpenSSL, monitoring plugins, so falling |
723 | * back to manually extracting certificate information */ | 525 | * back to manually extracting certificate information */ |
724 | handle_curl_option_return_code( | 526 | handle_curl_option_return_code( |
725 | curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); | 527 | curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); |
726 | break; | 528 | break; |
727 | 529 | ||
728 | case CURLHELP_SSL_LIBRARY_NSS: | 530 | case CURLHELP_SSL_LIBRARY_NSS: |
729 | # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) | 531 | # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) |
730 | /* NSS: support for CERTINFO is implemented since 7.34.0 */ | 532 | /* NSS: support for CERTINFO is implemented since 7.34.0 */ |
731 | handle_curl_option_return_code( | 533 | handle_curl_option_return_code( |
732 | curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); | 534 | curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); |
733 | # else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ | 535 | # else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ |
734 | die(STATE_CRITICAL, | 536 | die(STATE_CRITICAL, |
735 | "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library " | 537 | "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library " |
@@ -742,7 +544,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
742 | # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) | 544 | # if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) |
743 | /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */ | 545 | /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */ |
744 | handle_curl_option_return_code( | 546 | handle_curl_option_return_code( |
745 | curl_easy_setopt(global_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); | 547 | curl_easy_setopt(result.curl_state.curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); |
746 | # else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ | 548 | # else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ |
747 | die(STATE_CRITICAL, | 549 | die(STATE_CRITICAL, |
748 | "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library " | 550 | "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library " |
@@ -775,10 +577,10 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
775 | # if LIBCURL_VERSION_NUM >= \ | 577 | # if LIBCURL_VERSION_NUM >= \ |
776 | MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */ | 578 | MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */ |
777 | // ssl ctx function is not available with all ssl backends | 579 | // ssl ctx function is not available with all ssl backends |
778 | if (curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != | 580 | if (curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != |
779 | CURLE_UNKNOWN_OPTION) { | 581 | CURLE_UNKNOWN_OPTION) { |
780 | handle_curl_option_return_code( | 582 | handle_curl_option_return_code( |
781 | curl_easy_setopt(global_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), | 583 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), |
782 | "CURLOPT_SSL_CTX_FUNCTION"); | 584 | "CURLOPT_SSL_CTX_FUNCTION"); |
783 | } | 585 | } |
784 | # endif | 586 | # endif |
@@ -786,23 +588,22 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
786 | 588 | ||
787 | /* set default or user-given user agent identification */ | 589 | /* set default or user-given user agent identification */ |
788 | handle_curl_option_return_code( | 590 | handle_curl_option_return_code( |
789 | curl_easy_setopt(global_state.curl, CURLOPT_USERAGENT, config.user_agent), | 591 | curl_easy_setopt(result.curl_state.curl, CURLOPT_USERAGENT, config.user_agent), |
790 | "CURLOPT_USERAGENT"); | 592 | "CURLOPT_USERAGENT"); |
791 | 593 | ||
792 | /* proxy-authentication */ | 594 | /* proxy-authentication */ |
793 | if (strcmp(config.proxy_auth, "")) { | 595 | if (strcmp(config.proxy_auth, "")) { |
794 | handle_curl_option_return_code( | 596 | handle_curl_option_return_code( |
795 | curl_easy_setopt(global_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth), | 597 | curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXYUSERPWD, config.proxy_auth), |
796 | "CURLOPT_PROXYUSERPWD"); | 598 | "CURLOPT_PROXYUSERPWD"); |
797 | } | 599 | } |
798 | 600 | ||
799 | /* authentication */ | 601 | /* authentication */ |
800 | if (strcmp(config.user_auth, "")) { | 602 | if (strcmp(config.user_auth, "")) { |
801 | handle_curl_option_return_code( | 603 | handle_curl_option_return_code( |
802 | curl_easy_setopt(global_state.curl, CURLOPT_USERPWD, config.user_auth), | 604 | curl_easy_setopt(result.curl_state.curl, CURLOPT_USERPWD, config.user_auth), |
803 | "CURLOPT_USERPWD"); | 605 | "CURLOPT_USERPWD"); |
804 | } | 606 | } |
805 | |||
806 | /* TODO: parameter auth method, bitfield of following methods: | 607 | /* TODO: parameter auth method, bitfield of following methods: |
807 | * CURLAUTH_BASIC (default) | 608 | * CURLAUTH_BASIC (default) |
808 | * CURLAUTH_DIGEST | 609 | * CURLAUTH_DIGEST |
@@ -820,26 +621,26 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
820 | */ | 621 | */ |
821 | 622 | ||
822 | /* handle redirections */ | 623 | /* handle redirections */ |
823 | if (config.onredirect == STATE_DEPENDENT) { | 624 | if (on_redirect_dependent) { |
824 | if (config.followmethod == FOLLOW_LIBCURL) { | 625 | if (follow_method == FOLLOW_LIBCURL) { |
825 | handle_curl_option_return_code( | 626 | handle_curl_option_return_code( |
826 | curl_easy_setopt(global_state.curl, CURLOPT_FOLLOWLOCATION, 1), | 627 | curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1), |
827 | "CURLOPT_FOLLOWLOCATION"); | 628 | "CURLOPT_FOLLOWLOCATION"); |
828 | 629 | ||
829 | /* default -1 is infinite, not good, could lead to zombie plugins! | 630 | /* default -1 is infinite, not good, could lead to zombie plugins! |
830 | Setting it to one bigger than maximal limit to handle errors nicely below | 631 | Setting it to one bigger than maximal limit to handle errors nicely below |
831 | */ | 632 | */ |
832 | handle_curl_option_return_code( | 633 | handle_curl_option_return_code( |
833 | curl_easy_setopt(global_state.curl, CURLOPT_MAXREDIRS, config.max_depth + 1), | 634 | curl_easy_setopt(result.curl_state.curl, CURLOPT_MAXREDIRS, max_depth + 1), |
834 | "CURLOPT_MAXREDIRS"); | 635 | "CURLOPT_MAXREDIRS"); |
835 | 636 | ||
836 | /* for now allow only http and https (we are a http(s) check plugin in the end) */ | 637 | /* for now allow only http and https (we are a http(s) check plugin in the end) */ |
837 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) | 638 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) |
838 | handle_curl_option_return_code( | 639 | handle_curl_option_return_code( |
839 | curl_easy_setopt(global_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), | 640 | curl_easy_setopt(result.curl_state.curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), |
840 | "CURLOPT_REDIR_PROTOCOLS_STR"); | 641 | "CURLOPT_REDIR_PROTOCOLS_STR"); |
841 | #elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) | 642 | #elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) |
842 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, | 643 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, |
843 | CURLOPT_REDIR_PROTOCOLS, | 644 | CURLOPT_REDIR_PROTOCOLS, |
844 | CURLPROTO_HTTP | CURLPROTO_HTTPS), | 645 | CURLPROTO_HTTP | CURLPROTO_HTTPS), |
845 | "CURLOPT_REDIRECT_PROTOCOLS"); | 646 | "CURLOPT_REDIRECT_PROTOCOLS"); |
@@ -854,70 +655,72 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
854 | option here is nice like for expected page size? | 655 | option here is nice like for expected page size? |
855 | */ | 656 | */ |
856 | } else { | 657 | } else { |
857 | /* old style redirection is handled below */ | 658 | /* old style redirection*/ |
858 | } | 659 | } |
859 | } | 660 | } |
860 | |||
861 | /* no-body */ | 661 | /* no-body */ |
862 | if (workingState.no_body) { | 662 | if (working_state.no_body) { |
863 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_NOBODY, 1), | 663 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1), |
864 | "CURLOPT_NOBODY"); | 664 | "CURLOPT_NOBODY"); |
865 | } | 665 | } |
866 | 666 | ||
867 | /* IPv4 or IPv6 forced DNS resolution */ | 667 | /* IPv4 or IPv6 forced DNS resolution */ |
868 | if (config.sin_family == AF_UNSPEC) { | 668 | if (config.sin_family == AF_UNSPEC) { |
869 | handle_curl_option_return_code( | 669 | handle_curl_option_return_code( |
870 | curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), | 670 | curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), |
871 | "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); | 671 | "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); |
872 | } else if (config.sin_family == AF_INET) { | 672 | } else if (config.sin_family == AF_INET) { |
873 | handle_curl_option_return_code( | 673 | handle_curl_option_return_code( |
874 | curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), | 674 | curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), |
875 | "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); | 675 | "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); |
876 | } | 676 | } |
877 | #if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) | 677 | #if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) |
878 | else if (config.sin_family == AF_INET6) { | 678 | else if (config.sin_family == AF_INET6) { |
879 | handle_curl_option_return_code( | 679 | handle_curl_option_return_code( |
880 | curl_easy_setopt(global_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), | 680 | curl_easy_setopt(result.curl_state.curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), |
881 | "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); | 681 | "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); |
882 | } | 682 | } |
883 | #endif | 683 | #endif |
884 | 684 | ||
885 | /* either send http POST data (any data, not only POST)*/ | 685 | /* either send http POST data (any data, not only POST)*/ |
886 | if (!strcmp(workingState.http_method, "POST") || !strcmp(workingState.http_method, "PUT")) { | 686 | if (!strcmp(working_state.http_method, "POST") || !strcmp(working_state.http_method, "PUT")) { |
887 | /* set content of payload for POST and PUT */ | 687 | /* set content of payload for POST and PUT */ |
888 | if (config.http_content_type) { | 688 | if (config.http_content_type) { |
889 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", | 689 | snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", |
890 | config.http_content_type); | 690 | config.http_content_type); |
891 | header_list = curl_slist_append(header_list, http_header); | 691 | result.curl_state.header_list = |
692 | curl_slist_append(result.curl_state.header_list, http_header); | ||
892 | } | 693 | } |
893 | /* NULL indicates "HTTP Continue" in libcurl, provide an empty string | 694 | /* NULL indicates "HTTP Continue" in libcurl, provide an empty string |
894 | * in case of no POST/PUT data */ | 695 | * in case of no POST/PUT data */ |
895 | if (!workingState.http_post_data) { | 696 | if (!working_state.http_post_data) { |
896 | workingState.http_post_data = ""; | 697 | working_state.http_post_data = ""; |
897 | } | 698 | } |
898 | if (!strcmp(workingState.http_method, "POST")) { | 699 | |
700 | if (!strcmp(working_state.http_method, "POST")) { | ||
899 | /* POST method, set payload with CURLOPT_POSTFIELDS */ | 701 | /* POST method, set payload with CURLOPT_POSTFIELDS */ |
900 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_POSTFIELDS, | 702 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, |
901 | workingState.http_post_data), | 703 | CURLOPT_POSTFIELDS, |
704 | working_state.http_post_data), | ||
902 | "CURLOPT_POSTFIELDS"); | 705 | "CURLOPT_POSTFIELDS"); |
903 | } else if (!strcmp(workingState.http_method, "PUT")) { | 706 | } else if (!strcmp(working_state.http_method, "PUT")) { |
904 | handle_curl_option_return_code( | 707 | handle_curl_option_return_code( |
905 | curl_easy_setopt(global_state.curl, CURLOPT_READFUNCTION, | 708 | curl_easy_setopt(result.curl_state.curl, CURLOPT_READFUNCTION, |
906 | (curl_read_callback)curlhelp_buffer_read_callback), | 709 | (curl_read_callback)curlhelp_buffer_read_callback), |
907 | "CURLOPT_READFUNCTION"); | 710 | "CURLOPT_READFUNCTION"); |
908 | if (curlhelp_initreadbuffer(&global_state.put_buf, workingState.http_post_data, | 711 | if (curlhelp_initreadbuffer(&result.curl_state.put_buf, working_state.http_post_data, |
909 | strlen(workingState.http_post_data)) < 0) { | 712 | strlen(working_state.http_post_data)) < 0) { |
910 | die(STATE_UNKNOWN, | 713 | die(STATE_UNKNOWN, |
911 | "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); | 714 | "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); |
912 | } | 715 | } |
913 | global_state.put_buf_initialized = true; | 716 | result.curl_state.put_buf_initialized = true; |
914 | 717 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, | |
915 | handle_curl_option_return_code(curl_easy_setopt(global_state.curl, CURLOPT_READDATA, | 718 | CURLOPT_READDATA, |
916 | (void *)&global_state.put_buf), | 719 | (void *)&result.curl_state.put_buf), |
917 | "CURLOPT_READDATA"); | 720 | "CURLOPT_READDATA"); |
918 | handle_curl_option_return_code( | 721 | handle_curl_option_return_code( |
919 | curl_easy_setopt(global_state.curl, CURLOPT_INFILESIZE, | 722 | curl_easy_setopt(result.curl_state.curl, CURLOPT_INFILESIZE, |
920 | (curl_off_t)strlen(workingState.http_post_data)), | 723 | (curl_off_t)strlen(working_state.http_post_data)), |
921 | "CURLOPT_INFILESIZE"); | 724 | "CURLOPT_INFILESIZE"); |
922 | } | 725 | } |
923 | } | 726 | } |
@@ -927,35 +730,267 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
927 | /* enable reading cookies from a file, and if the filename is an empty string, only | 730 | /* enable reading cookies from a file, and if the filename is an empty string, only |
928 | * enable the curl cookie engine */ | 731 | * enable the curl cookie engine */ |
929 | handle_curl_option_return_code( | 732 | handle_curl_option_return_code( |
930 | curl_easy_setopt(global_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file), | 733 | curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEFILE, config.cookie_jar_file), |
931 | "CURLOPT_COOKIEFILE"); | 734 | "CURLOPT_COOKIEFILE"); |
932 | /* now enable saving cookies to a file, but only if the filename is not an empty string, | 735 | /* now enable saving cookies to a file, but only if the filename is not an empty string, |
933 | * since writing it would fail */ | 736 | * since writing it would fail */ |
934 | if (*config.cookie_jar_file) { | 737 | if (*config.cookie_jar_file) { |
935 | handle_curl_option_return_code( | 738 | handle_curl_option_return_code( |
936 | curl_easy_setopt(global_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file), | 739 | curl_easy_setopt(result.curl_state.curl, CURLOPT_COOKIEJAR, config.cookie_jar_file), |
937 | "CURLOPT_COOKIEJAR"); | 740 | "CURLOPT_COOKIEJAR"); |
938 | } | 741 | } |
939 | } | 742 | } |
743 | return result; | ||
744 | } | ||
745 | |||
746 | #if defined(HAVE_SSL) && defined(USE_OPENSSL) | ||
747 | mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, | ||
748 | int days_till_exp_crit); | ||
749 | #endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ | ||
750 | |||
751 | static void test_file(char * /*path*/); | ||
752 | |||
753 | int main(int argc, char **argv) { | ||
754 | setlocale(LC_ALL, ""); | ||
755 | bindtextdomain(PACKAGE, LOCALEDIR); | ||
756 | textdomain(PACKAGE); | ||
757 | |||
758 | /* Parse extra opts if any */ | ||
759 | argv = np_extra_opts(&argc, argv, progname); | ||
760 | |||
761 | /* parse arguments */ | ||
762 | check_curl_config_wrapper tmp_config = process_arguments(argc, argv); | ||
763 | if (tmp_config.errorcode == ERROR) { | ||
764 | usage4(_("Could not parse arguments")); | ||
765 | } | ||
766 | |||
767 | const check_curl_config config = tmp_config.config; | ||
768 | |||
769 | if (config.display_html) { | ||
770 | printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", | ||
771 | config.initial_config.use_ssl ? "https" : "http", | ||
772 | config.initial_config.host_name ? config.initial_config.host_name | ||
773 | : config.initial_config.server_address, | ||
774 | config.initial_config.virtualPort ? config.initial_config.virtualPort | ||
775 | : config.initial_config.serverPort, | ||
776 | config.initial_config.server_url); | ||
777 | } | ||
778 | |||
779 | check_curl_working_state working_state = config.initial_config; | ||
780 | |||
781 | exit((int)check_http(config, working_state, 0)); | ||
782 | } | ||
783 | |||
784 | #ifdef HAVE_SSL | ||
785 | # ifdef USE_OPENSSL | ||
786 | int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { | ||
787 | (void)preverify_ok; | ||
788 | /* TODO: we get all certificates of the chain, so which ones | ||
789 | * should we test? | ||
790 | * TODO: is the last certificate always the server certificate? | ||
791 | */ | ||
792 | cert = X509_STORE_CTX_get_current_cert(x509_ctx); | ||
793 | # if OPENSSL_VERSION_NUMBER >= 0x10100000L | ||
794 | X509_up_ref(cert); | ||
795 | # endif | ||
796 | if (verbose >= 2) { | ||
797 | puts("* SSL verify callback with certificate:"); | ||
798 | printf("* issuer:\n"); | ||
799 | X509_NAME *issuer = X509_get_issuer_name(cert); | ||
800 | X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); | ||
801 | printf("* curl verify_callback:\n* subject:\n"); | ||
802 | X509_NAME *subject = X509_get_subject_name(cert); | ||
803 | X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); | ||
804 | puts(""); | ||
805 | } | ||
806 | return 1; | ||
807 | } | ||
808 | |||
809 | CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) { | ||
810 | (void)curl; // ignore unused parameter | ||
811 | (void)parm; // ignore unused parameter | ||
812 | if (add_sslctx_verify_fun) { | ||
813 | SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback); | ||
814 | } | ||
815 | |||
816 | // workaround for issue: | ||
817 | // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0 | ||
818 | // see discussion https://github.com/openssl/openssl/discussions/22690 | ||
819 | # ifdef SSL_OP_IGNORE_UNEXPECTED_EOF | ||
820 | SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF); | ||
821 | # endif | ||
822 | |||
823 | return CURLE_OK; | ||
824 | } | ||
825 | # endif /* USE_OPENSSL */ | ||
826 | #endif /* HAVE_SSL */ | ||
827 | |||
828 | /* returns a string "HTTP/1.x" or "HTTP/2" */ | ||
829 | static char *string_statuscode(int major, int minor) { | ||
830 | static char buf[10]; | ||
831 | |||
832 | switch (major) { | ||
833 | case 1: | ||
834 | snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor); | ||
835 | break; | ||
836 | case 2: | ||
837 | case 3: | ||
838 | snprintf(buf, sizeof(buf), "HTTP/%d", major); | ||
839 | break; | ||
840 | default: | ||
841 | /* assuming here HTTP/N with N>=4 */ | ||
842 | snprintf(buf, sizeof(buf), "HTTP/%d", major); | ||
843 | break; | ||
844 | } | ||
845 | |||
846 | return buf; | ||
847 | } | ||
848 | |||
849 | /* Checks if the server 'reply' is one of the expected 'statuscodes' */ | ||
850 | static bool expected_statuscode(const char *reply, const char *statuscodes) { | ||
851 | char *expected; | ||
852 | |||
853 | if ((expected = strdup(statuscodes)) == NULL) { | ||
854 | die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); | ||
855 | } | ||
856 | |||
857 | bool result = false; | ||
858 | for (char *code = strtok(expected, ","); code != NULL; code = strtok(NULL, ",")) { | ||
859 | if (strstr(reply, code) != NULL) { | ||
860 | result = true; | ||
861 | break; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | free(expected); | ||
866 | return result; | ||
867 | } | ||
868 | |||
869 | void handle_curl_option_return_code(CURLcode res, const char *option) { | ||
870 | if (res != CURLE_OK) { | ||
871 | snprintf(msg, DEFAULT_BUFFER_SIZE, | ||
872 | _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res, | ||
873 | curl_easy_strerror(res)); | ||
874 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
875 | } | ||
876 | } | ||
877 | |||
878 | int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family) { | ||
879 | struct addrinfo hints = { | ||
880 | .ai_family = addr_family, | ||
881 | .ai_socktype = SOCK_STREAM, | ||
882 | .ai_flags = AI_CANONNAME, | ||
883 | }; | ||
884 | |||
885 | struct addrinfo *result; | ||
886 | int errcode = getaddrinfo(host, NULL, &hints, &result); | ||
887 | if (errcode != 0) { | ||
888 | return errcode; | ||
889 | } | ||
890 | |||
891 | strcpy(buf, ""); | ||
892 | struct addrinfo *res = result; | ||
893 | |||
894 | size_t buflen_remaining = buflen - 1; | ||
895 | size_t addrstr_len; | ||
896 | char addrstr[100]; | ||
897 | void *ptr = {0}; | ||
898 | while (res) { | ||
899 | switch (res->ai_family) { | ||
900 | case AF_INET: | ||
901 | ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr; | ||
902 | break; | ||
903 | case AF_INET6: | ||
904 | ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; | ||
905 | break; | ||
906 | } | ||
907 | |||
908 | inet_ntop(res->ai_family, ptr, addrstr, 100); | ||
909 | if (verbose >= 1) { | ||
910 | printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4, | ||
911 | addrstr); | ||
912 | } | ||
913 | |||
914 | // Append all IPs to buf as a comma-separated string | ||
915 | addrstr_len = strlen(addrstr); | ||
916 | if (buflen_remaining > addrstr_len + 1) { | ||
917 | if (buf[0] != '\0') { | ||
918 | strncat(buf, ",", buflen_remaining); | ||
919 | buflen_remaining -= 1; | ||
920 | } | ||
921 | strncat(buf, addrstr, buflen_remaining); | ||
922 | buflen_remaining -= addrstr_len; | ||
923 | } | ||
924 | |||
925 | res = res->ai_next; | ||
926 | } | ||
927 | |||
928 | freeaddrinfo(result); | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | static void cleanup(check_curl_global_state global_state) { | ||
934 | if (global_state.status_line_initialized) { | ||
935 | curlhelp_free_statusline(&global_state.status_line); | ||
936 | } | ||
937 | global_state.status_line_initialized = false; | ||
938 | |||
939 | if (global_state.curl_easy_initialized) { | ||
940 | curl_easy_cleanup(global_state.curl); | ||
941 | } | ||
942 | global_state.curl_easy_initialized = false; | ||
943 | |||
944 | if (global_state.curl_global_initialized) { | ||
945 | curl_global_cleanup(); | ||
946 | } | ||
947 | global_state.curl_global_initialized = false; | ||
948 | |||
949 | if (global_state.body_buf_initialized) { | ||
950 | curlhelp_freewritebuffer(&global_state.body_buf); | ||
951 | } | ||
952 | global_state.body_buf_initialized = false; | ||
953 | |||
954 | if (global_state.header_buf_initialized) { | ||
955 | curlhelp_freewritebuffer(&global_state.header_buf); | ||
956 | } | ||
957 | global_state.header_buf_initialized = false; | ||
958 | |||
959 | if (global_state.put_buf_initialized) { | ||
960 | curlhelp_freereadbuffer(&global_state.put_buf); | ||
961 | } | ||
962 | global_state.put_buf_initialized = false; | ||
963 | |||
964 | if (global_state.header_list) { | ||
965 | curl_slist_free_all(global_state.header_list); | ||
966 | } | ||
967 | |||
968 | if (global_state.host) { | ||
969 | curl_slist_free_all(global_state.host); | ||
970 | } | ||
971 | } | ||
972 | |||
973 | mp_state_enum check_http(const check_curl_config config, check_curl_working_state workingState, | ||
974 | int redir_depth) { | ||
975 | |||
976 | // ======================= | ||
977 | // Initialisation for curl | ||
978 | // ======================= | ||
979 | check_curl_configure_curl_wrapper conf_curl_struct = check_curl_configure_curl( | ||
980 | config.curl_config, workingState, config.check_cert, config.on_redirect_dependent, | ||
981 | config.followmethod, config.max_depth); | ||
982 | |||
983 | check_curl_global_state curl_state = conf_curl_struct.curl_state; | ||
940 | 984 | ||
941 | // ============== | 985 | // ============== |
942 | // do the request | 986 | // do the request |
943 | // ============== | 987 | // ============== |
944 | CURLcode res = curl_easy_perform(global_state.curl); | 988 | CURLcode res = curl_easy_perform(curl_state.curl); |
945 | 989 | ||
946 | if (verbose >= 2 && workingState.http_post_data) { | 990 | if (verbose >= 2 && workingState.http_post_data) { |
947 | printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data); | 991 | printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data); |
948 | } | 992 | } |
949 | 993 | ||
950 | /* free header and server IP resolve lists, we don't need it anymore */ | ||
951 | curl_slist_free_all(header_list); | ||
952 | header_list = NULL; | ||
953 | |||
954 | if (host) { | ||
955 | curl_slist_free_all(host); | ||
956 | host = NULL; | ||
957 | } | ||
958 | |||
959 | /* Curl errors, result in critical Nagios state */ | 994 | /* Curl errors, result in critical Nagios state */ |
960 | if (res != CURLE_OK) { | 995 | if (res != CURLE_OK) { |
961 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 996 | snprintf(msg, DEFAULT_BUFFER_SIZE, |
@@ -969,7 +1004,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
969 | // ========== | 1004 | // ========== |
970 | 1005 | ||
971 | mp_state_enum result_ssl = STATE_OK; | 1006 | mp_state_enum result_ssl = STATE_OK; |
972 | /* certificate checks */ | 1007 | /* certificate checks */ |
973 | #ifdef LIBCURL_FEATURE_SSL | 1008 | #ifdef LIBCURL_FEATURE_SSL |
974 | if (workingState.use_ssl) { | 1009 | if (workingState.use_ssl) { |
975 | if (config.check_cert) { | 1010 | if (config.check_cert) { |
@@ -992,7 +1027,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
992 | 1027 | ||
993 | cert_ptr_union cert_ptr = {0}; | 1028 | cert_ptr_union cert_ptr = {0}; |
994 | cert_ptr.to_info = NULL; | 1029 | cert_ptr.to_info = NULL; |
995 | res = curl_easy_getinfo(global_state.curl, CURLINFO_CERTINFO, &cert_ptr.to_info); | 1030 | res = curl_easy_getinfo(curl_state.curl, CURLINFO_CERTINFO, &cert_ptr.to_info); |
996 | if (!res && cert_ptr.to_info) { | 1031 | if (!res && cert_ptr.to_info) { |
997 | # ifdef USE_OPENSSL | 1032 | # ifdef USE_OPENSSL |
998 | /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert | 1033 | /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert |
@@ -1066,54 +1101,55 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1066 | */ | 1101 | */ |
1067 | double total_time; | 1102 | double total_time; |
1068 | handle_curl_option_return_code( | 1103 | handle_curl_option_return_code( |
1069 | curl_easy_getinfo(global_state.curl, CURLINFO_TOTAL_TIME, &total_time), | 1104 | curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time), |
1070 | "CURLINFO_TOTAL_TIME"); | 1105 | "CURLINFO_TOTAL_TIME"); |
1071 | size_t page_len = get_content_length(&global_state.header_buf, &global_state.body_buf); | 1106 | size_t page_len = get_content_length(&curl_state.header_buf, &curl_state.body_buf); |
1072 | char perfstring[DEFAULT_BUFFER_SIZE]; | 1107 | char perfstring[DEFAULT_BUFFER_SIZE]; |
1073 | if (config.show_extended_perfdata) { | 1108 | if (config.show_extended_perfdata) { |
1074 | double time_connect; | 1109 | double time_connect; |
1075 | handle_curl_option_return_code( | 1110 | handle_curl_option_return_code( |
1076 | curl_easy_getinfo(global_state.curl, CURLINFO_CONNECT_TIME, &time_connect), | 1111 | curl_easy_getinfo(curl_state.curl, CURLINFO_CONNECT_TIME, &time_connect), |
1077 | "CURLINFO_CONNECT_TIME"); | 1112 | "CURLINFO_CONNECT_TIME"); |
1078 | 1113 | ||
1079 | double time_appconnect; | 1114 | double time_appconnect; |
1080 | handle_curl_option_return_code( | 1115 | handle_curl_option_return_code( |
1081 | curl_easy_getinfo(global_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), | 1116 | curl_easy_getinfo(curl_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), |
1082 | "CURLINFO_APPCONNECT_TIME"); | 1117 | "CURLINFO_APPCONNECT_TIME"); |
1083 | 1118 | ||
1084 | double time_headers; | 1119 | double time_headers; |
1085 | handle_curl_option_return_code( | 1120 | handle_curl_option_return_code( |
1086 | curl_easy_getinfo(global_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers), | 1121 | curl_easy_getinfo(curl_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers), |
1087 | "CURLINFO_PRETRANSFER_TIME"); | 1122 | "CURLINFO_PRETRANSFER_TIME"); |
1088 | 1123 | ||
1089 | double time_firstbyte; | 1124 | double time_firstbyte; |
1090 | handle_curl_option_return_code( | 1125 | handle_curl_option_return_code( |
1091 | curl_easy_getinfo(global_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), | 1126 | curl_easy_getinfo(curl_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), |
1092 | "CURLINFO_STARTTRANSFER_TIME"); | 1127 | "CURLINFO_STARTTRANSFER_TIME"); |
1093 | 1128 | ||
1094 | snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", | 1129 | snprintf( |
1095 | perfd_time(total_time, config.thlds, config.socket_timeout), | 1130 | perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", |
1096 | perfd_size(page_len, config.min_page_len), | 1131 | perfd_time(total_time, config.thlds, config.curl_config.socket_timeout), |
1097 | perfd_time_connect(time_connect, config.socket_timeout), | 1132 | perfd_size(page_len, config.min_page_len), |
1098 | workingState.use_ssl | 1133 | perfd_time_connect(time_connect, config.curl_config.socket_timeout), |
1099 | ? perfd_time_ssl(time_appconnect - time_connect, config.socket_timeout) | 1134 | workingState.use_ssl |
1100 | : "", | 1135 | ? perfd_time_ssl(time_appconnect - time_connect, config.curl_config.socket_timeout) |
1101 | perfd_time_headers(time_headers - time_appconnect, config.socket_timeout), | 1136 | : "", |
1102 | perfd_time_firstbyte(time_firstbyte - time_headers, config.socket_timeout), | 1137 | perfd_time_headers(time_headers - time_appconnect, config.curl_config.socket_timeout), |
1103 | perfd_time_transfer(total_time - time_firstbyte, config.socket_timeout)); | 1138 | perfd_time_firstbyte(time_firstbyte - time_headers, config.curl_config.socket_timeout), |
1139 | perfd_time_transfer(total_time - time_firstbyte, config.curl_config.socket_timeout)); | ||
1104 | } else { | 1140 | } else { |
1105 | snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", | 1141 | snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", |
1106 | perfd_time(total_time, config.thlds, config.socket_timeout), | 1142 | perfd_time(total_time, config.thlds, config.curl_config.socket_timeout), |
1107 | perfd_size(page_len, config.min_page_len)); | 1143 | perfd_size(page_len, config.min_page_len)); |
1108 | } | 1144 | } |
1109 | 1145 | ||
1110 | /* return a CRITICAL status if we couldn't read any data */ | 1146 | /* return a CRITICAL status if we couldn't read any data */ |
1111 | if (strlen(global_state.header_buf.buf) == 0 && strlen(global_state.body_buf.buf) == 0) { | 1147 | if (strlen(curl_state.header_buf.buf) == 0 && strlen(curl_state.body_buf.buf) == 0) { |
1112 | die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); | 1148 | die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); |
1113 | } | 1149 | } |
1114 | 1150 | ||
1115 | /* get status line of answer, check sanity of HTTP code */ | 1151 | /* get status line of answer, check sanity of HTTP code */ |
1116 | if (curlhelp_parse_statusline(global_state.header_buf.buf, &global_state.status_line) < 0) { | 1152 | if (curlhelp_parse_statusline(curl_state.header_buf.buf, &curl_state.status_line) < 0) { |
1117 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 1153 | snprintf(msg, DEFAULT_BUFFER_SIZE, |
1118 | "Unparsable status line in %.3g seconds response time|%s\n", total_time, | 1154 | "Unparsable status line in %.3g seconds response time|%s\n", total_time, |
1119 | perfstring); | 1155 | perfstring); |
@@ -1121,12 +1157,12 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1121 | * line */ | 1157 | * line */ |
1122 | die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x unknown - %s", msg); | 1158 | die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x unknown - %s", msg); |
1123 | } | 1159 | } |
1124 | global_state.status_line_initialized = true; | 1160 | curl_state.status_line_initialized = true; |
1125 | 1161 | ||
1126 | /* get result code from cURL */ | 1162 | /* get result code from cURL */ |
1127 | long httpReturnCode; | 1163 | long httpReturnCode; |
1128 | handle_curl_option_return_code( | 1164 | handle_curl_option_return_code( |
1129 | curl_easy_getinfo(global_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode), | 1165 | curl_easy_getinfo(curl_state.curl, CURLINFO_RESPONSE_CODE, &httpReturnCode), |
1130 | "CURLINFO_RESPONSE_CODE"); | 1166 | "CURLINFO_RESPONSE_CODE"); |
1131 | if (verbose >= 2) { | 1167 | if (verbose >= 2) { |
1132 | printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", httpReturnCode); | 1168 | printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", httpReturnCode); |
@@ -1134,28 +1170,28 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1134 | 1170 | ||
1135 | /* print status line, header, body if verbose */ | 1171 | /* print status line, header, body if verbose */ |
1136 | if (verbose >= 2) { | 1172 | if (verbose >= 2) { |
1137 | printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", global_state.header_buf.buf, | 1173 | printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", curl_state.header_buf.buf, |
1138 | (workingState.no_body ? " [[ skipped ]]" : global_state.body_buf.buf)); | 1174 | (workingState.no_body ? " [[ skipped ]]" : curl_state.body_buf.buf)); |
1139 | } | 1175 | } |
1140 | 1176 | ||
1141 | /* make sure the status line matches the response we are looking for */ | 1177 | /* make sure the status line matches the response we are looking for */ |
1142 | if (!expected_statuscode(global_state.status_line.first_line, config.server_expect.string)) { | 1178 | if (!expected_statuscode(curl_state.status_line.first_line, config.server_expect.string)) { |
1143 | if (workingState.serverPort == HTTP_PORT) { | 1179 | if (workingState.serverPort == HTTP_PORT) { |
1144 | snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), | 1180 | snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), |
1145 | global_state.status_line.first_line); | 1181 | curl_state.status_line.first_line); |
1146 | } else { | 1182 | } else { |
1147 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 1183 | snprintf(msg, DEFAULT_BUFFER_SIZE, |
1148 | _("Invalid HTTP response received from host on port %d: %s\n"), | 1184 | _("Invalid HTTP response received from host on port %d: %s\n"), |
1149 | workingState.serverPort, global_state.status_line.first_line); | 1185 | workingState.serverPort, curl_state.status_line.first_line); |
1150 | } | 1186 | } |
1151 | die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "", | 1187 | die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "", |
1152 | config.show_body ? global_state.body_buf.buf : ""); | 1188 | config.show_body ? curl_state.body_buf.buf : ""); |
1153 | } | 1189 | } |
1154 | 1190 | ||
1155 | mp_state_enum result = STATE_OK; | 1191 | mp_state_enum result = STATE_OK; |
1156 | if (config.server_expect.is_present) { | 1192 | if (config.server_expect.is_present) { |
1157 | snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), | 1193 | snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), |
1158 | config.server_expect); | 1194 | config.server_expect.string); |
1159 | if (verbose) { | 1195 | if (verbose) { |
1160 | printf("%s\n", msg); | 1196 | printf("%s\n", msg); |
1161 | } | 1197 | } |
@@ -1164,7 +1200,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1164 | /* illegal return codes result in a critical state */ | 1200 | /* illegal return codes result in a critical state */ |
1165 | if (httpReturnCode >= 600 || httpReturnCode < 100) { | 1201 | if (httpReturnCode >= 600 || httpReturnCode < 100) { |
1166 | die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), | 1202 | die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), |
1167 | global_state.status_line.http_code, global_state.status_line.msg); | 1203 | curl_state.status_line.http_code, curl_state.status_line.msg); |
1168 | /* server errors result in a critical state */ | 1204 | /* server errors result in a critical state */ |
1169 | } else if (httpReturnCode >= 500) { | 1205 | } else if (httpReturnCode >= 500) { |
1170 | result = STATE_CRITICAL; | 1206 | result = STATE_CRITICAL; |
@@ -1173,25 +1209,25 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1173 | result = STATE_WARNING; | 1209 | result = STATE_WARNING; |
1174 | /* check redirected page if specified */ | 1210 | /* check redirected page if specified */ |
1175 | } else if (httpReturnCode >= 300) { | 1211 | } else if (httpReturnCode >= 300) { |
1176 | if (config.onredirect == STATE_DEPENDENT) { | 1212 | if (config.on_redirect_dependent) { |
1177 | if (config.followmethod == FOLLOW_LIBCURL) { | 1213 | if (config.followmethod == FOLLOW_LIBCURL) { |
1178 | httpReturnCode = global_state.status_line.http_code; | 1214 | httpReturnCode = curl_state.status_line.http_code; |
1179 | } else { | 1215 | } else { |
1180 | /* old check_http style redirection, if we come | 1216 | /* old check_http style redirection, if we come |
1181 | * back here, we are in the same status as with | 1217 | * back here, we are in the same status as with |
1182 | * the libcurl method | 1218 | * the libcurl method |
1183 | */ | 1219 | */ |
1184 | redir_wrapper redir_result = redir(&global_state.header_buf, config, | 1220 | redir_wrapper redir_result = |
1185 | redir_depth, workingState, global_state); | 1221 | redir(&curl_state.header_buf, config, redir_depth, workingState); |
1186 | check_http(config, redir_result.working_state, redir_result.redir_depth, | 1222 | cleanup(curl_state); |
1187 | header_list, redir_result.curl_state); | 1223 | check_http(config, redir_result.working_state, redir_result.redir_depth); |
1188 | } | 1224 | } |
1189 | } else { | 1225 | } else { |
1190 | /* this is a specific code in the command line to | 1226 | /* this is a specific code in the command line to |
1191 | * be returned when a redirection is encountered | 1227 | * be returned when a redirection is encountered |
1192 | */ | 1228 | */ |
1193 | } | 1229 | } |
1194 | result = max_state_alt(config.onredirect, result); | 1230 | result = max_state_alt(config.on_redirect_result_state, result); |
1195 | /* all other codes are considered ok */ | 1231 | /* all other codes are considered ok */ |
1196 | } else { | 1232 | } else { |
1197 | result = STATE_OK; | 1233 | result = STATE_OK; |
@@ -1201,7 +1237,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1201 | /* libcurl redirection internally, handle error states here */ | 1237 | /* libcurl redirection internally, handle error states here */ |
1202 | if (config.followmethod == FOLLOW_LIBCURL) { | 1238 | if (config.followmethod == FOLLOW_LIBCURL) { |
1203 | handle_curl_option_return_code( | 1239 | handle_curl_option_return_code( |
1204 | curl_easy_getinfo(global_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth), | 1240 | curl_easy_getinfo(curl_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth), |
1205 | "CURLINFO_REDIRECT_COUNT"); | 1241 | "CURLINFO_REDIRECT_COUNT"); |
1206 | 1242 | ||
1207 | if (verbose >= 2) { | 1243 | if (verbose >= 2) { |
@@ -1216,22 +1252,21 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1216 | } | 1252 | } |
1217 | 1253 | ||
1218 | /* check status codes, set exit status accordingly */ | 1254 | /* check status codes, set exit status accordingly */ |
1219 | if (global_state.status_line.http_code != httpReturnCode) { | 1255 | if (curl_state.status_line.http_code != httpReturnCode) { |
1220 | die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"), | 1256 | die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"), |
1221 | string_statuscode(global_state.status_line.http_major, | 1257 | string_statuscode(curl_state.status_line.http_major, curl_state.status_line.http_minor), |
1222 | global_state.status_line.http_minor), | 1258 | curl_state.status_line.http_code, curl_state.status_line.msg, httpReturnCode); |
1223 | global_state.status_line.http_code, global_state.status_line.msg, httpReturnCode); | ||
1224 | } | 1259 | } |
1225 | 1260 | ||
1226 | if (config.maximum_age >= 0) { | 1261 | if (config.maximum_age >= 0) { |
1227 | result = max_state_alt( | 1262 | result = max_state_alt( |
1228 | check_document_dates(&global_state.header_buf, &msg, config.maximum_age), result); | 1263 | check_document_dates(&curl_state.header_buf, &msg, config.maximum_age), result); |
1229 | } | 1264 | } |
1230 | 1265 | ||
1231 | /* Page and Header content checks go here */ | 1266 | /* Page and Header content checks go here */ |
1232 | 1267 | ||
1233 | if (strlen(config.header_expect)) { | 1268 | if (strlen(config.header_expect)) { |
1234 | if (!strstr(global_state.header_buf.buf, config.header_expect)) { | 1269 | if (!strstr(curl_state.header_buf.buf, config.header_expect)) { |
1235 | 1270 | ||
1236 | char output_header_search[30] = ""; | 1271 | char output_header_search[30] = ""; |
1237 | strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search)); | 1272 | strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search)); |
@@ -1254,7 +1289,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1254 | } | 1289 | } |
1255 | 1290 | ||
1256 | if (strlen(config.string_expect)) { | 1291 | if (strlen(config.string_expect)) { |
1257 | if (!strstr(global_state.body_buf.buf, config.string_expect)) { | 1292 | if (!strstr(curl_state.body_buf.buf, config.string_expect)) { |
1258 | 1293 | ||
1259 | char output_string_search[30] = ""; | 1294 | char output_string_search[30] = ""; |
1260 | strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search)); | 1295 | strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search)); |
@@ -1278,7 +1313,7 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1278 | 1313 | ||
1279 | if (strlen(config.regexp)) { | 1314 | if (strlen(config.regexp)) { |
1280 | regmatch_t pmatch[REGS]; | 1315 | regmatch_t pmatch[REGS]; |
1281 | int errcode = regexec(&config.compiled_regex, global_state.body_buf.buf, REGS, pmatch, 0); | 1316 | int errcode = regexec(&config.compiled_regex, curl_state.body_buf.buf, REGS, pmatch, 0); |
1282 | if ((errcode == 0 && !config.invert_regex) || | 1317 | if ((errcode == 0 && !config.invert_regex) || |
1283 | (errcode == REG_NOMATCH && config.invert_regex)) { | 1318 | (errcode == REG_NOMATCH && config.invert_regex)) { |
1284 | /* OK - No-op to avoid changing the logic around it */ | 1319 | /* OK - No-op to avoid changing the logic around it */ |
@@ -1344,11 +1379,10 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
1344 | die((int)max_state_alt(result, result_ssl), | 1379 | die((int)max_state_alt(result, result_ssl), |
1345 | "HTTP %s: %s %d %s%s%s - %zu bytes in %.3f second response time %s|%s\n%s%s", | 1380 | "HTTP %s: %s %d %s%s%s - %zu bytes in %.3f second response time %s|%s\n%s%s", |
1346 | state_text(result), | 1381 | state_text(result), |
1347 | string_statuscode(global_state.status_line.http_major, global_state.status_line.http_minor), | 1382 | string_statuscode(curl_state.status_line.http_major, curl_state.status_line.http_minor), |
1348 | global_state.status_line.http_code, global_state.status_line.msg, | 1383 | curl_state.status_line.http_code, curl_state.status_line.msg, strlen(msg) > 0 ? " - " : "", |
1349 | strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, | 1384 | msg, page_len, total_time, (config.display_html ? "</A>" : ""), perfstring, |
1350 | (config.display_html ? "</A>" : ""), perfstring, | 1385 | (config.show_body ? curl_state.body_buf.buf : ""), (config.show_body ? "\n" : "")); |
1351 | (config.show_body ? global_state.body_buf.buf : ""), (config.show_body ? "\n" : "")); | ||
1352 | 1386 | ||
1353 | return max_state_alt(result, result_ssl); | 1387 | return max_state_alt(result, result_ssl); |
1354 | } | 1388 | } |
@@ -1375,8 +1409,7 @@ char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { | |||
1375 | } | 1409 | } |
1376 | 1410 | ||
1377 | redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, | 1411 | redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, |
1378 | int redir_depth, check_curl_working_state working_state, | 1412 | int redir_depth, check_curl_working_state working_state) { |
1379 | check_curl_global_state global_state) { | ||
1380 | curlhelp_statusline status_line; | 1413 | curlhelp_statusline status_line; |
1381 | struct phr_header headers[255]; | 1414 | struct phr_header headers[255]; |
1382 | size_t msglen; | 1415 | size_t msglen; |
@@ -1533,8 +1566,6 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
1533 | * attached to the URL in Location | 1566 | * attached to the URL in Location |
1534 | */ | 1567 | */ |
1535 | 1568 | ||
1536 | cleanup(global_state); | ||
1537 | |||
1538 | redir_wrapper result = { | 1569 | redir_wrapper result = { |
1539 | .redir_depth = redir_depth, | 1570 | .redir_depth = redir_depth, |
1540 | .working_state = working_state, | 1571 | .working_state = working_state, |
@@ -1673,7 +1704,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1673 | if (!is_intnonneg(optarg)) { | 1704 | if (!is_intnonneg(optarg)) { |
1674 | usage2(_("Timeout interval must be a positive integer"), optarg); | 1705 | usage2(_("Timeout interval must be a positive integer"), optarg); |
1675 | } else { | 1706 | } else { |
1676 | result.config.socket_timeout = (int)strtol(optarg, NULL, 10); | 1707 | result.config.curl_config.socket_timeout = (int)strtol(optarg, NULL, 10); |
1677 | } | 1708 | } |
1678 | break; | 1709 | break; |
1679 | case 'c': /* critical time threshold */ | 1710 | case 'c': /* critical time threshold */ |
@@ -1724,12 +1755,12 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1724 | } | 1755 | } |
1725 | break; | 1756 | break; |
1726 | case 'a': /* authorization info */ | 1757 | case 'a': /* authorization info */ |
1727 | strncpy(result.config.user_auth, optarg, MAX_INPUT_BUFFER - 1); | 1758 | strncpy(result.config.curl_config.user_auth, optarg, MAX_INPUT_BUFFER - 1); |
1728 | result.config.user_auth[MAX_INPUT_BUFFER - 1] = 0; | 1759 | result.config.curl_config.user_auth[MAX_INPUT_BUFFER - 1] = 0; |
1729 | break; | 1760 | break; |
1730 | case 'b': /* proxy-authorization info */ | 1761 | case 'b': /* proxy-authorization info */ |
1731 | strncpy(result.config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1); | 1762 | strncpy(result.config.curl_config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1); |
1732 | result.config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0; | 1763 | result.config.curl_config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0; |
1733 | break; | 1764 | break; |
1734 | case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ | 1765 | case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ |
1735 | if (!result.config.initial_config.http_post_data) { | 1766 | if (!result.config.initial_config.http_post_data) { |
@@ -1746,19 +1777,20 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1746 | result.config.initial_config.http_method = strdup(optarg); | 1777 | result.config.initial_config.http_method = strdup(optarg); |
1747 | break; | 1778 | break; |
1748 | case 'A': /* useragent */ | 1779 | case 'A': /* useragent */ |
1749 | strncpy(result.config.user_agent, optarg, DEFAULT_BUFFER_SIZE); | 1780 | strncpy(result.config.curl_config.user_agent, optarg, DEFAULT_BUFFER_SIZE); |
1750 | result.config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0'; | 1781 | result.config.curl_config.user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0'; |
1751 | break; | 1782 | break; |
1752 | case 'k': /* Additional headers */ | 1783 | case 'k': /* Additional headers */ |
1753 | if (result.config.http_opt_headers_count == 0) { | 1784 | if (result.config.curl_config.http_opt_headers_count == 0) { |
1754 | result.config.http_opt_headers = | 1785 | result.config.curl_config.http_opt_headers = |
1755 | malloc(sizeof(char *) * (++result.config.http_opt_headers_count)); | 1786 | malloc(sizeof(char *) * (++result.config.curl_config.http_opt_headers_count)); |
1756 | } else { | 1787 | } else { |
1757 | result.config.http_opt_headers = | 1788 | result.config.curl_config.http_opt_headers = |
1758 | realloc(result.config.http_opt_headers, | 1789 | realloc(result.config.curl_config.http_opt_headers, |
1759 | sizeof(char *) * (++result.config.http_opt_headers_count)); | 1790 | sizeof(char *) * (++result.config.curl_config.http_opt_headers_count)); |
1760 | } | 1791 | } |
1761 | result.config.http_opt_headers[result.config.http_opt_headers_count - 1] = optarg; | 1792 | result.config.curl_config |
1793 | .http_opt_headers[result.config.curl_config.http_opt_headers_count - 1] = optarg; | ||
1762 | break; | 1794 | break; |
1763 | case 'L': /* show html link */ | 1795 | case 'L': /* show html link */ |
1764 | result.config.display_html = true; | 1796 | result.config.display_html = true; |
@@ -1805,7 +1837,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1805 | usage4(_("Invalid option - SSL is not available")); | 1837 | usage4(_("Invalid option - SSL is not available")); |
1806 | #endif | 1838 | #endif |
1807 | test_file(optarg); | 1839 | test_file(optarg); |
1808 | result.config.client_cert = optarg; | 1840 | result.config.curl_config.client_cert = optarg; |
1809 | enable_tls = true; | 1841 | enable_tls = true; |
1810 | break; | 1842 | break; |
1811 | case 'K': /* use client private key */ | 1843 | case 'K': /* use client private key */ |
@@ -1813,7 +1845,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1813 | usage4(_("Invalid option - SSL is not available")); | 1845 | usage4(_("Invalid option - SSL is not available")); |
1814 | #endif | 1846 | #endif |
1815 | test_file(optarg); | 1847 | test_file(optarg); |
1816 | result.config.client_privkey = optarg; | 1848 | result.config.curl_config.client_privkey = optarg; |
1817 | enable_tls = true; | 1849 | enable_tls = true; |
1818 | break; | 1850 | break; |
1819 | case CA_CERT_OPTION: /* use CA chain file */ | 1851 | case CA_CERT_OPTION: /* use CA chain file */ |
@@ -1821,14 +1853,14 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1821 | usage4(_("Invalid option - SSL is not available")); | 1853 | usage4(_("Invalid option - SSL is not available")); |
1822 | #endif | 1854 | #endif |
1823 | test_file(optarg); | 1855 | test_file(optarg); |
1824 | result.config.ca_cert = optarg; | 1856 | result.config.curl_config.ca_cert = optarg; |
1825 | enable_tls = true; | 1857 | enable_tls = true; |
1826 | break; | 1858 | break; |
1827 | case 'D': /* verify peer certificate & host */ | 1859 | case 'D': /* verify peer certificate & host */ |
1828 | #ifndef LIBCURL_FEATURE_SSL | 1860 | #ifndef LIBCURL_FEATURE_SSL |
1829 | usage4(_("Invalid option - SSL is not available")); | 1861 | usage4(_("Invalid option - SSL is not available")); |
1830 | #endif | 1862 | #endif |
1831 | result.config.verify_peer_and_host = true; | 1863 | result.config.curl_config.verify_peer_and_host = true; |
1832 | enable_tls = true; | 1864 | enable_tls = true; |
1833 | break; | 1865 | break; |
1834 | case 'S': /* use SSL */ | 1866 | case 'S': /* use SSL */ |
@@ -1852,36 +1884,44 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1852 | break; | 1884 | break; |
1853 | case 'f': /* onredirect */ | 1885 | case 'f': /* onredirect */ |
1854 | if (!strcmp(optarg, "ok")) { | 1886 | if (!strcmp(optarg, "ok")) { |
1855 | result.config.onredirect = STATE_OK; | 1887 | result.config.on_redirect_result_state = STATE_OK; |
1888 | result.config.on_redirect_dependent = false; | ||
1856 | } else if (!strcmp(optarg, "warning")) { | 1889 | } else if (!strcmp(optarg, "warning")) { |
1857 | result.config.onredirect = STATE_WARNING; | 1890 | result.config.on_redirect_result_state = STATE_WARNING; |
1891 | result.config.on_redirect_dependent = false; | ||
1858 | } else if (!strcmp(optarg, "critical")) { | 1892 | } else if (!strcmp(optarg, "critical")) { |
1859 | result.config.onredirect = STATE_CRITICAL; | 1893 | result.config.on_redirect_result_state = STATE_CRITICAL; |
1894 | result.config.on_redirect_dependent = false; | ||
1860 | } else if (!strcmp(optarg, "unknown")) { | 1895 | } else if (!strcmp(optarg, "unknown")) { |
1861 | result.config.onredirect = STATE_UNKNOWN; | 1896 | result.config.on_redirect_result_state = STATE_UNKNOWN; |
1897 | result.config.on_redirect_dependent = false; | ||
1862 | } else if (!strcmp(optarg, "follow")) { | 1898 | } else if (!strcmp(optarg, "follow")) { |
1863 | result.config.onredirect = STATE_DEPENDENT; | 1899 | result.config.on_redirect_dependent = true; |
1864 | } else if (!strcmp(optarg, "stickyport")) { | 1900 | } else if (!strcmp(optarg, "stickyport")) { |
1865 | result.config.onredirect = STATE_DEPENDENT, | 1901 | result.config.on_redirect_dependent = true; |
1866 | result.config.followmethod = FOLLOW_HTTP_CURL, | 1902 | result.config.followmethod = FOLLOW_HTTP_CURL, |
1867 | result.config.followsticky = STICKY_HOST | STICKY_PORT; | 1903 | result.config.followsticky = STICKY_HOST | STICKY_PORT; |
1868 | } else if (!strcmp(optarg, "sticky")) { | 1904 | } else if (!strcmp(optarg, "sticky")) { |
1869 | result.config.onredirect = STATE_DEPENDENT, | 1905 | result.config.on_redirect_dependent = true; |
1870 | result.config.followmethod = FOLLOW_HTTP_CURL, | 1906 | result.config.followmethod = FOLLOW_HTTP_CURL, |
1871 | result.config.followsticky = STICKY_HOST; | 1907 | result.config.followsticky = STICKY_HOST; |
1872 | } else if (!strcmp(optarg, "follow")) { | 1908 | } else if (!strcmp(optarg, "follow")) { |
1873 | result.config.onredirect = STATE_DEPENDENT, | 1909 | result.config.on_redirect_dependent = true; |
1874 | result.config.followmethod = FOLLOW_HTTP_CURL, | 1910 | result.config.followmethod = FOLLOW_HTTP_CURL, |
1875 | result.config.followsticky = STICKY_NONE; | 1911 | result.config.followsticky = STICKY_NONE; |
1876 | } else if (!strcmp(optarg, "curl")) { | 1912 | } else if (!strcmp(optarg, "curl")) { |
1877 | result.config.onredirect = STATE_DEPENDENT, | 1913 | result.config.on_redirect_dependent = true; |
1878 | result.config.followmethod = FOLLOW_LIBCURL; | 1914 | result.config.followmethod = FOLLOW_LIBCURL; |
1879 | } else { | 1915 | } else { |
1880 | usage2(_("Invalid onredirect option"), optarg); | 1916 | usage2(_("Invalid onredirect option"), optarg); |
1881 | } | 1917 | } |
1882 | if (verbose >= 2) { | 1918 | if (verbose >= 2) { |
1883 | printf(_("* Following redirects set to %s\n"), | 1919 | if (result.config.on_redirect_dependent) { |
1884 | state_text(result.config.onredirect)); | 1920 | printf(_("* Following redirects\n")); |
1921 | } else { | ||
1922 | printf(_("* Following redirects set to state %s\n"), | ||
1923 | state_text(result.config.on_redirect_result_state)); | ||
1924 | } | ||
1885 | } | 1925 | } |
1886 | break; | 1926 | break; |
1887 | case 'd': /* string or substring */ | 1927 | case 'd': /* string or substring */ |
@@ -1898,7 +1938,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1898 | result.config.server_expect.is_present = true; | 1938 | result.config.server_expect.is_present = true; |
1899 | break; | 1939 | break; |
1900 | case 'T': /* Content-type */ | 1940 | case 'T': /* Content-type */ |
1901 | result.config.http_content_type = strdup(optarg); | 1941 | result.config.curl_config.http_content_type = strdup(optarg); |
1902 | break; | 1942 | break; |
1903 | case 'l': /* linespan */ | 1943 | case 'l': /* linespan */ |
1904 | cflags &= ~REG_NEWLINE; | 1944 | cflags &= ~REG_NEWLINE; |
@@ -1933,11 +1973,11 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1933 | } | 1973 | } |
1934 | break; | 1974 | break; |
1935 | case '4': | 1975 | case '4': |
1936 | result.config.sin_family = AF_INET; | 1976 | result.config.curl_config.sin_family = AF_INET; |
1937 | break; | 1977 | break; |
1938 | case '6': | 1978 | case '6': |
1939 | #if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) | 1979 | #if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6) |
1940 | result.config.sin_family = AF_INET6; | 1980 | result.config.curl_config.sin_family = AF_INET6; |
1941 | #else | 1981 | #else |
1942 | usage4(_("IPv6 support not available")); | 1982 | usage4(_("IPv6 support not available")); |
1943 | #endif | 1983 | #endif |
@@ -1997,30 +2037,33 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
1997 | result.config.show_body = true; | 2037 | result.config.show_body = true; |
1998 | break; | 2038 | break; |
1999 | case HTTP_VERSION_OPTION: | 2039 | case HTTP_VERSION_OPTION: |
2000 | result.config.curl_http_version = CURL_HTTP_VERSION_NONE; | 2040 | result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_NONE; |
2001 | if (strcmp(optarg, "1.0") == 0) { | 2041 | if (strcmp(optarg, "1.0") == 0) { |
2002 | result.config.curl_http_version = CURL_HTTP_VERSION_1_0; | 2042 | result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_0; |
2003 | } else if (strcmp(optarg, "1.1") == 0) { | 2043 | } else if (strcmp(optarg, "1.1") == 0) { |
2004 | result.config.curl_http_version = CURL_HTTP_VERSION_1_1; | 2044 | result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_1_1; |
2005 | } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) { | 2045 | } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) { |
2006 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) | 2046 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) |
2007 | result.config.curl_http_version = CURL_HTTP_VERSION_2_0; | 2047 | result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_2_0; |
2008 | #else | 2048 | #else |
2009 | result.config.curl_http_version = CURL_HTTP_VERSION_NONE; | 2049 | result.config.curl_http_version = CURL_HTTP_VERSION_NONE; |
2010 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ | 2050 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ |
2051 | } else if ((strcmp(optarg, "3") == 0)) { | ||
2052 | // TODO find out which libcurl version starts supporting HTTP 3 | ||
2053 | result.config.curl_config.curl_http_version = CURL_HTTP_VERSION_3; | ||
2011 | } else { | 2054 | } else { |
2012 | fprintf(stderr, "unknown http-version parameter: %s\n", optarg); | 2055 | fprintf(stderr, "unknown http-version parameter: %s\n", optarg); |
2013 | exit(STATE_WARNING); | 2056 | exit(STATE_WARNING); |
2014 | } | 2057 | } |
2015 | break; | 2058 | break; |
2016 | case AUTOMATIC_DECOMPRESSION: | 2059 | case AUTOMATIC_DECOMPRESSION: |
2017 | result.config.automatic_decompression = true; | 2060 | result.config.curl_config.automatic_decompression = true; |
2018 | break; | 2061 | break; |
2019 | case COOKIE_JAR: | 2062 | case COOKIE_JAR: |
2020 | result.config.cookie_jar_file = optarg; | 2063 | result.config.curl_config.cookie_jar_file = optarg; |
2021 | break; | 2064 | break; |
2022 | case HAPROXY_PROTOCOL: | 2065 | case HAPROXY_PROTOCOL: |
2023 | result.config.haproxy_protocol = true; | 2066 | result.config.curl_config.haproxy_protocol = true; |
2024 | break; | 2067 | break; |
2025 | case '?': | 2068 | case '?': |
2026 | /* print short usage statement if args not parsable */ | 2069 | /* print short usage statement if args not parsable */ |
@@ -2035,7 +2078,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
2035 | /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. | 2078 | /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. |
2036 | * Only set if it's non-zero. This helps when we include multiple | 2079 | * Only set if it's non-zero. This helps when we include multiple |
2037 | * parameters, like -S and -C combinations */ | 2080 | * parameters, like -S and -C combinations */ |
2038 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; | 2081 | result.config.curl_config.ssl_version = CURL_SSLVERSION_DEFAULT; |
2039 | if (tls_option_optarg != NULL) { | 2082 | if (tls_option_optarg != NULL) { |
2040 | char *plus_ptr = strchr(optarg, '+'); | 2083 | char *plus_ptr = strchr(optarg, '+'); |
2041 | if (plus_ptr) { | 2084 | if (plus_ptr) { |
@@ -2044,30 +2087,30 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
2044 | } | 2087 | } |
2045 | 2088 | ||
2046 | if (optarg[0] == '2') { | 2089 | if (optarg[0] == '2') { |
2047 | result.config.ssl_version = CURL_SSLVERSION_SSLv2; | 2090 | result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv2; |
2048 | } else if (optarg[0] == '3') { | 2091 | } else if (optarg[0] == '3') { |
2049 | result.config.ssl_version = CURL_SSLVERSION_SSLv3; | 2092 | result.config.curl_config.ssl_version = CURL_SSLVERSION_SSLv3; |
2050 | } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) { | 2093 | } else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0")) { |
2051 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) | 2094 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) |
2052 | result.config.ssl_version = CURL_SSLVERSION_TLSv1_0; | 2095 | result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_0; |
2053 | #else | 2096 | #else |
2054 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; | 2097 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; |
2055 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ | 2098 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ |
2056 | } else if (!strcmp(optarg, "1.1")) { | 2099 | } else if (!strcmp(optarg, "1.1")) { |
2057 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) | 2100 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) |
2058 | result.config.ssl_version = CURL_SSLVERSION_TLSv1_1; | 2101 | result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_1; |
2059 | #else | 2102 | #else |
2060 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; | 2103 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; |
2061 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ | 2104 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ |
2062 | } else if (!strcmp(optarg, "1.2")) { | 2105 | } else if (!strcmp(optarg, "1.2")) { |
2063 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) | 2106 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) |
2064 | result.config.ssl_version = CURL_SSLVERSION_TLSv1_2; | 2107 | result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_2; |
2065 | #else | 2108 | #else |
2066 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; | 2109 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; |
2067 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ | 2110 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ |
2068 | } else if (!strcmp(optarg, "1.3")) { | 2111 | } else if (!strcmp(optarg, "1.3")) { |
2069 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) | 2112 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) |
2070 | result.config.ssl_version = CURL_SSLVERSION_TLSv1_3; | 2113 | result.config.curl_config.ssl_version = CURL_SSLVERSION_TLSv1_3; |
2071 | #else | 2114 | #else |
2072 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; | 2115 | result.config.ssl_version = CURL_SSLVERSION_DEFAULT; |
2073 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ | 2116 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ |
@@ -2078,35 +2121,35 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
2078 | } | 2121 | } |
2079 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) | 2122 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) |
2080 | if (got_plus) { | 2123 | if (got_plus) { |
2081 | switch (result.config.ssl_version) { | 2124 | switch (result.config.curl_config.ssl_version) { |
2082 | case CURL_SSLVERSION_TLSv1_3: | 2125 | case CURL_SSLVERSION_TLSv1_3: |
2083 | result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; | 2126 | result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; |
2084 | break; | 2127 | break; |
2085 | case CURL_SSLVERSION_TLSv1_2: | 2128 | case CURL_SSLVERSION_TLSv1_2: |
2086 | case CURL_SSLVERSION_TLSv1_1: | 2129 | case CURL_SSLVERSION_TLSv1_1: |
2087 | case CURL_SSLVERSION_TLSv1_0: | 2130 | case CURL_SSLVERSION_TLSv1_0: |
2088 | result.config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; | 2131 | result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; |
2089 | break; | 2132 | break; |
2090 | } | 2133 | } |
2091 | } else { | 2134 | } else { |
2092 | switch (result.config.ssl_version) { | 2135 | switch (result.config.curl_config.ssl_version) { |
2093 | case CURL_SSLVERSION_TLSv1_3: | 2136 | case CURL_SSLVERSION_TLSv1_3: |
2094 | result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; | 2137 | result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; |
2095 | break; | 2138 | break; |
2096 | case CURL_SSLVERSION_TLSv1_2: | 2139 | case CURL_SSLVERSION_TLSv1_2: |
2097 | result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; | 2140 | result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; |
2098 | break; | 2141 | break; |
2099 | case CURL_SSLVERSION_TLSv1_1: | 2142 | case CURL_SSLVERSION_TLSv1_1: |
2100 | result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; | 2143 | result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; |
2101 | break; | 2144 | break; |
2102 | case CURL_SSLVERSION_TLSv1_0: | 2145 | case CURL_SSLVERSION_TLSv1_0: |
2103 | result.config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; | 2146 | result.config.curl_config.ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; |
2104 | break; | 2147 | break; |
2105 | } | 2148 | } |
2106 | } | 2149 | } |
2107 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ | 2150 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ |
2108 | if (verbose >= 2) { | 2151 | if (verbose >= 2) { |
2109 | printf(_("* Set SSL/TLS version to %d\n"), result.config.ssl_version); | 2152 | printf(_("* Set SSL/TLS version to %d\n"), result.config.curl_config.ssl_version); |
2110 | } | 2153 | } |
2111 | if (!specify_port) { | 2154 | if (!specify_port) { |
2112 | result.config.initial_config.serverPort = HTTPS_PORT; | 2155 | result.config.initial_config.serverPort = HTTPS_PORT; |
@@ -2135,18 +2178,18 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
2135 | set_thresholds(&result.config.thlds, warning_thresholds, critical_thresholds); | 2178 | set_thresholds(&result.config.thlds, warning_thresholds, critical_thresholds); |
2136 | 2179 | ||
2137 | if (critical_thresholds && | 2180 | if (critical_thresholds && |
2138 | result.config.thlds->critical->end > (double)result.config.socket_timeout) { | 2181 | result.config.thlds->critical->end > (double)result.config.curl_config.socket_timeout) { |
2139 | result.config.socket_timeout = (int)result.config.thlds->critical->end + 1; | 2182 | result.config.curl_config.socket_timeout = (int)result.config.thlds->critical->end + 1; |
2140 | } | 2183 | } |
2141 | if (verbose >= 2) { | 2184 | if (verbose >= 2) { |
2142 | printf("* Socket timeout set to %ld seconds\n", result.config.socket_timeout); | 2185 | printf("* Socket timeout set to %ld seconds\n", result.config.curl_config.socket_timeout); |
2143 | } | 2186 | } |
2144 | 2187 | ||
2145 | if (result.config.initial_config.http_method == NULL) { | 2188 | if (result.config.initial_config.http_method == NULL) { |
2146 | result.config.initial_config.http_method = strdup("GET"); | 2189 | result.config.initial_config.http_method = strdup("GET"); |
2147 | } | 2190 | } |
2148 | 2191 | ||
2149 | if (result.config.client_cert && !result.config.client_privkey) { | 2192 | if (result.config.curl_config.client_cert && !result.config.curl_config.client_privkey) { |
2150 | usage4(_("If you use a client certificate you must also specify a private key file")); | 2193 | usage4(_("If you use a client certificate you must also specify a private key file")); |
2151 | } | 2194 | } |
2152 | 2195 | ||
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h index 7566b19c..be25d1bb 100644 --- a/plugins/check_curl.d/config.h +++ b/plugins/check_curl.d/config.h | |||
@@ -65,27 +65,32 @@ check_curl_working_state check_curl_working_state_init() { | |||
65 | } | 65 | } |
66 | 66 | ||
67 | typedef struct { | 67 | typedef struct { |
68 | check_curl_working_state initial_config; | ||
69 | sa_family_t sin_family; | ||
70 | |||
71 | bool automatic_decompression; | 68 | bool automatic_decompression; |
72 | bool haproxy_protocol; | 69 | bool haproxy_protocol; |
70 | long socket_timeout; | ||
71 | sa_family_t sin_family; | ||
72 | int curl_http_version; | ||
73 | char **http_opt_headers; | ||
74 | size_t http_opt_headers_count; | ||
75 | int ssl_version; | ||
73 | char *client_cert; | 76 | char *client_cert; |
74 | char *client_privkey; | 77 | char *client_privkey; |
75 | char *ca_cert; | 78 | char *ca_cert; |
76 | int ssl_version; | 79 | bool verify_peer_and_host; |
77 | char user_agent[DEFAULT_BUFFER_SIZE]; | 80 | char user_agent[DEFAULT_BUFFER_SIZE]; |
78 | char **http_opt_headers; | ||
79 | size_t http_opt_headers_count; | ||
80 | int max_depth; | ||
81 | char *http_content_type; | ||
82 | long socket_timeout; | ||
83 | char user_auth[MAX_INPUT_BUFFER]; | ||
84 | char proxy_auth[MAX_INPUT_BUFFER]; | 81 | char proxy_auth[MAX_INPUT_BUFFER]; |
82 | char user_auth[MAX_INPUT_BUFFER]; | ||
83 | char *http_content_type; | ||
84 | char *cookie_jar_file; | ||
85 | } check_curl_static_curl_config; | ||
86 | |||
87 | typedef struct { | ||
88 | check_curl_working_state initial_config; | ||
89 | |||
90 | check_curl_static_curl_config curl_config; | ||
91 | int max_depth; | ||
85 | int followmethod; | 92 | int followmethod; |
86 | int followsticky; | 93 | int followsticky; |
87 | int curl_http_version; | ||
88 | char *cookie_jar_file; | ||
89 | 94 | ||
90 | int maximum_age; | 95 | int maximum_age; |
91 | 96 | ||
@@ -97,7 +102,6 @@ typedef struct { | |||
97 | 102 | ||
98 | mp_state_enum state_regex; | 103 | mp_state_enum state_regex; |
99 | bool invert_regex; | 104 | bool invert_regex; |
100 | bool verify_peer_and_host; | ||
101 | bool check_cert; | 105 | bool check_cert; |
102 | bool continue_after_check_cert; | 106 | bool continue_after_check_cert; |
103 | int days_till_exp_warn; | 107 | int days_till_exp_warn; |
@@ -111,7 +115,8 @@ typedef struct { | |||
111 | } server_expect; | 115 | } server_expect; |
112 | char string_expect[MAX_INPUT_BUFFER]; | 116 | char string_expect[MAX_INPUT_BUFFER]; |
113 | char header_expect[MAX_INPUT_BUFFER]; | 117 | char header_expect[MAX_INPUT_BUFFER]; |
114 | mp_state_enum onredirect; | 118 | mp_state_enum on_redirect_result_state; |
119 | bool on_redirect_dependent; | ||
115 | 120 | ||
116 | bool show_extended_perfdata; | 121 | bool show_extended_perfdata; |
117 | bool show_body; | 122 | bool show_body; |
@@ -122,33 +127,35 @@ check_curl_config check_curl_config_init() { | |||
122 | check_curl_config tmp = { | 127 | check_curl_config tmp = { |
123 | .initial_config = check_curl_working_state_init(), | 128 | .initial_config = check_curl_working_state_init(), |
124 | 129 | ||
125 | .sin_family = AF_UNSPEC, | 130 | .curl_config = |
126 | 131 | { | |
127 | .automatic_decompression = false, | 132 | .automatic_decompression = false, |
128 | .haproxy_protocol = false, | 133 | .socket_timeout = DEFAULT_SOCKET_TIMEOUT, |
129 | .client_cert = NULL, | 134 | .haproxy_protocol = false, |
130 | .client_privkey = NULL, | 135 | .sin_family = AF_UNSPEC, |
131 | .ca_cert = NULL, | 136 | .curl_http_version = CURL_HTTP_VERSION_NONE, |
132 | .ssl_version = CURL_SSLVERSION_DEFAULT, | 137 | .http_opt_headers = NULL, |
133 | .user_agent = {'\0'}, | 138 | .http_opt_headers_count = 0, |
134 | .http_opt_headers = NULL, | 139 | .ssl_version = CURL_SSLVERSION_DEFAULT, |
135 | .http_opt_headers_count = 0, | 140 | .client_cert = NULL, |
141 | .client_privkey = NULL, | ||
142 | .ca_cert = NULL, | ||
143 | .verify_peer_and_host = false, | ||
144 | .user_agent = {'\0'}, | ||
145 | .proxy_auth = "", | ||
146 | .user_auth = "", | ||
147 | .http_content_type = NULL, | ||
148 | .cookie_jar_file = NULL, | ||
149 | }, | ||
136 | .max_depth = DEFAULT_MAX_REDIRS, | 150 | .max_depth = DEFAULT_MAX_REDIRS, |
137 | .http_content_type = NULL, | ||
138 | .socket_timeout = DEFAULT_SOCKET_TIMEOUT, | ||
139 | .user_auth = "", | ||
140 | .proxy_auth = "", | ||
141 | .followmethod = FOLLOW_HTTP_CURL, | 151 | .followmethod = FOLLOW_HTTP_CURL, |
142 | .followsticky = STICKY_NONE, | 152 | .followsticky = STICKY_NONE, |
143 | .curl_http_version = CURL_HTTP_VERSION_NONE, | ||
144 | .cookie_jar_file = NULL, | ||
145 | 153 | ||
146 | .maximum_age = -1, | 154 | .maximum_age = -1, |
147 | .regexp = {}, | 155 | .regexp = {}, |
148 | .compiled_regex = {}, | 156 | .compiled_regex = {}, |
149 | .state_regex = STATE_CRITICAL, | 157 | .state_regex = STATE_CRITICAL, |
150 | .invert_regex = false, | 158 | .invert_regex = false, |
151 | .verify_peer_and_host = false, | ||
152 | .check_cert = false, | 159 | .check_cert = false, |
153 | .continue_after_check_cert = false, | 160 | .continue_after_check_cert = false, |
154 | .days_till_exp_warn = 0, | 161 | .days_till_exp_warn = 0, |
@@ -163,11 +170,16 @@ check_curl_config check_curl_config_init() { | |||
163 | }, | 170 | }, |
164 | .string_expect = "", | 171 | .string_expect = "", |
165 | .header_expect = "", | 172 | .header_expect = "", |
166 | .onredirect = STATE_OK, | 173 | .on_redirect_result_state = STATE_OK, |
174 | .on_redirect_dependent = true, | ||
167 | 175 | ||
168 | .show_extended_perfdata = false, | 176 | .show_extended_perfdata = false, |
169 | .show_body = false, | 177 | .show_body = false, |
170 | .display_html = false, | 178 | .display_html = false, |
171 | }; | 179 | }; |
180 | |||
181 | snprintf(tmp.curl_config.user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", | ||
182 | "check_curl", NP_VERSION, VERSION, curl_version()); | ||
183 | |||
172 | return tmp; | 184 | return tmp; |
173 | } | 185 | } |