mirror of
https://github.com/curl/curl.git
synced 2025-09-12 07:02:41 +03:00
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:
parent
2372a5915c
commit
5a9262a333
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
22
lib/ftp.c
22
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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
85
lib/hostip.c
85
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)
|
||||
|
|
19
lib/hostip.h
19
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
202
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,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.
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue
Block a user