From: Stefan Eissing Date: Fri, 12 Jul 2024 10:46:50 +0000 (+0200) Subject: url: dns_entry related improvements X-Git-Tag: curl-8_10_0~418 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a9262a333900cb175f4067b10700b3e264552a5;p=thirdparty%2Fcurl.git url: dns_entry related improvements Replace Curl_resolv_unlock() with Curl_resolv_unlink(): -replace inuse member with refcount in Curl_dns_entry - pass Curl_dns_entry ** to unlink, so it gets always cleared - solve potential (but unlikley) UAF in FTP's handling of looked up Curl_dns_entry. Esp. do not use addr information after unlinking an entry. In reality, the unlink will not free memory, as the dns entry is still referenced by the hostcache. But this is not safe and relying on no other code pruning the cache in the meantime. - pass permanent flag when adding a dns entry instead of fixing timestamp afterwards. url.c: fold several static *resolve_* functions into one. Closes #14195 --- diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 9ef399a8a1..475da9c65e 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -679,12 +679,13 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, conn->ip_version = ipver; if(h) { + int h_af = h->addr->ai_family; /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */ Curl_printable_address(h->addr, myhost, sizeof(myhost)); infof(data, "Name '%s' family %i resolved to '%s' family %i", - host, af, myhost, h->addr->ai_family); - Curl_resolv_unlock(data, h); - if(af != h->addr->ai_family) { + host, af, myhost, h_af); + Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */ + if(af != h_af) { /* bad IP version combo, signal the caller to try another address family if available */ return CURLE_UNSUPPORTED_PROTOCOL; diff --git a/lib/conncache.c b/lib/conncache.c index 92fd60c4df..5de10de914 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -772,10 +772,8 @@ static void connc_run_conn_shutdown_handler(struct Curl_easy *data, struct connectdata *conn) { if(!conn->bits.shutdown_handler) { - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); - conn->dns_entry = NULL; - } + if(conn->dns_entry) + Curl_resolv_unlink(data, &conn->dns_entry); /* Cleanup NTLM connection-related data */ Curl_http_auth_cleanup_ntlm(conn); @@ -1178,7 +1176,7 @@ void Curl_conncache_print(struct conncache *connc) while(curr) { conn = curr->ptr; - fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse); + fprintf(stderr, " [%p %d]", (void *)conn, conn->refcount); curr = curr->next; } fprintf(stderr, "\n"); diff --git a/lib/doh.c b/lib/doh.c index 0dcca17ccd..ecb8cbe646 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -1360,7 +1360,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ - dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port); + dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port, FALSE); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); diff --git a/lib/ftp.c b/lib/ftp.c index ae340c44af..2f5748df7f 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1042,7 +1042,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, int error; char *host = NULL; char *string_ftpport = data->set.str[STRING_FTPPORT]; - struct Curl_dns_entry *h = NULL; + struct Curl_dns_entry *dns_entry = NULL; unsigned short port_min = 0; unsigned short port_max = 0; unsigned short port; @@ -1178,15 +1178,12 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, } /* resolv ip/host to ip */ - rc = Curl_resolv(data, host, 0, FALSE, &h); + rc = Curl_resolv(data, host, 0, FALSE, &dns_entry); if(rc == CURLRESOLV_PENDING) - (void)Curl_resolver_wait_resolv(data, &h); - if(h) { - res = h->addr; - /* when we return from this function, we can forget about this entry - to we can unlock it now already */ - Curl_resolv_unlock(data, h); - } /* (h) */ + (void)Curl_resolver_wait_resolv(data, &dns_entry); + if(dns_entry) { + res = dns_entry->addr; + } else res = NULL; /* failure! */ @@ -1381,6 +1378,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, ftp_state(data, FTP_PORT); out: + /* If we looked up a dns_entry, now is the time to safely release it */ + if(dns_entry) + Curl_resolv_unlink(data, &dns_entry); if(result) { ftp_state(data, FTP_STOP); } @@ -2098,7 +2098,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE); if(result) { - Curl_resolv_unlock(data, addr); /* we are done using this address */ + Curl_resolv_unlink(data, &addr); /* we are done using this address */ if(ftpc->count1 == 0 && ftpcode == 229) return ftp_epsv_disable(data, conn); @@ -2116,7 +2116,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, /* this just dumps information about this second connection */ ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport); - Curl_resolv_unlock(data, addr); /* we are done using this address */ + Curl_resolv_unlink(data, &addr); /* we are done using this address */ Curl_safefree(conn->secondaryhostname); conn->secondary_port = ftpc->newport; diff --git a/lib/hostasyn.c b/lib/hostasyn.c index 2f6762ca4e..4d6a8e8596 100644 --- a/lib/hostasyn.c +++ b/lib/hostasyn.c @@ -79,7 +79,7 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data, dns = Curl_cache_addr(data, ai, data->state.async.hostname, 0, - data->state.async.port); + data->state.async.port, FALSE); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); diff --git a/lib/hostip.c b/lib/hostip.c index 2c1f08e744..cdda8308ba 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -115,7 +115,7 @@ * CURLRES_* defines based on the config*.h and curl_setup.h defines. */ -static void freednsentry(void *freethis); +static void hostcache_unlink_entry(void *entry); #ifndef CURL_DISABLE_VERBOSE_STRINGS static void show_resolve_info(struct Curl_easy *data, @@ -178,7 +178,7 @@ create_hostcache_id(const char *name, struct hostcache_prune_data { time_t now; time_t oldest; /* oldest time in cache not pruned. */ - int cache_timeout; + int max_age_sec; }; /* @@ -189,16 +189,16 @@ struct hostcache_prune_data { * cache. */ static int -hostcache_timestamp_remove(void *datap, void *hc) +hostcache_entry_is_stale(void *datap, void *hc) { struct hostcache_prune_data *prune = (struct hostcache_prune_data *) datap; - struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc; + struct Curl_dns_entry *dns = (struct Curl_dns_entry *) hc; - if(c->timestamp) { + if(dns->timestamp) { /* age in seconds */ - time_t age = prune->now - c->timestamp; - if(age >= prune->cache_timeout) + time_t age = prune->now - dns->timestamp; + if(age >= prune->max_age_sec) return TRUE; if(age > prune->oldest) prune->oldest = age; @@ -216,13 +216,13 @@ hostcache_prune(struct Curl_hash *hostcache, int cache_timeout, { struct hostcache_prune_data user; - user.cache_timeout = cache_timeout; + user.max_age_sec = cache_timeout; user.now = now; user.oldest = 0; Curl_hash_clean_with_criterium(hostcache, (void *) &user, - hostcache_timestamp_remove); + hostcache_entry_is_stale); return user.oldest; } @@ -299,10 +299,10 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, struct hostcache_prune_data user; user.now = time(NULL); - user.cache_timeout = data->set.dns_cache_timeout; + user.max_age_sec = data->set.dns_cache_timeout; user.oldest = 0; - if(hostcache_timestamp_remove(&user, dns)) { + if(hostcache_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(data->dns.hostcache, entry_id, entry_len + 1); @@ -348,7 +348,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, * * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * The returned data *MUST* be "released" with Curl_resolv_unlink() after * use, or we will leak memory! */ struct Curl_dns_entry * @@ -364,7 +364,7 @@ Curl_fetch_addr(struct Curl_easy *data, dns = fetch_addr(data, hostname, port); if(dns) - dns->inuse++; /* we use it! */ + dns->refcount++; /* we use it! */ if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -468,7 +468,8 @@ Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, const char *hostname, size_t hostlen, /* length or zero */ - int port) + int port, + bool permanent) { char entry_id[MAX_HOSTCACHE_LEN]; size_t entry_len; @@ -496,11 +497,15 @@ Curl_cache_addr(struct Curl_easy *data, entry_len = create_hostcache_id(hostname, hostlen, port, entry_id, sizeof(entry_id)); - dns->inuse = 1; /* the cache has the first reference */ + dns->refcount = 1; /* the cache has the first reference */ dns->addr = addr; /* this is the address(es) */ - time(&dns->timestamp); - if(dns->timestamp == 0) - dns->timestamp = 1; /* zero indicates permanent CURLOPT_RESOLVE entry */ + if(permanent) + dns->timestamp = 0; /* an entry that never goes stale */ + else { + dns->timestamp = time(NULL); + if(dns->timestamp == 0) + dns->timestamp = 1; + } dns->hostport = port; if(hostlen) memcpy(dns->hostname, hostname, hostlen); @@ -514,7 +519,7 @@ Curl_cache_addr(struct Curl_easy *data, } dns = dns2; - dns->inuse++; /* mark entry as in-use */ + dns->refcount++; /* mark entry as in-use */ return dns; } @@ -666,8 +671,8 @@ static bool tailmatch(const char *full, const char *part) * resolves. See the return codes. * * The cache entry we return will get its 'inuse' counter increased when this - * function is used. You MUST call Curl_resolv_unlock() later (when you are - * done using this struct) to decrease the counter again. + * function is used. You MUST call Curl_resolv_unlink() later (when you are + * done using this struct) to decrease the reference counter again. * * Return codes: * @@ -708,7 +713,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, if(dns) { infof(data, "Hostname %s was found in DNS cache", hostname); - dns->inuse++; /* we use it! */ + dns->refcount++; /* we use it! */ rc = CURLRESOLV_RESOLVED; } @@ -828,7 +833,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ - dns = Curl_cache_addr(data, addr, hostname, 0, port); + dns = Curl_cache_addr(data, addr, hostname, 0, port, FALSE); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -868,8 +873,8 @@ void alarmfunc(int sig) * resolves. See the return codes. * * The cache entry we return will get its 'inuse' counter increased when this - * function is used. You MUST call Curl_resolv_unlock() later (when you are - * done using this struct) to decrease the counter again. + * function is used. You MUST call Curl_resolv_unlink() later (when you are + * done using this struct) to decrease the reference counter again. * * If built with a synchronous resolver and use of signals is not * disabled by the application, then a nonzero timeout will cause a @@ -1037,18 +1042,20 @@ clean_up: } /* - * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been - * made, the struct may be destroyed due to pruning. It is important that only - * one unlock is made for each Curl_resolv() call. + * Curl_resolv_unlink() releases a reference to the given cached DNS entry. + * When the reference count reaches 0, the entry is destroyed. It is important + * that only one unlink is made for each Curl_resolv() call. * * May be called with 'data' == NULL for global cache. */ -void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) +void Curl_resolv_unlink(struct Curl_easy *data, struct Curl_dns_entry **pdns) { + struct Curl_dns_entry *dns = *pdns; + *pdns = NULL; if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); - freednsentry(dns); + hostcache_unlink_entry(dns); if(data && data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -1057,13 +1064,13 @@ void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) /* * File-internal: release cache dns entry reference, free if inuse drops to 0 */ -static void freednsentry(void *freethis) +static void hostcache_unlink_entry(void *entry) { - struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis; - DEBUGASSERT(dns && (dns->inuse>0)); + struct Curl_dns_entry *dns = (struct Curl_dns_entry *) entry; + DEBUGASSERT(dns && (dns->refcount>0)); - dns->inuse--; - if(dns->inuse == 0) { + dns->refcount--; + if(dns->refcount == 0) { Curl_freeaddrinfo(dns->addr); #ifdef USE_HTTPSRR if(dns->hinfo) { @@ -1092,7 +1099,7 @@ static void freednsentry(void *freethis) void Curl_init_dnscache(struct Curl_hash *hash, size_t size) { Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare, - freednsentry); + hostcache_unlink_entry); } /* @@ -1285,13 +1292,11 @@ err: } /* put this new host in the cache */ - dns = Curl_cache_addr(data, head, host_begin, hlen, port); + dns = Curl_cache_addr(data, head, host_begin, hlen, port, permanent); if(dns) { - if(permanent) - dns->timestamp = 0; /* mark as permanent */ /* release the returned reference; the cache itself will keep the * entry alive: */ - dns->inuse--; + dns->refcount--; } if(data->share) diff --git a/lib/hostip.h b/lib/hostip.h index c85a688db6..fff1c066b4 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -99,8 +99,8 @@ struct Curl_dns_entry { #endif /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */ time_t timestamp; - /* use-counter, use Curl_resolv_unlock to release reference */ - long inuse; + /* reference counter, entry is freed on reaching 0 */ + size_t refcount; /* hostname port number that resolved to addr. */ int hostport; /* hostname that resolved to addr. may be NULL (unix domain sockets). */ @@ -113,7 +113,7 @@ bool Curl_host_is_ipnum(const char *hostname); * Curl_resolv() returns an entry with the info for the specified host * and port. * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * The returned data *MUST* be "released" with Curl_resolv_unlink() after * use, or we will leak memory! */ /* return codes */ @@ -161,9 +161,9 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, int *waitp); -/* unlock a previously resolved dns entry */ -void Curl_resolv_unlock(struct Curl_easy *data, - struct Curl_dns_entry *dns); +/* unlink a dns entry, potentially shared with a cache */ +void Curl_resolv_unlink(struct Curl_easy *data, + struct Curl_dns_entry **pdns); /* init a new dns cache */ void Curl_init_dnscache(struct Curl_hash *hash, size_t hashsize); @@ -199,7 +199,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ip, * * Returns the Curl_dns_entry entry pointer or NULL if not in the cache. * - * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after + * The returned data *MUST* be "released" with Curl_resolv_unlink() after * use, or we will leak memory! */ struct Curl_dns_entry * @@ -209,12 +209,13 @@ Curl_fetch_addr(struct Curl_easy *data, /* * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache. - * + * @param permanent iff TRUE, entry will never become stale * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, - const char *hostname, size_t hostlen, int port); + const char *hostname, size_t hostlen, int port, + bool permanent); #ifndef INADDR_NONE #define CURL_INADDR_NONE (in_addr_t) ~0 diff --git a/lib/multi.c b/lib/multi.c index 4a787f0059..954a495fa4 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -742,10 +742,8 @@ static CURLcode multi_done(struct Curl_easy *data, data->state.done = TRUE; /* called just now! */ - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; - } + if(conn->dns_entry) + Curl_resolv_unlink(data, &conn->dns_entry); /* done with this */ Curl_hostcache_prune(data); /* if data->set.reuse_forbid is TRUE, it means the libcurl client has diff --git a/lib/socks.c b/lib/socks.c index 094ff42cd7..4d6a00cf56 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -388,7 +388,7 @@ CONNECT_RESOLVED: infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf); - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ } else failf(data, "SOCKS4 connection to %s not supported", sx->hostname); @@ -893,7 +893,7 @@ CONNECT_RESOLVED: failf(data, "SOCKS5 connection to %s not supported", dest); } - Curl_resolv_unlock(data, dns); /* not used anymore from now on */ + Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ goto CONNECT_REQ_SEND; } CONNECT_RESOLVE_REMOTE: diff --git a/lib/url.c b/lib/url.c index 914b5b653c..017846a4e8 100644 --- a/lib/url.c +++ b/lib/url.c @@ -637,10 +637,8 @@ void Curl_disconnect(struct Curl_easy *data, return; } - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); - conn->dns_entry = NULL; - } + if(conn->dns_entry) + Curl_resolv_unlink(data, &conn->dns_entry); /* Cleanup NTLM connection-related data */ Curl_http_auth_cleanup_ntlm(conn); @@ -3101,140 +3099,82 @@ static CURLcode resolve_unix(struct Curl_easy *data, return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY; } - hostaddr->inuse++; + hostaddr->refcount = 1; /* connection is the only one holding this */ conn->dns_entry = hostaddr; return CURLE_OK; } #endif -#ifndef CURL_DISABLE_PROXY -static CURLcode resolve_proxy(struct Curl_easy *data, - struct connectdata *conn, - bool *async) +/************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ +static CURLcode resolve_server(struct Curl_easy *data, + struct connectdata *conn, + bool *async) { - struct Curl_dns_entry *hostaddr = NULL; - struct hostname *host; + struct hostname *ehost; timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + const char *peertype = "host"; int rc; +#ifdef USE_UNIX_SOCKETS + char *unix_path = conn->unix_domain_socket; - DEBUGASSERT(conn->dns_entry == NULL); - - host = conn->bits.socksproxy ? &conn->socks_proxy.host : - &conn->http_proxy.host; - - conn->hostname_resolve = strdup(host->name); - if(!conn->hostname_resolve) - return CURLE_OUT_OF_MEMORY; +#ifndef CURL_DISABLE_PROXY + if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name && + !strncmp(UNIX_SOCKET_PREFIX"/", + conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) + unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; +#endif - rc = Curl_resolv_timeout(data, conn->hostname_resolve, - conn->primary.remote_port, &hostaddr, timeout_ms); - conn->dns_entry = hostaddr; - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - else if(rc == CURLRESOLV_TIMEDOUT) - return CURLE_OPERATION_TIMEDOUT; - else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", host->dispname); - return CURLE_COULDNT_RESOLVE_PROXY; + if(unix_path) { + /* TODO, this only works if previous transport is TRNSPRT_TCP. Check it? */ + conn->transport = TRNSPRT_UNIX; + return resolve_unix(data, conn, unix_path); } - - return CURLE_OK; -} #endif -static CURLcode resolve_host(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - struct Curl_dns_entry *hostaddr = NULL; - struct hostname *connhost; - timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - int rc; - DEBUGASSERT(conn->dns_entry == NULL); - connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; - - /* If not connecting via a proxy, extract the port from the URL, if it is - * there, thus overriding any defaults that might have been set above. */ - conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port; +#ifndef CURL_DISABLE_PROXY + if(CONN_IS_PROXIED(conn)) { + ehost = conn->bits.socksproxy ? &conn->socks_proxy.host : + &conn->http_proxy.host; + peertype = "proxy"; + } + else +#endif + { + ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; + /* If not connecting via a proxy, extract the port from the URL, if it is + * there, thus overriding any defaults that might have been set above. */ + conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; + } /* Resolve target host right on */ - conn->hostname_resolve = strdup(connhost->name); + conn->hostname_resolve = strdup(ehost->name); if(!conn->hostname_resolve) return CURLE_OUT_OF_MEMORY; rc = Curl_resolv_timeout(data, conn->hostname_resolve, - conn->primary.remote_port, &hostaddr, timeout_ms); - conn->dns_entry = hostaddr; + conn->primary.remote_port, + &conn->dns_entry, timeout_ms); if(rc == CURLRESOLV_PENDING) *async = TRUE; else if(rc == CURLRESOLV_TIMEDOUT) { - failf(data, "Failed to resolve host '%s' with timeout after %" - CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname, + failf(data, "Failed to resolve %s '%s' with timeout after %" + CURL_FORMAT_TIMEDIFF_T " ms", peertype, ehost->dispname, Curl_timediff(Curl_now(), data->progress.t_startsingle)); return CURLE_OPERATION_TIMEDOUT; } - else if(!hostaddr) { - failf(data, "Could not resolve host: %s", connhost->dispname); + else if(!conn->dns_entry) { + failf(data, "Could not resolve %s: %s", peertype, ehost->dispname); return CURLE_COULDNT_RESOLVE_HOST; } return CURLE_OK; } -/* Perform a fresh resolve */ -static CURLcode resolve_fresh(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ -#ifdef USE_UNIX_SOCKETS - char *unix_path = conn->unix_domain_socket; - -#ifndef CURL_DISABLE_PROXY - if(!unix_path && conn->socks_proxy.host.name && - !strncmp(UNIX_SOCKET_PREFIX"/", - conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) - unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; -#endif - - if(unix_path) { - conn->transport = TRNSPRT_UNIX; - return resolve_unix(data, conn, unix_path); - } -#endif - -#ifndef CURL_DISABLE_PROXY - if(CONN_IS_PROXIED(conn)) - return resolve_proxy(data, conn, async); -#endif - - return resolve_host(data, conn, async); -} - -/************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ -static CURLcode resolve_server(struct Curl_easy *data, - struct connectdata *conn, - bool *async) -{ - DEBUGASSERT(conn); - DEBUGASSERT(data); - - /* Resolve the name of the server or proxy */ - if(conn->bits.reuse) { - /* We are reusing the connection - no need to resolve anything, and - idnconvert_hostname() was called already in create_conn() for the reuse - case. */ - *async = FALSE; - return CURLE_OK; - } - - return resolve_fresh(data, conn, async); -} - /* * Cleanup the connection `temp`, just allocated for `data`, before using the * previously `existing` one for `data`. All relevant info is copied over @@ -3708,12 +3648,20 @@ static CURLcode create_conn(struct Curl_easy *data, /* Continue connectdata initialization here. */ - /************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ - result = resolve_server(data, conn, async); - if(result) - goto out; + if(conn->bits.reuse) { + /* We are reusing the connection - no need to resolve anything, and + idnconvert_hostname() was called already in create_conn() for the reuse + case. */ + *async = FALSE; + } + else { + /************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ + result = resolve_server(data, conn, async); + if(result) + goto out; + } /* Everything general done, inform filters that they need * to prepare for a data transfer. diff --git a/lib/urldata.h b/lib/urldata.h index aab5748b04..117167c2dc 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -831,7 +831,8 @@ struct connectdata { struct proxy_info http_proxy; #endif /* 'primary' and 'secondary' get filled with IP quadruple - (local/remote numerical ip address and port) whenever a is *attempted*. + (local/remote numerical ip address and port) whenever a connect is + *attempted*. When more than one address is tried for a connection these will hold data for the last attempt. When the connection is actually established these are updated with data which comes directly from the socket. */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 8a65491b22..45bbf92563 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3897,7 +3897,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, if(data->set.tls_ech & CURLECH_HARD) return CURLE_SSL_CONNECT_ERROR; } - Curl_resolv_unlock(data, dns); + Curl_resolv_unlink(data, &dns); } } # ifdef OPENSSL_IS_BORINGSSL diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 2b467c9350..e45ee5bab3 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -988,7 +988,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(data->set.tls_ech & CURLECH_HARD) return CURLE_SSL_CONNECT_ERROR; } - Curl_resolv_unlock(data, dns); + Curl_resolv_unlink(data, &dns); } } diff --git a/tests/unit/unit1305.c b/tests/unit/unit1305.c index 19cc62c44a..c446d8fe6a 100644 --- a/tests/unit/unit1305.c +++ b/tests/unit/unit1305.c @@ -122,7 +122,7 @@ UNITTEST_START abort_unless(rc == CURLE_OK, "data node creation failed"); key_len = strlen(data_key); - data_node->inuse = 1; /* hash will hold the reference */ + data_node->refcount = 1; /* hash will hold the reference */ nodep = Curl_hash_add(&hp, data_key, key_len + 1, data_node); abort_unless(nodep, "insertion into hash failed"); /* Freeing will now be done by Curl_hash_destroy */