Coverage Report

Created: 2026-07-30 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/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 "multiif.h"
34
#include "progress.h"
35
#include "url.h"
36
#include "cf-dns.h"
37
38
39
struct cf_dns_ctx {
40
  struct Curl_dns_entry *dns;
41
  struct Curl_peer *peer;
42
  CURLcode resolv_result;
43
  uint32_t resolv_id;
44
  uint8_t dns_queries;
45
  uint8_t transport;
46
  BIT(started);
47
  BIT(announced);
48
  BIT(for_proxy);
49
};
50
51
static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data,
52
                                            struct Curl_peer *peer,
53
                                            uint8_t dns_queries,
54
                                            uint8_t transport,
55
                                            bool for_proxy)
56
0
{
57
0
  struct cf_dns_ctx *ctx;
58
59
0
  ctx = curlx_calloc(1, sizeof(*ctx));
60
0
  if(!ctx)
61
0
    return NULL;
62
63
0
  Curl_peer_link(&ctx->peer, peer);
64
0
  ctx->dns_queries = dns_queries;
65
0
  ctx->transport = transport;
66
0
  ctx->for_proxy = for_proxy;
67
68
0
  CURL_TRC_DNS(data, "[%s] created DNS filter for %s:%u, transport=%x",
69
0
               Curl_resolv_query_str(ctx->dns_queries),
70
0
               peer->hostname, peer->port, ctx->transport);
71
0
  return ctx;
72
0
}
73
74
static void cf_dns_ctx_destroy(struct Curl_easy *data,
75
                               struct cf_dns_ctx *ctx)
76
0
{
77
0
  if(ctx) {
78
0
    Curl_peer_unlink(&ctx->peer);
79
0
    Curl_dns_entry_unlink(data, &ctx->dns);
80
0
    curlx_free(ctx);
81
0
  }
82
0
}
83
84
#ifdef CURLVERBOSE
85
static void cf_dns_report_addr(struct Curl_easy *data,
86
                               struct dynbuf *tmp,
87
                               const char *label,
88
                               int ai_family,
89
                               const struct Curl_addrinfo *ai)
90
0
{
91
0
  char buf[MAX_IPADR_LEN];
92
0
  const char *sep = "";
93
0
  CURLcode result;
94
95
0
  curlx_dyn_reset(tmp);
96
0
  for(; ai; ai = ai->ai_next) {
97
0
    if(ai->ai_family == ai_family) {
98
0
      Curl_printable_address(ai, buf, sizeof(buf));
99
0
      result = curlx_dyn_addf(tmp, "%s%s", sep, buf);
100
0
      if(result) {
101
0
        infof(data, "too many IP, cannot show");
102
0
        return;
103
0
      }
104
0
      sep = ", ";
105
0
    }
106
0
  }
107
108
0
  infof(data, "%s%s", label,
109
0
        (curlx_dyn_len(tmp) ? curlx_dyn_ptr(tmp) : "(none)"));
110
0
}
111
112
static void cf_dns_report(struct Curl_cfilter *cf,
113
                          struct Curl_easy *data,
114
                          struct Curl_dns_entry *dns)
