Coverage Report

Created: 2026-08-13 07:07

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(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
338
       const isc_sockaddr_t *destaddr, dns_transport_t *transport,
339
0
       unsigned int dispopt, dns_dispatch_t **dispatchp) {
340
0
  return dns_dispatch_createtcp(
341
0
    requestmgr->dispatchmgr, srcaddr, destaddr, transport,
342
0
    DNS_DISPATCHTYPE_REQUEST, dispopt, dispatchp);
343
0
}
344
345
static isc_result_t
346
udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
347
0
       const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) {
348
0
  dns_dispatch_t *disp = NULL;
349
350
0
  if (srcaddr == NULL) {
351
0
    switch (isc_sockaddr_pf(destaddr)) {
352
0
    case PF_INET:
353
0
      disp = dns_dispatchset_get(requestmgr->dispatches4);
354
0
      break;
355
356
0
    case PF_INET6:
357
0
      disp = dns_dispatchset_get(requestmgr->dispatches6);
358
0
      break;
359
360
0
    default:
361
0
      return ISC_R_NOTIMPLEMENTED;
362
0
    }
363
0
    if (disp == NULL) {
364
0
      return ISC_R_FAMILYNOSUPPORT;
365
0
    }
366
0
    dns_dispatch_attach(disp, dispatchp);
367
0
    return ISC_R_SUCCESS;
368
0
  }
369
370
0
  return dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr,
371
0
              dispatchp);
372
0
}
373
374
static isc_result_t
375
get_dispatch(bool tcp, dns_requestmgr_t *requestmgr,
376
       const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
377
       dns_transport_t *transport, unsigned int dispopt,
378
0
       dns_dispatch_t **dispatchp) {
379
0
  isc_result_t result;
380
381
0
  if (tcp) {
382
0
    result = tcp_dispatch(requestmgr, srcaddr, destaddr, transport,
383
0
              dispopt, dispatchp);
384
0
  } else {
385
0
    result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp);
386
0
  }
387
0
  return result;
388
0
}
389
390
isc_result_t
391
dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
392
          const isc_sockaddr_t *srcaddr,
393
          const isc_sockaddr_t *destaddr,
394
          dns_transport_t *transport,
395
          isc_tlsctx_cache_t *tlsctx_cache, unsigned int options,
396
          unsigned int connect_timeout, unsigned int timeout,
397
          unsigned int udptimeout, unsigned int udpretries,
398
          isc_loop_t *loop, isc_job_cb cb, void *arg,
399
0
          dns_request_t **requestp) {
400
0
  dns_request_t *request = NULL;
401
0
  isc_result_t result;
402
0
  isc_mem_t *mctx = NULL;
403
0
  dns_messageid_t id;
404
0
  bool tcp = false;
405
0
  isc_region_t r;
406
0
  unsigned int dispopt = 0;
407
408
0
  REQUIRE(VALID_REQUESTMGR(requestmgr));
409
0
  REQUIRE(msgbuf != NULL);
410
0
  REQUIRE(destaddr != NULL);
411
0
  REQUIRE(loop != NULL);
412
0
  REQUIRE(cb != NULL);
413
0
  REQUIRE(requestp != NULL && *requestp == NULL);
414
0
  REQUIRE(connect_timeout > 0 && timeout > 0);
415
0
  REQUIRE(udpretries != UINT_MAX);
416
417
0
  if (srcaddr != NULL) {
418
0
    REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
419
0
  }
420
421
0
  mctx = requestmgr->mctx;
422
423
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
424
425
0
  rcu_read_lock();
426
427
0
  if (atomic_load_acquire(&requestmgr->shuttingdown)) {
428
0
    result = ISC_R_SHUTTINGDOWN;
429
0
    goto done;
430
0
  }
431
432
0
  if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
433
0
    result = DNS_R_BLACKHOLED;
434
0
    goto done;
435
0
  }
436
437
0
  isc_buffer_usedregion(msgbuf, &r);
438
0
  if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
439
0
    result = DNS_R_FORMERR;
