diff options
Diffstat (limited to 'plugins/check_curl.c')
| -rw-r--r-- | plugins/check_curl.c | 99 |
1 files changed, 90 insertions, 9 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 3e0a6f94..14cc8463 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c | |||
| @@ -55,6 +55,12 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 55 | 55 | ||
| 56 | #include <arpa/inet.h> | 56 | #include <arpa/inet.h> |
| 57 | 57 | ||
| 58 | #if defined(HAVE_SSL) && defined(USE_OPENSSL) | ||
| 59 | #include <openssl/opensslv.h> | ||
| 60 | #endif | ||
| 61 | |||
| 62 | #include <netdb.h> | ||
| 63 | |||
| 58 | #define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch)) | 64 | #define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch)) |
| 59 | 65 | ||
| 60 | #define DEFAULT_BUFFER_SIZE 2048 | 66 | #define DEFAULT_BUFFER_SIZE 2048 |
| @@ -206,6 +212,7 @@ int maximum_age = -1; | |||
| 206 | int address_family = AF_UNSPEC; | 212 | int address_family = AF_UNSPEC; |
| 207 | curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; | 213 | curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; |
| 208 | int curl_http_version = CURL_HTTP_VERSION_NONE; | 214 | int curl_http_version = CURL_HTTP_VERSION_NONE; |
| 215 | int automatic_decompression = FALSE; | ||
| 209 | 216 | ||
| 210 | int process_arguments (int, char**); | 217 | int process_arguments (int, char**); |
| 211 | void handle_curl_option_return_code (CURLcode res, const char* option); | 218 | void handle_curl_option_return_code (CURLcode res, const char* option); |
| @@ -285,6 +292,20 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) | |||
| 285 | * TODO: is the last certificate always the server certificate? | 292 | * TODO: is the last certificate always the server certificate? |
| 286 | */ | 293 | */ |
| 287 | cert = X509_STORE_CTX_get_current_cert(x509_ctx); | 294 | cert = X509_STORE_CTX_get_current_cert(x509_ctx); |
| 295 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L | ||
| 296 | X509_up_ref(cert); | ||
| 297 | #endif | ||
| 298 | if (verbose>=2) { | ||
| 299 | puts("* SSL verify callback with certificate:"); | ||
| 300 | X509_NAME *subject, *issuer; | ||
| 301 | printf("* issuer:\n"); | ||
| 302 | issuer = X509_get_issuer_name( cert ); | ||
| 303 | X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); | ||
| 304 | printf("* curl verify_callback:\n* subject:\n"); | ||
| 305 | subject = X509_get_subject_name( cert ); | ||
| 306 | X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); | ||
| 307 | puts(""); | ||
| 308 | } | ||
| 288 | return 1; | 309 | return 1; |
| 289 | } | 310 | } |
| 290 | 311 | ||
| @@ -351,12 +372,55 @@ handle_curl_option_return_code (CURLcode res, const char* option) | |||
| 351 | } | 372 | } |
| 352 | 373 | ||
| 353 | int | 374 | int |
| 375 | lookup_host (const char *host, char *buf, size_t buflen) | ||
| 376 | { | ||
| 377 | struct addrinfo hints, *res, *result; | ||
| 378 | int errcode; | ||
| 379 | void *ptr; | ||
| 380 | |||
| 381 | memset (&hints, 0, sizeof (hints)); | ||
| 382 | hints.ai_family = address_family; | ||
| 383 | hints.ai_socktype = SOCK_STREAM; | ||
| 384 | hints.ai_flags |= AI_CANONNAME; | ||
| 385 | |||
| 386 | errcode = getaddrinfo (host, NULL, &hints, &result); | ||
| 387 | if (errcode != 0) | ||
| 388 | return errcode; | ||
| 389 | |||
| 390 | res = result; | ||
| 391 | |||
| 392 | while (res) { | ||
| 393 | inet_ntop (res->ai_family, res->ai_addr->sa_data, buf, buflen); | ||
| 394 | switch (res->ai_family) { | ||
| 395 | case AF_INET: | ||
| 396 | ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr; | ||
| 397 | break; | ||
| 398 | case AF_INET6: | ||
| 399 | ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; | ||
| 400 | break; | ||
| 401 | } | ||
| 402 | inet_ntop (res->ai_family, ptr, buf, buflen); | ||
| 403 | if (verbose >= 1) | ||
| 404 | printf ("* getaddrinfo IPv%d address: %s\n", | ||
| 405 | res->ai_family == PF_INET6 ? 6 : 4, buf); | ||
| 406 | res = res->ai_next; | ||
| 407 | } | ||
| 408 | |||
| 409 | freeaddrinfo(result); | ||
| 410 | |||
| 411 | return 0; | ||
| 412 | } | ||
| 413 | |||
| 414 | int | ||
| 354 | check_http (void) | 415 | check_http (void) |
| 355 | { | 416 | { |
| 356 | int result = STATE_OK; | 417 | int result = STATE_OK; |
| 357 | int page_len = 0; | 418 | int page_len = 0; |
| 358 | int i; | 419 | int i; |
| 359 | char *force_host_header = NULL; | 420 | char *force_host_header = NULL; |
| 421 | struct curl_slist *host = NULL; | ||
| 422 | char addrstr[100]; | ||
| 423 | char dnscache[DEFAULT_BUFFER_SIZE]; | ||
| 360 | 424 | ||
| 361 | /* initialize curl */ | 425 | /* initialize curl */ |
| 362 | if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) | 426 | if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) |
| @@ -371,6 +435,13 @@ check_http (void) | |||
| 371 | /* print everything on stdout like check_http would do */ | 435 | /* print everything on stdout like check_http would do */ |
| 372 | handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); | 436 | handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); |
| 373 | 437 | ||
| 438 | if (automatic_decompression) | ||
| 439 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) | ||
| 440 | handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING"); | ||
| 441 | #else | ||
| 442 | handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING"); | ||
| 443 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ | ||
| 444 | |||
| 374 | /* initialize buffer for body of the answer */ | 445 | /* initialize buffer for body of the answer */ |
| 375 | if (curlhelp_initwritebuffer(&body_buf) < 0) | 446 | if (curlhelp_initwritebuffer(&body_buf) < 0) |
| 376 | die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); | 447 | die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); |
| @@ -392,9 +463,12 @@ check_http (void) | |||
| 392 | 463 | ||
| 393 | // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy | 464 | // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy |
| 394 | if(use_ssl && host_name != NULL) { | 465 | if(use_ssl && host_name != NULL) { |
| 395 | struct curl_slist *host = NULL; | 466 | if ( (res=lookup_host (server_address, addrstr, 100)) != 0) { |
| 396 | char dnscache[DEFAULT_BUFFER_SIZE]; | 467 | snprintf (msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), |
| 397 | snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, server_address); | 468 | server_address, res, gai_strerror (res)); |
| 469 | die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
| 470 | } | ||
| 471 | snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr); | ||
| 398 | host = curl_slist_append(NULL, dnscache); | 472 | host = curl_slist_append(NULL, dnscache); |
| 399 | curl_easy_setopt(curl, CURLOPT_RESOLVE, host); | 473 | curl_easy_setopt(curl, CURLOPT_RESOLVE, host); |
| 400 | if (verbose>=1) | 474 | if (verbose>=1) |
| @@ -959,8 +1033,8 @@ char* | |||
| 959 | uri_string (const UriTextRangeA range, char* buf, size_t buflen) | 1033 | uri_string (const UriTextRangeA range, char* buf, size_t buflen) |
| 960 | { | 1034 | { |
| 961 | if (!range.first) return "(null)"; | 1035 | if (!range.first) return "(null)"; |
| 962 | strncpy (buf, range.first, max (buflen, range.afterLast - range.first)); | 1036 | strncpy (buf, range.first, max (buflen-1, range.afterLast - range.first)); |
| 963 | buf[max (buflen, range.afterLast - range.first)] = '\0'; | 1037 | buf[max (buflen-1, range.afterLast - range.first)] = '\0'; |
| 964 | buf[range.afterLast - range.first] = '\0'; | 1038 | buf[range.afterLast - range.first] = '\0'; |
| 965 | return buf; | 1039 | return buf; |
| 966 | } | 1040 | } |
| @@ -1080,8 +1154,8 @@ redir (curlhelp_write_curlbuf* header_buf) | |||
| 1080 | !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && | 1154 | !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && |
| 1081 | (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && | 1155 | (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && |
| 1082 | !strcmp(server_url, new_url)) | 1156 | !strcmp(server_url, new_url)) |
| 1083 | die (STATE_WARNING, | 1157 | die (STATE_CRITICAL, |
| 1084 | _("HTTP WARNING - redirection creates an infinite loop - %s://%s:%d%s%s\n"), | 1158 | _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), |
| 1085 | use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : "")); | 1159 | use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : "")); |
| 1086 | 1160 | ||
| 1087 | /* set new values for redirected request */ | 1161 | /* set new values for redirected request */ |
| @@ -1137,7 +1211,8 @@ process_arguments (int argc, char **argv) | |||
| 1137 | INVERT_REGEX = CHAR_MAX + 1, | 1211 | INVERT_REGEX = CHAR_MAX + 1, |
| 1138 | SNI_OPTION, | 1212 | SNI_OPTION, |
| 1139 | CA_CERT_OPTION, | 1213 | CA_CERT_OPTION, |
| 1140 | HTTP_VERSION_OPTION | 1214 | HTTP_VERSION_OPTION, |
| 1215 | AUTOMATIC_DECOMPRESSION | ||
| 1141 | }; | 1216 | }; |
| 1142 | 1217 | ||
| 1143 | int option = 0; | 1218 | int option = 0; |
| @@ -1180,6 +1255,7 @@ process_arguments (int argc, char **argv) | |||
| 1180 | {"extended-perfdata", no_argument, 0, 'E'}, | 1255 | {"extended-perfdata", no_argument, 0, 'E'}, |
| 1181 | {"show-body", no_argument, 0, 'B'}, | 1256 | {"show-body", no_argument, 0, 'B'}, |
| 1182 | {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, | 1257 | {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, |
| 1258 | {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, | ||
| 1183 | {0, 0, 0, 0} | 1259 | {0, 0, 0, 0} |
| 1184 | }; | 1260 | }; |
| 1185 | 1261 | ||
| @@ -1346,7 +1422,7 @@ process_arguments (int argc, char **argv) | |||
| 1346 | #ifdef LIBCURL_FEATURE_SSL | 1422 | #ifdef LIBCURL_FEATURE_SSL |
| 1347 | case 'D': /* verify peer certificate & host */ | 1423 | case 'D': /* verify peer certificate & host */ |
| 1348 | verify_peer_and_host = TRUE; | 1424 | verify_peer_and_host = TRUE; |
| 1349 | goto enable_ssl; | 1425 | break; |
| 1350 | #endif | 1426 | #endif |
| 1351 | case 'S': /* use SSL */ | 1427 | case 'S': /* use SSL */ |
| 1352 | #ifdef LIBCURL_FEATURE_SSL | 1428 | #ifdef LIBCURL_FEATURE_SSL |
| @@ -1571,6 +1647,9 @@ process_arguments (int argc, char **argv) | |||
| 1571 | exit (STATE_WARNING); | 1647 | exit (STATE_WARNING); |
| 1572 | } | 1648 | } |
| 1573 | break; | 1649 | break; |
| 1650 | case AUTOMATIC_DECOMPRESSION: | ||
| 1651 | automatic_decompression = TRUE; | ||
| 1652 | break; | ||
| 1574 | case '?': | 1653 | case '?': |
| 1575 | /* print short usage statement if args not parsable */ | 1654 | /* print short usage statement if args not parsable */ |
| 1576 | usage5 (); | 1655 | usage5 (); |
| @@ -1781,6 +1860,8 @@ print_help (void) | |||
| 1781 | printf (" %s\n", "--http-version=VERSION"); | 1860 | printf (" %s\n", "--http-version=VERSION"); |
| 1782 | printf (" %s\n", _("Connect via specific HTTP protocol.")); | 1861 | printf (" %s\n", _("Connect via specific HTTP protocol.")); |
| 1783 | printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); | 1862 | printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); |
| 1863 | printf (" %s\n", "--enable-automatic-decompression"); | ||
| 1864 | printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); | ||
| 1784 | printf ("\n"); | 1865 | printf ("\n"); |
| 1785 | 1866 | ||
| 1786 | printf (UT_WARN_CRIT); | 1867 | printf (UT_WARN_CRIT); |
