Coverage Report

Created: 2025-11-11 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/request.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <inttypes.h>
17
#include <stdbool.h>
18
19
#include <isc/async.h>
20
#include <isc/log.h>
21
#include <isc/loop.h>
22
#include <isc/magic.h>
23
#include <isc/mem.h>
24
#include <isc/netmgr.h>
25
#include <isc/result.h>
26
#include <isc/thread.h>
27
#include <isc/tls.h>
28
#include <isc/util.h>
29
30
#include <dns/acl.h>
31
#include <dns/compress.h>
32
#include <dns/dispatch.h>
33
#include <dns/message.h>
34
#include <dns/rdata.h>
35
#include <dns/rdatastruct.h>
36
#include <dns/request.h>
37
#include <dns/transport.h>
38
#include <dns/tsig.h>
39
40
0
#define REQUESTMGR_MAGIC      ISC_MAGIC('R', 'q', 'u', 'M')
41
#define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
42
43
0
#define REQUEST_MAGIC        ISC_MAGIC('R', 'q', 'u', '!')
44
#define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC)
45
46
typedef ISC_LIST(dns_request_t) dns_requestlist_t;
47
48
struct dns_requestmgr {
49
  unsigned int magic;
50
  isc_mem_t *mctx;
51
  isc_refcount_t references;
52
53
  atomic_bool shuttingdown;
54
55
  dns_dispatchmgr_t *dispatchmgr;
56
  dns_dispatchset_t *dispatches4;
57
  dns_dispatchset_t *dispatches6;
58
  dns_requestlist_t *requests;
59
};
60
61
struct dns_request {
62
  unsigned int magic;
63
  isc_refcount_t references;
64
65
  isc_mem_t *mctx;
66
  int32_t flags;
67
68
  isc_loop_t *loop;
69
  isc_tid_t tid;
70
71
  isc_result_t result;
72
  isc_job_cb cb;
73
  void *arg;
74
  ISC_LINK(dns_request_t) link;
75
  isc_buffer_t *query;
76
  isc_buffer_t *answer;
77
  dns_dispatch_t *dispatch;
78
  dns_dispentry_t *dispentry;
79
  dns_requestmgr_t *requestmgr;
80
  isc_buffer_t *tsig;
81
  dns_tsigkey_t *tsigkey;
82
  isc_sockaddr_t destaddr;
83
  unsigned int connect_timeout;
84
  unsigned int timeout;
85
  unsigned int udpcount;
86
};
87
88
0
#define DNS_REQUEST_F_CONNECTING (1 << 0)
89
0
#define DNS_REQUEST_F_SENDING  (1 << 1)
90
0
#define DNS_REQUEST_F_COMPLETE   (1 << 2)
91
0
#define DNS_REQUEST_F_TCP  (1 << 3)
92
93
#define DNS_REQUEST_CONNECTING(r) (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
94
0
#define DNS_REQUEST_SENDING(r)    (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
95
0
#define DNS_REQUEST_COMPLETE(r)   (((r)->flags & DNS_REQUEST_F_COMPLETE) != 0)
96
97
/***
98
 *** Forward
99
 ***/
100
101
static isc_result_t
102
req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options,
103
     isc_mem_t *mctx);
104
static void
105
req_response(isc_result_t result, isc_region_t *region, void *arg);
106
static void
107
req_senddone(isc_result_t eresult, isc_region_t *region, void *arg);
108
static void
109
req_cleanup(dns_request_t *request);
110
static void
111
req_sendevent(dns_request_t *request, isc_result_t result);
112
static void
113
req_connected(isc_result_t eresult, isc_region_t *region, void *arg);
114
static void
115
req_destroy(dns_request_t *request);
116
static void
117
req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
118
119
/***
120
 *** Public
121
 ***/
122
123
isc_result_t
124
dns_requestmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t *dispatchmgr,
125
          dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