440
0
    goto done;
441
0
  }
442
443
0
  if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) {
444
0
    tcp = true;
445
0
  }
446
447
0
  request = new_request(mctx, loop, cb, arg, tcp, connect_timeout,
448
0
            timeout, udptimeout, udpretries);
449
450
0
  isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0));
451
0
  CHECK(isc_buffer_copyregion(request->query, &r));
452
453
0
  if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
454
0
    id = (r.base[0] << 8) | r.base[1];
455
0
    dispopt |= DNS_DISPATCHOPT_FIXEDID;
456
0
  }
457
458
0
  CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport,
459
0
         dispopt, &request->dispatch));
460
461
0
  CHECK(dns_dispatch_add(request->dispatch, loop, dispopt,
462
0
             request->connect_timeout, request->timeout,
463
0
             destaddr, transport, tlsctx_cache, req_connected,
464
0
             req_senddone, req_response, request, &id,
465
0
             &request->dispentry));
466
467
  /* Add message ID. */
468
0
  isc_buffer_usedregion(request->query, &r);
469
0
  r.base[0] = (id >> 8) & 0xff;
470
0
  r.base[1] = id & 0xff;
471
472
0
  request->destaddr = *destaddr;
473
0
  request->flags |= DNS_REQUEST_F_CONNECTING;
474
0
  if (tcp) {
475
0
    request->flags |= DNS_REQUEST_F_TCP;
476
0
  }
477
478
0
  dns_requestmgr_attach(requestmgr, &request->requestmgr);
479
0
  ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link);
480
481
0
  dns_request_ref(request); /* detached in req_connected() */
482
0
  result = dns_dispatch_connect(request->dispentry);
483
0
  if (result != ISC_R_SUCCESS) {
484
0
    dns_request_unref(request);
485
0
    goto cleanup;
486
0
  }
487
488
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
489
0
  *requestp = request;
490
491
0
cleanup:
492
0
  if (result != ISC_R_SUCCESS) {
493
0
    req_cleanup(request);
494
0
    dns_request_detach(&request);
495
0
    req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__,
496
0
      isc_result_totext(result));
497
0
  }
498
499
0
done:
500
0
  rcu_read_unlock();
501
0
  return result;
502
0
}
503
504
isc_result_t
505
dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
506
       const isc_sockaddr_t *srcaddr,
507
       const isc_sockaddr_t *destaddr, dns_transport_t *transport,
508
       isc_tlsctx_cache_t *tlsctx_cache, unsigned int options,
509
       dns_tsigkey_t *key, unsigned int connect_timeout,
510
       unsigned int timeout, unsigned int udptimeout,
511
       unsigned int udpretries, isc_loop_t *loop, isc_job_cb cb,
512
0
       void *arg, dns_request_t **requestp) {
513
0
  dns_request_t *request = NULL;
514
0
  isc_result_t result;
515
0
  isc_mem_t *mctx = NULL;
516
0
  dns_messageid_t id;
517
0
  bool tcp = false;
518
519
0
  REQUIRE(VALID_REQUESTMGR(requestmgr));
520
0
  REQUIRE(message != NULL);
521
0
  REQUIRE(destaddr != NULL);
522
0
  REQUIRE(loop != NULL);
523
0
  REQUIRE(cb != NULL);
524
0
  REQUIRE(requestp != NULL && *requestp == NULL);
525
0
  REQUIRE(connect_timeout > 0 && timeout > 0);
526
0
  REQUIRE(udpretries != UINT_MAX);
527
528
0
  if (srcaddr != NULL &&
529
0
      isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
530
0
  {
531
0
    return ISC_R_FAMILYMISMATCH;
532
0
  }
533
534
0
  mctx = requestmgr->mctx;
535
536
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
537
538
0
  rcu_read_lock();
539
540
0
  if (atomic_load_acquire(&requestmgr->shuttingdown)) {
541
0
    result = ISC_R_SHUTTINGDOWN;
542
0
    goto done;
543
0
  }
544
545
0
  if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
546
0
    result = DNS_R_BLACKHOLED;
547
0
    goto done;
548
0
  }
549
550
0
  if ((options & DNS_REQUESTOPT_TCP) != 0) {
551
0
    tcp = true;
552
0
  }
553
554
0
  request = new_request(mctx, loop, cb, arg, tcp, connect_timeout,
555
0
            timeout, udptimeout, udpretries);
556
557
0
  if (key != NULL) {
558
0
    dns_tsigkey_attach(key, &request->tsigkey);
559
0
  }
560
561
0
  CHECK(dns_message_settsigkey(message, request->tsigkey));
562
563
0
again:
564
0
  CHECK(get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport, 0,
565
0
         &request->dispatch));
