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
This commit is contained in:
Stefan Eissing 2024-07-12 12:46:50 +02:00 committed by Daniel Stenberg
parent 2372a5915c
commit 5a9262a333
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
14 changed files with 159 additions and 207 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

202
lib/url.c
View File

@ -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,118 +3099,12 @@ 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)
{
struct Curl_dns_entry *hostaddr = NULL;
struct hostname *host;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
int rc;
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;
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;
}
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;
/* Resolve target host right on */
conn->hostname_resolve = strdup(connhost->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;
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,
Curl_timediff(Curl_now(), data->progress.t_startsingle));
return CURLE_OPERATION_TIMEDOUT;
}
else if(!hostaddr) {
failf(data, "Could not resolve host: %s", connhost->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
*************************************************************/
@ -3220,19 +3112,67 @@ static CURLcode resolve_server(struct Curl_easy *data,
struct connectdata *conn,
bool *async)
{
DEBUGASSERT(conn);
DEBUGASSERT(data);
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;
/* 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;
#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
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);
}
#endif
DEBUGASSERT(conn->dns_entry == NULL);
#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;
}
return resolve_fresh(data, conn, async);
/* Resolve target host right on */
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,
&conn->dns_entry, timeout_ms);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(rc == CURLRESOLV_TIMEDOUT) {
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(!conn->dns_entry) {
failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
return CURLE_COULDNT_RESOLVE_HOST;
}
return CURLE_OK;
}
/*
@ -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.

View File

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

View File

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

View File

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

View File

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