126
0
          dns_requestmgr_t **requestmgrp) {
127
0
  REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
128
0
  REQUIRE(dispatchmgr != NULL);
129
130
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
131
132
0
  dns_requestmgr_t *requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
133
0
  *requestmgr = (dns_requestmgr_t){
134
0
    .magic = REQUESTMGR_MAGIC,
135
0
  };
136
0
  isc_mem_attach(mctx, &requestmgr->mctx);
137
138
0
  uint32_t nloops = isc_loopmgr_nloops();
139
0
  requestmgr->requests = isc_mem_cget(requestmgr->mctx, nloops,
140
0
              sizeof(requestmgr->requests[0]));
141
0
  for (size_t i = 0; i < nloops; i++) {
142
0
    ISC_LIST_INIT(requestmgr->requests[i]);
143
144
    /* unreferenced in requests_cancel() */
145
0
    isc_loop_ref(isc_loop_get(i));
146
0
  }
147
148
0
  dns_dispatchmgr_attach(dispatchmgr, &requestmgr->dispatchmgr);
149
150
0
  if (dispatchv4 != NULL) {
151
0
    dns_dispatchset_create(requestmgr->mctx, dispatchv4,
152
0
               &requestmgr->dispatches4,
153
0
               isc_loopmgr_nloops());
154
0
  }
155
0
  if (dispatchv6 != NULL) {
156
0
    dns_dispatchset_create(requestmgr->mctx, dispatchv6,
157
0
               &requestmgr->dispatches6,
158
0
               isc_loopmgr_nloops());
159
0
  }
160
161
0
  isc_refcount_init(&requestmgr->references, 1);
162
163
0
  req_log(ISC_LOG_DEBUG(3), "%s: %p", __func__, requestmgr);
164
165
0
  *requestmgrp = requestmgr;
166
0
  return ISC_R_SUCCESS;
167
0
}
168
169
static void
170
0
requests_cancel(void *arg) {
171
0
  dns_requestmgr_t *requestmgr = arg;
172
0
  isc_tid_t tid = isc_tid();
173
174
0
  ISC_LIST_FOREACH(requestmgr->requests[tid], request, link) {
175
0
    req_log(ISC_LOG_DEBUG(3), "%s(%" PRItid ": request %p",
176
0
      __func__, tid, request);
177
0
    if (DNS_REQUEST_COMPLETE(request)) {
178
      /* The callback has been already scheduled */
179
0
      continue;
180
0
    }
181
0
    req_sendevent(request, ISC_R_CANCELED);
182
0
  }
183
184
0
  isc_loop_unref(isc_loop_get(tid));
185
0
  dns_requestmgr_detach(&requestmgr);
186
0
}
187
188
void
189
0
dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
190
0
  bool first;
191
0
  REQUIRE(VALID_REQUESTMGR(requestmgr));
192
193
0
  req_log(ISC_LOG_DEBUG(3), "%s: %p", __func__, requestmgr);
194
195
0
  rcu_read_lock();
196
0
  first = atomic_compare_exchange_strong(&requestmgr->shuttingdown,
197
0
                 &(bool){ false }, true);
198
0
  rcu_read_unlock();
199
200
0
  if (!first) {
201
0
    return;
202
0
  }
203
204
  /*
205
   * Wait until all dns_request_create{raw}() are finished, so
206
   * there will be no new requests added to the lists.
207
   */
208
0
  synchronize_rcu();
209
210
0
  isc_tid_t tid = isc_tid();
211
0
  uint32_t nloops = isc_loopmgr_nloops();
212
0
  for (size_t i = 0; i < nloops; i++) {
213
0
    dns_requestmgr_ref(requestmgr);
214
215
0
    if (i == (uint32_t)tid) {
216
      /* Run the current loop synchronously */
217
0
      requests_cancel(requestmgr);
218
0
      continue;
219
0
    }
220
221
0
    isc_loop_t *loop = isc_loop_get(i);
222
0
    isc_async_run(loop, requests_cancel, requestmgr);
223
0
  }
