Coverage Report

Created: 2026-06-15 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmcurl/lib/cf-dns.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#include "urldata.h"
27
#include "curl_addrinfo.h"
28
#include "cfilters.h"
29
#include "connect.h"
30
#include "dnscache.h"
31
#include "httpsrr.h"
32
#include "curl_trc.h"
33
#include "progress.h"
34
#include "url.h"
35
#include "cf-dns.h"
36
37
38
struct cf_dns_ctx {
39
  struct Curl_dns_entry *dns;
40
  CURLcode resolv_result;
41
  uint32_t resolv_id;
42
  uint16_t port;
43
  uint8_t dns_queries;
44
  uint8_t transport;
45
  BIT(started);
46
  BIT(announced);
47
  BIT(abstract_unix_socket);
48
  BIT(complete_resolve);
49
  BIT(for_proxy);
50
  char hostname[1];
51
};
52
53
static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data,
54
                                            uint8_t dns_queries,
55
                                            const char *hostname,
56
                                            uint16_t port, uint8_t transport,
57
                                            bool abstract_unix_socket,
58
                                            bool for_proxy,
59
                                            bool complete_resolve,
60
                                            struct Curl_dns_entry *dns)
61
0
{
62
0
  struct cf_dns_ctx *ctx;
63
0
  size_t hlen = strlen(hostname);
64
65
0
  ctx = curlx_calloc(1, sizeof(*ctx) + hlen);
66
0
  if(!ctx)
67
0
    return NULL;
68
69
0
  ctx->port = port;
70
0
  ctx->dns_queries = dns_queries;
71
0
  ctx->transport = transport;
72
0
  ctx->abstract_unix_socket = abstract_unix_socket;
73
0
  ctx->for_proxy = for_proxy;
74
0
  ctx->complete_resolve = complete_resolve;
75
0
  ctx->dns = Curl_dns_entry_link(data, dns);
76
0
  ctx->started = !!ctx->dns;
77
0
  if(hlen)
78
0
    memcpy(ctx->hostname, hostname, hlen);
79
80
0
  CURL_TRC_DNS(data, "created DNS filter for %s:%u, transport=%x, queries=%x",
81
0
               ctx->hostname, ctx->port, ctx->transport, ctx->dns_queries);
82
0
  return ctx;
83
0
}
84
85
static void cf_dns_ctx_destroy(struct Curl_easy *data,
86
                               struct cf_dns_ctx *ctx)
87
0
{
88
0
  if(ctx) {
89
0
    Curl_dns_entry_unlink(data, &ctx->dns);
90
0
    curlx_free(ctx);
91
0
  }
92
0
}
93
94
#ifdef CURLVERBOSE
95
static void cf_dns_report_addr(struct Curl_easy *data,
96
                               struct dynbuf *tmp,
97
                               const char *label,
98
                               int ai_family,
99
                               const struct Curl_addrinfo *ai)
100
0
{
101
0
  char buf[MAX_IPADR_LEN];
102
0
  const char *sep = "";
103
0
  CURLcode result;
104
105
0
  curlx_dyn_reset(tmp);
106
0
  for(; ai; ai = ai->ai_next) {
107
0
    if(ai->ai_family == ai_family) {
108
0
      Curl_printable_address(ai, buf, sizeof(buf));
109
0
      result = curlx_dyn_addf(tmp, "%s%s", sep, buf);
110
0
      if(result) {
111
0
        infof(data, "too many IP, cannot show");
112
0
        return;
113
0
      }
114
0
      sep = ", ";
115
0
    }
116
0
  }
117
118
0
  infof(data, "%s%s", label,
119
0
        (curlx_dyn_len(tmp) ? curlx_dyn_ptr(tmp) : "(none)"));
120
0
}
121
122
static void cf_dns_report(struct Curl_cfilter *cf,
123
                          struct Curl_easy *data,
124
                          struct Curl_dns_entry *dns)
