This commit is contained in:
Stefan Eissing 2026-07-30 13:50:55 +02:00 committed by GitHub
commit a75e1f76fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 344 additions and 344 deletions

View file

@ -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 */

View file

@ -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;
}

View file

@ -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:

View file

@ -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,

View file

@ -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);
}

View file

@ -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()

View file

@ -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,

View file

@ -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, "*")) {

View file

@ -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.

View file

@ -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;

View file

@ -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;
};
/*

View file

@ -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;
}