]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
cf-dns: pass peer for result lookups
authorStefan Eissing <stefan@eissing.org>
Tue, 16 Jun 2026 10:07:08 +0000 (12:07 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 16 Jun 2026 21:15:43 +0000 (23:15 +0200)
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

docs/KNOWN_BUGS.md
lib/cf-dns.c
lib/cf-dns.h
lib/cf-https-connect.c
lib/cf-ip-happy.c
lib/socks.c
lib/vquic/cf-ngtcp2-cmn.c
lib/vquic/cf-quiche.c
lib/vtls/openssl.c
lib/vtls/rustls.c
lib/vtls/wolfssl.c

index 32a76242efd0829258c125daa9343d46c8d4f7f9..8bf35114c084ffa198bc7afd7efbf8d760a88fa8 100644 (file)
@@ -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
index c737ce14f435404bb578d64410589bfeda4cf3b1..631c987be262c771849008ac12fa90a0870663bb 100644 (file)
@@ -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 */
index f6902b8f7b2fd174fa51639fbf678f2fd861e24f..891b1efea606bc2c935b4aecc4232945e4bec654 100644 (file)
@@ -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;
index a2b7b40ab6f9e6c42d0bb468e708c8452faa97c5..1a2e966ef66aca8636b4df277765b2b3c86ed35b 100644 (file)
@@ -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");
index 68feca3062a1b1ef33f31a6c995f3df583a787ca..963ccea94d78bb9cfa2f0d2d323b0ed7c095665f 100644 (file)
@@ -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) {
index 9ae8cd79699c479efae678fd13d9864d25f7c7e4..6c458c505d2fda9f38b359da7b4fb1fead862eac 100644 (file)
@@ -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.",
index dc15928f19540fc23263b68ddd1d07077bfd5050..e1ca18cf69c80ec8732aa81b59a4b5a5e4717ff2 100644 (file)
@@ -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;
   }
index 1edd597ad72ede40502c4ed52bbda77242eb8ff9..31a3957ec372575126b426362baabfe52da34bc7 100644 (file)
@@ -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;
   }
index dfc14fbc304ae37562301b5e17135939a38afe8b..eb6839cfba4b5d548d247ed0bcd8869161d355e6 100644 (file)
@@ -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;
     }
index 39b15b889c6ae4d42286e4f4d27c518100ba02a5..5183844a6fbd4b4879b146217d13b2b2cb296fce 100644 (file)
@@ -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;
     }
index b6a98d775b4f5d6e006d0a32952e04820b8584ce..c55490eb833f46b0e86bf9fdb21cfc1e255c7586 100644 (file)
@@ -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;
     }