]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
hostip: make more functions return CURLcode
authorDaniel Stenberg <daniel@haxx.se>
Mon, 24 Nov 2025 13:00:09 +0000 (14:00 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 25 Nov 2025 08:13:34 +0000 (09:13 +0100)
- Curl_async_getaddrinfo() always returned NULL so it was pointless.
  Return proper curlcode instead to distinguish between errors. Same for
  Curl_doh().
- simplify the IP address handling
- make Curl_str2addr() function return CURLcode

Closes #19669

lib/asyn-ares.c
lib/asyn-thrdd.c
lib/asyn.h
lib/curl_addrinfo.c
lib/curl_addrinfo.h
lib/doh.c
lib/doh.h
lib/hostip.c
tests/libtest/lib655.c

index ab57d5e00b4152c9feee4fef322767ba476bd8ae..d459fd4a75cd7ca8fe022f69431c092fd0384e7b 100644 (file)
@@ -718,25 +718,18 @@ static void async_ares_rr_done(void *user_data, ares_status_t status,
 /*
  * Curl_async_getaddrinfo() - when using ares
  *
- * Returns name information about the given hostname and port number. If
- * successful, the 'hostent' is returned and the fourth argument will point to
- * memory we need to free after use. That memory *MUST* be freed with
- * Curl_freeaddrinfo(), nothing else.
+ * Starts a name resolve for the given hostname and port number.
  */
-struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
-                                             const char *hostname,
-                                             int port,
-                                             int ip_version,
-                                             int *waitp)
+CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, const char *hostname,
+                                int port, int ip_version)
 {
   struct async_ares_ctx *ares = &data->state.async.ares;
 #ifdef USE_HTTPSRR
   char *rrname = NULL;
 #endif
-  *waitp = 0; /* default to synchronous response */
 
   if(async_ares_init_lazy(data))
-    return NULL;
+    return CURLE_FAILED_INIT;
 
   data->state.async.done = FALSE;   /* not done */
   data->state.async.dns = NULL;     /* clear */
@@ -744,12 +737,12 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
   data->state.async.ip_version = ip_version;
   data->state.async.hostname = strdup(hostname);
   if(!data->state.async.hostname)
-    return NULL;
+    return CURLE_OUT_OF_MEMORY;
 #ifdef USE_HTTPSRR
   if(port != 443) {
     rrname = curl_maprintf("_%d_.https.%s", port, hostname);
     if(!rrname)
-      return NULL;
+      return CURLE_OUT_OF_MEMORY;
   }
 #endif
 
@@ -836,9 +829,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
                       async_ares_rr_done, data, NULL);
   }
 #endif
-  *waitp = 1; /* expect asynchronous response */
 
-  return NULL; /* no struct yet */
+  return CURLE_OK;
 }
 
 /* Set what DNS server are is to use. This is called in 2 situations:
index f4f57b547a018b0376cbbff776d7c5f83f781035..71e31e6d0d16b8a4ecb1956938ec59379fb4fd18 100644 (file)
@@ -755,15 +755,11 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
 /*
  * Curl_async_getaddrinfo() - for getaddrinfo
  */
-struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
-                                             const char *hostname,
-                                             int port,
-                                             int ip_version,
-                                             int *waitp)
+CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, const char *hostname,
+                                int port, int ip_version)
 {
   struct addrinfo hints;
   int pf = PF_INET;
-  *waitp = 0; /* default to synchronous response */
 
   CURL_TRC_DNS(data, "init threaded resolve of %s:%d", hostname, port);
 #ifdef CURLRES_IPV6
@@ -785,14 +781,11 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
     SOCK_STREAM : SOCK_DGRAM;
 
   /* fire up a new resolver thread! */
-  if(async_thrdd_init(data, hostname, port, ip_version, &hints)) {
-    *waitp = 1; /* expect asynchronous response */
-    return NULL;
-  }
+  if(async_thrdd_init(data, hostname, port, ip_version, &hints))
+    return CURLE_OK;
 
   failf(data, "getaddrinfo() thread failed to start");
-  return NULL;
-
+  return CURLE_FAILED_INIT;
 }
 
 #endif /* !HAVE_GETADDRINFO */
