Coverage Report

Created: 2026-10-17 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/dispatch.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
/*
17
 * FIXME: Might need dns_dispatch_shuttingdown()
18
 */
19
20
#include <inttypes.h>
21
#include <stdbool.h>
22
#include <stdlib.h>
23
#include <sys/types.h>
24
#include <unistd.h>
25
26
#include <isc/async.h>
27
#include <isc/hash.h>
28
#include <isc/hashmap.h>
29
#include <isc/log.h>
30
#include <isc/loop.h>
31
#include <isc/mem.h>
32
#include <isc/mutex.h>
33
#include <isc/net.h>
34
#include <isc/netmgr.h>
35
#include <isc/portset.h>
36
#include <isc/random.h>
37
#include <isc/stats.h>
38
#include <isc/string.h>
39
#include <isc/tid.h>
40
#include <isc/time.h>
41
#include <isc/tls.h>
42
#include <isc/urcu.h>
43
#include <isc/util.h>
44
45
#include <dns/acl.h>
46
#include <dns/dispatch.h>
47
#include <dns/message.h>
48
#include <dns/stats.h>
49
#include <dns/transport.h>
50
#include <dns/types.h>
51
52
/*
53
 * Maximum number of queries to pipeline on a single shared TCP dispatch.
54
 * Once reached, the dispatch is removed from the hash table so new queries
55
 * get a fresh connection.  Can be overridden via 'named -T tcppipelining=N'.
56
 */
57
size_t dns_dispatch_tcppipelining = 256;
58
59
typedef ISC_LIST(dns_dispentry_t) dns_displist_t;
60
61
struct dns_dispatchmgr {
62
  /* Unlocked. */
63
  unsigned int magic;
64
  isc_refcount_t references;
65
  isc_mem_t *mctx;
66
  dns_acl_t *blackhole;
67
  isc_stats_t *stats;
68
69
  unsigned int reuse_timeout;
70
71
  uint32_t nloops;
72
73
  struct cds_lfht **tcps;
74
75
  struct cds_lfht *qids;
76
77
  in_port_t *v4ports;    /*%< available ports for IPv4 */
78
  unsigned int nv4ports; /*%< # of available ports for IPv4 */
79
  in_port_t *v6ports;    /*%< available ports for IPv6 */
80
  unsigned int nv6ports; /*%< # of available ports for IPv6 */
81
};
82
83
typedef enum {
84
  DNS_DISPATCHSTATE_NONE = 0UL,
85
  DNS_DISPATCHSTATE_CONNECTING,
86
  DNS_DISPATCHSTATE_CONNECTED,
87
  DNS_DISPATCHSTATE_CANCELED,
88
} dns_dispatchstate_t;
89
90
struct dns_dispentry {
91
  unsigned int magic;
92
  isc_refcount_t references;
93
  isc_mem_t *mctx;
94
  dns_dispatch_t *disp;
95
  isc_loop_t *loop;
96
  isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */
97
  dns_dispatchstate_t state;
98
  dns_transport_t *transport;
99
  isc_tlsctx_cache_t *tlsctx_cache;
100
  unsigned int retries;
101
  unsigned int connect_timeout;
102
  unsigned int timeout;
103
  isc_time_t start;
104
  isc_sockaddr_t local;
105
  isc_sockaddr_t peer;
106
  in_port_t port;
107
  dns_messageid_t id;
108
  dispatch_cb_t connected;
109
  dispatch_cb_t sent;
110
  dispatch_cb_t response;
111
  void *arg;
112
  bool reading;
113
  isc_result_t result;
114
  ISC_LINK(dns_dispentry_t) alink;
115
  ISC_LINK(dns_dispentry_t) plink;
116
  ISC_LINK(dns_dispentry_t) rlink;
117
118
  struct cds_lfht_node ht_node;
119
  struct rcu_head rcu_head;
120
};
121
122
struct dns_dispatch {
123
  /* Unlocked. */
124
  unsigned int magic; /*%< magic */
125
  isc_tid_t tid;
126
  isc_socktype_t socktype;
127
  isc_refcount_t references;
128
  isc_mem_t *mctx;
129
  dns_dispatchmgr_t *mgr;     /*%< dispatch manager */
130
  isc_nmhandle_t *handle;     /*%< netmgr handle for TCP connection */
131
  isc_sockaddr_t local;     /*%< local address */
132
  isc_sockaddr_t peer;      /*%< peer address (TCP) */
133
  dns_transport_t *transport; /*%< TCP transport parameters */
134
135
  dns_dispatchopt_t options;
136
  dns_dispatchstate_t state;
137
  dns_dispatchtype_t disptype;
138
139
  dns_messageid_t nextid; /*%< next sequential QID for TCP */
140
141
  bool reading;
142
143
  dns_displist_t pending;
144
  dns_displist_t active;
145
146
  uint_fast32_t requests; /*%< how many requests we have */
147
148
  unsigned int timedout;
149
150
  struct cds_lfht_node ht_node;
151
  struct rcu_head rcu_head;
152
};
153
154
0
#define RESPONSE_MAGIC    ISC_MAGIC('D', 'r', 's', 'p')
155
#define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
156
157
0
#define DISPATCH_MAGIC    ISC_MAGIC('D', 'i', 's', 'p')
158
#define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
159
160
0
#define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r')
161
#define VALID_DISPATCHMGR(e)  ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
162
163
#if DNS_DISPATCH_TRACE
164
#define dns_dispentry_ref(ptr) \
165
  dns_dispentry__ref(ptr, __func__, __FILE__, __LINE__)
166
#define dns_dispentry_unref(ptr) \
167
  dns_dispentry__unref(ptr, __func__, __FILE__, __LINE__)
168
#define dns_dispentry_attach(ptr, ptrp) \
169
  dns_dispentry__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
170
#define dns_dispentry_detach(ptrp) \
171
  dns_dispentry__detach(ptrp, __func__, __FILE__, __LINE__)
172
ISC_REFCOUNT_TRACE_DECL(dns_dispentry);
173
#else
174
ISC_REFCOUNT_DECL(dns_dispentry);
175
#endif
176
177
/*
178
 * The number of attempts to find unique <addr, port, query_id> combination
179
 */
180
0
#define QID_MAX_TRIES 64
181
182
/*
183
 * Initial and minimum QID table sizes.
184
 */
185
0
#define QIDS_INIT_SIZE (1 << 4) /* Must be power of 2 */
186
0
#define QIDS_MIN_SIZE  (1 << 4) /* Must be power of 2 */
187
188
/*
189
 * Statics.
190
 */
191
static void
192
dispatchmgr_destroy(dns_dispatchmgr_t *mgr);
193
194
static void
195
udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
196
   void *arg);
197
static void
198
tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
199
   void *arg);
200
static void
201
dispentry_cancel(dns_dispentry_t *resp, isc_result_t result);
202
static isc_result_t
203
dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
204
       isc_tid_t tid, dns_dispatch_t **dispp);
205
static void
206
udp_startrecv(isc_nmhandle_t *handle, dns_dispentry_t *resp);
207
static void
208
udp_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp);
209
static void
210
tcp_startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp);
211
static void
212
tcp_dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp,
213
         int64_t timeout);
214
static void
215
udp_dispatch_getnext(dns_dispentry_t *resp, int64_t timeout);
216
217
static const char *
218
0
socktype2str(dns_dispentry_t *resp) {
219
0
  dns_transport_type_t transport_type = DNS_TRANSPORT_UDP;
220
0
  dns_dispatch_t *disp = resp->disp;
221
222
0
  if (disp->socktype == isc_socktype_tcp) {
223
0
    if (resp->transport != NULL) {
224
0
      transport_type =
225
0
        dns_transport_get_type(resp->transport);
226
0
    } else {
227
0
      transport_type = DNS_TRANSPORT_TCP;
228
0
    }
229
0
  }
230
231
0
  switch (transport_type) {
232
0
  case DNS_TRANSPORT_UDP:
233
0
    return "UDP";
234
0
  case DNS_TRANSPORT_TCP:
235
0
    return "TCP";
236
0
  case DNS_TRANSPORT_TLS:
237
0
    return "TLS";
238
0
  case DNS_TRANSPORT_HTTP:
239
0
    return "HTTP";
240
0
  default:
241
0
    return "<unexpected>";
242
0
  }
243
0
}
244
245
static const char *
246
0
state2str(dns_dispatchstate_t state) {
247
0
  switch (state) {
248
0
  case DNS_DISPATCHSTATE_NONE:
249
0
    return "none";
250
0
  case DNS_DISPATCHSTATE_CONNECTING:
251
0
    return "connecting";
252
0
  case DNS_DISPATCHSTATE_CONNECTED:
253
0
    return "connected";
254
0
  case DNS_DISPATCHSTATE_CANCELED:
255
0
    return "canceled";
256
0
  default:
257
0
    return "<unexpected>";
258
0
  }
259
0
}
260
261
static void
262
mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
263
  ISC_FORMAT_PRINTF(3, 4);
264
265
static void
266
0
mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
267
0
  char msgbuf[2048];
268
0
  va_list ap;
269
270
0
  if (!isc_log_wouldlog(level)) {
271
0
    return;
272
0
  }
273
274
0
  va_start(ap, fmt);
275
0
  vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
276
0
  va_end(ap);
277
278
0
  isc_log_write(DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH, level,
279
0
          "dispatchmgr %p: %s", mgr, msgbuf);
280
0
}
281
282
static void
283
0
inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
284
0
  if (mgr->stats != NULL) {
285
0
    isc_stats_increment(mgr->stats, counter);
286
0
  }
287
0
}
288
289
static void
290
0
dec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
291
0
  if (mgr->stats != NULL) {
292
0
    isc_stats_decrement(mgr->stats, counter);
293
0
  }
294
0
}
295
296
static void
297
dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
298
  ISC_FORMAT_PRINTF(3, 4);
299
300
static void
301
0
dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
302
0
  char msgbuf[2048];
303
0
  va_list ap;
304
0
  int r;
305
306
0
  if (!isc_log_wouldlog(level)) {
307
0
    return;
308
0
  }
309
310
0
  va_start(ap, fmt);
311
0
  r = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
312
0
  if (r < 0) {
313
0
    msgbuf[0] = '\0';
314
0
  } else if ((unsigned int)r >= sizeof(msgbuf)) {
315
    /* Truncated */
316
0
    msgbuf[sizeof(msgbuf) - 1] = '\0';
317
0
  }
318
0
  va_end(ap);
319
320
0
  isc_log_write(DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH, level,
321
0
          "dispatch %p: %s", disp, msgbuf);
322
0
}
323
324
static void
325
dispentry_log(dns_dispentry_t *resp, int level, const char *fmt, ...)
326
  ISC_FORMAT_PRINTF(3, 4);
327
328
static void
329
0
dispentry_log(dns_dispentry_t *resp, int level, const char *fmt, ...) {
330
0
  char msgbuf[2048];
331
0
  va_list ap;
332
0
  int r;
333
334
0
  if (!isc_log_wouldlog(level)) {
335
0
    return;
336
0
  }
337
338
0
  va_start(ap, fmt);
339
0
  r = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
340
0
  if (r < 0) {
341
0
    msgbuf[0] = '\0';
342
0
  } else if ((unsigned int)r >= sizeof(msgbuf)) {
343
    /* Truncated */
344
0
    msgbuf[sizeof(msgbuf) - 1] = '\0';
345
0
  }
346
0
  va_end(ap);
347
348
0
  dispatch_log(resp->disp, level, "%s response %p: %s",
349
0
         socktype2str(resp), resp, msgbuf);
350
0
}
351
352
/*%
353
 * Choose a random port number for a dispatch entry.
354
 */