115
0
{
116
0
  struct cf_dns_ctx *ctx = cf->ctx;
117
0
  struct dynbuf tmp;
118
119
0
  if(!Curl_trc_is_verbose(data) ||
120
     /* ignore no name or numerical IP addresses */
121
0
     !dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
122
0
    return;
123
124
0
  if(ctx->peer->unix_socket) {
125
0
#ifdef USE_UNIX_SOCKETS
126
0
    CURL_TRC_CF(data, cf, "resolved unix://%s", ctx->peer->hostname);
127
#else
128
    DEBUGASSERT(0);
129
#endif
130
0
  }
131
0
  else {
132
0
    curlx_dyn_init(&tmp, 1024);
133
0
    if(CURL_DNSQ_IS_ADDR(ctx->dns_queries)) {
134
0
      infof(data, "Host %s:%u was resolved.", dns->hostname, dns->port);
135
0
#ifdef CURLRES_IPV6
136
0
      cf_dns_report_addr(data, &tmp, "IPv6: ", AF_INET6, dns->addr);
137
0
#endif
138
0
      cf_dns_report_addr(data, &tmp, "IPv4: ", AF_INET, dns->addr);
139
0
    }
140
#ifdef USE_HTTPSRR
141
    else if(ctx->dns_queries & CURL_DNSQ_HTTPS) {
142
      if(!dns->hinfo)
143
        infof(data, "HTTPS-RR %s:%u: -", dns->hostname, dns->port);
144
      else if(!Curl_httpsrr_applicable(data, dns->hinfo))
145
        infof(data, "HTTPS-RR %s:%u: not applicable",
146
              dns->hostname, dns->port);
147
      else {
148
        CURLcode result = Curl_httpsrr_print(&tmp, dns->hinfo);
149
        if(!result)
150
          infof(data, "HTTPS-RR %s:%u: %s",
151
                dns->hostname, dns->port, curlx_dyn_ptr(&tmp));
152
        else
153
          infof(data, "Error printing HTTPS-RR information");
154
      }
155
    }
156
#endif
157
0
    curlx_dyn_free(&tmp);
158
0
  }
159
0
}
160
#else
161
#define cf_dns_report(x, y, z) Curl_nop_stmt
162
#endif
163
164
/*************************************************************
165
 * Resolve the address of the server or proxy
166
 *************************************************************/
167
static CURLcode cf_dns_start(struct Curl_cfilter *cf,
168
                             struct Curl_easy *data,
169
                             struct Curl_dns_entry **pdns)
170
0
{
171
0
  struct cf_dns_ctx *ctx = cf->ctx;
172
0
  timediff_t timeout_ms = Curl_timeleft_ms(data);
173
0
  CURLcode result = CURLE_OK;
174
175
0
  *pdns = NULL;
176
177
0
  CURL_TRC_CF(data, cf, "[%s] cf_dns_start %s %s:%u",
178
0
              Curl_resolv_query_str(ctx->dns_queries),
179
0
              ctx->peer->unix_socket ? "unix-domain-socket" : "host",
180
0
              ctx->peer->hostname, ctx->peer->port);
181
0
  if(ctx->peer->unix_socket)
182
0
    ctx->dns_queries = CURL_DNSQ_A; /* treat it like an A resolve */
183
184
0
  if(CURL_DNSQ_IS_ADDR(ctx->dns_queries)) {
185
0
    if(Curl_is_ipv4addr(ctx->peer->hostname))
186
0
      ctx->dns_queries |= CURL_DNSQ_A;
187
0
#ifdef USE_IPV6
188
0
    else if(ctx->peer->ipv6)
189
0
      ctx->dns_queries |= CURL_DNSQ_AAAA;
190
0
#endif
191
192
0
    result = Curl_resolv(data, ctx->peer, ctx->dns_queries, ctx->transport,
193
0
                         (bool)ctx->for_proxy, timeout_ms,
194
0
                         &ctx->resolv_id, pdns);
195
0
  }
196
#ifdef USE_HTTPSRR
197
  else if(ctx->dns_queries == CURL_DNSQ_HTTPS) {
198
    result = Curl_resolv_https(data, ctx->peer, (bool)ctx->for_proxy,
199
                               timeout_ms, &ctx->resolv_id, pdns);
200
  }
201
#endif
202
0
  else {
203
0
    failf(data, "unsupported DNS queries %x", ctx->dns_queries);
204
0
    return CURLE_FAILED_INIT;
205
0
  }
206
207
0
  DEBUGASSERT(!result || !*pdns);
208
0
  if(!result) { /* resolved right away, either sync or from dnscache */
209
0
    DEBUGASSERT(*pdns);
210
0
    return CURLE_OK;
211
0
  }
212
0
  else if(result == CURLE_AGAIN) { /* async resolv in progress */
213
0
    return CURLE_OK;
214
0
  }
215
0
  else if(result == CURLE_OPERATION_TIMEDOUT) { /* took too long */
216
0
    failf(data, "Failed to resolve '%s' with timeout after %"
217
0
          FMT_TIMEDIFF_T " ms", ctx->peer->hostname,
218
0
          curlx_ptimediff_ms(Curl_pgrs_now(data),
219
0
                             &data->progress.t_startsingle));
220
0
    return CURLE_OPERATION_TIMEDOUT;
221
0
  }
222
0
  else {
223
0
    DEBUGASSERT(result);
224
0
    if(ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))
225
0
      failf(data, "Could not resolve: %s", ctx->peer->hostname);
226
0
    return result;
227
0
  }
228
0
}
229
230
0
#define CURL_HEV3_RESOLVE_DELAY_MS    50
231
232
static bool cf_dns_ready_to_connect(struct Curl_cfilter *cf,
233
                                    struct Curl_easy *data)