index 7863042bbe37f74f5a72bcb0c8d1887853393754..8da7dd9720cc51079f5d12548b87f47691c2c4f4 100644 (file)
@@ -118,11 +118,8 @@ CURLcode Curl_async_await(struct Curl_easy *data,
  * Each resolver backend must of course make sure to return data in the
  * correct format to comply with this.
  */
-struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
-                                             const char *hostname,
-                                             int port,
-                                             int ip_version,
-                                             int *waitp);
+CURLcode Curl_async_getaddrinfo(struct Curl_easy *data, const char *hostname,
+                                int port, int ip_version);
 
 #ifdef USE_ARES
 /* common functions for c-ares and threaded resolver with HTTPSRR */
index fc26bef8333d0b4366637a110518a439f5bd59da..cd9b52febaa7b8cd3ae6a4659b1f41fa46f9f1a5 100644 (file)
@@ -347,7 +347,7 @@ Curl_he2ai(const struct hostent *he, int port)
 #endif
 
 /*
- * Curl_ip2addr()
+ * ip2addr()
  *
  * This function takes an Internet address, in binary form, as input parameter
  * along with its address family and the string version of the address, and it
@@ -355,8 +355,9 @@ Curl_he2ai(const struct hostent *he, int port)
  * given address/host
  */
 
-struct Curl_addrinfo *
-Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
+static CURLcode
+ip2addr(struct Curl_addrinfo **addrp,
+        int af, const void *inaddr, const char *hostname, int port)
 {
   struct Curl_addrinfo *ai;
   size_t addrsize;
@@ -369,6 +370,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
   DEBUGASSERT(inaddr && hostname);
 
   namelen = strlen(hostname) + 1;
+  *addrp = NULL;
 
   if(af == AF_INET)
     addrsize = sizeof(struct sockaddr_in);
@@ -377,12 +379,12 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
     addrsize = sizeof(struct sockaddr_in6);
 #endif
   else
-    return NULL;
+    return CURLE_BAD_FUNCTION_ARGUMENT;
 
   /* allocate memory to hold the struct, the address and the name */
   ai = calloc(1, sizeof(struct Curl_addrinfo) + addrsize + namelen);
   if(!ai)
-    return NULL;
+    return CURLE_OUT_OF_MEMORY;
   /* put the address after the struct */
   ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
   /* then put the name after the address */
@@ -412,29 +414,46 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
     break;
 #endif
   }
-
-  return ai;
+  *addrp = ai;
+  return CURLE_OK;
 }
 
 /*
  * Given an IPv4 or IPv6 dotted string address, this converts it to a proper
  * allocated Curl_addrinfo struct and returns it.
  */
-struct Curl_addrinfo *Curl_str2addr(char *address, int port)
+CURLcode Curl_str2addr(const char *address, int port,
+                       struct Curl_addrinfo **addrp)
 {
   struct in_addr in;
   if(curlx_inet_pton(AF_INET, address, &in) > 0)
     /* This is a dotted IP address 123.123.123.123-style */
-    return Curl_ip2addr(AF_INET, &in, address, port);
+    return ip2addr(addrp, AF_INET, &in, address, port);
+#ifdef USE_IPV6
+  {
+    struct in6_addr in6;
+    if(curlx_inet_pton(AF_INET6, address, &in6) > 0)
+      /* This is a dotted IPv6 address ::1-style */
+      return ip2addr(addrp, AF_INET6, &in6, address, port);
+  }
+#endif
+  return CURLE_BAD_FUNCTION_ARGUMENT; /* bad input format */
+}
+
+bool Curl_is_ipaddr(const char *address)
+{
+  struct in_addr in;
+  if(curlx_inet_pton(AF_INET, address, &in) > 0)
+    return TRUE;
 #ifdef USE_IPV6
   {
     struct in6_addr in6;
     if(curlx_inet_pton(AF_INET6, address, &in6) > 0)
       /* This is a dotted IPv6 address ::1-style */
-      return Curl_ip2addr(AF_INET6, &in6, address, port);
+      return TRUE;
   }
 #endif
-  return NULL; /* bad input format */
+  return FALSE;
 }
 
 #ifdef USE_UNIX_SOCKETS