224
0
}
225
226
static void
227
0
requestmgr_destroy(dns_requestmgr_t *requestmgr) {
228
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
229
230
0
  INSIST(atomic_load(&requestmgr->shuttingdown));
231
232
0
  size_t nloops = isc_loopmgr_nloops();
233
0
  for (size_t i = 0; i < nloops; i++) {
234
0
    INSIST(ISC_LIST_EMPTY(requestmgr->requests[i]));
235
0
  }
236
0
  isc_mem_cput(requestmgr->mctx, requestmgr->requests, nloops,
237
0
         sizeof(requestmgr->requests[0]));
238
239
0
  if (requestmgr->dispatches4 != NULL) {
240
0
    dns_dispatchset_destroy(&requestmgr->dispatches4);
241
0
  }
242
0
  if (requestmgr->dispatches6 != NULL) {
243
0
    dns_dispatchset_destroy(&requestmgr->dispatches6);
244
0
  }
245
0
  if (requestmgr->dispatchmgr != NULL) {
246
0
    dns_dispatchmgr_detach(&requestmgr->dispatchmgr);
247
0
  }
248
0
  requestmgr->magic = 0;
249
0
  isc_mem_putanddetach(&requestmgr->mctx, requestmgr,
250
0
           sizeof(*requestmgr));
251
0
}
252
253
#if DNS_REQUEST_TRACE
254
ISC_REFCOUNT_TRACE_IMPL(dns_requestmgr, requestmgr_destroy);
255
#else
256
0
ISC_REFCOUNT_IMPL(dns_requestmgr, requestmgr_destroy);
Unexecuted instantiation: dns_requestmgr_ref
Unexecuted instantiation: dns_requestmgr_unref
Unexecuted instantiation: dns_requestmgr_detach
257
0
#endif
258
0
259
0
static void
260
0
req_send(dns_request_t *request) {
261
0
  isc_region_t r;
262
263
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
264
265
0
  REQUIRE(VALID_REQUEST(request));
266
267
0
  isc_buffer_usedregion(request->query, &r);
268
269
0
  request->flags |= DNS_REQUEST_F_SENDING;
270
271
  /* detached in req_senddone() */
272
0
  dns_request_ref(request);
273
0
  dns_dispatch_send(request->dispentry, &r);
274
0
}
275
276
static dns_request_t *
277
new_request(isc_mem_t *mctx, isc_loop_t *loop, isc_job_cb cb, void *arg,
278
      bool tcp, unsigned int connect_timeout, unsigned int timeout,
279
0
      unsigned int udptimeout, unsigned int udpretries) {
280
0
  dns_request_t *request = isc_mem_get(mctx, sizeof(*request));
281
0
  *request = (dns_request_t){
282
0
    .magic = REQUEST_MAGIC,
283
0
    .loop = loop,
284
0
    .tid = isc_tid(),
285
0
    .cb = cb,
286
0
    .arg = arg,
287
0
    .link = ISC_LINK_INITIALIZER,
288
0
    .result = ISC_R_FAILURE,
289
0
    .udpcount = udpretries + 1,
290
0
  };
291
292
0
  isc_refcount_init(&request->references, 1);
293
0
  isc_mem_attach(mctx, &request->mctx);
294
295
0
  if (tcp) {
296
0
    request->connect_timeout = connect_timeout * 1000;
297
0
    request->timeout = timeout * 1000;
298
0
  } else {
299
0
    if (udptimeout == 0) {
300
0
      udptimeout = timeout / request->udpcount;
301
0
    }
302
0
    if (udptimeout == 0) {
303
0
      udptimeout = 1;
304
0
    }
305
0
    request->timeout = udptimeout * 1000;
306
0
  }
307
308
0
  return request;
309
0
}
310
311
static bool
312
0
isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) {
313
0
  dns_acl_t *blackhole;
314
0
  isc_netaddr_t netaddr;
315
0
  char netaddrstr[ISC_NETADDR_FORMATSIZE];
316
0
  int match;
317
0
  isc_result_t result;
318
319
0
  blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
320
0
  if (blackhole == NULL) {
321
0
    return false;
322
0
  }
323
324
0
  isc_netaddr_fromsockaddr(&netaddr, destaddr);
325
0
  result = dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, NULL);
326
0
  if (result != ISC_R_SUCCESS || match <= 0) {
327
0
    return false;
328
0
  }
329
330
0
  isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
331
0
  req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
332
333
0
  return true;
334
0
}
335
336
static isc_result_t
337
tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
338
       const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
339
0
       dns_transport_t *transport, dns_dispatch_t **dispatchp) {
340
0
  isc_result_t result;
341
342
0
  if (!newtcp) {
343
0
    result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
344
0
               srcaddr, transport, dispatchp);
345
0
    if (result == ISC_R_SUCCESS) {
346
0
      char peer[ISC_SOCKADDR_FORMATSIZE];
347
348
0
      isc_sockaddr_format(destaddr, peer, sizeof(peer));
349
0
      req_log(ISC_LOG_DEBUG(1),
350
0
        "attached to TCP connection to %s", peer);
351
0
      return result;
352
0
    }
353
0
  }
354
355
0
  result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
356
0
          destaddr, transport, 0, dispatchp);
357
0
  return result;
358
0
}
359
360
static isc_result_t
361
udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
362
0
       const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) {
363
0
  dns_dispatch_t *disp = NULL;
364
365
0
  if (srcaddr == NULL) {
366
0
    switch (isc_sockaddr_pf(destaddr)) {
367
0
    case PF_INET:
368
0
      disp = dns_dispatchset_get(requestmgr->dispatches4);
369
0
      break;
370
371
0
    case PF_INET6:
372
0
      disp = dns_dispatchset_get(requestmgr->dispatches6);
373
0
      break;
374
375
0
    default:
376
0
      return ISC_R_NOTIMPLEMENTED;
377
0
    }
378
0
    if (disp == NULL) {
379
0
      return ISC_R_FAMILYNOSUPPORT;
380
0
    }
381
0
    dns_dispatch_attach(disp, dispatchp);
382
0
    return ISC_R_SUCCESS;
383
0
  }
384
385
0
  return dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr,
386
0
              dispatchp);
387
0
}
388
389
static isc_result_t
390
get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr,
391
       const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
392
0
       dns_transport_t *transport, dns_dispatch_t **dispatchp) {
393
0
  isc_result_t result;
394
395
0
  if (tcp) {
396
0
    result = tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr,
397
0
              transport, dispatchp);
398
0
  } else {
399
0
    result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp);