234
0
{
235
0
  struct cf_dns_ctx *ctx = cf->ctx;
236
237
0
  if(ctx->resolv_result)
238
0
    return TRUE;
239
0
  else if(ctx->dns)
240
0
    return TRUE;
241
0
#ifdef USE_CURL_ASYNC
242
0
  else {
243
    /* We want AAAA answer as we prefer IPv6. If a sub-filter desires
244
    * HTTPS-RR, we check for that query as well. */
245
0
    uint8_t wanted_answers = CURL_DNSQ_AAAA;
246
247
    /* Note: if a query was never started, it is considered to have
248
     * an answer (e.g. a negative one). */
249
0
    if(Curl_resolv_has_answers(data, ctx->resolv_id, wanted_answers))
250
0
      return TRUE;
251
    /* If the wanted answers are not available after a delay,
252
     * we let the connect attempts start anyway. */
253
0
    return Curl_resolv_elapsed_ms(data, ctx->resolv_id) >=
254
0
           CURL_HEV3_RESOLVE_DELAY_MS;
255
0
  }
256
#else
257
  (void)data;
258
  DEBUGASSERT(0); /* We should not come here */
259
  return FALSE;
260
#endif /* USE_CURL_ASYNC */
261
0
}
262
263
static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
264
                               struct Curl_easy *data,
265
                               bool *done)
266
0
{
267
0
  struct cf_dns_ctx *ctx = cf->ctx;
268
0
  bool ip_query = (ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA));
269
270
0
  if(cf->connected) {
271
0
    *done = TRUE;
272
0
    return CURLE_OK;
273
0
  }
274
275
0
  *done = FALSE;
276
0
  if(!ctx->started) {
277
0
    ctx->started = TRUE;
278
0
    ctx->resolv_result = cf_dns_start(cf, data, &ctx->dns);
279
0
  }
280
281
0
  if(!ctx->dns && !ctx->resolv_result) {
282
0
    ctx->resolv_result =
283
0
      Curl_resolv_take_result(data, ctx->resolv_id, &ctx->dns);
284
0
  }
285
286
0
  if(ctx->resolv_result && ip_query) {
287
    /* failing A|AAAA resolves is a hard failure. */
288
0
    CURL_TRC_CF(data, cf, "error resolving: %d", (int)ctx->resolv_result);
289
0
    return ctx->resolv_result;
290
0
  }
291
292
0
  if(ctx->dns && !ctx->announced) {
293
0
    ctx->announced = TRUE;
294
0
    if((cf->sockindex == FIRSTSOCKET) && ip_query) {
295
0
      cf->conn->bits.dns_resolved = TRUE;
296
0
      Curl_pgrsTime(data, TIMER_NAMELOOKUP);
297
0
    }
298
0
    cf_dns_report(cf, data, ctx->dns);
299
0
  }