355
static isc_result_t
356
setup_socket(dns_dispatch_t *disp, dns_dispentry_t *resp,
357
0
       const isc_sockaddr_t *dest, in_port_t *portp) {
358
0
  dns_dispatchmgr_t *mgr = disp->mgr;
359
0
  unsigned int nports;
360
0
  in_port_t *ports = NULL;
361
0
  in_port_t port = *portp;
362
363
0
  if (resp->retries++ > 5) {
364
0
    return ISC_R_FAILURE;
365
0
  }
366
367
0
  if (isc_sockaddr_pf(&disp->local) == AF_INET) {
368
0
    nports = mgr->nv4ports;
369
0
    ports = mgr->v4ports;
370
0
  } else {
371
0
    nports = mgr->nv6ports;
372
0
    ports = mgr->v6ports;
373
0
  }
374
0
  if (nports == 0) {
375
0
    return ISC_R_ADDRNOTAVAIL;
376
0
  }
377
378
0
  resp->local = disp->local;
379
0
  resp->peer = *dest;
380
381
0
  if (port == 0) {
382
0
    port = ports[isc_random_uniform(nports)];
383
0
    isc_sockaddr_setport(&resp->local, port);
384
0
    *portp = port;
385
0
  }
386
0
  resp->port = port;
387
388
0
  return ISC_R_SUCCESS;
389
0
}
390
391
static uint32_t
392
0
qid_hash(const dns_dispentry_t *dispentry) {
393
0
  isc_hash32_t hash;
394
395
0
  isc_hash32_init(&hash);
396
397
0
  isc_sockaddr_hash_ex(&hash, &dispentry->peer, true);
398
0
  isc_hash32_hash(&hash, &dispentry->id, sizeof(dispentry->id), true);
399
0
  isc_hash32_hash(&hash, &dispentry->port, sizeof(dispentry->port), true);
400
401
0
  return isc_hash32_finalize(&hash);
402
0
}
403
404
static int
405
0
qid_match(struct cds_lfht_node *node, const void *key0) {
406
0
  const dns_dispentry_t *dispentry =
407
0
    caa_container_of(node, dns_dispentry_t, ht_node);
408
0
  const dns_dispentry_t *key = key0;
409
410
0
  return dispentry->id == key->id && dispentry->port == key->port &&
411
0
         isc_sockaddr_equal(&dispentry->peer, &key->peer);
412
0
}
413
414
static void
415
0
dispentry_destroy_rcu(struct rcu_head *rcu_head) {
416
0
  dns_dispentry_t *resp = caa_container_of(rcu_head, dns_dispentry_t,
417
0
             rcu_head);
418
0
  isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp));
419
0
}
420
421
static void
422
0
dispentry_destroy(dns_dispentry_t *resp) {
423
0
  dns_dispatch_t *disp = resp->disp;
424
425
  /*
426
   * We need to call this from here in case there's an external event that
427
   * shuts down our dispatch (like ISC_R_SHUTTINGDOWN).
428
   */
429
0
  dispentry_cancel(resp, ISC_R_CANCELED);
430
431
0
  INSIST(disp->requests > 0);
432
0
  disp->requests--;
433
434
0
  resp->magic = 0;
435
436
0
  INSIST(!ISC_LINK_LINKED(resp, plink));
437
0
  INSIST(!ISC_LINK_LINKED(resp, alink));
438
0
  INSIST(!ISC_LINK_LINKED(resp, rlink));
439
440
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "destroying");
441
442
0
  if (resp->handle != NULL) {
443
0
    dispentry_log(resp, ISC_LOG_DEBUG(90),
444
0
            "detaching handle %p from %p", resp->handle,
445
0
            &resp->handle);
446
0
    isc_nmhandle_detach(&resp->handle);
447
0
  }
448
449
0
  if (resp->tlsctx_cache != NULL) {
450
0
    isc_tlsctx_cache_detach(&resp->tlsctx_cache);
451
0
  }
452
453
0
  if (resp->transport != NULL) {
454
0
    dns_transport_detach(&resp->transport);
455
0
  }
456
457
0
  dns_dispatch_detach(&disp); /* DISPATCH001 */
458
459
0
  call_rcu(&resp->rcu_head, dispentry_destroy_rcu);
460
0
}
461
462
#if DNS_DISPATCH_TRACE
463
ISC_REFCOUNT_TRACE_IMPL(dns_dispentry, dispentry_destroy);
464
#else
465
0
ISC_REFCOUNT_IMPL(dns_dispentry, dispentry_destroy);
Unexecuted instantiation: dns_dispentry_ref
Unexecuted instantiation: dns_dispentry_unref
Unexecuted instantiation: dns_dispentry_detach
466
0
#endif
467
0
468
0
/*
469
0
 * How long in milliseconds has it been since this dispentry
470
0
 * started reading?
471
0
 */
472
0
static unsigned int
473
0
dispentry_runtime(dns_dispentry_t *resp, const isc_time_t *now) {
474
0
  if (isc_time_isepoch(&resp->start)) {
475
0
    return 0;
476
0
  }
477
478
0
  return isc_time_microdiff(now, &resp->start) / 1000;
479
0
}
480
481
/*
482
 * General flow:
483
 *
484
 * If I/O result == CANCELED or error, free the buffer.
485
 *
486
 * If query, free the buffer, restart.
487
 *
488
 * If response:
489
 *  Allocate event, fill in details.
490
 *    If cannot allocate, free buffer, restart.
491
 *  find target.  If not found, free buffer, restart.
492
 *  if event queue is not empty, queue.  else, send.
493
 *  restart.
494
 */
495
static void
496
udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
497
0
   void *arg) {
498
0
  dns_dispentry_t *resp = (dns_dispentry_t *)arg;
499
0
  dns_dispatch_t *disp = NULL;
500
0
  dns_messageid_t id;
501
0
  isc_result_t dres;
502
0
  isc_buffer_t source;
503
0
  unsigned int flags;
504
0
  isc_sockaddr_t peer;
505
0
  isc_netaddr_t netaddr;
506
0
  int match;
507
0
  int64_t timeout = 0;
508
0
  bool respond = true;
509
0
  isc_time_t now;
510
511
0
  REQUIRE(VALID_RESPONSE(resp));
512
0
  REQUIRE(VALID_DISPATCH(resp->disp));
513
514
0
  disp = resp->disp;
515
516
0
  REQUIRE(disp->tid == isc_tid());
517
0
  INSIST(resp->reading);
518
0
  resp->reading = false;
519
520
0
  if (resp->state == DNS_DISPATCHSTATE_CANCELED) {
521
    /*
522
     * Nobody is interested in the callback if the response
523
     * has been canceled already.  Detach from the response
524
     * and the handle.
525
     */
526
0
    respond = false;
527
0
    eresult = ISC_R_CANCELED;
528
0
  }
529
530
0
  dispentry_log(resp, ISC_LOG_DEBUG(90),
531
0
          "read callback:%s, requests %" PRIuFAST32,
532
0
          isc_result_totext(eresult), disp->requests);
533
534
0
  if (eresult != ISC_R_SUCCESS) {
535
    /*
536
     * This is most likely a network error on a connected
537
     * socket, a timeout, or the query has been canceled.
538
     * It makes no sense to check the address or parse the
539
     * packet, but we can return the error to the caller.
540
     */
541
0
    goto done;
542
0
  }
543
544
0
  peer = isc_nmhandle_peeraddr(handle);
545
0
  isc_netaddr_fromsockaddr(&netaddr, &peer);
546
547
  /*
548
   * If this is from a blackholed address, drop it.
549
   */
550
0
  if (disp->mgr->blackhole != NULL &&
551
0
      dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match,
552
0
        NULL) == ISC_R_SUCCESS &&
553
0
      match > 0)
554
0
  {
555
0
    if (isc_log_wouldlog(ISC_LOG_DEBUG(10))) {
556
0
      char netaddrstr[ISC_NETADDR_FORMATSIZE];
557
0
      isc_netaddr_format(&netaddr, netaddrstr,
558
0
             sizeof(netaddrstr));
559
0
      dispentry_log(resp, ISC_LOG_DEBUG(10),
560
0
              "blackholed packet from %s", netaddrstr);
561
0
    }
562
0
    goto next;
563
0
  }
564
565
  /*
566
   * Peek into the buffer to see what we can see.
567
   */
568
0
  id = resp->id;
569
0
  isc_buffer_init(&source, region->base, region->length);
570
0
  isc_buffer_add(&source, region->length);
571
0
  dres = dns_message_peekheader(&source, &id, &flags);
572
0
  if (dres != ISC_R_SUCCESS) {
573
0
    char netaddrstr[ISC_NETADDR_FORMATSIZE];
574
0
    isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
575
0
    dispentry_log(resp, ISC_LOG_DEBUG(10),
576
0
            "got garbage packet from %s", netaddrstr);
577
0
    goto next;
578
0
  }