125
0
{
126
0
  struct cf_dns_ctx *ctx = cf->ctx;
127
0
  struct dynbuf tmp;
128
129
0
  if(!Curl_trc_is_verbose(data) ||
130
     /* ignore no name or numerical IP addresses */
131
0
     !dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
132
0
    return;
133
134
0
  switch(ctx->transport) {
135
0
  case TRNSPRT_UNIX:
136
#ifdef USE_UNIX_SOCKETS
137
    CURL_TRC_CF(data, cf, "resolved unix domain %s",
138
                Curl_conn_get_unix_path(data->conn));
139
#else
140
0
    DEBUGASSERT(0);
141
0
#endif
142
0
    break;
143
0
  default:
144
0
    curlx_dyn_init(&tmp, 1024);
145
0
    infof(data, "Host %s:%u was resolved.", dns->hostname, dns->port);
146
0
#ifdef CURLRES_IPV6
147
0
    cf_dns_report_addr(data, &tmp, "IPv6: ", AF_INET6, dns->addr);
148
0
#endif
149
0
    cf_dns_report_addr(data, &tmp, "IPv4: ", AF_INET, dns->addr);
150
#ifdef USE_HTTPSRR
151
    if(!dns->hinfo)
152
      infof(data, "HTTPS-RR: -");
153
    else if(!Curl_httpsrr_applicable(data, dns->hinfo))
154
      infof(data, "HTTPS-RR: not applicable");
155
    else {
156
      CURLcode result = Curl_httpsrr_print(&tmp, dns->hinfo);
157
      if(!result)
158
        infof(data, "HTTPS-RR: %s", curlx_dyn_ptr(&tmp));
159
      else
160
        infof(data, "Error printing HTTPS-RR information");
161
    }
162
#endif
163
0
    curlx_dyn_free(&tmp);
164
0
    break;
165
0
  }
166
0
}
167
#else
168
#define cf_dns_report(x, y, z) Curl_nop_stmt
169
#endif
170
171
/*************************************************************
172
 * Resolve the address of the server or proxy
173
 *************************************************************/
174
static CURLcode cf_dns_start(struct Curl_cfilter *cf,
175
                             struct Curl_easy *data,
176
                             struct Curl_dns_entry **pdns)
177
0
{
178
0
  struct cf_dns_ctx *ctx = cf->ctx;
179
0
  timediff_t timeout_ms = Curl_timeleft_ms(data);
180
0
  CURLcode result;
181
182
0
  *pdns = NULL;
183
184
#ifdef USE_UNIX_SOCKETS
185
  if(ctx->transport == TRNSPRT_UNIX) {
186
    CURL_TRC_CF(data, cf, "resolve unix socket %s", ctx->hostname);
187
    return Curl_resolv_unix(data, ctx->hostname,
188
                            (bool)cf->conn->bits.abstract_unix_socket, pdns);
189
  }
190
#endif
191
192
  /* Resolve target host right on */
193
0
  CURL_TRC_CF(data, cf, "cf_dns_start host %s:%u", ctx->hostname, ctx->port);
194
0
  if(Curl_is_ipv4addr(ctx->hostname))
195
0
    ctx->dns_queries |= CURL_DNSQ_A;
196
0
#ifdef USE_IPV6
197
0
  else if(Curl_is_ipaddr(ctx->hostname)) /* not ipv4, must be ipv6 then */
198
0
    ctx->dns_queries |= CURL_DNSQ_AAAA;
199
0
#endif
200
0
  result = Curl_resolv(data, ctx->dns_queries,
201
0
                       ctx->hostname, ctx->port, ctx->transport,
202
0
                       (bool)ctx->for_proxy, timeout_ms,
203
0
                       &ctx->resolv_id, pdns);
204
0
  DEBUGASSERT(!result || !*pdns);
205
0
  if(!result) { /* resolved right away, either sync or from dnscache */
206
0
    DEBUGASSERT(*pdns);
207
0
    return CURLE_OK;
208
0
  }
209
0
  else if(result == CURLE_AGAIN) { /* async resolv in progress */
210
0
    return CURLE_OK;
211
0
  }
212
0
  else if(result == CURLE_OPERATION_TIMEDOUT) { /* took too long */
213
0
    failf(data, "Failed to resolve '%s' with timeout after %"
214
0
          FMT_TIMEDIFF_T " ms", ctx->hostname,
215
0
          curlx_ptimediff_ms(Curl_pgrs_now(data),
216
0
                             &data->progress.t_startsingle));
217
0
    return CURLE_OPERATION_TIMEDOUT;
218
0
  }
219
0
  else {
220
0
    DEBUGASSERT(result);
221
0
    failf(data, "Could not resolve: %s", ctx->hostname);
222
0
    return result;
223
0
  }
224
0
}
225
226
0
#define CURL_HEV3_RESOLVE_DELAY_MS    50
227
228
static bool cf_dns_ready_to_connect(struct Curl_cfilter *cf,
229
                                    struct Curl_easy *data)
230
0
{
231
0
  struct cf_dns_ctx *ctx = cf->ctx;
232
233
0
  if(ctx->resolv_result)
234
0
    return TRUE;
235
0
  else if(ctx->dns)
236
0
    return TRUE;
237
0
#ifdef USE_CURL_ASYNC
238
0
  else {
239
    /* We want AAAA answer as we prefer ipv6. If a sub-filter desires
240
    * HTTPS-RR, we check for that query as well. */
241
0
    uint8_t wanted_answers = CURL_DNSQ_AAAA;
242
0
    if(Curl_conn_cf_wants_httpsrr(cf, data))
243
0
      wanted_answers |= CURL_DNSQ_HTTPS;
244
245
    /* Note: if a query was never started, it is considered to have
246
     * an answer (e.g. a negative one). */
247
0
    if(Curl_resolv_has_answers(data, ctx->resolv_id, wanted_answers))
248
0
      return TRUE;
249
    /* If the wanted answers are not available after a delay,
250
     * we let the connect attempts start anyway. */
251
0
    return Curl_resolv_elapsed_ms(data, ctx->resolv_id) >=
252
0
           CURL_HEV3_RESOLVE_DELAY_MS;
253
0
  }
254
#else
255
  (void)data;
256
  DEBUGASSERT(0); /* We should not come here */
257
  return FALSE;
258
#endif /* USE_CURL_ASYNC */
259
0
}
260
261
static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
262
                               struct Curl_easy *data,
263
                               bool *done)