300
301
0
  if(!cf_dns_ready_to_connect(cf, data)) {
302
0
    return CURLE_OK;
303
0
  }
304
305
0
  if(cf->next && !cf->next->connected) {
306
0
    bool sub_done;
307
0
    CURLcode result = Curl_conn_cf_connect(cf->next, data, &sub_done);
308
0
    if(result || !sub_done)
309
0
      return result;
310
0
    DEBUGASSERT(sub_done);
311
0
  }
312
313
  /* sub filter chain is connected, this means the filter has done
314
   * its work and is connected as well, if it has results or not. */
315
0
  CURL_TRC_CF(data, cf, "connected filter chain below");
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 CURLcode cf_dns_adjust_pollset(struct Curl_cfilter *cf,
331
                                      struct Curl_easy *data,
332
                                      struct easy_pollset *ps)
333
0
{
334
0
#ifdef USE_CURL_ASYNC
335
0
  if(!cf->connected) {
336
    /* The pollset only works when we have started the resolving.
337
     * Otherwise we might wait on the WAKEUP socketpair forever.
338
     * Since DNS filters can be added in the middle of a connect
339
     * attempt, they are not always started that way. */
340
0
    struct cf_dns_ctx *ctx = cf->ctx;
341
0
    if(!ctx->started) {
342
0
      CURL_TRC_CF(data, cf, "adjust_pollset, starting %s:%u queries=%s",
343
0
                  ctx->peer->hostname, ctx->peer->port,
344
0
                  Curl_resolv_query_str(ctx->dns_queries));
345
0
      ctx->started = TRUE;
346
0
      ctx->resolv_result = cf_dns_start(cf, data, &ctx->dns);
347
0
      if(ctx->resolv_result || ctx->dns) {
348
0
        Curl_multi_mark_dirty(data);
349
0
      }
350
0
    }
351
0
    return Curl_resolv_pollset(data, ps);
352
0
  }
353
#else
354
  (void)cf;
355
  (void)data;
356
  (void)ps;
357
#endif
358
0
  return CURLE_OK;
359
0
}
360
361
static CURLcode cf_dns_cntrl(struct Curl_cfilter *cf,
362
                             struct Curl_easy *data,
363
                             int event, int arg1, void *arg2)
364
0
{
365
0
  struct cf_dns_ctx *ctx = cf->ctx;
366
0
  CURLcode result = CURLE_OK;
367
368
0
  (void)arg1;
369
0
  (void)arg2;
370
0
  switch(event) {
371
0
  case CF_CTRL_DATA_DONE:
372
0
    if(ctx->dns) {
373
      /* Should only come here when the connect attempt failed and
374
       * `data` is giving up on it. On a successful connect, we already
375
       * unlinked the DNS entry. */
376
0
      Curl_dns_entry_unlink(data, &ctx->dns);
377
0
    }
378
0
    break;
379
0
  default:
380
0
    break;
381
0
  }
382
0
  return result;
383
0
}
384
385
struct Curl_cftype Curl_cft_dns = {
386
  "DNS",
387
  CF_TYPE_SETUP | CF_TYPE_DNS,
388
  CURL_LOG_LVL_NONE,
389
  cf_dns_destroy,
390
  cf_dns_connect,
391
  Curl_cf_def_shutdown,
392
  cf_dns_adjust_pollset,
393
  Curl_cf_def_data_pending,
394
  Curl_cf_def_send,
395
  Curl_cf_def_recv,
396
  cf_dns_cntrl,
397
  Curl_cf_def_conn_is_alive,
398
  Curl_cf_def_conn_keep_alive,
399
  Curl_cf_def_query,
400
};
401
402
static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
403
                              struct Curl_easy *data,
404
                              struct Curl_peer *peer,
405
                              uint8_t dns_queries,
406
                              uint8_t transport,
407
                              bool for_proxy)
