cf-dns: resolve on filter demand
No binary (build failed)
—
(log yok)
| @@ -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; |
| + | |
| + | 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(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(!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); | |
| } | |
| @@ -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; | |
| } | |
| @@ -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; | |
| @@ -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 | |
| }; | |
| @@ -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; |
| + | } |
| + | |
| + | 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 resolution for peer. Searches for a "resolv" |
| - | * filter from the top of the filter chain down. Returns |
| + | /* 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 | |
| @@ -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, | |
| @@ -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; | |
| @@ -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); | |
| @@ -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; | |
| @@ -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; | |
| @@ -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; | |
| } | |
| @@ -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 | |
| @@ -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; | |
| @@ -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->type = CURL_DNST_HTTPS; |
| + | dns->dns_responses = dns->dns_queries = CURL_DNSQ_HTTPS; |
| + | if(phinfo) { |
| + | dns->hinfo = *phinfo; |
| + | *phinfo = NULL; |
| } | |
| - | dns->hinfo = hinfo; |
| - | dns->dns_responses |= CURL_DNSQ_HTTPS; |
| + | 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)"); | |
| @@ -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. | |
| @@ -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; |
| - | } |
| + | 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; |
| + | /* 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; |
| } | |
| + | } |
| - | /* 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 */ | |
| @@ -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", | |
| @@ -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); | |
| @@ -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; | |
| } | |
| @@ -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 | |
| @@ -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: | |
| @@ -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; | |
| @@ -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, | |
| @@ -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); | |
| @@ -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; | |
| @@ -41,6 +41,7 @@ Funny-head: yesyes | |
| <client> | |
| <server> | |
| http | |
| + | https |
| </server> | |
| # requires Debug so that it can use the DoH server without https | |
| @@ -55,7 +56,7 @@ IPv6 | |
| HTTP GET using DoH (with HTTPS RR) | |
| </name> | |
| <command> | |
| - | 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 |
| </command> | |
| </client> | |
| @@ -71,43 +72,43 @@ s/com\x00\x00(\x1c|\x01)/com-00-00!/g; | |
| <protocol crlf="yes"> | |
| %if HTTPSRR | |
| POST /%TESTNUMBER0001 HTTP/1.1 | |
| - | Host: %HOSTIP:%HTTPPORT |
| + | Host: %HOSTIP:%HTTPSPORT |
| Accept: */* | |
| Content-Type: application/dns-message | |
| - | Content-Length: 33 |
| + | Content-Length: 47 |
| - | %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 |
| + | %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: 47 |
| + | Content-Length: 33 |
| - | %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 |
| + | %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: */* | |
| %else | |
| 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%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: */* | |
| @@ -30,7 +30,7 @@ SOCKS5 proxy with too long username | |
| # it should never connect to the target server | |
| <command> | |
| - | 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 |
| </command> | |
| </client> | |
| @@ -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") | |
| @@ -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}' |
| @@ -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, | |
| @@ -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); | |