264
0
{
265
0
  struct cf_dns_ctx *ctx = cf->ctx;
266
267
0
  if(cf->connected) {
268
0
    *done = TRUE;
269
0
    return CURLE_OK;
270
0
  }
271
272
0
  *done = FALSE;
273
0
  if(!ctx->started) {
274
0
    ctx->started = TRUE;
275
0
    ctx->resolv_result = cf_dns_start(cf, data, &ctx->dns);
276
0
  }
277
278
0
  if(!ctx->dns && !ctx->resolv_result) {
279
0
    ctx->resolv_result =
280
0
      Curl_resolv_take_result(data, ctx->resolv_id, &ctx->dns);
281
0
  }
282
283
0
  if(ctx->resolv_result) {
284
0
    CURL_TRC_CF(data, cf, "error resolving: %d", ctx->resolv_result);
285
0
    return ctx->resolv_result;
286
0
  }
287
288
0
  if(ctx->dns && !ctx->announced) {
289
0
    ctx->announced = TRUE;
290
0
    if(cf->sockindex == FIRSTSOCKET) {
291
0
      cf->conn->bits.dns_resolved = TRUE;
292
0
      Curl_pgrsTime(data, TIMER_NAMELOOKUP);
293
0
    }
294
0
    cf_dns_report(cf, data, ctx->dns);
295
0
  }
296
297
0
  if(!cf_dns_ready_to_connect(cf, data)) {
298
0
    return CURLE_OK;
299
0
  }
300
301
0
  if(cf->next && !cf->next->connected) {
302
0
    bool sub_done;
303
0
    CURLcode result = Curl_conn_cf_connect(cf->next, data, &sub_done);
304
0
    if(result || !sub_done)
305
0
      return result;
306
0
    DEBUGASSERT(sub_done);
307
0
  }
308
309
  /* sub filter chain is connected */
310
0
  CURL_TRC_CF(data, cf, "connected filter chain below");
311
0
  if(ctx->complete_resolve && !ctx->dns && !ctx->resolv_result) {
312
    /* This filter only connects when it has resolved everything. */
313
0
    CURL_TRC_CF(data, cf, "delay connect until resolve complete");
314
0
    return CURLE_OK;
315
0
  }
316
0
  *done = TRUE;
317
0
  cf->connected = TRUE;
318
0
  Curl_resolv_destroy(data, ctx->resolv_id);
319
0
  return CURLE_OK;
320
0
}
321
322
static void cf_dns_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
323
0
{
324
0
  struct cf_dns_ctx *ctx = cf->ctx;
325
326
0
  CURL_TRC_CF(data, cf, "destroy");
327
0
  cf_dns_ctx_destroy(data, ctx);
328
0
}
329
330
static void cf_dns_close(struct Curl_cfilter *cf, struct Curl_easy *data)
331
0
{
332
0
  cf->connected = FALSE;
333
0
  if(cf->next)
334
0
    cf->next->cft->do_close(cf->next, data);
335
0
}
336
337
static CURLcode cf_dns_adjust_pollset(struct Curl_cfilter *cf,
338
                                      struct Curl_easy *data,
339
                                      struct easy_pollset *ps)