408
0
{
409
0
  struct Curl_cfilter *cf = NULL;
410
0
  struct cf_dns_ctx *ctx;
411
0
  CURLcode result = CURLE_OK;
412
413
0
  (void)data;
414
0
  ctx = cf_dns_ctx_create(data, peer, dns_queries, transport,
415
0
                          for_proxy);
416
0
  if(!ctx) {
417
0
    result = CURLE_OUT_OF_MEMORY;
418
0
    goto out;
419
0
  }
420
421
0
  result = Curl_cf_create(&cf, &Curl_cft_dns, ctx);
422
423
0
out:
424
0
  *pcf = result ? NULL : cf;
425
0
  if(result)
426
0
    cf_dns_ctx_destroy(data, ctx);
427
0
  return result;
428
0
}
429
430
/* Adds a "resolv" filter at the top of the connection's filter chain.
431
 * The filter will resolve the peer on the first connect attempt. */
432
static CURLcode cf_dns_add(struct Curl_easy *data,
433
                           struct connectdata *conn,
434
                           int sockindex,
435
                           struct Curl_peer *peer,
436
                           uint8_t dns_queries,
437
                           uint8_t transport)
438
0
{
439
0
  struct Curl_cfilter *cf = NULL;
440
0
  bool for_proxy = FALSE;
441
0
  CURLcode result;
442
443
0
  if(!peer)
444
0
    return CURLE_FAILED_INIT;
445
0
#ifndef CURL_DISABLE_PROXY
446
0
  for_proxy = (peer == conn->socks_proxy.peer) ||
447
0
              (peer == conn->http_proxy.peer);
448
0
#endif
449
450
0
  result = cf_dns_create(&cf, data, peer, dns_queries, transport, for_proxy);
451
0
  if(result)
452
0
    goto out;
453
0
  Curl_conn_cf_add(data, conn, sockindex, cf);
454
0
out:
455
0
  return result;
456
0
}
457
458
/* Insert a new "resolv" filter directly after `cf`. It will
459
 * start a DNS resolve for the given peer on the
460
 * first connect attempt.
461
 * See socks.c on how this is used to make a non-blocking DNS
462
 * resolve during connect.
463
 */
464
static CURLcode cf_dns_insert_after(struct Curl_cfilter *cf_at,
465
                                    struct Curl_easy *data,
466
                                    struct Curl_peer *peer,
467
                                    uint8_t dns_queries,
468
                                    uint8_t transport)
469
0
{
470
0
  struct Curl_cfilter *cf;
471
0
  CURLcode result;
472
473
0
  result = cf_dns_create(&cf, data, peer, dns_queries, transport, FALSE);
474
0
  if(result)
475
0
    return result;
476
477
0
  Curl_conn_cf_insert_after(cf_at, cf);
478
0
  return CURLE_OK;
479
0
}
480
481
static CURLcode cf_dns_add_resolve(struct Curl_easy *data,
482
                                   struct connectdata *conn,
483
                                   int sockindex,
484
                                   struct Curl_peer *peer,
485
                                   uint8_t dns_queries,
486
                                   uint8_t transport)