400
0
  }
401
0
  return result;
402
0
}
403
404
isc_result_t
405
dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
406
          const isc_sockaddr_t *srcaddr,
407
          const isc_sockaddr_t *destaddr,
408
          dns_transport_t *transport,
409
          isc_tlsctx_cache_t *tlsctx_cache, unsigned int options,
410
          unsigned int connect_timeout, unsigned int timeout,
411
          unsigned int udptimeout, unsigned int udpretries,
412
          isc_loop_t *loop, isc_job_cb cb, void *arg,
413
0
          dns_request_t **requestp) {
414
0
  dns_request_t *request = NULL;
415
0
  isc_result_t result;
416
0
  isc_mem_t *mctx = NULL;
417
0
  dns_messageid_t id;
418
0
  bool tcp = false;
419
0
  bool newtcp = false;
420
0
  isc_region_t r;
421
0
  unsigned int dispopt = 0;
422
423
0
  REQUIRE(VALID_REQUESTMGR(requestmgr));
424
0
  REQUIRE(msgbuf != NULL);
425
0
  REQUIRE(destaddr != NULL);
426
0
  REQUIRE(loop != NULL);
427
0
  REQUIRE(cb != NULL);
428
0
  REQUIRE(requestp != NULL && *requestp == NULL);
429
0
  REQUIRE(connect_timeout > 0 && timeout > 0);
430
0
  REQUIRE(udpretries != UINT_MAX);
431
432
0
  if (srcaddr != NULL) {
433
0
    REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
434
0
  }
435
436
0
  mctx = requestmgr->mctx;
437
438
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
439
440
0
  rcu_read_lock();
441
442
0
  if (atomic_load_acquire(&requestmgr->shuttingdown)) {
443
0
    result = ISC_R_SHUTTINGDOWN;
444
0
    goto done;
445
0
  }
446
447
0
  if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
448
0
    result = DNS_R_BLACKHOLED;
449
0
    goto done;
450
0
  }
451
452
0
  isc_buffer_usedregion(msgbuf, &r);
453
0
  if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
454
0
    result = DNS_R_FORMERR;
455
0
    goto done;
456
0
  }
457
458
0
  if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) {
459
0
    tcp = true;
460
0
  }
461
462
0
  request = new_request(mctx, loop, cb, arg, tcp, connect_timeout,
463
0
            timeout, udptimeout, udpretries);
464
465
0
  isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0));
466
0
  result = isc_buffer_copyregion(request->query, &r);
467
0
  if (result != ISC_R_SUCCESS) {
468
0
    goto cleanup;
469
0
  }
470
471
0
again:
472
0
  result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr,
473
0
            transport, &request->dispatch);
474
0
  if (result != ISC_R_SUCCESS) {
475
0
    goto cleanup;
476
0
  }
477
478
0
  if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
479
0
    id = (r.base[0] << 8) | r.base[1];
480
0
    dispopt |= DNS_DISPATCHOPT_FIXEDID;
481
0
  }
482
483
0
  result = dns_dispatch_add(request->dispatch, loop, dispopt,
484
0
          request->connect_timeout, request->timeout,
485
0
          destaddr, transport, tlsctx_cache,
486
0
          req_connected, req_senddone, req_response,
487
0
          request, &id, &request->dispentry);
488
0
  if (result != ISC_R_SUCCESS) {
489
0
    if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
490
0
      dns_dispatch_detach(&request->dispatch);
491
0
      newtcp = true;
492
0
      goto again;
493
0
    }
494
495
0
    goto cleanup;
496
0
  }
497
498
  /* Add message ID. */
499
0
  isc_buffer_usedregion(request->query, &r);
500
0
  r.base[0] = (id >> 8) & 0xff;
501
0
  r.base[1] = id & 0xff;
502
503
0
  request->destaddr = *destaddr;
504
0
  request->flags |= DNS_REQUEST_F_CONNECTING;
505
0
  if (tcp) {
506
0
    request->flags |= DNS_REQUEST_F_TCP;
507
0
  }
508
509
0
  dns_requestmgr_attach(requestmgr, &request->requestmgr);
510
0
  ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link);
511
512
0
  dns_request_ref(request); /* detached in req_connected() */
513
0
  result = dns_dispatch_connect(request->dispentry);
514
0
  if (result != ISC_R_SUCCESS) {
515
0
    dns_request_unref(request);
516
0
    goto cleanup;
517
0
  }
518
519
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
520
0
  *requestp = request;
521
522
0
cleanup:
523
0
  if (result != ISC_R_SUCCESS) {
524
0
    req_cleanup(request);
525
0
    dns_request_detach(&request);
526
0
    req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__,
527
0
      isc_result_totext(result));
