1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 /*! \file */
13
14 #include <inttypes.h>
15 #include <stdbool.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 #include <isc/atomic.h>
21 #include <isc/mem.h>
22 #include <isc/mutex.h>
23 #include <isc/netmgr.h>
24 #include <isc/portset.h>
25 #include <isc/print.h>
26 #include <isc/random.h>
27 #include <isc/stats.h>
28 #include <isc/string.h>
29 #include <isc/time.h>
30 #include <isc/util.h>
31
32 #include <dns/acl.h>
33 #include <dns/dispatch.h>
34 #include <dns/log.h>
35 #include <dns/message.h>
36 #include <dns/stats.h>
37 #include <dns/types.h>
38
39 typedef ISC_LIST(dns_dispentry_t) dns_displist_t;
40
41 typedef struct dns_qid {
42 unsigned int magic;
43 isc_mutex_t lock;
44 unsigned int qid_nbuckets; /*%< hash table size */
45 unsigned int qid_increment; /*%< id increment on collision */
46 dns_displist_t *qid_table; /*%< the table itself */
47 } dns_qid_t;
48
49 struct dns_dispatchmgr {
50 /* Unlocked. */
51 unsigned int magic;
52 isc_refcount_t references;
53 isc_mem_t *mctx;
54 dns_acl_t *blackhole;
55 isc_stats_t *stats;
56 isc_nm_t *nm;
57
58 /* Locked by "lock". */
59 isc_mutex_t lock;
60 unsigned int state;
61 ISC_LIST(dns_dispatch_t) list;
62
63 dns_qid_t *qid;
64
65 in_port_t *v4ports; /*%< available ports for IPv4 */
66 unsigned int nv4ports; /*%< # of available ports for IPv4 */
67 in_port_t *v6ports; /*%< available ports for IPv4 */
68 unsigned int nv6ports; /*%< # of available ports for IPv4 */
69 };
70
71 #define MGR_SHUTTINGDOWN 0x00000001U
72 #define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0)
73
74 struct dns_dispentry {
75 unsigned int magic;
76 isc_refcount_t references;
77 dns_dispatch_t *disp;
78 isc_nmhandle_t *handle; /*%< netmgr handle for UDP connection */
79 unsigned int bucket;
80 unsigned int retries;
81 unsigned int timeout;
82 isc_time_t start;
83 isc_sockaddr_t local;
84 isc_sockaddr_t peer;
85 in_port_t port;
86 dns_messageid_t id;
87 dispatch_cb_t connected;
88 dispatch_cb_t sent;
89 dispatch_cb_t response;
90 void *arg;
91 bool canceled;
92 ISC_LINK(dns_dispentry_t) link;
93 ISC_LINK(dns_dispentry_t) alink;
94 ISC_LINK(dns_dispentry_t) plink;
95 ISC_LINK(dns_dispentry_t) rlink;
96 };
97
98 /*%
99 * Fixed UDP buffer size.
100 */
101 #ifndef DNS_DISPATCH_UDPBUFSIZE
102 #define DNS_DISPATCH_UDPBUFSIZE 4096
103 #endif /* ifndef DNS_DISPATCH_UDPBUFSIZE */
104
105 typedef enum {
106 DNS_DISPATCHSTATE_NONE = 0UL,
107 DNS_DISPATCHSTATE_CONNECTING,
108 DNS_DISPATCHSTATE_CONNECTED
109 } dns_dispatchstate_t;
110
111 struct dns_dispatch {
112 /* Unlocked. */
113 unsigned int magic; /*%< magic */
114 dns_dispatchmgr_t *mgr; /*%< dispatch manager */
115 isc_nmhandle_t *handle; /*%< netmgr handle for TCP connection */
116 isc_sockaddr_t local; /*%< local address */
117 in_port_t localport; /*%< local UDP port */
118 isc_sockaddr_t peer; /*%< peer address (TCP) */
119
120 /*% Locked by mgr->lock. */
121 ISC_LINK(dns_dispatch_t) link;
122
123 /* Locked by "lock". */
124 isc_mutex_t lock; /*%< locks all below */
125 isc_socktype_t socktype;
126 atomic_uint_fast32_t state;
127 isc_refcount_t references;
128 unsigned int shutdown_out : 1;
129
130 dns_displist_t pending;
131 dns_displist_t active;
132 unsigned int nsockets;
133
134 unsigned int requests; /*%< how many requests we have */
135 unsigned int tcpbuffers; /*%< allocated buffers */
136 };
137
138 #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ')
139 #define VALID_QID(e) ISC_MAGIC_VALID((e), QID_MAGIC)
140
141 #define RESPONSE_MAGIC ISC_MAGIC('D', 'r', 's', 'p')
142 #define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
143
144 #define DISPSOCK_MAGIC ISC_MAGIC('D', 's', 'o', 'c')
145 #define VALID_DISPSOCK(e) ISC_MAGIC_VALID((e), DISPSOCK_MAGIC)
146
147 #define DISPATCH_MAGIC ISC_MAGIC('D', 'i', 's', 'p')
148 #define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
149
150 #define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r')
151 #define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
152
153 /*%
154 * Quota to control the number of UDP dispatch sockets. If a dispatch has
155 * more than the quota of sockets, new queries will purge oldest ones, so
156 * that a massive number of outstanding queries won't prevent subsequent
157 * queries (especially if the older ones take longer time and result in
158 * timeout).
159 */
160 #ifndef DNS_DISPATCH_SOCKSQUOTA
161 #define DNS_DISPATCH_SOCKSQUOTA 3072
162 #endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */
163
164 /*%
165 * Quota to control the number of concurrent requests that can be handled
166 * by each TCP dispatch. (UDP dispatches do not currently support socket
167 * sharing.)
168 */
169 #ifndef DNS_DISPATCH_MAXREQUESTS
170 #define DNS_DISPATCH_MAXREQUESTS 32768
171 #endif /* ifndef DNS_DISPATCH_MAXREQUESTS */
172
173 /*%
174 * Number of buckets in the QID hash table, and the value to
175 * increment the QID by when attempting to avoid collisions.
176 * The number of buckets should be prime, and the increment
177 * should be the next higher prime number.
178 */
179 #ifndef DNS_QID_BUCKETS
180 #define DNS_QID_BUCKETS 16411
181 #endif /* ifndef DNS_QID_BUCKETS */
182 #ifndef DNS_QID_INCREMENT
183 #define DNS_QID_INCREMENT 16433
184 #endif /* ifndef DNS_QID_INCREMENT */
185
186 /*
187 * Statics.
188 */
189 static void
190 dispatchmgr_destroy(dns_dispatchmgr_t *mgr);
191
192 static dns_dispentry_t *
193 entry_search(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t,
194 unsigned int);
195 static void
196 udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
197 void *arg);
198 static void
199 tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
200 void *arg);
201 static uint32_t
202 dns_hash(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t);
203 static void
204 dispatch_free(dns_dispatch_t **dispp);
205 static isc_result_t
206 dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
207 dns_dispatch_t **dispp);
208 static void
209 qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp);
210 static void
211 qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
212 static void
213 startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp);
214 void
215 dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout);
216
217 #define LVL(x) ISC_LOG_DEBUG(x)
218
219 static void
220 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
221 ISC_FORMAT_PRINTF(3, 4);
222
223 static void
mgr_log(dns_dispatchmgr_t * mgr,int level,const char * fmt,...)224 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
225 char msgbuf[2048];
226 va_list ap;
227
228 if (!isc_log_wouldlog(dns_lctx, level)) {
229 return;
230 }
231
232 va_start(ap, fmt);
233 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
234 va_end(ap);
235
236 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
237 DNS_LOGMODULE_DISPATCH, level, "dispatchmgr %p: %s", mgr,
238 msgbuf);
239 }
240
241 static inline void
inc_stats(dns_dispatchmgr_t * mgr,isc_statscounter_t counter)242 inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
243 if (mgr->stats != NULL) {
244 isc_stats_increment(mgr->stats, counter);
245 }
246 }
247
248 static inline void
dec_stats(dns_dispatchmgr_t * mgr,isc_statscounter_t counter)249 dec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
250 if (mgr->stats != NULL) {
251 isc_stats_decrement(mgr->stats, counter);
252 }
253 }
254
255 static void
256 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
257 ISC_FORMAT_PRINTF(3, 4);
258
259 static void
dispatch_log(dns_dispatch_t * disp,int level,const char * fmt,...)260 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
261 char msgbuf[2048];
262 va_list ap;
263
264 if (!isc_log_wouldlog(dns_lctx, level)) {
265 return;
266 }
267
268 va_start(ap, fmt);
269 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
270 va_end(ap);
271
272 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
273 DNS_LOGMODULE_DISPATCH, level, "dispatch %p: %s", disp,
274 msgbuf);
275 }
276
277 /*
278 * Return a hash of the destination and message id.
279 */
280 static uint32_t
dns_hash(dns_qid_t * qid,const isc_sockaddr_t * dest,dns_messageid_t id,in_port_t port)281 dns_hash(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id,
282 in_port_t port) {
283 uint32_t ret;
284
285 ret = isc_sockaddr_hash(dest, true);
286 ret ^= ((uint32_t)id << 16) | port;
287 ret %= qid->qid_nbuckets;
288
289 INSIST(ret < qid->qid_nbuckets);
290
291 return (ret);
292 }
293
294 /*%
295 * Choose a random port number for a dispatch entry.
296 * The caller must hold the disp->lock
297 */
298 static isc_result_t
setup_socket(dns_dispatch_t * disp,dns_dispentry_t * resp,const isc_sockaddr_t * dest,in_port_t * portp)299 setup_socket(dns_dispatch_t *disp, dns_dispentry_t *resp,
300 const isc_sockaddr_t *dest, in_port_t *portp) {
301 dns_dispatchmgr_t *mgr = disp->mgr;
302 unsigned int nports;
303 in_port_t *ports = NULL;
304 in_port_t port;
305
306 if (resp->retries++ > 5) {
307 return (ISC_R_FAILURE);
308 }
309
310 if (isc_sockaddr_pf(&disp->local) == AF_INET) {
311 nports = mgr->nv4ports;
312 ports = mgr->v4ports;
313 } else {
314 nports = mgr->nv6ports;
315 ports = mgr->v6ports;
316 }
317 if (nports == 0) {
318 return (ISC_R_ADDRNOTAVAIL);
319 }
320
321 disp->nsockets++;
322
323 resp->local = disp->local;
324 resp->peer = *dest;
325
326 port = ports[isc_random_uniform(nports)];
327 isc_sockaddr_setport(&resp->local, port);
328 resp->port = port;
329
330 *portp = port;
331
332 return (ISC_R_SUCCESS);
333 }
334
335 /*%
336 * Deactivate the socket for a dispatch entry.
337 * The dispatch must be locked.
338 */
339 static void
deactivate_dispentry(dns_dispatch_t * disp,dns_dispentry_t * resp)340 deactivate_dispentry(dns_dispatch_t *disp, dns_dispentry_t *resp) {
341 if (ISC_LINK_LINKED(resp, alink)) {
342 ISC_LIST_UNLINK(disp->active, resp, alink);
343 }
344
345 if (resp->handle != NULL) {
346 INSIST(disp->socktype == isc_socktype_udp);
347
348 isc_nm_cancelread(resp->handle);
349 isc_nmhandle_detach(&resp->handle);
350 }
351
352 disp->nsockets--;
353 }
354
355 /*
356 * Find an entry for query ID 'id', socket address 'dest', and port number
357 * 'port'.
358 * Return NULL if no such entry exists.
359 */
360 static dns_dispentry_t *
entry_search(dns_qid_t * qid,const isc_sockaddr_t * dest,dns_messageid_t id,in_port_t port,unsigned int bucket)361 entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id,
362 in_port_t port, unsigned int bucket) {
363 dns_dispentry_t *res = NULL;
364
365 REQUIRE(VALID_QID(qid));
366 REQUIRE(bucket < qid->qid_nbuckets);
367
368 res = ISC_LIST_HEAD(qid->qid_table[bucket]);
369
370 while (res != NULL) {
371 if (res->id == id && isc_sockaddr_equal(dest, &res->peer) &&
372 res->port == port) {
373 return (res);
374 }
375 res = ISC_LIST_NEXT(res, link);
376 }
377
378 return (NULL);
379 }
380
381 static void
dispentry_attach(dns_dispentry_t * resp,dns_dispentry_t ** respp)382 dispentry_attach(dns_dispentry_t *resp, dns_dispentry_t **respp) {
383 REQUIRE(VALID_RESPONSE(resp));
384 REQUIRE(respp != NULL && *respp == NULL);
385
386 isc_refcount_increment(&resp->references);
387
388 *respp = resp;
389 }
390
391 static void
dispentry_destroy(dns_dispentry_t * resp)392 dispentry_destroy(dns_dispentry_t *resp) {
393 dns_dispatch_t *disp = resp->disp;
394
395 resp->magic = 0;
396
397 if (ISC_LINK_LINKED(resp, plink)) {
398 ISC_LIST_UNLINK(disp->pending, resp, plink);
399 }
400
401 INSIST(!ISC_LINK_LINKED(resp, alink));
402 INSIST(!ISC_LINK_LINKED(resp, rlink));
403
404 if (resp->handle != NULL) {
405 isc_nmhandle_detach(&resp->handle);
406 }
407
408 isc_refcount_destroy(&resp->references);
409
410 isc_mem_put(disp->mgr->mctx, resp, sizeof(*resp));
411
412 dns_dispatch_detach(&disp);
413 }
414
415 static void
dispentry_detach(dns_dispentry_t ** respp)416 dispentry_detach(dns_dispentry_t **respp) {
417 dns_dispentry_t *resp = NULL;
418 uint_fast32_t ref;
419
420 REQUIRE(respp != NULL && VALID_RESPONSE(*respp));
421
422 resp = *respp;
423 *respp = NULL;
424
425 ref = isc_refcount_decrement(&resp->references);
426 if (ref == 1) {
427 dispentry_destroy(resp);
428 }
429 }
430
431 /*
432 * How long in milliseconds has it been since this dispentry
433 * started reading? (Only used for UDP, to adjust the timeout
434 * downward when running getnext.)
435 */
436 static unsigned int
dispentry_runtime(dns_dispentry_t * resp)437 dispentry_runtime(dns_dispentry_t *resp) {
438 isc_time_t now;
439
440 if (isc_time_isepoch(&resp->start)) {
441 return (0);
442 }
443
444 TIME_NOW(&now);
445 return (isc_time_microdiff(&now, &resp->start) / 1000);
446 }
447
448 /*
449 * General flow:
450 *
451 * If I/O result == CANCELED or error, free the buffer.
452 *
453 * If query, free the buffer, restart.
454 *
455 * If response:
456 * Allocate event, fill in details.
457 * If cannot allocate, free buffer, restart.
458 * find target. If not found, free buffer, restart.
459 * if event queue is not empty, queue. else, send.
460 * restart.
461 */
462 static void
udp_recv(isc_nmhandle_t * handle,isc_result_t eresult,isc_region_t * region,void * arg)463 udp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
464 void *arg) {
465 dns_dispentry_t *resp = (dns_dispentry_t *)arg;
466 dns_dispatch_t *disp = NULL;
467 dns_messageid_t id;
468 isc_result_t dres;
469 isc_buffer_t source;
470 unsigned int flags;
471 isc_sockaddr_t peer;
472 isc_netaddr_t netaddr;
473 int match, timeout;
474 dispatch_cb_t response = NULL;
475
476 REQUIRE(VALID_RESPONSE(resp));
477 REQUIRE(VALID_DISPATCH(resp->disp));
478
479 disp = resp->disp;
480
481 LOCK(&disp->lock);
482
483 dispatch_log(disp, LVL(90), "UDP response %p:%s:requests %d", resp,
484 isc_result_totext(eresult), disp->requests);
485
486 /*
487 * The resp may have been deactivated by shutdown; if
488 * so, we can skip the response callback.
489 */
490 if (ISC_LINK_LINKED(resp, alink)) {
491 response = resp->response;
492 }
493
494 if (eresult != ISC_R_SUCCESS) {
495 /*
496 * This is most likely a network error on a connected
497 * socket, a timeout, or the query has been canceled.
498 * It makes no sense to check the address or parse the
499 * packet, but we can return the error to the caller.
500 */
501 goto done;
502 }
503
504 INSIST(ISC_LINK_LINKED(resp, alink));
505
506 peer = isc_nmhandle_peeraddr(handle);
507 isc_netaddr_fromsockaddr(&netaddr, &peer);
508
509 /*
510 * If this is from a blackholed address, drop it.
511 */
512 if (disp->mgr->blackhole != NULL &&
513 dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match,
514 NULL) == ISC_R_SUCCESS &&
515 match > 0)
516 {
517 if (isc_log_wouldlog(dns_lctx, LVL(10))) {
518 char netaddrstr[ISC_NETADDR_FORMATSIZE];
519 isc_netaddr_format(&netaddr, netaddrstr,
520 sizeof(netaddrstr));
521 dispatch_log(disp, LVL(10), "blackholed packet from %s",
522 netaddrstr);
523 }
524 goto next;
525 }
526
527 /*
528 * Peek into the buffer to see what we can see.
529 */
530 id = resp->id;
531 isc_buffer_init(&source, region->base, region->length);
532 isc_buffer_add(&source, region->length);
533 dres = dns_message_peekheader(&source, &id, &flags);
534 if (dres != ISC_R_SUCCESS) {
535 dispatch_log(disp, LVL(10), "got garbage packet");
536 goto next;
537 }
538
539 dispatch_log(disp, LVL(92),
540 "got valid DNS message header, /QR %c, id %u",
541 (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id);
542
543 /*
544 * Look at the message flags. If it's a query, ignore it.
545 */
546 if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
547 goto next;
548 }
549
550 /*
551 * The QID and the address must match the expected ones.
552 */
553 if (resp->id != id || !isc_sockaddr_equal(&peer, &resp->peer)) {
554 dispatch_log(disp, LVL(90), "response doesn't match");
555 inc_stats(disp->mgr, dns_resstatscounter_mismatch);
556 goto next;
557 }
558
559 /*
560 * We have the right resp, so call the caller back.
561 */
562 goto done;
563
564 next:
565 /*
566 * This is the wrong response. Don't call the caller back
567 * but keep listening.
568 */
569 response = NULL;
570
571 timeout = resp->timeout - dispentry_runtime(resp);
572 if (timeout <= 0) {
573 eresult = ISC_R_TIMEDOUT;
574 goto done;
575 }
576 dispatch_getnext(disp, resp, resp->timeout - dispentry_runtime(resp));
577
578 done:
579 UNLOCK(&disp->lock);
580
581 if (response != NULL) {
582 response(eresult, region, resp->arg);
583 }
584
585 dispentry_detach(&resp);
586 }
587
588 /*
589 * General flow:
590 *
591 * If I/O result == CANCELED, EOF, or error, notify everyone as the
592 * various queues drain.
593 *
594 * If query, restart.
595 *
596 * If response:
597 * Allocate event, fill in details.
598 * If cannot allocate, restart.
599 * find target. If not found, restart.
600 * if event queue is not empty, queue. else, send.
601 * restart.
602 */
603 static void
tcp_recv(isc_nmhandle_t * handle,isc_result_t eresult,isc_region_t * region,void * arg)604 tcp_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
605 void *arg) {
606 dns_dispatch_t *disp = (dns_dispatch_t *)arg;
607 dns_dispentry_t *resp = NULL, *next = NULL;
608 dns_messageid_t id;
609 isc_result_t dres;
610 unsigned int flags;
611 unsigned int bucket;
612 dns_qid_t *qid = NULL;
613 int level;
614 char buf[ISC_SOCKADDR_FORMATSIZE];
615 isc_buffer_t source;
616 isc_sockaddr_t peer;
617 dns_displist_t resps;
618
619 REQUIRE(VALID_DISPATCH(disp));
620
621 qid = disp->mgr->qid;
622
623 LOCK(&disp->lock);
624
625 dispatch_log(disp, LVL(90), "TCP read:%s:requests %d, buffers %d",
626 isc_result_totext(eresult), disp->requests,
627 disp->tcpbuffers);
628
629 peer = isc_nmhandle_peeraddr(handle);
630 ISC_LIST_INIT(resps);
631
632 switch (eresult) {
633 case ISC_R_SUCCESS:
634 /* got our answer */
635 break;
636
637 case ISC_R_SHUTTINGDOWN:
638 case ISC_R_CANCELED:
639 case ISC_R_EOF:
640 dispatch_log(disp, LVL(90), "shutting down: %s",
641 isc_result_totext(eresult));
642 /*
643 * If there are any active responses, shut them all down.
644 */
645 for (resp = ISC_LIST_HEAD(disp->active); resp != NULL;
646 resp = next) {
647 next = ISC_LIST_NEXT(resp, alink);
648 dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
649 ISC_LIST_UNLINK(disp->active, resp, alink);
650 ISC_LIST_APPEND(resps, resp, rlink);
651 }
652 goto done;
653
654 case ISC_R_TIMEDOUT:
655 /*
656 * Time out the oldest response in the active queue,
657 * and move it to the end. (We don't remove it from the
658 * active queue immediately, though, because the callback
659 * might decide to keep waiting and leave it active.)
660 */
661 resp = ISC_LIST_HEAD(disp->active);
662 if (resp != NULL) {
663 dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
664 ISC_LIST_UNLINK(disp->active, resp, alink);
665 ISC_LIST_APPEND(disp->active, resp, alink);
666 }
667 goto done;
668
669 default:
670 if (eresult == ISC_R_CONNECTIONRESET) {
671 level = ISC_LOG_INFO;
672 } else {
673 level = ISC_LOG_ERROR;
674 }
675
676 isc_sockaddr_format(&peer, buf, sizeof(buf));
677 dispatch_log(disp, level,
678 "shutting down due to TCP "
679 "receive error: %s: %s",
680 buf, isc_result_totext(eresult));
681 goto done;
682 }
683
684 dispatch_log(disp, LVL(90), "success, length == %d, addr = %p",
685 region->length, region->base);
686
687 /*
688 * Peek into the buffer to see what we can see.
689 */
690 isc_buffer_init(&source, region->base, region->length);
691 isc_buffer_add(&source, region->length);
692 dres = dns_message_peekheader(&source, &id, &flags);
693 if (dres != ISC_R_SUCCESS) {
694 dispatch_log(disp, LVL(10), "got garbage packet");
695 goto next;
696 }
697
698 dispatch_log(disp, LVL(92),
699 "got valid DNS message header, /QR %c, id %u",
700 (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id);
701
702 /*
703 * Look at the message flags. If it's a query, ignore it
704 * and keep reading.
705 */
706 if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
707 /*
708 * Query.
709 */
710 goto next;
711 }
712
713 /*
714 * We have a valid response; find the associated dispentry object
715 * and call the caller back.
716 */
717 bucket = dns_hash(qid, &peer, id, disp->localport);
718 LOCK(&qid->lock);
719 resp = entry_search(qid, &peer, id, disp->localport, bucket);
720 if (resp != NULL) {
721 dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
722 }
723 dispatch_log(disp, LVL(90), "search for response in bucket %d: %s",
724 bucket, (resp == NULL ? "not found" : "found"));
725 UNLOCK(&qid->lock);
726
727 next:
728 dispatch_getnext(disp, NULL, -1);
729
730 done:
731 UNLOCK(&disp->lock);
732
733 if (resp != NULL) {
734 /* We got a matching response, or timed out */
735 resp->response(eresult, region, resp->arg);
736 dispentry_detach(&resp);
737 } else {
738 /* We're being shut down; cancel all outstanding resps */
739 for (resp = ISC_LIST_HEAD(resps); resp != NULL; resp = next) {
740 next = ISC_LIST_NEXT(resp, rlink);
741 ISC_LIST_UNLINK(resps, resp, rlink);
742 resp->response(ISC_R_SHUTTINGDOWN, region, resp->arg);
743 dispentry_detach(&resp);
744 }
745 }
746
747 dns_dispatch_detach(&disp);
748 }
749
750 /*%
751 * Create a temporary port list to set the initial default set of dispatch
752 * ports: [1024, 65535]. This is almost meaningless as the application will
753 * normally set the ports explicitly, but is provided to fill some minor corner
754 * cases.
755 */
756 static void
create_default_portset(isc_mem_t * mctx,isc_portset_t ** portsetp)757 create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) {
758 isc_portset_create(mctx, portsetp);
759 isc_portset_addrange(*portsetp, 1024, 65535);
760 }
761
762 static isc_result_t
setavailports(dns_dispatchmgr_t * mgr,isc_portset_t * v4portset,isc_portset_t * v6portset)763 setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
764 isc_portset_t *v6portset) {
765 in_port_t *v4ports, *v6ports, p = 0;
766 unsigned int nv4ports, nv6ports, i4 = 0, i6 = 0;
767
768 nv4ports = isc_portset_nports(v4portset);
769 nv6ports = isc_portset_nports(v6portset);
770
771 v4ports = NULL;
772 if (nv4ports != 0) {
773 v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports);
774 }
775 v6ports = NULL;
776 if (nv6ports != 0) {
777 v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports);
778 }
779
780 do {
781 if (isc_portset_isset(v4portset, p)) {
782 INSIST(i4 < nv4ports);
783 v4ports[i4++] = p;
784 }
785 if (isc_portset_isset(v6portset, p)) {
786 INSIST(i6 < nv6ports);
787 v6ports[i6++] = p;
788 }
789 } while (p++ < 65535);
790 INSIST(i4 == nv4ports && i6 == nv6ports);
791
792 if (mgr->v4ports != NULL) {
793 isc_mem_put(mgr->mctx, mgr->v4ports,
794 mgr->nv4ports * sizeof(in_port_t));
795 }
796 mgr->v4ports = v4ports;
797 mgr->nv4ports = nv4ports;
798
799 if (mgr->v6ports != NULL) {
800 isc_mem_put(mgr->mctx, mgr->v6ports,
801 mgr->nv6ports * sizeof(in_port_t));
802 }
803 mgr->v6ports = v6ports;
804 mgr->nv6ports = nv6ports;
805
806 return (ISC_R_SUCCESS);
807 }
808
809 /*
810 * Publics.
811 */
812
813 isc_result_t
dns_dispatchmgr_create(isc_mem_t * mctx,isc_nm_t * nm,dns_dispatchmgr_t ** mgrp)814 dns_dispatchmgr_create(isc_mem_t *mctx, isc_nm_t *nm,
815 dns_dispatchmgr_t **mgrp) {
816 dns_dispatchmgr_t *mgr = NULL;
817 isc_portset_t *v4portset = NULL;
818 isc_portset_t *v6portset = NULL;
819
820 REQUIRE(mctx != NULL);
821 REQUIRE(mgrp != NULL && *mgrp == NULL);
822
823 mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
824 *mgr = (dns_dispatchmgr_t){ .magic = 0 };
825
826 isc_refcount_init(&mgr->references, 1);
827
828 isc_mem_attach(mctx, &mgr->mctx);
829 isc_nm_attach(nm, &mgr->nm);
830
831 isc_mutex_init(&mgr->lock);
832
833 ISC_LIST_INIT(mgr->list);
834
835 create_default_portset(mctx, &v4portset);
836 create_default_portset(mctx, &v6portset);
837
838 setavailports(mgr, v4portset, v6portset);
839
840 isc_portset_destroy(mctx, &v4portset);
841 isc_portset_destroy(mctx, &v6portset);
842
843 qid_allocate(mgr, &mgr->qid);
844 mgr->magic = DNS_DISPATCHMGR_MAGIC;
845
846 *mgrp = mgr;
847 return (ISC_R_SUCCESS);
848 }
849
850 void
dns_dispatchmgr_attach(dns_dispatchmgr_t * mgr,dns_dispatchmgr_t ** mgrp)851 dns_dispatchmgr_attach(dns_dispatchmgr_t *mgr, dns_dispatchmgr_t **mgrp) {
852 REQUIRE(VALID_DISPATCHMGR(mgr));
853 REQUIRE(mgrp != NULL && *mgrp == NULL);
854
855 isc_refcount_increment(&mgr->references);
856
857 *mgrp = mgr;
858 }
859
860 void
dns_dispatchmgr_detach(dns_dispatchmgr_t ** mgrp)861 dns_dispatchmgr_detach(dns_dispatchmgr_t **mgrp) {
862 dns_dispatchmgr_t *mgr = NULL;
863 uint_fast32_t ref;
864
865 REQUIRE(mgrp != NULL && VALID_DISPATCHMGR(*mgrp));
866
867 mgr = *mgrp;
868 *mgrp = NULL;
869
870 ref = isc_refcount_decrement(&mgr->references);
871 if (ref == 1) {
872 dispatchmgr_destroy(mgr);
873 }
874 }
875
876 void
dns_dispatchmgr_setblackhole(dns_dispatchmgr_t * mgr,dns_acl_t * blackhole)877 dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
878 REQUIRE(VALID_DISPATCHMGR(mgr));
879 if (mgr->blackhole != NULL) {
880 dns_acl_detach(&mgr->blackhole);
881 }
882 dns_acl_attach(blackhole, &mgr->blackhole);
883 }
884
885 dns_acl_t *
dns_dispatchmgr_getblackhole(dns_dispatchmgr_t * mgr)886 dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
887 REQUIRE(VALID_DISPATCHMGR(mgr));
888 return (mgr->blackhole);
889 }
890
891 isc_result_t
dns_dispatchmgr_setavailports(dns_dispatchmgr_t * mgr,isc_portset_t * v4portset,isc_portset_t * v6portset)892 dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
893 isc_portset_t *v6portset) {
894 REQUIRE(VALID_DISPATCHMGR(mgr));
895 return (setavailports(mgr, v4portset, v6portset));
896 }
897
898 static void
dispatchmgr_destroy(dns_dispatchmgr_t * mgr)899 dispatchmgr_destroy(dns_dispatchmgr_t *mgr) {
900 REQUIRE(VALID_DISPATCHMGR(mgr));
901
902 isc_refcount_destroy(&mgr->references);
903
904 mgr->magic = 0;
905 isc_mutex_destroy(&mgr->lock);
906 mgr->state = 0;
907
908 qid_destroy(mgr->mctx, &mgr->qid);
909
910 if (mgr->blackhole != NULL) {
911 dns_acl_detach(&mgr->blackhole);
912 }
913
914 if (mgr->stats != NULL) {
915 isc_stats_detach(&mgr->stats);
916 }
917
918 if (mgr->v4ports != NULL) {
919 isc_mem_put(mgr->mctx, mgr->v4ports,
920 mgr->nv4ports * sizeof(in_port_t));
921 }
922 if (mgr->v6ports != NULL) {
923 isc_mem_put(mgr->mctx, mgr->v6ports,
924 mgr->nv6ports * sizeof(in_port_t));
925 }
926
927 isc_nm_detach(&mgr->nm);
928
929 isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t));
930 }
931
932 void
dns_dispatchmgr_setstats(dns_dispatchmgr_t * mgr,isc_stats_t * stats)933 dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) {
934 REQUIRE(VALID_DISPATCHMGR(mgr));
935 REQUIRE(ISC_LIST_EMPTY(mgr->list));
936 REQUIRE(mgr->stats == NULL);
937
938 isc_stats_attach(stats, &mgr->stats);
939 }
940
941 static void
qid_allocate(dns_dispatchmgr_t * mgr,dns_qid_t ** qidp)942 qid_allocate(dns_dispatchmgr_t *mgr, dns_qid_t **qidp) {
943 dns_qid_t *qid = NULL;
944 unsigned int i;
945
946 REQUIRE(qidp != NULL && *qidp == NULL);
947
948 qid = isc_mem_get(mgr->mctx, sizeof(*qid));
949 *qid = (dns_qid_t){ .qid_nbuckets = DNS_QID_BUCKETS,
950 .qid_increment = DNS_QID_INCREMENT };
951
952 qid->qid_table = isc_mem_get(mgr->mctx,
953 DNS_QID_BUCKETS * sizeof(dns_displist_t));
954 for (i = 0; i < qid->qid_nbuckets; i++) {
955 ISC_LIST_INIT(qid->qid_table[i]);
956 }
957
958 isc_mutex_init(&qid->lock);
959 qid->magic = QID_MAGIC;
960 *qidp = qid;
961 }
962
963 static void
qid_destroy(isc_mem_t * mctx,dns_qid_t ** qidp)964 qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
965 dns_qid_t *qid = NULL;
966
967 REQUIRE(qidp != NULL);
968 qid = *qidp;
969 *qidp = NULL;
970
971 REQUIRE(VALID_QID(qid));
972
973 qid->magic = 0;
974 isc_mem_put(mctx, qid->qid_table,
975 qid->qid_nbuckets * sizeof(dns_displist_t));
976 isc_mutex_destroy(&qid->lock);
977 isc_mem_put(mctx, qid, sizeof(*qid));
978 }
979
980 /*
981 * Allocate and set important limits.
982 */
983 static void
dispatch_allocate(dns_dispatchmgr_t * mgr,isc_socktype_t type,dns_dispatch_t ** dispp)984 dispatch_allocate(dns_dispatchmgr_t *mgr, isc_socktype_t type,
985 dns_dispatch_t **dispp) {
986 dns_dispatch_t *disp = NULL;
987
988 REQUIRE(VALID_DISPATCHMGR(mgr));
989 REQUIRE(dispp != NULL && *dispp == NULL);
990
991 /*
992 * Set up the dispatcher, mostly. Don't bother setting some of
993 * the options that are controlled by tcp vs. udp, etc.
994 */
995
996 disp = isc_mem_get(mgr->mctx, sizeof(*disp));
997 *disp = (dns_dispatch_t){ .socktype = type };
998
999 dns_dispatchmgr_attach(mgr, &disp->mgr);
1000 isc_refcount_init(&disp->references, 1);
1001 ISC_LINK_INIT(disp, link);
1002 ISC_LIST_INIT(disp->active);
1003 ISC_LIST_INIT(disp->pending);
1004
1005 isc_mutex_init(&disp->lock);
1006
1007 disp->magic = DISPATCH_MAGIC;
1008
1009 *dispp = disp;
1010 }
1011
1012 /*
1013 * MUST be unlocked, and not used by anything.
1014 */
1015 static void
dispatch_free(dns_dispatch_t ** dispp)1016 dispatch_free(dns_dispatch_t **dispp) {
1017 dns_dispatch_t *disp = NULL;
1018 dns_dispatchmgr_t *mgr = NULL;
1019
1020 REQUIRE(VALID_DISPATCH(*dispp));
1021 disp = *dispp;
1022 *dispp = NULL;
1023
1024 disp->magic = 0;
1025
1026 mgr = disp->mgr;
1027 REQUIRE(VALID_DISPATCHMGR(mgr));
1028
1029 INSIST(disp->requests == 0);
1030 INSIST(ISC_LIST_EMPTY(disp->active));
1031
1032 isc_mutex_destroy(&disp->lock);
1033
1034 isc_mem_put(mgr->mctx, disp, sizeof(*disp));
1035 }
1036
1037 isc_result_t
dns_dispatch_createtcp(dns_dispatchmgr_t * mgr,const isc_sockaddr_t * localaddr,const isc_sockaddr_t * destaddr,isc_dscp_t dscp,dns_dispatch_t ** dispp)1038 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1039 const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
1040 dns_dispatch_t **dispp) {
1041 dns_dispatch_t *disp = NULL;
1042
1043 REQUIRE(VALID_DISPATCHMGR(mgr));
1044 REQUIRE(destaddr != NULL);
1045
1046 UNUSED(dscp);
1047
1048 LOCK(&mgr->lock);
1049
1050 dispatch_allocate(mgr, isc_socktype_tcp, &disp);
1051
1052 disp->peer = *destaddr;
1053
1054 if (localaddr != NULL) {
1055 disp->local = *localaddr;
1056 } else {
1057 int pf;
1058 pf = isc_sockaddr_pf(destaddr);
1059 isc_sockaddr_anyofpf(&disp->local, pf);
1060 isc_sockaddr_setport(&disp->local, 0);
1061 }
1062
1063 /*
1064 * Append it to the dispatcher list.
1065 */
1066
1067 /* FIXME: There should be a lookup hashtable here */
1068 ISC_LIST_APPEND(mgr->list, disp, link);
1069 UNLOCK(&mgr->lock);
1070
1071 mgr_log(mgr, LVL(90), "dns_dispatch_createtcp: created TCP dispatch %p",
1072 disp);
1073 *dispp = disp;
1074
1075 return (ISC_R_SUCCESS);
1076 }
1077
1078 isc_result_t
dns_dispatch_gettcp(dns_dispatchmgr_t * mgr,const isc_sockaddr_t * destaddr,const isc_sockaddr_t * localaddr,bool * connected,dns_dispatch_t ** dispp)1079 dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr,
1080 const isc_sockaddr_t *localaddr, bool *connected,
1081 dns_dispatch_t **dispp) {
1082 dns_dispatch_t *disp_connected = NULL;
1083 dns_dispatch_t *disp_fallback = NULL;
1084 isc_result_t result = ISC_R_NOTFOUND;
1085
1086 REQUIRE(VALID_DISPATCHMGR(mgr));
1087 REQUIRE(destaddr != NULL);
1088 REQUIRE(connected != NULL);
1089 REQUIRE(dispp != NULL && *dispp == NULL);
1090
1091 LOCK(&mgr->lock);
1092
1093 for (dns_dispatch_t *disp = ISC_LIST_HEAD(mgr->list); disp != NULL;
1094 disp = ISC_LIST_NEXT(disp, link))
1095 {
1096 isc_sockaddr_t sockname;
1097 isc_sockaddr_t peeraddr;
1098
1099 LOCK(&disp->lock);
1100
1101 if (disp->handle != NULL) {
1102 sockname = isc_nmhandle_localaddr(disp->handle);
1103 peeraddr = isc_nmhandle_peeraddr(disp->handle);
1104 } else {
1105 sockname = disp->local;
1106 peeraddr = disp->peer;
1107 }
1108
1109 /*
1110 * The conditions match:
1111 * 1. socktype is TCP
1112 * 2. destination address is same
1113 * 3. local address is either NULL or same
1114 */
1115 if (disp->socktype == isc_socktype_tcp &&
1116 isc_sockaddr_equal(destaddr, &peeraddr) &&
1117 (localaddr == NULL ||
1118 isc_sockaddr_eqaddr(localaddr, &sockname)))
1119 {
1120 if (atomic_load(&disp->state) ==
1121 DNS_DISPATCHSTATE_CONNECTED) {
1122 /* We found connected dispatch */
1123 disp_connected = disp;
1124 UNLOCK(&disp->lock);
1125 break;
1126 }
1127
1128 /* We found "a" dispatch, store it for later */
1129 if (disp_fallback == NULL) {
1130 disp_fallback = disp;
1131 }
1132
1133 UNLOCK(&disp->lock);
1134 continue;
1135 }
1136
1137 UNLOCK(&disp->lock);
1138 }
1139
1140 if (disp_connected != NULL) {
1141 /* We found connected dispatch */
1142 INSIST(disp_connected->handle != NULL);
1143
1144 *connected = true;
1145 dns_dispatch_attach(disp_connected, dispp);
1146
1147 result = ISC_R_SUCCESS;
1148 } else if (disp_fallback != NULL) {
1149 /* We found matching dispatch */
1150 *connected = false;
1151
1152 dns_dispatch_attach(disp_fallback, dispp);
1153
1154 result = ISC_R_SUCCESS;
1155 }
1156
1157 UNLOCK(&mgr->lock);
1158
1159 return (result);
1160 }
1161
1162 isc_result_t
dns_dispatch_createudp(dns_dispatchmgr_t * mgr,const isc_sockaddr_t * localaddr,dns_dispatch_t ** dispp)1163 dns_dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1164 dns_dispatch_t **dispp) {
1165 isc_result_t result;
1166 dns_dispatch_t *disp = NULL;
1167
1168 REQUIRE(VALID_DISPATCHMGR(mgr));
1169 REQUIRE(localaddr != NULL);
1170 REQUIRE(dispp != NULL && *dispp == NULL);
1171
1172 LOCK(&mgr->lock);
1173 result = dispatch_createudp(mgr, localaddr, &disp);
1174 if (result == ISC_R_SUCCESS) {
1175 *dispp = disp;
1176 }
1177 UNLOCK(&mgr->lock);
1178
1179 return (result);
1180 }
1181
1182 static isc_result_t
dispatch_createudp(dns_dispatchmgr_t * mgr,const isc_sockaddr_t * localaddr,dns_dispatch_t ** dispp)1183 dispatch_createudp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *localaddr,
1184 dns_dispatch_t **dispp) {
1185 isc_result_t result = ISC_R_SUCCESS;
1186 dns_dispatch_t *disp = NULL;
1187 isc_sockaddr_t sa_any;
1188
1189 dispatch_allocate(mgr, isc_socktype_udp, &disp);
1190
1191 /*
1192 * Check whether this address/port is available locally.
1193 */
1194 isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
1195 if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
1196 result = isc_nm_checkaddr(localaddr, isc_socktype_udp);
1197 if (result != ISC_R_SUCCESS) {
1198 goto cleanup;
1199 }
1200 }
1201
1202 if (isc_log_wouldlog(dns_lctx, 90)) {
1203 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
1204
1205 isc_sockaddr_format(localaddr, addrbuf,
1206 ISC_SOCKADDR_FORMATSIZE);
1207 mgr_log(mgr, LVL(90),
1208 "dispatch_createudp: created UDP dispatch for %s",
1209 addrbuf);
1210 }
1211
1212 disp->local = *localaddr;
1213
1214 /*
1215 * Append it to the dispatcher list.
1216 */
1217 ISC_LIST_APPEND(mgr->list, disp, link);
1218
1219 mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
1220
1221 *dispp = disp;
1222
1223 return (result);
1224
1225 /*
1226 * Error returns.
1227 */
1228 cleanup:
1229 dispatch_free(&disp);
1230
1231 return (result);
1232 }
1233
1234 static void
dispatch_destroy(dns_dispatch_t * disp)1235 dispatch_destroy(dns_dispatch_t *disp) {
1236 dns_dispatchmgr_t *mgr = disp->mgr;
1237
1238 LOCK(&mgr->lock);
1239 ISC_LIST_UNLINK(mgr->list, disp, link);
1240 UNLOCK(&mgr->lock);
1241
1242 dispatch_log(disp, LVL(90), "shutting down; detaching from handle %p",
1243 disp->handle);
1244
1245 if (disp->handle != NULL) {
1246 isc_nmhandle_detach(&disp->handle);
1247 }
1248
1249 dispatch_free(&disp);
1250
1251 /*
1252 * Because dispatch uses mgr->mctx, we must detach after freeing
1253 * dispatch, not before.
1254 */
1255 dns_dispatchmgr_detach(&mgr);
1256 }
1257
1258 void
dns_dispatch_attach(dns_dispatch_t * disp,dns_dispatch_t ** dispp)1259 dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
1260 REQUIRE(VALID_DISPATCH(disp));
1261 REQUIRE(dispp != NULL && *dispp == NULL);
1262
1263 isc_refcount_increment(&disp->references);
1264
1265 *dispp = disp;
1266 }
1267
1268 void
dns_dispatch_detach(dns_dispatch_t ** dispp)1269 dns_dispatch_detach(dns_dispatch_t **dispp) {
1270 dns_dispatch_t *disp = NULL;
1271 uint_fast32_t ref;
1272
1273 REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
1274
1275 disp = *dispp;
1276 *dispp = NULL;
1277
1278 ref = isc_refcount_decrement(&disp->references);
1279 dispatch_log(disp, LVL(90), "detach: refcount %" PRIuFAST32, ref - 1);
1280 if (ref == 1) {
1281 LOCK(&disp->lock);
1282 INSIST(ISC_LIST_EMPTY(disp->pending));
1283 INSIST(ISC_LIST_EMPTY(disp->active));
1284 UNLOCK(&disp->lock);
1285
1286 dispatch_destroy(disp);
1287 }
1288 }
1289
1290 isc_result_t
dns_dispatch_add(dns_dispatch_t * disp,unsigned int options,unsigned int timeout,const isc_sockaddr_t * dest,dispatch_cb_t connected,dispatch_cb_t sent,dispatch_cb_t response,void * arg,dns_messageid_t * idp,dns_dispentry_t ** resp)1291 dns_dispatch_add(dns_dispatch_t *disp, unsigned int options,
1292 unsigned int timeout, const isc_sockaddr_t *dest,
1293 dispatch_cb_t connected, dispatch_cb_t sent,
1294 dispatch_cb_t response, void *arg, dns_messageid_t *idp,
1295 dns_dispentry_t **resp) {
1296 dns_dispentry_t *res = NULL;
1297 dns_qid_t *qid = NULL;
1298 in_port_t localport = 0;
1299 dns_messageid_t id;
1300 unsigned int bucket;
1301 bool ok = false;
1302 int i = 0;
1303 dispatch_cb_t oldest_response = NULL;
1304
1305 REQUIRE(VALID_DISPATCH(disp));
1306 REQUIRE(dest != NULL);
1307 REQUIRE(resp != NULL && *resp == NULL);
1308 REQUIRE(idp != NULL);
1309 REQUIRE(disp->socktype == isc_socktype_tcp ||
1310 disp->socktype == isc_socktype_udp);
1311
1312 LOCK(&disp->lock);
1313
1314 if (disp->requests >= DNS_DISPATCH_MAXREQUESTS) {
1315 UNLOCK(&disp->lock);
1316 return (ISC_R_QUOTA);
1317 }
1318
1319 qid = disp->mgr->qid;
1320
1321 if (disp->socktype == isc_socktype_udp &&
1322 disp->nsockets > DNS_DISPATCH_SOCKSQUOTA)
1323 {
1324 dns_dispentry_t *oldest = NULL;
1325
1326 /*
1327 * Kill oldest outstanding query if the number of sockets
1328 * exceeds the quota to keep the room for new queries.
1329 */
1330 oldest = ISC_LIST_HEAD(disp->active);
1331 if (oldest != NULL) {
1332 oldest_response = oldest->response;
1333 inc_stats(disp->mgr, dns_resstatscounter_dispabort);
1334 }
1335 }
1336
1337 res = isc_mem_get(disp->mgr->mctx, sizeof(*res));
1338
1339 *res = (dns_dispentry_t){ .port = localport,
1340 .timeout = timeout,
1341 .peer = *dest,
1342 .connected = connected,
1343 .sent = sent,
1344 .response = response,
1345 .arg = arg };
1346
1347 isc_refcount_init(&res->references, 1);
1348
1349 ISC_LINK_INIT(res, link);
1350 ISC_LINK_INIT(res, alink);
1351 ISC_LINK_INIT(res, plink);
1352 ISC_LINK_INIT(res, rlink);
1353
1354 if (disp->socktype == isc_socktype_udp) {
1355 isc_result_t result = setup_socket(disp, res, dest, &localport);
1356 if (result != ISC_R_SUCCESS) {
1357 isc_mem_put(disp->mgr->mctx, res, sizeof(*res));
1358 UNLOCK(&disp->lock);
1359 inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
1360 return (result);
1361 }
1362 }
1363
1364 /*
1365 * Try somewhat hard to find a unique ID. Start with
1366 * a random number unless DNS_DISPATCHOPT_FIXEDID is set,
1367 * in which case we start with the ID passed in via *idp.
1368 */
1369 if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) {
1370 id = *idp;
1371 } else {
1372 id = (dns_messageid_t)isc_random16();
1373 }
1374
1375 LOCK(&qid->lock);
1376 do {
1377 dns_dispentry_t *entry = NULL;
1378 bucket = dns_hash(qid, dest, id, localport);
1379 entry = entry_search(qid, dest, id, localport, bucket);
1380 if (entry == NULL) {
1381 ok = true;
1382 break;
1383 }
1384 id += qid->qid_increment;
1385 id &= 0x0000ffff;
1386 } while (i++ < 64);
1387 UNLOCK(&qid->lock);
1388
1389 if (!ok) {
1390 isc_mem_put(disp->mgr->mctx, res, sizeof(*res));
1391 UNLOCK(&disp->lock);
1392 return (ISC_R_NOMORE);
1393 }
1394
1395 dns_dispatch_attach(disp, &res->disp);
1396
1397 res->id = id;
1398 res->bucket = bucket;
1399 res->magic = RESPONSE_MAGIC;
1400
1401 disp->requests++;
1402
1403 LOCK(&qid->lock);
1404 ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
1405 UNLOCK(&qid->lock);
1406
1407 inc_stats(disp->mgr, (disp->socktype == isc_socktype_udp)
1408 ? dns_resstatscounter_disprequdp
1409 : dns_resstatscounter_dispreqtcp);
1410
1411 ISC_LIST_APPEND(disp->active, res, alink);
1412
1413 UNLOCK(&disp->lock);
1414
1415 if (oldest_response != NULL) {
1416 oldest_response(ISC_R_CANCELED, NULL, res->arg);
1417 }
1418
1419 *idp = id;
1420 *resp = res;
1421
1422 return (ISC_R_SUCCESS);
1423 }
1424
1425 void
dispatch_getnext(dns_dispatch_t * disp,dns_dispentry_t * resp,int32_t timeout)1426 dispatch_getnext(dns_dispatch_t *disp, dns_dispentry_t *resp, int32_t timeout) {
1427 REQUIRE(timeout <= UINT16_MAX);
1428
1429 switch (disp->socktype) {
1430 case isc_socktype_udp:
1431 dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
1432 if (timeout > 0) {
1433 isc_nmhandle_settimeout(resp->handle, timeout);
1434 }
1435 isc_nm_read(resp->handle, udp_recv, resp);
1436 break;
1437
1438 case isc_socktype_tcp:
1439 dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL });
1440 if (timeout > 0) {
1441 isc_nmhandle_settimeout(disp->handle, timeout);
1442 }
1443 isc_nm_read(disp->handle, tcp_recv, disp);
1444 break;
1445
1446 default:
1447 INSIST(0);
1448 ISC_UNREACHABLE();
1449 }
1450 }
1451
1452 isc_result_t
dns_dispatch_getnext(dns_dispentry_t * resp)1453 dns_dispatch_getnext(dns_dispentry_t *resp) {
1454 dns_dispatch_t *disp = NULL;
1455 int32_t timeout;
1456
1457 REQUIRE(VALID_RESPONSE(resp));
1458
1459 disp = resp->disp;
1460
1461 REQUIRE(VALID_DISPATCH(disp));
1462
1463 if (disp->socktype == isc_socktype_udp) {
1464 timeout = resp->timeout - dispentry_runtime(resp);
1465 if (timeout <= 0) {
1466 return (ISC_R_TIMEDOUT);
1467 }
1468 } else {
1469 timeout = -1;
1470 }
1471
1472 LOCK(&disp->lock);
1473 dispatch_getnext(disp, resp, timeout);
1474 UNLOCK(&disp->lock);
1475 return (ISC_R_SUCCESS);
1476 }
1477
1478 void
dns_dispatch_cancel(dns_dispentry_t ** respp)1479 dns_dispatch_cancel(dns_dispentry_t **respp) {
1480 dns_dispentry_t *resp = NULL;
1481
1482 REQUIRE(respp != NULL);
1483
1484 resp = *respp;
1485 *respp = NULL;
1486
1487 REQUIRE(VALID_RESPONSE(resp));
1488
1489 resp->canceled = true;
1490
1491 /* Connected UDP. */
1492 if (resp->handle != NULL) {
1493 isc_nm_cancelread(resp->handle);
1494 goto done;
1495 }
1496
1497 /* TCP pending connection. */
1498 if (ISC_LINK_LINKED(resp, plink)) {
1499 dns_dispentry_t *copy = resp;
1500
1501 ISC_LIST_UNLINK(resp->disp->pending, resp, plink);
1502 if (resp->connected != NULL) {
1503 resp->connected(ISC_R_CANCELED, NULL, resp->arg);
1504 }
1505
1506 /*
1507 * We need to detach twice if we were pending
1508 * connection - once to take the place of the
1509 * detach in tcp_connected() or udp_connected()
1510 * that we won't reach, and again later in
1511 * dns_dispatch_done().
1512 */
1513 dispentry_detach(©);
1514 goto done;
1515 }
1516
1517 /*
1518 * Connected TCP, or unconnected UDP.
1519 *
1520 * If TCP, we don't want to cancel the dispatch
1521 * unless this is the last resp waiting.
1522 */
1523 if (ISC_LINK_LINKED(resp, alink)) {
1524 ISC_LIST_UNLINK(resp->disp->active, resp, alink);
1525 if (ISC_LIST_EMPTY(resp->disp->active) &&
1526 resp->disp->handle != NULL) {
1527 isc_nm_cancelread(resp->disp->handle);
1528 } else if (resp->response != NULL) {
1529 resp->response(ISC_R_CANCELED, NULL, resp->arg);
1530 }
1531 }
1532
1533 done:
1534 dns_dispatch_done(&resp);
1535 }
1536
1537 void
dns_dispatch_done(dns_dispentry_t ** respp)1538 dns_dispatch_done(dns_dispentry_t **respp) {
1539 dns_dispatchmgr_t *mgr = NULL;
1540 dns_dispatch_t *disp = NULL;
1541 dns_dispentry_t *resp = NULL;
1542 dns_qid_t *qid = NULL;
1543
1544 REQUIRE(respp != NULL);
1545
1546 resp = *respp;
1547
1548 REQUIRE(VALID_RESPONSE(resp));
1549
1550 disp = resp->disp;
1551
1552 REQUIRE(VALID_DISPATCH(disp));
1553
1554 mgr = disp->mgr;
1555
1556 REQUIRE(VALID_DISPATCHMGR(mgr));
1557
1558 qid = mgr->qid;
1559
1560 LOCK(&disp->lock);
1561 INSIST(disp->requests > 0);
1562 disp->requests--;
1563
1564 dec_stats(disp->mgr, (disp->socktype == isc_socktype_udp)
1565 ? dns_resstatscounter_disprequdp
1566 : dns_resstatscounter_dispreqtcp);
1567
1568 deactivate_dispentry(disp, resp);
1569
1570 LOCK(&qid->lock);
1571 ISC_LIST_UNLINK(qid->qid_table[resp->bucket], resp, link);
1572 UNLOCK(&qid->lock);
1573 UNLOCK(&disp->lock);
1574
1575 dispentry_detach(respp);
1576 }
1577
1578 /*
1579 * disp must be locked.
1580 */
1581 static void
startrecv(isc_nmhandle_t * handle,dns_dispatch_t * disp,dns_dispentry_t * resp)1582 startrecv(isc_nmhandle_t *handle, dns_dispatch_t *disp, dns_dispentry_t *resp) {
1583 switch (disp->socktype) {
1584 case isc_socktype_udp:
1585 REQUIRE(resp != NULL && resp->handle == NULL);
1586
1587 TIME_NOW(&resp->start);
1588 isc_nmhandle_attach(handle, &resp->handle);
1589 dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
1590 isc_nm_read(resp->handle, udp_recv, resp);
1591 break;
1592
1593 case isc_socktype_tcp:
1594 REQUIRE(disp != NULL);
1595 LOCK(&disp->lock);
1596 REQUIRE(disp->handle == NULL);
1597
1598 isc_nmhandle_attach(handle, &disp->handle);
1599 dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL });
1600 isc_nm_read(disp->handle, tcp_recv, disp);
1601 UNLOCK(&disp->lock);
1602
1603 break;
1604
1605 default:
1606 INSIST(0);
1607 ISC_UNREACHABLE();
1608 }
1609 }
1610
1611 static void
tcp_connected(isc_nmhandle_t * handle,isc_result_t eresult,void * arg)1612 tcp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
1613 dns_dispatch_t *disp = (dns_dispatch_t *)arg;
1614 dns_dispentry_t *resp = NULL, *next = NULL;
1615 dns_displist_t resps;
1616
1617 dispatch_log(disp, LVL(90), "TCP connected (%p): %s", disp,
1618 isc_result_totext(eresult));
1619
1620 ISC_LIST_INIT(resps);
1621
1622 if (MGR_IS_SHUTTINGDOWN(disp->mgr)) {
1623 eresult = ISC_R_SHUTTINGDOWN;
1624 }
1625
1626 if (eresult == ISC_R_SUCCESS) {
1627 REQUIRE(atomic_compare_exchange_strong(
1628 &disp->state,
1629 &(uint_fast32_t){ DNS_DISPATCHSTATE_CONNECTING },
1630 DNS_DISPATCHSTATE_CONNECTED));
1631 startrecv(handle, disp, NULL);
1632 }
1633
1634 /*
1635 * If there are pending responses, call the connect
1636 * callbacks for all of them.
1637 */
1638 LOCK(&disp->lock);
1639 for (resp = ISC_LIST_HEAD(disp->pending); resp != NULL; resp = next) {
1640 next = ISC_LIST_NEXT(resp, plink);
1641 ISC_LIST_UNLINK(disp->pending, resp, plink);
1642 ISC_LIST_APPEND(resps, resp, plink);
1643 }
1644 UNLOCK(&disp->lock);
1645
1646 for (resp = ISC_LIST_HEAD(resps); resp != NULL; resp = next) {
1647 next = ISC_LIST_NEXT(resp, plink);
1648 ISC_LIST_UNLINK(resps, resp, plink);
1649
1650 if (resp->connected != NULL) {
1651 resp->connected(eresult, NULL, resp->arg);
1652 }
1653 dispentry_detach(&resp);
1654 }
1655
1656 dns_dispatch_detach(&disp);
1657 }
1658
1659 static void
udp_connected(isc_nmhandle_t * handle,isc_result_t eresult,void * arg)1660 udp_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
1661 dns_dispentry_t *resp = (dns_dispentry_t *)arg;
1662 dns_dispatch_t *disp = resp->disp;
1663
1664 dispatch_log(disp, LVL(90), "UDP connected (%p): %s", resp,
1665 isc_result_totext(eresult));
1666
1667 if (MGR_IS_SHUTTINGDOWN(disp->mgr)) {
1668 eresult = ISC_R_SHUTTINGDOWN;
1669 }
1670
1671 if (eresult == ISC_R_SUCCESS && resp->canceled) {
1672 eresult = ISC_R_CANCELED;
1673 } else if (eresult == ISC_R_SUCCESS) {
1674 startrecv(handle, disp, resp);
1675 } else if (eresult == ISC_R_ADDRINUSE) {
1676 in_port_t localport = 0;
1677 isc_result_t result;
1678
1679 /* probably a port collision; try a different one */
1680 disp->nsockets--;
1681 result = setup_socket(disp, resp, &resp->peer, &localport);
1682 if (result == ISC_R_SUCCESS) {
1683 dns_dispatch_connect(resp);
1684 goto detach;
1685 }
1686 }
1687
1688 if (resp->connected != NULL) {
1689 resp->connected(eresult, NULL, resp->arg);
1690 }
1691
1692 detach:
1693 dispentry_detach(&resp);
1694 }
1695
1696 isc_result_t
dns_dispatch_connect(dns_dispentry_t * resp)1697 dns_dispatch_connect(dns_dispentry_t *resp) {
1698 dns_dispatch_t *disp = NULL;
1699 uint_fast32_t state = DNS_DISPATCHSTATE_NONE;
1700
1701 REQUIRE(VALID_RESPONSE(resp));
1702
1703 disp = resp->disp;
1704
1705 /* This will be detached once we've connected. */
1706 dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
1707
1708 switch (disp->socktype) {
1709 case isc_socktype_tcp:
1710 /*
1711 * Check whether the dispatch is already connecting
1712 * or connected.
1713 */
1714 atomic_compare_exchange_strong(&disp->state,
1715 (uint_fast32_t *)&state,
1716 DNS_DISPATCHSTATE_CONNECTING);
1717 switch (state) {
1718 case DNS_DISPATCHSTATE_NONE:
1719 /* First connection, continue with connecting */
1720 LOCK(&disp->lock);
1721 INSIST(ISC_LIST_EMPTY(disp->pending));
1722 ISC_LIST_APPEND(disp->pending, resp, plink);
1723 UNLOCK(&disp->lock);
1724 dns_dispatch_attach(disp, &(dns_dispatch_t *){ NULL });
1725 isc_nm_tcpdnsconnect(disp->mgr->nm, &disp->local,
1726 &disp->peer, tcp_connected, disp,
1727 resp->timeout, 0);
1728 break;
1729
1730 case DNS_DISPATCHSTATE_CONNECTING:
1731 /* Connection pending; add resp to the list */
1732 LOCK(&disp->lock);
1733 ISC_LIST_APPEND(disp->pending, resp, plink);
1734 UNLOCK(&disp->lock);
1735 break;
1736
1737 case DNS_DISPATCHSTATE_CONNECTED:
1738 /* We are already connected; call the connected cb */
1739 if (resp->connected != NULL) {
1740 resp->connected(ISC_R_SUCCESS, NULL, resp->arg);
1741 }
1742 dispentry_detach(&resp);
1743 break;
1744
1745 default:
1746 INSIST(0);
1747 ISC_UNREACHABLE();
1748 }
1749
1750 break;
1751
1752 case isc_socktype_udp:
1753 isc_nm_udpconnect(disp->mgr->nm, &resp->local, &resp->peer,
1754 udp_connected, resp, resp->timeout, 0);
1755 break;
1756
1757 default:
1758 return (ISC_R_NOTIMPLEMENTED);
1759 }
1760
1761 return (ISC_R_SUCCESS);
1762 }
1763
1764 static void
send_done(isc_nmhandle_t * handle,isc_result_t result,void * cbarg)1765 send_done(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
1766 dns_dispentry_t *resp = (dns_dispentry_t *)cbarg;
1767
1768 REQUIRE(VALID_RESPONSE(resp));
1769
1770 resp->sent(result, NULL, resp->arg);
1771
1772 if (result != ISC_R_SUCCESS) {
1773 isc_nm_cancelread(handle);
1774 }
1775
1776 dispentry_detach(&resp);
1777 }
1778
1779 void
dns_dispatch_resume(dns_dispentry_t * resp,uint16_t timeout)1780 dns_dispatch_resume(dns_dispentry_t *resp, uint16_t timeout) {
1781 dns_dispatch_t *disp = NULL;
1782
1783 REQUIRE(VALID_RESPONSE(resp));
1784
1785 disp = resp->disp;
1786
1787 REQUIRE(VALID_DISPATCH(disp));
1788
1789 dispatch_getnext(disp, resp, timeout);
1790 }
1791
1792 void
dns_dispatch_send(dns_dispentry_t * resp,isc_region_t * r,isc_dscp_t dscp)1793 dns_dispatch_send(dns_dispentry_t *resp, isc_region_t *r, isc_dscp_t dscp) {
1794 isc_nmhandle_t *handle = NULL;
1795
1796 REQUIRE(VALID_RESPONSE(resp));
1797
1798 UNUSED(dscp);
1799
1800 #if 0
1801 /* XXX: no DSCP support */
1802 if (dscp == -1) {
1803 sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP;
1804 sendevent->dscp = 0;
1805 } else {
1806 sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP;
1807 sendevent->dscp = dscp;
1808 if (tcp) {
1809 isc_socket_dscp(sock, dscp);
1810 }
1811 }
1812 #endif
1813
1814 if (resp->disp->socktype == isc_socktype_tcp) {
1815 handle = resp->disp->handle;
1816 } else {
1817 handle = resp->handle;
1818 }
1819
1820 dispentry_attach(resp, &(dns_dispentry_t *){ NULL });
1821 isc_nm_send(handle, r, send_done, resp);
1822 }
1823
1824 isc_result_t
dns_dispatch_getlocaladdress(dns_dispatch_t * disp,isc_sockaddr_t * addrp)1825 dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
1826 REQUIRE(VALID_DISPATCH(disp));
1827 REQUIRE(addrp != NULL);
1828
1829 if (disp->socktype == isc_socktype_udp) {
1830 *addrp = disp->local;
1831 return (ISC_R_SUCCESS);
1832 }
1833 return (ISC_R_NOTIMPLEMENTED);
1834 }
1835
1836 isc_result_t
dns_dispentry_getlocaladdress(dns_dispentry_t * resp,isc_sockaddr_t * addrp)1837 dns_dispentry_getlocaladdress(dns_dispentry_t *resp, isc_sockaddr_t *addrp) {
1838 REQUIRE(VALID_RESPONSE(resp));
1839 REQUIRE(addrp != NULL);
1840
1841 if (resp->disp->socktype == isc_socktype_tcp) {
1842 *addrp = resp->disp->local;
1843 return (ISC_R_SUCCESS);
1844 }
1845
1846 if (resp->handle != NULL) {
1847 *addrp = isc_nmhandle_localaddr(resp->handle);
1848 return (ISC_R_SUCCESS);
1849 }
1850
1851 return (ISC_R_NOTIMPLEMENTED);
1852 }
1853
1854 dns_dispatch_t *
dns_dispatchset_get(dns_dispatchset_t * dset)1855 dns_dispatchset_get(dns_dispatchset_t *dset) {
1856 dns_dispatch_t *disp = NULL;
1857
1858 /* check that dispatch set is configured */
1859 if (dset == NULL || dset->ndisp == 0) {
1860 return (NULL);
1861 }
1862
1863 LOCK(&dset->lock);
1864 disp = dset->dispatches[dset->cur];
1865 dset->cur++;
1866 if (dset->cur == dset->ndisp) {
1867 dset->cur = 0;
1868 }
1869 UNLOCK(&dset->lock);
1870
1871 return (disp);
1872 }
1873
1874 isc_result_t
dns_dispatchset_create(isc_mem_t * mctx,dns_dispatch_t * source,dns_dispatchset_t ** dsetp,int n)1875 dns_dispatchset_create(isc_mem_t *mctx, dns_dispatch_t *source,
1876 dns_dispatchset_t **dsetp, int n) {
1877 isc_result_t result;
1878 dns_dispatchset_t *dset = NULL;
1879 dns_dispatchmgr_t *mgr = NULL;
1880 int i, j;
1881
1882 REQUIRE(VALID_DISPATCH(source));
1883 REQUIRE(source->socktype == isc_socktype_udp);
1884 REQUIRE(dsetp != NULL && *dsetp == NULL);
1885
1886 mgr = source->mgr;
1887
1888 dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t));
1889 *dset = (dns_dispatchset_t){ .ndisp = n };
1890
1891 isc_mutex_init(&dset->lock);
1892
1893 dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n);
1894
1895 isc_mem_attach(mctx, &dset->mctx);
1896
1897 dset->dispatches[0] = NULL;
1898 dns_dispatch_attach(source, &dset->dispatches[0]);
1899
1900 LOCK(&mgr->lock);
1901 for (i = 1; i < n; i++) {
1902 dset->dispatches[i] = NULL;
1903 result = dispatch_createudp(mgr, &source->local,
1904 &dset->dispatches[i]);
1905 if (result != ISC_R_SUCCESS) {
1906 goto fail;
1907 }
1908 }
1909
1910 UNLOCK(&mgr->lock);
1911 *dsetp = dset;
1912
1913 return (ISC_R_SUCCESS);
1914
1915 fail:
1916 UNLOCK(&mgr->lock);
1917
1918 for (j = 0; j < i; j++) {
1919 dns_dispatch_detach(&(dset->dispatches[j]));
1920 }
1921 isc_mem_put(mctx, dset->dispatches, sizeof(dns_dispatch_t *) * n);
1922 if (dset->mctx == mctx) {
1923 isc_mem_detach(&dset->mctx);
1924 }
1925
1926 isc_mutex_destroy(&dset->lock);
1927 isc_mem_put(mctx, dset, sizeof(dns_dispatchset_t));
1928 return (result);
1929 }
1930
1931 void
dns_dispatchset_destroy(dns_dispatchset_t ** dsetp)1932 dns_dispatchset_destroy(dns_dispatchset_t **dsetp) {
1933 dns_dispatchset_t *dset = NULL;
1934 int i;
1935
1936 REQUIRE(dsetp != NULL && *dsetp != NULL);
1937
1938 dset = *dsetp;
1939 *dsetp = NULL;
1940 for (i = 0; i < dset->ndisp; i++) {
1941 dns_dispatch_detach(&(dset->dispatches[i]));
1942 }
1943 isc_mem_put(dset->mctx, dset->dispatches,
1944 sizeof(dns_dispatch_t *) * dset->ndisp);
1945 isc_mutex_destroy(&dset->lock);
1946 isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t));
1947 }
1948