487
0
{
488
0
  struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
489
0
  struct Curl_cfilter *cf_dns = NULL;
490
0
  bool is_addr = CURL_DNSQ_IS_ADDR(dns_queries);
491
492
0
  if((dns_queries & CURL_DNSQ_HTTPS) &&
493
0
     Curl_is_ipaddr(peer->hostname)) {
494
0
    dns_queries = (uint8_t)(dns_queries & ~CURL_DNSQ_HTTPS);
495
0
  }
496
497
0
  for(; cf && dns_queries; cf = cf->next) {
498
0
    if(cf->cft == &Curl_cft_dns) {
499
0
      struct cf_dns_ctx *ctx = cf->ctx;
500
0
      cf_dns = cf;
501
0
      if(Curl_peer_same_destination(ctx->peer, peer)) {
502
        /* subtract queries already being scheduled/ongoing */
503
0
        dns_queries = (uint8_t)(~ctx->dns_queries & dns_queries);
504
0
        if(!dns_queries) { /* already there */
505
0
          return CURLE_OK;
506
0
        }
507
0
        else if(is_addr && !ctx->started &&
508
0
                CURL_DNSQ_IS_ADDR(ctx->dns_queries)) {
509
0
          ctx->dns_queries |= dns_queries;
510
0
          CURL_TRC_DNS(data, "[%s] added queries=%s for %s:%u",
511
0
                       Curl_resolv_query_str(ctx->dns_queries),
512
0
                       Curl_resolv_query_str(dns_queries),
513
0
                       peer->hostname, peer->port);
514
0
          return CURLE_OK;
515
0
        }
516
0
      }
517
0
    }
518
0
  }
519
520
0
  if(dns_queries) {
521
    /* No existing filter is handling these, add a new DNS filter
522
     * (after the last one if there was one already. FCFS. */
523
0
    if(cf_dns)
524
0
      return cf_dns_insert_after(cf_dns, data, peer, dns_queries, transport);
525
0
    else
526
0
      return cf_dns_add(data, conn, sockindex, peer, dns_queries, transport);
527
0
  }
528
0
  return CURLE_OK;
529
0
}
530
531
CURLcode Curl_conn_dns_add_addr_resolve(struct Curl_easy *data,
532
                                        struct connectdata *conn,
533
                                        int sockindex,
534
                                        struct Curl_peer *peer,
535
                                        uint8_t dns_queries,
536
                                        uint8_t transport)
537
0
{
538
  /* should only have address query bits */
539
0
  DEBUGASSERT(!(dns_queries & ~CURL_DNSQ_ADDR));
540
0
  return cf_dns_add_resolve(data, conn, sockindex, peer,
541
0
                            (dns_queries & CURL_DNSQ_ADDR), transport);
542
0
}
543
544
/* Return the result of the DNS address resolution for peer.
545
 * Searches for a DNS filter from the top of the filter chain down. Returns
546
 * - CURLE_AGAIN when not done yet
547
 * - CURLE_OK when DNS was successfully resolved
548
 * - CURLR_FAILED_INIT when no resolv filter was found
549
 * - error returned by the DNS resolv
550
 */
551
CURLcode Curl_conn_dns_addr_result(struct connectdata *conn,
552
                                   int sockindex,
553
                                   struct Curl_peer *peer)
554
0
{
555
0
  struct Curl_cfilter *cf = conn->cfilter[sockindex];
556
0
  for(; cf; cf = cf->next) {
557
0
    if(cf->cft == &Curl_cft_dns) {
558
0
      struct cf_dns_ctx *ctx = cf->ctx;
559
0
      if(Curl_peer_same_destination(ctx->peer, peer) &&
560
0
         (ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))) {
561
0
        if(ctx->dns || ctx->resolv_result)
562
0
          return ctx->resolv_result;
563
0
        return CURLE_AGAIN;
564
0
      }
565
0
    }
566
0
  }
567
0
  return CURLE_FAILED_INIT; /* no one is resolving */
568
0
}
569
570
static const struct Curl_addrinfo *cf_dns_get_nth_ai(
571
  struct Curl_cfilter *cf,
572
  const struct Curl_addrinfo *ai,
573
  int ai_family, unsigned int index)
574
0
{
575
0
  struct cf_dns_ctx *ctx = cf->ctx;
576
0
  unsigned int i = 0;
577
578
0
  if((ai_family == AF_INET) && !(ctx->dns_queries & CURL_DNSQ_A))
579
0
    return NULL;
580
0
#ifdef USE_IPV6
581
0
  if((ai_family == AF_INET6) && !(ctx->dns_queries & CURL_DNSQ_AAAA))
582
0
    return NULL;
583
0
#endif
584
0
  for(i = 0; ai; ai = ai->ai_next) {
585
0
    if(ai->ai_family == ai_family) {
586
0
      if(i == index)
587
0
        return ai;
588
0
      ++i;
589
0
    }
590
0
  }
591
0
  return NULL;
592
0
}
593
594
/* Return the addrinfo at `index` for the given `family` from the
595
 * first "resolve" filter at the connection. If the DNS resolving is
596
 * not done yet or if no address for the family exists, returns NULL.
597
 */