528
0
  }
529
530
0
done:
531
0
  rcu_read_unlock();
532
0
  return result;
533
0
}
534
535
isc_result_t
536
dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
537
       const isc_sockaddr_t *srcaddr,
538
       const isc_sockaddr_t *destaddr, dns_transport_t *transport,
539
       isc_tlsctx_cache_t *tlsctx_cache, unsigned int options,
540
       dns_tsigkey_t *key, unsigned int connect_timeout,
541
       unsigned int timeout, unsigned int udptimeout,
542
       unsigned int udpretries, isc_loop_t *loop, isc_job_cb cb,
543
0
       void *arg, dns_request_t **requestp) {
544
0
  dns_request_t *request = NULL;
545
0
  isc_result_t result;
546
0
  isc_mem_t *mctx = NULL;
547
0
  dns_messageid_t id;
548
0
  bool tcp = false;
549
550
0
  REQUIRE(VALID_REQUESTMGR(requestmgr));
551
0
  REQUIRE(message != NULL);
552
0
  REQUIRE(destaddr != NULL);
553
0
  REQUIRE(loop != NULL);
554
0
  REQUIRE(cb != NULL);
555
0
  REQUIRE(requestp != NULL && *requestp == NULL);
556
0
  REQUIRE(connect_timeout > 0 && timeout > 0);
557
0
  REQUIRE(udpretries != UINT_MAX);
558
559
0
  if (srcaddr != NULL &&
560
0
      isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
561
0
  {
562
0
    return ISC_R_FAMILYMISMATCH;
563
0
  }
564
565
0
  mctx = requestmgr->mctx;
566
567
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
568
569
0
  rcu_read_lock();
570
571
0
  if (atomic_load_acquire(&requestmgr->shuttingdown)) {
572
0
    result = ISC_R_SHUTTINGDOWN;
573
0
    goto done;
574
0
  }
575
576
0
  if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
577
0
    result = DNS_R_BLACKHOLED;
578
0
    goto done;
579
0
  }
580
581
0
  if ((options & DNS_REQUESTOPT_TCP) != 0) {
582
0
    tcp = true;
583
0
  }
584
585
0
  request = new_request(mctx, loop, cb, arg, tcp, connect_timeout,
586
0
            timeout, udptimeout, udpretries);
587
588
0
  if (key != NULL) {
589
0
    dns_tsigkey_attach(key, &request->tsigkey);
590
0
  }
591
592
0
  result = dns_message_settsigkey(message, request->tsigkey);
593
0
  if (result != ISC_R_SUCCESS) {
594
0
    goto cleanup;
595
0
  }
596
597
0
again:
598
0
  result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr,
599
0
            transport, &request->dispatch);
600
0
  if (result != ISC_R_SUCCESS) {
601
0
    goto cleanup;
602
0
  }
603
604
0
  result = dns_dispatch_add(request->dispatch, loop, 0,
605
0
          request->connect_timeout, request->timeout,
606
0
          destaddr, transport, tlsctx_cache,
607
0
          req_connected, req_senddone, req_response,
608
0
          request, &id, &request->dispentry);
609
0
  if (result != ISC_R_SUCCESS) {
610
0
    goto cleanup;
611
0
  }
612
613
0
  message->id = id;
614
0
  result = req_render(message, &request->query, options, mctx);
615
0
  if (result == DNS_R_USETCP && !tcp) {
616
    /* Try again using TCP. */
617
0
    dns_message_renderreset(message);
618
0
    dns_dispatch_done(&request->dispentry);
619
0
    dns_dispatch_detach(&request->dispatch);
620
0
    options |= DNS_REQUESTOPT_TCP;
621
0
    tcp = true;
622
0
    goto again;
623
0
  } else if (result != ISC_R_SUCCESS) {
624
0
    goto cleanup;
625
0
  }
626
627
0
  result = dns_message_getquerytsig(message, mctx, &request->tsig);
628
0
  if (result != ISC_R_SUCCESS) {
629
0
    goto cleanup;
630
0
  }
631
632
0
  request->destaddr = *destaddr;
633
0
  request->flags |= DNS_REQUEST_F_CONNECTING;
634
0
  if (tcp) {
635
0
    request->flags |= DNS_REQUEST_F_TCP;
636
0
  }
637
638
0
  dns_requestmgr_attach(requestmgr, &request->requestmgr);
639
0
  ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link);
640
641
0
  dns_request_ref(request); /* detached in req_connected() */
642
0
  result = dns_dispatch_connect(request->dispentry);
643
0
  if (result != ISC_R_SUCCESS) {
644
0
    dns_request_unref(request);
645
0
    goto cleanup;
646
0
  }
647
648
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
649
0
  *requestp = request;
