]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
url: dns_entry related improvements
authorStefan Eissing <stefan@eissing.org>
Fri, 12 Jul 2024 10:46:50 +0000 (12:46 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sat, 3 Aug 2024 17:51:02 +0000 (19:51 +0200)
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

14 files changed:
lib/cf-socket.c
lib/conncache.c
lib/doh.c
lib/ftp.c
lib/hostasyn.c
lib/hostip.c
lib/hostip.h
lib/multi.c
lib/socks.c
lib/url.c
lib/urldata.h
lib/vtls/openssl.c
lib/vtls/wolfssl.c
tests/unit/unit1305.c

index 9ef399a8a1f2fa15362c0f629bef784eaa118d7b..475da9c65e6fc81973c6dc46e9ba8c0302ce4917 100644 (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;
index 92fd60c4df4dfc59a868d06702dea9df264a2920..5de10de914857d0243626124bb88fc2b4963811e 100644 (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");
index 0dcca17ccda88c7da0465303e6383a05fd82e3ff..ecb8cbe646cf75543667a3120cf10302aa8e55c4 100644 (file)
--- 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);
index ae340c44af533c30a165436d1ea45c9cb0748665..2f5748df7f861126ed98c6cae9c45a2a96be156a 100644 (file)
--- 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;
index 2f6762ca4e1f9fcae6450fb596b35cae94c02931..4d6a8e85967f700623e1282641255b7e6dedbb58 100644 (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);
 
index 2c1f08e7446c11224eb9f776edb3bfdf2e20e9dd..cdda8308baeaf1539ccbd1850c6e094861170645 100644 (file)
  * 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)
index c85a688db62ff8e61375300be91e69a36586e450..fff1c066b406d07958dc95c9823d06a16569151d 100644 (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
index 4a787f00595cc8903b17bd0896fe9cf5bcd160b2..954a495fa4a38da15b60bd7c64ba04ef4633643c 100644 (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
index 094ff42cd7242172cfc0e733c1ea281c704a7b7a..4d6a00cf5679acfd02861022248f252ab0ffd634 100644 (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:
index 914b5b653ced5cef049d61a24e0936da79e92470..017846a4e8370c45597e59e3b55cd24c410e79f5 100644 (file)
--- 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.
index aab5748b04b936f97473b9d14d5c8fcc90d8411f..117167c2dc5e7a7292dea0d715093cbb595c87ff 100644 (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. */
index 8a65491b225a540fe2b86ab2f369017b5d7d6a64..45bbf92563cd6be27c497456696092d4ecb2adb2 100644 (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
index 2b467c9350d3d20afe657032d01df23190c3a340..e45ee5bab3c1fa99d29848d47dc2c8db9a0401e4 100644 (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);
       }
     }
 
index 19cc62c44a368cd131546b3ccb487b9b67e8653a..c446d8fe6a90247a4f48768c8454def6cd3a5f41 100644 (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 */