566
567
0
  CHECK(dns_dispatch_add(request->dispatch, loop, 0,
568
0
             request->connect_timeout, request->timeout,
569
0
             destaddr, transport, tlsctx_cache, req_connected,
570
0
             req_senddone, req_response, request, &id,
571
0
             &request->dispentry));
572
573
0
  message->id = id;
574
0
  result = req_render(message, &request->query, options, mctx);
575
0
  if (result == DNS_R_USETCP && !tcp) {
576
    /* Try again using TCP. */
577
0
    dns_message_renderreset(message);
578
0
    dns_dispatch_done(&request->dispentry);
579
0
    dns_dispatch_detach(&request->dispatch);
580
0
    options |= DNS_REQUESTOPT_TCP;
581
0
    tcp = true;
582
0
    goto again;
583
0
  } else if (result != ISC_R_SUCCESS) {
584
0
    goto cleanup;
585
0
  }
586
587
0
  CHECK(dns_message_getquerytsig(message, mctx, &request->tsig));
588
589
0
  request->destaddr = *destaddr;
590
0
  request->flags |= DNS_REQUEST_F_CONNECTING;
591
0
  if (tcp) {
592
0
    request->flags |= DNS_REQUEST_F_TCP;
593
0
  }
594
595
0
  dns_requestmgr_attach(requestmgr, &request->requestmgr);
596
0
  ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link);
597
598
0
  dns_request_ref(request); /* detached in req_connected() */
599
0
  result = dns_dispatch_connect(request->dispentry);
600
0
  if (result != ISC_R_SUCCESS) {
601
0
    dns_request_unref(request);
602
0
    goto cleanup;
603
0
  }
604
605
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
606
0
  *requestp = request;
607
608
0
cleanup:
609
0
  if (result != ISC_R_SUCCESS) {
610
0
    dns_message_settsigkey(message, NULL);
611
0
    req_cleanup(request);
612
0
    dns_request_detach(&request);
613
0
    req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__,
614
0
      isc_result_totext(result));
615
0
  }
616
0
done:
617
0
  rcu_read_unlock();
618
619
0
  return result;
620
0
}
621
622
static isc_result_t
623
req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options,
624
0
     isc_mem_t *mctx) {
625
0
  isc_buffer_t *buf1 = NULL;
626
0
  isc_buffer_t *buf2 = NULL;
627
0
  isc_result_t result;
628
0
  isc_region_t r;
629
0
  dns_compress_t cctx;
630
0
  unsigned int compflags;
631
632
0
  REQUIRE(bufferp != NULL && *bufferp == NULL);
633
634
0
  req_log(ISC_LOG_DEBUG(3), "%s", __func__);
635
636
  /*
637
   * Create buffer able to hold largest possible message.
638
   */
639
0
  isc_buffer_allocate(mctx, &buf1, 65535);
640
641
0
  compflags = 0;
642
0
  if ((options & DNS_REQUESTOPT_LARGE) != 0) {
643
0
    compflags |= DNS_COMPRESS_LARGE;
644
0
  }
645
0
  if ((options & DNS_REQUESTOPT_CASE) != 0) {
646
0
    compflags |= DNS_COMPRESS_CASE;
647
0
  }
648
0
  dns_compress_init(&cctx, mctx, compflags);
649
650
  /*
651
   * Render message.
652
   */
653
0
  CHECK(dns_message_renderbegin(message, &cctx, buf1));
654
0
  CHECK(dns_message_rendersection(message, DNS_SECTION_QUESTION, 0));
655
0
  CHECK(dns_message_rendersection(message, DNS_SECTION_ANSWER, 0));
656
0
  CHECK(dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0));