650
651
0
cleanup:
652
0
  if (result != ISC_R_SUCCESS) {
653
0
    req_cleanup(request);
654
0
    dns_request_detach(&request);
655
0
    req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__,
656
0
      isc_result_totext(result));
657
0
  }
658
0
done:
659
0
  rcu_read_unlock();
660
661
0
  return result;
662
0
}
663
664
static isc_result_t
665
req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options,
666
0
     isc_mem_t *mctx) {
667
0
  isc_buffer_t *buf1 = NULL;
668
0
  isc_buffer_t *buf2 = NULL;
669
0
  isc_result_t result;
670
0
  isc_region_t r;
671
0
  dns_compress_t cctx;
672
0
  unsigned int compflags;
673
674
0
  REQUIRE(bufferp != NULL && *bufferp == NULL);
675
676
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
677
678
  /*
679
   * Create buffer able to hold largest possible message.
680
   */
681
0
  isc_buffer_allocate(mctx, &buf1, 65535);
682
683
0
  compflags = 0;
684
0
  if ((options & DNS_REQUESTOPT_LARGE) != 0) {
685
0
    compflags |= DNS_COMPRESS_LARGE;
686
0
  }
687
0
  if ((options & DNS_REQUESTOPT_CASE) != 0) {
688
0
    compflags |= DNS_COMPRESS_CASE;
689
0
  }
690
0
  dns_compress_init(&cctx, mctx, compflags);
691
692
  /*
693
   * Render message.
694
   */
695
0
  result = dns_message_renderbegin(message, &cctx, buf1);
696
0
  if (result != ISC_R_SUCCESS) {
697
0
    goto cleanup;
698
0
  }
699
0
  result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
700
0
  if (result != ISC_R_SUCCESS) {
701
0
    goto cleanup;
702
0
  }
703
0
  result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
704
0
  if (result != ISC_R_SUCCESS) {
705
0
    goto cleanup;
706
0
  }
707
0
  result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
708
0
  if (result != ISC_R_SUCCESS) {
709
0
    goto cleanup;
710
0
  }
711
0
  result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
712
0
  if (result != ISC_R_SUCCESS) {
713
0
    goto cleanup;
714
0
  }
715
0
  result = dns_message_renderend(message);
716
0
  if (result != ISC_R_SUCCESS) {
717
0
    goto cleanup;
718
0
  }
719
720
  /*
721
   * Copy rendered message to exact sized buffer.
722
   */
723
0
  isc_buffer_usedregion(buf1, &r);
724
0
  if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) {
725
0
    result = DNS_R_USETCP;
726
0
    goto cleanup;
727
0
  }
728
0
  isc_buffer_allocate(mctx, &buf2, r.length);
729
0
  result = isc_buffer_copyregion(buf2, &r);
730
0
  if (result != ISC_R_SUCCESS) {
731
0
    goto cleanup;
732
0
  }
733
734
  /*
735
   * Cleanup and return.
736
   */
737
0
  dns_compress_invalidate(&cctx);
738
0
  isc_buffer_free(&buf1);
739
0
  *bufferp = buf2;
740
0
  return ISC_R_SUCCESS;
741
742
0
cleanup:
743
0
  dns_message_renderreset(message);
744
0
  dns_compress_invalidate(&cctx);
745
0
  if (buf1 != NULL) {
746
0
    isc_buffer_free(&buf1);
747
0
  }
748
0
  if (buf2 != NULL) {
749
0
    isc_buffer_free(&buf2);
750
0
  }
751
0
  return result;