340
0
{
341
0
#ifdef USE_CURL_ASYNC
342
0
  if(!cf->connected)
343
0
    return Curl_resolv_pollset(data, ps);
344
#else
345
  (void)cf;
346
  (void)data;
347
  (void)ps;
348
#endif
349
0
  return CURLE_OK;
350
0
}
351
352
static CURLcode cf_dns_cntrl(struct Curl_cfilter *cf,
353
                             struct Curl_easy *data,
354
                             int event, int arg1, void *arg2)
355
0
{
356
0
  struct cf_dns_ctx *ctx = cf->ctx;
357
0
  CURLcode result = CURLE_OK;
358
359
0
  (void)arg1;
360
0
  (void)arg2;
361
0
  switch(event) {
362
0
  case CF_CTRL_DATA_DONE:
363
0
    if(ctx->dns) {
364
      /* Should only come here when the connect attempt failed and
365
       * `data` is giving up on it. On a successful connect, we already
366
       * unlinked the DNS entry. */
367
0
      Curl_dns_entry_unlink(data, &ctx->dns);
368
0
    }
369
0
    break;
370
0
  default:
371
0
    break;
372
0
  }
373
0
  return result;
374
0
}
375
376
struct Curl_cftype Curl_cft_dns = {
377
  "DNS",
378
  CF_TYPE_SETUP,
379
  CURL_LOG_LVL_NONE,
380
  cf_dns_destroy,
381
  cf_dns_connect,
382
  cf_dns_close,
383
  Curl_cf_def_shutdown,
384
  cf_dns_adjust_pollset,
385
  Curl_cf_def_data_pending,
386
  Curl_cf_def_send,
387
  Curl_cf_def_recv,
388
  cf_dns_cntrl,
389
  Curl_cf_def_conn_is_alive,
390
  Curl_cf_def_conn_keep_alive,
391
  Curl_cf_def_query,
392
};
393
394
static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
395
                              struct Curl_easy *data,
396
                              uint8_t dns_queries,
397
                              const char *hostname,
398
                              uint16_t port,
399
                              uint8_t transport,
400
                              bool abstract_unix_socket,
401
                              bool for_proxy,
402
                              bool complete_resolve,
403
                              struct Curl_dns_entry *dns)
404
0
{
405
0
  struct Curl_cfilter *cf = NULL;
406
0
  struct cf_dns_ctx *ctx;
407
0
  CURLcode result = CURLE_OK;
408
409
0
  (void)data;
410
0
  ctx = cf_dns_ctx_create(data, dns_queries, hostname, port, transport,
411
0
                          abstract_unix_socket, for_proxy,
412
0
                          complete_resolve, dns);
413
0
  if(!ctx) {
414
0
    result = CURLE_OUT_OF_MEMORY;
415
0
    goto out;
416
0
  }
417
418
0
  result = Curl_cf_create(&cf, &Curl_cft_dns, ctx);
419
420
0
out:
421
0
  *pcf = result ? NULL : cf;
422
0
  if(result)
423
0
    cf_dns_ctx_destroy(data, ctx);
424
0
  return result;
425
0
}
426
427
/* Create a "resolv" filter for the transfer's connection. Figures
428
 * out the hostname/path and port where to connect to. */
429
static CURLcode cf_dns_conn_create(struct Curl_cfilter **pcf,
430
                                   struct Curl_easy *data,
431
                                   uint8_t dns_queries,
432
                                   uint8_t transport,
433
                                   bool complete_resolve,
434
                                   struct Curl_dns_entry *dns)