657
0
  CHECK(dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0));
658
0
  CHECK(dns_message_renderend(message));
659
660
  /*
661
   * Copy rendered message to exact sized buffer.
662
   */
663
0
  isc_buffer_usedregion(buf1, &r);
664
0
  if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) {
665
0
    CLEANUP(DNS_R_USETCP);
666
0
  }
667
0
  isc_buffer_allocate(mctx, &buf2, r.length);
668
0
  CHECK(isc_buffer_copyregion(buf2, &r));
669
670
  /*
671
   * Cleanup and return.
672
   */
673
0
  dns_compress_invalidate(&cctx);
674
0
  isc_buffer_free(&buf1);
675
0
  *bufferp = buf2;
676
0
  return ISC_R_SUCCESS;
677
678
0
cleanup:
679
0
  dns_message_renderreset(message);
680
0
  dns_compress_invalidate(&cctx);
681
0
  if (buf1 != NULL) {
682
0
    isc_buffer_free(&buf1);
683
0
  }
684
0
  if (buf2 != NULL) {
685
0
    isc_buffer_free(&buf2);
686
0
  }
687
0
  return result;
688
0
}
689
690
static void
691
0
request_cancel(dns_request_t *request) {
692
0
  REQUIRE(VALID_REQUEST(request));
693
0
  REQUIRE(request->tid == isc_tid());
694
695
0
  if (DNS_REQUEST_COMPLETE(request)) {
696
    /* The request callback was already called */
697
0
    return;
698
0
  }
699
700
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
701
0
  req_sendevent(request, ISC_R_CANCELED); /* call asynchronously */
702
0
}
703
704
static void
705
0
req_cancel_cb(void *arg) {
706
0
  dns_request_t *request = arg;
707
708
0
  request_cancel(request);
709
0
  dns_request_unref(request);
710
0
}
711
712
void
713
0
dns_request_cancel(dns_request_t *request) {
714
0
  REQUIRE(VALID_REQUEST(request));
715
716
0
  if (request->tid == isc_tid()) {
717
0
    request_cancel(request);
718
0
  } else {
719
0
    dns_request_ref(request);
720
0
    isc_async_run(request->loop, req_cancel_cb, request);
721
0
  }
722
0
}
723
724
isc_result_t
725
dns_request_getresponse(dns_request_t *request, dns_message_t *message,
726
0
      unsigned int options) {
727
0
  REQUIRE(VALID_REQUEST(request));
728
0
  REQUIRE(request->tid == isc_tid());
729
0
  REQUIRE(request->answer != NULL);
730
731
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
732
733
0
  dns_message_setquerytsig(message, request->tsig);
734
0
  RETERR(dns_message_settsigkey(message, request->tsigkey));
735
0
  RETERR(dns_message_parse(message, request->answer, options));
736
0
  if (request->tsigkey != NULL) {
737
0
    RETERR(dns_tsig_verify(request->answer, message, NULL, NULL));
738
0
  }
739
0
  return ISC_R_SUCCESS;
740
0
}
741
742
isc_buffer_t *
743
0
dns_request_getanswer(dns_request_t *request) {
744
0
  REQUIRE(VALID_REQUEST(request));
745
0
  REQUIRE(request->tid == isc_tid());
746
747
0
  return request->answer;
748
0
}
749
750
bool
751
0
dns_request_usedtcp(dns_request_t *request) {
752
0
  REQUIRE(VALID_REQUEST(request));
753
0
  REQUIRE(request->tid == isc_tid());
754
755
0
  return (request->flags & DNS_REQUEST_F_TCP) != 0;
756
0
}
757
758
void
759
0
dns_request_destroy(dns_request_t **requestp) {
760
0
  REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
761
762
0
  dns_request_t *request = *requestp;
763
0
  *requestp = NULL;
764
765
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
766
767
0
  if (DNS_REQUEST_COMPLETE(request)) {
768
0
    dns_request_cancel(request);
769
0
  }
770
771
  /* final detach to shut down request */
772
0
  dns_request_detach(&request);
773
0
}
774
775
static void
776
req_connected(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED,
777
0
        void *arg) {
778
0
  dns_request_t *request = (dns_request_t *)arg;
779
780
0
  REQUIRE(VALID_REQUEST(request));
781
0
  REQUIRE(request->tid == isc_tid());
782
0
  REQUIRE(DNS_REQUEST_CONNECTING(request));
783
784
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
785
0
    isc_result_totext(eresult));
