From: Stefan Eissing Date: Tue, 16 Jun 2026 10:07:08 +0000 (+0200) Subject: cf-dns: pass peer for result lookups X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;ds=inline;p=thirdparty%2Fcurl.git cf-dns: pass peer for result lookups The DNS filter knows the peer it resolves and the code parts that want the results know the peer as well. Pass it to lookup methods to make sure results match. Background: when tunneling, the resolved peer is not always the one that other filters are looking for. Especially when HTTPS-RR results are accessed in TLS filters, those will differ. This prevents a HTTPS-RR for a proxy to be used for the origin when ECH is activated. To make ECH work through a tunnel, we need to start an additional resolve. Something to be fixed after 8.21. Closes #22042 --- diff --git a/docs/KNOWN_BUGS.md b/docs/KNOWN_BUGS.md index 32a76242ef..8bf35114c0 100644 --- a/docs/KNOWN_BUGS.md +++ b/docs/KNOWN_BUGS.md @@ -48,6 +48,10 @@ Certain Windows installations may be missing CA roots. [curl issue 20897](https://github.com/curl/curl/issues/20897) [curl issue 12303](https://github.com/curl/curl/issues/12303) +## ECH not working through Proxy Tunnels + +[curl issue 22043](https://github.com/curl/curl/issues/22043) + # Email protocols ## IMAP `SEARCH ALL` truncated response diff --git a/lib/cf-dns.c b/lib/cf-dns.c index c737ce14f4..631c987be2 100644 --- a/lib/cf-dns.c +++ b/lib/cf-dns.c @@ -452,29 +452,35 @@ CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at, /* Return the resolv result from the first "resolv" filter, starting * the given filter `cf` downwards. */ -static CURLcode cf_dns_result(struct Curl_cfilter *cf) +static CURLcode cf_dns_result(struct Curl_cfilter *cf, + struct Curl_peer *peer) { for(; cf; cf = cf->next) { if(cf->cft == &Curl_cft_dns) { struct cf_dns_ctx *ctx = cf->ctx; - if(ctx->dns || ctx->resolv_result) - return ctx->resolv_result; - return CURLE_AGAIN; + if(Curl_peer_same_destination(ctx->peer, peer)) { + if(ctx->dns || ctx->resolv_result) + return ctx->resolv_result; + return CURLE_AGAIN; + } + return CURLE_OK; /* ok, but no results */ } } return CURLE_FAILED_INIT; } -/* Return the result of the DNS resolution. Searches for a "resolv" +/* Return the result of the DNS resolution for peer. Searches for a "resolv" * 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) +CURLcode Curl_conn_dns_result(struct connectdata *conn, + int sockindex, + struct Curl_peer *peer) { - return cf_dns_result(conn->cfilter[sockindex]); + return cf_dns_result(conn->cfilter[sockindex], peer); } static const struct Curl_addrinfo *cf_dns_get_nth_ai( @@ -507,6 +513,7 @@ static const struct Curl_addrinfo *cf_dns_get_nth_ai( */ 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) { @@ -514,12 +521,14 @@ const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf, for(; cf; cf = cf->next) { if(cf->cft == &Curl_cft_dns) { struct cf_dns_ctx *ctx = cf->ctx; - if(ctx->resolv_result) - return NULL; - else if(ctx->dns) - return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index); - else - return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index); + if(Curl_peer_same_destination(ctx->peer, peer)) { + if(ctx->resolv_result) + return NULL; + else if(ctx->dns) + return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index); + else + return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index); + } } } return NULL; @@ -530,11 +539,14 @@ const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf, * 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, - int sockindex, int ai_family, + struct Curl_peer *peer, + int sockindex, + int ai_family, unsigned int index) { struct connectdata *conn = data->conn; - return Curl_cf_dns_get_ai(conn->cfilter[sockindex], data, ai_family, index); + return Curl_cf_dns_get_ai(conn->cfilter[sockindex], data, peer, + ai_family, index); } #ifdef USE_HTTPSRR @@ -542,35 +554,43 @@ const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data, * connection. If the DNS resolving is not done yet or if there * is no HTTPS-RR info, returns NULL. */ -const struct Curl_https_rrinfo *Curl_conn_dns_get_https(struct Curl_easy *data, - int sockindex) +const struct Curl_https_rrinfo * +Curl_conn_dns_get_https(struct Curl_easy *data, + int sockindex, + struct Curl_peer *peer) { struct Curl_cfilter *cf = data->conn->cfilter[sockindex]; for(; cf; cf = cf->next) { if(cf->cft == &Curl_cft_dns) { struct cf_dns_ctx *ctx = cf->ctx; - if(ctx->dns) - return ctx->dns->hinfo; - else - return Curl_resolv_get_https(data, ctx->resolv_id); + if(Curl_peer_same_destination(ctx->peer, peer)) { + if(ctx->dns) + return ctx->dns->hinfo; + else + return Curl_resolv_get_https(data, ctx->resolv_id); + } } } return NULL; } -bool Curl_conn_dns_resolved_https(struct Curl_easy *data, int sockindex) +bool Curl_conn_dns_resolved_https(struct Curl_easy *data, + int sockindex, + struct Curl_peer *peer) { struct Curl_cfilter *cf = data->conn->cfilter[sockindex]; for(; cf; cf = cf->next) { if(cf->cft == &Curl_cft_dns) { struct cf_dns_ctx *ctx = cf->ctx; - if(ctx->dns) - return TRUE; - else - return Curl_resolv_knows_https(data, ctx->resolv_id); + if(Curl_peer_same_destination(ctx->peer, peer)) { + if(ctx->dns) + return TRUE; + else + return Curl_resolv_knows_https(data, ctx->resolv_id); + } } } - return FALSE; + return TRUE; } #endif /* USE_HTTPSRR */ diff --git a/lib/cf-dns.h b/lib/cf-dns.h index f6902b8f7b..891b1efea6 100644 --- a/lib/cf-dns.h +++ b/lib/cf-dns.h @@ -45,25 +45,33 @@ CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at, uint8_t transport, bool complete_resolve); -CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex); +CURLcode Curl_conn_dns_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, int sockindex, 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 -const struct Curl_https_rrinfo *Curl_conn_dns_get_https(struct Curl_easy *data, - int sockindex); -bool Curl_conn_dns_resolved_https(struct Curl_easy *data, int sockindex); +const struct Curl_https_rrinfo * +Curl_conn_dns_get_https(struct Curl_easy *data, + int sockindex, + struct Curl_peer *peer); +bool Curl_conn_dns_resolved_https(struct Curl_easy *data, + int sockindex, + struct Curl_peer *peer); #else -#define Curl_conn_dns_get_https(a, b) NULL -#define Curl_conn_dns_resolved_https(a, b) TRUE +#define Curl_conn_dns_get_https(a, b, c) NULL +#define Curl_conn_dns_resolved_https(a, b, c) TRUE #endif extern struct Curl_cftype Curl_cft_dns; diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index a2b7b40ab6..1a2e966ef6 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -304,7 +304,8 @@ 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); + rr = Curl_conn_dns_get_https( + data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex)); /* We do not support `rr->no_def_alpn`. */ if(Curl_httpsrr_applicable(data, rr) && !rr->no_def_alpn) { @@ -493,7 +494,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, *done = FALSE; if(!ctx->httpsrr_resolved) { - ctx->httpsrr_resolved = Curl_conn_dns_resolved_https(data, cf->sockindex); + ctx->httpsrr_resolved = Curl_conn_dns_resolved_https( + data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex)); #ifdef DEBUGBUILD if(!ctx->httpsrr_resolved && getenv("CURL_DBG_AWAIT_HTTPSRR")) { CURL_TRC_CF(data, cf, "awaiting HTTPS-RR"); diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 68feca3062..963ccea94d 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -118,15 +118,18 @@ UNITTEST void debug_set_transport_provider( struct cf_ai_iter { struct Curl_cfilter *cf; + struct Curl_peer *peer; int ai_family; unsigned int n; }; static void cf_ai_iter_init(struct cf_ai_iter *iter, struct Curl_cfilter *cf, + struct Curl_peer *peer, int ai_family) { iter->cf = cf; + iter->peer = peer; /* not linked, ctx->ballers owns and has same lifetime */ iter->ai_family = ai_family; iter->n = 0; } @@ -139,7 +142,7 @@ static const struct Curl_addrinfo *cf_ai_iter_next(struct cf_ai_iter *iter, if(!iter->cf) return NULL; - addr = Curl_conn_dns_get_ai(data, iter->cf->sockindex, + addr = Curl_conn_dns_get_ai(data, iter->peer, iter->cf->sockindex, iter->ai_family, iter->n); if(addr) iter->n++; @@ -150,7 +153,7 @@ static bool cf_ai_iter_has_more(struct cf_ai_iter *iter, struct Curl_easy *data) { return (iter->cf && - !!Curl_conn_dns_get_ai(data, iter->cf->sockindex, + !!Curl_conn_dns_get_ai(data, iter->peer, iter->cf->sockindex, iter->ai_family, iter->n)); } @@ -766,16 +769,16 @@ static CURLcode cf_ip_happy_init(struct Curl_cfilter *cf, if(ctx->ballers.transport_peer == TRNSPRT_UNIX) { #ifdef USE_UNIX_SOCKETS - cf_ai_iter_init(&ctx->ballers.addr_iter, cf, AF_UNIX); + cf_ai_iter_init(&ctx->ballers.addr_iter, cf, ctx->ballers.peer, AF_UNIX); #else return CURLE_UNSUPPORTED_PROTOCOL; #endif } else { /* TCP/UDP/QUIC */ #ifdef USE_IPV6 - cf_ai_iter_init(&ctx->ballers.ipv6_iter, cf, AF_INET6); + cf_ai_iter_init(&ctx->ballers.ipv6_iter, cf, ctx->ballers.peer, AF_INET6); #endif - cf_ai_iter_init(&ctx->ballers.addr_iter, cf, AF_INET); + cf_ai_iter_init(&ctx->ballers.addr_iter, cf, ctx->ballers.peer, AF_INET); } CURL_TRC_CF(data, cf, "init ip ballers for transport %u", @@ -854,7 +857,7 @@ 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); + result = Curl_conn_dns_result(cf->conn, cf->sockindex, ctx->ballers.peer); if(!result) ctx->dns_resolved = TRUE; else if(result == CURLE_AGAIN) { diff --git a/lib/socks.c b/lib/socks.c index 9ae8cd7969..6c458c505d 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -343,7 +343,7 @@ static CURLproxycode socks4_resolving(struct socks_ctx *sx, else if(!dns_done) return CURLPX_OK; - ai = Curl_cf_dns_get_ai(cf->next, data, AF_INET, 0); + ai = Curl_cf_dns_get_ai(cf->next, data, sx->dest, AF_INET, 0); if(ai) { struct sockaddr_in *saddr_in; char ipbuf[64]; @@ -862,10 +862,10 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx, #ifdef USE_IPV6 if(data->set.ipver != CURL_IPRESOLVE_V4) - ai = Curl_cf_dns_get_ai(cf->next, data, AF_INET6, 0); + ai = Curl_cf_dns_get_ai(cf->next, data, sx->dest, AF_INET6, 0); #endif if(!ai) - ai = Curl_cf_dns_get_ai(cf->next, data, AF_INET, 0); + ai = Curl_cf_dns_get_ai(cf->next, data, sx->dest, AF_INET, 0); if(!ai) { failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", diff --git a/lib/vquic/cf-ngtcp2-cmn.c b/lib/vquic/cf-ngtcp2-cmn.c index dc15928f19..e1ca18cf69 100644 --- a/lib/vquic/cf-ngtcp2-cmn.c +++ b/lib/vquic/cf-ngtcp2-cmn.c @@ -1055,7 +1055,7 @@ CURLcode Curl_cf_ngtcp2_cmn_connect(struct Curl_cfilter *cf, *done = FALSE; if(cf_ngtcp2_need_httpsrr(data) && - !Curl_conn_dns_resolved_https(data, cf->sockindex)) { + !Curl_conn_dns_resolved_https(data, cf->sockindex, ctx->ssl_peer.peer)) { CURL_TRC_CF(data, cf, "need HTTPS-RR, delaying connect"); return CURLE_OK; } diff --git a/lib/vquic/cf-quiche.c b/lib/vquic/cf-quiche.c index 1edd597ad7..31a3957ec3 100644 --- a/lib/vquic/cf-quiche.c +++ b/lib/vquic/cf-quiche.c @@ -1392,7 +1392,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, *done = FALSE; if(Curl_ossl_need_httpsrr(data) && - !Curl_conn_dns_resolved_https(data, cf->sockindex)) { + !Curl_conn_dns_resolved_https(data, cf->sockindex, ctx->ssl_peer.peer)) { CURL_TRC_CF(data, cf, "need HTTPS-RR, delaying connect"); return CURLE_OK; } diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index dfc14fbc30..eb6839cfba 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -3502,7 +3502,7 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx, } else { const struct Curl_https_rrinfo *rinfo = - Curl_conn_dns_get_https(data, cf->sockindex); + Curl_conn_dns_get_https(data, cf->sockindex, peer->peer); if(rinfo && rinfo->echconfiglist) { const unsigned char *ecl = rinfo->echconfiglist; @@ -4970,7 +4970,8 @@ static CURLcode ossl_connect(struct Curl_cfilter *cf, if(ssl_connect_1 == connssl->connecting_state) { if(Curl_ossl_need_httpsrr(data) && - !Curl_conn_dns_resolved_https(data, cf->sockindex)) { + !Curl_conn_dns_resolved_https(data, cf->sockindex, + connssl->peer.peer)) { CURL_TRC_CF(data, cf, "need HTTPS-RR, delaying connect"); return CURLE_OK; } diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 39b15b889c..5183844a6f 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -981,8 +981,9 @@ init_config_builder_ech(struct Curl_easy *data, } } else { + const struct ssl_connect_data *connssl = cf->ctx; const struct Curl_https_rrinfo *rinfo = - Curl_conn_dns_get_https(data, cf->sockindex); + Curl_conn_dns_get_https(data, cf->sockindex, connssl->peer.peer); if(!rinfo || !rinfo->echconfiglist) { failf(data, "rustls: ECH requested but no ECHConfig available"); @@ -1162,7 +1163,8 @@ static CURLcode cr_connect(struct Curl_cfilter *cf, struct Curl_easy *data, /* if we do ECH and need the HTTPS-RR information for it, * we delay the connect until it arrives or DNS resolve fails. */ if(cr_ech_need_httpsrr(data) && - !Curl_conn_dns_resolved_https(data, cf->sockindex)) { + !Curl_conn_dns_resolved_https(data, cf->sockindex, + connssl->peer.peer)) { CURL_TRC_CF(data, cf, "need HTTPS-RR for ECH, delaying connect"); return CURLE_OK; } diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index b6a98d775b..c55490eb83 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1217,7 +1217,8 @@ static CURLcode wssl_init_ssl_handle( #ifdef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG static CURLcode wssl_init_ech(struct wssl_ctx *wctx, struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + struct ssl_peer *peer) { int trying_ech_now = 0; @@ -1247,7 +1248,7 @@ static CURLcode wssl_init_ech(struct wssl_ctx *wctx, } else { const struct Curl_https_rrinfo *rinfo = - Curl_conn_dns_get_https(data, cf->sockindex); + Curl_conn_dns_get_https(data, cf->sockindex, peer->peer); if(rinfo && rinfo->echconfiglist) { const unsigned char *ecl = rinfo->echconfiglist; @@ -1412,7 +1413,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, #ifdef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG if(CURLECH_ENABLED(data)) { - result = wssl_init_ech(wctx, cf, data); + result = wssl_init_ech(wctx, cf, data, peer); if(result) goto out; } @@ -2120,7 +2121,8 @@ static CURLcode wssl_connect(struct Curl_cfilter *cf, /* if we do ECH and need the HTTPS-RR information for it, * we delay the connect until it arrives or DNS resolve fails. */ if(Curl_wssl_need_httpsrr(data) && - !Curl_conn_dns_resolved_https(data, cf->sockindex)) { + !Curl_conn_dns_resolved_https(data, cf->sockindex, + connssl->peer.peer)) { CURL_TRC_CF(data, cf, "need HTTPS-RR for ECH, delaying connect"); return CURLE_OK; }