752
0
}
753
754
static void
755
0
request_cancel(dns_request_t *request) {
756
0
  REQUIRE(VALID_REQUEST(request));
757
0
  REQUIRE(request->tid == isc_tid());
758
759
0
  if (DNS_REQUEST_COMPLETE(request)) {
760
    /* The request callback was already called */
761
0
    return;
762
0
  }
763
764
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
765
0
  req_sendevent(request, ISC_R_CANCELED); /* call asynchronously */
766
0
}
767
768
static void
769
0
req_cancel_cb(void *arg) {
770
0
  dns_request_t *request = arg;
771
772
0
  request_cancel(request);
773
0
  dns_request_unref(request);
774
0
}
775
776
void
777
0
dns_request_cancel(dns_request_t *request) {
778
0
  REQUIRE(VALID_REQUEST(request));
779
780
0
  if (request->tid == isc_tid()) {
781
0
    request_cancel(request);
782
0
  } else {
783
0
    dns_request_ref(request);
784
0
    isc_async_run(request->loop, req_cancel_cb, request);
785
0
  }
786
0
}
787
788
isc_result_t
789
dns_request_getresponse(dns_request_t *request, dns_message_t *message,
790
0
      unsigned int options) {
791
0
  isc_result_t result;
792
793
0
  REQUIRE(VALID_REQUEST(request));
794
0
  REQUIRE(request->tid == isc_tid());
795
0
  REQUIRE(request->answer != NULL);
796
797
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
798
799
0
  dns_message_setquerytsig(message, request->tsig);
800
0
  result = dns_message_settsigkey(message, request->tsigkey);
801
0
  if (result != ISC_R_SUCCESS) {
802
0
    return result;
803
0
  }
804
0
  result = dns_message_parse(message, request->answer, options);
805
0
  if (result != ISC_R_SUCCESS) {
806
0
    return result;
807
0
  }
808
0
  if (request->tsigkey != NULL) {
809
0
    result = dns_tsig_verify(request->answer, message, NULL, NULL);
810
0
  }
811
0
  return result;
812
0
}
813
814
isc_buffer_t *
815
0
dns_request_getanswer(dns_request_t *request) {
816
0
  REQUIRE(VALID_REQUEST(request));
817
0
  REQUIRE(request->tid == isc_tid());
818
819
0
  return request->answer;
820
0
}
821
822
bool
823
0
dns_request_usedtcp(dns_request_t *request) {
824
0
  REQUIRE(VALID_REQUEST(request));
825
0
  REQUIRE(request->tid == isc_tid());
826
827
0
  return (request->flags & DNS_REQUEST_F_TCP) != 0;
828
0
}
829
830
void
831
0
dns_request_destroy(dns_request_t **requestp) {
832
0
  REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
833
834
0
  dns_request_t *request = *requestp;
835
0
  *requestp = NULL;
836
837
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
838
839
0
  if (DNS_REQUEST_COMPLETE(request)) {
840
0
    dns_request_cancel(request);
841
0
  }
842
843
  /* final detach to shut down request */
844
0
  dns_request_detach(&request);
845
0
}
846
847
static void
848
req_connected(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED,
849
0
        void *arg) {
850
0
  dns_request_t *request = (dns_request_t *)arg;
851
852
0
  REQUIRE(VALID_REQUEST(request));
853
0
  REQUIRE(request->tid == isc_tid());
854
0
  REQUIRE(DNS_REQUEST_CONNECTING(request));
855
856
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
857
0
    isc_result_totext(eresult));
858
859
0
  request->flags &= ~DNS_REQUEST_F_CONNECTING;
860
861
0
  if (DNS_REQUEST_COMPLETE(request)) {
862
    /* The request callback was already called */
863
0
    goto detach;
864
0
  }
865
866
0
  if (eresult == ISC_R_SUCCESS) {
867
0
    req_send(request);
868
0
  } else {
869
0
    req_sendevent(request, eresult);
870
0
  }
871
872
0
detach:
873
  /* attached in dns_request_create/_createraw() */
874
0
  dns_request_unref(request);
875
0
}
876
877
static void
878
req_senddone(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED,
879
0
       void *arg) {
880
0
  dns_request_t *request = (dns_request_t *)arg;
881
882
0
  REQUIRE(VALID_REQUEST(request));
883
0
  REQUIRE(request->tid == isc_tid());
884
0
  REQUIRE(DNS_REQUEST_SENDING(request));
885
886
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
887
888
0
  request->flags &= ~DNS_REQUEST_F_SENDING;
889
890
0
  if (DNS_REQUEST_COMPLETE(request)) {
891
    /* The request callback was already called */
892
0
    goto detach;
893
0
  }
894
895
0
  if (eresult != ISC_R_SUCCESS) {
896
0
    req_sendevent(request, eresult);
897
0
  }
898
899
0
detach:
900
  /* attached in req_send() */
901
0
  dns_request_unref(request);
902
0
}
903
904
static void
905
0
req_response(isc_result_t eresult, isc_region_t *region, void *arg) {
906
0
  dns_request_t *request = (dns_request_t *)arg;
907
908
0
  if (eresult == ISC_R_CANCELED) {
909
0
    return;
910
0
  }
911
912
0
  REQUIRE(VALID_REQUEST(request));
913
0
  REQUIRE(request->tid == isc_tid());
914
915
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
916
0
    isc_result_totext(eresult));
917
918
0
  if (DNS_REQUEST_COMPLETE(request)) {
919
    /* The request callback was already called */
920
0
    return;
921
0
  }
922
923
0
  switch (eresult) {
924
0
  case ISC_R_TIMEDOUT:
925
0
    if (request->udpcount > 1 && !dns_request_usedtcp(request)) {
926
0
      request->udpcount -= 1;
927
0
      dns_dispatch_resume(request->dispentry,
928
0
              request->timeout);
929
0
      if (!DNS_REQUEST_SENDING(request)) {
930
0
        req_send(request);
931
0
      }
932
0
      return;
933
0
    }
934
0
    break;
935
0
  case ISC_R_SUCCESS:
936
    /* Copy region to request. */
937
0
    isc_buffer_allocate(request->mctx, &request->answer,
938
0
            region->length);
939
0
    eresult = isc_buffer_copyregion(request->answer, region);
940
0
    if (eresult != ISC_R_SUCCESS) {
941
0
      isc_buffer_free(&request->answer);
942
0
    }
943
0
    break;
944
0
  default:
945
0
    break;
946
0
  }
