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(&copy);
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