- 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
/*
* 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 */
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
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:
/*
* 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
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 */
* 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 */
#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
* 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;
DEBUGASSERT(inaddr && hostname);
namelen = strlen(hostname) + 1;
+ *addrp = NULL;
if(af == AF_INET)
addrsize = sizeof(struct sockaddr_in);
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 */
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
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,
}
/*
- * 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
+ * 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 result = CURLE_OK;
struct doh_probes *dohp = NULL;
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;
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,
result = Curl_dnscache_add(data, dns);
*dnsp = data->state.async.dns;
}
+ else
+ Curl_freeaddrinfo(ai);
} /* address processing done */
/* All done */
};
/*
- * 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);
/* 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;
/* 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) */
dns2 = Curl_hash_add(&dnscache->entries, entry_id, entry_len + 1,
(void *)dns);
if(!dns2) {
+ dns->addr = NULL;
dnscache_entry_free(dns);
return NULL;
}
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
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;
#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);
dnscache_unlock(data, dnscache);
if(dns) {
infof(data, "Hostname %s was found in DNS cache", hostname);
+ result = CURLE_OK;
goto out;
}
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);
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--;
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);
*entry = dns;
return dns ? CURLE_OK : CURLE_AGAIN;
}
+ result = CURLE_COULDNT_RESOLVE_HOST;
}
error:
if(dns)
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,
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, ']') ||
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;
}
/* 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);
/* 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;