786
787
0
  request->flags &= ~DNS_REQUEST_F_CONNECTING;
788
789
0
  if (DNS_REQUEST_COMPLETE(request)) {
790
    /* The request callback was already called */
791
0
    goto detach;
792
0
  }
793
794
0
  if (eresult == ISC_R_SUCCESS) {
795
0
    req_send(request);
796
0
  } else {
797
0
    req_sendevent(request, eresult);
798
0
  }
799
800
0
detach:
801
  /* attached in dns_request_create/_createraw() */
802
0
  dns_request_unref(request);
803
0
}
804
805
static void
806
req_senddone(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED,
807
0
       void *arg) {
808
0
  dns_request_t *request = (dns_request_t *)arg;
809
810
0
  REQUIRE(VALID_REQUEST(request));
811
0
  REQUIRE(request->tid == isc_tid());
812
0
  REQUIRE(DNS_REQUEST_SENDING(request));
813
814
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
815
816
0
  request->flags &= ~DNS_REQUEST_F_SENDING;
817
818
0
  if (DNS_REQUEST_COMPLETE(request)) {
819
    /* The request callback was already called */
820
0
    goto detach;
821
0
  }
822
823
0
  if (eresult != ISC_R_SUCCESS) {
824
0
    req_sendevent(request, eresult);
825
0
  }
826
827
0
detach:
828
  /* attached in req_send() */
829
0
  dns_request_unref(request);
830
0
}
831
832
static void
833
0
req_response(isc_result_t eresult, isc_region_t *region, void *arg) {
834
0
  dns_request_t *request = (dns_request_t *)arg;
835
836
0
  if (eresult == ISC_R_CANCELED) {
837
0
    return;
838
0
  }
839
840
0
  REQUIRE(VALID_REQUEST(request));
841
0
  REQUIRE(request->tid == isc_tid());
842
843
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
844
0
    isc_result_totext(eresult));
845
846
0
  if (DNS_REQUEST_COMPLETE(request)) {
847
    /* The request callback was already called */
848
0
    return;
849
0
  }
850
851
0
  switch (eresult) {
852
0
  case ISC_R_TIMEDOUT:
853
0
    if (request->udpcount > 1 && !dns_request_usedtcp(request)) {
854
0
      request->udpcount -= 1;
855
0
      dns_dispatch_resume(request->dispentry,
856
0
              request->timeout);
857
0
      if (!DNS_REQUEST_SENDING(request)) {
858
0
        req_send(request);
859
0
      }
860
0
      return;
861
0
    }
862
0
    break;
863
0
  case ISC_R_SUCCESS:
864
    /* Copy region to request. */
865
0
    isc_buffer_allocate(request->mctx, &request->answer,
866
0
            region->length);
867
0
    eresult = isc_buffer_copyregion(request->answer, region);
868
0
    if (eresult != ISC_R_SUCCESS) {
869
0
      isc_buffer_free(&request->answer);
870
0
    }
871
0
    break;
872
0
  default:
873
0
    break;
874
0
  }
875
876
0
  req_sendevent(request, eresult);