579
580
0
  dispentry_log(resp, ISC_LOG_DEBUG(92),
581
0
          "got valid DNS message header, /QR %c, id %u",
582
0
          ((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0', id);
583
584
  /*
585
   * Look at the message flags.  If it's a query, ignore it.
586
   */
587
0
  if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
588
0
    goto next;
589
0
  }
590
591
  /*
592
   * The QID and the address must match the expected ones.  A
593
   * mismatch can happen during normal operation only when a stale
594
   * response from a previous query arrives late, which is rare in
595
   * practice; treat any mismatch as a possible spoofing attempt and
596
   * let the caller retry over TCP to prevent off-path spoofing.
597
   */
598
0
  if (resp->id != id || !isc_sockaddr_equal(&peer, &resp->peer)) {
599
0
    dispentry_log(resp, ISC_LOG_DEBUG(90),
600
0
            "response doesn't match");
601
0
    inc_stats(disp->mgr, dns_resstatscounter_mismatch);
602
0
    eresult = DNS_R_MISMATCH;
603
0
    goto done;
604
0
  }
605
606
  /*
607
   * We have the right resp, so call the caller back.
608
   */
609
0
  goto done;
610
611
0
next:
612
  /*
613
   * This is the wrong response.  Check whether there is still enough
614
   * time to wait for the correct one to arrive before the timeout fires.
615
   */
616
0
  now = isc_loop_now(resp->loop);
617
0
  if (resp->timeout > 0) {
618
0
    timeout = resp->timeout - dispentry_runtime(resp, &now);
619
0
    if (timeout <= 0) {
620
      /*
621
       * The time window for receiving the correct response is
622
       * already closed, libuv has just not processed the
623
       * socket timer yet.  Invoke the read callback,
624
       * indicating a timeout.
625
       */
626
0
      eresult = ISC_R_TIMEDOUT;
627
0
      goto done;
628
0
    }
629
0
  }
630
631
  /*
632
   * Do not invoke the read callback just yet and instead wait for the
633
   * proper response to arrive until the original timeout fires.
634
   */
635
0
  respond = false;
636
0
  udp_dispatch_getnext(resp, timeout);
637
638
0
done:
639
0
  if (respond) {
640
0
    dispentry_log(resp, ISC_LOG_DEBUG(90),
641
0
            "UDP read callback on %p: %s", handle,
642
0
            isc_result_totext(eresult));
643
0
    resp->response(eresult, region, resp->arg);
644
0
  }
645
646
0
  dns_dispentry_detach(&resp); /* DISPENTRY003 */
647
0
}
648
649
static isc_result_t
650
0
tcp_recv_oldest(dns_dispatch_t *disp, dns_dispentry_t **respp) {
651
0
  dns_dispentry_t *resp = NULL;
652
0
  resp = ISC_LIST_HEAD(disp->active);
653
0
  if (resp != NULL) {
654
0
    disp->timedout++;
655
656
0
    *respp = resp;
657
0
    return ISC_R_TIMEDOUT;
658
0
  }
659
660
0
  return ISC_R_NOTFOUND;
661
0
}
662
663
static isc_result_t
664
tcp_recv_success(dns_dispatch_t *disp, isc_region_t *region,
665
0
     dns_dispentry_t **respp) {
666
0
  isc_buffer_t source;
667
0
  dns_messageid_t id;
668
0
  unsigned int flags;
669
0
  isc_result_t result = ISC_R_SUCCESS;
670
671
0
  dispatch_log(disp, ISC_LOG_DEBUG(90),
672
0
         "TCP read success, length == %d, addr = %p",
673
0
         region->length, region->base);
674
675
  /*
676
   * Peek into the buffer to see what we can see.
677
   */
678
0
  isc_buffer_init(&source, region->base, region->length);
679
0
  isc_buffer_add(&source, region->length);
680
0
  result = dns_message_peekheader(&source, &id, &flags);
681
0
  if (result != ISC_R_SUCCESS) {
682
0
    dispatch_log(disp, ISC_LOG_DEBUG(10), "got garbage packet");
683
0
    return ISC_R_UNEXPECTED;
684
0
  }
685
686
0
  dispatch_log(disp, ISC_LOG_DEBUG(92),
687
0
         "got valid DNS message header, /QR %c, id %u",
688
0
         ((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0', id);
689
690
  /*
691
   * Look at the message flags.  If it's a query, ignore it and keep
692
   * reading.
693
   */
694
0
  if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
695
0
    dispatch_log(disp, ISC_LOG_DEBUG(10),
696
0
           "got DNS query instead of answer");
697
0
    return ISC_R_UNEXPECTED;
698
0
  }
699
700
  /*
701
   * We have a valid response; find the associated dispentry by
702
   * scanning disp->active.  With sequential IDs and a bounded
703
   * pipelining limit this is a short linear scan.
704
   */
705
0
  dns_dispentry_t *resp = NULL;
706
0
  ISC_LIST_FOREACH(disp->active, r, alink) {
707
0
    if (r->id == id) {
708
0
      resp = r;
709
0
      break;
710
0
    }
711
0
  }
712
713
0
  if (resp != NULL) {
714
0
    *respp = resp;
715
0
  } else {
716
0
    result = ISC_R_NOTFOUND;
717
0
  }
718
0
  dispatch_log(disp, ISC_LOG_DEBUG(90), "search for response: %s",
719
0
         isc_result_totext(result));
720
721
0
  return result;
722
0
}
723
724
static void
725
tcp_recv_add(dns_displist_t *resps, dns_dispentry_t *resp,
726
0
       isc_result_t result) {
727
0
  dns_dispentry_ref(resp); /* DISPENTRY009 */
728
0
  ISC_LIST_UNLINK(resp->disp->active, resp, alink);
729
0
  ISC_LIST_APPEND(*resps, resp, rlink);
730
0
  INSIST(resp->reading);
731
0
  resp->reading = false;
732
0
  resp->result = result;
733
0
}
734
735
static void
736
tcp_recv_shutdown(dns_dispatch_t *disp, dns_displist_t *resps,
737
0
      isc_result_t result) {
738
  /*
739
   * If there are any active responses, shut them all down.
740
   */
741
0
  ISC_LIST_FOREACH(disp->active, resp, alink) {
742
0
    tcp_recv_add(resps, resp, result);
743
0
  }
744
0
  disp->state = DNS_DISPATCHSTATE_CANCELED;
745
746
  /* Close now so the socket doesn't linger in CLOSE-WAIT. */
747
0
  if (disp->handle != NULL) {
748
0
    isc_nmhandle_close(disp->handle);
749
0
  }
750
0
}
751
752
static void
753
0
tcp_recv_processall(dns_displist_t *resps, isc_region_t *region) {
754
0
  ISC_LIST_FOREACH(*resps, resp, rlink) {
755
0
    ISC_LIST_UNLINK(*resps, resp, rlink);
756
757
0
    dispentry_log(resp, ISC_LOG_DEBUG(90), "read callback: %s",
758
0
            isc_result_totext(resp->result));
759
0
    resp->response(resp->result, region, resp->arg);
760
0
    dns_dispentry_detach(&resp); /* DISPENTRY009 */
761
0
  }
762
0
}
763
764
static void
765
0
tcp_startrecv_idle(dns_dispatch_t *disp) {
766
0
  REQUIRE(disp->mgr->reuse_timeout > 0);
767
768
  /*
769
   * No outstanding responses, but the connection is still up and
770
   * reusable.  Keep a read pending (bounded by the idle timeout)
771
   * so that a peer-initiated close is detected promptly;
772
   * otherwise the socket would linger in CLOSE-WAIT and be handed
773
   * out again as a dead reused connection.
774
   */
775
0
  isc_nmhandle_cleartimeout(disp->handle);
776
0
  isc_nmhandle_settimeout(disp->handle, disp->mgr->reuse_timeout);
777
0
  if (!disp->reading) {
778
0
    dispatch_log(disp, ISC_LOG_DEBUG(90), "keeping idle read on %p",
779
0
           disp->handle);
780
0
    tcp_startrecv(disp, NULL);
781
0
  }
782
0
}
783
784
/*
785
 * General flow:
786
 *
787
 * If I/O result == CANCELED, EOF, or error, notify everyone as the
788
 * various queues drain.
789
 *
790
 * If response:
791
 *  Allocate event, fill in details.
792
 *    If cannot allocate, restart.
793
 *  find target.  If not found, restart.
794
 *  if event queue is not empty, queue.  else, send.
795
 *  restart.
796
 */
797
static void
798
tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
799
0
   void *arg) {
800
0
  dns_dispatch_t *disp = (dns_dispatch_t *)arg;
801
0
  dns_dispentry_t *resp = NULL;
802
0
  char buf[ISC_SOCKADDR_FORMATSIZE];
803
0
  isc_sockaddr_t peer;
804
0
  dns_displist_t resps = ISC_LIST_INITIALIZER;
805
0
  isc_time_t now;
806
0
  int timeout = 0;
807
0
  isc_result_t result = eresult;
808
809
0
  REQUIRE(VALID_DISPATCH(disp));
810
811
0
  REQUIRE(disp->tid == isc_tid());
812
0
  INSIST(disp->reading);
813
0
  disp->reading = false;
814
815
0
  dispatch_log(disp, ISC_LOG_DEBUG(90),
816
0
         "TCP read:%s:requests %" PRIuFAST32,
817
0
         isc_result_totext(eresult), disp->requests);
818
819
0
  peer = isc_nmhandle_peeraddr(handle);
820
821
0
  rcu_read_lock();
822
  /*
823
   * Phase 1: Process timeout and success.
824
   */
825
0
  switch (eresult) {
826
0
  case ISC_R_TIMEDOUT:
827
    /*
828
     * Time out the oldest response in the active queue.
829
     */
830
0
    result = tcp_recv_oldest(disp, &resp);
831
0
    break;
832
0
  case ISC_R_SUCCESS:
833
    /* We got an answer */
834
0
    result = tcp_recv_success(disp, region, &resp);
835
0
    break;
836
837
0
  default:
838
0
    break;
839
0
  }
840
841
0
  if (resp != NULL) {
842
0
    tcp_recv_add(&resps, resp, result);
843
0
  }
844
845
  /*
846
   * Phase 2: Look if we timed out before.
847
   */
848
849
0
  if (result == ISC_R_NOTFOUND) {
850
0
    if (eresult == ISC_R_TIMEDOUT) {
851
      /*
852
       * An idle keep-alive read timed out with no outstanding
853
       * responses.
854
       */
855
0
      result = ISC_R_CANCELED;
856
0
    } else if (disp->timedout > 0) {
857
      /* There was active query that timed-out before */
858
0
      disp->timedout--;
859
0
    } else {
860
0
      result = ISC_R_UNEXPECTED;
861
0
    }
862
0
  }
863
864
  /*
865
   * Phase 3: Trigger timeouts.  It's possible that the responses would
866
   * have been timed out out already, but non-matching TCP reads have
867
   * prevented this.
868
   */
869
0
  resp = ISC_LIST_HEAD(disp->active);
870
0
  if (resp != NULL) {
871
0
    now = isc_loop_now(resp->loop);
872
0
  }
873
0
  while (resp != NULL) {
874
0
    dns_dispentry_t *next = ISC_LIST_NEXT(resp, alink);
875
876
0
    if (resp->timeout > 0) {
877
0
      timeout = resp->timeout - dispentry_runtime(resp, &now);
878
0
      if (timeout <= 0) {
879
0
        tcp_recv_add(&resps, resp, ISC_R_TIMEDOUT);
880
0
      }
881
0
    }
882
883
0
    resp = next;
884
0
  }
885
886
  /*
887
   * Phase 4: log if we errored out.
888
   */
889
0
  switch (result) {
890
0
  case ISC_R_SUCCESS:
891
0
  case ISC_R_TIMEDOUT:
892
0
  case ISC_R_NOTFOUND:
893
0
    break;
894
0
  case ISC_R_SHUTTINGDOWN:
895
0
  case ISC_R_CANCELED:
896
0
  case ISC_R_EOF:
897
0
  case ISC_R_CONNECTIONRESET:
898
0
    if (isc_log_wouldlog(ISC_LOG_DEBUG(90))) {
899
0
      isc_sockaddr_format(&peer, buf, sizeof(buf));
900
0
      dispatch_log(disp, ISC_LOG_DEBUG(90),
901
0
             "shutting down TCP: %s: %s", buf,
902
0
             isc_result_totext(result));
903
0
    }
904
0
    tcp_recv_shutdown(disp, &resps, result);
905
0
    break;
906
0
  default:
907
0
    isc_sockaddr_format(&peer, buf, sizeof(buf));
908
0
    dispatch_log(disp, ISC_LOG_ERROR,
909
0
           "shutting down due to TCP "
910
0
           "receive error: %s: %s",
911
0
           buf, isc_result_totext(result));
912
0
    tcp_recv_shutdown(disp, &resps, result);
913
0
    break;
914
0
  }
915
916
  /*
917
   * Phase 5: Resume reading if there are still active responses
918
   */
919
0
  resp = ISC_LIST_HEAD(disp->active);
920
0
  if (resp != NULL) {
921
0
    if (resp->timeout > 0) {
922
0
      timeout = resp->timeout - dispentry_runtime(resp, &now);
923
0
      INSIST(timeout > 0);
924
0
    }
925
0
    tcp_startrecv(disp, resp);
926
0
    if (timeout > 0) {
927
0
      isc_nmhandle_settimeout(handle, timeout);
928
0
    }
929
0
  }
930
931
0
  rcu_read_unlock();
932
933
  /*
934
   * Phase 6: Process all scheduled callbacks.
935
   */
936
0
  tcp_recv_processall(&resps, region);
937
938
  /*
939
   * Phase 7: Restart reading on idle connections.
940
   */
941
0
  if (ISC_LIST_EMPTY(disp->active) &&
942
0
      disp->state == DNS_DISPATCHSTATE_CONNECTED &&
943
0
      disp->mgr->reuse_timeout > 0)
944
0
  {
945
0
    tcp_startrecv_idle(disp);
946
0
  }
947
948
0
  dns_dispatch_detach(&disp); /* DISPATCH002 */
949
0
}
950
951
/*%
952
 * Create a temporary port list to set the initial default set of dispatch
953
 * ephemeral ports.  This is almost meaningless as the application will
954
 * normally set the ports explicitly, but is provided to fill some minor corner
955
 * cases.
956
 */
957
static void
958
0
create_default_portset(isc_mem_t *mctx, int family, isc_portset_t **portsetp) {
959
0
  in_port_t low, high;
960
961
0
  isc_net_getportrange(family, &low, &high);
962
963
0
  isc_portset_create(mctx, portsetp);
964
0
  isc_portset_addrange(*portsetp, low, high);
965
0
}
966
967
static isc_result_t
968
setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
969
0
        isc_portset_t *v6portset) {
970
0
  in_port_t *v4ports, *v6ports, p = 0;
971
0
  unsigned int nv4ports, nv6ports, i4 = 0, i6 = 0;
972
973
0
  nv4ports = isc_portset_nports(v4portset);
974
0
  nv6ports = isc_portset_nports(v6portset);
975
976
0
  v4ports = NULL;
977
0
  if (nv4ports != 0) {
978
0
    v4ports = isc_mem_cget(mgr->mctx, nv4ports, sizeof(in_port_t));
979
0
  }
980
0
  v6ports = NULL;
981
0
  if (nv6ports != 0) {
982
0
    v6ports = isc_mem_cget(mgr->mctx, nv6ports, sizeof(in_port_t));
983
0
  }
984
985
0
  do {
986
0
    if (isc_portset_isset(v4portset, p)) {
987
0
      INSIST(i4 < nv4ports);
988
0
      v4ports[i4++] = p;
989
0
    }
990
0
    if (isc_portset_isset(v6portset, p)) {
991
0
      INSIST(i6 < nv6ports);
992
0
      v6ports[i6++] = p;
993
0
    }
994
0
  } while (p++ < 65535);
995
0
  INSIST(i4 == nv4ports && i6 == nv6ports);
996
997
0
  if (mgr->v4ports != NULL) {
998
0
    isc_mem_cput(mgr->mctx, mgr->v4ports, mgr->nv4ports,
999
0
           sizeof(in_port_t));
1000
0
  }
1001
0
  mgr->v4ports = v4ports;
1002
0
  mgr->nv4ports = nv4ports;
1003
1004
0
  if (mgr->v6ports != NULL) {
1005
0
    isc_mem_cput(mgr->mctx, mgr->v6ports, mgr->nv6ports,
1006
0
           sizeof(in_port_t));
1007
0
  }
1008
0
  mgr->v6ports = v6ports;
1009
0
  mgr->nv6ports = nv6ports;
1010
1011
0
  return ISC_R_SUCCESS;
1012
0
}
1013
1014
/*
1015
 * Publics.
1016
 */
1017
1018
isc_result_t
1019
0
dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) {
1020
0
  dns_dispatchmgr_t *mgr = NULL;
1021
0
  isc_portset_t *v4portset = NULL;
1022
0
  isc_portset_t *v6portset = NULL;
1023
1024
0
  REQUIRE(mctx != NULL);
1025
0
  REQUIRE(mgrp != NULL && *mgrp == NULL);
1026
1027
0
  mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
1028
0
  *mgr = (dns_dispatchmgr_t){
1029
0
    .magic = 0,
1030
0
    .nloops = isc_loopmgr_nloops(),
1031
0
  };
1032
1033
#if DNS_DISPATCH_TRACE
1034
  fprintf(stderr, "dns_dispatchmgr__init:%s:%s:%d:%p->references = 1\n",
1035
    __func__, __FILE__, __LINE__, mgr);
1036
#endif
1037
0
  isc_refcount_init(&mgr->references, 1);
1038
1039
0
  isc_mem_attach(mctx, &mgr->mctx);
1040
1041
0
  mgr->tcps = isc_mem_cget(mgr->mctx, mgr->nloops, sizeof(mgr->tcps[0]));
1042
0
  for (size_t i = 0; i < mgr->nloops; i++) {
1043
0
    mgr->tcps[i] = cds_lfht_new(
1044
0
      2, 2, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
1045
0
      NULL);
1046
0
  }
1047
1048
0
  create_default_portset(mgr->mctx, AF_INET, &v4portset);
1049
0
  create_default_portset(mgr->mctx, AF_INET6, &v6portset);
1050
1051
0
  setavailports(mgr, v4portset, v6portset);
1052
1053
0
  isc_portset_destroy(mgr->mctx, &v4portset);
1054
0
  isc_portset_destroy(mgr->mctx, &v6portset);
1055
1056
0
  mgr->qids = cds_lfht_new(QIDS_INIT_SIZE, QIDS_MIN_SIZE, 0,
1057
0
         CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING,
1058
0
         NULL);
1059
1060
0
  mgr->magic = DNS_DISPATCHMGR_MAGIC;
1061
1062
0
  *mgrp = mgr;
1063
0
  return ISC_R_SUCCESS;
1064
0
}
1065
1066
#if DNS_DISPATCH_TRACE
1067
ISC_REFCOUNT_TRACE_IMPL(dns_dispatchmgr, dispatchmgr_destroy);
1068
#else
1069
0
ISC_REFCOUNT_IMPL(dns_dispatchmgr, dispatchmgr_destroy);
Unexecuted instantiation: dns_dispatchmgr_ref
Unexecuted instantiation: dns_dispatchmgr_unref
Unexecuted instantiation: dns_dispatchmgr_detach
1070
0
#endif
1071
0
1072
0
void
1073
0
dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
1074
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1075
0
  if (mgr->blackhole != NULL) {
1076
0
    dns_acl_detach(&mgr->blackhole);
1077
0
  }