435
0
{
436
0
  struct connectdata *conn = data->conn;
437
0
  const char *hostname = NULL;
438
0
  uint16_t port = 0;
439
0
  bool abstract_unix_socket = FALSE, for_proxy = FALSE;
440
441
#ifdef USE_UNIX_SOCKETS
442
  {
443
    const char *unix_path = Curl_conn_get_unix_path(conn);
444
    if(unix_path) {
445
      DEBUGASSERT(transport == TRNSPRT_UNIX);
446
      hostname = unix_path;
447
      abstract_unix_socket = (bool)conn->bits.abstract_unix_socket;
448
    }
449
  }
450
#endif
451
452
0
#ifndef CURL_DISABLE_PROXY
453
0
  if(!hostname && conn->bits.proxy) {
454
0
    for_proxy = TRUE;
455
0
    hostname = conn->bits.socksproxy ?
456
0
      conn->socks_proxy.host.name : conn->http_proxy.host.name;
457
0
    port = conn->bits.socksproxy ?
458
0
      conn->socks_proxy.port : conn->http_proxy.port;
459
0
  }
460
0
#endif
461
0
  if(!hostname) {
462
0
    struct hostname *ehost;
463
0
    ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
464
    /* If not connecting via a proxy, extract the port from the URL, if it is
465
     * there, thus overriding any defaults that might have been set above. */
466
0
    hostname = ehost->name;
467
0
    port = conn->bits.conn_to_port ?
468
0
      conn->conn_to_port : (uint16_t)conn->remote_port;
469
0
  }
470
471
0
  if(!hostname) {
472
0
    DEBUGASSERT(0);
473
0
    return CURLE_FAILED_INIT;
474
0
  }
475
0
  return cf_dns_create(pcf, data, dns_queries,
476
0
                       hostname, port, transport,
477
0
                       abstract_unix_socket, for_proxy,
478
0
                       complete_resolve, dns);
479
0
}
480
481
/* Adds a "resolv" filter at the top of the connection's filter chain.
482
 * For FIRSTSOCKET, the `dns` parameter may be NULL. The filter will
483
 * figure out hostname and port to connect to and start the DNS resolve
484
 * on the first connect attempt.
485
 * For SECONDARYSOCKET, the `dns` parameter must be given.
486
 */
487
CURLcode Curl_cf_dns_add(struct Curl_easy *data,
488
                         struct connectdata *conn,
489
                         int sockindex,
490
                         uint8_t dns_queries,
491
                         uint8_t transport,
492
                         struct Curl_dns_entry *dns)
493
0
{
494
0
  struct Curl_cfilter *cf = NULL;
495
0
  CURLcode result;
496
497
0
  DEBUGASSERT(data);
498
0
  if(sockindex == FIRSTSOCKET)
499
0
    result = cf_dns_conn_create(&cf, data, dns_queries, transport, FALSE, dns);
500
0
  else if(dns) {
501
0
    result = cf_dns_create(&cf, data, dns_queries,
502
0
                           dns->hostname, dns->port, transport,
503
0
                           FALSE, FALSE, FALSE, dns);
504
0
  }
505
0
  else {
506
0
    DEBUGASSERT(0);
507
0
    result = CURLE_FAILED_INIT;
508
0
  }
509
0
  if(result)
510
0
    goto out;
511
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
512
0
out:
513
0
  return result;
514
0
}
515
516
/* Insert a new "resolv" filter directly after `cf`. It will
517
 * start a DNS resolve for the given hostnmae and port on the
518
 * first connect attempt.
519
 * See socks.c on how this is used to make a non-blocking DNS
520
 * resolve during connect.
521
 */
522
CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
523
                                  struct Curl_easy *data,
524
                                  uint8_t dns_queries,
525
                                  const char *hostname,
526
                                  uint16_t port,
527
                                  uint8_t transport,
528
                                  bool complete_resolve)
529
0
{
530
0
  struct Curl_cfilter *cf;
531
0
  CURLcode result;
532
533
0
  result = cf_dns_create(&cf, data, dns_queries,
534
0
                         hostname, port, transport,
535
0
                         FALSE, FALSE, complete_resolve, NULL);
536
0
  if(result)
537
0
    return result;
538
539
0
  Curl_conn_cf_insert_after(cf_at, cf);
540
0
  return CURLE_OK;
541
0
}
542
543
/* Return the resolv result from the first "resolv" filter, starting
544
 * the given filter `cf` downwards.
545
 */