877
0
}
878
879
static void
880
0
req_sendevent_cb(void *arg) {
881
0
  dns_request_t *request = arg;
882
883
0
  request->cb(request);
884
0
  dns_request_unref(request);
885
0
}
886
887
static void
888
0
req_cleanup(dns_request_t *request) {
889
0
  if (ISC_LINK_LINKED(request, link)) {
890
0
    ISC_LIST_UNLINK(request->requestmgr->requests[request->tid],
891
0
        request, link);
892
0
  }
893
0
  if (request->dispentry != NULL) {
894
0
    dns_dispatch_done(&request->dispentry);
895
0
  }
896
0
  if (request->dispatch != NULL) {
897
0
    dns_dispatch_detach(&request->dispatch);
898
0
  }
899
0
}
900
901
static void
902
0
req_sendevent(dns_request_t *request, isc_result_t result) {
903
0
  REQUIRE(VALID_REQUEST(request));
904
0
  REQUIRE(request->tid == isc_tid());
905
0
  REQUIRE(!DNS_REQUEST_COMPLETE(request));
906
907
0
  request->flags |= DNS_REQUEST_F_COMPLETE;
908
909
0
  req_cleanup(request);
910
911
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
912
0
    isc_result_totext(result));
913
914
0
  request->result = result;
915
916
  /*
917
   * Do not call request->cb directly as it introduces a dead lock
918
   * between dns_zonemgr_shutdown and sendtoprimary in lib/dns/zone.c
919
   * zone->lock.
920
   */
921
0
  dns_request_ref(request);
922
0
  isc_async_run(request->loop, req_sendevent_cb, request);
923
0
}
924
925
static void
926
0
req_destroy(dns_request_t *request) {
927
0
  REQUIRE(VALID_REQUEST(request));
928
0
  REQUIRE(request->tid == isc_tid());
929
0
  REQUIRE(!ISC_LINK_LINKED(request, link));
930
931
0
  req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
932
933
  /*
934
   * These should have been cleaned up before the
935
   * completion event was sent.
936
   */
937
0
  INSIST(!ISC_LINK_LINKED(request, link));
938
0
  INSIST(request->dispentry == NULL);
939
0
  INSIST(request->dispatch == NULL);
940
941
0
  request->magic = 0;
942
0
  if (request->query != NULL) {
943
0
    isc_buffer_free(&request->query);
944
0
  }
945
0
  if (request->answer != NULL) {
946
0
    isc_buffer_free(&request->answer);
947
0
  }
948
0
  if (request->tsig != NULL) {
949
0
    isc_buffer_free(&request->tsig);
950
0
  }
951
0
  if (request->tsigkey != NULL) {
952
0
    dns_tsigkey_detach(&request->tsigkey);
953
0
  }
954
0
  if (request->requestmgr != NULL) {
955
0
    dns_requestmgr_detach(&request->requestmgr);
956
0
  }
957
0
  isc_mem_putanddetach(&request->mctx, request, sizeof(*request));
958
0
}
959
960
void *
961
0
dns_request_getarg(dns_request_t *request) {
962
0
  REQUIRE(VALID_REQUEST(request));
963
0
  REQUIRE(request->tid == isc_tid());
964
965
0
  return request->arg;
966
0
}
967
968
isc_result_t
969
0
dns_request_getresult(dns_request_t *request) {
970
0
  REQUIRE(VALID_REQUEST(request));
971
0
  REQUIRE(request->tid == isc_tid());
972
973
0
  return request->result;
974
0
}
975
976
#if DNS_REQUEST_TRACE
977
ISC_REFCOUNT_TRACE_IMPL(dns_request, req_destroy);
978
#else
979
0
ISC_REFCOUNT_IMPL(dns_request, req_destroy);
Unexecuted instantiation: dns_request_ref
Unexecuted instantiation: dns_request_unref
Unexecuted instantiation: dns_request_detach
980
0
#endif
981
0
982
0
static void
983
0
req_log(int level, const char *fmt, ...) {
984
0
  va_list ap;
985
986
0
  va_start(ap, fmt);
987
0
  isc_log_vwrite(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST, level,
988
0
           fmt, ap);
989
  va_end(ap);
990
0
}