1078
0
  dns_acl_attach(blackhole, &mgr->blackhole);
1079
0
}
1080
1081
dns_acl_t *
1082
0
dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
1083
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1084
0
  return mgr->blackhole;
1085
0
}
1086
1087
isc_result_t
1088
dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
1089
0
            isc_portset_t *v6portset) {
1090
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1091
0
  return setavailports(mgr, v4portset, v6portset);
1092
0
}
1093
1094
void
1095
dns_dispatchmgr_setreusetimeout(dns_dispatchmgr_t *mgr,
1096
0
        unsigned int reuse_timeout) {
1097
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1098
0
  mgr->reuse_timeout = reuse_timeout;
1099
0
}
1100
1101
static void
1102
0
dispatchmgr_destroy(dns_dispatchmgr_t *mgr) {
1103
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1104
1105
0
  isc_refcount_destroy(&mgr->references);
1106
1107
0
  mgr->magic = 0;
1108
1109
0
  RUNTIME_CHECK(!cds_lfht_destroy(mgr->qids, NULL));
1110
1111
0
  for (size_t i = 0; i < mgr->nloops; i++) {
1112
0
    RUNTIME_CHECK(!cds_lfht_destroy(mgr->tcps[i], NULL));
1113
0
  }
1114
0
  isc_mem_cput(mgr->mctx, mgr->tcps, mgr->nloops, sizeof(mgr->tcps[0]));
1115
1116
0
  if (mgr->blackhole != NULL) {
1117
0
    dns_acl_detach(&mgr->blackhole);
1118
0
  }
1119
1120
0
  if (mgr->stats != NULL) {
1121
0
    isc_stats_detach(&mgr->stats);
1122
0
  }
1123
1124
0
  if (mgr->v4ports != NULL) {
1125
0
    isc_mem_cput(mgr->mctx, mgr->v4ports, mgr->nv4ports,
1126
0
           sizeof(in_port_t));
1127
0
  }
1128
0
  if (mgr->v6ports != NULL) {
1129
0
    isc_mem_cput(mgr->mctx, mgr->v6ports, mgr->nv6ports,
1130
0
           sizeof(in_port_t));
1131
0
  }
1132
1133
0
  isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t));
1134
0
}
1135
1136
void
1137
0
dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) {
1138
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1139
0
  REQUIRE(mgr->stats == NULL);
1140
1141
0
  isc_stats_attach(stats, &mgr->stats);
1142
0
}
1143
1144
/*
1145
 * Allocate and set important limits.
1146
 */
1147
static void
1148
dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type, isc_tid_t tid,
1149
0
      dns_dispatch_t **dispp) {
1150
0
  dns_dispatch_t *disp = NULL;
1151
1152
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1153
0
  REQUIRE(dispp != NULL && *dispp == NULL);
1154
1155
  /*
1156
   * Set up the dispatcher, mostly.  Don't bother setting some of
1157
   * the options that are controlled by tcp vs. udp, etc.
1158
   */
1159
1160
0
  disp = isc_mem_get(mgr->mctx, sizeof(*disp));
1161
0
  *disp = (dns_dispatch_t){
1162
0
    .socktype = type,
1163
0
    .active = ISC_LIST_INITIALIZER,
1164
0
    .pending = ISC_LIST_INITIALIZER,
1165
0
    .tid = tid,
1166
0
    .magic = DISPATCH_MAGIC,
1167
0
  };
1168
1169
0
  isc_mem_attach(mgr->mctx, &disp->mctx);
1170
1171
0
  dns_dispatchmgr_attach(mgr, &disp->mgr);
1172
#if DNS_DISPATCH_TRACE
1173
  fprintf(stderr, "dns_dispatch__init:%s:%s:%d:%p->references = 1\n",
1174
    __func__, __FILE__, __LINE__, disp);
1175
#endif
1176
0
  isc_refcount_init(&disp->references, 1); /* DISPATCH000 */
1177
1178
0
  *dispp = disp;
1179
0
}
1180
1181
struct dispatch_key {
1182
  const isc_sockaddr_t *local;
1183
  const isc_sockaddr_t *peer;
1184
  const dns_transport_t *transport;
1185
  const dns_dispatchtype_t disptype;
1186
};
1187
1188
static uint32_t
1189
0
dispatch_hash(struct dispatch_key *key) {
1190
0
  isc_hash32_t hash;
1191
1192
0
  isc_hash32_init(&hash);
1193
1194
0
  isc_sockaddr_hash_ex(&hash, key->peer, false);
1195
0
  if (key->local != NULL) {
1196
0
    isc_sockaddr_hash_ex(&hash, key->local, true);
1197
0
  }
1198
0
  if (key->transport != NULL) {
1199
0
    uintptr_t transport = (uintptr_t)key->transport;
1200
0
    isc_hash32_hash(&hash, &transport, sizeof(transport), true);
1201
0
  }
1202
0
  isc_hash32_hash(&hash, &key->disptype, sizeof(key->disptype), true);
1203
1204
0
  return isc_hash32_finalize(&hash);
1205
0
}
1206
1207
static int
1208
0
dispatch_match(struct cds_lfht_node *node, const void *key0) {
1209
0
  dns_dispatch_t *disp = caa_container_of(node, dns_dispatch_t, ht_node);
1210
0
  const struct dispatch_key *key = key0;
1211
1212
0
  return disp->disptype == key->disptype &&
1213
0
         disp->transport == key->transport &&
1214
0
         isc_sockaddr_equal(&disp->peer, key->peer) &&
1215
0
         (key->local == NULL ||
1216
0
    isc_sockaddr_equal(&disp->local, key->local));
1217
0
}
1218
1219
static isc_result_t
1220
dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1221
    const isc_sockaddr_t *destaddr, dns_transport_t *transport,
1222
0
    dns_dispatchtype_t disptype, dns_dispatch_t **dispp) {
1223
0
  dns_dispatch_t *disp_connected = NULL;
1224
0
  dns_dispatch_t *disp_fallback = NULL;
1225
0
  isc_result_t result = ISC_R_NOTFOUND;
1226
0
  isc_tid_t tid = isc_tid();
1227
1228
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1229
0
  REQUIRE(destaddr != NULL);
1230
0
  REQUIRE(dispp != NULL && *dispp == NULL);
1231
1232
0
  struct dispatch_key key = {
1233
0
    .local = localaddr,
1234
0
    .peer = destaddr,
1235
0
    .transport = transport,
1236
0
    .disptype = disptype,
1237
0
  };
1238
1239
0
  rcu_read_lock();
1240
0
  struct cds_lfht_iter iter;
1241
0
  dns_dispatch_t *disp = NULL;
1242
0
  cds_lfht_for_each_entry_duplicate(mgr->tcps[tid], dispatch_hash(&key),
1243
0
            dispatch_match, &key, &iter, disp,
1244
0
            ht_node) {
1245
0
    INSIST(disp->tid == isc_tid());
1246
0
    INSIST(disp->socktype == isc_socktype_tcp);
1247
1248
0
    switch (disp->state) {
1249
0
    case DNS_DISPATCHSTATE_NONE:
1250
      /* A dispatch in indeterminate state, skip it */
1251
0
      break;
1252
0
    case DNS_DISPATCHSTATE_CONNECTED:
1253
      /* We found a connected dispatch */
1254
0
      dns_dispatch_attach(disp, &disp_connected);
1255
0
      break;
1256
0
    case DNS_DISPATCHSTATE_CONNECTING:
1257
      /* We found "a" dispatch, store it for later */
1258
0
      if (disp_fallback == NULL) {
1259
0
        dns_dispatch_attach(disp, &disp_fallback);
1260
0
      }
1261
0
      break;
1262
0
    case DNS_DISPATCHSTATE_CANCELED:
1263
      /* A canceled dispatch, skip it. */
1264
0
      break;
1265
0
    default:
1266
0
      UNREACHABLE();
1267
0
    }
1268
1269
0
    if (disp_connected != NULL) {
1270
0
      break;
1271
0
    }
1272
0
  }
1273
0
  rcu_read_unlock();
1274
1275
0
  if (disp_connected != NULL) {
1276
    /* We found connected dispatch */
1277
0
    INSIST(disp_connected->handle != NULL);
1278
1279
0
    *dispp = disp_connected;
1280
0
    disp_connected = NULL;
1281
1282
0
    result = ISC_R_SUCCESS;
1283
1284
0
    if (disp_fallback != NULL) {
1285
0
      dns_dispatch_detach(&disp_fallback);
1286
0
    }
1287
0
  } else if (disp_fallback != NULL) {
1288
0
    *dispp = disp_fallback;
1289
1290
0
    result = ISC_R_SUCCESS;
1291
0
  }
1292
1293
0
  return result;
1294
0
}
1295
1296
static void
1297
dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1298
       const isc_sockaddr_t *destaddr, dns_transport_t *transport,