546
static CURLcode cf_dns_result(struct Curl_cfilter *cf)
547
0
{
548
0
  for(; cf; cf = cf->next) {
549
0
    if(cf->cft == &Curl_cft_dns) {
550
0
      struct cf_dns_ctx *ctx = cf->ctx;
551
0
      if(ctx->dns || ctx->resolv_result)
552
0
        return ctx->resolv_result;
553
0
      return CURLE_AGAIN;
554
0
    }
555
0
  }
556
0
  return CURLE_FAILED_INIT;
557
0
}
558
559
/* Return the result of the DNS resolution. Searches for a "resolv"
560
 * filter from the top of the filter chain down. Returns
561
 * - CURLE_AGAIN when not done yet
562
 * - CURLE_OK when DNS was successfully resolved
563
 * - CURLR_FAILED_INIT when no resolv filter was found
564
 * - error returned by the DNS resolv
565
 */
566
CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex)
567
0
{
568
0
  return cf_dns_result(conn->cfilter[sockindex]);
569
0
}
570
571
static const struct Curl_addrinfo *cf_dns_get_nth_ai(
572
  struct Curl_cfilter *cf,
573
  const struct Curl_addrinfo *ai,
574
  int ai_family, unsigned int index)
575
0
{
576
0
  struct cf_dns_ctx *ctx = cf->ctx;
577
0
  unsigned int i = 0;
578
579
0
  if((ai_family == AF_INET) && !(ctx->dns_queries & CURL_DNSQ_A))
580
0
    return NULL;
581
0
#ifdef USE_IPV6
582
0
  if((ai_family == AF_INET6) && !(ctx->dns_queries & CURL_DNSQ_AAAA))
583
0
    return NULL;
584
0
#endif
585
0
  for(i = 0; ai; ai = ai->ai_next) {
586
0
    if(ai->ai_family == ai_family) {
587
0
      if(i == index)
588
0
        return ai;
589
0
      ++i;
590
0
    }
591
0
  }
592
0
  return NULL;
593
0
}
594
595
/* Return the addrinfo at `index` for the given `family` from the
596
 * first "resolve" filter underneath `cf`. If the DNS resolving is
597
 * not done yet or if no address for the family exists, returns NULL.
598
 */
599
const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
600
                                               struct Curl_easy *data,
601
                                               int ai_family,
602
                                               unsigned int index)
603
0
{
604
0
  (void)data;
605
0
  for(; cf; cf = cf->next) {
606
0
    if(cf->cft == &Curl_cft_dns) {
607
0
      struct cf_dns_ctx *ctx = cf->ctx;
608
0
      if(ctx->resolv_result)
609
0
        return NULL;
610
0
      else if(ctx->dns)
611
0
        return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index);
612
0
      else
613
0
        return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index);
614
0
    }
615
0
  }
616
0
  return NULL;
617
0
}
618
619
/* Return the addrinfo at `index` for the given `family` from the
620
 * first "resolve" filter at the connection. If the DNS resolving is
621
 * not done yet or if no address for the family exists, returns NULL.
622
 */
623
const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
624
                                                 int sockindex, int ai_family,
625
                                                 unsigned int index)
626
0
{
627
0
  struct connectdata *conn = data->conn;
628
0
  return Curl_cf_dns_get_ai(conn->cfilter[sockindex], data, ai_family, index);
629
0
}
630
631
#ifdef USE_HTTPSRR
632
/* Return the HTTPS-RR info from the first "resolve" filter at the
633
 * connection. If the DNS resolving is not done yet or if there
634
 * is no HTTPS-RR info, returns NULL.
635
 */
636
const struct Curl_https_rrinfo *Curl_conn_dns_get_https(struct Curl_easy *data,
637
                                                        int sockindex)
638
{
639
  struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
640
  for(; cf; cf = cf->next) {
641
    if(cf->cft == &Curl_cft_dns) {
642
      struct cf_dns_ctx *ctx = cf->ctx;
643
      if(ctx->dns)
644
        return ctx->dns->hinfo;
645
      else
646
        return Curl_resolv_get_https(data, ctx->resolv_id);
647
    }
648
  }
649
  return NULL;
650
}
651
652
bool Curl_conn_dns_resolved_https(struct Curl_easy *data, int sockindex)
653
{
654
  struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
655
  for(; cf; cf = cf->next) {
656
    if(cf->cft == &Curl_cft_dns) {
657
      struct cf_dns_ctx *ctx = cf->ctx;
658
      if(ctx->dns)
659
        return TRUE;
660
      else
661
        return Curl_resolv_knows_https(data, ctx->resolv_id);
662
    }
663
  }
664
  return FALSE;
665
}
666
667
#endif /* USE_HTTPSRR */