diff options
| author | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-09-12 16:37:24 +0200 |
|---|---|---|
| committer | Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> | 2025-09-12 16:37:24 +0200 |
| commit | 44b2a25a6b9fb0791ec7150100a4d51e5f129611 (patch) | |
| tree | 4fb13f9effac32bf156cc6eaefe22f6deea6d7ea | |
| parent | aaff3aa9da27ff7666d2a776d524c784b76eb3d7 (diff) | |
| download | monitoring-plugins-44b2a25a6b9fb0791ec7150100a4d51e5f129611.tar.gz | |
check_curl: implement new output mechanism
| -rw-r--r-- | plugins/check_curl.c | 562 | ||||
| -rw-r--r-- | plugins/check_curl.d/check_curl_helpers.c | 251 | ||||
| -rw-r--r-- | plugins/check_curl.d/check_curl_helpers.h | 21 | ||||
| -rw-r--r-- | plugins/check_curl.d/config.h | 7 |
4 files changed, 443 insertions, 398 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c index b0dde1eb..722666dd 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c | |||
| @@ -42,7 +42,10 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 42 | #include "thresholds.h" | 42 | #include "thresholds.h" |
| 43 | #include <stdbool.h> | 43 | #include <stdbool.h> |
| 44 | #include <ctype.h> | 44 | #include <ctype.h> |
| 45 | #include "output.h" | ||
| 46 | #include "perfdata.h" | ||
| 45 | 47 | ||
| 48 | #include <assert.h> | ||
| 46 | #include "common.h" | 49 | #include "common.h" |
| 47 | #include "utils.h" | 50 | #include "utils.h" |
| 48 | #include "./check_curl.d/check_curl_helpers.h" | 51 | #include "./check_curl.d/check_curl_helpers.h" |
| @@ -78,7 +81,6 @@ enum { | |||
| 78 | // Globals | 81 | // Globals |
| 79 | int verbose = 0; | 82 | int verbose = 0; |
| 80 | 83 | ||
| 81 | extern char msg[DEFAULT_BUFFER_SIZE]; | ||
| 82 | extern char errbuf[MAX_INPUT_BUFFER]; | 84 | extern char errbuf[MAX_INPUT_BUFFER]; |
| 83 | extern bool is_openssl_callback; | 85 | extern bool is_openssl_callback; |
| 84 | extern bool add_sslctx_verify_fun; | 86 | extern bool add_sslctx_verify_fun; |
| @@ -93,8 +95,8 @@ typedef struct { | |||
| 93 | } check_curl_config_wrapper; | 95 | } check_curl_config_wrapper; |
| 94 | static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); | 96 | static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); |
| 95 | 97 | ||
| 96 | static mp_state_enum check_http(check_curl_config /*config*/, check_curl_working_state workingState, | 98 | static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState, |
| 97 | int redir_depth); | 99 | int redir_depth); |
| 98 | 100 | ||
| 99 | typedef struct { | 101 | typedef struct { |
| 100 | int redir_depth; | 102 | int redir_depth; |
| @@ -149,7 +151,12 @@ int main(int argc, char **argv) { | |||
| 149 | 151 | ||
| 150 | check_curl_working_state working_state = config.initial_config; | 152 | check_curl_working_state working_state = config.initial_config; |
| 151 | 153 | ||
| 152 | exit((int)check_http(config, working_state, 0)); | 154 | mp_check overall = mp_check_init(); |
| 155 | mp_subcheck sc_test = check_http(config, working_state, 0); | ||
| 156 | |||
| 157 | mp_add_subcheck_to_check(&overall, sc_test); | ||
| 158 | |||
| 159 | mp_exit(overall); | ||
| 153 | } | 160 | } |
| 154 | 161 | ||
| 155 | #ifdef HAVE_SSL | 162 | #ifdef HAVE_SSL |
| @@ -200,8 +207,8 @@ CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) { | |||
| 200 | # endif /* USE_OPENSSL */ | 207 | # endif /* USE_OPENSSL */ |
| 201 | #endif /* HAVE_SSL */ | 208 | #endif /* HAVE_SSL */ |
| 202 | 209 | ||
| 203 | mp_state_enum check_http(const check_curl_config config, check_curl_working_state workingState, | 210 | mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState, |
| 204 | int redir_depth) { | 211 | int redir_depth) { |
| 205 | 212 | ||
| 206 | // ======================= | 213 | // ======================= |
| 207 | // Initialisation for curl | 214 | // Initialisation for curl |
| @@ -213,6 +220,13 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
| 213 | check_curl_global_state curl_state = conf_curl_struct.curl_state; | 220 | check_curl_global_state curl_state = conf_curl_struct.curl_state; |
| 214 | workingState = conf_curl_struct.working_state; | 221 | workingState = conf_curl_struct.working_state; |
| 215 | 222 | ||
| 223 | mp_subcheck sc_result = mp_subcheck_init(); | ||
| 224 | |||
| 225 | char *url = fmt_url(workingState); | ||
| 226 | xasprintf(&sc_result.output, "Testing %s", url); | ||
| 227 | // TODO add some output here URL or something | ||
| 228 | free(url); | ||
| 229 | |||
| 216 | // ============== | 230 | // ============== |
| 217 | // do the request | 231 | // do the request |
| 218 | // ============== | 232 | // ============== |
| @@ -222,172 +236,149 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
| 222 | printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data); | 236 | printf("**** REQUEST CONTENT ****\n%s\n", workingState.http_post_data); |
| 223 | } | 237 | } |
| 224 | 238 | ||
| 239 | mp_subcheck sc_curl = mp_subcheck_init(); | ||
| 240 | |||
| 225 | /* Curl errors, result in critical Nagios state */ | 241 | /* Curl errors, result in critical Nagios state */ |
| 226 | if (res != CURLE_OK) { | 242 | if (res != CURLE_OK) { |
| 227 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 243 | xasprintf(&sc_curl.output, |
| 228 | _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), | 244 | _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), |
| 229 | workingState.serverPort, res, errbuf[0] ? errbuf : curl_easy_strerror(res)); | 245 | workingState.serverPort, res, errbuf[0] ? errbuf : curl_easy_strerror(res)); |
| 230 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | 246 | sc_curl = mp_set_subcheck_state(sc_curl, STATE_CRITICAL); |
| 247 | mp_add_subcheck_to_subcheck(&sc_result, sc_curl); | ||
| 248 | return sc_result; | ||
| 231 | } | 249 | } |
| 232 | 250 | ||
| 251 | xasprintf(&sc_curl.output, "cURL performed query"); | ||
| 252 | sc_curl = mp_set_subcheck_state(sc_curl, STATE_OK); | ||
| 253 | mp_add_subcheck_to_subcheck(&sc_result, sc_curl); | ||
| 254 | |||
| 233 | // ========== | 255 | // ========== |
| 234 | // Evaluation | 256 | // Evaluation |
| 235 | // ========== | 257 | // ========== |
| 236 | 258 | ||
| 237 | mp_state_enum result_ssl = STATE_OK; | ||
| 238 | /* certificate checks */ | ||
| 239 | #ifdef LIBCURL_FEATURE_SSL | 259 | #ifdef LIBCURL_FEATURE_SSL |
| 240 | if (workingState.use_ssl) { | 260 | if (workingState.use_ssl && config.check_cert) { |
| 241 | if (config.check_cert) { | 261 | mp_subcheck sc_certificate = check_curl_certificate_checks( |
| 242 | if (is_openssl_callback) { | 262 | curl_state.curl, cert, config.days_till_exp_warn, config.days_till_exp_crit); |
| 243 | # ifdef USE_OPENSSL | ||
| 244 | /* check certificate with OpenSSL functions, curl has been built against OpenSSL | ||
| 245 | * and we actually have OpenSSL in the monitoring tools | ||
| 246 | */ | ||
| 247 | result_ssl = np_net_ssl_check_certificate(cert, config.days_till_exp_warn, | ||
| 248 | config.days_till_exp_crit); | ||
| 249 | if (!config.continue_after_check_cert) { | ||
| 250 | return result_ssl; | ||
| 251 | } | ||
| 252 | # else /* USE_OPENSSL */ | ||
| 253 | die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL " | ||
| 254 | "callback used and not linked against OpenSSL\n"); | ||
| 255 | # endif /* USE_OPENSSL */ | ||
| 256 | } else { | ||
| 257 | struct curl_slist *slist; | ||
| 258 | 263 | ||
| 259 | cert_ptr_union cert_ptr = {0}; | 264 | mp_add_subcheck_to_subcheck(&sc_result, sc_certificate); |
| 260 | cert_ptr.to_info = NULL; | 265 | if (!config.continue_after_check_cert) { |
| 261 | res = curl_easy_getinfo(curl_state.curl, CURLINFO_CERTINFO, &cert_ptr.to_info); | 266 | // TODO finish here then |
| 262 | if (!res && cert_ptr.to_info) { | ||
| 263 | # ifdef USE_OPENSSL | ||
| 264 | /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert | ||
| 265 | * parsing We only check the first certificate and assume it's the one of | ||
| 266 | * the server | ||
| 267 | */ | ||
| 268 | char *raw_cert = NULL; | ||
| 269 | bool got_first_cert = false; | ||
| 270 | for (int i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { | ||
| 271 | if (got_first_cert) { | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | |||
| 275 | for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; | ||
| 276 | slist = slist->next) { | ||
| 277 | if (verbose >= 2) { | ||
| 278 | printf("%d ** %s\n", i, slist->data); | ||
| 279 | } | ||
| 280 | if (strncmp(slist->data, "Cert:", 5) == 0) { | ||
| 281 | raw_cert = &slist->data[5]; | ||
| 282 | got_first_cert = true; | ||
| 283 | break; | ||
| 284 | } | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | if (!raw_cert) { | ||
| 289 | snprintf(msg, DEFAULT_BUFFER_SIZE, | ||
| 290 | _("Cannot retrieve certificates from CERTINFO information - " | ||
| 291 | "certificate data was empty")); | ||
| 292 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
| 293 | } | ||
| 294 | BIO *cert_BIO = BIO_new(BIO_s_mem()); | ||
| 295 | BIO_write(cert_BIO, raw_cert, (int)strlen(raw_cert)); | ||
| 296 | cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL); | ||
| 297 | if (!cert) { | ||
| 298 | snprintf( | ||
| 299 | msg, DEFAULT_BUFFER_SIZE, | ||
| 300 | _("Cannot read certificate from CERTINFO information - BIO error")); | ||
| 301 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
| 302 | } | ||
| 303 | BIO_free(cert_BIO); | ||
| 304 | result_ssl = np_net_ssl_check_certificate(cert, config.days_till_exp_warn, | ||
| 305 | config.days_till_exp_crit); | ||
| 306 | if (!config.continue_after_check_cert) { | ||
| 307 | return result_ssl; | ||
| 308 | } | ||
| 309 | # else /* USE_OPENSSL */ | ||
| 310 | /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our | ||
| 311 | * disposal, so we use the libcurl CURLINFO data | ||
| 312 | */ | ||
| 313 | result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, | ||
| 314 | days_till_exp_crit); | ||
| 315 | if (!continue_after_check_cert) { | ||
| 316 | return result_ssl; | ||
| 317 | } | ||
| 318 | # endif /* USE_OPENSSL */ | ||
| 319 | } else { | ||
| 320 | snprintf(msg, DEFAULT_BUFFER_SIZE, | ||
| 321 | _("Cannot retrieve certificates - cURL returned %d - %s"), res, | ||
| 322 | curl_easy_strerror(res)); | ||
| 323 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
| 324 | } | ||
| 325 | } | ||
| 326 | } | 267 | } |
| 327 | } | 268 | } |
| 328 | #endif /* LIBCURL_FEATURE_SSL */ | 269 | #endif |
| 329 | 270 | ||
| 330 | /* we got the data and we executed the request in a given time, so we can append | 271 | /* we got the data and we executed the request in a given time, so we can append |
| 331 | * performance data to the answer always | 272 | * performance data to the answer always |
| 332 | */ | 273 | */ |
| 274 | |||
| 275 | // total time the query took | ||
| 276 | mp_perfdata pd_total_time = perfdata_init(); | ||
| 333 | double total_time; | 277 | double total_time; |
| 334 | handle_curl_option_return_code( | 278 | handle_curl_option_return_code( |
| 335 | curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time), | 279 | curl_easy_getinfo(curl_state.curl, CURLINFO_TOTAL_TIME, &total_time), |
| 336 | "CURLINFO_TOTAL_TIME"); | 280 | "CURLINFO_TOTAL_TIME"); |
| 337 | size_t page_len = get_content_length(curl_state.header_buf, curl_state.body_buf); | 281 | mp_perfdata_value pd_val_total_time = mp_create_pd_value(total_time); |
| 338 | char perfstring[DEFAULT_BUFFER_SIZE]; | 282 | pd_total_time.value = pd_val_total_time; |
| 283 | pd_total_time = mp_pd_set_thresholds(pd_total_time, config.thlds); | ||
| 284 | pd_total_time.label = "time"; | ||
| 285 | pd_total_time.uom = "s"; | ||
| 286 | |||
| 287 | mp_subcheck sc_total_time = mp_subcheck_init(); | ||
| 288 | sc_total_time = mp_set_subcheck_state(sc_total_time, mp_get_pd_status(pd_total_time)); | ||
| 289 | xasprintf(&sc_total_time.output, "Total connection time: %fs", total_time); | ||
| 290 | mp_add_perfdata_to_subcheck(&sc_total_time, pd_total_time); | ||
| 291 | |||
| 292 | mp_add_subcheck_to_subcheck(&sc_result, sc_total_time); | ||
| 293 | |||
| 339 | if (config.show_extended_perfdata) { | 294 | if (config.show_extended_perfdata) { |
| 295 | // overall connection time | ||
| 296 | mp_perfdata pd_time_connect = perfdata_init(); | ||
| 340 | double time_connect; | 297 | double time_connect; |
| 341 | handle_curl_option_return_code( | 298 | handle_curl_option_return_code( |
| 342 | curl_easy_getinfo(curl_state.curl, CURLINFO_CONNECT_TIME, &time_connect), | 299 | curl_easy_getinfo(curl_state.curl, CURLINFO_CONNECT_TIME, &time_connect), |
| 343 | "CURLINFO_CONNECT_TIME"); | 300 | "CURLINFO_CONNECT_TIME"); |
| 344 | 301 | ||
| 302 | mp_perfdata_value pd_val_time_connect = mp_create_pd_value(time_connect); | ||
| 303 | pd_time_connect.value = pd_val_time_connect; | ||
| 304 | pd_time_connect.label = "time"; | ||
| 305 | pd_time_connect.uom = "s"; | ||
| 306 | pd_time_connect = mp_set_pd_max_value( | ||
| 307 | pd_time_connect, mp_create_pd_value(config.curl_config.socket_timeout)); | ||
| 308 | |||
| 309 | pd_time_connect = mp_pd_set_thresholds(pd_time_connect, config.thlds); | ||
| 310 | mp_add_perfdata_to_subcheck(&sc_result, pd_time_connect); | ||
| 311 | |||
| 312 | // application connection time, used to compute other timings | ||
| 345 | double time_appconnect; | 313 | double time_appconnect; |
| 346 | handle_curl_option_return_code( | 314 | handle_curl_option_return_code( |
| 347 | curl_easy_getinfo(curl_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), | 315 | curl_easy_getinfo(curl_state.curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), |
| 348 | "CURLINFO_APPCONNECT_TIME"); | 316 | "CURLINFO_APPCONNECT_TIME"); |
| 349 | 317 | ||
| 350 | double time_headers; | 318 | if (workingState.use_ssl) { |
| 351 | handle_curl_option_return_code( | 319 | mp_perfdata pd_time_tls = perfdata_init(); |
| 352 | curl_easy_getinfo(curl_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers), | 320 | { |
| 353 | "CURLINFO_PRETRANSFER_TIME"); | 321 | mp_perfdata_value pd_val_time_tls = |
| 322 | mp_create_pd_value(time_appconnect - time_connect); | ||
| 323 | |||
| 324 | pd_time_tls.value = pd_val_time_tls; | ||
| 325 | } | ||
| 326 | pd_time_tls.label = "time_tls"; | ||
| 327 | pd_time_tls.uom = "s"; | ||
| 328 | mp_add_perfdata_to_subcheck(&sc_result, pd_time_tls); | ||
| 329 | } | ||
| 330 | |||
| 331 | mp_perfdata pd_time_headers = perfdata_init(); | ||
| 332 | { | ||
| 333 | double time_headers; | ||
| 334 | handle_curl_option_return_code( | ||
| 335 | curl_easy_getinfo(curl_state.curl, CURLINFO_PRETRANSFER_TIME, &time_headers), | ||
| 336 | "CURLINFO_PRETRANSFER_TIME"); | ||
| 337 | |||
| 338 | mp_perfdata_value pd_val_time_headers = | ||
| 339 | mp_create_pd_value(time_headers - time_appconnect); | ||
| 340 | |||
| 341 | pd_time_headers.value = pd_val_time_headers; | ||
| 342 | } | ||
| 343 | pd_time_headers.label = "time_headers"; | ||
| 344 | pd_time_headers.uom = "s"; | ||
| 345 | mp_add_perfdata_to_subcheck(&sc_result, pd_time_headers); | ||
| 354 | 346 | ||
| 347 | mp_perfdata pd_time_firstbyte = perfdata_init(); | ||
| 355 | double time_firstbyte; | 348 | double time_firstbyte; |
| 356 | handle_curl_option_return_code( | 349 | handle_curl_option_return_code( |
| 357 | curl_easy_getinfo(curl_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), | 350 | curl_easy_getinfo(curl_state.curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), |
| 358 | "CURLINFO_STARTTRANSFER_TIME"); | 351 | "CURLINFO_STARTTRANSFER_TIME"); |
| 359 | 352 | ||
| 360 | snprintf( | 353 | mp_perfdata_value pd_val_time_firstbyte = mp_create_pd_value(time_firstbyte); |
| 361 | perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", | 354 | pd_time_firstbyte.value = pd_val_time_firstbyte; |
| 362 | perfd_time(total_time, config.thlds, config.curl_config.socket_timeout), | 355 | pd_time_firstbyte.label = "time_firstbyte"; |
| 363 | perfd_size(page_len, config.min_page_len), | 356 | pd_time_firstbyte.uom = "s"; |
| 364 | perfd_time_connect(time_connect, config.curl_config.socket_timeout), | 357 | mp_add_perfdata_to_subcheck(&sc_result, pd_time_firstbyte); |
| 365 | workingState.use_ssl | 358 | |
| 366 | ? perfd_time_ssl(time_appconnect - time_connect, config.curl_config.socket_timeout) | 359 | mp_perfdata pd_time_transfer = perfdata_init(); |
| 367 | : "", | 360 | pd_time_transfer.value = mp_create_pd_value(total_time - time_firstbyte); |
| 368 | perfd_time_headers(time_headers - time_appconnect, config.curl_config.socket_timeout), | 361 | pd_time_transfer.label = "time_transfer"; |
| 369 | perfd_time_firstbyte(time_firstbyte - time_headers, config.curl_config.socket_timeout), | 362 | pd_time_transfer.uom = "s"; |
| 370 | perfd_time_transfer(total_time - time_firstbyte, config.curl_config.socket_timeout)); | 363 | mp_add_perfdata_to_subcheck(&sc_result, pd_time_transfer); |
| 371 | } else { | ||
| 372 | snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", | ||
| 373 | perfd_time(total_time, config.thlds, config.curl_config.socket_timeout), | ||
| 374 | perfd_size(page_len, config.min_page_len)); | ||
| 375 | } | 364 | } |
| 376 | 365 | ||
| 377 | /* return a CRITICAL status if we couldn't read any data */ | 366 | /* return a CRITICAL status if we couldn't read any data */ |
| 378 | if (strlen(curl_state.header_buf->buf) == 0 && strlen(curl_state.body_buf->buf) == 0) { | 367 | if (strlen(curl_state.header_buf->buf) == 0 && strlen(curl_state.body_buf->buf) == 0) { |
| 379 | die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); | 368 | sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL); |
| 369 | xasprintf(&sc_result.output, "No header received from host"); | ||
| 370 | return sc_result; | ||
| 380 | } | 371 | } |
| 381 | 372 | ||
| 382 | /* get status line of answer, check sanity of HTTP code */ | 373 | /* get status line of answer, check sanity of HTTP code */ |
| 383 | if (curlhelp_parse_statusline(curl_state.header_buf->buf, curl_state.status_line) < 0) { | 374 | if (curlhelp_parse_statusline(curl_state.header_buf->buf, curl_state.status_line) < 0) { |
| 384 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 375 | sc_result = mp_set_subcheck_state(sc_result, STATE_CRITICAL); |
| 385 | "Unparsable status line in %.3g seconds response time|%s\n", total_time, | ||
| 386 | perfstring); | ||
| 387 | /* we cannot know the major/minor version here for sure as we cannot parse the first | 376 | /* we cannot know the major/minor version here for sure as we cannot parse the first |
| 388 | * line */ | 377 | * line */ |
| 389 | die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x unknown - %s", msg); | 378 | xasprintf(&sc_result.output, "HTTP/x.x unknown - Unparsable status line"); |
| 379 | return sc_result; | ||
| 390 | } | 380 | } |
| 381 | |||
| 391 | curl_state.status_line_initialized = true; | 382 | curl_state.status_line_initialized = true; |
| 392 | 383 | ||
| 393 | /* get result code from cURL */ | 384 | /* get result code from cURL */ |
| @@ -406,43 +397,71 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
| 406 | } | 397 | } |
| 407 | 398 | ||
| 408 | /* make sure the status line matches the response we are looking for */ | 399 | /* make sure the status line matches the response we are looking for */ |
| 400 | mp_subcheck sc_expect = mp_subcheck_init(); | ||
| 401 | sc_expect = mp_set_subcheck_default_state(sc_expect, STATE_OK); | ||
| 409 | if (!expected_statuscode(curl_state.status_line->first_line, config.server_expect.string)) { | 402 | if (!expected_statuscode(curl_state.status_line->first_line, config.server_expect.string)) { |
| 410 | if (workingState.serverPort == HTTP_PORT) { | 403 | if (workingState.serverPort == HTTP_PORT) { |
| 411 | snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), | 404 | xasprintf(&sc_expect.output, _("Invalid HTTP response received from host: %s\n"), |
| 412 | curl_state.status_line->first_line); | 405 | curl_state.status_line->first_line); |
| 413 | } else { | 406 | } else { |
| 414 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 407 | xasprintf(&sc_expect.output, |
| 415 | _("Invalid HTTP response received from host on port %d: %s\n"), | 408 | _("Invalid HTTP response received from host on port %d: %s\n"), |
| 416 | workingState.serverPort, curl_state.status_line->first_line); | 409 | workingState.serverPort, curl_state.status_line->first_line); |
| 417 | } | 410 | } |
| 418 | die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, config.show_body ? "\n" : "", | 411 | sc_expect = mp_set_subcheck_default_state(sc_expect, STATE_CRITICAL); |
| 419 | config.show_body ? curl_state.body_buf->buf : ""); | 412 | } else { |
| 413 | xasprintf(&sc_expect.output, _("Status line output matched \"%s\""), | ||
| 414 | config.server_expect.string); | ||
| 420 | } | 415 | } |
| 416 | mp_add_subcheck_to_subcheck(&sc_result, sc_expect); | ||
| 421 | 417 | ||
| 422 | mp_state_enum result = STATE_OK; | 418 | if (!config.server_expect.is_present) { |
| 423 | if (config.server_expect.is_present) { | ||
| 424 | snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), | ||
| 425 | config.server_expect.string); | ||
| 426 | if (verbose) { | ||
| 427 | printf("%s\n", msg); | ||
| 428 | } | ||
| 429 | result = STATE_OK; | ||
| 430 | } else { | ||
| 431 | /* illegal return codes result in a critical state */ | 419 | /* illegal return codes result in a critical state */ |
| 420 | mp_subcheck sc_return_code = mp_subcheck_init(); | ||
| 421 | sc_return_code = mp_set_subcheck_default_state(sc_return_code, STATE_OK); | ||
| 422 | xasprintf(&sc_return_code.output, "HTTP return code: %d", | ||
| 423 | curl_state.status_line->http_code); | ||
| 424 | |||
| 432 | if (httpReturnCode >= 600 || httpReturnCode < 100) { | 425 | if (httpReturnCode >= 600 || httpReturnCode < 100) { |
| 433 | die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), | 426 | sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_CRITICAL); |
| 434 | curl_state.status_line->http_code, curl_state.status_line->msg); | 427 | xasprintf(&sc_return_code.output, _("Invalid Status (%d, %.40s)"), |
| 435 | /* server errors result in a critical state */ | 428 | curl_state.status_line->http_code, curl_state.status_line->msg); |
| 436 | } else if (httpReturnCode >= 500) { | 429 | mp_add_subcheck_to_subcheck(&sc_result, sc_return_code); |
| 437 | result = STATE_CRITICAL; | 430 | return sc_result; |
| 431 | } | ||
| 432 | |||
| 433 | // server errors result in a critical state | ||
| 434 | if (httpReturnCode >= 500) { | ||
| 435 | sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_CRITICAL); | ||
| 438 | /* client errors result in a warning state */ | 436 | /* client errors result in a warning state */ |
| 439 | } else if (httpReturnCode >= 400) { | 437 | } else if (httpReturnCode >= 400) { |
| 440 | result = STATE_WARNING; | 438 | sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_WARNING); |
| 441 | /* check redirected page if specified */ | 439 | /* check redirected page if specified */ |
| 442 | } else if (httpReturnCode >= 300) { | 440 | } else if (httpReturnCode >= 300) { |
| 443 | if (config.on_redirect_dependent) { | 441 | if (config.on_redirect_dependent) { |
| 444 | if (config.followmethod == FOLLOW_LIBCURL) { | 442 | if (config.followmethod == FOLLOW_LIBCURL) { |
| 445 | httpReturnCode = curl_state.status_line->http_code; | 443 | httpReturnCode = curl_state.status_line->http_code; |
| 444 | handle_curl_option_return_code( | ||
| 445 | curl_easy_getinfo(curl_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth), | ||
| 446 | "CURLINFO_REDIRECT_COUNT"); | ||
| 447 | |||
| 448 | if (verbose >= 2) { | ||
| 449 | printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); | ||
| 450 | } | ||
| 451 | |||
| 452 | mp_subcheck sc_redir_depth = mp_subcheck_init(); | ||
| 453 | if (redir_depth > config.max_depth) { | ||
| 454 | xasprintf(&sc_redir_depth.output, | ||
| 455 | "maximum redirection depth %d exceeded in libcurl", | ||
| 456 | config.max_depth); | ||
| 457 | sc_redir_depth = mp_set_subcheck_state(sc_redir_depth, STATE_CRITICAL); | ||
| 458 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); | ||
| 459 | return sc_result; | ||
| 460 | } | ||
| 461 | xasprintf(&sc_redir_depth.output, "redirection depth %d (of a maximum %d)", | ||
| 462 | redir_depth, config.max_depth); | ||
| 463 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); | ||
| 464 | |||
| 446 | } else { | 465 | } else { |
| 447 | /* old check_http style redirection, if we come | 466 | /* old check_http style redirection, if we come |
| 448 | * back here, we are in the same status as with | 467 | * back here, we are in the same status as with |
| @@ -451,54 +470,53 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
| 451 | redir_wrapper redir_result = | 470 | redir_wrapper redir_result = |
| 452 | redir(curl_state.header_buf, config, redir_depth, workingState); | 471 | redir(curl_state.header_buf, config, redir_depth, workingState); |
| 453 | cleanup(curl_state); | 472 | cleanup(curl_state); |
| 454 | check_http(config, redir_result.working_state, redir_result.redir_depth); | 473 | mp_subcheck sc_redir = |
| 474 | check_http(config, redir_result.working_state, redir_result.redir_depth); | ||
| 475 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir); | ||
| 476 | |||
| 477 | return sc_result; | ||
| 455 | } | 478 | } |
| 456 | } else { | 479 | } else { |
| 457 | /* this is a specific code in the command line to | 480 | /* this is a specific code in the command line to |
| 458 | * be returned when a redirection is encountered | 481 | * be returned when a redirection is encountered |
| 459 | */ | 482 | */ |
| 483 | sc_return_code = | ||
| 484 | mp_set_subcheck_state(sc_return_code, config.on_redirect_result_state); | ||
| 460 | } | 485 | } |
| 461 | result = max_state_alt(config.on_redirect_result_state, result); | ||
| 462 | /* all other codes are considered ok */ | ||
| 463 | } else { | 486 | } else { |
| 464 | result = STATE_OK; | 487 | sc_return_code = mp_set_subcheck_state(sc_return_code, STATE_OK); |
| 465 | } | ||
| 466 | } | ||
| 467 | |||
| 468 | /* libcurl redirection internally, handle error states here */ | ||
| 469 | if (config.followmethod == FOLLOW_LIBCURL) { | ||
| 470 | handle_curl_option_return_code( | ||
| 471 | curl_easy_getinfo(curl_state.curl, CURLINFO_REDIRECT_COUNT, &redir_depth), | ||
| 472 | "CURLINFO_REDIRECT_COUNT"); | ||
| 473 | |||
| 474 | if (verbose >= 2) { | ||
| 475 | printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); | ||
| 476 | } | 488 | } |
| 477 | 489 | ||
| 478 | if (redir_depth > config.max_depth) { | 490 | mp_add_subcheck_to_subcheck(&sc_result, sc_return_code); |
| 479 | snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", | ||
| 480 | config.max_depth); | ||
| 481 | die(STATE_WARNING, "HTTP WARNING - %s", msg); | ||
| 482 | } | ||
| 483 | } | 491 | } |
| 484 | 492 | ||
| 485 | /* check status codes, set exit status accordingly */ | 493 | /* check status codes, set exit status accordingly */ |
| 486 | if (curl_state.status_line->http_code != httpReturnCode) { | 494 | if (curl_state.status_line->http_code != httpReturnCode) { |
| 487 | die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"), | 495 | mp_subcheck sc_http_return_code_sanity = mp_subcheck_init(); |
| 488 | string_statuscode(curl_state.status_line->http_major, curl_state.status_line->http_minor), | 496 | sc_http_return_code_sanity = |
| 489 | curl_state.status_line->http_code, curl_state.status_line->msg, httpReturnCode); | 497 | mp_set_subcheck_state(sc_http_return_code_sanity, STATE_CRITICAL); |
| 498 | xasprintf(&sc_http_return_code_sanity.output, | ||
| 499 | _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"), | ||
| 500 | string_statuscode(curl_state.status_line->http_major, | ||
| 501 | curl_state.status_line->http_minor), | ||
| 502 | curl_state.status_line->http_code, curl_state.status_line->msg, httpReturnCode); | ||
| 503 | |||
| 504 | mp_add_subcheck_to_subcheck(&sc_result, sc_http_return_code_sanity); | ||
| 505 | return sc_result; | ||
| 490 | } | 506 | } |
| 491 | 507 | ||
| 492 | if (config.maximum_age >= 0) { | 508 | if (config.maximum_age >= 0) { |
| 493 | result = max_state_alt( | 509 | mp_subcheck sc_max_age = check_document_dates(curl_state.header_buf, config.maximum_age); |
| 494 | check_document_dates(curl_state.header_buf, msg, config.maximum_age), result); | 510 | mp_add_subcheck_to_subcheck(&sc_result, sc_max_age); |
| 495 | } | 511 | } |
| 496 | 512 | ||
| 497 | /* Page and Header content checks go here */ | 513 | /* Page and Header content checks go here */ |
| 498 | |||
| 499 | if (strlen(config.header_expect)) { | 514 | if (strlen(config.header_expect)) { |
| 500 | if (!strstr(curl_state.header_buf->buf, config.header_expect)) { | 515 | mp_subcheck sc_header_expect = mp_subcheck_init(); |
| 516 | sc_header_expect = mp_set_subcheck_default_state(sc_header_expect, STATE_OK); | ||
| 517 | xasprintf(&sc_header_expect.output, "Expect %s in header", config.header_expect); | ||
| 501 | 518 | ||
| 519 | if (!strstr(curl_state.header_buf->buf, config.header_expect)) { | ||
| 502 | char output_header_search[30] = ""; | 520 | char output_header_search[30] = ""; |
| 503 | strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search)); | 521 | strncpy(&output_header_search[0], config.header_expect, sizeof(output_header_search)); |
| 504 | 522 | ||
| @@ -506,22 +524,23 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
| 506 | bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4); | 524 | bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4); |
| 507 | } | 525 | } |
| 508 | 526 | ||
| 509 | char tmp[DEFAULT_BUFFER_SIZE]; | 527 | xasprintf(&sc_header_expect.output, _("header '%s' not found on '%s://%s:%d%s', "), |
| 510 | 528 | output_header_search, workingState.use_ssl ? "https" : "http", | |
| 511 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), | 529 | workingState.host_name ? workingState.host_name : workingState.server_address, |
| 512 | msg, output_header_search, workingState.use_ssl ? "https" : "http", | 530 | workingState.serverPort, workingState.server_url); |
| 513 | workingState.host_name ? workingState.host_name : workingState.server_address, | ||
| 514 | workingState.serverPort, workingState.server_url); | ||
| 515 | |||
| 516 | strcpy(msg, tmp); | ||
| 517 | 531 | ||
| 518 | result = STATE_CRITICAL; | 532 | sc_header_expect = mp_set_subcheck_state(sc_header_expect, STATE_CRITICAL); |
| 519 | } | 533 | } |
| 534 | |||
| 535 | mp_add_subcheck_to_subcheck(&sc_result, sc_header_expect); | ||
| 520 | } | 536 | } |
| 521 | 537 | ||
| 522 | if (strlen(config.string_expect)) { | 538 | if (strlen(config.string_expect)) { |
| 523 | if (!strstr(curl_state.body_buf->buf, config.string_expect)) { | 539 | mp_subcheck sc_string_expect = mp_subcheck_init(); |
| 540 | sc_string_expect = mp_set_subcheck_default_state(sc_string_expect, STATE_OK); | ||
| 541 | xasprintf(&sc_string_expect.output, "Expect string \"%s\" in body", config.string_expect); | ||
| 524 | 542 | ||
| 543 | if (!strstr(curl_state.body_buf->buf, config.string_expect)) { | ||
| 525 | char output_string_search[30] = ""; | 544 | char output_string_search[30] = ""; |
| 526 | strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search)); | 545 | strncpy(&output_string_search[0], config.string_expect, sizeof(output_string_search)); |
| 527 | 546 | ||
| @@ -529,93 +548,86 @@ mp_state_enum check_http(const check_curl_config config, check_curl_working_stat | |||
| 529 | bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4); | 548 | bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4); |
| 530 | } | 549 | } |
| 531 | 550 | ||
| 532 | char tmp[DEFAULT_BUFFER_SIZE]; | 551 | xasprintf(&sc_string_expect.output, _("string '%s' not found on '%s://%s:%d%s', "), |
| 533 | 552 | output_string_search, workingState.use_ssl ? "https" : "http", | |
| 534 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), | 553 | workingState.host_name ? workingState.host_name : workingState.server_address, |
| 535 | msg, output_string_search, workingState.use_ssl ? "https" : "http", | 554 | workingState.serverPort, workingState.server_url); |
| 536 | workingState.host_name ? workingState.host_name : workingState.server_address, | ||
| 537 | workingState.serverPort, workingState.server_url); | ||
| 538 | 555 | ||
| 539 | strcpy(msg, tmp); | 556 | sc_string_expect = mp_set_subcheck_state(sc_string_expect, STATE_CRITICAL); |
| 540 | |||
| 541 | result = STATE_CRITICAL; | ||
| 542 | } | 557 | } |
| 558 | |||
| 559 | mp_add_subcheck_to_subcheck(&sc_result, sc_string_expect); | ||
| 543 | } | 560 | } |
| 544 | 561 | ||
| 545 | if (strlen(config.regexp)) { | 562 | if (strlen(config.regexp)) { |
| 563 | mp_subcheck sc_body_regex = mp_subcheck_init(); | ||
| 564 | xasprintf(&sc_body_regex.output, "Regex \"%s\" in body matched", config.regexp); | ||
| 546 | regmatch_t pmatch[REGS]; | 565 | regmatch_t pmatch[REGS]; |
| 566 | |||
| 547 | int errcode = regexec(&config.compiled_regex, curl_state.body_buf->buf, REGS, pmatch, 0); | 567 | int errcode = regexec(&config.compiled_regex, curl_state.body_buf->buf, REGS, pmatch, 0); |
| 548 | if ((errcode == 0 && !config.invert_regex) || | ||
| 549 | (errcode == REG_NOMATCH && config.invert_regex)) { | ||
| 550 | /* OK - No-op to avoid changing the logic around it */ | ||
| 551 | result = max_state_alt(STATE_OK, result); | ||
| 552 | } else if ((errcode == REG_NOMATCH && !config.invert_regex) || | ||
| 553 | (errcode == 0 && config.invert_regex)) { | ||
| 554 | if (!config.invert_regex) { | ||
| 555 | char tmp[DEFAULT_BUFFER_SIZE]; | ||
| 556 | |||
| 557 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); | ||
| 558 | strcpy(msg, tmp); | ||
| 559 | 568 | ||
| 569 | if (errcode == 0) { | ||
| 570 | // got a match | ||
| 571 | if (config.invert_regex) { | ||
| 572 | sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_OK); | ||
| 560 | } else { | 573 | } else { |
| 561 | char tmp[DEFAULT_BUFFER_SIZE]; | 574 | sc_body_regex = mp_set_subcheck_state(sc_body_regex, config.state_regex); |
| 562 | |||
| 563 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); | ||
| 564 | strcpy(msg, tmp); | ||
| 565 | } | 575 | } |
| 566 | result = config.state_regex; | ||
| 567 | } else { | 576 | } else { |
| 568 | regerror(errcode, &config.compiled_regex, errbuf, MAX_INPUT_BUFFER); | 577 | xasprintf(&sc_body_regex.output, "%s not", sc_body_regex.output); |
| 569 | 578 | // got no match | |
| 570 | char tmp[DEFAULT_BUFFER_SIZE]; | 579 | if (config.invert_regex) { |
| 571 | 580 | sc_body_regex = mp_set_subcheck_state(sc_body_regex, config.state_regex); | |
| 572 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); | 581 | } else { |
| 573 | strcpy(msg, tmp); | 582 | sc_body_regex = mp_set_subcheck_state(sc_body_regex, STATE_OK); |
| 574 | result = STATE_UNKNOWN; | 583 | } |
| 575 | } | 584 | } |
| 576 | } | ||
| 577 | 585 | ||
| 578 | /* make sure the page is of an appropriate size */ | 586 | mp_add_subcheck_to_subcheck(&sc_result, sc_body_regex); |
| 579 | if ((config.max_page_len > 0) && (page_len > config.max_page_len)) { | 587 | } |
| 580 | char tmp[DEFAULT_BUFFER_SIZE]; | ||
| 581 | 588 | ||
| 582 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %zu too large, "), msg, page_len); | 589 | // size a.k.a. page length |
| 590 | mp_perfdata pd_page_length = perfdata_init(); | ||
| 591 | size_t page_len = get_content_length(curl_state.header_buf, curl_state.body_buf); | ||
| 592 | mp_perfdata_value pd_val_page_length = mp_create_pd_value(page_len); | ||
| 593 | pd_page_length.value = pd_val_page_length; | ||
| 594 | pd_page_length.label = "size"; | ||
| 595 | pd_page_length.uom = "B"; | ||
| 596 | pd_page_length.min = mp_create_pd_value(0); | ||
| 597 | pd_page_length.warn = config.page_length_limits; | ||
| 598 | pd_page_length.warn_present = true; | ||
| 583 | 599 | ||
| 584 | strcpy(msg, tmp); | 600 | /* make sure the page is of an appropriate size */ |
| 601 | if (config.page_length_limits_is_set) { | ||
| 602 | mp_thresholds page_length_threshold = mp_thresholds_init(); | ||
| 603 | page_length_threshold.warning = config.page_length_limits; | ||
| 604 | page_length_threshold.warning_is_set = true; | ||
| 585 | 605 | ||
| 586 | result = max_state_alt(STATE_WARNING, result); | 606 | pd_page_length = mp_pd_set_thresholds(pd_page_length, page_length_threshold); |
| 587 | 607 | ||
| 588 | } else if ((config.min_page_len > 0) && (page_len < config.min_page_len)) { | 608 | mp_subcheck sc_page_length = mp_subcheck_init(); |
| 589 | char tmp[DEFAULT_BUFFER_SIZE]; | ||
| 590 | 609 | ||
| 591 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %zu too small, "), msg, page_len); | 610 | mp_add_perfdata_to_subcheck(&sc_page_length, pd_page_length); |
| 592 | strcpy(msg, tmp); | ||
| 593 | result = max_state_alt(STATE_WARNING, result); | ||
| 594 | } | ||
| 595 | 611 | ||
| 596 | /* -w, -c: check warning and critical level */ | 612 | mp_state_enum tmp_state = mp_get_pd_status(pd_page_length); |
| 597 | result = max_state_alt(get_status(total_time, config.thlds), result); | 613 | sc_page_length = mp_set_subcheck_state(sc_page_length, tmp_state); |
| 598 | 614 | ||
| 599 | /* Cut-off trailing characters */ | 615 | switch (tmp_state) { |
| 600 | if (strlen(msg) >= 2) { | 616 | case STATE_CRITICAL: |
| 601 | if (msg[strlen(msg) - 2] == ',') { | 617 | case STATE_WARNING: |
| 602 | msg[strlen(msg) - 2] = '\0'; | 618 | xasprintf(&sc_page_length.output, _("page size %zu violates threshold"), page_len); |
| 603 | } else { | 619 | break; |
| 604 | msg[strlen(msg) - 3] = '\0'; | 620 | case STATE_OK: |
| 621 | xasprintf(&sc_page_length.output, _("page size %zu is OK"), page_len); | ||
| 622 | break; | ||
| 623 | default: | ||
| 624 | assert(false); | ||
| 605 | } | 625 | } |
| 626 | |||
| 627 | mp_add_subcheck_to_subcheck(&sc_result, sc_page_length); | ||
| 606 | } | 628 | } |
| 607 | 629 | ||
| 608 | /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), | 630 | return sc_result; |
| 609 | * msg); */ | ||
| 610 | die((int)max_state_alt(result, result_ssl), | ||
| 611 | "HTTP %s: %s %d %s%s%s - %zu bytes in %.3f second response time %s|%s\n%s%s", | ||
| 612 | state_text(result), | ||
| 613 | string_statuscode(curl_state.status_line->http_major, curl_state.status_line->http_minor), | ||
| 614 | curl_state.status_line->http_code, curl_state.status_line->msg, strlen(msg) > 0 ? " - " : "", | ||
| 615 | msg, page_len, total_time, (config.display_html ? "</A>" : ""), perfstring, | ||
| 616 | (config.show_body ? curl_state.body_buf->buf : ""), (config.show_body ? "\n" : "")); | ||
| 617 | |||
| 618 | return max_state_alt(result, result_ssl); | ||
| 619 | } | 631 | } |
| 620 | 632 | ||
| 621 | int uri_strcmp(const UriTextRangeA range, const char *stringToCompare) { | 633 | int uri_strcmp(const UriTextRangeA range, const char *stringToCompare) { |
| @@ -895,8 +907,6 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
| 895 | } | 907 | } |
| 896 | 908 | ||
| 897 | int option = 0; | 909 | int option = 0; |
| 898 | char *warning_thresholds = NULL; | ||
| 899 | char *critical_thresholds = NULL; | ||
| 900 | int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; | 910 | int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; |
| 901 | bool specify_port = false; | 911 | bool specify_port = false; |
| 902 | bool enable_tls = false; | 912 | bool enable_tls = false; |
| @@ -931,11 +941,22 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
| 931 | } | 941 | } |
| 932 | break; | 942 | break; |
| 933 | case 'c': /* critical time threshold */ | 943 | case 'c': /* critical time threshold */ |
| 934 | critical_thresholds = optarg; | 944 | { |
| 935 | break; | 945 | mp_range_parsed critical_range = mp_parse_range_string(optarg); |
| 946 | if (critical_range.error != MP_PARSING_SUCCES) { | ||
| 947 | die(STATE_UNKNOWN, "failed to parse critical threshold: %s", optarg); | ||
| 948 | } | ||
| 949 | result.config.thlds = mp_thresholds_set_crit(result.config.thlds, critical_range.range); | ||
| 950 | } break; | ||
| 936 | case 'w': /* warning time threshold */ | 951 | case 'w': /* warning time threshold */ |
| 937 | warning_thresholds = optarg; | 952 | { |
| 938 | break; | 953 | mp_range_parsed warning_range = mp_parse_range_string(optarg); |
| 954 | |||
| 955 | if (warning_range.error != MP_PARSING_SUCCES) { | ||
| 956 | die(STATE_UNKNOWN, "failed to parse warning threshold: %s", optarg); | ||
| 957 | } | ||
| 958 | result.config.thlds = mp_thresholds_set_warn(result.config.thlds, warning_range.range); | ||
| 959 | } break; | ||
| 939 | case 'H': /* virtual host */ | 960 | case 'H': /* virtual host */ |
| 940 | result.config.initial_config.host_name = strdup(optarg); | 961 | result.config.initial_config.host_name = strdup(optarg); |
| 941 | char *tmp_string; | 962 | char *tmp_string; |
| @@ -1207,27 +1228,14 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
| 1207 | break; | 1228 | break; |
| 1208 | case 'm': /* min_page_length */ | 1229 | case 'm': /* min_page_length */ |
| 1209 | { | 1230 | { |
| 1210 | char *tmp; | 1231 | mp_range_parsed foo = mp_parse_range_string(optarg); |
| 1211 | if (strchr(optarg, ':') != (char *)NULL) { | ||
| 1212 | /* range, so get two values, min:max */ | ||
| 1213 | tmp = strtok(optarg, ":"); | ||
| 1214 | if (tmp == NULL) { | ||
| 1215 | printf("Bad format: try \"-m min:max\"\n"); | ||
| 1216 | exit(STATE_WARNING); | ||
| 1217 | } else { | ||
| 1218 | result.config.min_page_len = atol(tmp); | ||
| 1219 | } | ||
| 1220 | 1232 | ||
| 1221 | tmp = strtok(NULL, ":"); | 1233 | if (foo.error != MP_PARSING_SUCCES) { |
| 1222 | if (tmp == NULL) { | 1234 | die(STATE_CRITICAL, "failed to parse page size limits: %s", optarg); |
| 1223 | printf("Bad format: try \"-m min:max\"\n"); | ||
| 1224 | exit(STATE_WARNING); | ||
| 1225 | } else { | ||
| 1226 | result.config.max_page_len = atol(tmp); | ||
| 1227 | } | ||
| 1228 | } else { | ||
| 1229 | result.config.min_page_len = atol(optarg); | ||
| 1230 | } | 1235 | } |
| 1236 | |||
| 1237 | result.config.page_length_limits = foo.range; | ||
| 1238 | result.config.page_length_limits_is_set = true; | ||
| 1231 | break; | 1239 | break; |
| 1232 | } | 1240 | } |
| 1233 | case 'N': /* no-body */ | 1241 | case 'N': /* no-body */ |
| @@ -1401,16 +1409,6 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
| 1401 | } | 1409 | } |
| 1402 | } | 1410 | } |
| 1403 | 1411 | ||
| 1404 | set_thresholds(&result.config.thlds, warning_thresholds, critical_thresholds); | ||
| 1405 | |||
| 1406 | if (critical_thresholds && | ||
| 1407 | result.config.thlds->critical->end > (double)result.config.curl_config.socket_timeout) { | ||
| 1408 | result.config.curl_config.socket_timeout = (int)result.config.thlds->critical->end + 1; | ||
| 1409 | } | ||
| 1410 | if (verbose >= 2) { | ||
| 1411 | printf("* Socket timeout set to %ld seconds\n", result.config.curl_config.socket_timeout); | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | if (result.config.initial_config.http_method == NULL) { | 1412 | if (result.config.initial_config.http_method == NULL) { |
| 1415 | result.config.initial_config.http_method = strdup("GET"); | 1413 | result.config.initial_config.http_method = strdup("GET"); |
| 1416 | } | 1414 | } |
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c index e33f2aa9..49949ccb 100644 --- a/plugins/check_curl.d/check_curl_helpers.c +++ b/plugins/check_curl.d/check_curl_helpers.c | |||
| @@ -5,9 +5,12 @@ | |||
| 5 | #include <netdb.h> | 5 | #include <netdb.h> |
| 6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
| 7 | #include "../utils.h" | 7 | #include "../utils.h" |
| 8 | #include "check_curl.d/config.h" | ||
| 9 | #include "output.h" | ||
| 10 | #include "perfdata.h" | ||
| 11 | #include "states.h" | ||
| 8 | 12 | ||
| 9 | extern int verbose; | 13 | extern int verbose; |
| 10 | char msg[DEFAULT_BUFFER_SIZE]; | ||
| 11 | char errbuf[MAX_INPUT_BUFFER]; | 14 | char errbuf[MAX_INPUT_BUFFER]; |
| 12 | bool is_openssl_callback = false; | 15 | bool is_openssl_callback = false; |
| 13 | bool add_sslctx_verify_fun = false; | 16 | bool add_sslctx_verify_fun = false; |
| @@ -127,10 +130,9 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 127 | int res; | 130 | int res; |
| 128 | if ((res = lookup_host(working_state.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2, | 131 | if ((res = lookup_host(working_state.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2, |
| 129 | config.sin_family)) != 0) { | 132 | config.sin_family)) != 0) { |
| 130 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 133 | die(STATE_CRITICAL, |
| 131 | _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), | 134 | _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), |
| 132 | working_state.server_address, res, gai_strerror(res)); | 135 | working_state.server_address, res, gai_strerror(res)); |
| 133 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
| 134 | } | 136 | } |
| 135 | snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", working_state.host_name, | 137 | snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", working_state.host_name, |
| 136 | working_state.serverPort, addrstr); | 138 | working_state.serverPort, addrstr); |
| @@ -154,12 +156,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 154 | } | 156 | } |
| 155 | 157 | ||
| 156 | /* compose URL: use the address we want to connect to, set Host: header later */ | 158 | /* compose URL: use the address we want to connect to, set Host: header later */ |
| 157 | char url[DEFAULT_BUFFER_SIZE]; | 159 | char *url = fmt_url(working_state); |
| 158 | snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", working_state.use_ssl ? "https" : "http", | ||
| 159 | (working_state.use_ssl & (working_state.host_name != NULL)) | ||
| 160 | ? working_state.host_name | ||
| 161 | : working_state.server_address, | ||
| 162 | working_state.serverPort, working_state.server_url); | ||
| 163 | 160 | ||
| 164 | if (verbose >= 1) { | 161 | if (verbose >= 1) { |
| 165 | printf("* curl CURLOPT_URL: %s\n", url); | 162 | printf("* curl CURLOPT_URL: %s\n", url); |
| @@ -167,6 +164,8 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 167 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, url), | 164 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_URL, url), |
| 168 | "CURLOPT_URL"); | 165 | "CURLOPT_URL"); |
| 169 | 166 | ||
| 167 | free(url); | ||
| 168 | |||
| 170 | /* extract proxy information for legacy proxy https requests */ | 169 | /* extract proxy information for legacy proxy https requests */ |
| 171 | if (!strcmp(working_state.http_method, "CONNECT") || | 170 | if (!strcmp(working_state.http_method, "CONNECT") || |
| 172 | strstr(working_state.server_url, "http") == working_state.server_url) { | 171 | strstr(working_state.server_url, "http") == working_state.server_url) { |
| @@ -548,10 +547,8 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 548 | 547 | ||
| 549 | void handle_curl_option_return_code(CURLcode res, const char *option) { | 548 | void handle_curl_option_return_code(CURLcode res, const char *option) { |
| 550 | if (res != CURLE_OK) { | 549 | if (res != CURLE_OK) { |
| 551 | snprintf(msg, DEFAULT_BUFFER_SIZE, | 550 | die(STATE_CRITICAL, _("Error while setting cURL option '%s': cURL returned %d - %s"), |
| 552 | _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res, | 551 | option, res, curl_easy_strerror(res)); |
| 553 | curl_easy_strerror(res)); | ||
| 554 | die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
| 555 | } | 552 | } |
| 556 | } | 553 | } |
| 557 | 554 | ||
| @@ -618,9 +615,9 @@ check_curl_config check_curl_config_init() { | |||
| 618 | .continue_after_check_cert = false, | 615 | .continue_after_check_cert = false, |
| 619 | .days_till_exp_warn = 0, | 616 | .days_till_exp_warn = 0, |
| 620 | .days_till_exp_crit = 0, | 617 | .days_till_exp_crit = 0, |
| 621 | .thlds = NULL, | 618 | .thlds = mp_thresholds_init(), |
| 622 | .min_page_len = 0, | 619 | .page_length_limits = mp_range_init(), |
| 623 | .max_page_len = 0, | 620 | .page_length_limits_is_set = false, |
| 624 | .server_expect = | 621 | .server_expect = |
| 625 | { | 622 | { |
| 626 | .string = HTTP_EXPECT, | 623 | .string = HTTP_EXPECT, |
| @@ -729,9 +726,7 @@ size_t get_content_length(const curlhelp_write_curlbuf *header_buf, | |||
| 729 | return header_buf->buflen + body_buf->buflen; | 726 | return header_buf->buflen + body_buf->buflen; |
| 730 | } | 727 | } |
| 731 | 728 | ||
| 732 | mp_state_enum check_document_dates(const curlhelp_write_curlbuf *header_buf, | 729 | mp_subcheck check_document_dates(const curlhelp_write_curlbuf *header_buf, const int maximum_age) { |
| 733 | const char msg[static DEFAULT_BUFFER_SIZE], | ||
| 734 | const int maximum_age) { | ||
| 735 | struct phr_header headers[255]; | 730 | struct phr_header headers[255]; |
| 736 | size_t nof_headers = 255; | 731 | size_t nof_headers = 255; |
| 737 | curlhelp_statusline status_line; | 732 | curlhelp_statusline status_line; |
| @@ -747,73 +742,54 @@ mp_state_enum check_document_dates(const curlhelp_write_curlbuf *header_buf, | |||
| 747 | char *server_date = get_header_value(headers, nof_headers, "date"); | 742 | char *server_date = get_header_value(headers, nof_headers, "date"); |
| 748 | char *document_date = get_header_value(headers, nof_headers, "last-modified"); | 743 | char *document_date = get_header_value(headers, nof_headers, "last-modified"); |
| 749 | 744 | ||
| 750 | mp_state_enum date_result = STATE_OK; | 745 | mp_subcheck sc_document_dates = mp_subcheck_init(); |
| 751 | if (!server_date || !*server_date) { | 746 | if (!server_date || !*server_date) { |
| 752 | char tmp[DEFAULT_BUFFER_SIZE]; | 747 | xasprintf(&sc_document_dates.output, _("Server date unknown")); |
| 753 | 748 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_UNKNOWN); | |
| 754 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), msg); | ||
| 755 | strcpy(msg, tmp); | ||
| 756 | |||
| 757 | date_result = max_state_alt(STATE_UNKNOWN, date_result); | ||
| 758 | |||
| 759 | } else if (!document_date || !*document_date) { | 749 | } else if (!document_date || !*document_date) { |
| 760 | char tmp[DEFAULT_BUFFER_SIZE]; | 750 | xasprintf(&sc_document_dates.output, _("Document modification date unknown, ")); |
| 761 | 751 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); | |
| 762 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), msg); | ||
| 763 | strcpy(msg, tmp); | ||
| 764 | |||
| 765 | date_result = max_state_alt(STATE_CRITICAL, date_result); | ||
| 766 | |||
| 767 | } else { | 752 | } else { |
| 768 | time_t srv_data = curl_getdate(server_date, NULL); | 753 | time_t srv_data = curl_getdate(server_date, NULL); |
| 769 | time_t doc_data = curl_getdate(document_date, NULL); | 754 | time_t doc_data = curl_getdate(document_date, NULL); |
| 755 | |||
| 770 | if (verbose >= 2) { | 756 | if (verbose >= 2) { |
| 771 | printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, | 757 | printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, |
| 772 | document_date, (int)doc_data); | 758 | document_date, (int)doc_data); |
| 773 | } | 759 | } |
| 774 | if (srv_data <= 0) { | ||
| 775 | char tmp[DEFAULT_BUFFER_SIZE]; | ||
| 776 | 760 | ||
| 777 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), msg, | 761 | if (srv_data <= 0) { |
| 778 | server_date); | 762 | xasprintf(&sc_document_dates.output, _("Server date \"%100s\" unparsable"), |
| 779 | strcpy(msg, tmp); | 763 | server_date); |
| 780 | 764 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); | |
| 781 | date_result = max_state_alt(STATE_CRITICAL, date_result); | ||
| 782 | } else if (doc_data <= 0) { | 765 | } else if (doc_data <= 0) { |
| 783 | char tmp[DEFAULT_BUFFER_SIZE]; | ||
| 784 | |||
| 785 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), msg, | ||
| 786 | document_date); | ||
| 787 | strcpy(msg, tmp); | ||
| 788 | 766 | ||
| 789 | date_result = max_state_alt(STATE_CRITICAL, date_result); | 767 | xasprintf(&sc_document_dates.output, _("Document date \"%100s\" unparsable"), |
| 768 | document_date); | ||
| 769 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); | ||
| 790 | } else if (doc_data > srv_data + 30) { | 770 | } else if (doc_data > srv_data + 30) { |
| 791 | char tmp[DEFAULT_BUFFER_SIZE]; | ||
| 792 | 771 | ||
| 793 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), msg, | 772 | xasprintf(&sc_document_dates.output, _("Document is %d seconds in the future"), |
| 794 | (int)doc_data - (int)srv_data); | 773 | (int)doc_data - (int)srv_data); |
| 795 | strcpy(msg, tmp); | ||
| 796 | 774 | ||
| 797 | date_result = max_state_alt(STATE_CRITICAL, date_result); | 775 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); |
| 798 | } else if (doc_data < srv_data - maximum_age) { | 776 | } else if (doc_data < srv_data - maximum_age) { |
| 799 | time_t last_modified = (srv_data - doc_data); | 777 | time_t last_modified = (srv_data - doc_data); |
| 800 | if (last_modified > (60 * 60 * 24 * 2)) { | 778 | if (last_modified > (60 * 60 * 24 * 2)) { // two days hardcoded? |
| 801 | char tmp[DEFAULT_BUFFER_SIZE]; | 779 | xasprintf(&sc_document_dates.output, _("Last modified %.1f days ago"), |
| 802 | 780 | ((float)last_modified) / (60 * 60 * 24)); | |
| 803 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), msg, | 781 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); |
| 804 | ((float)last_modified) / (60 * 60 * 24)); | ||
| 805 | strcpy(msg, tmp); | ||
| 806 | |||
| 807 | date_result = max_state_alt(STATE_CRITICAL, date_result); | ||
| 808 | } else { | 782 | } else { |
| 809 | char tmp[DEFAULT_BUFFER_SIZE]; | 783 | xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), |
| 810 | 784 | last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60); | |
| 811 | snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %ld:%02ld:%02ld ago, "), msg, | 785 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); |
| 812 | last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60); | ||
| 813 | strcpy(msg, tmp); | ||
| 814 | |||
| 815 | date_result = max_state_alt(STATE_CRITICAL, date_result); | ||
| 816 | } | 786 | } |
| 787 | } else { | ||
| 788 | // TODO is this the OK case? | ||
| 789 | time_t last_modified = (srv_data - doc_data); | ||
| 790 | xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), | ||
| 791 | last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60); | ||
| 792 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_OK); | ||
| 817 | } | 793 | } |
| 818 | } | 794 | } |
| 819 | 795 | ||
| @@ -824,7 +800,7 @@ mp_state_enum check_document_dates(const curlhelp_write_curlbuf *header_buf, | |||
| 824 | free(document_date); | 800 | free(document_date); |
| 825 | } | 801 | } |
| 826 | 802 | ||
| 827 | return date_result; | 803 | return sc_document_dates; |
| 828 | } | 804 | } |
| 829 | 805 | ||
| 830 | void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); } | 806 | void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); } |
| @@ -1172,46 +1148,117 @@ char *string_statuscode(int major, int minor) { | |||
| 1172 | return buf; | 1148 | return buf; |
| 1173 | } | 1149 | } |
| 1174 | 1150 | ||
| 1175 | char *perfd_time(double elapsed_time, thresholds *thlds, long socket_timeout) { | 1151 | /* check whether a file exists */ |
| 1176 | return fperfdata("time", elapsed_time, "s", (thlds->warning != NULL), | 1152 | void test_file(char *path) { |
| 1177 | thlds->warning ? thlds->warning->end : 0, (thlds->critical != NULL), | 1153 | if (access(path, R_OK) == 0) { |
| 1178 | thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout); | 1154 | return; |
| 1155 | } | ||
| 1156 | usage2(_("file does not exist or is not readable"), path); | ||
| 1179 | } | 1157 | } |
| 1180 | 1158 | ||
| 1181 | char *perfd_time_connect(double elapsed_time_connect, long socket_timeout) { | 1159 | mp_subcheck np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, |
| 1182 | return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, | 1160 | int days_till_exp_crit); |
| 1183 | socket_timeout); | ||
| 1184 | } | ||
| 1185 | 1161 | ||
| 1186 | char *perfd_time_ssl(double elapsed_time_ssl, long socket_timeout) { | 1162 | mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp, |
| 1187 | return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, | 1163 | int crit_days_till_exp) { |
| 1188 | socket_timeout); | 1164 | mp_subcheck sc_cert_result = mp_subcheck_init(); |
| 1189 | } | 1165 | sc_cert_result = mp_set_subcheck_default_state(sc_cert_result, STATE_OK); |
| 1190 | 1166 | ||
| 1191 | char *perfd_time_headers(double elapsed_time_headers, long socket_timeout) { | 1167 | #ifdef LIBCURL_FEATURE_SSL |
| 1192 | return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, | 1168 | if (is_openssl_callback) { |
| 1193 | socket_timeout); | 1169 | # ifdef USE_OPENSSL |
| 1194 | } | 1170 | /* check certificate with OpenSSL functions, curl has been built against OpenSSL |
| 1171 | * and we actually have OpenSSL in the monitoring tools | ||
| 1172 | */ | ||
| 1173 | return np_net_ssl_check_certificate(cert, warn_days_till_exp, crit_days_till_exp); | ||
| 1174 | # else /* USE_OPENSSL */ | ||
| 1175 | xasprintf(&result.output, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL " | ||
| 1176 | "callback used and not linked against OpenSSL\n"); | ||
| 1177 | mp_set_subcheck_state(result, STATE_CRITICAL); | ||
| 1178 | # endif /* USE_OPENSSL */ | ||
| 1179 | } else { | ||
| 1180 | struct curl_slist *slist; | ||
| 1181 | |||
| 1182 | cert_ptr_union cert_ptr = {0}; | ||
| 1183 | cert_ptr.to_info = NULL; | ||
| 1184 | CURLcode res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info); | ||
| 1185 | if (!res && cert_ptr.to_info) { | ||
| 1186 | # ifdef USE_OPENSSL | ||
| 1187 | /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert | ||
| 1188 | * parsing We only check the first certificate and assume it's the one of | ||
| 1189 | * the server | ||
| 1190 | */ | ||
| 1191 | char *raw_cert = NULL; | ||
| 1192 | bool got_first_cert = false; | ||
| 1193 | for (int i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { | ||
| 1194 | if (got_first_cert) { | ||
| 1195 | break; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { | ||
| 1199 | if (verbose >= 2) { | ||
| 1200 | printf("%d ** %s\n", i, slist->data); | ||
| 1201 | } | ||
| 1202 | if (strncmp(slist->data, "Cert:", 5) == 0) { | ||
| 1203 | raw_cert = &slist->data[5]; | ||
| 1204 | got_first_cert = true; | ||
| 1205 | break; | ||
| 1206 | } | ||
| 1207 | } | ||
| 1208 | } | ||
| 1195 | 1209 | ||
| 1196 | char *perfd_time_firstbyte(double elapsed_time_firstbyte, long socket_timeout) { | 1210 | if (!raw_cert) { |
| 1197 | return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, | ||
| 1198 | true, socket_timeout); | ||
| 1199 | } | ||
| 1200 | 1211 | ||
| 1201 | char *perfd_time_transfer(double elapsed_time_transfer, long socket_timeout) { | 1212 | xasprintf(&sc_cert_result.output, |
| 1202 | return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, | 1213 | _("Cannot retrieve certificates from CERTINFO information - " |
| 1203 | true, socket_timeout); | 1214 | "certificate data was empty")); |
| 1204 | } | 1215 | sc_cert_result = mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL); |
| 1216 | return sc_cert_result; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | BIO *cert_BIO = BIO_new(BIO_s_mem()); | ||
| 1220 | BIO_write(cert_BIO, raw_cert, (int)strlen(raw_cert)); | ||
| 1221 | |||
| 1222 | cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL); | ||
| 1223 | if (!cert) { | ||
| 1224 | xasprintf(&sc_cert_result.output, | ||
| 1225 | _("Cannot read certificate from CERTINFO information - BIO error")); | ||
| 1226 | sc_cert_result = mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL); | ||
| 1227 | return sc_cert_result; | ||
| 1228 | } | ||
| 1205 | 1229 | ||
| 1206 | char *perfd_size(size_t page_len, int min_page_len) { | 1230 | BIO_free(cert_BIO); |
| 1207 | return perfdata("size", page_len, "B", (min_page_len > 0), min_page_len, (min_page_len > 0), 0, | 1231 | return np_net_ssl_check_certificate(cert, warn_days_till_exp, crit_days_till_exp); |
| 1208 | true, 0, false, 0); | 1232 | # else /* USE_OPENSSL */ |
| 1233 | /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our | ||
| 1234 | * disposal, so we use the libcurl CURLINFO data | ||
| 1235 | */ | ||
| 1236 | return net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, | ||
| 1237 | days_till_exp_crit); | ||
| 1238 | # endif /* USE_OPENSSL */ | ||
| 1239 | } else { | ||
| 1240 | xasprintf(&sc_cert_result.output, | ||
| 1241 | _("Cannot retrieve certificates - cURL returned %d - %s"), res, | ||
| 1242 | curl_easy_strerror(res)); | ||
| 1243 | mp_set_subcheck_state(sc_cert_result, STATE_CRITICAL); | ||
| 1244 | } | ||
| 1245 | } | ||
| 1246 | #endif /* LIBCURL_FEATURE_SSL */ | ||
| 1247 | |||
| 1248 | return sc_cert_result; | ||
| 1209 | } | 1249 | } |
| 1210 | 1250 | ||
| 1211 | /* check whether a file exists */ | 1251 | char *fmt_url(check_curl_working_state workingState) { |
| 1212 | void test_file(char *path) { | 1252 | char *url = calloc(DEFAULT_BUFFER_SIZE, sizeof(char)); |
| 1213 | if (access(path, R_OK) == 0) { | 1253 | if (url == NULL) { |
| 1214 | return; | 1254 | die(STATE_UNKNOWN, "memory allocation failed"); |
| 1215 | } | 1255 | } |
| 1216 | usage2(_("file does not exist or is not readable"), path); | 1256 | |
| 1257 | snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", workingState.use_ssl ? "https" : "http", | ||
| 1258 | (workingState.use_ssl & (workingState.host_name != NULL)) | ||
| 1259 | ? workingState.host_name | ||
| 1260 | : workingState.server_address, | ||
| 1261 | workingState.serverPort, workingState.server_url); | ||
| 1262 | |||
| 1263 | return url; | ||
| 1217 | } | 1264 | } |
diff --git a/plugins/check_curl.d/check_curl_helpers.h b/plugins/check_curl.d/check_curl_helpers.h index 0f43ab90..87e45a9d 100644 --- a/plugins/check_curl.d/check_curl_helpers.h +++ b/plugins/check_curl.d/check_curl_helpers.h | |||
| @@ -1,7 +1,11 @@ | |||
| 1 | #include "./config.h" | 1 | #include "./config.h" |
| 2 | #include <curl/curl.h> | 2 | #include <curl/curl.h> |
| 3 | #include "../picohttpparser/picohttpparser.h" | 3 | #include "../picohttpparser/picohttpparser.h" |
| 4 | // #include "curl/easy.h" | 4 | #include "output.h" |
| 5 | |||
| 6 | #if defined(HAVE_SSL) && defined(USE_OPENSSL) | ||
| 7 | # include <openssl/opensslv.h> | ||
| 8 | #endif | ||
| 5 | 9 | ||
| 6 | /* for buffers for header and body */ | 10 | /* for buffers for header and body */ |
| 7 | typedef struct { | 11 | typedef struct { |
| @@ -99,8 +103,8 @@ int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*stat | |||
| 99 | void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/); | 103 | void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/); |
| 100 | 104 | ||
| 101 | char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header); | 105 | char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header); |
| 102 | mp_state_enum check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, | 106 | mp_subcheck check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, |
| 103 | const char msg[static DEFAULT_BUFFER_SIZE], int /*maximum_age*/); | 107 | int /*maximum_age*/); |
| 104 | size_t get_content_length(const curlhelp_write_curlbuf *header_buf, | 108 | size_t get_content_length(const curlhelp_write_curlbuf *header_buf, |
| 105 | const curlhelp_write_curlbuf *body_buf); | 109 | const curlhelp_write_curlbuf *body_buf); |
| 106 | int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family); | 110 | int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family); |
| @@ -114,12 +118,7 @@ void cleanup(check_curl_global_state global_state); | |||
| 114 | bool expected_statuscode(const char *reply, const char *statuscodes); | 118 | bool expected_statuscode(const char *reply, const char *statuscodes); |
| 115 | char *string_statuscode(int major, int minor); | 119 | char *string_statuscode(int major, int minor); |
| 116 | 120 | ||
| 117 | char *perfd_time(double elapsed_time, thresholds * /*thlds*/, long /*socket_timeout*/); | ||
| 118 | char *perfd_time_connect(double elapsed_time_connect, long /*socket_timeout*/); | ||
| 119 | char *perfd_time_ssl(double elapsed_time_ssl, long /*socket_timeout*/); | ||
| 120 | char *perfd_time_firstbyte(double elapsed_time_firstbyte, long /*socket_timeout*/); | ||
| 121 | char *perfd_time_headers(double elapsed_time_headers, long /*socket_timeout*/); | ||
| 122 | char *perfd_time_transfer(double elapsed_time_transfer, long /*socket_timeout*/); | ||
| 123 | char *perfd_size(size_t page_len, int /*min_page_len*/); | ||
| 124 | |||
| 125 | void test_file(char *path); | 121 | void test_file(char *path); |
| 122 | mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp, | ||
| 123 | int crit_days_till_exp); | ||
| 124 | char *fmt_url(check_curl_working_state workingState); | ||
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h index a4b1eecf..32399b8a 100644 --- a/plugins/check_curl.d/config.h +++ b/plugins/check_curl.d/config.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <string.h> | 8 | #include <string.h> |
| 9 | #include <sys/socket.h> | 9 | #include <sys/socket.h> |
| 10 | #include "curl/curl.h" | 10 | #include "curl/curl.h" |
| 11 | #include "perfdata.h" | ||
| 11 | #include "regex.h" | 12 | #include "regex.h" |
| 12 | 13 | ||
| 13 | enum { | 14 | enum { |
| @@ -93,9 +94,9 @@ typedef struct { | |||
| 93 | bool continue_after_check_cert; | 94 | bool continue_after_check_cert; |
| 94 | int days_till_exp_warn; | 95 | int days_till_exp_warn; |
| 95 | int days_till_exp_crit; | 96 | int days_till_exp_crit; |
| 96 | thresholds *thlds; | 97 | mp_thresholds thlds; |
| 97 | size_t min_page_len; | 98 | mp_range page_length_limits; |
| 98 | size_t max_page_len; | 99 | bool page_length_limits_is_set; |
| 99 | struct { | 100 | struct { |
| 100 | char string[MAX_INPUT_BUFFER]; | 101 | char string[MAX_INPUT_BUFFER]; |
| 101 | bool is_present; | 102 | bool is_present; |