1299
       dns_dispatchtype_t disptype, dns_dispatchopt_t options,
1300
0
       dns_dispatch_t **dispp) {
1301
0
  dns_dispatch_t *disp = NULL;
1302
0
  isc_tid_t tid = isc_tid();
1303
1304
0
  dispatch_allocate(mgr, isc_socktype_tcp, tid, &disp);
1305
1306
0
  disp->disptype = disptype;
1307
0
  disp->nextid = isc_random16();
1308
0
  disp->options = options;
1309
0
  disp->peer = *destaddr;
1310
0
  if (transport != NULL) {
1311
0
    dns_transport_attach(transport, &disp->transport);
1312
0
  }
1313
1314
0
  if (localaddr != NULL) {
1315
0
    disp->local = *localaddr;
1316
0
  } else {
1317
0
    int pf;
1318
0
    pf = isc_sockaddr_pf(destaddr);
1319
0
    isc_sockaddr_anyofpf(&disp->local, pf);
1320
0
    isc_sockaddr_setport(&disp->local, 0);
1321
0
  }
1322
1323
  /*
1324
   * Append it to the dispatcher list.
1325
   */
1326
0
  if ((options & DNS_DISPATCHOPT_FIXEDID) == 0) {
1327
0
    struct dispatch_key key = {
1328
0
      .local = &disp->local,
1329
0
      .peer = &disp->peer,
1330
0
      .transport = transport,
1331
0
      .disptype = disptype,
1332
0
    };
1333
0
    rcu_read_lock();
1334
0
    cds_lfht_add(mgr->tcps[tid], dispatch_hash(&key),
1335
0
           &disp->ht_node);
1336
0
    rcu_read_unlock();
1337
0
  }
1338
1339
0
  *dispp = disp;
1340
0
}
1341
1342
isc_result_t
1343
dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1344
           const isc_sockaddr_t *destaddr,
1345
           dns_transport_t *transport, dns_dispatchtype_t disptype,
1346
0
           dns_dispatchopt_t options, dns_dispatch_t **dispp) {
1347
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1348
0
  REQUIRE(destaddr != NULL);
1349
1350
0
  isc_result_t result;
1351
1352
0
  if ((options & DNS_DISPATCHOPT_FIXEDID) == 0 &&
1353
0
      disptype != DNS_DISPATCHTYPE_XFRIN)
1354
0
  {
1355
0
    result = dispatch_gettcp(mgr, localaddr, destaddr, transport,
1356
0
           disptype, dispp);
1357
0
    if (result == ISC_R_SUCCESS) {
1358
0
      if (isc_log_wouldlog(90)) {
1359
0
        char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1360
1361
0
        isc_sockaddr_format(&(*dispp)->local, addrbuf,
1362
0
                ISC_SOCKADDR_FORMATSIZE);
1363
1364
0
        mgr_log(mgr, ISC_LOG_DEBUG(90),
1365
0
          "dns_dispatch_createtcp: reused TCP "
1366
0
          "dispatch %p for "
1367
0
          "%s",
1368
0
          *dispp, addrbuf);
1369
0
      }
1370
0
      return result;
1371
0
    }
1372
0
  }
1373
1374
  /*
1375
   * Otherwise allocate new TCP dispatch.
1376
   */
1377
1378
0
  dispatch_createtcp(mgr, localaddr, destaddr, transport, disptype,
1379
0
         options, dispp);
1380
1381
0
  if (isc_log_wouldlog(90)) {
1382
0
    char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1383
1384
0
    isc_sockaddr_format(&(*dispp)->local, addrbuf,
1385
0
            ISC_SOCKADDR_FORMATSIZE);
1386
1387
0
    mgr_log(mgr, ISC_LOG_DEBUG(90),
1388
0
      "dns_dispatch_createtcp: created TCP dispatch %p for "
1389
0
      "%s",
1390
0
      *dispp, addrbuf);
1391
0
  }
1392
1393
0
  return ISC_R_SUCCESS;
1394
0
}
1395
1396
isc_result_t
1397
dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1398
0
           dns_dispatch_t **dispp) {
1399
0
  isc_result_t result;
1400
0
  dns_dispatch_t *disp = NULL;
1401
1402
0
  REQUIRE(VALID_DISPATCHMGR(mgr));
1403
0
  REQUIRE(localaddr != NULL);
1404
0
  REQUIRE(dispp != NULL && *dispp == NULL);
1405
1406
0
  result = dispatch_createudp(mgr, localaddr, isc_tid(), &disp);
1407
0
  if (result == ISC_R_SUCCESS) {
1408
0
    *dispp = disp;
1409
0
  }
1410
1411
0
  return result;
1412
0
}
1413
1414
static isc_result_t
1415
dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1416
0
       isc_tid_t tid, dns_dispatch_t **dispp) {
1417
0
  isc_result_t result = ISC_R_SUCCESS;
1418
0
  dns_dispatch_t *disp = NULL;
1419
0
  isc_sockaddr_t sa_any;
1420
1421
  /*
1422
   * Check whether this address/port is available locally.
1423
   */
1424
0
  isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
1425
0
  if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
1426
0
    RETERR(isc_nm_checkaddr(localaddr, isc_socktype_udp));
1427
0
  }
1428
1429
0
  dispatch_allocate(mgr, isc_socktype_udp, tid, &disp);
1430
1431
0
  if (isc_log_wouldlog(90)) {
1432
0
    char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1433
1434
0
    isc_sockaddr_format(localaddr, addrbuf,
1435
0
            ISC_SOCKADDR_FORMATSIZE);
1436
0
    mgr_log(mgr, ISC_LOG_DEBUG(90),
1437
0
      "dispatch_createudp: created UDP dispatch %p for %s",
1438
0
      disp, addrbuf);
1439
0
  }
1440
1441
0
  disp->local = *localaddr;
1442
1443
  /*
1444
   * Don't append it to the dispatcher list, we don't care about UDP, only
1445
   * TCP should be searched
1446
   *
1447
   * ISC_LIST_APPEND(mgr->list, disp, link);
1448
   */
1449
1450
0
  *dispp = disp;
1451
1452
0
  return result;
1453
0
}
1454
1455
static void
1456
0
dispatch_destroy_rcu(struct rcu_head *rcu_head) {
1457
0
  dns_dispatch_t *disp = caa_container_of(rcu_head, dns_dispatch_t,
1458
0
            rcu_head);
1459
1460
0
  isc_mem_putanddetach(&disp->mctx, disp, sizeof(*disp));
1461
0
}
1462
1463
static void
1464
0
dispatch_destroy(dns_dispatch_t *disp) {
1465
0
  dns_dispatchmgr_t *mgr = disp->mgr;
1466
0
  isc_tid_t tid = isc_tid();
1467
1468
0
  disp->magic = 0;
1469
1470
0
  if ((disp->options & DNS_DISPATCHOPT_FIXEDID) == 0 &&
1471
0
      disp->socktype == isc_socktype_tcp)
1472
0
  {
1473
0
    (void)cds_lfht_del(mgr->tcps[tid], &disp->ht_node);
1474
0
  }
1475
1476
0
  INSIST(disp->requests == 0);
1477
0
  INSIST(ISC_LIST_EMPTY(disp->pending));
1478
0
  INSIST(ISC_LIST_EMPTY(disp->active));
1479
1480
0
  dispatch_log(disp, ISC_LOG_DEBUG(90), "destroying dispatch %p", disp);
1481
1482
0
  if (disp->handle) {
1483
0
    dispatch_log(disp, ISC_LOG_DEBUG(90),
1484
0
           "detaching TCP handle %p from %p", disp->handle,
1485
0
           &disp->handle);
1486
0
    isc_nmhandle_detach(&disp->handle);
1487
0
  }
1488
0
  if (disp->transport != NULL) {
1489
0
    dns_transport_detach(&disp->transport);
1490
0
  }
1491
0
  dns_dispatchmgr_detach(&disp->mgr);
1492
1493
0
  call_rcu(&disp->rcu_head, dispatch_destroy_rcu);
1494
0
}
1495
1496
#if DNS_DISPATCH_TRACE
1497
ISC_REFCOUNT_TRACE_IMPL(dns_dispatch, dispatch_destroy);
1498
#else
1499
0
ISC_REFCOUNT_IMPL(dns_dispatch, dispatch_destroy);
Unexecuted instantiation: dns_dispatch_ref
Unexecuted instantiation: dns_dispatch_unref
Unexecuted instantiation: dns_dispatch_detach
1500
0
#endif
1501
0
1502
0
isc_result_t
1503
0
dns_dispatch_add(dns_dispatch_t *disp, isc_loop_t *loop,
1504
0
     dns_dispatchopt_t options, unsigned int connect_timeout,
1505
0
     unsigned int timeout, const isc_sockaddr_t *dest,
1506
0
     dns_transport_t *transport, isc_tlsctx_cache_t *tlsctx_cache,
1507
0
     dispatch_cb_t connected, dispatch_cb_t sent,
1508
0
     dispatch_cb_t response, void *arg, dns_messageid_t *idp,
1509
0
     dns_dispentry_t **respp) {
1510
0
  REQUIRE(VALID_DISPATCH(disp));
1511
0
  REQUIRE(dest != NULL);
1512
0
  REQUIRE(respp != NULL && *respp == NULL);
1513
0
  REQUIRE(idp != NULL);
1514
0
  REQUIRE(disp->socktype == isc_socktype_tcp ||
1515
0
    disp->socktype == isc_socktype_udp);
1516
0
  REQUIRE(connected != NULL);
1517
0
  REQUIRE(response != NULL);
1518
0
  REQUIRE(sent != NULL);
1519
0
  REQUIRE(loop != NULL);
1520
0
  REQUIRE(disp->tid == isc_tid());
1521
0
  REQUIRE(disp->transport == transport);
1522
1523
0
  if (disp->state == DNS_DISPATCHSTATE_CANCELED) {
1524
0
    return ISC_R_CANCELED;
1525
0
  }
1526
1527
0
  in_port_t localport = isc_sockaddr_getport(&disp->local);
1528
0
  dns_dispentry_t *resp = isc_mem_get(disp->mctx, sizeof(*resp));
1529
0
  *resp = (dns_dispentry_t){
1530
0
    .connect_timeout = connect_timeout,
1531
0
    .timeout = timeout,
1532
0
    .port = localport,
1533
0
    .peer = *dest,
1534
0
    .loop = loop,
1535
0
    .connected = connected,
1536
0
    .sent = sent,
1537
0
    .response = response,
1538
0
    .arg = arg,
1539
0
    .alink = ISC_LINK_INITIALIZER,
1540
0
    .plink = ISC_LINK_INITIALIZER,
1541
0
    .rlink = ISC_LINK_INITIALIZER,
1542
0
    .magic = RESPONSE_MAGIC,
1543
0
  };
1544
1545
#if DNS_DISPATCH_TRACE
1546
  fprintf(stderr, "dns_dispentry__init:%s:%s:%d:%p->references = 1\n",
1547
    __func__, __FILE__, __LINE__, resp);
1548
#endif
1549
0
  isc_refcount_init(&resp->references, 1); /* DISPENTRY000 */
1550
1551
0
  if (disp->socktype == isc_socktype_udp) {
1552
0
    isc_result_t result = setup_socket(disp, resp, dest,
1553
0
               &localport);
1554
0
    if (result != ISC_R_SUCCESS) {
1555
0
      isc_mem_put(disp->mctx, resp, sizeof(*resp));
1556
0
      inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
1557
0
      return result;
1558
0
    }
1559
0
  }
1560
1561
0
  isc_result_t result = ISC_R_NOMORE;
1562
0
  rcu_read_lock();
1563
1564
0
  if (disp->socktype == isc_socktype_tcp) {
1565
    /*
1566
     * TCP dispentries don't use the global QID hash table.
1567
     * Responses are matched by scanning disp->active, and
1568
     * sequential per-dispatch IDs (bounded by the pipelining
1569
     * limit) are guaranteed to be unique within the dispatch.
1570
     * FIXEDID TCP dispatches are always fresh and isolated
1571
     * (see dns_dispatch_createtcp), so the caller-supplied ID
1572
     * can't collide either.
1573
     */
1574
0
    resp->id = ((options & DNS_DISPATCHOPT_FIXEDID) != 0)
1575
0
           ? *idp
1576
0
           : disp->nextid++;
1577
0
    result = ISC_R_SUCCESS;
1578
0
  } else {
1579
0
    size_t i = 0;
1580
0
    do {
1581
      /*
1582
       * Try somewhat hard to find a unique random ID
1583
       * (or use the fixed ID if DNS_DISPATCHOPT_FIXEDID
1584
       * is set).
1585
       */
1586
0
      resp->id = ((options & DNS_DISPATCHOPT_FIXEDID) != 0)
1587
0
             ? *idp
1588
0
             : (dns_messageid_t)isc_random16();
1589
1590
0
      struct cds_lfht_node *node = cds_lfht_add_unique(
1591
0
        disp->mgr->qids, qid_hash(resp), qid_match,
1592
0
        resp, &resp->ht_node);
1593
1594
0
      if (node != &resp->ht_node) {
1595
0
        if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) {
1596
          /*
1597
           * When using fixed ID, we either
1598
           * must use it or fail.
1599
           */
1600
0
          goto fail;
1601
0
        }
1602
0
      } else {
1603
0
        result = ISC_R_SUCCESS;
1604
0
        break;
1605
0
      }
1606
0
    } while (i++ < QID_MAX_TRIES);
1607
0
  }
