diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
index ef4bbcbcc6..106c7333f5 100644
--- a/lib/asyn-ares.c
+++ b/lib/asyn-ares.c
@@ -188,25 +188,6 @@ out:
return result;
}
-/*
- * async_ares_cleanup() cleans up async resolver data.
- */
-static void async_ares_cleanup(struct Curl_resolv_async *async)
-{
- struct async_ares_ctx *ares = &async->ares;
- if(ares->res_A) {
- Curl_freeaddrinfo(ares->res_A);
- ares->res_A = NULL;
- }
- if(ares->res_AAAA) {
- Curl_freeaddrinfo(ares->res_AAAA);
- ares->res_AAAA = NULL;
- }
-#ifdef USE_HTTPSRR
- Curl_httpsrr_cleanup(&ares->hinfo);
-#endif
-}
-
void Curl_async_ares_shutdown(struct Curl_easy *data,
struct Curl_resolv_async *async)
{
@@ -227,7 +208,19 @@ void Curl_async_ares_destroy(struct Curl_easy *data,
ares_destroy(ares->channel);
ares->channel = NULL;
}
- async_ares_cleanup(async);
+ if(ares->res_A) {
+ Curl_freeaddrinfo(ares->res_A);
+ ares->res_A = NULL;
+ }
+ if(ares->res_AAAA) {
+ Curl_freeaddrinfo(ares->res_AAAA);
+ ares->res_AAAA = NULL;
+ }
+#ifdef USE_HTTPSRR
+ curlx_safefree(ares->https_name);
+ Curl_httpsrr_destroy(ares->hinfo);
+ ares->hinfo = NULL;
+#endif
}
CURLcode Curl_async_pollset(struct Curl_easy *data,
@@ -259,6 +252,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
struct Curl_dns_entry **pdns)
{
struct async_ares_ctx *ares = &async->ares;
+ struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK;
DEBUGASSERT(pdns);
@@ -279,34 +273,31 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
/* all c-ares operations done, what is the result to report? */
result = ares->result;
if(ares->ares_status == ARES_SUCCESS && !result) {
- struct Curl_dns_entry *dns =
- Curl_dnscache_mk_entry2(data, async->dns_queries,
- &ares->res_AAAA, &ares->res_A,
- async->hostname, async->port);
- if(!dns) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-#ifdef HTTPSRR_WORKS
- if(async->dns_queries & CURL_DNSQ_HTTPS) {
- if(ares->hinfo.complete) {
- struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&ares->hinfo);
- if(!lhrr)
- result = CURLE_OUT_OF_MEMORY;
- else
- Curl_dns_entry_set_https_rr(dns, lhrr);
+
+ if(CURL_DNSQ_IS_ADDR(async->dns_queries)) {
+ dns = Curl_dnsc_mk_addr2(data, async->dns_queries,
+ &ares->res_AAAA, &ares->res_A,
+ async->hostname, async->port);
+ if(!dns) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+#ifdef HTTPSRR_WORKS
+ if(!dns && (async->dns_queries & CURL_DNSQ_HTTPS)) {
+ dns = Curl_dnsc_mk_https(data, &ares->hinfo,
+ async->hostname, async->port);
+ if(!dns) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
- else
- Curl_dns_entry_set_https_rr(dns, NULL);
}
#endif
- if(!result) {
- *pdns = dns;
- }
}
/* if we have not found anything, report the proper
* CURLE_COULDNT_RESOLVE_* code */
- if(!result && !*pdns) {
+ if(!result && !dns) {
const char *msg = NULL;
/* only an authoritative "does not exist" answer from every query
may be cached as a negative entry, not transient failures like
@@ -319,13 +310,16 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
result = Curl_async_failed(data, async, msg);
}
- CURL_TRC_DNS(data, "ares: is_resolved() result=%d, dns=%sfound",
- (int)result, *pdns ? "" : "not ");
- async_ares_cleanup(async);
+ CURL_TRC_DNS(data, "[%s] ares_take_result, result=%d, ares_result=%d, "
+ "ares_status=%d, dns=%sfound",
+ Curl_resolv_query_str(async->dns_queries),
+ (int)result, (int)ares->result, ares->ares_status,
+ dns ? "" : "not ");
out:
if(result != CURLE_AGAIN)
ares->result = result;
+ *pdns = result ? NULL : dns;
return result;
}
@@ -400,7 +394,7 @@ const struct Curl_https_rrinfo *Curl_async_get_https(
struct Curl_resolv_async *async)
{
if(Curl_async_knows_https(data, async))
- return &async->ares.hinfo;
+ return async->ares.hinfo;
return NULL;
}
@@ -626,6 +620,9 @@ static void async_ares_rr_done(void *user_data, ares_status_t status,
async->dns_responses |= CURL_DNSQ_HTTPS;
async->queries_ongoing--;
async->done = !async->queries_ongoing;
+ ares->ares_status = status;
+ if((status != ARES_ENOTFOUND) && (status != ARES_ENODATA))
+ ares->transient_err = TRUE;
if((ARES_SUCCESS != status) || !dnsrec)
return;
ares->result = Curl_httpsrr_from_ares(dnsrec, &ares->hinfo);
@@ -677,7 +674,7 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
struct ares_addrinfo_hints hints;
memset(&hints, 0, sizeof(hints));
- CURL_TRC_DNS(data, "ares: query AAAA records for %s", async->hostname);
+ CURL_TRC_DNS(data, "[AAAA] ares: query records for %s", async->hostname);
hints.ai_family = PF_INET6;
hints.ai_socktype = socktype;
hints.ai_flags = ARES_AI_NUMERICSERV;
@@ -691,7 +688,7 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
struct ares_addrinfo_hints hints;
memset(&hints, 0, sizeof(hints));
- CURL_TRC_DNS(data, "ares: query A records for %s", async->hostname);
+ CURL_TRC_DNS(data, "[A] ares: query records for %s", async->hostname);
hints.ai_family = PF_INET;
hints.ai_socktype = socktype;
hints.ai_flags = ARES_AI_NUMERICSERV;
@@ -701,20 +698,19 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
}
#ifdef USE_HTTPSRR
- memset(&ares->hinfo, 0, sizeof(ares->hinfo));
if(async->dns_queries & CURL_DNSQ_HTTPS) {
- char *rrname = NULL;
+ ares->https_name = NULL;
if(async->port != 443) {
- rrname = curl_maprintf("_%d._https.%s", async->port, async->hostname);
- if(!rrname)
+ ares->https_name = curl_maprintf("_%d._https.%s",
+ async->port, async->hostname);
+ if(!ares->https_name)
return CURLE_OUT_OF_MEMORY;
}
- CURL_TRC_DNS(data, "ares: query HTTPS records for %s",
- rrname ? rrname : async->hostname);
- ares->hinfo.rrname = rrname;
+ CURL_TRC_DNS(data, "[HTTPS] ares: query records for %s",
+ ares->https_name ? ares->https_name : async->hostname);
async->queries_ongoing++;
ares_query_dnsrec(ares->channel,
- rrname ? rrname : async->hostname,
+ ares->https_name ? ares->https_name : async->hostname,
ARES_CLASS_IN, ARES_REC_TYPE_HTTPS,
async_ares_rr_done, async, NULL);
}
diff --git a/lib/asyn-base.c b/lib/asyn-base.c
index 62cb0effe4..b140b0f5b9 100644
--- a/lib/asyn-base.c
+++ b/lib/asyn-base.c
@@ -256,9 +256,10 @@ CURLcode Curl_async_failed(struct Curl_easy *data,
}
#endif
- failf(data, "Could not resolve %s: %s%s%s%s",
- host_or_proxy, async->hostname,
- detail ? " (" : "", detail ? detail : "", detail ? ")" : "");
+ if(async->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))
+ failf(data, "Could not resolve %s: %s%s%s%s",
+ host_or_proxy, async->hostname,
+ detail ? " (" : "", detail ? detail : "", detail ? ")" : "");
return result;
}
diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c
index 29e9b138d3..a3166f52f8 100644
--- a/lib/asyn-thrdd.c
+++ b/lib/asyn-thrdd.c
@@ -242,8 +242,7 @@ static CURLcode async_rr_start(struct Curl_easy *data,
}
#endif
- memset(&thrdd->rr.hinfo, 0, sizeof(thrdd->rr.hinfo));
- thrdd->rr.hinfo.rrname = rrname;
+ thrdd->rr.https_name = rrname;
async->queries_ongoing++;
ares_query_dnsrec(thrdd->rr.channel,
rrname ? rrname : async->hostname, ARES_CLASS_IN,
@@ -291,7 +290,8 @@ void Curl_async_thrdd_destroy(struct Curl_easy *data,
ares_destroy(async->thrdd.rr.channel);
async->thrdd.rr.channel = NULL;
}
- Curl_httpsrr_cleanup(&async->thrdd.rr.hinfo);
+ curlx_safefree(async->thrdd.rr.https_name);
+ Curl_httpsrr_destroy(async->thrdd.rr.hinfo);
#endif
async_thrdd_item_destroy(async->thrdd.res_A);
async->thrdd.res_A = NULL;
@@ -668,6 +668,9 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
#endif
out:
+ if(!async->queries_ongoing)
+ async->done = TRUE;
+
if(result)
CURL_TRC_DNS(data, "error queueing query %s:%d -> %d",
async->hostname, async->port, (int)result);
@@ -769,7 +772,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
if((thrdd->res_A && thrdd->res_A->res) ||
(thrdd->res_AAAA && thrdd->res_AAAA->res)) {
- dns = Curl_dnscache_mk_entry2(
+ dns = Curl_dnsc_mk_addr2(
data, async->dns_queries,
thrdd->res_A ? &thrdd->res_A->res : NULL,
thrdd->res_AAAA ? &thrdd->res_AAAA->res : NULL,
@@ -778,22 +781,19 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+ }
#ifdef USE_HTTPSRR_ARES
- if(thrdd->rr.channel) {
- struct Curl_https_rrinfo *lhrr = NULL;
- if(thrdd->rr.hinfo.complete) {
- lhrr = Curl_httpsrr_dup_move(&thrdd->rr.hinfo);
- if(!lhrr) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
- }
- Curl_httpsrr_trace(data, lhrr);
- Curl_dns_entry_set_https_rr(dns, lhrr);
+ if(!dns && thrdd->rr.channel) {
+ Curl_httpsrr_trace(data, thrdd->rr.hinfo);
+ dns = Curl_dnsc_mk_https(data, &thrdd->rr.hinfo,
+ async->hostname, async->port);
+ if(!dns) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
-#endif
}
+#endif
if(dns) {
*pdns = dns;
@@ -864,7 +864,7 @@ const struct Curl_https_rrinfo *Curl_async_get_https(
{
#ifdef USE_HTTPSRR_ARES
if(Curl_async_knows_https(data, async))
- return &async->thrdd.rr.hinfo;
+ return async->thrdd.rr.hinfo;
#else
(void)data;
(void)async;
diff --git a/lib/asyn.h b/lib/asyn.h
index e4bc05e0dd..76996f888a 100644
--- a/lib/asyn.h
+++ b/lib/asyn.h
@@ -120,7 +120,8 @@ struct async_ares_ctx {
CURLcode result; /* CURLE_OK or error handling response */
struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
#ifdef USE_HTTPSRR
- struct Curl_https_rrinfo hinfo;
+ char *https_name;
+ struct Curl_https_rrinfo *hinfo;
#endif
BIT(transient_err); /* an A/AAAA query failed without the resolver
answering that the name does not exist */
@@ -144,7 +145,8 @@ struct async_thrdd_ctx {
#if defined(USE_HTTPSRR) && defined(USE_ARES)
struct {
ares_channel channel;
- struct Curl_https_rrinfo hinfo;
+ char *https_name;
+ struct Curl_https_rrinfo *hinfo;
} rr;
#endif
};
diff --git a/lib/cf-dns.c b/lib/cf-dns.c
index 6388d65a9e..4152a00c17 100644
--- a/lib/cf-dns.c
+++ b/lib/cf-dns.c
@@ -30,6 +30,7 @@
#include "dnscache.h"
#include "httpsrr.h"
#include "curl_trc.h"
+#include "multiif.h"
#include "progress.h"
#include "url.h"
#include "cf-dns.h"
@@ -44,7 +45,6 @@ struct cf_dns_ctx {
uint8_t transport;
BIT(started);
BIT(announced);
- BIT(complete_resolve);
BIT(for_proxy);
};
@@ -52,8 +52,7 @@ static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data,
struct Curl_peer *peer,
uint8_t dns_queries,
uint8_t transport,
- bool for_proxy,
- bool complete_resolve)
+ bool for_proxy)
{
struct cf_dns_ctx *ctx;
@@ -65,10 +64,10 @@ static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data,
ctx->dns_queries = dns_queries;
ctx->transport = transport;
ctx->for_proxy = for_proxy;
- ctx->complete_resolve = complete_resolve;
- CURL_TRC_DNS(data, "created DNS filter for %s:%u, transport=%x, queries=%x",
- peer->hostname, peer->port, ctx->transport, ctx->dns_queries);
+ CURL_TRC_DNS(data, "[%s] created DNS filter for %s:%u, transport=%x",
+ Curl_resolv_query_str(ctx->dns_queries),
+ peer->hostname, peer->port, ctx->transport);
return ctx;
}
@@ -131,22 +130,28 @@ static void cf_dns_report(struct Curl_cfilter *cf,
}
else {
curlx_dyn_init(&tmp, 1024);
- infof(data, "Host %s:%u was resolved.", dns->hostname, dns->port);
+ if(CURL_DNSQ_IS_ADDR(ctx->dns_queries)) {
+ infof(data, "Host %s:%u was resolved.", dns->hostname, dns->port);
#ifdef CURLRES_IPV6
- cf_dns_report_addr(data, &tmp, "IPv6: ", AF_INET6, dns->addr);
+ cf_dns_report_addr(data, &tmp, "IPv6: ", AF_INET6, dns->addr);
#endif
- cf_dns_report_addr(data, &tmp, "IPv4: ", AF_INET, dns->addr);
+ cf_dns_report_addr(data, &tmp, "IPv4: ", AF_INET, dns->addr);
+ }
#ifdef USE_HTTPSRR
- if(!dns->hinfo)
- infof(data, "HTTPS-RR: -");
- else if(!Curl_httpsrr_applicable(data, dns->hinfo))
- infof(data, "HTTPS-RR: not applicable");
- else {
- CURLcode result = Curl_httpsrr_print(&tmp, dns->hinfo);
- if(!result)
- infof(data, "HTTPS-RR: %s", curlx_dyn_ptr(&tmp));
- else
- infof(data, "Error printing HTTPS-RR information");
+ else if(ctx->dns_queries & CURL_DNSQ_HTTPS) {
+ if(!dns->hinfo)
+ infof(data, "HTTPS-RR %s:%u: -", dns->hostname, dns->port);
+ else if(!Curl_httpsrr_applicable(data, dns->hinfo))
+ infof(data, "HTTPS-RR %s:%u: not applicable",
+ dns->hostname, dns->port);
+ else {
+ CURLcode result = Curl_httpsrr_print(&tmp, dns->hinfo);
+ if(!result)
+ infof(data, "HTTPS-RR %s:%u: %s",
+ dns->hostname, dns->port, curlx_dyn_ptr(&tmp));
+ else
+ infof(data, "Error printing HTTPS-RR information");
+ }
}
#endif
curlx_dyn_free(&tmp);
@@ -165,25 +170,40 @@ static CURLcode cf_dns_start(struct Curl_cfilter *cf,
{
struct cf_dns_ctx *ctx = cf->ctx;
timediff_t timeout_ms = Curl_timeleft_ms(data);
- CURLcode result;
+ CURLcode result = CURLE_OK;
*pdns = NULL;
- CURL_TRC_CF(data, cf, "cf_dns_start %s %s:%u",
+ CURL_TRC_CF(data, cf, "[%s] cf_dns_start %s %s:%u",
+ Curl_resolv_query_str(ctx->dns_queries),
ctx->peer->unix_socket ? "unix-domain-socket" : "host",
ctx->peer->hostname, ctx->peer->port);
if(ctx->peer->unix_socket)
- ctx->dns_queries = 0;
- else if(Curl_is_ipv4addr(ctx->peer->hostname))
- ctx->dns_queries |= CURL_DNSQ_A;
+ ctx->dns_queries = CURL_DNSQ_A; /* treat it like an A resolve */
+
+ if(CURL_DNSQ_IS_ADDR(ctx->dns_queries)) {
+ if(Curl_is_ipv4addr(ctx->peer->hostname))
+ ctx->dns_queries |= CURL_DNSQ_A;
#ifdef USE_IPV6
- else if(ctx->peer->ipv6)
- ctx->dns_queries |= CURL_DNSQ_AAAA;
+ else if(ctx->peer->ipv6)
+ ctx->dns_queries |= CURL_DNSQ_AAAA;
#endif
- result = Curl_resolv(data, ctx->peer, ctx->dns_queries, ctx->transport,
- (bool)ctx->for_proxy, timeout_ms,
- &ctx->resolv_id, pdns);
+ result = Curl_resolv(data, ctx->peer, ctx->dns_queries, ctx->transport,
+ (bool)ctx->for_proxy, timeout_ms,
+ &ctx->resolv_id, pdns);
+ }
+#ifdef USE_HTTPSRR
+ else if(ctx->dns_queries == CURL_DNSQ_HTTPS) {
+ result = Curl_resolv_https(data, ctx->peer, (bool)ctx->for_proxy,
+ timeout_ms, &ctx->resolv_id, pdns);
+ }
+#endif
+ else {
+ failf(data, "unsupported DNS queries %x", ctx->dns_queries);
+ return CURLE_FAILED_INIT;
+ }
+
DEBUGASSERT(!result || !*pdns);
if(!result) { /* resolved right away, either sync or from dnscache */
DEBUGASSERT(*pdns);
@@ -201,7 +221,8 @@ static CURLcode cf_dns_start(struct Curl_cfilter *cf,
}
else {
DEBUGASSERT(result);
- failf(data, "Could not resolve: %s", ctx->peer->hostname);
+ if(ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))
+ failf(data, "Could not resolve: %s", ctx->peer->hostname);
return result;
}
}
@@ -222,8 +243,6 @@ static bool cf_dns_ready_to_connect(struct Curl_cfilter *cf,
/* We want AAAA answer as we prefer IPv6. If a sub-filter desires
* HTTPS-RR, we check for that query as well. */
uint8_t wanted_answers = CURL_DNSQ_AAAA;
- if(Curl_conn_cf_wants_httpsrr(cf, data))
- wanted_answers |= CURL_DNSQ_HTTPS;
/* Note: if a query was never started, it is considered to have
* an answer (e.g. a negative one). */
@@ -246,6 +265,7 @@ static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
bool *done)
{
struct cf_dns_ctx *ctx = cf->ctx;
+ bool ip_query = (ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA));
if(cf->connected) {
*done = TRUE;
@@ -263,7 +283,8 @@ static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
Curl_resolv_take_result(data, ctx->resolv_id, &ctx->dns);
}
- if(ctx->resolv_result) {
+ if(ctx->resolv_result && ip_query) {
+ /* failing A|AAAA resolves is a hard failure. */
CURL_TRC_CF(data, cf, "error resolving: %d", (int)ctx->resolv_result);
return ctx->resolv_result;
}
@@ -289,13 +310,9 @@ static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
DEBUGASSERT(sub_done);
}
- /* sub filter chain is connected */
+ /* sub filter chain is connected, this means the filter has done
+ * its work and is connected as well, if it has results or not. */
CURL_TRC_CF(data, cf, "connected filter chain below");
- if(ctx->complete_resolve && !ctx->dns && !ctx->resolv_result) {
- /* This filter only connects when it has resolved everything. */
- CURL_TRC_CF(data, cf, "delay connect until resolve complete");
- return CURLE_OK;
- }
*done = TRUE;
cf->connected = TRUE;
Curl_resolv_destroy(data, ctx->resolv_id);
@@ -315,8 +332,24 @@ static CURLcode cf_dns_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
#ifdef USE_CURL_ASYNC
- if(!cf->connected)
+ if(!cf->connected) {
+ /* The pollset only works when we have started the resolving.
+ * Otherwise we might wait on the WAKEUP socketpair forever.
+ * Since DNS filters can be added in the middle of a connect
+ * attempt, they are not always started that way. */
+ struct cf_dns_ctx *ctx = cf->ctx;
+ if(!ctx->started) {
+ CURL_TRC_CF(data, cf, "adjust_pollset, starting %s:%u queries=%s",
+ ctx->peer->hostname, ctx->peer->port,
+ Curl_resolv_query_str(ctx->dns_queries));
+ ctx->started = TRUE;
+ ctx->resolv_result = cf_dns_start(cf, data, &ctx->dns);
+ if(ctx->resolv_result || ctx->dns) {
+ Curl_multi_mark_dirty(data);
+ }
+ }
return Curl_resolv_pollset(data, ps);
+ }
#else
(void)cf;
(void)data;
@@ -351,7 +384,7 @@ static CURLcode cf_dns_cntrl(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_dns = {
"DNS",
- CF_TYPE_SETUP,
+ CF_TYPE_SETUP | CF_TYPE_DNS,
CURL_LOG_LVL_NONE,
cf_dns_destroy,
cf_dns_connect,
@@ -371,8 +404,7 @@ static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
struct Curl_peer *peer,
uint8_t dns_queries,
uint8_t transport,
- bool for_proxy,
- bool complete_resolve)
+ bool for_proxy)
{
struct Curl_cfilter *cf = NULL;
struct cf_dns_ctx *ctx;
@@ -380,7 +412,7 @@ static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
(void)data;
ctx = cf_dns_ctx_create(data, peer, dns_queries, transport,
- for_proxy, complete_resolve);
+ for_proxy);
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -397,12 +429,12 @@ out:
/* Adds a "resolv" filter at the top of the connection's filter chain.
* The filter will resolve the peer on the first connect attempt. */
-CURLcode Curl_cf_dns_add(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
- struct Curl_peer *peer,
- uint8_t dns_queries,
- uint8_t transport)
+static CURLcode cf_dns_add(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer,
+ uint8_t dns_queries,
+ uint8_t transport)
{
struct Curl_cfilter *cf = NULL;
bool for_proxy = FALSE;
@@ -415,8 +447,7 @@ CURLcode Curl_cf_dns_add(struct Curl_easy *data,
(peer == conn->http_proxy.peer);
#endif
- result = cf_dns_create(&cf, data, peer, dns_queries, transport,
- for_proxy, FALSE);
+ result = cf_dns_create(&cf, data, peer, dns_queries, transport, for_proxy);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -430,18 +461,16 @@ out:
* See socks.c on how this is used to make a non-blocking DNS
* resolve during connect.
*/
-CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
- struct Curl_easy *data,
- uint8_t dns_queries,
- struct Curl_peer *peer,
- uint8_t transport,
- bool complete_resolve)
+static CURLcode cf_dns_insert_after(struct Curl_cfilter *cf_at,
+ struct Curl_easy *data,
+ struct Curl_peer *peer,
+ uint8_t dns_queries,
+ uint8_t transport)
{
struct Curl_cfilter *cf;
CURLcode result;
- result = cf_dns_create(&cf, data, peer, dns_queries, transport,
- FALSE, complete_resolve);
+ result = cf_dns_create(&cf, data, peer, dns_queries, transport, FALSE);
if(result)
return result;
@@ -449,38 +478,93 @@ CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
return CURLE_OK;
}
-/* Return the resolv result from the first "resolv" filter, starting
- * the given filter `cf` downwards.
- */
-static CURLcode cf_dns_result(struct Curl_cfilter *cf,
- struct Curl_peer *peer)
+static CURLcode cf_dns_add_resolve(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer,
+ uint8_t dns_queries,
+ uint8_t transport)
{
- for(; cf; cf = cf->next) {
+ struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
+ struct Curl_cfilter *cf_dns = NULL;
+ bool is_addr = CURL_DNSQ_IS_ADDR(dns_queries);
+
+ if((dns_queries & CURL_DNSQ_HTTPS) &&
+ Curl_is_ipaddr(peer->hostname)) {
+ dns_queries = (uint8_t)(dns_queries & ~CURL_DNSQ_HTTPS);
+ }
+
+ for(; cf && dns_queries; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
+ cf_dns = cf;
if(Curl_peer_same_destination(ctx->peer, peer)) {
- if(ctx->dns || ctx->resolv_result)
- return ctx->resolv_result;
- return CURLE_AGAIN;
+ /* subtract queries already being scheduled/ongoing */
+ dns_queries = (uint8_t)(~ctx->dns_queries & dns_queries);
+ if(!dns_queries) { /* already there */
+ return CURLE_OK;
+ }
+ else if(is_addr && !ctx->started &&
+ CURL_DNSQ_IS_ADDR(ctx->dns_queries)) {
+ ctx->dns_queries |= dns_queries;
+ CURL_TRC_DNS(data, "[%s] added queries=%s for %s:%u",
+ Curl_resolv_query_str(ctx->dns_queries),
+ Curl_resolv_query_str(dns_queries),
+ peer->hostname, peer->port);
+ return CURLE_OK;
+ }
}
- return CURLE_OK; /* ok, but no results */
}
}
- return CURLE_FAILED_INIT;
+
+ if(dns_queries) {
+ /* No existing filter is handling these, add a new DNS filter
+ * (after the last one if there was one already. FCFS. */
+ if(cf_dns)
+ return cf_dns_insert_after(cf_dns, data, peer, dns_queries, transport);
+ else
+ return cf_dns_add(data, conn, sockindex, peer, dns_queries, transport);
+ }
+ return CURLE_OK;
}
-/* Return the result of the DNS resolution for peer. Searches for a "resolv"
- * filter from the top of the filter chain down. Returns
+CURLcode Curl_conn_dns_add_addr_resolve(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer,
+ uint8_t dns_queries,
+ uint8_t transport)
+{
+ /* should only have address query bits */
+ DEBUGASSERT(!(dns_queries & ~CURL_DNSQ_ADDR));
+ return cf_dns_add_resolve(data, conn, sockindex, peer,
+ (dns_queries & CURL_DNSQ_ADDR), transport);
+}
+
+/* Return the result of the DNS address resolution for peer.
+ * Searches for a DNS filter from the top of the filter chain down. Returns
* - CURLE_AGAIN when not done yet
* - CURLE_OK when DNS was successfully resolved
* - CURLR_FAILED_INIT when no resolv filter was found
* - error returned by the DNS resolv
*/
-CURLcode Curl_conn_dns_result(struct connectdata *conn,
- int sockindex,
- struct Curl_peer *peer)
+CURLcode Curl_conn_dns_addr_result(struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer)
{
- return cf_dns_result(conn->cfilter[sockindex], peer);
+ struct Curl_cfilter *cf = conn->cfilter[sockindex];
+ for(; cf; cf = cf->next) {
+ if(cf->cft == &Curl_cft_dns) {
+ struct cf_dns_ctx *ctx = cf->ctx;
+ if(Curl_peer_same_destination(ctx->peer, peer) &&
+ (ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))) {
+ if(ctx->dns || ctx->resolv_result)
+ return ctx->resolv_result;
+ return CURLE_AGAIN;
+ }
+ }
+ }
+ return CURLE_FAILED_INIT; /* no one is resolving */
}
static const struct Curl_addrinfo *cf_dns_get_nth_ai(
@@ -508,20 +592,25 @@ static const struct Curl_addrinfo *cf_dns_get_nth_ai(
}
/* Return the addrinfo at `index` for the given `family` from the
- * first "resolve" filter underneath `cf`. If the DNS resolving is
+ * first "resolve" filter at the connection. If the DNS resolving is
* not done yet or if no address for the family exists, returns NULL.
*/
-const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct Curl_peer *peer,
- int ai_family,
- unsigned int index)
+const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
+ struct Curl_peer *peer,
+ int sockindex,
+ int ai_family,
+ unsigned int index)
{
- (void)data;
+ struct connectdata *conn = data->conn;
+ struct Curl_cfilter *cf = conn->cfilter[sockindex];
+
for(; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
- if(Curl_peer_same_destination(ctx->peer, peer)) {
+ if(Curl_peer_same_destination(ctx->peer, peer) &&
+ (ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))) {
+ CURL_TRC_CF(data, cf, "get %uth result for %s:%u, family=%d, dns=%d",
+ index, peer->hostname, peer->port, ai_family, !!ctx->dns);
if(ctx->resolv_result)
return NULL;
else if(ctx->dns)
@@ -534,22 +623,16 @@ const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
return NULL;
}
-/* Return the addrinfo at `index` for the given `family` from the
- * first "resolve" filter at the connection. If the DNS resolving is
- * not done yet or if no address for the family exists, returns NULL.
- */
-const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
- struct Curl_peer *peer,
- int sockindex,
- int ai_family,
- unsigned int index)
+#ifdef USE_HTTPSRR
+CURLcode Curl_conn_dns_add_https_resolve(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer)
{
- struct connectdata *conn = data->conn;
- return Curl_cf_dns_get_ai(conn->cfilter[sockindex], data, peer,
- ai_family, index);
+ return cf_dns_add_resolve(data, conn, sockindex, peer,
+ CURL_DNSQ_HTTPS, conn->transport_wanted);
}
-#ifdef USE_HTTPSRR
/* Return the HTTPS-RR info from the first "resolve" filter at the
* connection. If the DNS resolving is not done yet or if there
* is no HTTPS-RR info, returns NULL.
@@ -563,7 +646,8 @@ Curl_conn_dns_get_https(struct Curl_easy *data,
for(; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
- if(Curl_peer_same_destination(ctx->peer, peer)) {
+ if(Curl_peer_same_destination(ctx->peer, peer) &&
+ (ctx->dns_queries & CURL_DNSQ_HTTPS)) {
if(ctx->dns)
return ctx->dns->hinfo;
else
@@ -582,7 +666,8 @@ bool Curl_conn_dns_resolved_https(struct Curl_easy *data,
for(; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
- if(Curl_peer_same_destination(ctx->peer, peer)) {
+ if(Curl_peer_same_destination(ctx->peer, peer) &&
+ (ctx->dns_queries & CURL_DNSQ_HTTPS)) {
if(ctx->dns)
return TRUE;
else
diff --git a/lib/cf-dns.h b/lib/cf-dns.h
index 891b1efea6..ef90d711e2 100644
--- a/lib/cf-dns.h
+++ b/lib/cf-dns.h
@@ -31,23 +31,16 @@ struct Curl_dns_entry;
struct Curl_addrinfo;
struct Curl_peer;
-CURLcode Curl_cf_dns_add(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex,
- struct Curl_peer *peer,
- uint8_t dns_queries,
- uint8_t transport);
+CURLcode Curl_conn_dns_add_addr_resolve(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer,
+ uint8_t dns_queries,
+ uint8_t transport);
-CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
- struct Curl_easy *data,
- uint8_t dns_queries,
- struct Curl_peer *peer,
- uint8_t transport,
- bool complete_resolve);
-
-CURLcode Curl_conn_dns_result(struct connectdata *conn,
- int sockindex,
- struct Curl_peer *peer);
+CURLcode Curl_conn_dns_addr_result(struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer);
const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
struct Curl_peer *peer,
@@ -55,13 +48,12 @@ const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
int ai_family,
unsigned int index);
-const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct Curl_peer *peer,
- int ai_family,
- unsigned int index);
-
#ifdef USE_HTTPSRR
+CURLcode Curl_conn_dns_add_https_resolve(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex,
+ struct Curl_peer *peer);
+
const struct Curl_https_rrinfo *
Curl_conn_dns_get_https(struct Curl_easy *data,
int sockindex,
diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c
index 1a2e966ef6..c39f59f2ee 100644
--- a/lib/cf-https-connect.c
+++ b/lib/cf-https-connect.c
@@ -110,6 +110,7 @@ static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
struct cf_hc_ctx {
cf_hc_state state;
+ struct Curl_peer *destination; /* who we ultimately want to talk to */
struct curltime started; /* when connect started */
CURLcode result; /* overall result */
CURLcode check_h3_result;
@@ -123,21 +124,14 @@ struct cf_hc_ctx {
BIT(ballers_complete);
};
-static void cf_hc_ctx_close(struct Curl_easy *data,
- struct cf_hc_ctx *ctx)
+static void cf_hc_ctx_destroy(struct Curl_easy *data,
+ struct cf_hc_ctx *ctx)
{
if(ctx) {
size_t i;
for(i = 0; i < ctx->baller_count; ++i)
cf_hc_baller_discard(&ctx->ballers[i], data);
- }
-}
-
-static void cf_hc_ctx_destroy(struct Curl_easy *data,
- struct cf_hc_ctx *ctx)
-{
- if(ctx) {
- cf_hc_ctx_close(data, ctx);
+ Curl_peer_unlink(&ctx->destination);
curlx_free(ctx);
}
}
@@ -222,7 +216,6 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
ctx->state = CF_HC_SUCCESS;
cf->connected = TRUE;
- cf_hc_ctx_close(data, ctx);
/* ballers may have failf()'d, the winner resets it, so our
* errorbuf is clean again. */
Curl_reset_fail(data);
@@ -296,6 +289,7 @@ static enum alpnid cf_hc_get_httpsrr_alpn(struct Curl_cfilter *cf,
enum alpnid not_this_one)
{
#ifdef USE_HTTPSRR
+ struct cf_hc_ctx *ctx = cf->ctx;
/* Is there an HTTPSRR use its ALPNs here.
* We are here after having selected a connection to a host+port and
* can no longer change that. Any HTTPSRR advice for other hosts and ports
@@ -304,9 +298,9 @@ static enum alpnid cf_hc_get_httpsrr_alpn(struct Curl_cfilter *cf,
size_t i;
/* Do we have HTTPS-RR information? */
- rr = Curl_conn_dns_get_https(
- data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex));
+ rr = Curl_conn_dns_get_https(data, cf->sockindex, ctx->destination);
+ CURL_TRC_CF(data, cf, "HTTPS-RR %savailable", rr ? "" : "not ");
/* We do not support `rr->no_def_alpn`. */
if(Curl_httpsrr_applicable(data, rr) && !rr->no_def_alpn) {
for(i = 0; i < CURL_ARRAYSIZE(rr->alpns); ++i) {
@@ -495,7 +489,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
if(!ctx->httpsrr_resolved) {
ctx->httpsrr_resolved = Curl_conn_dns_resolved_https(
- data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex));
+ data, cf->sockindex, ctx->destination);
#ifdef DEBUGBUILD
if(!ctx->httpsrr_resolved && getenv("CURL_DBG_AWAIT_HTTPSRR")) {
CURL_TRC_CF(data, cf, "awaiting HTTPS-RR");
@@ -744,7 +738,7 @@ static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
struct Curl_cftype Curl_cft_http_connect = {
"HTTPS-CONNECT",
- CF_TYPE_SETUP | CF_TYPE_HTTPSRR,
+ CF_TYPE_SETUP,
CURL_LOG_LVL_NONE,
cf_hc_destroy,
cf_hc_connect,
@@ -761,6 +755,7 @@ struct Curl_cftype Curl_cft_http_connect = {
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
+ struct Curl_peer *destination,
uint8_t def_transport)
{
struct Curl_cfilter *cf = NULL;
@@ -772,6 +767,7 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+ Curl_peer_link(&ctx->destination, destination);
ctx->def_transport = def_transport;
ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2;
@@ -788,6 +784,7 @@ out:
}
static CURLcode cf_hc_add(struct Curl_easy *data,
+ struct Curl_peer *destination,
struct connectdata *conn,
int sockindex,
uint8_t def_transport)
@@ -796,15 +793,21 @@ static CURLcode cf_hc_add(struct Curl_easy *data,
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- result = cf_hc_create(&cf, data, def_transport);
+ result = cf_hc_create(&cf, data, destination, def_transport);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
+
+#ifdef USE_HTTPSRR
+ result = Curl_conn_dns_add_https_resolve(data, cf->conn, cf->sockindex,
+ destination);
+#endif
out:
return result;
}
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
+ struct Curl_peer *destination,
struct connectdata *conn,
int sockindex)
{
@@ -821,7 +824,8 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
!conn->bits.tls_enable_alpn)
goto out;
- result = cf_hc_add(data, conn, sockindex, conn->transport_wanted);
+ result = cf_hc_add(data, destination, conn, sockindex,
+ conn->transport_wanted);
out:
return result;
diff --git a/lib/cf-https-connect.h b/lib/cf-https-connect.h
index 3160c0382a..caa2b17e7f 100644
--- a/lib/cf-https-connect.h
+++ b/lib/cf-https-connect.h
@@ -31,10 +31,12 @@ struct Curl_cfilter;
struct Curl_easy;
struct connectdata;
struct Curl_cftype;
+struct Curl_peer;
extern struct Curl_cftype Curl_cft_http_connect;
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
+ struct Curl_peer *destination,
struct connectdata *conn,
int sockindex);
diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c
index 91ff029f6f..794d5e4cb9 100644
--- a/lib/cf-ip-happy.c
+++ b/lib/cf-ip-happy.c
@@ -857,7 +857,8 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
*done = FALSE;
if(!ctx->dns_resolved) {
- result = Curl_conn_dns_result(cf->conn, cf->sockindex, ctx->ballers.peer);
+ result = Curl_conn_dns_addr_result(cf->conn, cf->sockindex,
+ ctx->ballers.peer);
if(!result)
ctx->dns_resolved = TRUE;
else if(result == CURLE_AGAIN) {
@@ -888,10 +889,6 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
cf->connected = TRUE;
cf->next = ctx->ballers.winner->cf;
ctx->ballers.winner->cf = NULL;
- cf_ip_happy_ctx_clear(ctx, data);
- Curl_expire_done(data, EXPIRE_HAPPY_EYEBALLS);
- /* whatever errors were reported by ballers, clear our errorbuf */
- Curl_reset_fail(data);
if(cf->conn->scheme->protocol & PROTO_FAMILY_SSH)
Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
@@ -900,13 +897,16 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
struct ip_quadruple ipquad;
bool is_ipv6;
if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
- const char *host;
- Curl_conn_get_current_host(data, cf->sockindex, &host, NULL);
CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
- host, ipquad.remote_ip, ipquad.remote_port);
+ ctx->ballers.peer->hostname,
+ ipquad.remote_ip, ipquad.remote_port);
}
}
#endif
+ cf_ip_happy_ctx_clear(ctx, data);
+ Curl_expire_done(data, EXPIRE_HAPPY_EYEBALLS);
+ /* whatever errors were reported by ballers, clear our errorbuf */
+ Curl_reset_fail(data);
data->info.numconnects++; /* to track the # of connections made */
}
break;
diff --git a/lib/cf-setup.c b/lib/cf-setup.c
index b073989a4e..7699ef5dfe 100644
--- a/lib/cf-setup.c
+++ b/lib/cf-setup.c
@@ -251,7 +251,7 @@ static CURLcode cf_setup_add_origin_filters(struct Curl_cfilter *cf,
(int)result);
return result;
}
- result = Curl_cf_quic_insert_after(cf, origin, peer);
+ result = Curl_cf_quic_insert_after(cf, data, origin, peer);
if(result) {
CURL_TRC_CF(data, cf, "adding QUIC filter failed -> %d", (int)result);
return result;
diff --git a/lib/cfilters.c b/lib/cfilters.c
index c5ee51a1b4..238698d332 100644
--- a/lib/cfilters.c
+++ b/lib/cfilters.c
@@ -644,17 +644,6 @@ int Curl_protocol_for_transport(uint8_t transport)
}
}
-bool Curl_conn_cf_wants_httpsrr(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- (void)data;
- for(; cf; cf = cf->next) {
- if(cf->cft->flags & CF_TYPE_HTTPSRR)
- return TRUE;
- }
- return FALSE;
-}
-
const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -728,17 +717,17 @@ CURLcode Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
CURLcode result = CURLE_OK;
- /* Get the lowest not-connected filter, if there are any */
- while(cf && !cf->connected && cf->next && !cf->next->connected)
- cf = cf->next;
- /* Skip all filters that have already shut down */
- while(cf && cf->shutdown)
- cf = cf->next;
- /* From there on, give all filters a chance to adjust the pollset.
- * Lower filters are called later, so they may override */
- while(cf && !result) {
- result = cf->cft->adjust_pollset(cf, data, ps);
- cf = cf->next;
+ /* Go through all filters, top to bottom, and let them manage the pollset
+ * - connected filters can do so
+ * - CF_TYPE_DNS filters can
+ * - unconnected filters without next or connect next can
+ */
+ for(; cf && !result; cf = cf->next) {
+ if(cf->shutdown)
+ continue;
+ if(cf->connected || (cf->cft->flags & CF_TYPE_DNS) ||
+ !cf->next || cf->next->connected)
+ result = cf->cft->adjust_pollset(cf, data, ps);
}
return result;
}
diff --git a/lib/cfilters.h b/lib/cfilters.h
index b1aad029e0..f55a572e2e 100644
--- a/lib/cfilters.h
+++ b/lib/cfilters.h
@@ -197,7 +197,7 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
* CF_TYPE_HTTP implement a version of the HTTP protocol
* CF_TYPE_SETUP filter is only needed for connection setup and
* can be removed once connected
- * CF_TYPE_HTTPSRR filter that wants HTTPS-RR information
+ * CF_TYPE_DNS filter managing DNS resolve operations
*/
#define CF_TYPE_IP_CONNECT (1 << 0)
#define CF_TYPE_SSL (1 << 1)
@@ -205,7 +205,7 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
#define CF_TYPE_PROXY (1 << 3)
#define CF_TYPE_HTTP (1 << 4)
#define CF_TYPE_SETUP (1 << 5)
-#define CF_TYPE_HTTPSRR (1 << 6)
+#define CF_TYPE_DNS (1 << 6)
/* A connection filter type, e.g. specific implementation. */
struct Curl_cftype {
@@ -352,10 +352,6 @@ int Curl_protocol_for_transport(uint8_t transport);
const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf,
struct Curl_easy *data);
-/* The filter (or one of its sub-filters) wants HTTPS-RR information. */
-bool Curl_conn_cf_wants_httpsrr(struct Curl_cfilter *cf,
- struct Curl_easy *data);
-
#define CURL_CF_SSL_DEFAULT (-1)
#define CURL_CF_SSL_DISABLE 0
#define CURL_CF_SSL_ENABLE 1
diff --git a/lib/connect.c b/lib/connect.c
index 86e97b955a..ca81849ce7 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -237,22 +237,23 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
int sockindex,
int ssl_mode)
{
+ struct Curl_peer *first_peer = Curl_conn_get_first_peer(conn, sockindex);
CURLcode result = CURLE_OK;
- struct Curl_peer *peer = Curl_conn_get_first_peer(conn, sockindex);
uint8_t dns_queries;
DEBUGASSERT(data);
DEBUGASSERT(conn->scheme);
DEBUGASSERT(!conn->cfilter[sockindex]);
- if(!peer)
+ if(!first_peer)
return CURLE_FAILED_INIT;
#ifndef CURL_DISABLE_HTTP
if(!conn->cfilter[sockindex] &&
conn->scheme->protocol == CURLPROTO_HTTPS) {
DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
- result = Curl_cf_https_setup(data, conn, sockindex);
+ result = Curl_cf_https_setup(
+ data, Curl_conn_get_destination(conn, sockindex), conn, sockindex);
if(result)
goto out;
}
@@ -266,13 +267,16 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
goto out;
}
+ /* Whatever the filter chain will be in the end, it will need the
+ * resolving of `first_peer`. Add that now so the resolve is started
+ * right away. */
dns_queries = Curl_resolv_dns_queries(data, conn->ip_version);
-#ifdef USE_HTTPSRR
- if(sockindex == FIRSTSOCKET)
- dns_queries |= CURL_DNSQ_HTTPS;
-#endif
- result = Curl_cf_dns_add(data, conn, sockindex, peer, dns_queries,
- conn->transport_wanted);
+ result = Curl_conn_dns_add_addr_resolve(data, conn, sockindex,
+ first_peer, dns_queries,
+ conn->transport_wanted);
+ if(result)
+ goto out;
+
DEBUGASSERT(conn->cfilter[sockindex]);
out:
return result;
diff --git a/lib/dnscache.c b/lib/dnscache.c
index 9c8341e56f..9f435cc0cd 100644
--- a/lib/dnscache.c
+++ b/lib/dnscache.c
@@ -64,10 +64,7 @@ static void dnscache_entry_free(struct Curl_dns_entry *dns)
{
Curl_freeaddrinfo(dns->addr);
#ifdef USE_HTTPSRR
- if(dns->hinfo) {
- Curl_httpsrr_cleanup(dns->hinfo);
- curlx_free(dns->hinfo);
- }
+ Curl_httpsrr_destroy(dns->hinfo);
#endif
curlx_free(dns);
}
@@ -76,17 +73,19 @@ static void dnscache_entry_free(struct Curl_dns_entry *dns)
* Create a hostcache id string for the provided host + port, to be used by
* the DNS caching. Without alloc. Return length of the id string.
*/
-static size_t create_dnscache_id(const char *name,
+static size_t create_dnscache_id(char type, const char *name,
size_t nlen, /* 0 or actual name length */
- uint16_t port, char *ptr, size_t buflen)
+ uint16_t port,
+ char *buf, size_t buflen)
{
size_t len = nlen ? nlen : strlen(name);
DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN);
- if(len > (buflen - 7))
- len = buflen - 7;
+ if(len > (buflen - 8))
+ len = buflen - 8;
/* store and lower case the name */
- Curl_strntolower(ptr, name, len);
- return curl_msnprintf(&ptr[len], 7, ":%u", port) + len;
+ buf[0] = type;
+ Curl_strntolower(buf + 1, name, len);
+ return curl_msnprintf(&buf[len + 1], 7, ":%u", port) + len + 1;
}
struct dnscache_prune_data {
@@ -219,6 +218,8 @@ static CURLcode fetch_addr(struct Curl_easy *data,
struct Curl_dns_entry *dns = NULL;
char entry_id[MAX_HOSTCACHE_LEN];
size_t entry_len;
+ char entry_type = CURL_DNSQ_IS_ADDR(dns_queries) ?
+ CURL_DNST_ADDR : CURL_DNST_HTTPS;
CURLcode result = CURLE_OK;
*pdns = NULL;
@@ -226,15 +227,16 @@ static CURLcode fetch_addr(struct Curl_easy *data,
return CURLE_OK;
/* Create an entry id, based upon the hostname and port */
- entry_len = create_dnscache_id(hostname, 0, port,
+ entry_len = create_dnscache_id(entry_type, hostname, 0, port,
entry_id, sizeof(entry_id));
/* See if it is already in our dns cache */
dns = Curl_hash_pick(&dnscache->entries, entry_id, entry_len + 1);
/* No entry found in cache, check if we might have a wildcard entry */
- if(!dns && data->state.wildcard_resolve) {
- entry_len = create_dnscache_id("*", 1, port, entry_id, sizeof(entry_id));
+ if(!dns && data->state.wildcard_resolve && CURL_DNSQ_IS_ADDR(dns_queries)) {
+ entry_len = create_dnscache_id(CURL_DNST_ADDR, "*", 1, port,
+ entry_id, sizeof(entry_id));
/* See if it is already in our dns cache */
dns = Curl_hash_pick(&dnscache->entries, entry_id, entry_len + 1);
@@ -255,9 +257,11 @@ static CURLcode fetch_addr(struct Curl_easy *data,
}
}
- if(dns) {
- if((dns->dns_queries & dns_queries) != dns_queries) {
- /* The entry does not cover all wanted DNS queries, a miss. */
+ /* We need to cache address information and HTTPS-RR separately. */
+ if(dns && CURL_DNSQ_IS_ADDR(dns_queries)) {
+ if((uint8_t)(dns->dns_queries & dns_queries) !=
+ (uint8_t)(dns_queries & CURL_DNSQ_ADDR)) {
+ /* The entry does not cover all wanted address queries, a miss. */
dns = NULL;
}
else if(!(dns->dns_responses & dns_queries)) {
@@ -267,12 +271,12 @@ static CURLcode fetch_addr(struct Curl_easy *data,
dns = NULL;
result = CURLE_COULDNT_RESOLVE_HOST;
}
+ else if(dns && !dns->addr) { /* negative entry */
+ dns = NULL;
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ }
}
- if(dns && !dns->addr) { /* negative entry */
- dns = NULL;
- result = CURLE_COULDNT_RESOLVE_HOST;
- }
*pdns = dns;
return result;
}
@@ -311,6 +315,9 @@ CURLcode Curl_dnscache_get(struct Curl_easy *data,
}
dnscache_unlock(data, dnscache);
+ CURL_TRC_DNS(data, "cache lookup %s:%u queries=%s -> %d %sfound",
+ hostname, port, Curl_resolv_query_str(dns_queries),
+ (int)result, dns ? "" : "not ");
*pentry = dns;
return result;
}
@@ -407,11 +414,8 @@ static bool dnscache_ai_has_family(struct Curl_addrinfo *ai,
return FALSE;
}
-static struct Curl_dns_entry *dnscache_entry_create(
+static struct Curl_dns_entry *dnsc_entry_create(
struct Curl_easy *data,
- uint8_t dns_queries,
- struct Curl_addrinfo **paddr1,
- struct Curl_addrinfo **paddr2,
const char *hostname,
size_t hostlen,
uint16_t port,
@@ -425,7 +429,6 @@ static struct Curl_dns_entry *dnscache_entry_create(
goto out;
dns->refcount = 1; /* the cache has the first reference */
- dns->dns_queries = dns_queries;
dns->port = port;
if(hostlen)
memcpy(dns->hostname, hostname, hostlen);
@@ -438,6 +441,29 @@ static struct Curl_dns_entry *dnscache_entry_create(
dns->timestamp = *Curl_pgrs_now(data);
}
+out:
+ return dns;
+}
+
+static struct Curl_dns_entry *
+dnsc_entry_assign_addr(
+ struct Curl_easy *data,
+ struct Curl_dns_entry *dns,
+ uint8_t dns_queries,
+ struct Curl_addrinfo **paddr1,
+ struct Curl_addrinfo **paddr2)
+{
+ if(!dns)
+ goto out;
+ /* only do this when this is the only reference */
+ DEBUGASSERT(dns->refcount == 1);
+ DEBUGASSERT(dns->type == CURL_DNST_INIT);
+
+ dns->type = CURL_DNST_ADDR;
+ /* queries should only be about addresses */
+ DEBUGASSERT(!(dns_queries & ~CURL_DNSQ_ADDR));
+ dns->dns_queries = (dns_queries & CURL_DNSQ_ADDR);
+
/* Take the given address lists into the entry */
if(paddr1 && *paddr1) {
dns->addr = *paddr1;
@@ -488,67 +514,129 @@ out:
return dns;
}
-struct Curl_dns_entry *Curl_dnscache_mk_entry(struct Curl_easy *data,
+struct Curl_dns_entry *Curl_dnsc_mk_addr(struct Curl_easy *data,
uint8_t dns_queries,
struct Curl_addrinfo **paddr,
const char *hostname,
uint16_t port)
{
- return dnscache_entry_create(data, dns_queries, paddr, NULL, hostname,
- hostname ? strlen(hostname) : 0,
- port, FALSE);
+ struct Curl_dns_entry *dns = dnsc_entry_create(
+ data, hostname, hostname ? strlen(hostname) : 0, port, FALSE);
+ dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL);
+ return dns;
}
-struct Curl_dns_entry *Curl_dnscache_mk_entry2(struct Curl_easy *data,
+struct Curl_dns_entry *Curl_dnsc_mk_addr2(struct Curl_easy *data,
uint8_t dns_queries,
struct Curl_addrinfo **paddr1,
struct Curl_addrinfo **paddr2,
const char *hostname,
uint16_t port)
{
- return dnscache_entry_create(data, dns_queries, paddr1, paddr2, hostname,
- hostname ? strlen(hostname) : 0,
- port, FALSE);
+ struct Curl_dns_entry *dns = dnsc_entry_create(
+ data, hostname, hostname ? strlen(hostname) : 0, port, FALSE);
+ dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr1, paddr2);
+ return dns;
}
#ifdef USE_HTTPSRR
-void Curl_dns_entry_set_https_rr(struct Curl_dns_entry *dns,
- struct Curl_https_rrinfo *hinfo)
+static struct Curl_dns_entry *
+dnsc_entry_assign_https(struct Curl_dns_entry *dns,
+ struct Curl_https_rrinfo **phinfo)
{
+ if(!dns)
+ goto out;
/* only do this when this is the only reference */
DEBUGASSERT(dns->refcount == 1);
- /* it should have been in the queries */
- DEBUGASSERT(dns->dns_queries & CURL_DNSQ_HTTPS);
+ DEBUGASSERT(dns->type == CURL_DNST_INIT);
+
if(dns->hinfo) {
- Curl_httpsrr_cleanup(dns->hinfo);
- curlx_free(dns->hinfo);
+ Curl_httpsrr_destroy(dns->hinfo);
+ dns->hinfo = NULL;
}
- dns->hinfo = hinfo;
- dns->dns_responses |= CURL_DNSQ_HTTPS;
+ dns->type = CURL_DNST_HTTPS;
+ dns->dns_responses = dns->dns_queries = CURL_DNSQ_HTTPS;
+ if(phinfo) {
+ dns->hinfo = *phinfo;
+ *phinfo = NULL;
+ }
+out:
+ if(phinfo && *phinfo) {
+ Curl_httpsrr_destroy(*phinfo);
+ *phinfo = NULL;
+ }
+ return dns;
}
+
+struct Curl_dns_entry *Curl_dnsc_mk_https(struct Curl_easy *data,
+ struct Curl_https_rrinfo **phinfo,
+ const char *hostname,
+ uint16_t port)
+{
+ struct Curl_dns_entry *dns = dnsc_entry_create(
+ data, hostname, hostname ? strlen(hostname) : 0, port, FALSE);
+ dns = dnsc_entry_assign_https(dns, phinfo);
+ return dns;
+}
+
+static struct Curl_dns_entry *dnsc_add_https(struct Curl_easy *data,
+ struct Curl_dnscache *dnscache,
+ struct Curl_https_rrinfo **phinfo,
+ const char *hostname,
+ size_t hlen,
+ uint16_t port,
+ bool permanent)
+{
+ char entry_id[MAX_HOSTCACHE_LEN];
+ size_t entry_len;
+ struct Curl_dns_entry *dns, *dns2;
+
+ dns = dnsc_entry_create(data, hostname, hostname ? strlen(hostname) : 0,
+ port, permanent);
+ dns = dnsc_entry_assign_https(dns, phinfo);
+ if(!dns)
+ return NULL;
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_len = create_dnscache_id(CURL_DNST_HTTPS, hostname, hlen, port,
+ entry_id, sizeof(entry_id));
+
+ /* Store the resolved data in our DNS cache. */
+ dns2 = Curl_hash_add(&dnscache->entries, entry_id, entry_len + 1,
+ (void *)dns);
+ if(!dns2) {
+ dnscache_entry_free(dns);
+ return NULL;
+ }
+
+ dns = dns2;
+ dns->refcount++; /* mark entry as in-use */
+ return dns;
+}
+
#endif /* USE_HTTPSRR */
-static struct Curl_dns_entry *dnscache_add_addr(struct Curl_easy *data,
- struct Curl_dnscache *dnscache,
- uint8_t dns_queries,
- struct Curl_addrinfo **paddr,
- const char *hostname,
- size_t hlen,
- uint16_t port,
- bool permanent)
+static struct Curl_dns_entry *dnsc_add_addr(struct Curl_easy *data,
+ struct Curl_dnscache *dnscache,
+ uint8_t dns_queries,
+ struct Curl_addrinfo **paddr,
+ const char *hostname,
+ size_t hlen,
+ uint16_t port,
+ bool permanent)
{
char entry_id[MAX_HOSTCACHE_LEN];
size_t entry_len;
struct Curl_dns_entry *dns;
struct Curl_dns_entry *dns2;
- dns = dnscache_entry_create(data, dns_queries, paddr, NULL,
- hostname, hlen, port, permanent);
+ dns = dnsc_entry_create(data, hostname, hlen, port, permanent);
+ dns = dnsc_entry_assign_addr(data, dns, dns_queries, paddr, NULL);
if(!dns)
return NULL;
/* Create an entry id, based upon the hostname and port */
- entry_len = create_dnscache_id(hostname, hlen, port,
+ entry_len = create_dnscache_id(CURL_DNST_ADDR, hostname, hlen, port,
entry_id, sizeof(entry_id));
/* Store the resolved data in our DNS cache. */
@@ -573,8 +661,12 @@ CURLcode Curl_dnscache_add(struct Curl_easy *data,
if(!dnscache)
return CURLE_FAILED_INIT;
+ if(!entry || (entry->type == CURL_DNST_INIT))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
/* Create an entry id, based upon the hostname and port */
- idlen = create_dnscache_id(entry->hostname, 0, entry->port, id, sizeof(id));
+ idlen = create_dnscache_id(entry->type, entry->hostname, 0, entry->port,
+ id, sizeof(id));
/* Store the resolved data in our DNS cache and up ref count */
dnscache_lock(data, dnscache);
@@ -584,6 +676,9 @@ CURLcode Curl_dnscache_add(struct Curl_easy *data,
}
entry->refcount++;
dnscache_unlock(data, dnscache);
+ CURL_TRC_DNS(data, "cached entry for %s:%u queries=%s",
+ entry->hostname, entry->port,
+ Curl_resolv_query_str(entry->dns_queries));
return CURLE_OK;
}
@@ -593,16 +688,35 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data,
uint16_t port)
{
struct Curl_dnscache *dnscache = dnscache_get(data);
- struct Curl_dns_entry *dns;
+ struct Curl_dns_entry *dns = NULL;
+ CURLcode result = CURLE_OK;
+
DEBUGASSERT(dnscache);
if(!dnscache)
return CURLE_FAILED_INIT;
dnscache_lock(data, dnscache);
- /* put this new host in the cache */
- dns = dnscache_add_addr(data, dnscache, dns_queries, NULL,
- host, strlen(host), port, FALSE);
+ if(dns_queries & CURL_DNSQ_ADDR) {
+ /* put this new host in the cache */
+ dns = dnsc_add_addr(data, dnscache, dns_queries, NULL,
+ host, strlen(host), port, FALSE);
+ if(!dns)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+#ifdef USE_HTTPSRR
+ else if(dns_queries == CURL_DNSQ_HTTPS) {
+ dns = dnsc_add_https(data, dnscache, NULL,
+ host, strlen(host), port, FALSE);
+ if(!dns)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+#endif
+ else {
+ /* a query we do not know, just cache nothing */
+ DEBUGASSERT(0);
+ }
+
if(dns) {
/* release the returned reference; the cache itself will keep the
* entry alive: */
@@ -610,10 +724,9 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data,
dnscache_unlock(data, dnscache);
CURL_TRC_DNS(data, "cache negative name resolve for %s:%d type=%s",
host, port, Curl_resolv_query_str(dns_queries));
- return CURLE_OK;
}
dnscache_unlock(data, dnscache);
- return CURLE_OUT_OF_MEMORY;
+ return result;
}
/*
@@ -697,7 +810,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
if(!curlx_str_number(&host, &num, 0xffff)) {
/* Create an entry id, based upon the hostname and port */
- entry_len = create_dnscache_id(curlx_str(&source),
+ entry_len = create_dnscache_id(CURL_DNST_ADDR, curlx_str(&source),
curlx_strlen(&source), (uint16_t)num,
entry_id, sizeof(entry_id));
dnscache_lock(data, dnscache);
@@ -802,7 +915,8 @@ err:
}
/* Create an entry id, based upon the hostname and port */
- entry_len = create_dnscache_id(curlx_str(&source), curlx_strlen(&source),
+ entry_len = create_dnscache_id(CURL_DNST_ADDR,
+ curlx_str(&source), curlx_strlen(&source),
port, entry_id, sizeof(entry_id));
dnscache_lock(data, dnscache);
@@ -828,10 +942,10 @@ err:
Curl_hash_delete(&dnscache->entries, entry_id, entry_len + 1);
}
- /* put this new host in the cache, an override for ALL dns queries */
- dns = dnscache_add_addr(data, dnscache, CURL_DNSQ_ALL,
- &head, curlx_str(&source),
- curlx_strlen(&source), port, permanent);
+ /* put this new host in the cache, override all address queries */
+ dns = dnsc_add_addr(data, dnscache, CURL_DNSQ_ADDR,
+ &head, curlx_str(&source),
+ curlx_strlen(&source), port, permanent);
if(dns)
/* release the returned reference; the cache itself will keep the
* entry alive: */
@@ -842,7 +956,7 @@ err:
if(!dns)
return CURLE_OUT_OF_MEMORY;
- infof(data, "Added %.*s:%u:%s to DNS cache%s",
+ infof(data, "[DNS] added %.*s:%u:%s to cache%s",
(int)curlx_strlen(&source), curlx_str(&source), port, addresses,
permanent ? "" : " (non-permanent)");
diff --git a/lib/dnscache.h b/lib/dnscache.h
index 9239977cf8..c029eb9d30 100644
--- a/lib/dnscache.h
+++ b/lib/dnscache.h
@@ -36,6 +36,10 @@ struct easy_pollset;
struct Curl_https_rrinfo;
struct Curl_multi;
+#define CURL_DNST_INIT '\0'
+#define CURL_DNST_ADDR 'A'
+#define CURL_DNST_HTTPS 'H'
+
struct Curl_dns_entry {
struct Curl_addrinfo *addr;
#ifdef USE_HTTPSRR
@@ -47,6 +51,7 @@ struct Curl_dns_entry {
uint32_t refcount;
/* hostname port number that resolved to addr. */
uint16_t port;
+ char type; /* CURL_DNST_ADDR or CURL_DNST_HTTPS */
uint8_t dns_queries; /* CURL_DNSQ_* type of queries performed for this */
uint8_t dns_responses; /* CURL_DNSQ_* type this entry has responses for */
/* hostname that resolved to addr. may be NULL (Unix domain sockets). */
@@ -62,13 +67,13 @@ struct Curl_dns_entry {
*
* Returns entry or NULL on OOM.
*/
-struct Curl_dns_entry *Curl_dnscache_mk_entry(struct Curl_easy *data,
+struct Curl_dns_entry *Curl_dnsc_mk_addr(struct Curl_easy *data,
uint8_t dns_queries,
struct Curl_addrinfo **paddr,
const char *hostname,
uint16_t port);
-struct Curl_dns_entry *Curl_dnscache_mk_entry2(struct Curl_easy *data,
+struct Curl_dns_entry *Curl_dnsc_mk_addr2(struct Curl_easy *data,
uint8_t dns_queries,
struct Curl_addrinfo **paddr1,
struct Curl_addrinfo **paddr2,
@@ -76,8 +81,10 @@ struct Curl_dns_entry *Curl_dnscache_mk_entry2(struct Curl_easy *data,
uint16_t port);
#ifdef USE_HTTPSRR
-void Curl_dns_entry_set_https_rr(struct Curl_dns_entry *dns,
- struct Curl_https_rrinfo *hinfo);
+struct Curl_dns_entry *Curl_dnsc_mk_https(struct Curl_easy *data,
+ struct Curl_https_rrinfo **phinfo,
+ const char *hostname,
+ uint16_t port);
#endif /* USE_HTTPSRR */
/* unlink a dns entry, frees all resources if it was the last reference.
diff --git a/lib/doh.c b/lib/doh.c
index b1f138f32c..f336eb5003 100644
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -1189,47 +1189,11 @@ UNITTEST CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
*hrr = lhrr;
return CURLE_OK;
err:
- Curl_httpsrr_cleanup(lhrr);
- curlx_safefree(lhrr);
+ Curl_httpsrr_destroy(lhrr);
return result;
}
-#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
-static void doh_print_httpsrr(struct Curl_easy *data,
- struct Curl_https_rrinfo *hrr)
-{
- DEBUGASSERT(hrr);
- infof(data, "HTTPS RR: priority %d, target: %s", hrr->priority, hrr->target);
- if(hrr->alpns[0] != ALPN_none)
- infof(data, "HTTPS RR: alpns %u %u %u %u",
- hrr->alpns[0], hrr->alpns[1], hrr->alpns[2], hrr->alpns[3]);
- else
- infof(data, "HTTPS RR: no alpns");
- if(hrr->no_def_alpn)
- infof(data, "HTTPS RR: no_def_alpn set");
- else
- infof(data, "HTTPS RR: no_def_alpn not set");
- if(hrr->ipv4hints) {
- doh_print_buf(data, "HTTPS RR: ipv4hints",
- hrr->ipv4hints, hrr->ipv4hints_len);
- }
- else
- infof(data, "HTTPS RR: no ipv4hints");
- if(hrr->echconfiglist) {
- doh_print_buf(data, "HTTPS RR: ECHConfigList",
- hrr->echconfiglist, hrr->echconfiglist_len);
- }
- else
- infof(data, "HTTPS RR: no ECHConfigList");
- if(hrr->ipv6hints) {
- doh_print_buf(data, "HTTPS RR: ipv6hint",
- hrr->ipv6hints, hrr->ipv6hints_len);
- }
- else
- infof(data, "HTTPS RR: no ipv6hints");
-}
-# endif
-#endif
+#endif /* USE_HTTPSRR */
CURLcode Curl_doh_take_result(struct Curl_easy *data,
struct Curl_resolv_async *async,
@@ -1250,6 +1214,7 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data,
CURLE_COULDNT_RESOLVE_PROXY : CURLE_COULDNT_RESOLVE_HOST;
}
else if(!dohp->pending) {
+ struct Curl_dns_entry *dns = NULL;
DOHcode rc[DOH_SLOT_COUNT];
bool negative = TRUE;
int slot;
@@ -1277,37 +1242,48 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data,
}
} /* next slot */
- if(!rc[DOH_SLOT_IPV4] || !rc[DOH_SLOT_IPV6]) {
- /* we have an address, of one kind or other */
- struct Curl_dns_entry *dns;
- struct Curl_addrinfo *ai;
+ if(CURL_DNSQ_IS_ADDR(async->dns_queries)) {
+ if(!rc[DOH_SLOT_IPV4] || !rc[DOH_SLOT_IPV6]) {
+ /* we have an address, of one kind or other */
+ struct Curl_addrinfo *ai;
- if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
- CURL_TRC_DNS(data, "hostname: %s", dohp->host);
- doh_show(data, &de);
+ if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
+ CURL_TRC_DNS(data, "hostname: %s", dohp->host);
+ doh_show(data, &de);
+ }
+
+ result = doh2ai(&de, dohp->host, dohp->port, &ai);
+ if(result) {
+ /* a decoded response without any usable address, e.g. only
+ CNAME records, is an authoritative "no data" answer */
+ if((result == CURLE_COULDNT_RESOLVE_HOST) && negative)
+ async->negative_answer = TRUE;
+ goto error;
+ }
+
+ /* we got a response, create a dns entry. */
+ dns = Curl_dnsc_mk_addr(data, async->dns_queries,
+ &ai, dohp->host, dohp->port);
+ if(!dns) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ } /* address processing done */
+ else {
+ /* every query failed. Only NXDOMAIN answers for all of them
+ make this a negative answer, eligible for caching. */
+ async->negative_answer = negative;
+ result = async->for_proxy ?
+ CURLE_COULDNT_RESOLVE_PROXY : CURLE_COULDNT_RESOLVE_HOST;
}
+ }
- result = doh2ai(&de, dohp->host, dohp->port, &ai);
- if(result) {
- /* a decoded response without any usable address, e.g. only
- CNAME records, is an authoritative "no data" answer */
- if((result == CURLE_COULDNT_RESOLVE_HOST) && negative)
- async->negative_answer = TRUE;
- goto error;
- }
-
- /* we got a response, create a dns entry. */
- dns = Curl_dnscache_mk_entry(data, async->dns_queries,
- &ai, dohp->host, dohp->port);
- if(!dns) {
- result = CURLE_OUT_OF_MEMORY;
- goto error;
- }
-
- /* Now add and HTTPSRR information if we have */
#ifdef USE_HTTPSRR
+ if(!dns && (async->dns_queries & CURL_DNSQ_HTTPS)) {
+ /* Now add and HTTPSRR information if we have */
+ struct Curl_https_rrinfo *hrr = NULL;
+
if(de.numhttps_rrs > 0 && result == CURLE_OK) {
- struct Curl_https_rrinfo *hrr = NULL;
result = doh_resp_decode_httpsrr(data, de.https_rrs->val,
de.https_rrs->len, &hrr);
if(result) {
@@ -1316,25 +1292,20 @@ CURLcode Curl_doh_take_result(struct Curl_easy *data,
goto error;
}
infof(data, "Some HTTPS RR to process");
-#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
- doh_print_httpsrr(data, hrr);
-#endif
- Curl_dns_entry_set_https_rr(dns, hrr);
}
+ Curl_httpsrr_trace(data, hrr);
+ dns = Curl_dnsc_mk_https(data, &hrr, async->hostname, async->port);
+ if(!dns) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ }
#endif /* USE_HTTPSRR */
- /* and add the entry to the cache */
+ /* and add the entry to the cache */
+ if(dns)
result = Curl_dnscache_add(data, dns);
- *pdns = dns;
- } /* address processing done */
- else {
- /* every query failed. Only NXDOMAIN answers for all of them
- make this a negative answer, eligible for caching. */
- async->negative_answer = negative;
- result = async->for_proxy ?
- CURLE_COULDNT_RESOLVE_PROXY : CURLE_COULDNT_RESOLVE_HOST;
- }
-
+ *pdns = dns;
} /* !dohp->pending */
else
/* wait for pending DoH transactions to complete */
diff --git a/lib/hostip.c b/lib/hostip.c
index 6afe63ff45..dc39f581b2 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -354,7 +354,7 @@ static bool can_resolve_dns_queries(struct Curl_easy *data,
uint8_t dns_queries)
{
(void)data;
- if((CURL_DNSQ_IP(dns_queries) == CURL_DNSQ_AAAA) && !ipv6works(data))
+ if((CURL_DNSQ_IS_ADDR(dns_queries) == CURL_DNSQ_AAAA) && !ipv6works(data))
return FALSE;
return TRUE;
}
@@ -445,7 +445,7 @@ static CURLcode hostip_resolv_take_result(struct Curl_easy *data,
result = Curl_async_take_result(data, async, pdns);
if(result == CURLE_AGAIN) {
- CURL_TRC_DNS(data, "resolve incomplete, queries=%s, responses=%s, "
+ CURL_TRC_DNS(data, "[%s] resolve incomplete, responses=%s, "
"ongoing=%d for %s:%d",
Curl_resolv_query_str(async->dns_queries),
Curl_resolv_query_str(async->dns_responses),
@@ -458,11 +458,13 @@ static CURLcode hostip_resolv_take_result(struct Curl_easy *data,
else if(result) {
/* a local failure, not a resolve answer. Keep the error as it
is so it does not get treated as one. */
- CURL_TRC_DNS(data, "resolve error %d for %s:%u",
+ CURL_TRC_DNS(data, "[%s] resolve error %d for %s:%u",
+ Curl_resolv_query_str(async->dns_queries),
(int)result, async->hostname, async->port);
}
else {
- CURL_TRC_DNS(data, "resolve complete for %s:%u",
+ CURL_TRC_DNS(data, "[%s] resolve complete for %s:%u",
+ Curl_resolv_query_str(async->dns_queries),
async->hostname, async->port);
DEBUGASSERT(*pdns);
}
@@ -514,6 +516,18 @@ const struct Curl_addrinfo *Curl_resolv_get_ai(struct Curl_easy *data,
}
#ifdef USE_HTTPSRR
+
+CURLcode Curl_resolv_https(struct Curl_easy *data,
+ struct Curl_peer *peer,
+ bool for_proxy,
+ timediff_t timeout_ms,
+ uint32_t *presolv_id,
+ struct Curl_dns_entry **pdns)
+{
+ return Curl_resolv(data, peer, CURL_DNSQ_HTTPS, TRNSPRT_TCP,
+ for_proxy, timeout_ms, presolv_id, pdns);
+}
+
const struct Curl_https_rrinfo *
Curl_resolv_get_https(struct Curl_easy *data, uint32_t resolv_id)
{
@@ -555,6 +569,7 @@ static CURLcode hostip_resolv_start(struct Curl_easy *data,
#endif
struct Curl_addrinfo *addr = NULL;
size_t hostname_len;
+ bool addr_queries = (dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA));
CURLcode result = CURLE_OK;
*pnegative = FALSE;
@@ -564,33 +579,34 @@ static CURLcode hostip_resolv_start(struct Curl_easy *data,
*pdns = NULL;
/* Check for "known" things to resolve ourselves. */
+ if(addr_queries) {
#ifndef USE_RESOLVE_ON_IPS
- if(Curl_is_ipaddr(hostname)) {
- /* test655 verifies that the announce is done, even though there
- * is no real resolving. So, keep doing this. */
- result = Curl_resolv_announce_start(data, NULL);
- if(result)
+ if(Curl_is_ipaddr(hostname)) {
+ /* test655 verifies that the announce is done, even though there
+ * is no real resolving. So, keep doing this. */
+ result = Curl_resolv_announce_start(data, NULL);
+ if(result)
+ goto out;
+ /* shortcut literal IP addresses, if we are not told to resolve them. */
+ result = Curl_str2addr(hostname, port, &addr);
goto out;
- /* shortcut literal IP addresses, if we are not told to resolve them. */
- result = Curl_str2addr(hostname, port, &addr);
- goto out;
- }
+ }
#endif
- hostname_len = strlen(hostname);
- if(curl_strequal(hostname, "localhost") ||
- curl_strequal(hostname, "localhost.") ||
- tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
- tailmatch(hostname, hostname_len, STRCONST(".localhost."))) {
- result = Curl_resolv_announce_start(data, NULL);
- if(result)
+ hostname_len = strlen(hostname);
+ if(curl_strequal(hostname, "localhost") ||
+ curl_strequal(hostname, "localhost.") ||
+ tailmatch(hostname, hostname_len, STRCONST(".localhost")) ||
+ tailmatch(hostname, hostname_len, STRCONST(".localhost."))) {
+ result = Curl_resolv_announce_start(data, NULL);
+ if(result)
+ goto out;
+ addr = get_localhost(port, hostname);
+ if(!addr)
+ result = CURLE_OUT_OF_MEMORY;
goto out;
- addr = get_localhost(port, hostname);
- if(!addr)
- result = CURLE_OUT_OF_MEMORY;
- goto out;
+ }
}
-
#ifndef CURL_DISABLE_DOH
if(!Curl_is_ipaddr(hostname) && allowDOH && data->set.doh) {
result = Curl_resolv_announce_start(data, NULL);
@@ -654,7 +670,7 @@ out:
if(addr) {
/* we got a response, create a dns entry, add to cache, return */
DEBUGASSERT(!*pdns);
- *pdns = Curl_dnscache_mk_entry(data, dns_queries, &addr, hostname, port);
+ *pdns = Curl_dnsc_mk_addr(data, dns_queries, &addr, hostname, port);
if(!*pdns)
result = CURLE_OUT_OF_MEMORY;
}
@@ -717,9 +733,9 @@ static CURLcode hostip_resolv(struct Curl_easy *data,
}
#ifdef DEBUGBUILD
- CURL_TRC_DNS(data, "hostip_resolv(%s:%u, queries=%s)",
- hostname, port, Curl_resolv_query_str(dns_queries));
- if((CURL_DNSQ_IP(dns_queries) == CURL_DNSQ_AAAA) &&
+ CURL_TRC_DNS(data, "[%s] hostip_resolv(%s:%u)",
+ Curl_resolv_query_str(dns_queries), hostname, port);
+ if((CURL_DNSQ_IS_ADDR(dns_queries) == CURL_DNSQ_AAAA) &&
getenv("CURL_DBG_RESOLV_FAIL_IPV6")) {
infof(data, "DEBUG fail ipv6 resolve");
result = hostip_resolv_failed(data, hostname, for_proxy);
@@ -742,6 +758,8 @@ static CURLcode hostip_resolv(struct Curl_easy *data,
result = hostip_resolv_start(data, dns_queries, hostname, port,
transport, for_proxy, timeout_ms, allowDOH,
presolv_id, pdns, &negative);
+ CURL_TRC_DNS(data, "[%s] hostip_resolv started -> %d",
+ Curl_resolv_query_str(dns_queries), (int)result);
}
out:
@@ -750,7 +768,8 @@ out:
if(IS_RESOLV_FAIL(result)) {
if(cache_dns && negative)
Curl_dnscache_add_negative(data, dns_queries, hostname, port);
- failf(data, "Could not resolve: %s:%u", hostname, port);
+ if(dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))
+ failf(data, "Could not resolve: %s:%u", hostname, port);
}
else {
failf(data, "Error %d resolving %s:%u", (int)result, hostname, port);
@@ -967,7 +986,7 @@ static CURLcode resolv_unix(struct Curl_easy *data,
return result;
}
- *pdns = Curl_dnscache_mk_entry(data, 0, &addr, NULL, 0);
+ *pdns = Curl_dnsc_mk_addr(data, 0, &addr, NULL, 0);
return *pdns ? CURLE_OK : CURLE_OUT_OF_MEMORY;
}
#endif /* USE_UNIX_SOCKETS */
@@ -1011,7 +1030,7 @@ CURLcode Curl_resolv(struct Curl_easy *data,
timeout_ms = CURL_TIMEOUT_RESOLVE_MS;
#ifdef USE_UNIX_SOCKETS
- if(peer->unix_socket)
+ if((dns_queries & CURL_DNSQ_ADDR) && peer->unix_socket)
return resolv_unix(data, peer->hostname, (bool)peer->abstract_uds, pdns);
#else
if(peer->unix_socket)
@@ -1019,14 +1038,17 @@ CURLcode Curl_resolv(struct Curl_easy *data,
#endif
#ifdef USE_ALARM_TIMEOUT
- if(timeout_ms && data->set.no_signal) {
- /* Cannot use ALARM when signals are disabled */
- timeout_ms = 0;
- }
- if(timeout_ms && !Curl_doh_wanted(data)) {
- return resolv_alarm_timeout(data, dns_queries, peer->hostname, peer->port,
- transport, for_proxy, timeout_ms, presolv_id,
- pdns);
+ if(dns_queries & CURL_DNSQ_ADDR) {
+ if(timeout_ms && data->set.no_signal) {
+ /* Cannot use ALARM when signals are disabled */
+ timeout_ms = 0;
+ }
+ if(timeout_ms && !Curl_doh_wanted(data)) {
+ return resolv_alarm_timeout(data, dns_queries,
+ peer->hostname, peer->port,
+ transport, for_proxy, timeout_ms,
+ presolv_id, pdns);
+ }
}
#endif /* !USE_ALARM_TIMEOUT */
@@ -1094,7 +1116,8 @@ CURLcode Curl_resolv_take_result(struct Curl_easy *data, uint32_t resolv_id,
if(async->negative_answer)
Curl_dnscache_add_negative(data, async->dns_queries,
async->hostname, async->port);
- failf(data, "Could not resolve: %s:%u", async->hostname, async->port);
+ if(async->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))
+ failf(data, "Could not resolve: %s:%u", async->hostname, async->port);
}
else if(result) {
failf(data, "Error %d resolving %s:%u",
diff --git a/lib/hostip.h b/lib/hostip.h
index 45370ec48e..eef7991847 100644
--- a/lib/hostip.h
+++ b/lib/hostip.h
@@ -52,8 +52,8 @@ struct Curl_peer;
#define CURL_DNSQ_AAAA (1U << 1)
#define CURL_DNSQ_HTTPS (1U << 2)
-#define CURL_DNSQ_ALL (CURL_DNSQ_A | CURL_DNSQ_AAAA | CURL_DNSQ_HTTPS)
-#define CURL_DNSQ_IP(x) (uint8_t)((x)&(CURL_DNSQ_A | CURL_DNSQ_AAAA))
+#define CURL_DNSQ_ADDR (uint8_t)(CURL_DNSQ_A | CURL_DNSQ_AAAA)
+#define CURL_DNSQ_IS_ADDR(x) (uint8_t)((x)&(CURL_DNSQ_ADDR))
#ifdef CURLVERBOSE
const char *Curl_resolv_query_str(uint8_t dns_queries);
@@ -153,6 +153,22 @@ const struct Curl_addrinfo *Curl_resolv_get_ai(struct Curl_easy *data,
int ai_family,
unsigned int index);
#ifdef USE_HTTPSRR
+
+/* Start DNS resolving for HTTPS records. Returns
+ * - CURLE_OK: `*pdns` is the resolved DNS entry (needs to be unlinked).
+ * `*presolv_id` is 0.
+ * - CURLE_AGAIN: resolve is asynchronous and not finished yet.
+ * `presolv_id` is the identifier for querying results later.
+ * - other: the operation failed, `*pdns` is NULL, `*presolv_id` is 0.
+ */
+CURLcode Curl_resolv_https(struct Curl_easy *data,
+ struct Curl_peer *peer,
+ bool for_proxy,
+ timediff_t timeout_ms,
+ uint32_t *presolv_id,
+ struct Curl_dns_entry **pdns);
+
+
const struct Curl_https_rrinfo *Curl_resolv_get_https(struct Curl_easy *data,
uint32_t resolv_id);
bool Curl_resolv_knows_https(struct Curl_easy *data, uint32_t resolv_id);
diff --git a/lib/httpsrr.c b/lib/httpsrr.c
index 53647b81ed..a05a5cb5c1 100644
--- a/lib/httpsrr.c
+++ b/lib/httpsrr.c
@@ -97,7 +97,7 @@ void Curl_httpsrr_trace(struct Curl_easy *data,
struct dynbuf tmp;
CURLcode result;
- if(!rr || !rr->complete) {
+ if(!rr) {
CURL_TRC_DNS(data, "[HTTPS-RR] not available");
return;
}
@@ -225,23 +225,15 @@ CURLcode Curl_httpsrr_set(struct Curl_https_rrinfo *rr,
return result;
}
-struct Curl_https_rrinfo *Curl_httpsrr_dup_move(
- struct Curl_https_rrinfo *rrinfo)
+void Curl_httpsrr_destroy(struct Curl_https_rrinfo *rrinfo)
{
- struct Curl_https_rrinfo *dup = curlx_memdup(rrinfo, sizeof(*rrinfo));
- if(dup)
- memset(rrinfo, 0, sizeof(*rrinfo));
- return dup;
-}
-
-void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo)
-{
- curlx_safefree(rrinfo->target);
- curlx_safefree(rrinfo->echconfiglist);
- curlx_safefree(rrinfo->ipv4hints);
- curlx_safefree(rrinfo->ipv6hints);
- curlx_safefree(rrinfo->rrname);
- rrinfo->complete = FALSE;
+ if(rrinfo) {
+ curlx_free(rrinfo->target);
+ curlx_free(rrinfo->echconfiglist);
+ curlx_free(rrinfo->ipv4hints);
+ curlx_free(rrinfo->ipv6hints);
+ curlx_free(rrinfo);
+ }
}
bool Curl_httpsrr_applicable(struct Curl_easy *data,
@@ -269,11 +261,16 @@ static CURLcode httpsrr_opt(const ares_dns_rr_t *rr,
}
CURLcode Curl_httpsrr_from_ares(const ares_dns_record_t *dnsrec,
- struct Curl_https_rrinfo *hinfo)
+ struct Curl_https_rrinfo **phinfo)
{
- CURLcode result = CURLE_OK;
+ struct Curl_https_rrinfo *hinfo = NULL;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
size_t i;
+ hinfo = curlx_calloc(1, sizeof(*hinfo));
+ if(!hinfo)
+ goto out;
+
for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) {
const char *target;
size_t opt;
@@ -297,12 +294,20 @@ CURLcode Curl_httpsrr_from_ares(const ares_dns_record_t *dnsrec,
opt++) {
result = httpsrr_opt(rr, ARES_RR_HTTPS_PARAMS, opt, hinfo);
if(result)
- break;
+ goto out;
}
}
+ result = CURLE_OK;
+
out:
- hinfo->complete = !result;
- curlx_safefree(hinfo->rrname);
+ if(result) {
+ *phinfo = NULL;
+ Curl_httpsrr_destroy(hinfo);
+ }
+ else {
+ DEBUGASSERT(hinfo);
+ *phinfo = hinfo;
+ }
return result;
}
diff --git a/lib/httpsrr.h b/lib/httpsrr.h
index 2ee1beab3e..8d6eed1c93 100644
--- a/lib/httpsrr.h
+++ b/lib/httpsrr.h
@@ -38,7 +38,6 @@ struct Curl_easy;
struct dynbuf;
struct Curl_https_rrinfo {
- char *rrname; /* if NULL, the same as the URL hostname */
/*
* Fields from HTTPS RR. The only mandatory fields are priority and target.
* See https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
@@ -57,16 +56,12 @@ struct Curl_https_rrinfo {
BIT(no_def_alpn); /* keytag = 2 */
BIT(mandatory); /* keytag = 0 */
BIT(port_set); /* port value has been assigned */
- BIT(complete); /* values have been successfully assigned */
};
CURLcode Curl_httpsrr_set(struct Curl_https_rrinfo *rr,
uint16_t rrkey, const uint8_t *val, size_t vlen);
-struct Curl_https_rrinfo *Curl_httpsrr_dup_move(
- struct Curl_https_rrinfo *rrinfo);
-
-void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo);
+void Curl_httpsrr_destroy(struct Curl_https_rrinfo *rrinfo);
/* TRUE if the record is applicable to the transfer and its connection. */
bool Curl_httpsrr_applicable(struct Curl_easy *data,
@@ -85,7 +80,7 @@ bool Curl_httpsrr_applicable(struct Curl_easy *data,
#ifdef USE_ARES
CURLcode Curl_httpsrr_from_ares(const ares_dns_record_t *dnsrec,
- struct Curl_https_rrinfo *hinfo);
+ struct Curl_https_rrinfo **phinfo);
#endif /* USE_ARES */
#ifdef CURLVERBOSE
diff --git a/lib/multi.c b/lib/multi.c
index 265a247227..9e3b092e48 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1182,10 +1182,7 @@ CURLMcode Curl_multi_pollset(struct Curl_easy *data,
break;
case MSTATE_CONNECTING:
- if(data->conn && !data->conn->bits.dns_resolved)
- result = Curl_resolv_pollset(data, ps);
- if(!result)
- result = mstate_connecting_pollset(data, ps);
+ result = mstate_connecting_pollset(data, ps);
break;
case MSTATE_PROTOCONNECT:
diff --git a/lib/socks.c b/lib/socks.c
index ab3663e886..71c7d1bb56 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -105,7 +105,6 @@ struct socks_ctx {
uint8_t proxy_type;
unsigned char version;
BIT(resolve_local);
- BIT(start_resolving);
BIT(socks4a);
};
@@ -318,32 +317,19 @@ static CURLproxycode socks4_resolving(struct socks_ctx *sx,
const struct Curl_addrinfo *ai = NULL;
CURLcode result;
size_t nwritten;
- bool dns_done;
*done = FALSE;
- if(sx->start_resolving) {
- /* need to resolve hostname to add destination address */
- sx->start_resolving = FALSE;
- result = Curl_cf_dns_insert_after(
- cf, data, Curl_resolv_dns_queries(data, sx->ip_version),
- sx->dest, TRNSPRT_TCP, TRUE);
- if(result) {
- failf(data, "unable to create DNS filter for socks");
- return CURLPX_UNKNOWN_FAIL;
- }
- }
-
- /* resolve the hostname by connecting the DNS filter */
- result = Curl_conn_cf_connect(cf->next, data, &dns_done);
+ result = Curl_conn_dns_addr_result(cf->conn, cf->sockindex, sx->dest);
if(result) {
- failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
- sx->dest->hostname);
- return CURLPX_RESOLVE_HOST;
- }
- else if(!dns_done)
+ if(result != CURLE_AGAIN) {
+ failf(data, "error %d resolving SOCKS destination %s:%u",
+ (int)result, sx->dest->hostname, sx->dest->port);
+ return CURLPX_RESOLVE_HOST;
+ }
return CURLPX_OK;
+ }
- ai = Curl_cf_dns_get_ai(cf->next, data, sx->dest, AF_INET, 0);
+ ai = Curl_conn_dns_get_ai(data, sx->dest, cf->sockindex, AF_INET, 0);
if(ai) {
struct sockaddr_in *saddr_in;
char ipbuf[64];
@@ -476,9 +462,7 @@ process_state:
case SOCKS4_ST_START:
Curl_bufq_reset(&sx->iobuf);
- sx->start_resolving = FALSE;
sx->socks4a = (sx->proxy_type == CURLPROXY_SOCKS4A);
- sx->resolve_local = !sx->socks4a;
sx->presult = CURLPX_OK;
/* SOCKS4 can only do IPv4, insist! */
@@ -526,7 +510,6 @@ process_state:
sxstate(sx, cf, data, SOCKS4_ST_SEND);
goto process_state;
}
- sx->start_resolving = TRUE;
sxstate(sx, cf, data, SOCKS4_ST_RESOLVING);
FALLTHROUGH();
@@ -835,37 +818,24 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx,
CURLcode result;
CURLproxycode presult = CURLPX_OK;
size_t nwritten;
- bool dns_done;
*done = FALSE;
- if(sx->start_resolving) {
- /* need to resolve hostname to add destination address */
- sx->start_resolving = FALSE;
- result = Curl_cf_dns_insert_after(
- cf, data, Curl_resolv_dns_queries(data, sx->ip_version),
- sx->dest, TRNSPRT_TCP, TRUE);
- if(result) {
- failf(data, "unable to create DNS filter for socks");
- return CURLPX_UNKNOWN_FAIL;
- }
- }
-
- /* resolve the hostname by connecting the DNS filter */
- result = Curl_conn_cf_connect(cf->next, data, &dns_done);
+ result = Curl_conn_dns_addr_result(cf->conn, cf->sockindex, sx->dest);
if(result) {
- failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
- sx->dest->hostname);
- return CURLPX_RESOLVE_HOST;
- }
- else if(!dns_done)
+ if(result != CURLE_AGAIN) {
+ failf(data, "error %d resolving SOCKS destination %s:%u",
+ (int)result, sx->dest->hostname, sx->dest->port);
+ return CURLPX_RESOLVE_HOST;
+ }
return CURLPX_OK;
+ }
#ifdef USE_IPV6
if(data->set.ipver != CURL_IPRESOLVE_V4)
- ai = Curl_cf_dns_get_ai(cf->next, data, sx->dest, AF_INET6, 0);
+ ai = Curl_conn_dns_get_ai(data, sx->dest, cf->sockindex, AF_INET6, 0);
#endif
if(!ai)
- ai = Curl_cf_dns_get_ai(cf->next, data, sx->dest, AF_INET, 0);
+ ai = Curl_conn_dns_get_ai(data, sx->dest, cf->sockindex, AF_INET, 0);
if(!ai) {
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
@@ -1037,7 +1007,6 @@ process_state:
switch(sx->state) {
case SOCKS_ST_INIT:
sx->version = 5;
- sx->resolve_local = (sx->proxy_type == CURLPROXY_SOCKS5);
sxstate(sx, cf, data, SOCKS5_ST_START);
FALLTHROUGH();
@@ -1126,7 +1095,6 @@ process_state:
sxstate(sx, cf, data, SOCKS5_ST_REQ1_SEND);
goto process_state;
}
- sx->start_resolving = TRUE;
sxstate(sx, cf, data, SOCKS5_ST_RESOLVING);
FALLTHROUGH();
@@ -1351,6 +1319,8 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
{
struct Curl_cfilter *cf;
struct socks_ctx *ctx;
+ bool resolve_local = FALSE;
+ uint8_t dns_queries = Curl_resolv_dns_queries(data, ip_version);
CURLcode result;
if(!dest)
@@ -1358,10 +1328,16 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
switch(proxy_type) {
case CURLPROXY_SOCKS5:
+ resolve_local = TRUE;
+ break;
case CURLPROXY_SOCKS5_HOSTNAME:
+ break;
case CURLPROXY_SOCKS4:
+ resolve_local = TRUE;
+ dns_queries = (uint8_t)(dns_queries & ~CURL_DNSQ_AAAA);
+ break;
case CURLPROXY_SOCKS4A:
- break; /* all supported */
+ break;
default:
failf(data, "unknown proxytype %d option given", proxy_type);
return CURLE_COULDNT_CONNECT;
@@ -1376,13 +1352,21 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
Curl_peer_link(&ctx->dest, dest);
ctx->ip_version = ip_version;
ctx->proxy_type = proxy_type;
+ ctx->resolve_local = resolve_local;
Curl_creds_link(&ctx->creds, creds);
Curl_bufq_init2(&ctx->iobuf, SOCKS_CHUNK_SIZE, SOCKS_CHUNKS,
BUFQ_OPT_SOFT_LIMIT);
result = Curl_cf_create(&cf, &Curl_cft_socks_proxy, ctx);
- if(!result)
+ if(!result) {
Curl_conn_cf_insert_after(cf_at, cf);
+ if(ctx->resolve_local) {
+ result = Curl_conn_dns_add_addr_resolve(data, cf_at->conn,
+ cf_at->sockindex,
+ ctx->dest, dns_queries,
+ TRNSPRT_TCP);
+ }
+ }
else
socks_proxy_ctx_free(ctx);
return result;
diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c
index 4cfd3fbac4..802ffb7d30 100644
--- a/lib/vquic/vquic.c
+++ b/lib/vquic/vquic.c
@@ -41,6 +41,7 @@
#include "curlx/dynbuf.h"
#include "curlx/fopen.h"
#include "cfilters.h"
+#include "cf-dns.h"
#include "vquic/cf-ngtcp2.h"
#include "vquic/cf-ngtcp2-cmn.h"
#include "vquic/cf-ngtcp2-proxy.h"
@@ -763,19 +764,36 @@ CURLcode Curl_qlogdir(struct Curl_easy *data,
}
CURLcode Curl_cf_quic_insert_after(struct Curl_cfilter *cf_at,
+ struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer)
{
+ CURLcode result;
+
+ (void)data; /* not used in all cases and compilers are stupid */
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
- return Curl_cf_ngtcp2_insert_after(cf_at, origin, peer);
+ result = Curl_cf_ngtcp2_insert_after(cf_at, origin, peer);
#elif defined(USE_QUICHE)
- return Curl_cf_quiche_insert_after(cf_at, origin, peer);
+ result = Curl_cf_quiche_insert_after(cf_at, origin, peer);
#else
(void)cf_at;
(void)origin;
(void)peer;
- return CURLE_NOT_BUILT_IN;
+ result = CURLE_NOT_BUILT_IN;
#endif
+
+#if defined(USE_HTTPSRR) && defined(USE_ECH)
+ /* When using ECH, kick off the HTTPS-RR resolve */
+ if(!result && (origin->scheme->family == CURLPROTO_HTTP) &&
+ CURLECH_ENABLED(data) &&
+ Curl_ssl_supports(data, SSLSUPP_ECH) &&
+ (data->set.tls_ech != CURLECH_GREASE) &&
+ !data->set.str[STRING_ECH_CONFIG]) {
+ result = Curl_conn_dns_add_https_resolve(data, cf_at->conn,
+ cf_at->sockindex, origin);
+ }
+#endif /* USE_HTTPSRR && USE_ECH */
+ return result;
}
CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
diff --git a/lib/vquic/vquic.h b/lib/vquic/vquic.h
index 5211a9b33a..8674a3001d 100644
--- a/lib/vquic/vquic.h
+++ b/lib/vquic/vquic.h
@@ -40,6 +40,7 @@ CURLcode Curl_qlogdir(struct Curl_easy *data,
int *qlogfdp);
CURLcode Curl_cf_quic_insert_after(struct Curl_cfilter *cf_at,
+ struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer);
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 02dbb9f7c7..816912a135 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -46,6 +46,7 @@
#include "urldata.h"
#include "cfilters.h"
+#include "cf-dns.h"
#include "vtls/vtls.h" /* generic SSL protos etc */
#include "vtls/vtls_int.h"
@@ -1421,8 +1422,20 @@ CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
result = cf_ssl_create(&cf, data, cf_at->conn);
if(!result)
result = cf_ssl_peer_init(cf, origin, peer, &cf_at->conn->ssl_config);
- if(!result)
+ if(!result) {
Curl_conn_cf_insert_after(cf_at, cf);
+#if defined(USE_HTTPSRR) && defined(USE_ECH)
+ /* When using ECH, kick off the HTTPS-RR resolve */
+ if((origin->scheme->family == CURLPROTO_HTTP) &&
+ CURLECH_ENABLED(data) &&
+ Curl_ssl_supports(data, SSLSUPP_ECH) &&
+ (data->set.tls_ech != CURLECH_GREASE) &&
+ !data->set.str[STRING_ECH_CONFIG]) {
+ result = Curl_conn_dns_add_https_resolve(data, cf->conn, cf->sockindex,
+ origin);
+ }
+#endif /* USE_HTTPSRR && USE_ECH */
+ }
else if(cf)
Curl_conn_cf_discard_chain(&cf, data);
return result;
diff --git a/tests/data/test2100 b/tests/data/test2100
index 8793c57865..1bb5361e15 100644
--- a/tests/data/test2100
+++ b/tests/data/test2100
@@ -41,6 +41,7 @@ Funny-head: yesyes
http
+https
# requires Debug so that it can use the DoH server without https
@@ -55,7 +56,7 @@ IPv6
HTTP GET using DoH (with HTTPS RR)
-http://foo.example.com:%HTTPPORT/%TESTNUMBER --doh-url http://%HOSTIP:%HTTPPORT/%TESTNUMBER0001
+https://foo.example.com:%HTTPSPORT/%TESTNUMBER --insecure --doh-insecure --doh-url https://%HOSTIP:%HTTPSPORT/%TESTNUMBER0001
@@ -71,43 +72,43 @@ s/com\x00\x00(\x1c|\x01)/com-00-00!/g;
%if HTTPSRR
POST /%TESTNUMBER0001 HTTP/1.1
-Host: %HOSTIP:%HTTPPORT
-Accept: */*
-Content-Type: application/dns-message
-Content-Length: 33
-
-%hex[%00%00%01%00%00%01%00%00%00%00%00%00%03foo%07example%03com-00-00!%00%01]hex%POST /%TESTNUMBER0001 HTTP/1.1
-Host: %HOSTIP:%HTTPPORT
-Accept: */*
-Content-Type: application/dns-message
-Content-Length: 33
-
-%hex[%00%00%01%00%00%01%00%00%00%00%00%00%03foo%07example%03com-00-00!%00%01]hex%POST /%TESTNUMBER0001 HTTP/1.1
-Host: %HOSTIP:%HTTPPORT
+Host: %HOSTIP:%HTTPSPORT
Accept: */*
Content-Type: application/dns-message
Content-Length: 47
-%hex[%00%00%01%00%00%01%00%00%00%00%00%00%06_%HTTPPORT%06_https%03foo%07example%03com%00%00A%00%01]hex%GET /%TESTNUMBER HTTP/1.1
-Host: foo.example.com:%HTTPPORT
-User-Agent: curl/%VERSION
-Accept: */*
-
-%else
-POST /%TESTNUMBER0001 HTTP/1.1
-Host: %HOSTIP:%HTTPPORT
+%hex[%00%00%01%00%00%01%00%00%00%00%00%00%06_%HTTPSPORT%06_https%03foo%07example%03com%00%00A%00%01]hex%POST /%TESTNUMBER0001 HTTP/1.1
+Host: %HOSTIP:%HTTPSPORT
Accept: */*
Content-Type: application/dns-message
Content-Length: 33
%hex[%00%00%01%00%00%01%00%00%00%00%00%00%03foo%07example%03com-00-00!%00%01]hex%POST /%TESTNUMBER0001 HTTP/1.1
-Host: %HOSTIP:%HTTPPORT
+Host: %HOSTIP:%HTTPSPORT
Accept: */*
Content-Type: application/dns-message
Content-Length: 33
%hex[%00%00%01%00%00%01%00%00%00%00%00%00%03foo%07example%03com-00-00!%00%01]hex%GET /%TESTNUMBER HTTP/1.1
-Host: foo.example.com:%HTTPPORT
+Host: foo.example.com:%HTTPSPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+%else
+POST /%TESTNUMBER0001 HTTP/1.1
+Host: %HOSTIP:%HTTPSPORT
+Accept: */*
+Content-Type: application/dns-message
+Content-Length: 33
+
+%hex[%00%00%01%00%00%01%00%00%00%00%00%00%03foo%07example%03com-00-00!%00%01]hex%POST /%TESTNUMBER0001 HTTP/1.1
+Host: %HOSTIP:%HTTPSPORT
+Accept: */*
+Content-Type: application/dns-message
+Content-Length: 33
+
+%hex[%00%00%01%00%00%01%00%00%00%00%00%00%03foo%07example%03com-00-00!%00%01]hex%GET /%TESTNUMBER HTTP/1.1
+Host: foo.example.com:%HTTPSPORT
User-Agent: curl/%VERSION
Accept: */*
diff --git a/tests/data/test716 b/tests/data/test716
index 6f692fbd09..266826c8d5 100644
--- a/tests/data/test716
+++ b/tests/data/test716
@@ -30,7 +30,7 @@ SOCKS5 proxy with too long username
# it should never connect to the target server
-http://hohoho.example.com:99/%TESTNUMBER -x socks5://%repeat[256 x A]%:b@%HOSTIP:%SOCKSPORT
+http://localhost:99/%TESTNUMBER -x socks5://%repeat[256 x A]%:b@%HOSTIP:%SOCKSPORT
diff --git a/tests/http/test_06_eyeballs.py b/tests/http/test_06_eyeballs.py
index d883822d54..8e2104df19 100644
--- a/tests/http/test_06_eyeballs.py
+++ b/tests/http/test_06_eyeballs.py
@@ -133,7 +133,7 @@ class TestEyeballs:
# no immediately failed attempts, as should be
he_timers_set = [line for line in r.trace_lines
if re.match(r'.*\[TIMER] \[HAPPY_EYEBALLS] set for', line)]
- assert len(he_timers_set) == 2, f'found: {"".join(he_timers_set)}\n{r.dump_logs()}'
+ assert len(he_timers_set) >= 2, f'found: {"".join(he_timers_set)}\n{r.dump_logs()}'
# download using HTTP/3 on missing server with alt-svc pointing there
@pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support")
diff --git a/tests/http/test_22_httpsrr.py b/tests/http/test_22_httpsrr.py
index 51ed3bbd9d..0b95472aa7 100644
--- a/tests/http/test_22_httpsrr.py
+++ b/tests/http/test_22_httpsrr.py
@@ -129,3 +129,22 @@ class TestHTTPSRR:
r.check_exit_code(0)
r.check_stats(count=1, http_status=200, exitcode=0)
assert r.stats[0]['http_version'] == '2', f'{r}'
+
+ # download https: via https: proxytunnel
+ @pytest.mark.skipif(condition=not Env.curl_has_feature('HTTPS-proxy'),
+ reason='curl lacks HTTPS-proxy support')
+ @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")
+ def test_22_06_httpsrr_proxy(self, env: Env, httpd, nghttpx_fwd, dnsd):
+ dnsd.set_answers(addr_a=['127.0.0.1'],
+ https=['10 . alpn=http/1.1'])
+ run_env = os.environ.copy()
+ run_env['CURL_DNS_SERVER'] = f'127.0.0.1:{dnsd.port}'
+ run_env['CURL_DBG_AWAIT_HTTPSRR'] = '1'
+ run_env['CURL_QUICK_EXIT'] = '1'
+ curl = CurlClient(env=env, run_env=run_env)
+ url = f'https://localhost:{env.https_port}/data.json'
+ xargs = curl.get_proxy_args(tunnel=True)
+ r = curl.http_download(urls=[url], alpn_proto='h2', with_stats=True,
+ extra_args=xargs)
+ r.check_response(count=1, http_status=200)
+ assert r.stats[0]['http_version'] == '1.1', f'{r}'
diff --git a/tests/unit/unit1607.c b/tests/unit/unit1607.c
index d4052b762f..2b55621340 100644
--- a/tests/unit/unit1607.c
+++ b/tests/unit/unit1607.c
@@ -51,7 +51,7 @@ static CURLcode test_unit1607(const char *arg)
/* lowercase host and port to retrieve the addresses from hostcache */
const char *host;
- int port;
+ uint16_t port;
/* whether we expect a permanent or non-permanent cache entry */
bool permanent;
@@ -113,6 +113,7 @@ static CURLcode test_unit1607(const char *arg)
easy = curl_easy_init();
if(!easy)
goto error;
+ curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
/* create a multi handle and add the easy handle to it so that the
hostcache is setup */
@@ -126,7 +127,8 @@ static CURLcode test_unit1607(const char *arg)
Curl_loadhostpairs(easy);
- entry_id = (void *)curl_maprintf("%s:%d", tests[i].host, tests[i].port);
+ entry_id = (void *)curl_maprintf("%c%s:%u", CURL_DNST_ADDR,
+ tests[i].host, tests[i].port);
if(!entry_id)
goto error;
dns = Curl_hash_pick(&multi->dnscache.entries,
diff --git a/tests/unit/unit1658.c b/tests/unit/unit1658.c
index 49859c69c8..041ced7f29 100644
--- a/tests/unit/unit1658.c
+++ b/tests/unit/unit1658.c
@@ -544,8 +544,7 @@ static CURLcode test_unit1658(const char *arg)
/* free the generated struct */
if(hrr) {
- Curl_httpsrr_cleanup(hrr);
- curl_free(hrr);
+ Curl_httpsrr_destroy(hrr);
}
}
curl_easy_cleanup(easy);