Coverage Report

Created: 2026-08-11 08:26

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