1608
0
fail:
1609
0
  if (result != ISC_R_SUCCESS) {
1610
0
    isc_mem_put(disp->mctx, resp, sizeof(*resp));
1611
0
    rcu_read_unlock();
1612
0
    return result;
1613
0
  }
1614
1615
0
  isc_mem_attach(disp->mctx, &resp->mctx);
1616
1617
0
  if (transport != NULL) {
1618
0
    dns_transport_attach(transport, &resp->transport);
1619
0
  }
1620
1621
0
  if (tlsctx_cache != NULL) {
1622
0
    isc_tlsctx_cache_attach(tlsctx_cache, &resp->tlsctx_cache);
1623
0
  }
1624
1625
0
  dns_dispatch_attach(disp, &resp->disp); /* DISPATCH001 */
1626
1627
0
  disp->requests++;
1628
1629
  /*
1630
   * If this shared TCP dispatch has reached the pipelining limit,
1631
   * remove it from the hash table so new queries get a fresh
1632
   * connection.  The dispatch continues to serve its existing
1633
   * queries until they complete.
1634
   */
1635
0
  if (disp->socktype == isc_socktype_tcp &&
1636
0
      (disp->options & DNS_DISPATCHOPT_FIXEDID) == 0 &&
1637
0
      disp->requests >= dns_dispatch_tcppipelining)
1638
0
  {
1639
0
    (void)cds_lfht_del(disp->mgr->tcps[isc_tid()], &disp->ht_node);
1640
0
  }
1641
1642
0
  inc_stats(disp->mgr, (disp->socktype == isc_socktype_udp)
1643
0
             ? dns_resstatscounter_disprequdp
1644
0
             : dns_resstatscounter_dispreqtcp);
1645
1646
0
  rcu_read_unlock();
1647
1648
0
  *idp = resp->id;
1649
0
  *respp = resp;
1650
1651
0
  return ISC_R_SUCCESS;
1652
0
}
1653
1654
isc_result_t
1655
0
dns_dispatch_getnext(dns_dispentry_t *resp) {
1656
0
  REQUIRE(VALID_RESPONSE(resp));
1657
0
  REQUIRE(VALID_DISPATCH(resp->disp));
1658
1659
0
  dns_dispatch_t *disp = resp->disp;
1660
0
  isc_result_t result = ISC_R_SUCCESS;
1661
0
  int64_t timeout = 0;
1662
1663
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "getnext for QID %d", resp->id);
1664
1665
0
  if (resp->timeout > 0) {
1666
0
    isc_time_t now = isc_loop_now(resp->loop);
1667
0
    timeout = resp->timeout - dispentry_runtime(resp, &now);
1668
0
    if (timeout <= 0) {
1669
0
      return ISC_R_TIMEDOUT;
1670
0
    }
1671
0
  }
1672
1673
0
  INSIST(disp->tid == isc_tid());
1674
0
  switch (disp->socktype) {
1675
0
  case isc_socktype_udp:
1676
0
    udp_dispatch_getnext(resp, timeout);
1677
0
    break;
1678
0
  case isc_socktype_tcp:
1679
0
    tcp_dispatch_getnext(disp, resp, timeout);
1680
0
    break;
1681
0
  default:
1682
0
    UNREACHABLE();
1683
0
  }
1684
1685
0
  return result;
1686
0
}
1687
1688
/*
1689
 * NOTE: Must be RCU read locked!
1690
 */
1691
static void
1692
0
udp_dispentry_cancel(dns_dispentry_t *resp, isc_result_t result) {
1693
0
  REQUIRE(VALID_RESPONSE(resp));
1694
0
  REQUIRE(VALID_DISPATCH(resp->disp));
1695
0
  REQUIRE(VALID_DISPATCHMGR(resp->disp->mgr));
1696
1697
0
  dns_dispatch_t *disp = resp->disp;
1698
0
  bool respond = false;
1699
1700
0
  REQUIRE(disp->tid == isc_tid());
1701
0
  dispentry_log(resp, ISC_LOG_DEBUG(90),
1702
0
          "canceling response: %s, %s/%s (%s/%s), "
1703
0
          "requests %" PRIuFAST32,
1704
0
          isc_result_totext(result), state2str(resp->state),
1705
0
          resp->reading ? "reading" : "not reading",
1706
0
          state2str(disp->state),
1707
0
          disp->reading ? "reading" : "not reading",
1708
0
          disp->requests);
1709
1710
0
  if (ISC_LINK_LINKED(resp, alink)) {
1711
0
    ISC_LIST_UNLINK(disp->active, resp, alink);
1712
0
  }
1713
1714
0
  switch (resp->state) {
1715
0
  case DNS_DISPATCHSTATE_NONE:
1716
0
    break;
1717
1718
0
  case DNS_DISPATCHSTATE_CONNECTING:
1719
0
    break;
1720
1721
0
  case DNS_DISPATCHSTATE_CONNECTED:
1722
0
    if (resp->reading) {
1723
0
      respond = true;
1724
0
      dispentry_log(resp, ISC_LOG_DEBUG(90),
1725
0
              "canceling read on %p", resp->handle);
1726
0
      isc_nm_cancelread(resp->handle);
1727
0
    }
1728
0
    break;
1729
1730
0
  case DNS_DISPATCHSTATE_CANCELED:
1731
0
    goto unlock;
1732
1733
0
  default:
1734
0
    UNREACHABLE();
1735
0
  }
1736
1737
0
  dec_stats(disp->mgr, dns_resstatscounter_disprequdp);
1738
1739
0
  (void)cds_lfht_del(disp->mgr->qids, &resp->ht_node);
1740
1741
0
  resp->state = DNS_DISPATCHSTATE_CANCELED;
1742
1743
0
unlock:
1744
0
  if (respond) {
1745
0
    dispentry_log(resp, ISC_LOG_DEBUG(90), "read callback: %s",
1746
0
            isc_result_totext(result));
1747
0
    resp->response(result, NULL, resp->arg);
1748
0
  }
1749
0
}
1750
1751
/*
1752
 * NOTE: Must be RCU read locked!
1753
 */
1754
static void
1755
0
tcp_dispentry_cancel(dns_dispentry_t *resp, isc_result_t result) {
1756
0
  REQUIRE(VALID_RESPONSE(resp));
1757
0
  REQUIRE(VALID_DISPATCH(resp->disp));
1758
0
  REQUIRE(VALID_DISPATCHMGR(resp->disp->mgr));
1759
1760
0
  dns_dispatch_t *disp = resp->disp;
1761
0
  dns_displist_t resps = ISC_LIST_INITIALIZER;
1762
1763
0
  REQUIRE(disp->tid == isc_tid());
1764
0
  dispentry_log(resp, ISC_LOG_DEBUG(90),
1765
0
          "canceling response: %s, %s/%s (%s/%s), "
1766
0
          "requests %" PRIuFAST32,
1767
0
          isc_result_totext(result), state2str(resp->state),
1768
0
          resp->reading ? "reading" : "not reading",
1769
0
          state2str(disp->state),
1770
0
          disp->reading ? "reading" : "not reading",
1771
0
          disp->requests);
1772
1773
0
  switch (resp->state) {
1774
0
  case DNS_DISPATCHSTATE_NONE:
1775
0
    break;
1776
1777
0
  case DNS_DISPATCHSTATE_CONNECTING:
1778
0
    break;
1779
1780
0
  case DNS_DISPATCHSTATE_CONNECTED:
1781
0
    if (resp->reading) {
1782
0
      tcp_recv_add(&resps, resp, ISC_R_CANCELED);
1783
0
    }
1784
1785
0
    INSIST(!ISC_LINK_LINKED(resp, alink));
1786
1787
0
    if (ISC_LIST_EMPTY(disp->active) &&
1788
0
        disp->state == DNS_DISPATCHSTATE_CONNECTED)
1789
0
    {
1790
0
      INSIST(disp->handle != NULL);
1791
1792
      /*
1793
       * This was the last outstanding response on a still
1794
       * connected dispatch.  Keep the connection open with a
1795
       * read pending (bounded by the idle timeout) so that it
1796
       * can be reused by a subsequent query and so that a
1797
       * peer-initiated close is noticed promptly instead of
1798
       * leaving the socket stuck in CLOSE-WAIT.  If the
1799
       * dispatch is already shutting down, leave it alone so
1800
       * it can be torn down.
1801
       */
1802
0
      if (disp->mgr->reuse_timeout > 0) {
1803
0
        tcp_startrecv_idle(disp);
1804
0
      } else if (disp->reading) {
1805
0
        dispentry_log(resp, ISC_LOG_DEBUG(90),
1806
0
                "canceling read on %p",
1807
0
                disp->handle);
1808
0
        isc_nm_cancelread(disp->handle);
1809
0
      }
1810
0
    }
1811
0
    break;
1812
1813
0
  case DNS_DISPATCHSTATE_CANCELED:
1814
0
    goto unlock;
1815
1816
0
  default:
1817
0
    UNREACHABLE();
1818
0
  }
1819
1820
0
  dec_stats(disp->mgr, dns_resstatscounter_dispreqtcp);
1821
1822
0
  resp->state = DNS_DISPATCHSTATE_CANCELED;
1823
1824
0
unlock:
1825
1826
  /*
1827
   * NOTE: Calling the response callback directly from here should be done
1828
   * asynchronously, as the dns_dispatch_done() is usually called directly
1829
   * from the response callback, so there's a slight chance that the call
1830
   * stack will get higher here, but it's mitigated by the ".reading"
1831
   * flag, so we don't ever go into a loop.
1832
   */
1833
1834
0
  tcp_recv_processall(&resps, NULL);
1835
0
}
1836
1837
static void
1838
0
dispentry_cancel(dns_dispentry_t *resp, isc_result_t result) {
1839
0
  REQUIRE(VALID_RESPONSE(resp));
1840
0
  REQUIRE(VALID_DISPATCH(resp->disp));
1841
1842
0
  dns_dispatch_t *disp = resp->disp;
1843
1844
0
  rcu_read_lock();
1845
0
  switch (disp->socktype) {
1846
0
  case isc_socktype_udp:
1847
0
    udp_dispentry_cancel(resp, result);
1848
0
    break;
1849
0
  case isc_socktype_tcp:
1850
0
    tcp_dispentry_cancel(resp, result);
1851
0
    break;
1852
0
  default:
1853
0
    UNREACHABLE();
1854
0
  }
1855
0
  rcu_read_unlock();
1856
0
}
1857
1858
void
1859
0
dns_dispatch_done(dns_dispentry_t **respp) {
1860
0
  REQUIRE(VALID_RESPONSE(*respp));
1861
1862
0
  dns_dispentry_t *resp = *respp;
1863
0
  *respp = NULL;
1864
1865
0
  dispentry_cancel(resp, ISC_R_CANCELED);
1866
0
  dns_dispentry_detach(&resp); /* DISPENTRY000 */
1867
0
}
1868
1869
static void
1870
0
udp_startrecv(isc_nmhandle_t *handle, dns_dispentry_t *resp) {
1871
0
  REQUIRE(VALID_RESPONSE(resp));
1872
1873
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "attaching handle %p to %p",
1874
0
          handle, &resp->handle);