947
948
0
  req_sendevent(request, eresult);
949
0
}
950
951
static void
952
0
req_sendevent_cb(void *arg) {
953
0
  dns_request_t *request = arg;
954
955
0
  request->cb(request);
956
0
  dns_request_unref(request);
957
0
}
958
959
static void
960
0
req_cleanup(dns_request_t *request) {
961
0
  if (ISC_LINK_LINKED(request, link)) {
962
0
    ISC_LIST_UNLINK(request->requestmgr->requests[request->tid],
963
0
        request, link);
964
0
  }
965
0
  if (request->dispentry != NULL) {
966
0
    dns_dispatch_done(&request->dispentry);
967
0
  }
968
0
  if (request->dispatch != NULL) {
969
0
    dns_dispatch_detach(&request->dispatch);
970
0
  }
971
0
}
972
973
static void
974
0
req_sendevent(dns_request_t *request, isc_result_t result) {
975
0
  REQUIRE(VALID_REQUEST(request));
976
0
  REQUIRE(request->tid == isc_tid());
977
0
  REQUIRE(!DNS_REQUEST_COMPLETE(request));
978
979
0
  request->flags |= DNS_REQUEST_F_COMPLETE;
980
981
0
  req_cleanup(request);
982
983
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
984
0
    isc_result_totext(result));
985
986
0
  request->result = result;
987
988
  /*
989
   * Do not call request->cb directly as it introduces a dead lock
990
   * between dns_zonemgr_shutdown and sendtoprimary in lib/dns/zone.c
991
   * zone->lock.
992
   */
993
0
  dns_request_ref(request);
994
0
  isc_async_run(request->loop, req_sendevent_cb, request);
995
0
}
996
997
static void
998
0
req_destroy(dns_request_t *request) {
999
0
  REQUIRE(VALID_REQUEST(request));
1000
0
  REQUIRE(request->tid == isc_tid());
1001
0
  REQUIRE(!ISC_LINK_LINKED(request, link));
1002
1003
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
1004
1005
  /*
1006
   * These should have been cleaned up before the
1007
   * completion event was sent.
1008
   */
1009
0
  INSIST(!ISC_LINK_LINKED(request, link));
1010
0
  INSIST(request->dispentry == NULL);
1011
0
  INSIST(request->dispatch == NULL);
1012
1013
0
  request->magic = 0;
1014
0
  if (request->query != NULL) {
1015
0
    isc_buffer_free(&request->query);
1016
0
  }
1017
0
  if (request->answer != NULL) {
1018
0
    isc_buffer_free(&request->answer);
1019
0
  }
1020
0
  if (request->tsig != NULL) {
1021
0
    isc_buffer_free(&request->tsig);
1022
0
  }
1023
0
  if (request->tsigkey != NULL) {
1024
0
    dns_tsigkey_detach(&request->tsigkey);
1025
0
  }
1026
0
  if (request->requestmgr != NULL) {
1027
0
    dns_requestmgr_detach(&request->requestmgr);
1028
0
  }
1029
0
  isc_mem_putanddetach(&request->mctx, request, sizeof(*request));
1030
0
}
1031
1032
void *
1033
0
dns_request_getarg(dns_request_t *request) {
1034
0
  REQUIRE(VALID_REQUEST(request));
1035
0
  REQUIRE(request->tid == isc_tid());
1036
1037
0
  return request->arg;
1038
0
}
1039
1040
isc_result_t
1041
0
dns_request_getresult(dns_request_t *request) {
1042
0
  REQUIRE(VALID_REQUEST(request));
1043
0
  REQUIRE(request->tid == isc_tid());
1044
1045
0
  return request->result;
1046
0
}
1047
1048
#if DNS_REQUEST_TRACE
1049
ISC_REFCOUNT_TRACE_IMPL(dns_request, req_destroy);
1050
#else
1051
0
ISC_REFCOUNT_IMPL(dns_request, req_destroy);
Unexecuted instantiation: dns_request_ref
Unexecuted instantiation: dns_request_unref
Unexecuted instantiation: dns_request_detach
1052
0
#endif
1053
0
1054
0
static void
1055
0
req_log(int level, const char *fmt, ...) {
1056
0
  va_list ap;
1057
1058
0
  va_start(ap, fmt);
1059
0
  isc_log_vwrite(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST, level,
1060
0
           fmt, ap);
1061
  va_end(ap);
1062
0
}