598
const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
599
                                                 struct Curl_peer *peer,
600
                                                 int sockindex,
601
                                                 int ai_family,
602
                                                 unsigned int index)
603
0
{
604
0
  struct connectdata *conn = data->conn;
605
0
  struct Curl_cfilter *cf = conn->cfilter[sockindex];
606
607
0
  for(; cf; cf = cf->next) {
608
0
    if(cf->cft == &Curl_cft_dns) {
609
0
      struct cf_dns_ctx *ctx = cf->ctx;
610
0
      if(Curl_peer_same_destination(ctx->peer, peer) &&
611
0
         (ctx->dns_queries & (CURL_DNSQ_A|CURL_DNSQ_AAAA))) {
612
0
        CURL_TRC_CF(data, cf, "get %uth result for %s:%u, family=%d, dns=%d",
613
0
                    index, peer->hostname, peer->port, ai_family, !!ctx->dns);
614
0
        if(ctx->resolv_result)
615
0
          return NULL;
616
0
        else if(ctx->dns)
617
0
          return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index);
618
0
        else
619
0
          return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index);
620
0
      }
621
0
    }
622
0
  }
623
0
  return NULL;
624
0
}
625
626
#ifdef USE_HTTPSRR
627
CURLcode Curl_conn_dns_add_https_resolve(struct Curl_easy *data,
628
                                         struct connectdata *conn,
629
                                         int sockindex,
630
                                         struct Curl_peer *peer)
631
{
632
  return cf_dns_add_resolve(data, conn, sockindex, peer,
633
                            CURL_DNSQ_HTTPS, conn->transport_wanted);
634
}
635
636
/* Return the HTTPS-RR info from the first "resolve" filter at the
637
 * connection. If the DNS resolving is not done yet or if there
638
 * is no HTTPS-RR info, returns NULL.
639
 */
640
const struct Curl_https_rrinfo *
641
Curl_conn_dns_get_https(struct Curl_easy *data,
642
                        int sockindex,
643
                        struct Curl_peer *peer)
644
{
645
  struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
646
  for(; cf; cf = cf->next) {
647
    if(cf->cft == &Curl_cft_dns) {
648
      struct cf_dns_ctx *ctx = cf->ctx;
649
      if(Curl_peer_same_destination(ctx->peer, peer) &&
650
         (ctx->dns_queries & CURL_DNSQ_HTTPS)) {
651
        if(ctx->dns)
652
          return ctx->dns->hinfo;
653
        else
654
          return Curl_resolv_get_https(data, ctx->resolv_id);
655
      }
656
    }
657
  }
658
  return NULL;
659
}
660
661
bool Curl_conn_dns_resolved_https(struct Curl_easy *data,
662
                                  int sockindex,
663
                                  struct Curl_peer *peer)
664
{
665
  struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
666
  for(; cf; cf = cf->next) {
667
    if(cf->cft == &Curl_cft_dns) {
668
      struct cf_dns_ctx *ctx = cf->ctx;
669
      if(Curl_peer_same_destination(ctx->peer, peer) &&
670
         (ctx->dns_queries & CURL_DNSQ_HTTPS)) {
671
        if(ctx->dns)
672
          return TRUE;
673
        else
674
          return Curl_resolv_knows_https(data, ctx->resolv_id);
675
      }
676
    }
677
  }
678
  return TRUE;
679
}
680
681
#endif /* USE_HTTPSRR */