summaryrefslogtreecommitdiffstats
path: root/plugins/check_curl.d
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_curl.d')
-rw-r--r--plugins/check_curl.d/check_curl_helpers.c455
-rw-r--r--plugins/check_curl.d/check_curl_helpers.h9
-rw-r--r--plugins/check_curl.d/config.h7
3 files changed, 467 insertions, 4 deletions
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c
index ad31b847..4372dc0b 100644
--- a/plugins/check_curl.d/check_curl_helpers.c
+++ b/plugins/check_curl.d/check_curl_helpers.c
@@ -3,8 +3,11 @@
3#include <arpa/inet.h> 3#include <arpa/inet.h>
4#include <netinet/in.h> 4#include <netinet/in.h>
5#include <netdb.h> 5#include <netdb.h>
6#include <stdint.h>
7#include <stdio.h>
6#include <stdlib.h> 8#include <stdlib.h>
7#include <string.h> 9#include <string.h>
10#include <sys/socket.h>
8#include "../utils.h" 11#include "../utils.h"
9#include "check_curl.d/config.h" 12#include "check_curl.d/config.h"
10#include "output.h" 13#include "output.h"
@@ -116,6 +119,107 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
116 curl_easy_setopt(result.curl_state.curl, CURLOPT_TIMEOUT, config.socket_timeout), 119 curl_easy_setopt(result.curl_state.curl, CURLOPT_TIMEOUT, config.socket_timeout),
117 "CURLOPT_TIMEOUT"); 120 "CURLOPT_TIMEOUT");
118 121
122 /* set proxy */
123 /* http(s) proxy can either be given from the command line, or taken from environment variables */
124 /* socks4(a) / socks5(h) proxy should be given using the command line */
125
126 /* first source to check is the environment variables */
127 /* lower case proxy environment variables are almost always accepted, while some programs also checking
128 uppercase ones. discover both, but take the lowercase one if both are present */
129
130 /* extra information: libcurl does not discover the uppercase version HTTP_PROXY due to security reasons */
131 /* https://github.com/curl/curl/blob/d445f2d930ae701039518d695481ee53b8490521/lib/url.c#L1987 */
132
133 /* first environment variable to read is all_proxy. it can be overridden by protocol specific environment variables */
134 char *all_proxy_env, *all_proxy_uppercase_env;
135 all_proxy_env = getenv("all_proxy");
136 all_proxy_uppercase_env = getenv("ALL_PROXY");
137 if (all_proxy_env != NULL && strlen(all_proxy_env)){
138 working_state.curlopt_proxy = strdup(all_proxy_env);
139 if (all_proxy_uppercase_env != NULL && verbose >= 1) {
140 printf("* cURL ignoring environment variable 'ALL_PROXY' as 'all_proxy' is set\n");
141 }
142 } else if (all_proxy_uppercase_env != NULL && strlen(all_proxy_uppercase_env) > 0) {
143 working_state.curlopt_proxy = strdup(all_proxy_uppercase_env);
144 }
145
146 /* second environment variable to read is http_proxy. only set curlopt_proxy if ssl is not toggled */
147 char *http_proxy_env, *http_proxy_uppercase_env;
148 http_proxy_env = getenv("http_proxy");
149 http_proxy_uppercase_env = getenv("HTTP_PROXY");
150 if (!working_state.use_ssl){
151 if (http_proxy_env != NULL && strlen(http_proxy_env) > 0) {
152 working_state.curlopt_proxy = strdup(http_proxy_env);
153 if (http_proxy_uppercase_env != NULL && verbose >= 1) {
154 printf("* cURL ignoring environment variable 'HTTP_PROXY' as 'http_proxy' is set\n");
155 }
156 } else if (http_proxy_uppercase_env != NULL && strlen(http_proxy_uppercase_env) > 0) {
157 working_state.curlopt_proxy = strdup(http_proxy_uppercase_env);
158 }
159 }
160#ifdef LIBCURL_FEATURE_SSL
161 /* optionally read https_proxy environment variable and set curlopt_proxy if ssl is toggled */
162 char *https_proxy_env, *https_proxy_uppercase_env;
163 https_proxy_env = getenv("https_proxy");
164 https_proxy_uppercase_env = getenv("HTTPS_PROXY");
165 if (working_state.use_ssl) {
166 if (https_proxy_env != NULL && strlen(https_proxy_env) > 0) {
167 working_state.curlopt_proxy = strdup(https_proxy_env);
168 if (https_proxy_uppercase_env != NULL && verbose >= 1) {
169 printf("* cURL ignoring environment variable 'HTTPS_PROXY' as 'https_proxy' is set\n");
170 }
171 }
172 else if (https_proxy_uppercase_env != NULL && strlen(https_proxy_uppercase_env) >= 0) {
173 working_state.curlopt_proxy = strdup(https_proxy_uppercase_env);
174 }
175 }
176#endif /* LIBCURL_FEATURE_SSL */
177
178 /* second source to check for proxies is command line argument, overwriting the environment variables */
179 if (strlen(config.proxy) > 0) {
180 working_state.curlopt_proxy = strdup(config.proxy);
181 }
182
183 if (working_state.curlopt_proxy != NULL && strlen(working_state.curlopt_proxy)){
184 handle_curl_option_return_code(
185 curl_easy_setopt(result.curl_state.curl, CURLOPT_PROXY, working_state.curlopt_proxy), "CURLOPT_PROXY");
186 if (verbose >= 1) {
187 printf("* curl CURLOPT_PROXY: %s\n", working_state.curlopt_proxy);
188 }
189 }
190
191 /* set no_proxy */
192 /* first source to check is environment variables */
193 char *no_proxy_env, *no_proxy_uppercase_env;
194 no_proxy_env = getenv("no_proxy");
195 no_proxy_uppercase_env = getenv("NO_PROXY");
196 if (no_proxy_env != NULL && strlen(no_proxy_env)){
197 working_state.curlopt_noproxy = strdup(no_proxy_env);
198 if (no_proxy_uppercase_env != NULL && verbose >= 1){
199 printf("* cURL ignoring environment variable 'NO_PROXY' as 'no_proxy' is set\n");
200 }
201 }else if (no_proxy_uppercase_env != NULL && strlen(no_proxy_uppercase_env) > 0){
202 working_state.curlopt_noproxy = strdup(no_proxy_uppercase_env);
203 }
204
205 /* second source to check for no_proxy is command line argument, overwriting the environment variables */
206 if (strlen(config.no_proxy) > 0) {
207 working_state.curlopt_noproxy = strdup(config.no_proxy);
208 }
209
210 if ( working_state.curlopt_noproxy != NULL && strlen(working_state.curlopt_noproxy)){
211 handle_curl_option_return_code(
212 curl_easy_setopt(result.curl_state.curl, CURLOPT_NOPROXY, working_state.curlopt_noproxy), "CURLOPT_NOPROXY");
213 if (verbose >= 1) {
214 printf("* curl CURLOPT_NOPROXY: %s\n", working_state.curlopt_noproxy);
215 }
216 }
217
218 int proxy_resolves_hostname = determine_hostname_resolver(working_state, config);
219 if (verbose >= 1) {
220 printf("* proxy_resolves_hostname: %d\n", proxy_resolves_hostname);
221 }
222
119 /* enable haproxy protocol */ 223 /* enable haproxy protocol */
120 if (config.haproxy_protocol) { 224 if (config.haproxy_protocol) {
121 handle_curl_option_return_code( 225 handle_curl_option_return_code(
@@ -123,11 +227,11 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
123 "CURLOPT_HAPROXYPROTOCOL"); 227 "CURLOPT_HAPROXYPROTOCOL");
124 } 228 }
125 229
126 // fill dns resolve cache to make curl connect to the given server_address instead of the 230 /* fill dns resolve cache to make curl connect to the given server_address instead of the */
127 // host_name, only required for ssl, because we use the host_name later on to make SNI happy 231 /* host_name, only required for ssl, because we use the host_name later on to make SNI happy */
128 char dnscache[DEFAULT_BUFFER_SIZE]; 232 char dnscache[DEFAULT_BUFFER_SIZE];
129 char addrstr[DEFAULT_BUFFER_SIZE / 2]; 233 char addrstr[DEFAULT_BUFFER_SIZE / 2];
130 if (working_state.use_ssl && working_state.host_name != NULL) { 234 if (working_state.use_ssl && working_state.host_name != NULL && !proxy_resolves_hostname ) {
131 char *tmp_mod_address; 235 char *tmp_mod_address;
132 236
133 /* lookup_host() requires an IPv6 address without the brackets. */ 237 /* lookup_host() requires an IPv6 address without the brackets. */
@@ -562,7 +666,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
562 666
563void handle_curl_option_return_code(CURLcode res, const char *option) { 667void handle_curl_option_return_code(CURLcode res, const char *option) {
564 if (res != CURLE_OK) { 668 if (res != CURLE_OK) {
565 die(STATE_CRITICAL, _("Error while setting cURL option '%s': cURL returned %d - %s"), 669 die(STATE_CRITICAL, _("Error while setting cURL option '%s': cURL returned %d - %s\n"),
566 option, res, curl_easy_strerror(res)); 670 option, res, curl_easy_strerror(res));
567 } 671 }
568} 672}
@@ -589,6 +693,8 @@ check_curl_working_state check_curl_working_state_init() {
589 .serverPort = HTTP_PORT, 693 .serverPort = HTTP_PORT,
590 .use_ssl = false, 694 .use_ssl = false,
591 .no_body = false, 695 .no_body = false,
696 .curlopt_proxy = NULL,
697 .curlopt_noproxy = NULL,
592 }; 698 };
593 return result; 699 return result;
594} 700}
@@ -612,6 +718,8 @@ check_curl_config check_curl_config_init() {
612 .ca_cert = NULL, 718 .ca_cert = NULL,
613 .verify_peer_and_host = false, 719 .verify_peer_and_host = false,
614 .user_agent = {'\0'}, 720 .user_agent = {'\0'},
721 .proxy = "",
722 .no_proxy = "",
615 .proxy_auth = "", 723 .proxy_auth = "",
616 .user_auth = "", 724 .user_auth = "",
617 .http_content_type = NULL, 725 .http_content_type = NULL,
@@ -1295,3 +1403,342 @@ char *fmt_url(check_curl_working_state workingState) {
1295 1403
1296 return url; 1404 return url;
1297} 1405}
1406
1407int determine_hostname_resolver(const check_curl_working_state working_state, const check_curl_static_curl_config config){
1408 char *host_name_display = "NULL";
1409 unsigned long host_name_len = 0;
1410 if( working_state.host_name){
1411 host_name_len = strlen(working_state.host_name);
1412 host_name_display = working_state.host_name;
1413 }
1414
1415 /* IPv4 or IPv6 version of the address */
1416 char *server_address_clean = strdup(working_state.server_address);
1417 /* server address might be a full length ipv6 address encapsulated in square brackets */
1418 if ((strnlen(working_state.server_address, MAX_IPV4_HOSTLENGTH) > 2) && (working_state.server_address[0] == '[') && (working_state.server_address[strlen(working_state.server_address)-1] == ']') ) {
1419 server_address_clean = strndup( working_state.server_address + 1, strlen(working_state.server_address) - 2);
1420 }
1421
1422 /* check curlopt_noproxy option first */
1423 /* https://curl.se/libcurl/c/CURLOPT_NOPROXY.html */
1424
1425 /* curlopt_noproxy is specified as a comma separated list of
1426 direct IPv4 or IPv6 addresses e.g 130.133.8.40, 2001:4860:4802:32::a ,
1427 IPv4 or IPv6 CIDR regions e.g 10.241.0.0/16 , abcd:ef01:2345::/48 ,
1428 direct hostnames e.g example.com, google.de */
1429
1430 if (working_state.curlopt_noproxy != NULL){
1431 char* curlopt_noproxy_copy = strdup( working_state.curlopt_noproxy);
1432 char* noproxy_item = strtok(curlopt_noproxy_copy, ",");
1433 while(noproxy_item != NULL){
1434 unsigned long noproxy_item_len = strlen(noproxy_item);
1435
1436 /* According to the CURLOPT_NOPROXY documentation: */
1437 /* https://curl.se/libcurl/c/CURLOPT_NOPROXY.html */
1438 /* The only wildcard available is a single * character, which matches all hosts, and effectively disables the proxy. */
1439 if ( strlen(noproxy_item) == 1 && noproxy_item[0] == '*'){
1440 if (verbose >= 1){
1441 printf("* noproxy includes '*' which disables proxy for all host name incl. : %s / server address incl. : %s\n", host_name_display , server_address_clean);
1442 }
1443 free(curlopt_noproxy_copy);
1444 free(server_address_clean);
1445 return 0;
1446 }
1447
1448 /* direct comparison with the server_address */
1449 if( server_address_clean != NULL && strlen(server_address_clean) == strlen(noproxy_item) && strcmp(server_address_clean, noproxy_item) == 0){
1450 if (verbose >= 1){
1451 printf("* server_address is in the no_proxy list: %s\n", noproxy_item);
1452 }
1453 free(curlopt_noproxy_copy);
1454 free(server_address_clean);
1455 return 0;
1456 }
1457
1458 /* direct comparison with the host_name */
1459 if( working_state.host_name != NULL && host_name_len == noproxy_item_len && strcmp(working_state.host_name, noproxy_item) == 0){
1460 if (verbose >= 1){
1461 printf("* host_name is in the no_proxy list: %s\n", noproxy_item);
1462 }
1463 free(curlopt_noproxy_copy);
1464 free(server_address_clean);
1465 return 0;
1466 }
1467
1468 /* check if hostname is a subdomain of the item, e.g www.example.com when token is example.com */
1469 /* subdomain1.acme.com will not will use a proxy if you only specify 'acme' in the noproxy */
1470 /* check if noproxy_item is a suffix */
1471 /* check if the character just before the suffix is '.' */
1472 if( working_state.host_name != NULL && host_name_len > noproxy_item_len){
1473 unsigned long suffix_start_idx = host_name_len - noproxy_item_len;
1474 if (strcmp(working_state.host_name + suffix_start_idx, noproxy_item ) == 0 && working_state.host_name[suffix_start_idx-1] == '.' ){
1475 if (verbose >= 1){
1476 printf("* host_name: %s is a subdomain of the no_proxy list item: %s\n", working_state.host_name , noproxy_item);
1477 }
1478 free(curlopt_noproxy_copy);
1479 free(server_address_clean);
1480 return 0;
1481 }
1482 }
1483
1484 // noproxy_item could be a CIDR IP range
1485 if( server_address_clean != NULL && strlen(server_address_clean)){
1486
1487 int ip_addr_inside_cidr_ret = ip_addr_inside_cidr(noproxy_item, server_address_clean);
1488
1489 switch(ip_addr_inside_cidr_ret){
1490 case 1:
1491 return 0;
1492 break;
1493 case 0:
1494 if(verbose >= 1){
1495 printf("server address: %s is not inside IP cidr: %s\n", server_address_clean, noproxy_item);
1496 }
1497 break;
1498 case -1:
1499 if(verbose >= 1){
1500 printf("could not fully determine if server address: %s is inside the IP cidr: %s\n", server_address_clean, noproxy_item);
1501 }
1502 break;
1503 }
1504 }
1505
1506 noproxy_item = strtok(NULL, ",");
1507 }
1508
1509 free(curlopt_noproxy_copy);
1510 }
1511
1512 if (working_state.curlopt_proxy != NULL){
1513 // Libcurl documentation
1514 // Setting the proxy string to "" (an empty string) explicitly disables the use of a proxy, even if there is an environment variable set for it.
1515 if ( strlen(working_state.curlopt_proxy) == 0){
1516 return 0;
1517 }
1518
1519 if ( strncmp( working_state.curlopt_proxy, "http://", 7) == 0){
1520 if (verbose >= 1){
1521 printf("* proxy scheme is http, proxy: %s resolves host: %s or server_address: %s\n", working_state.curlopt_proxy, host_name_display, server_address_clean);
1522 }
1523 free(server_address_clean);
1524 return 1;
1525 }
1526
1527 if ( strncmp( working_state.curlopt_proxy, "https://", 8) == 0){
1528 if (verbose >= 1){
1529 printf("* proxy scheme is https, proxy: %s resolves host: %s or server_address: %s\n", working_state.curlopt_proxy, host_name_display, server_address_clean);
1530 }
1531 free(server_address_clean);
1532 return 1;
1533 }
1534
1535 if ( strncmp( working_state.curlopt_proxy, "socks4://", 9) == 0){
1536 if (verbose >= 1){
1537 printf("* proxy scheme is socks, proxy: %s does not resolve host: %s or server_address: %s\n", working_state.curlopt_proxy, host_name_display, server_address_clean);
1538 }
1539 free(server_address_clean);
1540 return 0;
1541 }
1542
1543 if ( strncmp( working_state.curlopt_proxy, "socks4a://", 10) == 0){
1544 if (verbose >= 1){
1545 printf("* proxy scheme is socks4a, proxy: %s resolves host: %s or server_address: %s\n", working_state.curlopt_proxy, host_name_display, server_address_clean);
1546 }
1547 free(server_address_clean);
1548 return 1;
1549 }
1550
1551 if ( strncmp( working_state.curlopt_proxy, "socks5://", 9) == 0){
1552 if (verbose >= 1){
1553 printf("* proxy scheme is socks5, proxy: %s does not resolve host: %s or server_address: %s\n", working_state.curlopt_proxy, host_name_display, server_address_clean);
1554 }
1555 free(server_address_clean);
1556 return 0;
1557 }
1558
1559 if ( strncmp( working_state.curlopt_proxy, "socks5h://", 10) == 0){
1560 if (verbose >= 1){
1561 printf("* proxy scheme is socks5h, proxy: %s resolves host: %s or server_address: %s\n", working_state.curlopt_proxy, host_name_display, server_address_clean);
1562 }
1563 free(server_address_clean);
1564 return 1;
1565 }
1566
1567 // Libcurl documentation:
1568 // Without a scheme prefix, CURLOPT_PROXYTYPE can be used to specify which kind of proxy the string identifies.
1569 // We do not set this value
1570 // Without a scheme, it is treated as an http proxy
1571
1572 return 1;
1573 }
1574
1575 if (verbose >= 1){
1576 printf("* proxy scheme is unknown/unavailable, no proxy is assumed for host: %s or server_address: %s\n", host_name_display, server_address_clean);
1577 }
1578
1579 free(server_address_clean);
1580 return 0;
1581}
1582
1583int ip_addr_inside_cidr(const char* cidr_region_or_ip_addr, const char* target_ip){
1584 unsigned int slash_count = 0;
1585 unsigned int last_slash_idx = 0;
1586 for(size_t i = 0; i < strlen(cidr_region_or_ip_addr); i++){
1587 if(cidr_region_or_ip_addr[i] == '/'){
1588 slash_count++;
1589 last_slash_idx = (unsigned int)i;
1590 }
1591 }
1592
1593 char *cidr_ip_part = NULL;
1594 int prefix_length = 0;
1595
1596 if (slash_count == 0) {
1597 cidr_ip_part = strdup(cidr_region_or_ip_addr);
1598 if (!cidr_ip_part) return -1;
1599 } else if (slash_count == 1) {
1600 cidr_ip_part = strndup(cidr_region_or_ip_addr, last_slash_idx);
1601 if (!cidr_ip_part) return -1;
1602
1603 errno = 0;
1604 long long tmp = strtoll(cidr_region_or_ip_addr + last_slash_idx + 1, NULL, 10);
1605 if (errno == ERANGE) {
1606 if (verbose >= 1) {
1607 printf("cidr_region_or_ip: %s , could not parse subnet length\n", cidr_region_or_ip_addr);
1608 }
1609 free(cidr_ip_part);
1610 return -1;
1611 }
1612 prefix_length = (int)tmp;
1613 } else {
1614 printf("cidr_region_or_ip: %s , has %d number of '/' characters, is not a valid cidr_region or IP\n", cidr_region_or_ip_addr, slash_count);
1615 return -1;
1616 }
1617
1618 int cidr_addr_family, target_addr_family;
1619 if (strchr(cidr_ip_part, ':')){
1620 cidr_addr_family = AF_INET6;
1621 } else {
1622 cidr_addr_family = AF_INET;
1623 }
1624
1625 if (strchr(target_ip, ':')){
1626 target_addr_family = AF_INET6;
1627 } else {
1628 target_addr_family = AF_INET;
1629 }
1630
1631 if (cidr_addr_family != target_addr_family){
1632 if (verbose >= 1){
1633 printf("cidr address: %s and target ip address: %s have different address families\n", cidr_ip_part, target_ip);
1634 }
1635 free(cidr_ip_part);
1636 return 0;
1637 }
1638
1639 // If no prefix is given, treat the cidr as a single address (full-length prefix)
1640 if (slash_count == 0) {
1641 prefix_length = (cidr_addr_family == AF_INET) ? 32 : 128;
1642 }
1643
1644 int max_bits = (cidr_addr_family == AF_INET) ? 32u : 128u;
1645 if (prefix_length < 0 || prefix_length > max_bits) {
1646 if (verbose >= 1) {
1647 printf("cidr_region_or_ip: %s has invalid prefix length: %u\n", cidr_region_or_ip_addr, prefix_length);
1648 }
1649 free(cidr_ip_part);
1650 return -1;
1651 }
1652
1653 if (verbose >= 1){
1654 printf("cidr_region_or_ip: %s , has prefix length: %u\n", cidr_region_or_ip_addr, prefix_length);
1655 }
1656
1657 int inet_pton_rc;
1658 uint8_t *cidr_bytes = NULL;
1659 uint8_t *target_bytes = NULL;
1660 uint8_t cidr_buf[16];
1661 uint8_t target_buf[16];
1662 size_t total_bytes = 0;
1663
1664 if (cidr_addr_family == AF_INET) {
1665 struct in_addr cidr_ipv4;
1666 struct in_addr target_ipv4;
1667 inet_pton_rc = inet_pton(AF_INET, cidr_ip_part, &cidr_ipv4);
1668 if (inet_pton_rc != 1) {
1669 if (verbose >= 1) {
1670 printf("ip string: %s contains characters not valid for its address family: IPv4\n", cidr_ip_part);
1671 }
1672 free(cidr_ip_part);
1673 return -1;
1674 }
1675 inet_pton_rc = inet_pton(AF_INET, target_ip, &target_ipv4);
1676 if (inet_pton_rc != 1) {
1677 if (verbose >= 1) {
1678 printf("ip string: %s contains characters not valid for its address family: IPv4\n", target_ip);
1679 }
1680 free(cidr_ip_part);
1681 return -1;
1682 }
1683 // copy the addresses in network byte order to a buffer for comparison
1684 memcpy(cidr_buf, &cidr_ipv4.s_addr, 4);
1685 memcpy(target_buf, &target_ipv4.s_addr, 4);
1686 cidr_bytes = cidr_buf;
1687 target_bytes = target_buf;
1688 total_bytes = 4;
1689 } else {
1690 struct in6_addr cidr_ipv6;
1691 struct in6_addr target_ipv6;
1692 inet_pton_rc = inet_pton(AF_INET6, cidr_ip_part, &cidr_ipv6);
1693 if (inet_pton_rc != 1) {
1694 if (verbose >= 1) {
1695 printf("ip string: %s contains characters not valid for its address family: IPv6\n", cidr_ip_part);
1696 }
1697 free(cidr_ip_part);
1698 return -1;
1699 }
1700 inet_pton_rc = inet_pton(AF_INET6, target_ip, &target_ipv6);
1701 if (inet_pton_rc != 1) {
1702 if (verbose >= 1) {
1703 printf("ip string: %s contains characters not valid for its address family: IPv6\n", target_ip);
1704 }
1705 free(cidr_ip_part);
1706 return -1;
1707 }
1708 memcpy(cidr_buf, &cidr_ipv6, 16);
1709 memcpy(target_buf, &target_ipv6, 16);
1710 cidr_bytes = cidr_buf;
1711 target_bytes = target_buf;
1712 total_bytes = 16;
1713 }
1714
1715 int prefix_bytes = prefix_length / 8;
1716 int prefix_bits = prefix_length % 8;
1717
1718 if (prefix_bytes > 0) {
1719 if (memcmp(cidr_bytes, target_bytes, (size_t)prefix_bytes) != 0) {
1720 if (verbose >= 1) {
1721 printf("the first %d bytes of the cidr_region_or_ip: %s and target_ip: %s are different\n", prefix_bytes, cidr_ip_part, target_ip);
1722 }
1723 free(cidr_ip_part);
1724 return 0;
1725 }
1726 }
1727
1728 if (prefix_bits != 0) {
1729 uint8_t cidr_oct = cidr_bytes[prefix_bytes];
1730 uint8_t target_oct = target_bytes[prefix_bytes];
1731 // the mask has first prefix_bits bits 1, the rest as 0
1732 uint8_t mask = (uint8_t)(0xFFu << (8 - prefix_bits));
1733 if ((cidr_oct & mask) != (target_oct & mask)) {
1734 if (verbose >= 1) {
1735 printf("looking at the last %d bits of the prefix, cidr_region_or_ip(%s) byte is: %u and target_ip byte(%s) is: %u, applying bitmask: %02X returns different results\n", prefix_bits, cidr_ip_part, (unsigned)cidr_oct, target_ip, (unsigned)target_oct, mask);
1736 }
1737 free(cidr_ip_part);
1738 return 0;
1739 }
1740 }
1741
1742 free(cidr_ip_part);
1743 return 1;
1744}
diff --git a/plugins/check_curl.d/check_curl_helpers.h b/plugins/check_curl.d/check_curl_helpers.h
index e77b763b..cc47bf9d 100644
--- a/plugins/check_curl.d/check_curl_helpers.h
+++ b/plugins/check_curl.d/check_curl_helpers.h
@@ -126,3 +126,12 @@ void test_file(char *path);
126mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp, 126mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp,
127 int crit_days_till_exp); 127 int crit_days_till_exp);
128char *fmt_url(check_curl_working_state workingState); 128char *fmt_url(check_curl_working_state workingState);
129
130
131/* function that will determine if the host or the proxy resolves the target hostname
132returns 0 if requester resolves the hostname locally, 1 if proxy resolves the hostname */
133int determine_hostname_resolver(const check_curl_working_state working_state, const check_curl_static_curl_config config);
134
135/* Checks if an IP is inside given CIDR region. Using /protocol_size or not specifying the prefix length performs an equality check. Supports both IPv4 and IPv6
136returns 1 if the target_ip address is inside the given cidr_region_or_ip_addr, 0 if its out. return codes < 0 mean an error has occurred. */
137int ip_addr_inside_cidr(const char* cidr_region_or_ip_addr, const char* target_ip);
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h
index 61067d46..bcdf3010 100644
--- a/plugins/check_curl.d/config.h
+++ b/plugins/check_curl.d/config.h
@@ -48,6 +48,11 @@ typedef struct {
48 48
49 bool use_ssl; 49 bool use_ssl;
50 bool no_body; 50 bool no_body;
51
52 /* curl CURLOPT_PROXY option will be set to this value if not NULL */
53 char *curlopt_proxy;
54 /* curl CURLOPT_NOPROXY option will be set to this value if not NULL */
55 char *curlopt_noproxy;
51} check_curl_working_state; 56} check_curl_working_state;
52 57
53check_curl_working_state check_curl_working_state_init(); 58check_curl_working_state check_curl_working_state_init();
@@ -65,6 +70,8 @@ typedef struct {
65 char *client_privkey; 70 char *client_privkey;
66 char *ca_cert; 71 char *ca_cert;
67 bool verify_peer_and_host; 72 bool verify_peer_and_host;
73 char proxy[DEFAULT_BUFFER_SIZE];
74 char no_proxy[DEFAULT_BUFFER_SIZE];
68 char user_agent[DEFAULT_BUFFER_SIZE]; 75 char user_agent[DEFAULT_BUFFER_SIZE];
69 char proxy_auth[MAX_INPUT_BUFFER]; 76 char proxy_auth[MAX_INPUT_BUFFER];
70 char user_auth[MAX_INPUT_BUFFER]; 77 char user_auth[MAX_INPUT_BUFFER];