diff --git a/SOURCES/0031-curl-7.76.1-CVE-2023-28321.patch b/SOURCES/0031-curl-7.76.1-CVE-2023-28321.patch
index b306e91..10450e0 100644
--- a/SOURCES/0031-curl-7.76.1-CVE-2023-28321.patch
+++ b/SOURCES/0031-curl-7.76.1-CVE-2023-28321.patch
@@ -41,7 +41,7 @@ index e827dc58f378c..d061c6356f97f 100644
/*
* Match a hostname against a wildcard pattern.
* E.g.
-@@ -65,26 +76,27 @@
+@@ -65,26 +76,31 @@
static int hostmatch(char *hostname, char *pattern)
{
@@ -73,10 +73,14 @@ index e827dc58f378c..d061c6356f97f 100644
- if(pattern_wildcard == NULL)
- return strcasecompare(pattern, hostname) ?
- CURL_HOST_MATCH : CURL_HOST_NOMATCH;
-+ if(hostname[hostlen-1]=='.')
++ if(hostname[hostlen-1]=='.') {
+ hostname[hostlen-1] = 0;
-+ if(pattern[patternlen-1]=='.')
++ hostlen--;
++ }
++ if(pattern[patternlen-1]=='.') {
+ pattern[patternlen-1] = 0;
++ patternlen--;
++ }
+
+ if(strncmp(pattern, "*.", 2))
+ return pmatch(hostname, hostlen, pattern, patternlen);
@@ -143,7 +147,7 @@ index 84f962abebee3..f31b2c2a3f330 100644
-@@ -15,9 +14,9 @@ none
+@@ -14,9 +13,9 @@ none
unittest
@@ -154,7 +158,7 @@ index 84f962abebee3..f31b2c2a3f330 100644
+Curl_cert_hostcheck unit tests
+
-
+
diff --git a/tests/unit/unit1397.c b/tests/unit/unit1397.c
index 2f3d3aa4d09e1..3ae75618d5d10 100644
@@ -169,7 +173,7 @@ index 2f3d3aa4d09e1..3ae75618d5d10 100644
static CURLcode unit_setup(void)
{
return CURLE_OK;
-@@ -30,50 +28,93 @@ static CURLcode unit_setup(void)
+@@ -30,50 +28,91 @@ static CURLcode unit_setup(void)
static void unit_stop(void)
{
@@ -280,9 +284,7 @@ index 2f3d3aa4d09e1..3ae75618d5d10 100644
+ int i;
+ for(i = 0; tests[i].host; i++) {
+ if(tests[i].match != Curl_cert_hostcheck(tests[i].pattern,
-+ strlen(tests[i].pattern),
-+ tests[i].host,
-+ strlen(tests[i].host))) {
++ tests[i].host)) {
+ fprintf(stderr,
+ "HOST: %s\n"
+ "PTRN: %s\n"
diff --git a/SOURCES/0039-curl-7.76.1-pause-on-http.patch b/SOURCES/0039-curl-7.76.1-pause-on-http.patch
new file mode 100644
index 0000000..96ddcd4
--- /dev/null
+++ b/SOURCES/0039-curl-7.76.1-pause-on-http.patch
@@ -0,0 +1,28 @@
+From badcf275bc5e7a13128734968102a48c93962cef Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Mon, 17 May 2021 09:05:39 +0200
+Subject: [PATCH] http2: make sure pause is done on HTTP
+
+Since the function is called for any protocol, we can't assume that the
+HTTP struct is there without first making sure it is HTTP.
+
+Reported-by: Denis Goleshchikhin
+Fixes #7079
+---
+ lib/http2.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/lib/http2.c b/lib/http2.c
+index ac04d348c495..bc604ce1551a 100644
+--- a/lib/http2.c
++++ b/lib/http2.c
+@@ -2353,7 +2353,8 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ /* if it isn't HTTP/2, we're done */
+- if(!data->conn->proto.httpc.h2)
++ if(!(data->conn->handler->protocol & PROTO_FAMILY_HTTP) ||
++ !data->conn->proto.httpc.h2)
+ return CURLE_OK;
+ #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
+ else {
diff --git a/SOURCES/0040-curl-7.76.1-noproxy-support-using-cidr.patch b/SOURCES/0040-curl-7.76.1-noproxy-support-using-cidr.patch
new file mode 100644
index 0000000..806a94e
--- /dev/null
+++ b/SOURCES/0040-curl-7.76.1-noproxy-support-using-cidr.patch
@@ -0,0 +1,1694 @@
+From 1e9a538e05c0107c54ef81d9de7cd0b27cd13309 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+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.
+
+Split out the noproxy checks and functionality into noproxy.c
+
+Added unit test 1614 to verify checking functions.
+
+Reported-by: Mathieu Carbonneaux
+
+Fixes #9773
+Fixes #5745
+Closes #9775
+---
+ docs/KNOWN_BUGS | 8 --
+ docs/libcurl/opts/CURLOPT_NOPROXY.3 | 4 -
+ lib/Makefile.inc | 2 +
+ lib/noproxy.c | 212 ++++++++++++++++++++++++++++
+ lib/noproxy.h | 44 ++++++
+ lib/url.c | 82 +----------
+ tests/data/Makefile.inc | 2 +-
+ tests/data/test1614 | 25 ++++
+ tests/unit/Makefile.inc | 5 +-
+ tests/unit/unit1614.c | 133 +++++++++++++++++
+ 10 files changed, 424 insertions(+), 93 deletions(-)
+ create mode 100644 lib/noproxy.c
+ create mode 100644 lib/noproxy.h
+ create mode 100644 tests/data/test1614
+ create mode 100644 tests/unit/unit1614.c
+
+diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS
+index 5a1dea1b5..6cbcd51de 100644
+--- a/docs/KNOWN_BUGS
++++ b/docs/KNOWN_BUGS
+@@ -119,7 +119,6 @@ problems may have been fixed or changed somewhat since this was written.
+ 11.9 DoH doesn't inherit all transfer options
+ 11.10 Blocking socket operations in non-blocking API
+ 11.11 A shared connection cache is not thread-safe
+- 11.12 'no_proxy' string-matches IPv6 numerical addresses
+ 11.13 wakeup socket disconnect causes havoc
+ 11.14 Multi perform hangs waiting for threaded resolver
+ 11.15 CURLOPT_OPENSOCKETPAIRFUNCTION is missing
+@@ -931,13 +930,6 @@ problems may have been fixed or changed somewhat since this was written.
+
+ See https://github.com/curl/curl/issues/4915 and lib1541.c
+
+-11.12 'no_proxy' string-matches IPv6 numerical addresses
+-
+- This has the downside that "::1" for example doesn't match "::0:1" even
+- though they are in fact the same address.
+-
+- See https://github.com/curl/curl/issues/5745
+-
+ 11.13 wakeup socket disconnect causes havoc
+
+ waking an iPad breaks the wakeup socket pair, triggering a POLLIN event and
+diff --git a/docs/libcurl/opts/CURLOPT_NOPROXY.3 b/docs/libcurl/opts/CURLOPT_NOPROXY.3
+index da336014f..138f57637 100644
+--- a/docs/libcurl/opts/CURLOPT_NOPROXY.3
++++ b/docs/libcurl/opts/CURLOPT_NOPROXY.3
+@@ -53,10 +53,6 @@ brackets:
+
+ "example.com,::1,localhost"
+
+-IPv6 numerical addresses are compared as strings, so they will only match if
+-the representations are the same: "::1" is the same as "::0:1" but they don't
+-match.
+-
+ The application does not have to keep the string around after setting this
+ option.
+ .SH "Environment variables"
+diff --git a/lib/Makefile.inc b/lib/Makefile.inc
+index 229f42d86..b2d2e9e52 100644
+--- a/lib/Makefile.inc
++++ b/lib/Makefile.inc
+@@ -177,6 +177,7 @@ LIB_CFILES = \
+ netrc.c \
+ non-ascii.c \
+ nonblock.c \
++ noproxy.c \
+ openldap.c \
+ parsedate.c \
+ pingpong.c \
+@@ -301,6 +302,7 @@ LIB_HFILES = \
+ netrc.h \
+ non-ascii.h \
+ nonblock.h \
++ noproxy.h \
+ parsedate.h \
+ pingpong.h \
+ pop3.h \
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+new file mode 100644
+index 000000000..701a09e04
+--- /dev/null
++++ b/lib/noproxy.c
+@@ -0,0 +1,212 @@
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++
++#include "curl_setup.h"
++
++#ifndef CURL_DISABLE_PROXY
++
++#include "inet_pton.h"
++#include "strcase.h"
++#include "noproxy.h"
++
++/*
++ * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the
++ * specified CIDR address range.
++ */
++UNITTEST 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 && (bits != 32)) {
++ unsigned int mask = 0xffffffff << (32 - bits);
++ unsigned int haddr = htonl(address);
++ unsigned int hcheck = htonl(check);
++#if 0
++ fprintf(stderr, "Host %s (%x) network %s (%x) bits %u mask %x => %x\n",
++ ipv4, haddr, network, hcheck, bits, mask,
++ (haddr ^ hcheck) & mask);
++#endif
++ if((haddr ^ hcheck) & mask)
++ return FALSE;
++ return TRUE;
++ }
++ return (address == check);
++}
++
++UNITTEST 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(1 != Curl_inet_pton(AF_INET6, ipv6, address))
++ return FALSE;
++ if(1 != Curl_inet_pton(AF_INET6, network, check))
++ return FALSE;
++ if((bytes > 16) || ((bytes == 16) && rest))
++ 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.
++****************************************************************/
++bool Curl_check_noproxy(const char *name, const char *no_proxy)
++{
++ /* no_proxy=domain1.dom,host.domain2.dom
++ * (a comma-separated list of hosts which should
++ * not be proxied, or an asterisk to override
++ * all proxy variables)
++ */
++ if(no_proxy && no_proxy[0]) {
++ const char *p = no_proxy;
++ size_t namelen;
++ enum nametype type = TYPE_HOST;
++ char hostip[128];
++ if(!strcmp("*", no_proxy))
++ return TRUE;
++
++ /* NO_PROXY was specified and it wasn't just an asterisk */
++
++ if(name[0] == '[') {
++ char *endptr;
++ /* IPv6 numerical address */
++ endptr = strchr(name, ']');
++ if(!endptr)
++ return FALSE;
++ name++;
++ namelen = endptr - name;
++ if(namelen >= sizeof(hostip))
++ return FALSE;
++ memcpy(hostip, name, namelen);
++ hostip[namelen] = 0;
++ name = hostip;
++ type = TYPE_IPV6;
++ }
++ else {
++ unsigned int address;
++ if(1 == Curl_inet_pton(AF_INET, name, &address))
++ type = TYPE_IPV4;
++ namelen = strlen(name);
++ }
++
++ while(*p) {
++ const char *token;
++ size_t tokenlen = 0;
++ bool match = FALSE;
++
++ /* pass blanks */
++ while(*p && ISBLANK(*p))
++ p++;
++
++ token = p;
++ /* pass over the pattern */
++ while(*p && !ISBLANK(*p) && (*p != ',')) {
++ p++;
++ tokenlen++;
++ }
++
++ if(tokenlen) {
++ switch(type) {
++ case TYPE_HOST:
++ if(*token == '.') {
++ ++token;
++ --tokenlen;
++ /* tailmatch */
++ match = (tokenlen <= namelen) &&
++ strncasecompare(token, name + (namelen - tokenlen), namelen);
++ }
++ else
++ match = (tokenlen == namelen) &&
++ strncasecompare(token, name, namelen);
++ break;
++ case TYPE_IPV4:
++ /* FALLTHROUGH */
++ case TYPE_IPV6: {
++ const char *check = token;
++ char *slash = strchr(check, '/');
++ unsigned int bits = 0;
++ char checkip[128];
++ /* if the slash is part of this token, use it */
++ if(slash && (slash < &check[tokenlen])) {
++ bits = atoi(slash + 1);
++ /* copy the check name to a temp buffer */
++ if(tokenlen >= sizeof(checkip))
++ break;
++ memcpy(checkip, check, tokenlen);
++ checkip[ slash - check ] = 0;
++ check = checkip;
++ }
++ if(type == TYPE_IPV6)
++ match = Curl_cidr6_match(name, check, bits);
++ else
++ match = Curl_cidr4_match(name, check, bits);
++ break;
++ }
++ }
++ if(match)
++ return TRUE;
++ } /* if(tokenlen) */
++ while(*p == ',')
++ p++;
++ } /* while(*p) */
++ } /* NO_PROXY was specified and it wasn't just an asterisk */
++
++ return FALSE;
++}
++
++#endif /* CURL_DISABLE_PROXY */
++
+diff --git a/lib/noproxy.h b/lib/noproxy.h
+new file mode 100644
+index 000000000..8800a2127
+--- /dev/null
++++ b/lib/noproxy.h
+@@ -0,0 +1,44 @@
++#ifndef HEADER_CURL_NOPROXY_H
++#define HEADER_CURL_NOPROXY_H
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++#include "curl_setup.h"
++
++#ifndef CURL_DISABLE_PROXY
++
++#ifdef DEBUGBUILD
++
++UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */
++ const char *network, /* 1.2.3.4 address */
++ unsigned int bits);
++UNITTEST bool Curl_cidr6_match(const char *ipv6,
++ const char *network,
++ unsigned int bits);
++#endif
++
++bool Curl_check_noproxy(const char *name, const char *no_proxy);
++
++#endif
++
++#endif /* HEADER_CURL_NOPROXY_H */
+diff --git a/lib/url.c b/lib/url.c
+index 5ace2fdd8..a3be56bce 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -106,6 +106,7 @@ bool Curl_win32_idn_to_ascii(const char *in, char **out);
+ #include "urlapi-int.h"
+ #include "system_win32.h"
+ #include "hsts.h"
++#include "noproxy.h"
+
+ /* And now for the protocols */
+ #include "ftp.h"
+@@ -2261,83 +2262,6 @@ void Curl_free_request_state(struct Curl_easy *data)
+
+
+ #ifndef CURL_DISABLE_PROXY
+-/****************************************************************
+-* Checks if the host is in the noproxy list. returns true if it matches
+-* and therefore the proxy should NOT be used.
+-****************************************************************/
+-static bool check_noproxy(const char *name, const char *no_proxy)
+-{
+- /* no_proxy=domain1.dom,host.domain2.dom
+- * (a comma-separated list of hosts which should
+- * not be proxied, or an asterisk to override
+- * 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;
+- size_t namelen;
+- char *endptr;
+- 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] == '[') {
+- /* IPv6 numerical address */
+- endptr = strchr(name, ']');
+- if(!endptr)
+- return FALSE;
+- name++;
+- 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(tok_start == no_proxy_len)
+- break; /* It was all trailing separator chars, no more tokens. */
+-
+- 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. */
+- ;
+-
+- /* To match previous behavior, 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;
+- }
+- }
+- } /* if((tok_end - tok_start) <= namelen) */
+- } /* for(tok_start = 0; tok_start < no_proxy_len;
+- tok_start = tok_end + 1) */
+- } /* NO_PROXY was specified and it wasn't just an asterisk */
+-
+- return FALSE;
+-}
+
+ #ifndef CURL_DISABLE_HTTP
+ /****************************************************************
+@@ -2706,8 +2630,8 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+ }
+ }
+
+- if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
+- data->set.str[STRING_NOPROXY] : no_proxy)) {
++ if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
++ data->set.str[STRING_NOPROXY] : no_proxy)) {
+ Curl_safefree(proxy);
+ Curl_safefree(socksproxy);
+ }
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index 8195ad7ec..b3727a6c6 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -202,7 +202,7 @@ test1566 test1567 test1568 test1569 test1570 \
+ test1590 test1591 test1592 test1593 test1594 test1595 test1596 \
+ \
+ test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
+-test1608 test1609 test1610 test1611 test1612 test1613 \
++test1608 test1609 test1610 test1611 test1612 test1613 test1614 \
+ \
+ test1620 test1621 \
+ \
+diff --git a/tests/data/test1614 b/tests/data/test1614
+new file mode 100644
+index 000000000..4a9d54eb6
+--- /dev/null
++++ b/tests/data/test1614
+@@ -0,0 +1,25 @@
++
++
++
++unittest
++
++
++
++#
++# Client-side
++
++
++none
++
++
++unittest
++proxy
++
++
++cidr comparisons
++
++
++
++0
++
++
+diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
+index f86cb7c39..831a82033 100644
+--- a/tests/unit/Makefile.inc
++++ b/tests/unit/Makefile.inc
+@@ -34,7 +34,7 @@ UNITPROGS = unit1300 unit1301 unit1302 unit1303 unit1304 unit1305 unit1307 \
+ unit1330 unit1394 unit1395 unit1396 unit1397 unit1398 \
+ unit1399 \
+ unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
+- unit1608 unit1609 unit1610 unit1611 unit1612 \
++ unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 \
+ unit1620 unit1621 \
+ unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
+ unit1660
+@@ -132,6 +132,9 @@ unit1611_CPPFLAGS = $(AM_CPPFLAGS)
+ unit1612_SOURCES = unit1612.c $(UNITFILES)
+ unit1612_CPPFLAGS = $(AM_CPPFLAGS)
+
++unit1614_SOURCES = unit1614.c $(UNITFILES)
++unit1614_CPPFLAGS = $(AM_CPPFLAGS)
++
+ unit1620_SOURCES = unit1620.c $(UNITFILES)
+ unit1620_CPPFLAGS = $(AM_CPPFLAGS)
+
+diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c
+new file mode 100644
+index 000000000..d64f651c8
+--- /dev/null
++++ b/tests/unit/unit1614.c
+@@ -0,0 +1,133 @@
++/***************************************************************************
++ * _ _ ____ _
++ * Project ___| | | | _ \| |
++ * / __| | | | |_) | |
++ * | (__| |_| | _ <| |___
++ * \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++#include "curlcheck.h"
++
++#include "noproxy.h"
++
++static CURLcode unit_setup(void)
++{
++ return CURLE_OK;
++}
++
++static void unit_stop(void)
++{
++
++}
++
++struct check {
++ const char *a;
++ const char *n;
++ unsigned int bits;
++ bool match;
++};
++
++struct noproxy {
++ const char *a;
++ const char *n;
++ bool match;
++};
++
++UNITTEST_START
++#ifdef DEBUGBUILD
++{
++ int i;
++ int err = 0;
++ struct check list4[]= {
++ { "192.160.0.1", "192.160.0.1", 33, FALSE},
++ { "192.160.0.1", "192.160.0.1", 32, TRUE},
++ { "192.160.0.1", "192.160.0.1", 0, TRUE},
++ { "192.160.0.1", "192.160.0.1", 24, TRUE},
++ { "192.160.0.1", "192.160.0.1", 26, TRUE},
++ { "192.160.0.1", "192.160.0.1", 20, TRUE},
++ { "192.160.0.1", "192.160.0.1", 18, TRUE},
++ { "192.160.0.1", "192.160.0.1", 12, TRUE},
++ { "192.160.0.1", "192.160.0.1", 8, TRUE},
++ { "192.160.0.1", "10.0.0.1", 8, FALSE},
++ { "192.160.0.1", "10.0.0.1", 32, FALSE},
++ { "192.160.0.1", "10.0.0.1", 0, FALSE},
++ { NULL, NULL, 0, FALSE} /* end marker */
++ };
++ struct check list6[]= {
++ { "::1", "::1", 0, TRUE},
++ { "::1", "::1", 128, TRUE},
++ { "::1", "0:0::1", 128, TRUE},
++ { "::1", "0:0::1", 129, FALSE},
++ { "fe80::ab47:4396:55c9:8474", "fe80::ab47:4396:55c9:8474", 64, TRUE},
++ { NULL, NULL, 0, FALSE} /* end marker */
++ };
++ struct noproxy list[]= {
++ { "foobar", "barfoo", FALSE},
++ { "foobar", "foobar", TRUE},
++ { "192.168.0.1", "foobar", FALSE},
++ { "192.168.0.1", "192.168.0.0/16", TRUE},
++ { "192.168.0.1", "192.168.0.0/24", TRUE},
++ { "192.168.0.1", "192.168.0.0/32", FALSE},
++ { "192.168.0.1", "192.168.0.0", FALSE},
++ { "192.168.1.1", "192.168.0.0/24", FALSE},
++ { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE},
++ { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE},
++ { "[::1]", "foo, bar, 192.168.0.0/16", FALSE},
++ { "[::1]", "foo, bar, ::1/64", TRUE},
++ { "bar", "foo, bar, ::1/64", TRUE},
++ { "BAr", "foo, bar, ::1/64", TRUE},
++ { "BAr", "foo,,,,, bar, ::1/64", TRUE},
++ { "www.example.com", "foo, .example.com", TRUE},
++ { "www.example.com", "www2.example.com, .example.net", FALSE},
++ { "example.com", ".example.com, .example.net", TRUE},
++ { "nonexample.com", ".example.com, .example.net", FALSE},
++ { NULL, NULL, FALSE}
++ };
++ for(i = 0; list4[i].a; i++) {
++ bool match = Curl_cidr4_match(list4[i].a, list4[i].n, list4[i].bits);
++ if(match != list4[i].match) {
++ fprintf(stderr, "%s in %s/%u should %smatch\n",
++ list4[i].a, list4[i].n, list4[i].bits,
++ list4[i].match ? "": "not ");
++ err++;
++ }
++ }
++ for(i = 0; list6[i].a; i++) {
++ bool match = Curl_cidr6_match(list6[i].a, list6[i].n, list6[i].bits);
++ if(match != list6[i].match) {
++ fprintf(stderr, "%s in %s/%u should %smatch\n",
++ list6[i].a, list6[i].n, list6[i].bits,
++ list6[i].match ? "": "not ");
++ err++;
++ }
++ }
++ for(i = 0; list[i].a; i++) {
++ bool match = Curl_check_noproxy(list[i].a, list[i].n);
++ if(match != list[i].match) {
++ fprintf(stderr, "%s in %s should %smatch\n",
++ list[i].a, list[i].n,
++ list[i].match ? "": "not ");
++ err++;
++ }
++ }
++ return err;
++}
++#else
++return 0;
++#endif
++UNITTEST_STOP
+--
+2.49.0
+
+From 36474f1050c7f4117e3c8de6cc9217cfebfc717d Mon Sep 17 00:00:00 2001
+From: Viktor Szakats
+Date: Fri, 21 Oct 2022 19:06:25 +0000
+Subject: [PATCH] noproxy: fix builds without AF_INET6
+
+Regression from 1e9a538e05c0107c54ef81d9de7cd0b27cd13309
+
+Reviewed-by: Daniel Stenberg
+
+Closes #9778
+---
+ lib/noproxy.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 701a09e04..0b9355a66 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -70,6 +70,7 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
+ const char *network,
+ unsigned int bits)
+ {
++#ifdef ENABLE_IPV6
+ int bytes;
+ int rest;
+ unsigned char address[16];
+@@ -92,6 +93,9 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
+ return FALSE;
+
+ return TRUE;
++#else
++ return FALSE;
++#endif
+ }
+
+ enum nametype {
+--
+2.49.0
+
+From 9b63dda16ec02c758f43143abcb8c5eeaecef8ae Mon Sep 17 00:00:00 2001
+From: Viktor Szakats
+Date: Sat, 22 Oct 2022 23:20:26 +0000
+Subject: [PATCH] noproxy: silence unused variable warnings with no ipv6
+
+Follow-up to 36474f1050c7f4117e3c8de6cc9217cfebfc717d
+
+Reviewed-by: Daniel Stenberg
+Closes #9782
+---
+ lib/noproxy.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 0b9355a66..4b70a4be4 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -94,6 +94,9 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
+
+ return TRUE;
+ #else
++ (void)ipv6;
++ (void)network;
++ (void)bits;
+ return FALSE;
+ #endif
+ }
+@@ -213,4 +216,3 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ }
+
+ #endif /* CURL_DISABLE_PROXY */
+-
+--
+2.49.0
+
+From 86c0029047022ea150df1f1a35f184dd7315288a Mon Sep 17 00:00:00 2001
+From: Viktor Szakats
+Date: Tue, 25 Oct 2022 15:19:28 +0000
+Subject: [PATCH] noproxy: include netinet/in.h for htonl()
+
+Solve the Amiga build warning by including `netinet/in.h`.
+
+`krb5.c` and `socketpair.c` are using `htonl()` too. This header is
+already included in those sources.
+
+Regression from 1e9a538e05c0107c54ef81d9de7cd0b27cd13309
+
+Reviewed-by: Daniel Stenberg
+Closes #9787
+---
+ lib/noproxy.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 4b70a4be4..81f1e0993 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -30,6 +30,10 @@
+ #include "strcase.h"
+ #include "noproxy.h"
+
++#ifdef HAVE_NETINET_IN_H
++#include
++#endif
++
+ /*
+ * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the
+ * specified CIDR address range.
+--
+2.49.0
+
+From efc286b7a62af0568fdcbf3c68791c9955182128 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Thu, 27 Oct 2022 13:54:27 +0200
+Subject: [PATCH] noproxy: also match with adjacent comma
+
+If the host name is an IP address and the noproxy string contained that
+IP address with a following comma, it would erroneously not match.
+
+Extended test 1614 to verify this combo as well.
+
+Reported-by: Henning Schild
+
+Fixes #9813
+Closes #9814
+---
+ lib/noproxy.c | 20 ++++++++++++--------
+ tests/data/test1614 | 2 +-
+ tests/unit/unit1614.c | 14 ++++++++++++++
+ 3 files changed, 27 insertions(+), 9 deletions(-)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 3409dab6f..58bc69a2d 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -192,18 +192,22 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ /* FALLTHROUGH */
+ case TYPE_IPV6: {
+ const char *check = token;
+- char *slash = strchr(check, '/');
++ 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 && (slash < &check[tokenlen])) {
++ if(slash) {
+ bits = atoi(slash + 1);
+- /* copy the check name to a temp buffer */
+- if(tokenlen >= sizeof(checkip))
+- break;
+- memcpy(checkip, check, tokenlen);
+- checkip[ slash - check ] = 0;
+- check = checkip;
++ *slash = 0; /* null terminate there */
+ }
+ if(type == TYPE_IPV6)
+ match = Curl_cidr6_match(name, check, bits);
+diff --git a/tests/data/test1614 b/tests/data/test1614
+index 4a9d54eb6..73bdbb4e0 100644
+--- a/tests/data/test1614
++++ b/tests/data/test1614
+@@ -16,7 +16,7 @@ unittest
+ proxy
+
+
+-cidr comparisons
++noproxy and cidr comparisons
+
+
+
+diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c
+index 60285450c..c2f563a0d 100644
+--- a/tests/unit/unit1614.c
++++ b/tests/unit/unit1614.c
+@@ -77,6 +77,20 @@ UNITTEST_START
+ { NULL, NULL, 0, FALSE} /* end marker */
+ };
+ struct noproxy list[]= {
++ { "127.0.0.1", "127.0.0.1,localhost", TRUE},
++ { "127.0.0.1", "127.0.0.1,localhost,", TRUE},
++ { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE},
++ { "127.0.0.1", "127.0.0.1/28,localhost,", TRUE},
++ { "127.0.0.1", "127.0.0.1/31,localhost,", TRUE},
++ { "127.0.0.1", "localhost,127.0.0.1", TRUE},
++ { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
++ "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
++ "0.0.1.127.0.0.1.127.0.0." /* 128 bytes "address" */, FALSE},
++ { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
++ "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
++ "0.0.1.127.0.0.1.127.0.0" /* 127 bytes "address" */, FALSE},
++ { "localhost", "localhost,127.0.0.1", TRUE},
++ { "localhost", "127.0.0.1,localhost", TRUE},
+ { "foobar", "barfoo", FALSE},
+ { "foobar", "foobar", TRUE},
+ { "192.168.0.1", "foobar", FALSE},
+--
+2.49.0
+
+From d4fed2a13a81d23e73f1fb491c335a1b1d91e3fb Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Fri, 28 Oct 2022 00:07:14 +0200
+Subject: [PATCH] docs: explain the noproxy CIDR notation support
+
+Follow-up to 1e9a538e05c0107c
+
+Closes #9818
+---
+ docs/cmdline-opts/noproxy.d | 5 +++++
+ docs/cmdline-opts/page-footer | 7 ++++---
+ docs/libcurl/opts/CURLOPT_NOPROXY.3 | 5 +++++
+ 3 files changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/docs/cmdline-opts/noproxy.d b/docs/cmdline-opts/noproxy.d
+index c28e897eb..998f57071 100644
+--- a/docs/cmdline-opts/noproxy.d
++++ b/docs/cmdline-opts/noproxy.d
+@@ -19,3 +19,8 @@ not www.notlocal.com.
+ Since 7.53.0, This option overrides the environment variables that disable the
+ proxy. If there's an environment variable disabling a proxy, you can set
+ noproxy list to \&"" to override it.
++
++Since 7.86.0, IP addresses specified to this option can be provided using CIDR
++notation: an appended slash and number specifies the number of "network bits"
++out of the address to use in the comparison. For example "192.168.0.0/16"
++would match all addresses starting with "192.168".
+diff --git a/docs/cmdline-opts/page-footer b/docs/cmdline-opts/page-footer
+index c8a65be04..99459ba3d 100644
+--- a/docs/cmdline-opts/page-footer
++++ b/docs/cmdline-opts/page-footer
+@@ -37,9 +37,10 @@ accesses the target URL through the proxy.
+ The list of host names can also be include numerical IP addresses, and IPv6
+ versions should then be given without enclosing brackets.
+
+-IPv6 numerical addresses are compared as strings, so they will only match if
+-the representations are the same: "::1" is the same as "::0:1" but they don't
+-match.
++Since 7.86.0, IP addresses can be specified using CIDR notation: an appended
++slash and number specifies the number of "network bits" out of the address to
++use in the comparison. For example "192.168.0.0/16" would match all addresses
++starting with "192.168".
+ .IP "CURL_SSL_BACKEND "
+ If curl was built with support for "MultiSSL", meaning that it has built-in
+ support for more than one TLS backend, this environment variable can be set to
+diff --git a/docs/libcurl/opts/CURLOPT_NOPROXY.3 b/docs/libcurl/opts/CURLOPT_NOPROXY.3
+index 138f57637..5e4c32130 100644
+--- a/docs/libcurl/opts/CURLOPT_NOPROXY.3
++++ b/docs/libcurl/opts/CURLOPT_NOPROXY.3
+@@ -53,6 +53,11 @@ brackets:
+
+ "example.com,::1,localhost"
+
++Since 7.86.0, IP addresses specified to this option can be provided using CIDR
++notation: an appended slash and number specifies the number of "network bits"
++out of the address to use in the comparison. For example "192.168.0.0/16"
++would match all addresses starting with "192.168".
++
+ The application does not have to keep the string around after setting this
+ option.
+ .SH "Environment variables"
+--
+2.49.0
+
+From b830f9ba9e94acf672cd191993ff679fa888838b Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Fri, 28 Oct 2022 10:51:49 +0200
+Subject: [PATCH] noproxy: fix tail-matching
+
+Also ignore trailing dots in both host name and comparison pattern.
+
+Regression in 7.86.0 (from 1e9a538e05c0)
+
+Extended test 1614 to verify better.
+
+Reported-by: Henning Schild
+Fixes #9821
+Closes #9822
+---
+ lib/noproxy.c | 30 +++++++++++++++++++++++-------
+ tests/unit/unit1614.c | 9 +++++++++
+ 2 files changed, 32 insertions(+), 7 deletions(-)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 58bc69a2d..2832ae166 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -153,9 +153,14 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ }
+ else {
+ unsigned int address;
++ namelen = strlen(name);
+ if(1 == Curl_inet_pton(AF_INET, name, &address))
+ type = TYPE_IPV4;
+- namelen = strlen(name);
++ else {
++ /* ignore trailing dots in the host name */
++ if(name[namelen - 1] == '.')
++ namelen--;
++ }
+ }
+
+ while(*p) {
+@@ -177,12 +182,23 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ if(tokenlen) {
+ switch(type) {
+ case TYPE_HOST:
+- if(*token == '.') {
+- ++token;
+- --tokenlen;
+- /* tailmatch */
+- match = (tokenlen <= namelen) &&
+- strncasecompare(token, name + (namelen - tokenlen), namelen);
++ /* ignore trailing dots in the token to check */
++ if(token[tokenlen - 1] == '.')
++ tokenlen--;
++
++ if(tokenlen && (*token == '.')) {
++ /* A: example.com matches '.example.com'
++ B: www.example.com matches '.example.com'
++ C: nonexample.com DOES NOT match '.example.com'
++ */
++ if((tokenlen - 1) == namelen)
++ /* case A, exact match without leading dot */
++ match = strncasecompare(token + 1, name, namelen);
++ else if(tokenlen < namelen)
++ /* case B, tailmatch with leading dot */
++ match = strncasecompare(token, name + (namelen - tokenlen),
++ tokenlen);
++ /* case C passes through, not a match */
+ }
+ else
+ match = (tokenlen == namelen) &&
+diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c
+index c2f563a0d..8f62b70d4 100644
+--- a/tests/unit/unit1614.c
++++ b/tests/unit/unit1614.c
+@@ -77,6 +77,15 @@ UNITTEST_START
+ { NULL, NULL, 0, FALSE} /* end marker */
+ };
+ struct noproxy list[]= {
++ { "www.example.com", "localhost,.example.com,.example.de", TRUE},
++ { "www.example.com.", "localhost,.example.com,.example.de", TRUE},
++ { "example.com", "localhost,.example.com,.example.de", TRUE},
++ { "example.com.", "localhost,.example.com,.example.de", TRUE},
++ { "www.example.com", "localhost,.example.com.,.example.de", TRUE},
++ { "www.example.com", "localhost,www.example.com.,.example.de", TRUE},
++ { "example.com", "localhost,example.com,.example.de", TRUE},
++ { "example.com.", "localhost,example.com,.example.de", TRUE},
++ { "www.example.com", "localhost,example.com,.example.de", FALSE},
+ { "127.0.0.1", "127.0.0.1,localhost", TRUE},
+ { "127.0.0.1", "127.0.0.1,localhost,", TRUE},
+ { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE},
+--
+2.49.0
+
+From b1953c1933b369b1217ef0f16053e26da63488c3 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Sun, 6 Nov 2022 23:19:51 +0100
+Subject: [PATCH] noproxy: tailmatch like in 7.85.0 and earlier
+
+A regfression in 7.86.0 (via 1e9a538e05c010) made the tailmatch work
+differently than before. This restores the logic to how it used to work:
+
+All names listed in NO_PROXY are tailmatched against the used domain
+name, if the lengths are identical it needs a full match.
+
+Update the docs, update test 1614.
+
+Reported-by: Stuart Henderson
+Fixes #9842
+Closes #9858
+---
+ docs/libcurl/opts/CURLOPT_NOPROXY.3 | 4 ----
+ lib/noproxy.c | 32 +++++++++++++++--------------
+ tests/unit/unit1614.c | 3 ++-
+ 3 files changed, 19 insertions(+), 20 deletions(-)
+
+diff --git a/docs/libcurl/opts/CURLOPT_NOPROXY.3 b/docs/libcurl/opts/CURLOPT_NOPROXY.3
+index 5e4c32130..dc3cf7c10 100644
+--- a/docs/libcurl/opts/CURLOPT_NOPROXY.3
++++ b/docs/libcurl/opts/CURLOPT_NOPROXY.3
+@@ -40,10 +40,6 @@ list is matched as either a domain which contains the hostname, or the
+ example.com:80, and www.example.com, but not www.notanexample.com or
+ example.com.othertld.
+
+-If the name in the noproxy list has a leading period, it is a domain match
+-against the provided host name. This way ".example.com" will switch off proxy
+-use for both "www.example.com" as well as for "foo.example.com".
+-
+ Setting the noproxy string to "" (an empty string) will explicitly enable the
+ proxy for all host names, even if there is an environment variable set for it.
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 2832ae166..fb856e4fa 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -187,22 +187,24 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ tokenlen--;
+
+ if(tokenlen && (*token == '.')) {
+- /* A: example.com matches '.example.com'
+- B: www.example.com matches '.example.com'
+- C: nonexample.com DOES NOT match '.example.com'
+- */
+- if((tokenlen - 1) == namelen)
+- /* case A, exact match without leading dot */
+- match = strncasecompare(token + 1, name, namelen);
+- else if(tokenlen < namelen)
+- /* case B, tailmatch with leading dot */
+- match = strncasecompare(token, name + (namelen - tokenlen),
+- tokenlen);
+- /* case C passes through, not a match */
++ /* ignore leading token dot as well */
++ token++;
++ tokenlen--;
+ }
+- else
+- match = (tokenlen == namelen) &&
+- strncasecompare(token, name, namelen);
++ /* 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 */
+diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c
+index 8f62b70d4..523d102bf 100644
+--- a/tests/unit/unit1614.c
++++ b/tests/unit/unit1614.c
+@@ -85,7 +85,8 @@ UNITTEST_START
+ { "www.example.com", "localhost,www.example.com.,.example.de", TRUE},
+ { "example.com", "localhost,example.com,.example.de", TRUE},
+ { "example.com.", "localhost,example.com,.example.de", TRUE},
+- { "www.example.com", "localhost,example.com,.example.de", FALSE},
++ { "nexample.com", "localhost,example.com,.example.de", FALSE},
++ { "www.example.com", "localhost,example.com,.example.de", TRUE},
+ { "127.0.0.1", "127.0.0.1,localhost", TRUE},
+ { "127.0.0.1", "127.0.0.1,localhost,", TRUE},
+ { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE},
+--
+2.49.0
+
+From 60453483b5c26447df95a8a80712e809094cb2a2 Mon Sep 17 00:00:00 2001
+From: Daniel Gustafsson
+Date: Thu, 8 Dec 2022 23:37:32 +0100
+Subject: [PATCH] noproxy: guard against empty hostnames in noproxy check
+
+When checking for a noproxy setting we need to ensure that we get
+a hostname passed in. If there is no hostname then there cannot be
+a matching noproxy rule for it by definition.
+
+Closes: #10057
+Reported-by: Geeknik Labs
+Reviewed-by: Daniel Stenberg
+---
+ lib/noproxy.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index fb856e4fa..9b13fe895 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -121,6 +121,13 @@ enum nametype {
+ ****************************************************************/
+ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ {
++ /*
++ * If we don't have a hostname at all, like for example with a FILE
++ * transfer, we have nothing to interrogate the noproxy list with.
++ */
++ if(!name || name[0] == '\0')
++ return FALSE;
++
+ /* no_proxy=domain1.dom,host.domain2.dom
+ * (a comma-separated list of hosts which should
+ * not be proxied, or an asterisk to override
+--
+2.49.0
+
+From 7ad8a7ba9ebdedceafe8859d3bd4d22ee447648d Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Tue, 3 Jan 2023 14:58:37 +0100
+Subject: [PATCH] noproxy: support for space-separated names is deprecated
+
+To be removed in July 2024.
+
+Assisted-by: Michael Osipov
+Fixes #10209
+Closes #10215
+---
+ lib/noproxy.c | 13 ++++++-
+ lib/noproxy.h | 3 +-
+ lib/url.c | 6 ++-
+ tests/unit/unit1614.c | 91 ++++++++++++++++++++++++-------------------
+ 5 files changed, 88 insertions(+), 44 deletions(-)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 6c0c486f8..f1c1ed2c6 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -119,8 +119,10 @@ enum nametype {
+ * Checks if the host is in the noproxy list. returns TRUE if it matches and
+ * therefore the proxy should NOT be used.
+ ****************************************************************/
+-bool Curl_check_noproxy(const char *name, const char *no_proxy)
++bool Curl_check_noproxy(const char *name, const char *no_proxy,
++ bool *spacesep)
+ {
++ *spacesep = FALSE;
+ /*
+ * If we don't have a hostname at all, like for example with a FILE
+ * transfer, we have nothing to interrogate the noproxy list with.
+@@ -244,6 +246,15 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ if(match)
+ return TRUE;
+ } /* if(tokenlen) */
++ /* pass blanks after pattern */
++ while(ISBLANK(*p))
++ p++;
++ /* if not a comma! */
++ if(*p && (*p != ',')) {
++ *spacesep = TRUE;
++ continue;
++ }
++ /* pass any number of commas */
+ while(*p == ',')
+ p++;
+ } /* while(*p) */
+diff --git a/lib/noproxy.h b/lib/noproxy.h
+index b6a1a556a..a3a680772 100644
+--- a/lib/noproxy.h
++++ b/lib/noproxy.h
+@@ -37,7 +37,8 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
+ unsigned int bits);
+ #endif
+
+-bool Curl_check_noproxy(const char *name, const char *no_proxy);
++bool Curl_check_noproxy(const char *name, const char *no_proxy,
++ bool *spacesep);
+
+ #endif
+
+diff --git a/lib/url.c b/lib/url.c
+index e531a821c..f90427f9b 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -2401,6 +2401,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+ char *socksproxy = NULL;
+ char *no_proxy = NULL;
+ CURLcode result = CURLE_OK;
++ bool spacesep = FALSE;
+
+ /*************************************************************
+ * Extract the user and password from the authentication string
+@@ -2447,7 +2448,8 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+ }
+
+ if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
+- data->set.str[STRING_NOPROXY] : no_proxy)) {
++ data->set.str[STRING_NOPROXY] : no_proxy,
++ &spacesep)) {
+ Curl_safefree(proxy);
+ Curl_safefree(socksproxy);
+ }
+@@ -2456,6 +2458,8 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+ /* if the host is not in the noproxy list, detect proxy. */
+ proxy = detect_proxy(data, conn);
+ #endif /* CURL_DISABLE_HTTP */
++ if(spacesep)
++ infof(data, "space-separated NOPROXY patterns are deprecated");
+
+ Curl_safefree(no_proxy);
+
+diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c
+index cc685b9ce..0818ea7ed 100644
+--- a/tests/unit/unit1614.c
++++ b/tests/unit/unit1614.c
+@@ -46,6 +46,7 @@ struct noproxy {
+ const char *a;
+ const char *n;
+ bool match;
++ bool space; /* space separated */
+ };
+
+ UNITTEST_START
+@@ -77,50 +78,52 @@ UNITTEST_START
+ { NULL, NULL, 0, FALSE} /* end marker */
+ };
+ struct noproxy list[]= {
+- { "www.example.com", "localhost,.example.com,.example.de", TRUE},
+- { "www.example.com.", "localhost,.example.com,.example.de", TRUE},
+- { "example.com", "localhost,.example.com,.example.de", TRUE},
+- { "example.com.", "localhost,.example.com,.example.de", TRUE},
+- { "www.example.com", "localhost,.example.com.,.example.de", TRUE},
+- { "www.example.com", "localhost,www.example.com.,.example.de", TRUE},
+- { "example.com", "localhost,example.com,.example.de", TRUE},
+- { "example.com.", "localhost,example.com,.example.de", TRUE},
+- { "nexample.com", "localhost,example.com,.example.de", FALSE},
+- { "www.example.com", "localhost,example.com,.example.de", TRUE},
+- { "127.0.0.1", "127.0.0.1,localhost", TRUE},
+- { "127.0.0.1", "127.0.0.1,localhost,", TRUE},
+- { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE},
+- { "127.0.0.1", "127.0.0.1/28,localhost,", TRUE},
+- { "127.0.0.1", "127.0.0.1/31,localhost,", TRUE},
+- { "127.0.0.1", "localhost,127.0.0.1", TRUE},
++ { "www.example.com", "localhost .example.com .example.de", TRUE, TRUE},
++ { "www.example.com", "localhost,.example.com,.example.de", TRUE, FALSE},
++ { "www.example.com.", "localhost,.example.com,.example.de", TRUE, FALSE},
++ { "example.com", "localhost,.example.com,.example.de", TRUE, FALSE},
++ { "example.com.", "localhost,.example.com,.example.de", TRUE, FALSE},
++ { "www.example.com", "localhost,.example.com.,.example.de", TRUE, FALSE},
++ { "www.example.com", "localhost,www.example.com.,.example.de",
++ TRUE, FALSE},
++ { "example.com", "localhost,example.com,.example.de", TRUE, FALSE},
++ { "example.com.", "localhost,example.com,.example.de", TRUE, FALSE},
++ { "nexample.com", "localhost,example.com,.example.de", FALSE, FALSE},
++ { "www.example.com", "localhost,example.com,.example.de", TRUE, FALSE},
++ { "127.0.0.1", "127.0.0.1,localhost", TRUE, FALSE},
++ { "127.0.0.1", "127.0.0.1,localhost,", TRUE, FALSE},
++ { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE, FALSE},
++ { "127.0.0.1", "127.0.0.1/28,localhost,", TRUE, FALSE},
++ { "127.0.0.1", "127.0.0.1/31,localhost,", TRUE, FALSE},
++ { "127.0.0.1", "localhost,127.0.0.1", TRUE, FALSE},
+ { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
+ "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
+- "0.0.1.127.0.0.1.127.0.0." /* 128 bytes "address" */, FALSE},
++ "0.0.1.127.0.0.1.127.0.0." /* 128 bytes "address" */, FALSE, FALSE},
+ { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
+ "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
+- "0.0.1.127.0.0.1.127.0.0" /* 127 bytes "address" */, FALSE},
+- { "localhost", "localhost,127.0.0.1", TRUE},
+- { "localhost", "127.0.0.1,localhost", TRUE},
+- { "foobar", "barfoo", FALSE},
+- { "foobar", "foobar", TRUE},
+- { "192.168.0.1", "foobar", FALSE},
+- { "192.168.0.1", "192.168.0.0/16", TRUE},
+- { "192.168.0.1", "192.168.0.0/24", TRUE},
+- { "192.168.0.1", "192.168.0.0/32", FALSE},
+- { "192.168.0.1", "192.168.0.0", FALSE},
+- { "192.168.1.1", "192.168.0.0/24", FALSE},
+- { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE},
+- { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE},
+- { "[::1]", "foo, bar, 192.168.0.0/16", FALSE},
+- { "[::1]", "foo, bar, ::1/64", TRUE},
+- { "bar", "foo, bar, ::1/64", TRUE},
+- { "BAr", "foo, bar, ::1/64", TRUE},
+- { "BAr", "foo,,,,, bar, ::1/64", TRUE},
+- { "www.example.com", "foo, .example.com", TRUE},
+- { "www.example.com", "www2.example.com, .example.net", FALSE},
+- { "example.com", ".example.com, .example.net", TRUE},
+- { "nonexample.com", ".example.com, .example.net", FALSE},
+- { NULL, NULL, FALSE}
++ "0.0.1.127.0.0.1.127.0.0" /* 127 bytes "address" */, FALSE, FALSE},
++ { "localhost", "localhost,127.0.0.1", TRUE, FALSE},
++ { "localhost", "127.0.0.1,localhost", TRUE, FALSE},
++ { "foobar", "barfoo", FALSE, FALSE},
++ { "foobar", "foobar", TRUE, FALSE},
++ { "192.168.0.1", "foobar", FALSE, FALSE},
++ { "192.168.0.1", "192.168.0.0/16", TRUE, FALSE},
++ { "192.168.0.1", "192.168.0.0/24", TRUE, FALSE},
++ { "192.168.0.1", "192.168.0.0/32", FALSE, FALSE},
++ { "192.168.0.1", "192.168.0.0", FALSE, FALSE},
++ { "192.168.1.1", "192.168.0.0/24", FALSE, FALSE},
++ { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE, FALSE},
++ { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE, FALSE},
++ { "[::1]", "foo, bar, 192.168.0.0/16", FALSE, FALSE},
++ { "[::1]", "foo, bar, ::1/64", TRUE, FALSE},
++ { "bar", "foo, bar, ::1/64", TRUE, FALSE},
++ { "BAr", "foo, bar, ::1/64", TRUE, FALSE},
++ { "BAr", "foo,,,,, bar, ::1/64", TRUE, FALSE},
++ { "www.example.com", "foo, .example.com", TRUE, FALSE},
++ { "www.example.com", "www2.example.com, .example.net", FALSE, FALSE},
++ { "example.com", ".example.com, .example.net", TRUE, FALSE},
++ { "nonexample.com", ".example.com, .example.net", FALSE, FALSE},
++ { NULL, NULL, FALSE, FALSE}
+ };
+ for(i = 0; list4[i].a; i++) {
+ bool match = Curl_cidr4_match(list4[i].a, list4[i].n, list4[i].bits);
+--
+2.49.0
+
+From ca05e1afba7088c2f7e96ce47d2d3a249ce7a903 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Tue, 11 Apr 2023 16:24:29 +0200
+Subject: [PATCH] noproxy: pointer to local array 'hostip' is stored outside
+ scope
+
+Ref: #10929
+Closes #10933
+---
+ lib/noproxy.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index f1c1ed2c6..2b9908d89 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -122,6 +122,7 @@ enum nametype {
+ bool Curl_check_noproxy(const char *name, const char *no_proxy,
+ bool *spacesep)
+ {
++ char hostip[128];
+ *spacesep = FALSE;
+ /*
+ * If we don't have a hostname at all, like for example with a FILE
+@@ -139,7 +140,6 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy,
+ const char *p = no_proxy;
+ size_t namelen;
+ enum nametype type = TYPE_HOST;
+- char hostip[128];
+ if(!strcmp("*", no_proxy))
+ return TRUE;
+
+--
+2.49.0
+
+From e78913e6b5aaf36da6e5e0e68b2300d84ab85d15 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Sat, 1 Jun 2024 12:25:12 +0200
+Subject: [PATCH] noproxy: patterns need to be comma separated
+
+or they will not parse correctly.
+
+Mentioned in DEPRECATED since Janurary 2023 (in 7ad8a7ba9ebdedc).
+
+Closes #13789
+---
+ docs/DEPRECATE.md | 20 +---------
+ lib/noproxy.c | 13 +++---
+ lib/noproxy.h | 4 +-
+ lib/url.c | 7 +---
+ tests/unit/unit1614.c | 92 ++++++++++++++++++++-----------------------
+ 5 files changed, 50 insertions(+), 86 deletions(-)
+
+diff --git a/docs/DEPRECATE.md b/docs/DEPRECATE.md
+index 0e39903e1..073bc94e3 100644
+--- a/docs/DEPRECATE.md
++++ b/docs/DEPRECATE.md
+@@ -53,3 +34,4 @@ curl removes the support for space-separated names in July 2024.
+ - Pipelining
+ - axTLS
+ - PolarSSL
++ - space-separated `NOPROXY` patterns
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 62299e28f..b5aec75e7 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -119,11 +119,10 @@ enum nametype {
+ * Checks if the host is in the noproxy list. returns TRUE if it matches and
+ * therefore the proxy should NOT be used.
+ ****************************************************************/
+-bool Curl_check_noproxy(const char *name, const char *no_proxy,
+- bool *spacesep)
++bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ {
+ char hostip[128];
+- *spacesep = FALSE;
++
+ /*
+ * If we don't have a hostname at all, like for example with a FILE
+ * transfer, we have nothing to interrogate the noproxy list with.
+@@ -248,11 +247,9 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy,
+ /* pass blanks after pattern */
+ while(ISBLANK(*p))
+ p++;
+- /* if not a comma! */
+- if(*p && (*p != ',')) {
+- *spacesep = TRUE;
+- continue;
+- }
++ /* if not a comma, this ends the loop */
++ if(*p != ',')
++ break;
+ /* pass any number of commas */
+ while(*p == ',')
+ p++;
+diff --git a/lib/noproxy.h b/lib/noproxy.h
+index f4890bbf0..71ae7eaaf 100644
+--- a/lib/noproxy.h
++++ b/lib/noproxy.h
+@@ -37,9 +37,7 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
+ unsigned int bits);
+ #endif
+
+-bool Curl_check_noproxy(const char *name, const char *no_proxy,
+- bool *spacesep);
+-
++bool Curl_check_noproxy(const char *name, const char *no_proxy);
+ #endif
+
+ #endif /* HEADER_CURL_NOPROXY_H */
+diff --git a/lib/url.c b/lib/url.c
+index 7287d2d89..41e35e153 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -2374,7 +2374,6 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+ char *socksproxy = NULL;
+ char *no_proxy = NULL;
+ CURLcode result = CURLE_OK;
+- bool spacesep = FALSE;
+
+ /*************************************************************
+ * Extract the user and password from the authentication string
+@@ -2421,8 +2420,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+ }
+
+ if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
+- data->set.str[STRING_NOPROXY] : no_proxy,
+- &spacesep)) {
++ data->set.str[STRING_NOPROXY] : no_proxy)) {
+ Curl_safefree(proxy);
+ Curl_safefree(socksproxy);
+ }
+@@ -2431,9 +2429,6 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
+ /* if the host is not in the noproxy list, detect proxy. */
+ proxy = detect_proxy(data, conn);
+ #endif /* CURL_DISABLE_HTTP */
+- if(spacesep)
+- infof(data, "space-separated NOPROXY patterns are deprecated");
+-
+ Curl_safefree(no_proxy);
+
+ #ifdef USE_UNIX_SOCKETS
+diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c
+index ef03e3b4c..b516db249 100644
+--- a/tests/unit/unit1614.c
++++ b/tests/unit/unit1614.c
+@@ -46,7 +46,6 @@ struct noproxy {
+ const char *a;
+ const char *n;
+ bool match;
+- bool space; /* space separated */
+ };
+
+ UNITTEST_START
+@@ -78,52 +77,51 @@ UNITTEST_START
+ { NULL, NULL, 0, FALSE} /* end marker */
+ };
+ struct noproxy list[]= {
+- { "www.example.com", "localhost .example.com .example.de", TRUE, TRUE},
+- { "www.example.com", "localhost,.example.com,.example.de", TRUE, FALSE},
+- { "www.example.com.", "localhost,.example.com,.example.de", TRUE, FALSE},
+- { "example.com", "localhost,.example.com,.example.de", TRUE, FALSE},
+- { "example.com.", "localhost,.example.com,.example.de", TRUE, FALSE},
+- { "www.example.com", "localhost,.example.com.,.example.de", TRUE, FALSE},
+- { "www.example.com", "localhost,www.example.com.,.example.de",
+- TRUE, FALSE},
+- { "example.com", "localhost,example.com,.example.de", TRUE, FALSE},
+- { "example.com.", "localhost,example.com,.example.de", TRUE, FALSE},
+- { "nexample.com", "localhost,example.com,.example.de", FALSE, FALSE},
+- { "www.example.com", "localhost,example.com,.example.de", TRUE, FALSE},
+- { "127.0.0.1", "127.0.0.1,localhost", TRUE, FALSE},
+- { "127.0.0.1", "127.0.0.1,localhost,", TRUE, FALSE},
+- { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE, FALSE},
+- { "127.0.0.1", "127.0.0.1/28,localhost,", TRUE, FALSE},
+- { "127.0.0.1", "127.0.0.1/31,localhost,", TRUE, FALSE},
+- { "127.0.0.1", "localhost,127.0.0.1", TRUE, FALSE},
++ { "www.example.com", "localhost .example.com .example.de", FALSE},
++ { "www.example.com", "localhost,.example.com,.example.de", TRUE},
++ { "www.example.com.", "localhost,.example.com,.example.de", TRUE},
++ { "example.com", "localhost,.example.com,.example.de", TRUE},
++ { "example.com.", "localhost,.example.com,.example.de", TRUE},
++ { "www.example.com", "localhost,.example.com.,.example.de", TRUE},
++ { "www.example.com", "localhost,www.example.com.,.example.de", TRUE},
++ { "example.com", "localhost,example.com,.example.de", TRUE},
++ { "example.com.", "localhost,example.com,.example.de", TRUE},
++ { "nexample.com", "localhost,example.com,.example.de", FALSE},
++ { "www.example.com", "localhost,example.com,.example.de", TRUE},
++ { "127.0.0.1", "127.0.0.1,localhost", TRUE},
++ { "127.0.0.1", "127.0.0.1,localhost,", TRUE},
++ { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE},
++ { "127.0.0.1", "127.0.0.1/28,localhost,", TRUE},
++ { "127.0.0.1", "127.0.0.1/31,localhost,", TRUE},
++ { "127.0.0.1", "localhost,127.0.0.1", TRUE},
+ { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
+ "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
+- "0.0.1.127.0.0.1.127.0.0." /* 128 bytes "address" */, FALSE, FALSE},
++ "0.0.1.127.0.0.1.127.0.0." /* 128 bytes "address" */, FALSE},
+ { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
+ "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
+- "0.0.1.127.0.0.1.127.0.0" /* 127 bytes "address" */, FALSE, FALSE},
+- { "localhost", "localhost,127.0.0.1", TRUE, FALSE},
+- { "localhost", "127.0.0.1,localhost", TRUE, FALSE},
+- { "foobar", "barfoo", FALSE, FALSE},
+- { "foobar", "foobar", TRUE, FALSE},
+- { "192.168.0.1", "foobar", FALSE, FALSE},
+- { "192.168.0.1", "192.168.0.0/16", TRUE, FALSE},
+- { "192.168.0.1", "192.168.0.0/24", TRUE, FALSE},
+- { "192.168.0.1", "192.168.0.0/32", FALSE, FALSE},
+- { "192.168.0.1", "192.168.0.0", FALSE, FALSE},
+- { "192.168.1.1", "192.168.0.0/24", FALSE, FALSE},
+- { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE, FALSE},
+- { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE, FALSE},
+- { "[::1]", "foo, bar, 192.168.0.0/16", FALSE, FALSE},
+- { "[::1]", "foo, bar, ::1/64", TRUE, FALSE},
+- { "bar", "foo, bar, ::1/64", TRUE, FALSE},
+- { "BAr", "foo, bar, ::1/64", TRUE, FALSE},
+- { "BAr", "foo,,,,, bar, ::1/64", TRUE, FALSE},
+- { "www.example.com", "foo, .example.com", TRUE, FALSE},
+- { "www.example.com", "www2.example.com, .example.net", FALSE, FALSE},
+- { "example.com", ".example.com, .example.net", TRUE, FALSE},
+- { "nonexample.com", ".example.com, .example.net", FALSE, FALSE},
+- { NULL, NULL, FALSE, FALSE}
++ "0.0.1.127.0.0.1.127.0.0" /* 127 bytes "address" */, FALSE},
++ { "localhost", "localhost,127.0.0.1", TRUE},
++ { "localhost", "127.0.0.1,localhost", TRUE},
++ { "foobar", "barfoo", FALSE},
++ { "foobar", "foobar", TRUE},
++ { "192.168.0.1", "foobar", FALSE},
++ { "192.168.0.1", "192.168.0.0/16", TRUE},
++ { "192.168.0.1", "192.168.0.0/24", TRUE},
++ { "192.168.0.1", "192.168.0.0/32", FALSE},
++ { "192.168.0.1", "192.168.0.0", FALSE},
++ { "192.168.1.1", "192.168.0.0/24", FALSE},
++ { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE},
++ { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE},
++ { "[::1]", "foo, bar, 192.168.0.0/16", FALSE},
++ { "[::1]", "foo, bar, ::1/64", TRUE},
++ { "bar", "foo, bar, ::1/64", TRUE},
++ { "BAr", "foo, bar, ::1/64", TRUE},
++ { "BAr", "foo,,,,, bar, ::1/64", TRUE},
++ { "www.example.com", "foo, .example.com", TRUE},
++ { "www.example.com", "www2.example.com, .example.net", FALSE},
++ { "example.com", ".example.com, .example.net", TRUE},
++ { "nonexample.com", ".example.com, .example.net", FALSE},
++ { NULL, NULL, FALSE}
+ };
+ for(i = 0; list4[i].a; i++) {
+ bool match = Curl_cidr4_match(list4[i].a, list4[i].n, list4[i].bits);
+--
+2.49.0
+
+From 4e71f134e5aa3bd77ec645f12826e1823d06b398 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg
+Date: Thu, 6 Jun 2024 22:58:45 +0200
+Subject: [PATCH] noproxy: test bad ipv6 net size first
+
+No need to parse anything if the size is out of range.
+
+Added some tests to this effect to test 1614.
+
+Closes #13902
+---
+ lib/noproxy.c | 6 ++++--
+ tests/unit/unit1614.c | 4 ++++
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/lib/noproxy.c b/lib/noproxy.c
+index 7df40b8d7..f57a50b43 100644
+--- a/lib/noproxy.c
++++ b/lib/noproxy.c
+@@ -89,12 +89,12 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
+
+ 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 > 16) || ((bytes == 16) && rest))
+- return FALSE;
+ if(bytes && memcmp(address, check, bytes))
+ return FALSE;
+ if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest))))
+@@ -231,6 +231,8 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
+ slash = strchr(check, '/');
+ /* if the slash is part of this token, use it */
+ if(slash) {
++ /* if the bits variable gets a crazy value here, that is fine as
++ the value will then be rejected in the cidr function */
+ bits = atoi(slash + 1);
+ *slash = 0; /* null terminate there */
+ }
+diff --git a/tests/unit/unit1614.c b/tests/unit/unit1614.c
+index b516db249..fd6f5849c 100644
+--- a/tests/unit/unit1614.c
++++ b/tests/unit/unit1614.c
+@@ -110,10 +110,14 @@ UNITTEST_START
+ { "192.168.0.1", "192.168.0.0/32", FALSE},
+ { "192.168.0.1", "192.168.0.0", FALSE},
+ { "192.168.1.1", "192.168.0.0/24", FALSE},
++ { "192.168.1.1", "192.168.0.0/33", FALSE},
+ { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE},
+ { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE},
+ { "[::1]", "foo, bar, 192.168.0.0/16", FALSE},
+ { "[::1]", "foo, bar, ::1/64", TRUE},
++ { "[::1]", "::1/64", TRUE},
++ { "[::1]", "::1/96", TRUE},
++ { "[::1]", "::1/129", FALSE},
+ { "bar", "foo, bar, ::1/64", TRUE},
+ { "BAr", "foo, bar, ::1/64", TRUE},
+ { "BAr", "foo,,,,, bar, ::1/64", TRUE},
+--
+2.49.0
+
diff --git a/SPECS/curl.spec b/SPECS/curl.spec
index a8a96a6..f833bc0 100644
--- a/SPECS/curl.spec
+++ b/SPECS/curl.spec
@@ -1,7 +1,7 @@
Summary: A utility for getting files from remote servers (FTP, HTTP, and others)
Name: curl
Version: 7.76.1
-Release: 31%{?dist}
+Release: 34%{?dist}
License: MIT
Source: https://curl.se/download/%{name}-%{version}.tar.xz
@@ -116,6 +116,12 @@ Patch37: 0037-curl-7.76.1-ignore-unexpected-eof.patch
# provide common cleanup method for push headers (CVE-2024-2398)
Patch38: 0038-curl-7.76.1-CVE-2024-2398.patch
+# make sure pause is done on HTTP
+Patch39: 0039-curl-7.76.1-pause-on-http.patch
+
+# noproxy: support proxies specified using cidr notation
+Patch40: 0040-curl-7.76.1-noproxy-support-using-cidr.patch
+
# patch making libcurl multilib ready
Patch101: 0101-curl-7.32.0-multilib.patch
@@ -291,48 +297,50 @@ be installed.
%setup -q
# upstream patches
-%patch1 -p1
-%patch2 -p1
-%patch3 -p1
-%patch4 -p1
-%patch5 -p1
-%patch6 -p1
-%patch7 -p1
-%patch8 -p1
-%patch9 -p1
-%patch10 -p1
-%patch11 -p1
-%patch12 -p1
-%patch13 -p1
-%patch14 -p1
-%patch15 -p1
-%patch16 -p1
-%patch17 -p1
-%patch19 -p1
-%patch20 -p1
-%patch21 -p1
-%patch22 -p1
-%patch23 -p1
-%patch24 -p1
-%patch25 -p1
-%patch26 -p1
-%patch27 -p1
-%patch28 -p1
-%patch29 -p1
-%patch30 -p1
-%patch31 -p1
-%patch32 -p1
-%patch33 -p1
-%patch34 -p1
-%patch35 -p1
-%patch36 -p1
-%patch37 -p1
-%patch38 -p1
+%patch -P 1 -p1
+%patch -P 2 -p1
+%patch -P 3 -p1
+%patch -P 4 -p1
+%patch -P 5 -p1
+%patch -P 6 -p1
+%patch -P 7 -p1
+%patch -P 8 -p1
+%patch -P 9 -p1
+%patch -P 10 -p1
+%patch -P 11 -p1
+%patch -P 12 -p1
+%patch -P 13 -p1
+%patch -P 14 -p1
+%patch -P 15 -p1
+%patch -P 16 -p1
+%patch -P 17 -p1
+%patch -P 19 -p1
+%patch -P 20 -p1
+%patch -P 21 -p1
+%patch -P 22 -p1
+%patch -P 23 -p1
+%patch -P 24 -p1
+%patch -P 25 -p1
+%patch -P 26 -p1
+%patch -P 27 -p1
+%patch -P 28 -p1
+%patch -P 29 -p1
+%patch -P 30 -p1
+%patch -P 31 -p1
+%patch -P 32 -p1
+%patch -P 33 -p1
+%patch -P 34 -p1
+%patch -P 35 -p1
+%patch -P 36 -p1
+%patch -P 37 -p1
+%patch -P 38 -p1
+%patch -P 39 -p1
+%patch -P 40 -p1
# Fedora patches
-%patch101 -p1
-%patch102 -p1
-%patch105 -p1
+%patch -P 101 -p1
+%patch -P 102 -p1
+%patch -P 105 -p1
# disable test 1112 (#565305), test 1455 (occasionally fails with 'bind failed
# with errno 98: Address already in use' in Koji environment), and test 1801
@@ -359,39 +367,6 @@ printf "702\n703\n716\n" >> tests/data/DISABLED
printf "2034\n2037\n2041\n" >> tests/data/DISABLED
%endif
-# temporarily (really!, not like these above) disable tests related to openssl
-# and reported by valgrind. All of it are failing with similar stack trace:
-#=== Start of file valgrind3000
-# ==92709== Syscall param openat(filename) points to unaddressable byte(s)
-# ==92709== at 0x49D9784: open (open64.c:48)
-# ==92709== by 0x495E095: _IO_file_open (fileops.c:189)
-# ==92709== by 0x495E26A: _IO_file_fopen@@GLIBC_2.2.5 (fileops.c:281)
-# ==92709== by 0x49524CC: __fopen_internal (iofopen.c:75)
-# ==92709== by 0x4B37F2E: load_system_str (ssl_ciph.c:1472)
-# ==92709== by 0x4B43118: ssl_create_cipher_list (ssl_ciph.c:1528)
-# ==92709== by 0x4B4FCFF: UnknownInlinedFun (ssl_lib.c:3938)
-# ==92709== by 0x4B4FCFF: SSL_CTX_new_ex (ssl_lib.c:3823)
-# ==92709== by 0x48ABFA1: ossl_connect_step1.lto_priv.0 (openssl.c:2621)
-# ==92709== by 0x48BAF16: ossl_connect_common (openssl.c:4042)
-# ==92709== by 0x48B3D16: UnknownInlinedFun (vtls.c:370)
-# ==92709== by 0x48B3D16: Curl_ssl_connect_nonblocking (vtls.c:353)
-# ==92709== by 0x48873BB: UnknownInlinedFun (http.c:1595)
-# ==92709== by 0x48873BB: Curl_http_connect (http.c:1518)
-# ==92709== by 0x4895575: UnknownInlinedFun (multi.c:1514)
-# ==92709== by 0x4895575: multi_runsingle (multi.c:1847)
-# ==92709== by 0x48978AD: curl_multi_perform (multi.c:2403)
-# ==92709== by 0x4874152: UnknownInlinedFun (easy.c:606)
-# ==92709== by 0x4874152: UnknownInlinedFun (easy.c:696)
-# ==92709== by 0x4874152: curl_easy_perform (easy.c:715)
-# ==92709== by 0x11478B: UnknownInlinedFun (tool_operate.c:2379)
-# ==92709== by 0x11478B: UnknownInlinedFun (tool_operate.c:2553)
-# ==92709== by 0x11478B: UnknownInlinedFun (tool_operate.c:2669)
-# ==92709== by 0x11478B: main (tool_main.c:277)
-# ==92709== Address 0xffffffffff000804 is not stack'd, malloc'd or (recently) free'd
-# ==92709==
-#=== End of file valgrind3000
-printf "300\n301\n303\n304\n305\n306\n309\n310\n311\n312\n313\n320\n321\n322\n324\n325\n400\n401\n403\n404\n405\n406\n407\n408\n409\n410\n560\n1272\n1561\n1562\n1630\n1631\n1632\n2034\n2035\n2037\n2038\n2041\n2042\n2048\n3000\n3001\n" >> tests/data/DISABLED
-
# adapt test 323 for updated OpenSSL
sed -e 's|^35$|35,52|' -i tests/data/test323
@@ -586,6 +561,17 @@ rm -f ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la
%{_libdir}/libcurl.so.4.[0-9].[0-9].minimal
%changelog
+* Mon Jul 23 2025 Jacek Migacz - 7.76.1-34
+- revert several disabled tests related to openssl/valgrind (RHEL-99465)
+
+* Thu May 15 2025 Jacek Migacz - 7.76.1-33
+- noproxy: support proxies specified using cidr notation (RHEL-81412)
+
+* Tue Dec 17 2024 Jacek Migacz - 7.76.1-32
+- make up incomplete patch for host name wildcard checking (RHEL-5675)
+- eliminate use of obsolete patch syntax (RHEL-65791)
+- http2: make sure pause is done on HTTP (RHEL-85847)
+
* Thu Aug 22 2024 Jacek Migacz - 7.76.1-31
- provide common cleanup method for push headers (CVE-2024-2398)