index 2303e95e314ea9c7c38bdcb3c20946ef2d957ae9..9a26c6784912b2a1a5d0b748291f8a3260a209cb 100644 (file)
@@ -76,10 +76,8 @@ struct Curl_addrinfo *
 Curl_he2ai(const struct hostent *he, int port);
 #endif
 
-struct Curl_addrinfo *
-Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
-
-struct Curl_addrinfo *Curl_str2addr(char *dotted, int port);
+bool Curl_is_ipaddr(const char *address);
+CURLcode Curl_str2addr(const char *dotted, int port, struct Curl_addrinfo **);
 
 #ifdef USE_UNIX_SOCKETS
 struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
index 45524edf4c0bd0fa7373e255bf8665dc560b10cc..83a83f5346726875a69c654c9192008217218f92 100644 (file)
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -441,15 +441,12 @@ error:
 }
 
 /*
- * Curl_doh() resolves a name using DoH. It resolves a name and returns a
- * 'Curl_addrinfo *' with the address information.
+ * Curl_doh() starts a name resolve using DoH. It resolves a name and returns
+ * 'Curl_addrinfo *' with the address information.
  */
 
-struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
-                               const char *hostname,
-                               int port,
-                               int ip_version,
-                               int *waitp)
+CURLcode Curl_doh(struct Curl_easy *data, const char *hostname,
+                  int port, int ip_version)
 {
   CURLcode result = CURLE_OK;
   struct doh_probes *dohp = NULL;
@@ -467,12 +464,12 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
   data->state.async.ip_version = ip_version;
   data->state.async.hostname = strdup(hostname);
   if(!data->state.async.hostname)
-    return NULL;
+    return CURLE_OUT_OF_MEMORY;
 
   /* start clean, consider allocating this struct on demand */
   data->state.async.doh = dohp = calloc(1, sizeof(struct doh_probes));
   if(!dohp)
-    return NULL;
+    return CURLE_OUT_OF_MEMORY;
 
   for(i = 0; i < DOH_SLOT_COUNT; ++i) {
     dohp->probe_resp[i].probe_mid = UINT_MAX;
@@ -527,12 +524,11 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
     dohp->pending++;
   }
 #endif
-  *waitp = TRUE; /* this never returns synchronously */
-  return NULL;
+  return CURLE_OK;
 
 error:
   Curl_doh_cleanup(data);
-  return NULL;
+  return result;
 }
 
 static DOHcode doh_skipqname(const unsigned char *doh, size_t dohlen,
@@ -1300,6 +1296,8 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
         result = Curl_dnscache_add(data, dns);
         *dnsp = data->state.async.dns;
       }
+      else
+        Curl_freeaddrinfo(ai);
     } /* address processing done */
 
     /* All done */
index 3fd7de2c1c57238e3cdb9f3e4bad8d783ba564cd..726fb9f7355702151b821123bab3ac22a4855cba 100644 (file)
--- a/lib/doh.h
+++ b/lib/doh.h
@@ -112,15 +112,12 @@ struct doh_probes {
 };
 
 /*
- * Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name
- * and returns a 'Curl_addrinfo *' with the address information.
+ * Curl_doh() starts a name resolve using DoH (DNS-over-HTTPS). It resolves a
+ * name and returns a 'Curl_addrinfo *' with the address information.
  */
 
-struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
-                               const char *hostname,
-                               int port,
-                               int ip_version,
-                               int *waitp);
+CURLcode Curl_doh(struct Curl_easy *data, const char *hostname,
+                  int port, int ip_version);
 
 CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                               struct Curl_dns_entry **dns);
index d5f753f4b4a7e2993ec2c8958593d3b7f037c1c4..4c1bb9236776f5a5c9fe3941f0e71548dd33d54e 100644 (file)
@@ -509,10 +509,8 @@ Curl_dnscache_mk_entry(struct Curl_easy *data,
   /* shuffle addresses if requested */
   if(data->set.dns_shuffle_addresses) {
     CURLcode result = Curl_shuffle_addr(data, &addr);
-    if(result) {
-      Curl_freeaddrinfo(addr);
+    if(result)
       return NULL;
-    }
   }
 #else
   (void)data;
@@ -522,10 +520,8 @@ Curl_dnscache_mk_entry(struct Curl_easy *data,
 
   /* Create a new cache entry */
   dns = calloc(1, sizeof(struct Curl_dns_entry) + hostlen);
-  if(!dns) {
-    Curl_freeaddrinfo(addr);
+  if(!dns)
     return NULL;
-  }
 
   dns->refcount = 1; /* the cache has the first reference */
   dns->addr = addr; /* this is the address(es) */
@@ -569,6 +565,7 @@ dnscache_add_addr(struct Curl_easy *data,
   dns2 = Curl_hash_add(&dnscache->entries, entry_id, entry_len + 1,
                        (void *)dns);
   if(!dns2) {
+    dns->addr = NULL;
     dnscache_entry_free(dns);
     return NULL;
   }
@@ -744,40 +741,6 @@ static bool tailmatch(const char *full, size_t flen,
   return curl_strnequal(part, &full[flen - plen], plen);
 }
 
-static struct Curl_addrinfo *
-convert_ipaddr_direct(const char *hostname, int port, bool *is_ipaddr)
-{
-  struct in_addr in;
-  *is_ipaddr = FALSE;
-  /* First check if this is an IPv4 address string */
-  if(curlx_inet_pton(AF_INET, hostname, &in) > 0) {
-    /* This is a dotted IP address 123.123.123.123-style */
-    *is_ipaddr = TRUE;
-#ifdef USE_RESOLVE_ON_IPS
-    (void)port;
-    return NULL;
-#else
-    return Curl_ip2addr(AF_INET, &in, hostname, port);
-#endif
-  }
-#ifdef USE_IPV6
-  else {
-    struct in6_addr in6;
-    /* check if this is an IPv6 address string */
-    if(curlx_inet_pton(AF_INET6, hostname, &in6) > 0) {
-      /* This is an IPv6 address literal */
-      *is_ipaddr = TRUE;
-#ifdef USE_RESOLVE_ON_IPS
-      return NULL;
-#else
-      return Curl_ip2addr(AF_INET6, &in6, hostname, port);
-#endif
-    }
-  }
-#endif /* USE_IPV6 */
-  return NULL;
-}
-
 static bool can_resolve_ip_version(struct Curl_easy *data, int ip_version)
 {
 #ifdef CURLRES_IPV6
@@ -841,10 +804,10 @@ CURLcode Curl_resolv(struct Curl_easy *data,
   struct Curl_dnscache *dnscache = dnscache_get(data);
   struct Curl_dns_entry *dns = NULL;
   struct Curl_addrinfo *addr = NULL;
-  int respwait = 0;
-  bool is_ipaddr;
+  bool respwait = FALSE;
   size_t hostname_len;
   bool keep_negative = TRUE; /* cache a negative result */
+  CURLcode result = CURLE_COULDNT_RESOLVE_HOST;
 
   *entry = NULL;
 
@@ -853,8 +816,11 @@ CURLcode Curl_resolv(struct Curl_easy *data,
 #else
   (void)allowDOH;
 #endif
-  if(!dnscache)
+  DEBUGASSERT(dnscache);
+  if(!dnscache) {
+    result = CURLE_BAD_FUNCTION_ARGUMENT;
     goto error;
+  }
 
   /* We should intentionally error and not resolve .onion TLDs */
   hostname_len = strlen(hostname);
@@ -874,6 +840,7 @@ CURLcode Curl_resolv(struct Curl_easy *data,
   dnscache_unlock(data, dnscache);
   if(dns) {
     infof(data, "Hostname %s was found in DNS cache", hostname);
+    result = CURLE_OK;
     goto out;
   }
 
@@ -882,7 +849,8 @@ CURLcode Curl_resolv(struct Curl_easy *data,
     void *resolver = NULL;
     int st;
 #ifdef CURLRES_ASYNCH
-    if(Curl_async_get_impl(data, &resolver))
+    result = Curl_async_get_impl(data, &resolver);
+    if(result)
       goto error;
 #endif
     Curl_set_in_callback(data, TRUE);
@@ -891,57 +859,58 @@ CURLcode Curl_resolv(struct Curl_easy *data,
     Curl_set_in_callback(data, FALSE);
     if(st) {
       keep_negative = FALSE;
+      result = CURLE_ABORTED_BY_CALLBACK;
       goto error;
     }
   }
 
-  /* shortcut literal IP addresses, if we are not told to resolve them. */
-  addr = convert_ipaddr_direct(hostname, port, &is_ipaddr);
-  if(addr)
-    goto out;
-
+  if(Curl_is_ipaddr(hostname)) {
 #ifndef USE_RESOLVE_ON_IPS
-  /* allowed to convert, hostname is IP address, then NULL means error */
-  if(is_ipaddr) {
-    keep_negative = FALSE;
-    goto error;
-  }
+    /* shortcut literal IP addresses, if we are not told to resolve them. */
+    result = Curl_str2addr(hostname, port, &addr);
+    if(result)
+      goto error;
+    goto out;
 #endif
+  }
 
-  /* Really need a resolver for hostname. */
-  if(ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data))
-    goto error;
-
-  if(!is_ipaddr &&
-     (curl_strequal(hostname, "localhost") ||
-      curl_strequal(hostname, "localhost.") ||
-      tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
-      tailmatch(hostname, hostname_len, STRCONST(".localhost.")))) {
+  if(curl_strequal(hostname, "localhost") ||
+     curl_strequal(hostname, "localhost.") ||
+     tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
+     tailmatch(hostname, hostname_len, STRCONST(".localhost."))) {
     addr = get_localhost(port, hostname);
+    result = addr ? CURLE_OK : CURLE_OUT_OF_MEMORY;
   }
 #ifndef CURL_DISABLE_DOH
-  else if(!is_ipaddr && allowDOH && data->set.doh) {
-    addr = Curl_doh(data, hostname, port, ip_version, &respwait);
+  else if(!Curl_is_ipaddr(hostname) && allowDOH && data->set.doh) {
+    result = Curl_doh(data, hostname, port, ip_version);
+    respwait = TRUE;
   }
 #endif
   else {
     /* Can we provide the requested IP specifics in resolving? */
-    if(!can_resolve_ip_version(data, ip_version))
+    if(!can_resolve_ip_version(data, ip_version)) {
+      result = CURLE_COULDNT_RESOLVE_HOST;
       goto error;
+    }
 
 #ifdef CURLRES_ASYNCH
-    addr = Curl_async_getaddrinfo(data, hostname, port, ip_version, &respwait);
+    result = Curl_async_getaddrinfo(data, hostname, port, ip_version);
+    respwait = TRUE;
 #else
-    respwait = 0; /* no async waiting here */
+    respwait = FALSE; /* no async waiting here */
     addr = Curl_sync_getaddrinfo(data, hostname, port, ip_version);
+    if(addr)
+      result = CURLE_OK;
 #endif
   }
 
 out:
-  /* We either have found a `dns` or looked up the `addr`
-   * or `respwait` is set for an async operation.
-   * Everything else is a failure to resolve. */
-  if(dns) {
+  /* We either have found a `dns` or looked up the `addr` or `respwait` is set
+   * for an async operation. Everything else is a failure to resolve. */
+  if(result)
+    ;
+  else if(dns) {
     if(!dns->addr) {
       infof(data, "Negative DNS entry");
       dns->refcount--;
@@ -955,7 +924,12 @@ out:
     dns = Curl_dnscache_mk_entry(data, addr, hostname, 0, port, FALSE);
     if(!dns || Curl_dnscache_add(data, dns)) {
       /* this is OOM or similar, do not store such negative resolves */
+      Curl_freeaddrinfo(addr);
+      if(dns)
+        /* avoid a dangling pointer to addr in the dying dns entry */
+        dns->addr = NULL;
       keep_negative = FALSE;
+      result = CURLE_OUT_OF_MEMORY;
       goto error;
     }
     show_resolve_info(data, dns);
@@ -967,6 +941,7 @@ out:
       *entry = dns;
       return dns ? CURLE_OK : CURLE_AGAIN;
     }
+    result = CURLE_COULDNT_RESOLVE_HOST;
   }
 error:
   if(dns)
@@ -974,7 +949,8 @@ error:
   Curl_async_shutdown(data);
   if(keep_negative)
     store_negative_resolve(data, hostname, port);
-  return CURLE_COULDNT_RESOLVE_HOST;
+  DEBUGASSERT(result);
+  return result;
 }
 
 CURLcode Curl_resolv_blocking(struct Curl_easy *data,
@@ -1338,6 +1314,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       while(*host) {
         struct Curl_str target;
         struct Curl_addrinfo *ai;
+        CURLcode result;
 
         if(!curlx_str_single(&host, '[')) {
           if(curlx_str_until(&host, &target, MAX_IPADR_LEN, ']') ||
@@ -1368,8 +1345,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         memcpy(address, curlx_str(&target), curlx_strlen(&target));
         address[curlx_strlen(&target)] = '\0';
 
-        ai = Curl_str2addr(address, (int)port);
-        if(!ai) {
+        result = Curl_str2addr(address, (int)port, &ai);
+        if(result) {
           infof(data, "Resolve address '%s' found illegal", address);
           goto err;
         }
@@ -1428,11 +1405,12 @@ err:
       /* put this new host in the cache */
       dns = dnscache_add_addr(data, dnscache, head, curlx_str(&source),
                               curlx_strlen(&source), (int)port, permanent);
-      if(dns) {
+      if(dns)
         /* release the returned reference; the cache itself will keep the
          * entry alive: */
         dns->refcount--;
-      }
+      else
+        Curl_freeaddrinfo(head);
 
       dnscache_unlock(data, dnscache);
 
index 07392cbd86b75ed642daaf16041a37e06bf4f9e9..a213a1c493b3ea5b5cba0b6fe5366be348a0e0d7 100644 (file)
@@ -82,9 +82,9 @@ static CURLcode test_lib655(const char *URL)
 
   /* this should fail */
   res = curl_easy_perform(curl);
-  if(res != CURLE_COULDNT_RESOLVE_HOST) {
+  if(res != CURLE_ABORTED_BY_CALLBACK) {
     curl_mfprintf(stderr, "curl_easy_perform should have returned "
-                  "CURLE_COULDNT_RESOLVE_HOST but instead returned error %d\n",
+                  "CURLE_ABORTED_BY_CALLBACK but instead returned error %d\n",
                   res);
     if(res == CURLE_OK)
       res = TEST_ERR_FAILURE;