From 1902e8fc511078fb5e26fc2b907b4cce77e1240d Mon Sep 17 00:00:00 2001 From: Dmitry Karpov Date: Mon, 19 Sep 2022 13:59:35 -0700 Subject: [PATCH] resolve: make forced IPv4 resolve only use A queries This protects IPv4-only transfers from undesired bad IPv6-related side effects and make IPv4 transfers in dual-stack libcurl behave the same way as in IPv4 single-stack libcurl. Closes #9540 --- lib/asyn-ares.c | 5 +++-- lib/asyn-thread.c | 2 +- lib/doh.c | 2 +- lib/hostip.c | 23 +++++++++++++++++++++++ lib/hostip6.c | 2 +- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index dff671b4de..1f3965541e 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -781,7 +781,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, #ifdef CURLRES_IPV6 if(Curl_ipv6works(data)) /* The stack seems to be IPv6-enabled */ - pf = PF_UNSPEC; + if(data->conn->ip_version != CURL_IPRESOLVE_V4) + pf = PF_UNSPEC; #endif /* CURLRES_IPV6 */ hints.ai_family = pf; hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)? @@ -794,7 +795,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, #else #ifdef HAVE_CARES_IPV6 - if(Curl_ipv6works(data)) { + if(Curl_ipv6works(data) && data->conn->ip_version != CURL_IPRESOLVE_V4) { /* The stack seems to be IPv6-enabled */ res->num_pending = 2; diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index 1ab1e977b5..68fddf0b22 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -707,7 +707,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, *waitp = 0; /* default to synchronous response */ #ifdef CURLRES_IPV6 - if(Curl_ipv6works(data)) + if(Curl_ipv6works(data) && data->conn->ip_version != CURL_IPRESOLVE_V4) /* The stack seems to be IPv6-enabled */ pf = PF_UNSPEC; #endif /* CURLRES_IPV6 */ diff --git a/lib/doh.c b/lib/doh.c index 087258d930..29399772b1 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -396,7 +396,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, goto error; dohp->pending++; - if(Curl_ipv6works(data)) { + if(Curl_ipv6works(data) && conn->ip_version != CURL_IPRESOLVE_V4) { /* create IPv6 DoH request */ result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6], DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH], diff --git a/lib/hostip.c b/lib/hostip.c index d08d4daec8..ec27602dc9 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -297,6 +297,29 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, } } + /* See if the returned entry matches the required resolve mode */ + if(dns && data->conn->ip_version != CURL_IPRESOLVE_WHATEVER) { + int pf = PF_INET; + bool found = false; + struct Curl_addrinfo *addr = dns->addr; + + if(data->conn->ip_version == CURL_IPRESOLVE_V6) + pf = PF_INET6; + + while(addr) { + if(addr->ai_family == pf) { + found = true; + break; + } + addr = addr->ai_next; + } + + if(!found) { + infof(data, "Hostname in DNS cache doesn't have needed family, zapped"); + dns = NULL; /* the memory deallocation is being handled by the hash */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); + } + } return dns; } diff --git a/lib/hostip6.c b/lib/hostip6.c index f1b36afb28..4e8e916ce7 100644 --- a/lib/hostip6.c +++ b/lib/hostip6.c @@ -117,7 +117,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, *waitp = 0; /* synchronous response only */ - if(Curl_ipv6works(data)) + if(Curl_ipv6works(data) && data->conn->ip_version != CURL_IPRESOLVE_V4) /* The stack seems to be IPv6-enabled */ pf = PF_UNSPEC;