1875
0
  isc_nmhandle_attach(handle, &resp->handle);
1876
0
  dns_dispentry_ref(resp); /* DISPENTRY003 */
1877
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "reading");
1878
0
  isc_nm_read(resp->handle, udp_recv, resp);
1879
0
  resp->reading = true;
1880
0
}
1881
1882
static void
1883
0
tcp_startrecv(dns_dispatch_t *disp, dns_dispentry_t *resp) {
1884
0
  REQUIRE(VALID_DISPATCH(disp));
1885
0
  REQUIRE(disp->socktype == isc_socktype_tcp);
1886
1887
0
  if (disp->reading) {
1888
0
    return;
1889
0
  }
1890
1891
0
  dns_dispatch_ref(disp); /* DISPATCH002 */
1892
0
  if (resp != NULL) {
1893
0
    dispentry_log(resp, ISC_LOG_DEBUG(90), "reading from %p",
1894
0
            disp->handle);
1895
0
    INSIST(!isc_time_isepoch(&resp->start));
1896
0
  } else {
1897
0
    dispatch_log(disp, ISC_LOG_DEBUG(90),
1898
0
           "TCP reading without response from %p",
1899
0
           disp->handle);
1900
0
  }
1901
0
  isc_nm_read(disp->handle, tcp_recv, disp);
1902
0
  disp->reading = true;
1903
0
}
1904
1905
static void
1906
0
resp_connected(void *arg) {
1907
0
  dns_dispentry_t *resp = arg;
1908
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "connect callback: %s",
1909
0
          isc_result_totext(resp->result));
1910
1911
0
  resp->connected(resp->result, NULL, resp->arg);
1912
0
  dns_dispentry_detach(&resp); /* DISPENTRY005 */
1913
0
}
1914
1915
static void
1916
0
tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
1917
0
  dns_dispatch_t *disp = (dns_dispatch_t *)arg;
1918
0
  dns_displist_t resps = ISC_LIST_INITIALIZER;
1919
1920
0
  if (isc_log_wouldlog(90)) {
1921
0
    char localbuf[ISC_SOCKADDR_FORMATSIZE];
1922
0
    char peerbuf[ISC_SOCKADDR_FORMATSIZE];
1923
0
    if (handle != NULL) {
1924
0
      isc_sockaddr_t local = isc_nmhandle_localaddr(handle);
1925
0
      isc_sockaddr_t peer = isc_nmhandle_peeraddr(handle);
1926
1927
0
      isc_sockaddr_format(&local, localbuf,
1928
0
              ISC_SOCKADDR_FORMATSIZE);
1929
0
      isc_sockaddr_format(&peer, peerbuf,
1930
0
              ISC_SOCKADDR_FORMATSIZE);
1931
0
    } else {
1932
0
      isc_sockaddr_format(&disp->local, localbuf,
1933
0
              ISC_SOCKADDR_FORMATSIZE);
1934
0
      isc_sockaddr_format(&disp->peer, peerbuf,
1935
0
              ISC_SOCKADDR_FORMATSIZE);
1936
0
    }
1937
1938
0
    dispatch_log(disp, ISC_LOG_DEBUG(90),
1939
0
           "connected from %s to %s: %s", localbuf, peerbuf,
1940
0
           isc_result_totext(eresult));
1941
0
  }
1942
1943
0
  REQUIRE(disp->tid == isc_tid());
1944
0
  INSIST(disp->state == DNS_DISPATCHSTATE_CONNECTING);
1945
1946
  /*
1947
   * If there are pending responses, call the connect
1948
   * callbacks for all of them.
1949
   */
1950
0
  ISC_LIST_FOREACH(disp->pending, resp, plink) {
1951
0
    ISC_LIST_UNLINK(disp->pending, resp, plink);
1952
0
    ISC_LIST_APPEND(resps, resp, rlink);
1953
0
    resp->result = eresult;
1954
1955
0
    if (resp->state == DNS_DISPATCHSTATE_CANCELED) {
1956
0
      resp->result = ISC_R_CANCELED;
1957
0
    } else if (eresult == ISC_R_SUCCESS) {
1958
0
      resp->state = DNS_DISPATCHSTATE_CONNECTED;
1959
0
      ISC_LIST_APPEND(disp->active, resp, alink);
1960
0
      resp->reading = true;
1961
0
      dispentry_log(resp, ISC_LOG_DEBUG(90), "start reading");
1962
0
    } else {
1963
0
      resp->state = DNS_DISPATCHSTATE_NONE;
1964
0
    }
1965
0
  }
1966
1967
  /* Take the oldest active response. */
1968
0
  dns_dispentry_t *oldest = ISC_LIST_HEAD(disp->active);
1969
0
  if (oldest == NULL) {
1970
    /* All responses have been canceled */
1971
0
    disp->state = DNS_DISPATCHSTATE_CANCELED;
1972
0
  } else if (eresult == ISC_R_SUCCESS) {
1973
0
    disp->state = DNS_DISPATCHSTATE_CONNECTED;
1974
0
    isc_nmhandle_attach(handle, &disp->handle);
1975
0
    isc_nmhandle_cleartimeout(disp->handle);
1976
0
    if (oldest->timeout != 0) {
1977
0
      isc_nmhandle_settimeout(disp->handle, oldest->timeout);
1978
0
    }
1979
0
    tcp_startrecv(disp, oldest);
1980
0
  } else {
1981
0
    disp->state = DNS_DISPATCHSTATE_NONE;
1982
0
  }
1983
1984
0
  ISC_LIST_FOREACH(resps, resp, rlink) {
1985
0
    ISC_LIST_UNLINK(resps, resp, rlink);
1986
1987
0
    resp_connected(resp);
1988
0
  }
1989
1990
0
  dns_dispatch_detach(&disp); /* DISPATCH003 */
1991
0
}
1992
1993
static void
1994
0
udp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
1995
0
  dns_dispentry_t *resp = (dns_dispentry_t *)arg;
1996
0
  dns_dispatch_t *disp = resp->disp;
1997
1998
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "connected: %s",
1999
0
          isc_result_totext(eresult));
2000
2001
0
  REQUIRE(disp->tid == isc_tid());
2002
0
  switch (resp->state) {
2003
0
  case DNS_DISPATCHSTATE_CANCELED:
2004
0
    eresult = ISC_R_CANCELED;
2005
0
    ISC_LIST_UNLINK(disp->pending, resp, plink);
2006
0
    goto unlock;
2007
0
  case DNS_DISPATCHSTATE_CONNECTING:
2008
0
    ISC_LIST_UNLINK(disp->pending, resp, plink);
2009
0
    break;
2010
0
  default:
2011
0
    UNREACHABLE();
2012
0
  }
2013
2014
0
  switch (eresult) {
2015
0
  case ISC_R_CANCELED:
2016
0
    break;
2017
0
  case ISC_R_SUCCESS:
2018
0
    resp->state = DNS_DISPATCHSTATE_CONNECTED;
2019
0
    udp_startrecv(handle, resp);
2020
0
    break;
2021
0
  case ISC_R_NOPERM:
2022
0
  case ISC_R_ADDRINUSE: {
2023
0
    in_port_t localport = isc_sockaddr_getport(&disp->local);
2024
0
    isc_result_t result;
2025
2026
    /* probably a port collision; try a different one */
2027
0
    result = setup_socket(disp, resp, &resp->peer, &localport);
2028
0
    if (result == ISC_R_SUCCESS) {
2029
0
      udp_dispatch_connect(disp, resp);
2030
0
      goto detach;
2031
0
    }
2032
0
    resp->state = DNS_DISPATCHSTATE_NONE;
2033
0
    break;
2034
0
  }
2035
0
  default:
2036
0
    resp->state = DNS_DISPATCHSTATE_NONE;
2037
0
    break;
2038
0
  }
2039
0
unlock:
2040
2041
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "connect callback: %s",
2042
0
          isc_result_totext(eresult));
2043
0
  resp->connected(eresult, NULL, resp->arg);
2044
2045
0
detach:
2046
0
  dns_dispentry_detach(&resp); /* DISPENTRY004 */
2047
0
}
2048
2049
static void
2050
0
udp_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp) {
2051
0
  REQUIRE(disp->tid == isc_tid());
2052
0
  resp->state = DNS_DISPATCHSTATE_CONNECTING;
2053
0
  resp->start = isc_loop_now(resp->loop);
2054
0
  dns_dispentry_ref(resp); /* DISPENTRY004 */
2055
0
  ISC_LIST_APPEND(disp->pending, resp, plink);
2056
2057
0
  isc_nm_udpconnect(&resp->local, &resp->peer, udp_connected, resp,
2058
0
        resp->timeout);
2059
0
}
2060
2061
static inline const char *
2062
0
get_tls_sni_hostname(dns_dispentry_t *resp) {
2063
0
  char *hostname = NULL;
2064
2065
0
  if (resp->transport != NULL) {
2066
0
    hostname = dns_transport_get_remote_hostname(resp->transport);
2067
0
  }
2068
2069
0
  if (hostname == NULL) {
2070
0
    return NULL;
2071
0
  }
2072
2073
0
  if (isc_tls_valid_sni_hostname(hostname)) {
2074
0
    return hostname;
2075
0
  }
2076
2077
0
  return NULL;
2078
0
}
2079
2080
static isc_result_t
2081
0
tcp_dispatch_connect(dns_dispatch_t *disp, dns_dispentry_t *resp) {
2082
0
  dns_transport_type_t transport_type = DNS_TRANSPORT_TCP;
2083
0
  isc_tlsctx_t *tlsctx = NULL;
2084
0
  isc_tlsctx_client_session_cache_t *sess_cache = NULL;
2085
2086
0
  if (resp->transport != NULL) {
2087
0
    transport_type = dns_transport_get_type(resp->transport);
2088
0
  }
2089
2090
0
  if (transport_type == DNS_TRANSPORT_TLS) {
2091
0
    RETERR(dns_transport_get_tlsctx(resp->transport, &resp->peer,
2092
0
            resp->tlsctx_cache, resp->mctx,
2093
0
            &tlsctx, &sess_cache));
2094
0
    INSIST(tlsctx != NULL);
2095
0
  }
2096
2097
  /* Check whether the dispatch is already connecting or connected. */
2098
0
  REQUIRE(disp->tid == isc_tid());
2099
0
  switch (disp->state) {
2100
0
  case DNS_DISPATCHSTATE_NONE:
2101
    /* First connection, continue with connecting */
2102
0
    disp->state = DNS_DISPATCHSTATE_CONNECTING;
2103
0
    resp->state = DNS_DISPATCHSTATE_CONNECTING;
2104
0
    resp->start = isc_loop_now(resp->loop);
2105
0
    dns_dispentry_ref(resp); /* DISPENTRY005 */
2106
0
    ISC_LIST_APPEND(disp->pending, resp, plink);
2107
2108
0
    char localbuf[ISC_SOCKADDR_FORMATSIZE];
2109
0
    char peerbuf[ISC_SOCKADDR_FORMATSIZE];
2110
2111
0
    isc_sockaddr_format(&disp->local, localbuf,
2112
0
            ISC_SOCKADDR_FORMATSIZE);
2113
0
    isc_sockaddr_format(&disp->peer, peerbuf,
2114
0
            ISC_SOCKADDR_FORMATSIZE);
2115
2116
0
    dns_dispatch_ref(disp); /* DISPATCH003 */
2117
0
    dispentry_log(resp, ISC_LOG_DEBUG(90),
2118
0
            "connecting from %s to %s, timeout %u", localbuf,
2119
0
            peerbuf, resp->connect_timeout);
2120
2121
0
    const char *hostname = get_tls_sni_hostname(resp);
2122
2123
0
    isc_nm_streamdnsconnect(&disp->local, &disp->peer,
2124
0
          tcp_connected, disp,
2125
0
          resp->connect_timeout, tlsctx, hostname,
2126
0
          sess_cache, ISC_NM_PROXY_NONE, NULL);
2127
0
    break;
2128
2129
0
  case DNS_DISPATCHSTATE_CONNECTING:
2130
    /* Connection pending; add resp to the list */
2131
0
    resp->state = DNS_DISPATCHSTATE_CONNECTING;
2132
0
    resp->start = isc_loop_now(resp->loop);
2133
0
    dns_dispentry_ref(resp); /* DISPENTRY005 */
2134
0
    ISC_LIST_APPEND(disp->pending, resp, plink);
2135
0
    break;
2136
2137
0
  case DNS_DISPATCHSTATE_CONNECTED:
2138
0
    resp->state = DNS_DISPATCHSTATE_CONNECTED;
2139
0
    resp->start = isc_loop_now(resp->loop);
2140
2141
    /* Add the resp to the reading list */
2142
0
    ISC_LIST_APPEND(disp->active, resp, alink);
2143
0
    dispentry_log(resp, ISC_LOG_DEBUG(90),
2144
0
            "already connected; attaching");
2145
0
    resp->reading = true;
2146
2147
    /*
2148
     * Replace any idle timeout with this query's timeout.  The
2149
     * connection may have been kept reading while idle (with the
2150
     * idle timeout applied), so update the handle timeout even when
2151
     * a read is already pending.
2152
     */
2153
0
    isc_nmhandle_cleartimeout(disp->handle);
2154
0
    if (resp->timeout != 0) {
2155
0
      isc_nmhandle_settimeout(disp->handle, resp->timeout);
2156
0
    }
2157
2158
0
    if (!disp->reading) {
2159
      /* Restart the reading */
2160
0
      tcp_startrecv(disp, resp);
2161
0
    }
2162
2163
    /* Already connected; call the connected cb asynchronously */
2164
0
    dns_dispentry_ref(resp); /* DISPENTRY005 */
2165
0
    isc_async_run(resp->loop, resp_connected, resp);
2166
0
    break;
2167
2168
0
  default:
2169
0
    UNREACHABLE();
2170
0
  }
2171
2172
0
  return ISC_R_SUCCESS;
2173
0
}
2174
2175
isc_result_t
2176
0
dns_dispatch_connect(dns_dispentry_t *resp) {
2177
0
  REQUIRE(VALID_RESPONSE(resp));
2178
0
  REQUIRE(VALID_DISPATCH(resp->disp));
2179
2180
0
  dns_dispatch_t *disp = resp->disp;
2181
2182
0
  switch (disp->socktype) {
2183
0
  case isc_socktype_tcp:
2184
0
    return tcp_dispatch_connect(disp, resp);
2185
2186
0
  case isc_socktype_udp:
2187
0
    udp_dispatch_connect(disp, resp);
2188
0
    return ISC_R_SUCCESS;
2189
2190
0
  default:
2191
0
    UNREACHABLE();
2192
0
  }
2193
0
}
2194
2195
static void
2196
0
send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
2197
0
  dns_dispentry_t *resp = (dns_dispentry_t *)cbarg;
