noproxy: support proxies specified using cidr notation
Resolves: RHEL-86910
This commit is contained in:
parent
66cf34993a
commit
ec7cc6fa07
268
0070-curl-7.61.1-noproxy-support-using-cidr.patch
Normal file
268
0070-curl-7.61.1-noproxy-support-using-cidr.patch
Normal file
@ -0,0 +1,268 @@
|
||||
From 1e9a538e05c0107c54ef81d9de7cd0b27cd13309 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Stenberg <daniel@haxx.se>
|
||||
Date: Thu, 20 Oct 2022 15:21:12 +0200
|
||||
Subject: [PATCH] noproxy: support proxies specified using cidr notation
|
||||
|
||||
For both IPv4 and IPv6 addresses. Now also checks IPv6 addresses "correctly"
|
||||
and not with string comparisons.
|
||||
|
||||
Backported to curl 7.61.1 for RHEL 8.
|
||||
|
||||
Reported-by: Mathieu Carbonneaux
|
||||
Fixes #9773
|
||||
Fixes #5745
|
||||
Closes #9775
|
||||
---
|
||||
index f159008..d151f5c 100644
|
||||
--- a/lib/url.c
|
||||
+++ b/lib/url.c
|
||||
@@ -2509,6 +2509,75 @@ void Curl_free_request_state(struct Curl_easy *data)
|
||||
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
+
|
||||
+/*
|
||||
+ * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the
|
||||
+ * specified CIDR address range.
|
||||
+ */
|
||||
+static bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */
|
||||
+ const char *network, /* 1.2.3.4 address */
|
||||
+ unsigned int bits)
|
||||
+{
|
||||
+ unsigned int address = 0;
|
||||
+ unsigned int check = 0;
|
||||
+
|
||||
+ if(bits > 32)
|
||||
+ /* strange input */
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if(1 != Curl_inet_pton(AF_INET, ipv4, &address))
|
||||
+ return FALSE;
|
||||
+ if(1 != Curl_inet_pton(AF_INET, network, &check))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if(!bits)
|
||||
+ return TRUE; /* /0 means all addresses match */
|
||||
+
|
||||
+ if(bits && (bits != 32)) {
|
||||
+ unsigned int mask = 0xffffffff << (32 - bits);
|
||||
+ unsigned int haddr = htonl(address);
|
||||
+ unsigned int hcheck = htonl(check);
|
||||
+ if((haddr ^ hcheck) & mask)
|
||||
+ return FALSE;
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ return (address == check);
|
||||
+}
|
||||
+
|
||||
+static bool Curl_cidr6_match(const char *ipv6,
|
||||
+ const char *network,
|
||||
+ unsigned int bits)
|
||||
+{
|
||||
+ int bytes;
|
||||
+ int rest;
|
||||
+ unsigned char address[16];
|
||||
+ unsigned char check[16];
|
||||
+
|
||||
+ if(!bits)
|
||||
+ bits = 128;
|
||||
+
|
||||
+ bytes = bits/8;
|
||||
+ rest = bits & 0x07;
|
||||
+ if((bytes > 16) || ((bytes == 16) && rest))
|
||||
+ return FALSE;
|
||||
+ if(1 != Curl_inet_pton(AF_INET6, ipv6, address))
|
||||
+ return FALSE;
|
||||
+ if(1 != Curl_inet_pton(AF_INET6, network, check))
|
||||
+ return FALSE;
|
||||
+ if(bytes && memcmp(address, check, bytes))
|
||||
+ return FALSE;
|
||||
+ if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest))))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+enum nametype {
|
||||
+ TYPE_HOST,
|
||||
+ TYPE_IPV4,
|
||||
+ TYPE_IPV6
|
||||
+};
|
||||
+
|
||||
/****************************************************************
|
||||
* Checks if the host is in the noproxy list. returns true if it matches
|
||||
* and therefore the proxy should NOT be used.
|
||||
@@ -2521,70 +2590,127 @@ static bool check_noproxy(const char *name, const char *no_proxy)
|
||||
* all proxy variables)
|
||||
*/
|
||||
if(no_proxy && no_proxy[0]) {
|
||||
- size_t tok_start;
|
||||
- size_t tok_end;
|
||||
- const char *separator = ", ";
|
||||
- size_t no_proxy_len;
|
||||
+ const char *p = no_proxy;
|
||||
size_t namelen;
|
||||
- char *endptr;
|
||||
- if(strcasecompare("*", no_proxy)) {
|
||||
+ enum nametype type = TYPE_HOST;
|
||||
+ char hostip[128];
|
||||
+ if(strcasecompare("*", no_proxy))
|
||||
return TRUE;
|
||||
- }
|
||||
|
||||
/* NO_PROXY was specified and it wasn't just an asterisk */
|
||||
|
||||
- no_proxy_len = strlen(no_proxy);
|
||||
if(name[0] == '[') {
|
||||
+ char *endptr;
|
||||
/* IPv6 numerical address */
|
||||
endptr = strchr(name, ']');
|
||||
if(!endptr)
|
||||
return FALSE;
|
||||
name++;
|
||||
- }
|
||||
- else
|
||||
- endptr = strchr(name, ':');
|
||||
- if(endptr)
|
||||
namelen = endptr - name;
|
||||
- else
|
||||
- namelen = strlen(name);
|
||||
-
|
||||
- for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) {
|
||||
- while(tok_start < no_proxy_len &&
|
||||
- strchr(separator, no_proxy[tok_start]) != NULL) {
|
||||
- /* Look for the beginning of the token. */
|
||||
- ++tok_start;
|
||||
+ if(namelen >= sizeof(hostip))
|
||||
+ return FALSE;
|
||||
+ memcpy(hostip, name, namelen);
|
||||
+ hostip[namelen] = 0;
|
||||
+ name = hostip;
|
||||
+ type = TYPE_IPV6;
|
||||
+ }
|
||||
+ else {
|
||||
+ char *portptr;
|
||||
+ unsigned int address;
|
||||
+ /* First, strip off any port number */
|
||||
+ portptr = strchr(name, ':');
|
||||
+ if(portptr)
|
||||
+ namelen = portptr - name;
|
||||
+ else
|
||||
+ namelen = strlen(name);
|
||||
+
|
||||
+ /* Copy name without port to buffer for type detection */
|
||||
+ if(namelen >= sizeof(hostip))
|
||||
+ namelen = sizeof(hostip) - 1;
|
||||
+ memcpy(hostip, name, namelen);
|
||||
+ hostip[namelen] = 0;
|
||||
+
|
||||
+ /* Now check if it's an IPv4 address */
|
||||
+ if(1 == Curl_inet_pton(AF_INET, hostip, &address)) {
|
||||
+ type = TYPE_IPV4;
|
||||
+ name = hostip;
|
||||
}
|
||||
+ else {
|
||||
+ /* It's a hostname - namelen already excludes port */
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- if(tok_start == no_proxy_len)
|
||||
- break; /* It was all trailing separator chars, no more tokens. */
|
||||
+ while(*p) {
|
||||
+ const char *token;
|
||||
+ size_t tokenlen = 0;
|
||||
+ bool match = FALSE;
|
||||
|
||||
- for(tok_end = tok_start; tok_end < no_proxy_len &&
|
||||
- strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end)
|
||||
- /* Look for the end of the token. */
|
||||
- ;
|
||||
+ /* pass blanks */
|
||||
+ while(*p && ISBLANK(*p))
|
||||
+ p++;
|
||||
|
||||
- /* To match previous behaviour, where it was necessary to specify
|
||||
- * ".local.com" to prevent matching "notlocal.com", we will leave
|
||||
- * the '.' off.
|
||||
- */
|
||||
- if(no_proxy[tok_start] == '.')
|
||||
- ++tok_start;
|
||||
-
|
||||
- if((tok_end - tok_start) <= namelen) {
|
||||
- /* Match the last part of the name to the domain we are checking. */
|
||||
- const char *checkn = name + namelen - (tok_end - tok_start);
|
||||
- if(strncasecompare(no_proxy + tok_start, checkn,
|
||||
- tok_end - tok_start)) {
|
||||
- if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') {
|
||||
- /* We either have an exact match, or the previous character is a .
|
||||
- * so it is within the same domain, so no proxy for this host.
|
||||
- */
|
||||
- return TRUE;
|
||||
+ token = p;
|
||||
+ /* pass over the pattern */
|
||||
+ while(*p && !ISBLANK(*p) && (*p != ',')) {
|
||||
+ p++;
|
||||
+ tokenlen++;
|
||||
+ }
|
||||
+
|
||||
+ if(tokenlen) {
|
||||
+ switch(type) {
|
||||
+ case TYPE_HOST:
|
||||
+ /* Skip leading dot in token */
|
||||
+ if(tokenlen && (*token == '.')) {
|
||||
+ token++;
|
||||
+ tokenlen--;
|
||||
+ }
|
||||
+ /* A: example.com matches 'example.com'
|
||||
+ B: www.example.com matches 'example.com'
|
||||
+ C: nonexample.com DOES NOT match 'example.com' */
|
||||
+ if(tokenlen == namelen)
|
||||
+ /* case A, exact match */
|
||||
+ match = strncasecompare(token, name, namelen);
|
||||
+ else if(tokenlen < namelen) {
|
||||
+ /* case B, tailmatch domain */
|
||||
+ match = (name[namelen - tokenlen - 1] == '.') &&
|
||||
+ strncasecompare(token, name + (namelen - tokenlen), tokenlen);
|
||||
}
|
||||
+ /* case C passes through, not a match */
|
||||
+ break;
|
||||
+ case TYPE_IPV4:
|
||||
+ /* FALLTHROUGH */
|
||||
+ case TYPE_IPV6: {
|
||||
+ const char *check = token;
|
||||
+ char *slash;
|
||||
+ unsigned int bits = 0;
|
||||
+ char checkip[128];
|
||||
+ if(tokenlen >= sizeof(checkip))
|
||||
+ /* this cannot match */
|
||||
+ break;
|
||||
+ /* copy the check name to a temp buffer */
|
||||
+ memcpy(checkip, check, tokenlen);
|
||||
+ checkip[tokenlen] = 0;
|
||||
+ check = checkip;
|
||||
+
|
||||
+ slash = strchr(check, '/');
|
||||
+ /* if the slash is part of this token, use it */
|
||||
+ if(slash) {
|
||||
+ bits = atoi(slash + 1);
|
||||
+ *slash = 0;
|
||||
+ }
|
||||
+ if(type == TYPE_IPV6)
|
||||
+ match = Curl_cidr6_match(name, check, bits);
|
||||
+ else
|
||||
+ match = Curl_cidr4_match(name, check, bits);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- } /* if((tok_end - tok_start) <= namelen) */
|
||||
- } /* for(tok_start = 0; tok_start < no_proxy_len;
|
||||
- tok_start = tok_end + 1) */
|
||||
+ if(match)
|
||||
+ return TRUE;
|
||||
+ } /* if(tokenlen) */
|
||||
+ while(*p == ',')
|
||||
+ p++;
|
||||
+ } /* while(*p) */
|
||||
} /* NO_PROXY was specified and it wasn't just an asterisk */
|
||||
|
||||
return FALSE;
|
||||
15
curl.spec
15
curl.spec
@ -1,7 +1,7 @@
|
||||
Summary: A utility for getting files from remote servers (FTP, HTTP, and others)
|
||||
Name: curl
|
||||
Version: 7.61.1
|
||||
Release: 34%{?dist}.10
|
||||
Release: 34%{?dist}.11
|
||||
License: MIT
|
||||
Source: https://curl.haxx.se/download/%{name}-%{version}.tar.xz
|
||||
|
||||
@ -202,6 +202,9 @@ Patch68: 0068-curl-7.61.1-CVE-2025-9086.patch
|
||||
# AWS Signature Version 4 authentication support
|
||||
Patch69: 0069-curl-7.61.1-aws-sigv4.patch
|
||||
|
||||
# noproxy: support proxies specified using cidr notation
|
||||
Patch70: 0070-curl-7.61.1-noproxy-support-using-cidr.patch
|
||||
|
||||
# patch making libcurl multilib ready
|
||||
Patch101: 0101-curl-7.32.0-multilib.patch
|
||||
|
||||
@ -409,7 +412,6 @@ sed -e 's|%%HTTPPORT|%{?__isa_bits}90|g' -i tests/data/test1448
|
||||
%patch -P 35 -p1
|
||||
%patch -P 36 -p1
|
||||
%patch -P 37 -p1
|
||||
|
||||
%patch -P 38 -p1
|
||||
sed -e 's|:8992/|:%{?__isa_bits}92/|g' -i tests/data/test97{3..6}
|
||||
|
||||
@ -444,6 +446,7 @@ git apply %{PATCH52}
|
||||
%patch -P 67 -p1
|
||||
%patch -P 68 -p1
|
||||
%patch -P 69 -p1
|
||||
%patch -P 70 -p1
|
||||
|
||||
# make tests/*.py use Python 3
|
||||
sed -e '1 s|^#!/.*python|#!%{__python3}|' -i tests/*.py
|
||||
@ -457,7 +460,9 @@ automake
|
||||
# <https://github.com/bagder/curl/commit/21e82bd6#commitcomment-12226582>
|
||||
# and test 1900, which is flaky and covers a deprecated feature of libcurl
|
||||
# <https://github.com/curl/curl/pull/2705>
|
||||
printf "1112\n1455\n1801\n1900\n" >> tests/data/DISABLED
|
||||
# disable test 1456 - requires test framework features not available in 7.61.1
|
||||
# (crlf attribute support for <protocol> tag)
|
||||
printf "1112\n1455\n1456\n1801\n1900\n" >> tests/data/DISABLED
|
||||
|
||||
# disable test 1319 on ppc64 (server times out)
|
||||
%ifarch ppc64
|
||||
@ -606,6 +611,10 @@ rm -f ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la
|
||||
%{_libdir}/libcurl.so.4.[0-9].[0-9].minimal
|
||||
|
||||
%changelog
|
||||
* Tue Jan 13 2026 Jacek Migacz <jmigacz@redhat.com> - 7.61.1-34.el8_10.11
|
||||
- noproxy: support proxies specified using cidr notation (RHEL-86910)
|
||||
- disable test1456 (requires test framework features not in 7.61.1)
|
||||
|
||||
* Wed Dec 03 2025 Jacek Migacz <jmigacz@redhat.com> - 7.61.1-34.el8_10.10
|
||||
- AWS Signature Version 4 authentication support (RHEL-116183)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user