diff --git a/plugins/check_curl.c b/plugins/check_curl.c index 95e45282..953fa9b2 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c @@ -889,6 +889,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { {"url", required_argument, 0, 'u'}, {"port", required_argument, 0, 'p'}, {"authorization", required_argument, 0, 'a'}, + {"proxy", required_argument, 0, 'x'}, {"proxy-authorization", required_argument, 0, 'b'}, {"header-string", required_argument, 0, 'd'}, {"string", required_argument, 0, 's'}, @@ -961,7 +962,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { while (true) { int option_index = getopt_long( - argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", + argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:x:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option); if (option_index == -1 || option_index == EOF || option_index == 1) { break; @@ -1049,6 +1050,10 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { strncpy(result.config.curl_config.user_auth, optarg, MAX_INPUT_BUFFER - 1); result.config.curl_config.user_auth[MAX_INPUT_BUFFER - 1] = 0; break; + case 'x': /* proxy info*/ + strncpy(result.config.curl_config.proxy, optarg, DEFAULT_BUFFER_SIZE -1); + result.config.curl_config.user_auth[DEFAULT_BUFFER_SIZE -1] = 0; + break; case 'b': /* proxy-authorization info */ strncpy(result.config.curl_config.proxy_auth, optarg, MAX_INPUT_BUFFER - 1); result.config.curl_config.proxy_auth[MAX_INPUT_BUFFER - 1] = 0; @@ -1614,6 +1619,11 @@ void print_help(void) { printf(" %s\n", "--state-regex=STATE"); printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of " "\"critical\",\"warning\"")); + printf(" %s\n", "-x, --proxy=PROXY_SERVER"); + printf(" %s\n", _("Specify the proxy in form of ://:")); + printf(" %s\n", _("Available schemes are http, https, socks4, socks4a, socks5, socks5a")); + printf(" %s\n", _("If port is not specified, libcurl defaults to 1080")); + printf(" %s\n", _("This value will be set as CURLOPT_PROXY")); printf(" %s\n", "-a, --authorization=AUTH_PAIR"); printf(" %s\n", _("Username:password on sites with basic authentication")); printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); @@ -1722,9 +1732,14 @@ void print_help(void) { #endif printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); - printf(" %s\n", _("It is recommended to use an environment proxy like:")); + printf(" %s\n", _("Proxies are defined checked using the -x or --proxy parameter:")); + printf(" %s\n", _("The environment variables are only checked -x/--proxy arguments are not set:")); + printf(" %s\n", _("Depending on the SSL enablement, either http_proxy or https_proxy environment variable is used.")); + printf(" %s\n", _("These variables can also be given in uppercase, but the lowercase ones will take predence if both are defined.")); printf(" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); + printf(" %s\n", + _("HTTPS_PROXY=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org --ssl")); printf(" %s\n", _("legacy proxy requests in check_http style still work:")); printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ " "-H www.monitoring-plugins.org")); @@ -1756,8 +1771,8 @@ void print_usage(void) { printf(" %s -H | -I [-u ] [-p ]\n", progname); printf(" [-J ] [-K ] [--ca-cert ] [-D]\n"); - printf(" [-w ] [-c ] [-t ] [-L] [-E] [-a auth]\n"); - printf(" [-b proxy_auth] [-f ]\n"); + printf(" [-w ] [-c ] [-t ] [-L] [-E] [-x ]\n"); + printf(" [-a auth] [-b proxy_auth] [-f ]\n"); printf(" [-e ] [-d string] [-s string] [-l] [-r | -R ]\n"); printf(" [-P string] [-m :] [-4|-6] [-N] [-M ]\n"); diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c index ad31b847..68bd7c09 100644 --- a/plugins/check_curl.d/check_curl_helpers.c +++ b/plugins/check_curl.d/check_curl_helpers.c @@ -116,6 +116,54 @@ check_curl_configure_curl(const check_curl_static_curl_config config, curl_easy_setopt(result.curl_state.curl, CURLOPT_TIMEOUT, config.socket_timeout), "CURLOPT_TIMEOUT"); + /* set proxy */ + const struct curl_easyoption *curlopt_proxy_easyoption = curl_easy_option_by_id(CURLOPT_PROXY); + handle_curl_easyoption(curlopt_proxy_easyoption,"CURLOPT_PROXY"); + char proxy_option_str[DEFAULT_BUFFER_SIZE]; + if (verbose >= 1 && curlopt_proxy_easyoption != NULL){ + printf("* cURL Easy Option %s\n", format_curl_easyoption(curlopt_proxy_easyoption, proxy_option_str, DEFAULT_BUFFER_SIZE)); + } + /* proxy can either be given from the command line, or taken from environment variables */ + char curlopt_proxy[DEFAULT_BUFFER_SIZE]; + if (config.proxy != NULL && strlen(config.proxy) > 0 ){ + strcpy(curlopt_proxy, config.proxy); + }else{ + char *http_proxy_env; + http_proxy_env = getenv("http_proxy"); + char *http_proxy_uppercase_env; + http_proxy_uppercase_env = getenv("HTTP_PROXY"); + char *https_proxy_env; + https_proxy_env = getenv("https_proxy"); + char *https_proxy_uppercase_env; + https_proxy_uppercase_env = getenv("HTTPS_PROXY"); + /* lower case proxy environment varialbes are generally more accepted. accept both, but take the lowercase one when both are available*/ + if(working_state.use_ssl){ + if(https_proxy_env != NULL && strlen(https_proxy_env) > 0){ + strcpy(curlopt_proxy, https_proxy_env); + if(https_proxy_uppercase_env != NULL && verbose >=1){ + printf("* cURL ignoring environment variable HTTPS_PROXY as https_proxy is set\n"); + } + }else if(https_proxy_uppercase_env != NULL && strlen(https_proxy_uppercase_env) >= 0){ + strcpy(curlopt_proxy, https_proxy_uppercase_env); + } + else{ + strcpy(curlopt_proxy,""); + } + }else{ + if(http_proxy_env != NULL && strlen(http_proxy_env) > 0){ + strcpy(curlopt_proxy, http_proxy_env); + if(http_proxy_uppercase_env != NULL && verbose >=1){ + printf("* cURL ignoring environment variable HTTP_PROXY as http_proxy is set\n"); + } + }else if(http_proxy_uppercase_env != NULL && strlen(http_proxy_uppercase_env) > 0){ + strcpy(curlopt_proxy, http_proxy_uppercase_env); + }else{ + strcpy(curlopt_proxy,""); + } + } + } + handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXY, curlopt_proxy), "CURLOPT_PROXY"); + /* enable haproxy protocol */ if (config.haproxy_protocol) { handle_curl_option_return_code( @@ -123,11 +171,13 @@ check_curl_configure_curl(const check_curl_static_curl_config config, "CURLOPT_HAPROXYPROTOCOL"); } - // 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 + /* 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 */ + /* TODO: do not skip populating the DNS cache if the proxy scheme is socks4 or socks5.*/ + /* If the proxy should resolve the hostname, socks4h and socks5h scheme is used.*/ char dnscache[DEFAULT_BUFFER_SIZE]; char addrstr[DEFAULT_BUFFER_SIZE / 2]; - if (working_state.use_ssl && working_state.host_name != NULL) { + if (working_state.use_ssl && working_state.host_name != NULL && (curlopt_proxy != NULL && strlen(curlopt_proxy) == 0)) { char *tmp_mod_address; /* lookup_host() requires an IPv6 address without the brackets. */ @@ -567,6 +617,53 @@ void handle_curl_option_return_code(CURLcode res, const char *option) { } } +void handle_curl_easyoption(const struct curl_easyoption *option, const char *name) { + if (option == NULL){ + die(STATE_CRITICAL, _("Error while getting cURL option '%s': cURL option is null"), name); + } +} + +char *format_curl_easyoption(const struct curl_easyoption *option, char *buf, unsigned int buflen){ + if(option == NULL){ + die(STATE_CRITICAL, _("Can not print details about an empty cURL option")); + } + int offset = snprintf(buf, buflen, "name: %s flags: %s", option->name, option->flags); + switch(option->type){ + case CURLOT_LONG: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_LONG"); + break; + case CURLOT_VALUES: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_VALUES"); + break; + case CURLOT_OFF_T: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_OFF_T"); + break; + case CURLOT_OBJECT: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_OBJECT"); + break; + case CURLOT_STRING: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_STRING"); + break; + case CURLOT_SLIST: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_SLIST"); + break; + case CURLOT_CBPTR: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_CBPTR"); + break; + case CURLOT_BLOB: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_BLOB"); + break; + case CURLOT_FUNCTION: + offset += snprintf(buf + offset, buflen - offset, " type: CURLOT_FUNCTION"); + break; + default: + offset += snprintf(buf + offset, buflen - offset, " type: Unknown"); + break; + } + offset += snprintf(buf + offset, buflen - offset, " id: %d", option->id); + return buf; +} + char *get_header_value(const struct phr_header *headers, const size_t nof_headers, const char *header) { for (size_t i = 0; i < nof_headers; i++) { @@ -612,6 +709,7 @@ check_curl_config check_curl_config_init() { .ca_cert = NULL, .verify_peer_and_host = false, .user_agent = {'\0'}, + .proxy = "", .proxy_auth = "", .user_auth = "", .http_content_type = NULL, diff --git a/plugins/check_curl.d/check_curl_helpers.h b/plugins/check_curl.d/check_curl_helpers.h index e77b763b..a5a0c5df 100644 --- a/plugins/check_curl.d/check_curl_helpers.h +++ b/plugins/check_curl.d/check_curl_helpers.h @@ -84,6 +84,10 @@ check_curl_configure_curl_wrapper check_curl_configure_curl(check_curl_static_cu void handle_curl_option_return_code(CURLcode res, const char *option); +void handle_curl_easyoption(const struct curl_easyoption *option, const char *name); + +char *format_curl_easyoption(const struct curl_easyoption *option, char *buf, unsigned int buflen); + int curlhelp_initwritebuffer(curlhelp_write_curlbuf **buf); size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/); diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h index 61067d46..be50c3d0 100644 --- a/plugins/check_curl.d/config.h +++ b/plugins/check_curl.d/config.h @@ -65,6 +65,7 @@ typedef struct { char *client_privkey; char *ca_cert; bool verify_peer_and_host; + char proxy[DEFAULT_BUFFER_SIZE]; char user_agent[DEFAULT_BUFFER_SIZE]; char proxy_auth[MAX_INPUT_BUFFER]; char user_auth[MAX_INPUT_BUFFER];