2198
2199
0
  REQUIRE(VALID_RESPONSE(resp));
2200
2201
0
  dns_dispatch_t *disp = resp->disp;
2202
2203
0
  REQUIRE(VALID_DISPATCH(disp));
2204
2205
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "sent: %s",
2206
0
          isc_result_totext(result));
2207
2208
0
  resp->sent(result, NULL, resp->arg);
2209
2210
0
  if (result != ISC_R_SUCCESS) {
2211
0
    dispentry_cancel(resp, result);
2212
0
  }
2213
2214
0
  dns_dispentry_detach(&resp); /* DISPENTRY007 */
2215
0
  isc_nmhandle_detach(&handle);
2216
0
}
2217
2218
static void
2219
tcp_dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp,
2220
0
         int64_t timeout) {
2221
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "continue reading");
2222
2223
0
  if (!resp->reading) {
2224
0
    ISC_LIST_APPEND(disp->active, resp, alink);
2225
0
    resp->reading = true;
2226
0
  }
2227
2228
0
  if (disp->reading) {
2229
0
    return;
2230
0
  }
2231
2232
0
  if (timeout != 0) {
2233
0
    INSIST(timeout > 0 && timeout <= UINT32_MAX);
2234
0
    isc_nmhandle_settimeout(disp->handle, timeout);
2235
0
  }
2236
2237
0
  dns_dispatch_ref(disp); /* DISPATCH002 */
2238
0
  isc_nm_read(disp->handle, tcp_recv, disp);
2239
0
  disp->reading = true;
2240
0
}
2241
2242
static void
2243
0
udp_dispatch_getnext(dns_dispentry_t *resp, int64_t timeout) {
2244
0
  if (resp->reading) {
2245
0
    return;
2246
0
  }
2247
2248
0
  if (timeout != 0) {
2249
0
    INSIST(timeout > 0 && timeout <= UINT32_MAX);
2250
0
    isc_nmhandle_settimeout(resp->handle, timeout);
2251
0
  }
2252
2253
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "continue reading");
2254
2255
0
  dns_dispentry_ref(resp); /* DISPENTRY003 */
2256
0
  isc_nm_read(resp->handle, udp_recv, resp);
2257
0
  resp->reading = true;
2258
0
}
2259
2260
void
2261
0
dns_dispatch_resume(dns_dispentry_t *resp, unsigned int timeout) {
2262
0
  REQUIRE(VALID_RESPONSE(resp));
2263
0
  REQUIRE(VALID_DISPATCH(resp->disp));
2264
2265
0
  dns_dispatch_t *disp = resp->disp;
2266
2267
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "resume");
2268
2269
0
  REQUIRE(disp->tid == isc_tid());
2270
0
  switch (disp->socktype) {
2271
0
  case isc_socktype_udp: {
2272
0
    udp_dispatch_getnext(resp, timeout);
2273
0
    break;
2274
0
  }
2275
0
  case isc_socktype_tcp:
2276
0
    INSIST(disp->timedout > 0);
2277
0
    disp->timedout--;
2278
0
    tcp_dispatch_getnext(disp, resp, timeout);
2279
0
    break;
2280
0
  default:
2281
0
    UNREACHABLE();
2282
0
  }
2283
0
}
2284
2285
void
2286
0
dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r) {
2287
0
  REQUIRE(VALID_RESPONSE(resp));
2288
0
  REQUIRE(VALID_DISPATCH(resp->disp));
2289
2290
0
  dns_dispatch_t *disp = resp->disp;
2291
0
  isc_nmhandle_t *sendhandle = NULL;
2292
2293
0
  dispentry_log(resp, ISC_LOG_DEBUG(90), "sending");
2294
0
  switch (disp->socktype) {
2295
0
  case isc_socktype_udp:
2296
0
    isc_nmhandle_attach(resp->handle, &sendhandle);
2297
0
    break;
2298
0
  case isc_socktype_tcp:
2299
0
    isc_nmhandle_attach(disp->handle, &sendhandle);
2300
0
    break;
2301
0
  default:
2302
0
    UNREACHABLE();
2303
0
  }
2304
0
  dns_dispentry_ref(resp); /* DISPENTRY007 */
2305
0
  isc_nm_send(sendhandle, r, send_done, resp);
2306
0
}
2307
2308
isc_result_t
2309
0
dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
2310
0
  REQUIRE(VALID_DISPATCH(disp));
2311
0
  REQUIRE(addrp != NULL);
2312
2313
0
  if (disp->socktype == isc_socktype_udp) {
2314
0
    *addrp = disp->local;
2315
0
    return ISC_R_SUCCESS;
2316
0
  }
2317
0
  return ISC_R_NOTIMPLEMENTED;
2318
0
}
2319
2320
isc_result_t
2321
0
dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) {
2322
0
  REQUIRE(VALID_RESPONSE(resp));
2323
0
  REQUIRE(VALID_DISPATCH(resp->disp));
2324
0
  REQUIRE(addrp != NULL);
2325
2326
0
  dns_dispatch_t *disp = resp->disp;
2327
2328
0
  switch (disp->socktype) {
2329
0
  case isc_socktype_tcp:
2330
0
    *addrp = isc_nmhandle_localaddr(disp->handle);
2331
0
    return ISC_R_SUCCESS;
2332
0
  case isc_socktype_udp:
2333
0
    *addrp = isc_nmhandle_localaddr(resp->handle);
2334
0
    return ISC_R_SUCCESS;
2335
0
  default:
2336
0
    UNREACHABLE();
2337
0
  }
2338
0
}
2339
2340
dns_dispatch_t *
2341
0
dns_dispatchset_get(dns_dispatchset_t *dset) {
2342
0
  isc_tid_t tid = isc_tid();
2343
2344
  /* check that dispatch set is configured */
2345
0
  if (dset == NULL || dset->ndisp == 0) {
2346
0
    return NULL;
2347
0
  }
2348
2349
0
  INSIST((uint32_t)tid < dset->ndisp);
2350
2351
0
  return dset->dispatches[tid];
2352
0
}
2353
2354
isc_result_t
2355
dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
2356
0
           dns_dispatchset_t **dsetp, uint32_t ndisp) {
2357
0
  isc_result_t result;
2358
0
  dns_dispatchset_t *dset = NULL;
2359
0
  dns_dispatchmgr_t *mgr = NULL;
2360
0
  size_t i;
2361
2362
0
  REQUIRE(VALID_DISPATCH(source));
2363
0
  REQUIRE(source->socktype == isc_socktype_udp);
2364
0
  REQUIRE(dsetp != NULL && *dsetp == NULL);
2365
2366
0
  mgr = source->mgr;
2367
2368
0
  dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t));
2369
0
  *dset = (dns_dispatchset_t){ .ndisp = ndisp };
2370
2371
0
  isc_mem_attach(mctx, &dset->mctx);
2372
2373
0
  dset->dispatches = isc_mem_cget(dset->mctx, ndisp,
2374
0
          sizeof(dns_dispatch_t *));
2375
2376
0
  dset->dispatches[0] = NULL;
2377
0
  dns_dispatch_attach(source, &dset->dispatches[0]); /* DISPATCH004 */
2378
2379
0
  for (i = 1; i < dset->ndisp; i++) {
2380
0
    result = dispatch_createudp(mgr, &source->local, i,
2381
0
              &dset->dispatches[i]);
2382
0
    if (result != ISC_R_SUCCESS) {
2383
0
      goto fail;
2384
0
    }
2385
0
  }
2386
2387
0
  *dsetp = dset;
2388
2389
0
  return ISC_R_SUCCESS;
2390
2391
0
fail:
2392
0
  for (size_t j = 0; j < i; j++) {
2393
0
    dns_dispatch_detach(&(dset->dispatches[j])); /* DISPATCH004 */
2394
0
  }
2395
0
  isc_mem_cput(dset->mctx, dset->dispatches, ndisp,
2396
0
         sizeof(dns_dispatch_t *));
2397
2398
0
  isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t));
2399
0
  return result;
2400
0
}
2401
2402
void
2403
0
dns_dispatchset_destroy(dns_dispatchset_t **dsetp) {
2404
0
  REQUIRE(dsetp != NULL && *dsetp != NULL);
2405
2406
0
  dns_dispatchset_t *dset = *dsetp;
2407
0
  *dsetp = NULL;
2408
2409
0
  for (size_t i = 0; i < dset->ndisp; i++) {
2410
0
    dns_dispatch_detach(&(dset->dispatches[i])); /* DISPATCH004 */
2411
0
  }
2412
0
  isc_mem_cput(dset->mctx, dset->dispatches, dset->ndisp,
2413
0
         sizeof(dns_dispatch_t *));
2414
0
  isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t));
2415
0
}
2416
2417
isc_result_t
2418
0
dns_dispatch_checkperm(dns_dispatch_t *disp) {
2419
0
  REQUIRE(VALID_DISPATCH(disp));
2420
2421
0
  if (disp->handle == NULL || disp->socktype == isc_socktype_udp) {
2422
0
    return ISC_R_NOPERM;
2423
0
  }
2424
2425
0
  return isc_nm_xfr_checkperm(disp->handle);
2426
0
}