From b2f459ac85713351d44ad9ac07f097bfccfebf64 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 30 Jul 2026 13:49:58 +0200 Subject: [PATCH] Curl_peer in resolve and dnscache operations Removes unused/duplicate members in async/ares/doh structs. --- lib/asyn-ares.c | 62 ++++------ lib/asyn-base.c | 3 +- lib/asyn-thrdd.c | 67 +++++------ lib/asyn.h | 7 +- lib/cf-dns.c | 37 ++---- lib/curl_addrinfo.c | 15 +++ lib/curl_addrinfo.h | 5 + lib/dnscache.c | 284 +++++++++++++++++++++++++------------------- lib/dnscache.h | 17 ++- lib/doh.c | 29 ++--- lib/doh.h | 2 - lib/hostip.c | 160 ++++++++++++------------- 12 files changed, 344 insertions(+), 344 deletions(-) diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 72bfda510a..827b9b5fce 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -217,7 +217,6 @@ void Curl_async_ares_destroy(struct Curl_easy *data, ares->res_AAAA = NULL; } #ifdef USE_HTTPSRR - curlx_safefree(ares->https_name); Curl_httpsrr_destroy(ares->hinfo); ares->hinfo = NULL; #endif @@ -277,7 +276,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data, if(CURL_DNSQ_IS_ADDR(async->dns_queries)) { dns = Curl_dnsc_mk_addr2(data, async->dns_queries, &ares->res_AAAA, &ares->res_A, - async->hostname, async->port); + async->peer); if(!dns) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -286,8 +285,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data, #ifdef HTTPSRR_WORKS if(!dns && (async->dns_queries & CURL_DNSQ_HTTPS)) { - dns = Curl_dnsc_mk_https(data, &ares->hinfo, - async->hostname, async->port); + dns = Curl_dnsc_mk_https(data, &ares->hinfo, async->peer); if(!dns) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -349,22 +347,6 @@ static timediff_t async_ares_poll_timeout(struct async_ares_ctx *ares, return 1000; } -static const struct Curl_addrinfo *async_ares_get_ai( - const struct Curl_addrinfo *ai, - int ai_family, - unsigned int index) -{ - unsigned int i = 0; - for(i = 0; ai; ai = ai->ai_next) { - if(ai->ai_family == ai_family) { - if(i == index) - return ai; - ++i; - } - } - return NULL; -} - const struct Curl_addrinfo *Curl_async_get_ai(struct Curl_easy *data, struct Curl_resolv_async *async, int ai_family, @@ -375,17 +357,14 @@ const struct Curl_addrinfo *Curl_async_get_ai(struct Curl_easy *data, (void)data; switch(ai_family) { case AF_INET: - if(ares->res_A) - return async_ares_get_ai(ares->res_A, ai_family, index); - break; + return Curl_addrinfo_get(ares->res_A, ai_family, index); +#ifdef USE_IPV6 case AF_INET6: - if(ares->res_AAAA) - return async_ares_get_ai(ares->res_AAAA, ai_family, index); - break; + return Curl_addrinfo_get(ares->res_AAAA, ai_family, index); +#endif default: - break; + return NULL; } - return NULL; } #ifdef USE_HTTPSRR @@ -664,7 +643,7 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, } #endif - curl_msnprintf(service, sizeof(service), "%d", async->port); + curl_msnprintf(service, sizeof(service), "%d", async->peer->port); socktype = (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM; @@ -674,12 +653,13 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, struct ares_addrinfo_hints hints; memset(&hints, 0, sizeof(hints)); - CURL_TRC_DNS(data, "[AAAA] ares: query records for %s", async->hostname); + CURL_TRC_DNS(data, "[AAAA] ares: query records for %s", + async->peer->hostname); hints.ai_family = PF_INET6; hints.ai_socktype = socktype; hints.ai_flags = ARES_AI_NUMERICSERV; async->queries_ongoing++; - ares_getaddrinfo(ares->channel, async->hostname, + ares_getaddrinfo(ares->channel, async->peer->hostname, service, &hints, async_ares_AAAA_cb, async); } #endif /* CURLRES_IPV6 */ @@ -688,31 +668,33 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, struct ares_addrinfo_hints hints; memset(&hints, 0, sizeof(hints)); - CURL_TRC_DNS(data, "[A] ares: query records for %s", async->hostname); + CURL_TRC_DNS(data, "[A] ares: query records for %s", + async->peer->hostname); hints.ai_family = PF_INET; hints.ai_socktype = socktype; hints.ai_flags = ARES_AI_NUMERICSERV; async->queries_ongoing++; - ares_getaddrinfo(ares->channel, async->hostname, + ares_getaddrinfo(ares->channel, async->peer->hostname, service, &hints, async_ares_A_cb, async); } #ifdef USE_HTTPSRR if(async->dns_queries & CURL_DNSQ_HTTPS) { - ares->https_name = NULL; - if(async->port != 443) { - ares->https_name = curl_maprintf("_%d._https.%s", - async->port, async->hostname); - if(!ares->https_name) + char *https_name = NULL; + if(async->peer->port != 443) { + https_name = curl_maprintf("_%u._https.%s", + async->peer->port, async->peer->hostname); + if(!https_name) return CURLE_OUT_OF_MEMORY; } CURL_TRC_DNS(data, "[HTTPS] ares: query records for %s", - ares->https_name ? ares->https_name : async->hostname); + https_name ? https_name : async->peer->hostname); async->queries_ongoing++; ares_query_dnsrec(ares->channel, - ares->https_name ? ares->https_name : async->hostname, + https_name ? https_name : async->peer->hostname, ARES_CLASS_IN, ARES_REC_TYPE_HTTPS, async_ares_rr_done, async, NULL); + curlx_free(https_name); } #endif /* USE_HTTPSRR */ diff --git a/lib/asyn-base.c b/lib/asyn-base.c index b140b0f5b9..ac1e32e830 100644 --- a/lib/asyn-base.c +++ b/lib/asyn-base.c @@ -238,6 +238,7 @@ void Curl_async_destroy(struct Curl_easy *data, #ifndef CURL_DISABLE_DOH Curl_doh_cleanup(data, async); #endif + Curl_peer_unlink(&async->peer); curlx_safefree(async); } } @@ -258,7 +259,7 @@ CURLcode Curl_async_failed(struct Curl_easy *data, if(async->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA)) failf(data, "Could not resolve %s: %s%s%s%s", - host_or_proxy, async->hostname, + host_or_proxy, async->peer->hostname, detail ? " (" : "", detail ? detail : "", detail ? ")" : ""); return result; } diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index 0941c08f5e..8eb2584476 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -216,41 +216,47 @@ static CURLcode async_rr_start(struct Curl_easy *data, struct Curl_resolv_async *async) { struct async_thrdd_ctx *thrdd = &async->thrdd; + char *https_name = NULL; int status; - char *rrname = NULL; + CURLcode result = CURLE_OK; DEBUGASSERT(!thrdd->rr.channel); - if(async->port != 443) { - rrname = curl_maprintf("_%d_.https.%s", async->port, async->hostname); - if(!rrname) - return CURLE_OUT_OF_MEMORY; + if(async->peer->port != 443) { + https_name = curl_maprintf("_%u_.https.%s", + async->peer->port, async->peer->hostname); + if(!https_name) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } } status = ares_init_options(&thrdd->rr.channel, NULL, 0); if(status != ARES_SUCCESS) { thrdd->rr.channel = NULL; - curlx_free(rrname); - return CURLE_FAILED_INIT; + result = CURLE_FAILED_INIT; + goto out; } #ifdef DEBUGBUILD if(getenv("CURL_DNS_SERVER")) { const char *servers = getenv("CURL_DNS_SERVER"); status = ares_set_servers_ports_csv(thrdd->rr.channel, servers); if(status) { - curlx_free(rrname); - return CURLE_FAILED_INIT; + result = CURLE_FAILED_INIT; + goto out; } } #endif - thrdd->rr.https_name = rrname; async->queries_ongoing++; ares_query_dnsrec(thrdd->rr.channel, - rrname ? rrname : async->hostname, ARES_CLASS_IN, - ARES_REC_TYPE_HTTPS, + https_name ? https_name : async->peer->hostname, + ARES_CLASS_IN, ARES_REC_TYPE_HTTPS, async_thrdd_rr_done, async, NULL); - CURL_TRC_DNS(data, "[HTTPS-RR] initiated request for %s", - rrname ? rrname : async->hostname); - return CURLE_OK; + CURL_TRC_DNS(data, "[HTTPS] query records for %s", + https_name ? https_name : async->peer->hostname); + +out: + curlx_free(https_name); + return result; } #endif @@ -290,7 +296,6 @@ void Curl_async_thrdd_destroy(struct Curl_easy *data, ares_destroy(async->thrdd.rr.channel); async->thrdd.rr.channel = NULL; } - curlx_safefree(async->thrdd.rr.https_name); Curl_httpsrr_destroy(async->thrdd.rr.hinfo); #endif async_thrdd_item_destroy(async->thrdd.inc_A); @@ -607,7 +612,7 @@ static CURLcode async_thrdd_query(struct Curl_easy *data, CURLcode result; item = async_thrdd_item_create(data, async->id, dns_queries, - async->hostname, async->port, + async->peer->hostname, async->peer->port, async->transport); if(!item) { result = CURLE_OUT_OF_MEMORY; @@ -676,7 +681,7 @@ out: if(result) CURL_TRC_DNS(data, "error queueing query %s:%d -> %d", - async->hostname, async->port, (int)result); + async->peer->hostname, async->peer->port, (int)result); return result; } @@ -892,7 +897,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data, data, async->dns_queries, thrdd->res_A ? &thrdd->res_A->res : NULL, thrdd->res_AAAA ? &thrdd->res_AAAA->res : NULL, - async->hostname, async->port); + async->peer); if(!dns) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -902,8 +907,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data, #ifdef USE_HTTPSRR_ARES if(!dns && thrdd->rr.channel) { Curl_httpsrr_trace(data, thrdd->rr.hinfo); - dns = Curl_dnsc_mk_https(data, &thrdd->rr.hinfo, - async->hostname, async->port); + dns = Curl_dnsc_mk_https(data, &thrdd->rr.hinfo, async->peer); if(!dns) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -928,26 +932,11 @@ out: (result != CURLE_COULDNT_RESOLVE_HOST) && (result != CURLE_COULDNT_RESOLVE_PROXY)) { CURL_TRC_DNS(data, "Error %d resolving %s:%d", - (int)result, async->hostname, async->port); + (int)result, async->peer->hostname, async->peer->port); } return result; } -static const struct Curl_addrinfo *async_thrdd_get_ai( - const struct Curl_addrinfo *ai, - int ai_family, unsigned int index) -{ - unsigned int i = 0; - for(i = 0; ai; ai = ai->ai_next) { - if(ai->ai_family == ai_family) { - if(i == index) - return ai; - ++i; - } - } - return NULL; -} - const struct Curl_addrinfo *Curl_async_get_ai(struct Curl_easy *data, struct Curl_resolv_async *async, int ai_family, @@ -959,12 +948,12 @@ const struct Curl_addrinfo *Curl_async_get_ai(struct Curl_easy *data, switch(ai_family) { case AF_INET: if(thrdd->res_A) - return async_thrdd_get_ai(thrdd->res_A->res, ai_family, index); + return Curl_addrinfo_get(thrdd->res_A->res, ai_family, index); break; #ifdef USE_IPV6 case AF_INET6: if(thrdd->res_AAAA) - return async_thrdd_get_ai(thrdd->res_AAAA->res, ai_family, index); + return Curl_addrinfo_get(thrdd->res_AAAA->res, ai_family, index); break; #endif default: diff --git a/lib/asyn.h b/lib/asyn.h index 43e1dc6463..75abd64073 100644 --- a/lib/asyn.h +++ b/lib/asyn.h @@ -118,9 +118,7 @@ struct async_ares_ctx { struct Curl_addrinfo *res_AAAA; int ares_status; /* ARES_SUCCESS, ARES_ENOTFOUND, etc. */ CURLcode result; /* CURLE_OK or error handling response */ - struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ #ifdef USE_HTTPSRR - char *https_name; struct Curl_https_rrinfo *hinfo; #endif BIT(transient_err); /* an A/AAAA query failed without the resolver @@ -147,7 +145,6 @@ struct async_thrdd_ctx { #if defined(USE_HTTPSRR) && defined(USE_ARES) struct { ares_channel channel; - char *https_name; struct Curl_https_rrinfo *hinfo; } rr; #endif @@ -232,6 +229,7 @@ CURLcode Curl_async_pollset(struct Curl_easy *data, struct Curl_resolv_async { struct Curl_resolv_async *next; + struct Curl_peer *peer; #ifdef USE_RESOLV_ARES struct async_ares_ctx ares; #elif defined(USE_RESOLV_THREADED) @@ -246,8 +244,6 @@ struct Curl_resolv_async { CURLcode result; uint32_t poll_interval; uint32_t id; /* unique id per easy handle of the resolve operation */ - /* what is being resolved */ - uint16_t port; uint8_t dns_queries; /* what queries are being performed */ uint8_t dns_responses; /* what queries had responses so far. */ uint8_t transport; @@ -261,7 +257,6 @@ struct Curl_resolv_async { exist. Only such failures may be cached as negative entries, not transient or local resolver failures. */ - char hostname[1]; }; timediff_t Curl_async_timeleft_ms(struct Curl_easy *data, diff --git a/lib/cf-dns.c b/lib/cf-dns.c index e3693e3acc..984d7a404d 100644 --- a/lib/cf-dns.c +++ b/lib/cf-dns.c @@ -567,30 +567,6 @@ CURLcode Curl_conn_dns_addr_result(struct connectdata *conn, return CURLE_FAILED_INIT; /* no one is resolving */ } -static const struct Curl_addrinfo *cf_dns_get_nth_ai( - struct Curl_cfilter *cf, - const struct Curl_addrinfo *ai, - int ai_family, unsigned int index) -{ - struct cf_dns_ctx *ctx = cf->ctx; - unsigned int i = 0; - - if((ai_family == AF_INET) && !(ctx->dns_queries & CURL_DNSQ_A)) - return NULL; -#ifdef USE_IPV6 - if((ai_family == AF_INET6) && !(ctx->dns_queries & CURL_DNSQ_AAAA)) - return NULL; -#endif - for(i = 0; ai; ai = ai->ai_next) { - if(ai->ai_family == ai_family) { - if(i == index) - return ai; - ++i; - } - } - return NULL; -} - /* Return the addrinfo at `index` for the given `family` from the * first "resolve" filter at the connection. If the DNS resolving is * not done yet or if no address for the family exists, returns NULL. @@ -613,8 +589,17 @@ const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data, index, peer->hostname, peer->port, ai_family, !!ctx->dns); if(ctx->resolv_result) return NULL; - else if(ctx->dns) - return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index); + else if(ctx->dns) { + /* A cached DNS entry may contain address families that we + * here never queried for. We want to give no results for those. */ + if((ai_family == AF_INET) && !(ctx->dns_queries & CURL_DNSQ_A)) + return NULL; +#ifdef USE_IPV6 + if((ai_family == AF_INET6) && !(ctx->dns_queries & CURL_DNSQ_AAAA)) + return NULL; +#endif + return Curl_addrinfo_get(ctx->dns->addr, ai_family, index); + } else return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index); } diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index ea818a38e5..98ba7aec1c 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -79,6 +79,21 @@ void Curl_freeaddrinfo(struct Curl_addrinfo *cahead) } } +struct Curl_addrinfo *Curl_addrinfo_get(struct Curl_addrinfo *ai, + int ai_family, + unsigned int n) +{ + unsigned int i; + for(i = 0; ai; ai = ai->ai_next) { + if(ai->ai_family == ai_family) { + if(i == n) + return ai; + ++i; + } + } + return NULL; +} + #ifdef HAVE_GETADDRINFO /* * Curl_getaddrinfo_ex() diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h index 046be23816..7b2b4d2834 100644 --- a/lib/curl_addrinfo.h +++ b/lib/curl_addrinfo.h @@ -62,6 +62,11 @@ struct Curl_addrinfo { void Curl_freeaddrinfo(struct Curl_addrinfo *cahead); +/* Get the n-th addrinfo of family ai_family. */ +struct Curl_addrinfo *Curl_addrinfo_get(struct Curl_addrinfo *ai, + int ai_family, + unsigned int n); + #ifdef HAVE_GETADDRINFO int Curl_getaddrinfo_ex(const char *nodename, const char *servname, diff --git a/lib/dnscache.c b/lib/dnscache.c index 73de3cacb3..44db67720b 100644 --- a/lib/dnscache.c +++ b/lib/dnscache.c @@ -60,6 +60,51 @@ #define MAX_DNS_CACHE_SIZE 29999 +struct dnsc_id { + struct Curl_str name; + uint16_t port; + char type; +}; + +static void dnsc_peer2id(struct dnsc_id *pid, char type, + struct Curl_peer *peer) +{ + curlx_str_assign(&pid->name, peer->hostname, strlen(peer->hostname)); + pid->port = peer->port; + pid->type = type; +} + +static void dnsc_str2id(struct dnsc_id *pid, char type, + struct Curl_str *name, uint16_t port) +{ + pid->name = *name; + pid->port = port; + pid->type = type; +} + +struct dnsc_key { + char data[MAX_HOSTCACHE_LEN]; + size_t len; +}; + +/* + * Create a hostcache id string for the provided host + port, to be used by + * the DNS caching. Without alloc. Return length of the id string. + */ +static void dnsc_id2key(struct dnsc_key *key, struct dnsc_id *id) +{ + size_t namelen = curlx_strlen(&id->name); + if(namelen > (sizeof(key->data) - 8)) + namelen = sizeof(key->data) - 8; + /* store and lower case the name */ + key->data[0] = id->type; + Curl_strntolower(key->data + 1, curlx_str(&id->name), namelen); + /* include the terminating 0 in key length */ + key->len = namelen + 2 + + curl_msnprintf(&key->data[namelen + 1], 7, ":%u", id->port); +} + + static void dnscache_entry_free(struct Curl_dns_entry *dns) { Curl_freeaddrinfo(dns->addr); @@ -69,25 +114,6 @@ static void dnscache_entry_free(struct Curl_dns_entry *dns) curlx_free(dns); } -/* - * Create a hostcache id string for the provided host + port, to be used by - * the DNS caching. Without alloc. Return length of the id string. - */ -static size_t create_dnscache_id(char type, const char *name, - size_t nlen, /* 0 or actual name length */ - uint16_t port, - char *buf, size_t buflen) -{ - size_t len = nlen ? nlen : strlen(name); - DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN); - if(len > (buflen - 8)) - len = buflen - 8; - /* store and lower case the name */ - buf[0] = type; - Curl_strntolower(buf + 1, name, len); - return curl_msnprintf(&buf[len + 1], 7, ":%u", port) + len + 1; -} - struct dnscache_prune_data { struct curltime now; timediff_t oldest_ms; /* oldest time in cache not pruned. */ @@ -211,35 +237,36 @@ void Curl_dnscache_clear(struct Curl_easy *data) static CURLcode fetch_addr(struct Curl_easy *data, struct Curl_dnscache *dnscache, uint8_t dns_queries, - const char *hostname, - uint16_t port, + struct Curl_peer *peer, struct Curl_dns_entry **pdns) { struct Curl_dns_entry *dns = NULL; - char entry_id[MAX_HOSTCACHE_LEN]; - size_t entry_len; - char entry_type = CURL_DNSQ_IS_ADDR(dns_queries) ? - CURL_DNST_ADDR : CURL_DNST_HTTPS; + struct dnsc_id id; + struct dnsc_key key; + char type = CURL_DNSQ_IS_ADDR(dns_queries) ? + CURL_DNST_ADDR : CURL_DNST_HTTPS; CURLcode result = CURLE_OK; *pdns = NULL; if(!dnscache) return CURLE_OK; - /* Create an entry id, based upon the hostname and port */ - entry_len = create_dnscache_id(entry_type, hostname, 0, port, - entry_id, sizeof(entry_id)); + dnsc_peer2id(&id, type, peer); + dnsc_id2key(&key, &id); /* See if it is already in our dns cache */ - dns = Curl_hash_pick(&dnscache->entries, entry_id, entry_len + 1); + dns = Curl_hash_pick(&dnscache->entries, key.data, key.len); /* No entry found in cache, check if we might have a wildcard entry */ - if(!dns && data->state.wildcard_resolve && CURL_DNSQ_IS_ADDR(dns_queries)) { - entry_len = create_dnscache_id(CURL_DNST_ADDR, "*", 1, port, - entry_id, sizeof(entry_id)); + if(!dns && (type == CURL_DNST_ADDR) && data->state.wildcard_resolve) { + struct Curl_str wildname; + + curlx_str_assign(&wildname, "*", 1); + dnsc_str2id(&id, CURL_DNST_ADDR, &wildname, peer->port); + dnsc_id2key(&key, &id); /* See if it is already in our dns cache */ - dns = Curl_hash_pick(&dnscache->entries, entry_id, entry_len + 1); + dns = Curl_hash_pick(&dnscache->entries, key.data, key.len); } if(dns && (data->set.dns_cache_timeout_ms != -1)) { @@ -253,7 +280,7 @@ static CURLcode fetch_addr(struct Curl_easy *data, if(dnscache_entry_is_stale(&user, dns)) { infof(data, "Hostname in DNS cache was stale, zapped"); dns = NULL; /* the memory deallocation is being handled by the hash */ - Curl_hash_delete(&dnscache->entries, entry_id, entry_len + 1); + Curl_hash_delete(&dnscache->entries, key.data, key.len); } } @@ -297,8 +324,7 @@ static CURLcode fetch_addr(struct Curl_easy *data, */ CURLcode Curl_dnscache_get(struct Curl_easy *data, uint8_t dns_queries, - const char *hostname, - uint16_t port, + struct Curl_peer *peer, struct Curl_dns_entry **pentry) { struct Curl_dnscache *dnscache = dnscache_get(data); @@ -306,7 +332,7 @@ CURLcode Curl_dnscache_get(struct Curl_easy *data, CURLcode result = CURLE_OK; dnscache_lock(data, dnscache); - result = fetch_addr(data, dnscache, dns_queries, hostname, port, &dns); + result = fetch_addr(data, dnscache, dns_queries, peer, &dns); if(!result && dns) dns->refcount++; /* we pass out a reference */ else if(result) { @@ -316,7 +342,7 @@ CURLcode Curl_dnscache_get(struct Curl_easy *data, dnscache_unlock(data, dnscache); CURL_TRC_DNS(data, "cache lookup %s:%u queries=%s -> %d %sfound", - hostname, port, Curl_resolv_query_str(dns_queries), + peer->hostname, peer->port, Curl_resolv_query_str(dns_queries), (int)result, dns ? "" : "not "); *pentry = dns; return result; @@ -414,24 +440,23 @@ static bool dnscache_ai_has_family(struct Curl_addrinfo *ai, return FALSE; } -static struct Curl_dns_entry *dnsc_entry_create( - struct Curl_easy *data, - const char *hostname, - size_t hostlen, - uint16_t port, - bool permanent) +static struct Curl_dns_entry *dnsc_entry_create(struct Curl_easy *data, + struct dnsc_id *pid, + bool permanent) { struct Curl_dns_entry *dns = NULL; /* Create a new cache entry, struct already has the hostname NUL */ - dns = curlx_calloc(1, sizeof(struct Curl_dns_entry) + hostlen); + dns = curlx_calloc(1, sizeof(struct Curl_dns_entry) + + curlx_strlen(&pid->name)); if(!dns) goto out; dns->refcount = 1; /* the cache has the first reference */ - dns->port = port; - if(hostlen) - memcpy(dns->hostname, hostname, hostlen); + dns->hostlen = curlx_strlen(&pid->name); + dns->port = pid->port; + if(dns->hostlen) + memcpy(dns->hostname, curlx_str(&pid->name), dns->hostlen); if(permanent) { dns->timestamp.tv_sec = 0; /* an entry that never goes stale */ @@ -515,26 +540,30 @@ out: } struct Curl_dns_entry *Curl_dnsc_mk_addr(struct Curl_easy *data, - uint8_t dns_queries, - struct Curl_addrinfo **paddr, - const char *hostname, - uint16_t port) + uint8_t dns_queries, + struct Curl_addrinfo **paddr, + struct Curl_peer *peer) { - struct Curl_dns_entry *dns = dnsc_entry_create( - data, hostname, hostname ? strlen(hostname) : 0, port, FALSE); + struct dnsc_id id; + struct Curl_dns_entry *dns; + + dnsc_peer2id(&id, CURL_DNST_ADDR, peer); + dns = dnsc_entry_create(data, &id, FALSE); dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL); return dns; } struct Curl_dns_entry *Curl_dnsc_mk_addr2(struct Curl_easy *data, - uint8_t dns_queries, - struct Curl_addrinfo **paddr1, - struct Curl_addrinfo **paddr2, - const char *hostname, - uint16_t port) + uint8_t dns_queries, + struct Curl_addrinfo **paddr1, + struct Curl_addrinfo **paddr2, + struct Curl_peer *peer) { - struct Curl_dns_entry *dns = dnsc_entry_create( - data, hostname, hostname ? strlen(hostname) : 0, port, FALSE); + struct dnsc_id id; + struct Curl_dns_entry *dns; + + dnsc_peer2id(&id, CURL_DNST_ADDR, peer); + dns = dnsc_entry_create(data, &id, FALSE); dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr1, paddr2); return dns; } @@ -570,11 +599,13 @@ out: struct Curl_dns_entry *Curl_dnsc_mk_https(struct Curl_easy *data, struct Curl_https_rrinfo **phinfo, - const char *hostname, - uint16_t port) + struct Curl_peer *peer) { - struct Curl_dns_entry *dns = dnsc_entry_create( - data, hostname, hostname ? strlen(hostname) : 0, port, FALSE); + struct dnsc_id id; + struct Curl_dns_entry *dns; + + dnsc_peer2id(&id, CURL_DNST_HTTPS, peer); + dns = dnsc_entry_create(data, &id, FALSE); dns = dnsc_entry_assign_https(dns, phinfo); return dns; } @@ -582,28 +613,20 @@ struct Curl_dns_entry *Curl_dnsc_mk_https(struct Curl_easy *data, static struct Curl_dns_entry *dnsc_add_https(struct Curl_easy *data, struct Curl_dnscache *dnscache, struct Curl_https_rrinfo **phinfo, - const char *hostname, - size_t hlen, - uint16_t port, + struct dnsc_id *id, bool permanent) { - char entry_id[MAX_HOSTCACHE_LEN]; - size_t entry_len; struct Curl_dns_entry *dns, *dns2; + struct dnsc_key key; - dns = dnsc_entry_create(data, hostname, hostname ? strlen(hostname) : 0, - port, permanent); + dns = dnsc_entry_create(data, id, permanent); dns = dnsc_entry_assign_https(dns, phinfo); if(!dns) return NULL; - /* Create an entry id, based upon the hostname and port */ - entry_len = create_dnscache_id(CURL_DNST_HTTPS, hostname, hlen, port, - entry_id, sizeof(entry_id)); - /* Store the resolved data in our DNS cache. */ - dns2 = Curl_hash_add(&dnscache->entries, entry_id, entry_len + 1, - (void *)dns); + dnsc_id2key(&key, id); + dns2 = Curl_hash_add(&dnscache->entries, key.data, key.len, (void *)dns); if(!dns2) { dnscache_entry_free(dns); return NULL; @@ -620,28 +643,51 @@ static struct Curl_dns_entry *dnsc_add_addr(struct Curl_easy *data, struct Curl_dnscache *dnscache, uint8_t dns_queries, struct Curl_addrinfo **paddr, - const char *hostname, - size_t hlen, - uint16_t port, + struct dnsc_id *id, + struct dnsc_key *key, bool permanent) { - char entry_id[MAX_HOSTCACHE_LEN]; - size_t entry_len; struct Curl_dns_entry *dns; struct Curl_dns_entry *dns2; - dns = dnsc_entry_create(data, hostname, hlen, port, permanent); + dns = dnsc_entry_create(data, id, permanent); + dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL); + if(!dns) + return NULL; + + /* Store the resolved data in our DNS cache. */ + dns2 = Curl_hash_add(&dnscache->entries, key->data, key->len, (void *)dns); + if(!dns2) { + dnscache_entry_free(dns); + return NULL; + } + + dns = dns2; + dns->refcount++; /* mark entry as in-use */ + return dns; +} + +static struct Curl_dns_entry * +dnsc_add_peer_addr(struct Curl_easy *data, + struct Curl_dnscache *dnscache, + uint8_t dns_queries, + struct Curl_addrinfo **paddr, + struct dnsc_id *id, + bool permanent) +{ + struct Curl_dns_entry *dns; + struct Curl_dns_entry *dns2; + struct dnsc_key key; + + dns = dnsc_entry_create(data, id, permanent); dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL); if(!dns) return NULL; - /* Create an entry id, based upon the hostname and port */ - entry_len = create_dnscache_id(CURL_DNST_ADDR, hostname, hlen, port, - entry_id, sizeof(entry_id)); /* Store the resolved data in our DNS cache. */ - dns2 = Curl_hash_add(&dnscache->entries, entry_id, entry_len + 1, - (void *)dns); + dnsc_id2key(&key, id); + dns2 = Curl_hash_add(&dnscache->entries, key.data, key.len, (void *)dns); if(!dns2) { dnscache_entry_free(dns); return NULL; @@ -656,21 +702,22 @@ CURLcode Curl_dnscache_add(struct Curl_easy *data, struct Curl_dns_entry *entry) { struct Curl_dnscache *dnscache = dnscache_get(data); - char id[MAX_HOSTCACHE_LEN]; - size_t idlen; + struct Curl_str name; + struct dnsc_id id; + struct dnsc_key key; if(!dnscache) return CURLE_FAILED_INIT; if(!entry || (entry->type == CURL_DNST_INIT)) return CURLE_BAD_FUNCTION_ARGUMENT; - /* Create an entry id, based upon the hostname and port */ - idlen = create_dnscache_id(entry->type, entry->hostname, 0, entry->port, - id, sizeof(id)); + curlx_str_assign(&name, entry->hostname, entry->hostlen); + dnsc_str2id(&id, entry->type, &name, entry->port); + dnsc_id2key(&key, &id); /* Store the resolved data in our DNS cache and up ref count */ dnscache_lock(data, dnscache); - if(!Curl_hash_add(&dnscache->entries, id, idlen + 1, (void *)entry)) { + if(!Curl_hash_add(&dnscache->entries, key.data, key.len, (void *)entry)) { dnscache_unlock(data, dnscache); return CURLE_OUT_OF_MEMORY; } @@ -684,11 +731,11 @@ CURLcode Curl_dnscache_add(struct Curl_easy *data, CURLcode Curl_dnscache_add_negative(struct Curl_easy *data, uint8_t dns_queries, - const char *host, - uint16_t port) + struct Curl_peer *peer) { struct Curl_dnscache *dnscache = dnscache_get(data); struct Curl_dns_entry *dns = NULL; + struct dnsc_id id; CURLcode result = CURLE_OK; DEBUGASSERT(dnscache); @@ -699,15 +746,15 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data, if(dns_queries & CURL_DNSQ_ADDR) { /* put this new host in the cache */ - dns = dnsc_add_addr(data, dnscache, dns_queries, NULL, - host, strlen(host), port, FALSE); + dnsc_peer2id(&id, CURL_DNST_ADDR, peer); + dns = dnsc_add_peer_addr(data, dnscache, dns_queries, NULL, &id, FALSE); if(!dns) result = CURLE_OUT_OF_MEMORY; } #ifdef USE_HTTPSRR else if(dns_queries == CURL_DNSQ_HTTPS) { - dns = dnsc_add_https(data, dnscache, NULL, - host, strlen(host), port, FALSE); + dnsc_peer2id(&id, CURL_DNST_HTTPS, peer); + dns = dnsc_add_https(data, dnscache, NULL, &id, FALSE); if(!dns) result = CURLE_OUT_OF_MEMORY; } @@ -722,7 +769,8 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data, * entry alive: */ dns->refcount--; CURL_TRC_DNS(data, "cache negative name resolve for %s:%d type=%s", - host, port, Curl_resolv_query_str(dns_queries)); + peer->hostname, peer->port, + Curl_resolv_query_str(dns_queries)); } dnscache_unlock(data, dnscache); return result; @@ -777,6 +825,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) { struct Curl_dnscache *dnscache = dnscache_get(data); struct curl_slist *hostp; + struct dnsc_id id; + struct dnsc_key key; if(!dnscache) return CURLE_FAILED_INIT; @@ -785,14 +835,12 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) data->state.wildcard_resolve = FALSE; for(hostp = data->state.resolve; hostp; hostp = hostp->next) { - char entry_id[MAX_HOSTCACHE_LEN]; const char *host = hostp->data; struct Curl_str source; if(!host) continue; if(*host == '-') { curl_off_t num = 0; - size_t entry_len; host++; if(!curlx_str_single(&host, '[')) { if(curlx_str_until(&host, &source, MAX_IPADR_LEN, ']') || @@ -809,19 +857,17 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) if(!curlx_str_number(&host, &num, 0xffff)) { /* Create an entry id, based upon the hostname and port */ - entry_len = create_dnscache_id(CURL_DNST_ADDR, curlx_str(&source), - curlx_strlen(&source), (uint16_t)num, - entry_id, sizeof(entry_id)); + dnsc_str2id(&id, CURL_DNST_ADDR, &source, (uint16_t)num); + dnsc_id2key(&key, &id); dnscache_lock(data, dnscache); /* delete entry, ignore if it did not exist */ - Curl_hash_delete(&dnscache->entries, entry_id, entry_len + 1); + Curl_hash_delete(&dnscache->entries, key.data, key.len); dnscache_unlock(data, dnscache); } } else { struct Curl_dns_entry *dns; struct Curl_addrinfo *head = NULL, *tail = NULL; - size_t entry_len; char address[64]; curl_off_t tmpofft = 0; uint16_t port = 0; @@ -913,15 +959,12 @@ err: return CURLE_SETOPT_OPTION_SYNTAX; } - /* Create an entry id, based upon the hostname and port */ - entry_len = create_dnscache_id(CURL_DNST_ADDR, - curlx_str(&source), curlx_strlen(&source), - port, entry_id, sizeof(entry_id)); - + dnsc_str2id(&id, CURL_DNST_ADDR, &source, port); + dnsc_id2key(&key, &id); dnscache_lock(data, dnscache); /* See if it is already in our dns cache */ - dns = Curl_hash_pick(&dnscache->entries, entry_id, entry_len + 1); + dns = Curl_hash_pick(&dnscache->entries, key.data, key.len); if(dns) { infof(data, "RESOLVE %.*s:%u - old addresses discarded", @@ -938,13 +981,12 @@ err: 4. when adding a non-permanent entry, we want it to get a "fresh" timeout that starts _now_. */ - Curl_hash_delete(&dnscache->entries, entry_id, entry_len + 1); + Curl_hash_delete(&dnscache->entries, key.data, key.len); } /* put this new host in the cache, override all address queries */ - dns = dnsc_add_addr(data, dnscache, CURL_DNSQ_ADDR, - &head, curlx_str(&source), - curlx_strlen(&source), port, permanent); + dns = dnsc_add_addr(data, dnscache, CURL_DNSQ_ADDR, &head, + &id, &key, permanent); if(dns) /* release the returned reference; the cache itself will keep the * entry alive: */ @@ -956,8 +998,8 @@ err: return CURLE_OUT_OF_MEMORY; infof(data, "[DNS] added %.*s:%u:%s to cache%s", - (int)curlx_strlen(&source), curlx_str(&source), port, addresses, - permanent ? "" : " (non-permanent)"); + (int)curlx_strlen(&id.name), curlx_str(&id.name), id.port, + addresses, permanent ? "" : " (non-permanent)"); /* Wildcard hostname */ if(curlx_str_casecompare(&source, "*")) { diff --git a/lib/dnscache.h b/lib/dnscache.h index c029eb9d30..1b9518b3bf 100644 --- a/lib/dnscache.h +++ b/lib/dnscache.h @@ -35,6 +35,7 @@ struct connectdata; struct easy_pollset; struct Curl_https_rrinfo; struct Curl_multi; +struct Curl_peer; #define CURL_DNST_INIT '\0' #define CURL_DNST_ADDR 'A' @@ -47,6 +48,7 @@ struct Curl_dns_entry { #endif /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */ struct curltime timestamp; + size_t hostlen; /* reference counter, entry is freed on reaching 0 */ uint32_t refcount; /* hostname port number that resolved to addr. */ @@ -70,21 +72,18 @@ struct Curl_dns_entry { struct Curl_dns_entry *Curl_dnsc_mk_addr(struct Curl_easy *data, uint8_t dns_queries, struct Curl_addrinfo **paddr, - const char *hostname, - uint16_t port); + struct Curl_peer *peer); struct Curl_dns_entry *Curl_dnsc_mk_addr2(struct Curl_easy *data, uint8_t dns_queries, struct Curl_addrinfo **paddr1, struct Curl_addrinfo **paddr2, - const char *hostname, - uint16_t port); + struct Curl_peer *peer); #ifdef USE_HTTPSRR struct Curl_dns_entry *Curl_dnsc_mk_https(struct Curl_easy *data, struct Curl_https_rrinfo **phinfo, - const char *hostname, - uint16_t port); + struct Curl_peer *peer); #endif /* USE_HTTPSRR */ /* unlink a dns entry, frees all resources if it was the last reference. @@ -119,8 +118,7 @@ void Curl_dnscache_clear(struct Curl_easy *data); */ CURLcode Curl_dnscache_get(struct Curl_easy *data, uint8_t dns_queries, - const char *hostname, - uint16_t port, + struct Curl_peer *peer, struct Curl_dns_entry **pentry); /* @@ -134,8 +132,7 @@ CURLcode Curl_dnscache_add(struct Curl_easy *data, * it could not be resolved. */ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data, uint8_t dns_queries, - const char *host, - uint16_t port); + struct Curl_peer *peer); /* * Populate the cache with specified entries from CURLOPT_RESOLVE. diff --git a/lib/doh.c b/lib/doh.c index 6d39f6ff0e..a6ac8bde72 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -463,7 +463,7 @@ CURLcode Curl_doh(struct Curl_easy *data, size_t i; DEBUGASSERT(!async->doh); - DEBUGASSERT(async->hostname[0]); + DEBUGASSERT(async->peer->hostname[0]); if(async->doh) { DEBUGASSERT(0); /* should not happen */ Curl_doh_cleanup(data, async); @@ -479,13 +479,10 @@ CURLcode Curl_doh(struct Curl_easy *data, curlx_dyn_init(&dohp->probe_resp[i].body, DYN_DOH_RESPONSE); } - dohp->host = async->hostname; - dohp->port = async->port; - /* create IPv4 DoH request */ if(async->dns_queries & CURL_DNSQ_A) { result = doh_probe_run(data, CURL_DNS_TYPE_A, - async->hostname, data->set.str[STRING_DOH], + async->peer->hostname, data->set.str[STRING_DOH], data->multi, async->id, &dohp->probe_resp[DOH_SLOT_IPV4].probe_mid); if(result) @@ -497,7 +494,7 @@ CURLcode Curl_doh(struct Curl_easy *data, if(async->dns_queries & CURL_DNSQ_AAAA) { /* create IPv6 DoH request */ result = doh_probe_run(data, CURL_DNS_TYPE_AAAA, - async->hostname, data->set.str[STRING_DOH], + async->peer->hostname, data->set.str[STRING_DOH], data->multi, async->id, &dohp->probe_resp[DOH_SLOT_IPV6].probe_mid); if(result) @@ -509,13 +506,14 @@ CURLcode Curl_doh(struct Curl_easy *data, #ifdef USE_HTTPSRR if(async->dns_queries & CURL_DNSQ_HTTPS) { char *qname = NULL; - if(async->port != PORT_HTTPS) { - qname = curl_maprintf("_%d._https.%s", async->port, async->hostname); + if(async->peer->port != PORT_HTTPS) { + qname = curl_maprintf("_%d._https.%s", + async->peer->port, async->peer->hostname); if(!qname) goto error; } result = doh_probe_run(data, CURL_DNS_TYPE_HTTPS, - qname ? qname : async->hostname, + qname ? qname : async->peer->hostname, data->set.str[STRING_DOH], data->multi, async->id, &dohp->probe_resp[DOH_SLOT_HTTPS_RR].probe_mid); @@ -1209,7 +1207,7 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data, if(CURL_DNSQ_IS_ADDR(async->dns_queries) && dohp->probe_resp[DOH_SLOT_IPV4].probe_mid == UINT32_MAX && dohp->probe_resp[DOH_SLOT_IPV6].probe_mid == UINT32_MAX) { - failf(data, "Could not DoH-resolve: %s", dohp->host); + failf(data, "Could not DoH-resolve: %s", async->peer->hostname); return async->for_proxy ? CURLE_COULDNT_RESOLVE_PROXY : CURLE_COULDNT_RESOLVE_HOST; } @@ -1240,7 +1238,7 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data, CURL_TRC_DNS(data, "[%s] [DoH] error: %s type %s for %s", Curl_resolv_query_str(async->dns_queries), doh_strerror(rc[slot]), - doh_type2name(p->dnstype), dohp->host); + doh_type2name(p->dnstype), async->peer->hostname); } } /* next slot */ @@ -1250,11 +1248,11 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data, struct Curl_addrinfo *ai; if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_doh)) { - CURL_TRC_DNS(data, "hostname: %s", dohp->host); + CURL_TRC_DNS(data, "hostname: %s", async->peer->hostname); doh_show(data, &de); } - result = doh2ai(&de, dohp->host, dohp->port, &ai); + result = doh2ai(&de, async->peer->hostname, async->peer->port, &ai); if(result) { /* a decoded response without any usable address, e.g. only CNAME records, is an authoritative "no data" answer */ @@ -1264,8 +1262,7 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data, } /* we got a response, create a dns entry. */ - dns = Curl_dnsc_mk_addr(data, async->dns_queries, - &ai, dohp->host, dohp->port); + dns = Curl_dnsc_mk_addr(data, async->dns_queries, &ai, async->peer); if(!dns) { result = CURLE_OUT_OF_MEMORY; goto error; @@ -1297,7 +1294,7 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data, infof(data, "Some HTTPS RR to process"); } Curl_httpsrr_trace(data, hrr); - dns = Curl_dnsc_mk_https(data, &hrr, async->hostname, async->port); + dns = Curl_dnsc_mk_https(data, &hrr, async->peer); if(!dns) { result = CURLE_OUT_OF_MEMORY; goto error; diff --git a/lib/doh.h b/lib/doh.h index f4ecec0881..5179c28cae 100644 --- a/lib/doh.h +++ b/lib/doh.h @@ -110,8 +110,6 @@ struct doh_response { struct doh_probes { struct doh_response probe_resp[DOH_SLOT_COUNT]; unsigned int pending; /* still outstanding probes */ - uint16_t port; - const char *host; }; /* diff --git a/lib/hostip.c b/lib/hostip.c index 7427f8fdd9..9befeff2f8 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -342,11 +342,11 @@ static bool tailmatch(const char *full, size_t flen, } static CURLcode hostip_resolv_failed(struct Curl_easy *data, - const char *hostname, + struct Curl_peer *peer, bool for_proxy) { failf(data, "Could not resolve %s: %s", - for_proxy ? "proxy" : "host", hostname); + for_proxy ? "proxy" : "host", peer->hostname); return RESOLV_FAIL(for_proxy); } @@ -383,14 +383,12 @@ CURLcode Curl_resolv_announce_start(struct Curl_easy *data, static struct Curl_resolv_async *hostip_async_new(struct Curl_easy *data, uint8_t dns_queries, - const char *hostname, - uint16_t port, + struct Curl_peer *peer, uint8_t transport, bool for_proxy, timediff_t timeout_ms) { struct Curl_resolv_async *async; - size_t hostlen = strlen(hostname); if(!data->multi) { DEBUGASSERT(0); @@ -398,7 +396,7 @@ static struct Curl_resolv_async *hostip_async_new(struct Curl_easy *data, } /* struct size already includes the NUL for hostname */ - async = curlx_calloc(1, sizeof(*async) + hostlen); + async = curlx_calloc(1, sizeof(*async)); if(!async) return NULL; @@ -412,18 +410,15 @@ static struct Curl_resolv_async *hostip_async_new(struct Curl_easy *data, else data->multi->last_resolv_id++; async->id = data->multi->last_resolv_id; + Curl_peer_link(&async->peer, peer); async->dns_queries = dns_queries; - async->port = port; async->transport = transport; async->for_proxy = for_proxy; async->start = *Curl_pgrs_now(data); async->timeout_ms = timeout_ms; - if(hostlen) { - memcpy(async->hostname, hostname, hostlen); - async->is_ipaddr = Curl_is_ipaddr(async->hostname); - if(async->is_ipaddr) - async->is_ipv4addr = Curl_is_ipv4addr(async->hostname); - } + async->is_ipaddr = Curl_is_ipaddr(peer->hostname); + if(async->is_ipaddr) + async->is_ipv4addr = Curl_is_ipv4addr(peer->hostname); return async; } @@ -450,7 +445,8 @@ static CURLcode hostip_resolv_take_result(struct Curl_easy *data, "ongoing=%d for %s:%d", Curl_resolv_query_str(async->dns_queries), Curl_resolv_query_str(async->dns_responses), - async->queries_ongoing, async->hostname, async->port); + async->queries_ongoing, + async->peer->hostname, async->peer->port); result = CURLE_OK; } else if(IS_RESOLV_FAIL(result)) { @@ -461,12 +457,12 @@ static CURLcode hostip_resolv_take_result(struct Curl_easy *data, is so it does not get treated as one. */ CURL_TRC_DNS(data, "[%s] resolve error %d for %s:%u", Curl_resolv_query_str(async->dns_queries), - (int)result, async->hostname, async->port); + (int)result, async->peer->hostname, async->peer->port); } else { CURL_TRC_DNS(data, "[%s] resolve complete for %s:%u", Curl_resolv_query_str(async->dns_queries), - async->hostname, async->port); + async->peer->hostname, async->peer->port); DEBUGASSERT(*pdns); } @@ -504,15 +500,10 @@ const struct Curl_addrinfo *Curl_resolv_get_ai(struct Curl_easy *data, unsigned int index) { struct Curl_resolv_async *async = Curl_async_get(data, resolv_id); + (void)ai_family; (void)index; - if(!async) + if(!async || !CURL_DNSQ_IS_ADDR(async->dns_queries)) return NULL; - if((ai_family == AF_INET) && !(async->dns_queries & CURL_DNSQ_A)) - return NULL; -#ifdef USE_IPV6 - if((ai_family == AF_INET6) && !(async->dns_queries & CURL_DNSQ_AAAA)) - return NULL; -#endif return Curl_async_get_ai(data, async, ai_family, index); } @@ -555,8 +546,7 @@ bool Curl_resolv_knows_https(struct Curl_easy *data, uint32_t resolv_id) that must not be cached as negative entries. */ static CURLcode hostip_resolv_start(struct Curl_easy *data, uint8_t dns_queries, - const char *hostname, - uint16_t port, + struct Curl_peer *peer, uint8_t transport, bool for_proxy, timediff_t timeout_ms, @@ -582,40 +572,40 @@ static CURLcode hostip_resolv_start(struct Curl_easy *data, /* Check for "known" things to resolve ourselves. */ if(addr_queries) { #ifndef USE_RESOLVE_ON_IPS - if(Curl_is_ipaddr(hostname)) { + if(Curl_is_ipaddr(peer->hostname)) { /* test655 verifies that the announce is done, even though there * is no real resolving. So, keep doing this. */ result = Curl_resolv_announce_start(data, NULL); if(result) goto out; /* shortcut literal IP addresses, if we are not told to resolve them. */ - result = Curl_str2addr(hostname, port, &addr); + result = Curl_str2addr(peer->hostname, peer->port, &addr); goto out; } #endif - hostname_len = strlen(hostname); - if(curl_strequal(hostname, "localhost") || - curl_strequal(hostname, "localhost.") || - tailmatch(hostname, hostname_len, STRCONST(".localhost")) || - tailmatch(hostname, hostname_len, STRCONST(".localhost."))) { + hostname_len = strlen(peer->hostname); + if(curl_strequal(peer->hostname, "localhost") || + curl_strequal(peer->hostname, "localhost.") || + tailmatch(peer->hostname, hostname_len, STRCONST(".localhost")) || + tailmatch(peer->hostname, hostname_len, STRCONST(".localhost."))) { result = Curl_resolv_announce_start(data, NULL); if(result) goto out; - addr = get_localhost(port, hostname); + addr = get_localhost(peer->port, peer->hostname); if(!addr) result = CURLE_OUT_OF_MEMORY; goto out; } } #ifndef CURL_DISABLE_DOH - if(!Curl_is_ipaddr(hostname) && allowDOH && data->set.doh) { + if(!Curl_is_ipaddr(peer->hostname) && allowDOH && data->set.doh) { result = Curl_resolv_announce_start(data, NULL); if(result) goto out; if(!async) { - async = hostip_async_new(data, dns_queries, hostname, port, - transport, for_proxy, timeout_ms); + async = hostip_async_new(data, dns_queries, peer, transport, + for_proxy, timeout_ms); if(!async) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -637,8 +627,8 @@ static CURLcode hostip_resolv_start(struct Curl_easy *data, #ifdef CURLRES_ASYNCH (void)addr; if(!async) { - async = hostip_async_new(data, dns_queries, hostname, port, - transport, for_proxy, timeout_ms); + async = hostip_async_new(data, dns_queries, peer, transport, + for_proxy, timeout_ms); if(!async) { result = CURLE_OUT_OF_MEMORY; goto out; @@ -657,7 +647,8 @@ static CURLcode hostip_resolv_start(struct Curl_easy *data, result = Curl_resolv_announce_start(data, NULL); if(result) goto out; - addr = Curl_sync_getaddrinfo(data, dns_queries, hostname, port, transport); + addr = Curl_sync_getaddrinfo(data, dns_queries, peer->hostname, peer->port, + transport); if(!addr) { result = RESOLV_FAIL(for_proxy); /* the synchronous resolvers do not tell a transient failure from @@ -671,7 +662,7 @@ out: if(addr) { /* we got a response, create a dns entry, add to cache, return */ DEBUGASSERT(!*pdns); - *pdns = Curl_dnsc_mk_addr(data, dns_queries, &addr, hostname, port); + *pdns = Curl_dnsc_mk_addr(data, dns_queries, &addr, peer); if(!*pdns) result = CURLE_OUT_OF_MEMORY; } @@ -701,8 +692,7 @@ out: static CURLcode hostip_resolv(struct Curl_easy *data, uint8_t dns_queries, - const char *hostname, - uint16_t port, + struct Curl_peer *peer, uint8_t transport, bool for_proxy, timediff_t timeout_ms, @@ -724,40 +714,40 @@ static CURLcode hostip_resolv(struct Curl_easy *data, #endif /* We should intentionally error and not resolve .onion TLDs */ - hostname_len = strlen(hostname); + hostname_len = strlen(peer->hostname); DEBUGASSERT(hostname_len); if(hostname_len >= 7 && - (curl_strequal(&hostname[hostname_len - 6], ".onion") || - curl_strequal(&hostname[hostname_len - 7], ".onion."))) { + (curl_strequal(&peer->hostname[hostname_len - 6], ".onion") || + curl_strequal(&peer->hostname[hostname_len - 7], ".onion."))) { failf(data, "Not resolving .onion address (RFC 7686)"); goto out; } #ifdef DEBUGBUILD CURL_TRC_DNS(data, "[%s] hostip_resolv(%s:%u)", - Curl_resolv_query_str(dns_queries), hostname, port); + Curl_resolv_query_str(dns_queries), peer->hostname, peer->port); if((CURL_DNSQ_IS_ADDR(dns_queries) == CURL_DNSQ_AAAA) && getenv("CURL_DBG_RESOLV_FAIL_IPV6")) { infof(data, "DEBUG fail ipv6 resolve"); - result = hostip_resolv_failed(data, hostname, for_proxy); + result = hostip_resolv_failed(data, peer, for_proxy); goto out; } #endif /* Let's check our DNS cache first */ - result = Curl_dnscache_get(data, dns_queries, hostname, port, pdns); + result = Curl_dnscache_get(data, dns_queries, peer, pdns); if(*pdns) { - infof(data, "Hostname %s was found in DNS cache", hostname); + infof(data, "Hostname %s was found in DNS cache", peer->hostname); result = CURLE_OK; } else if(result) { infof(data, "Negative DNS entry"); - result = hostip_resolv_failed(data, hostname, for_proxy); + result = hostip_resolv_failed(data, peer, for_proxy); } else { /* No luck, we need to start resolving. */ cache_dns = TRUE; - result = hostip_resolv_start(data, dns_queries, hostname, port, - transport, for_proxy, timeout_ms, allowDOH, + result = hostip_resolv_start(data, dns_queries, peer, transport, + for_proxy, timeout_ms, allowDOH, presolv_id, pdns, &negative); CURL_TRC_DNS(data, "[%s] hostip_resolv started -> %d", Curl_resolv_query_str(dns_queries), (int)result); @@ -768,12 +758,13 @@ out: Curl_dns_entry_unlink(data, pdns); if(IS_RESOLV_FAIL(result)) { if(cache_dns && negative) - Curl_dnscache_add_negative(data, dns_queries, hostname, port); + Curl_dnscache_add_negative(data, dns_queries, peer); if(dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA)) - failf(data, "Could not resolve: %s:%u", hostname, port); + failf(data, "Could not resolve: %s:%u", peer->hostname, peer->port); } else { - failf(data, "Error %d resolving %s:%u", (int)result, hostname, port); + failf(data, "Error %d resolving %s:%u", + (int)result, peer->hostname, peer->port); } } else if(cache_dns && *pdns) { @@ -792,13 +783,19 @@ CURLcode Curl_resolv_blocking(struct Curl_easy *data, uint8_t transport, struct Curl_dns_entry **pdns) { + struct Curl_peer *peer = NULL; CURLcode result; uint32_t resolv_id; + DEBUGASSERT(hostname && *hostname); *pdns = NULL; + + result = Curl_peer_create(data, data->conn->scheme, hostname, port, &peer); + if(result) + goto out; + /* We cannot do a blocking resolve using DoH currently */ - result = hostip_resolv(data, dns_queries, - hostname, port, transport, FALSE, 0, FALSE, + result = hostip_resolv(data, dns_queries, peer, transport, FALSE, 0, FALSE, &resolv_id, pdns); switch(result) { case CURLE_OK: @@ -814,6 +811,9 @@ CURLcode Curl_resolv_blocking(struct Curl_easy *data, default: break; } + +out: + Curl_peer_unlink(&peer); return result; } @@ -831,8 +831,7 @@ CURL_NORETURN static void alarmfunc(int sig) static CURLcode resolv_alarm_timeout(struct Curl_easy *data, uint8_t dns_queries, - const char *hostname, - uint16_t port, + struct Curl_peer *peer, uint8_t transport, bool for_proxy, timediff_t timeout_ms, @@ -852,7 +851,7 @@ static CURLcode resolv_alarm_timeout(struct Curl_easy *data, volatile unsigned int prev_alarm = 0; CURLcode result; - DEBUGASSERT(hostname && *hostname); + DEBUGASSERT(peer->hostname && *peer->hostname); DEBUGASSERT(timeout_ms > 0); DEBUGASSERT(!data->set.no_signal); #ifndef CURL_DISABLE_DOH @@ -913,7 +912,7 @@ static CURLcode resolv_alarm_timeout(struct Curl_easy *data, /* Perform the actual name resolution. This might be interrupted by an * alarm if it takes too long. */ - result = hostip_resolv(data, dns_queries, hostname, port, transport, + result = hostip_resolv(data, dns_queries, peer, transport, for_proxy, timeout_ms, FALSE, presolv_id, entry); clean_up: @@ -967,27 +966,26 @@ clean_up: #ifdef USE_UNIX_SOCKETS static CURLcode resolv_unix(struct Curl_easy *data, - const char *unix_path, - bool abstract_path, + struct Curl_peer *peer, struct Curl_dns_entry **pdns) { struct Curl_addrinfo *addr; CURLcode result; - DEBUGASSERT(unix_path); + DEBUGASSERT(peer->unix_socket); *pdns = NULL; - result = Curl_unix2addr(unix_path, abstract_path, &addr); + result = Curl_unix2addr(peer->hostname, (bool)peer->abstract_uds, &addr); if(result) { if(result == CURLE_TOO_LARGE) { /* Long paths are not supported for now */ - failf(data, "Unix socket path too long: '%s'", unix_path); + failf(data, "Unix socket path too long: '%s'", peer->hostname); result = CURLE_COULDNT_RESOLVE_HOST; } return result; } - *pdns = Curl_dnsc_mk_addr(data, 0, &addr, NULL, 0); + *pdns = Curl_dnsc_mk_addr(data, 0, &addr, peer); return *pdns ? CURLE_OK : CURLE_OUT_OF_MEMORY; } #endif /* USE_UNIX_SOCKETS */ @@ -1032,10 +1030,10 @@ CURLcode Curl_resolv(struct Curl_easy *data, #ifdef USE_UNIX_SOCKETS if((dns_queries & CURL_DNSQ_ADDR) && peer->unix_socket) - return resolv_unix(data, peer->hostname, (bool)peer->abstract_uds, pdns); + return resolv_unix(data, peer, pdns); #else if(peer->unix_socket) - return hostip_resolv_failed(data, peer->hostname, for_proxy); + return hostip_resolv_failed(data, peer, for_proxy); #endif #ifdef USE_ALARM_TIMEOUT @@ -1045,10 +1043,8 @@ CURLcode Curl_resolv(struct Curl_easy *data, timeout_ms = 0; } if(timeout_ms && !Curl_doh_wanted(data)) { - return resolv_alarm_timeout(data, dns_queries, - peer->hostname, peer->port, - transport, for_proxy, timeout_ms, - presolv_id, pdns); + return resolv_alarm_timeout(data, dns_queries, peer, transport, + for_proxy, timeout_ms, presolv_id, pdns); } } #endif /* !USE_ALARM_TIMEOUT */ @@ -1058,9 +1054,8 @@ CURLcode Curl_resolv(struct Curl_easy *data, infof(data, "timeout on name lookup is not supported"); #endif - return hostip_resolv(data, dns_queries, peer->hostname, peer->port, - transport, for_proxy, timeout_ms, TRUE, presolv_id, - pdns); + return hostip_resolv(data, dns_queries, peer, transport, + for_proxy, timeout_ms, TRUE, presolv_id, pdns); } #ifdef USE_CURL_ASYNC @@ -1087,11 +1082,10 @@ CURLcode Curl_resolv_take_result(struct Curl_easy *data, uint32_t resolv_id, return CURLE_FAILED_INIT; /* check if we have the name resolved by now (from someone else) */ - result = Curl_dnscache_get(data, async->dns_queries, - async->hostname, async->port, pdns); + result = Curl_dnscache_get(data, async->dns_queries, async->peer, pdns); if(*pdns) { /* Tell a possibly async resolver we no longer need the results. */ - infof(data, "Hostname '%s' was found in DNS cache", async->hostname); + infof(data, "Hostname '%s' was found in DNS cache", async->peer->hostname); Curl_async_shutdown(data, async); return CURLE_OK; } @@ -1115,14 +1109,14 @@ CURLcode Curl_resolv_take_result(struct Curl_easy *data, uint32_t resolv_id, nothing about the name and would poison the cache for every transfer using it. */ if(async->negative_answer) - Curl_dnscache_add_negative(data, async->dns_queries, - async->hostname, async->port); + Curl_dnscache_add_negative(data, async->dns_queries, async->peer); if(async->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA)) - failf(data, "Could not resolve: %s:%u", async->hostname, async->port); + failf(data, "Could not resolve: %s:%u", + async->peer->hostname, async->peer->port); } else if(result) { failf(data, "Error %d resolving %s:%u", - (int)result, async->hostname, async->port); + (int)result, async->peer->hostname, async->peer->port); } return result; }