xref: /netbsd-src/external/mpl/bind/dist/lib/dns/request.c (revision 0e2e28bced52bda3788c857106bde6c44d2df3b8)
1 /*	$NetBSD: request.c,v 1.9 2024/02/21 22:52:08 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 /*! \file */
17 
18 #include <inttypes.h>
19 #include <stdbool.h>
20 
21 #include <isc/magic.h>
22 #include <isc/mem.h>
23 #include <isc/netmgr.h>
24 #include <isc/result.h>
25 #include <isc/task.h>
26 #include <isc/thread.h>
27 #include <isc/util.h>
28 
29 #include <dns/acl.h>
30 #include <dns/compress.h>
31 #include <dns/dispatch.h>
32 #include <dns/events.h>
33 #include <dns/log.h>
34 #include <dns/message.h>
35 #include <dns/rdata.h>
36 #include <dns/rdatastruct.h>
37 #include <dns/request.h>
38 #include <dns/tsig.h>
39 
40 #define REQUESTMGR_MAGIC      ISC_MAGIC('R', 'q', 'u', 'M')
41 #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
42 
43 #define REQUEST_MAGIC	       ISC_MAGIC('R', 'q', 'u', '!')
44 #define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC)
45 
46 typedef ISC_LIST(dns_request_t) dns_requestlist_t;
47 
48 #define DNS_REQUEST_NLOCKS 7
49 
50 struct dns_requestmgr {
51 	unsigned int magic;
52 	isc_refcount_t references;
53 
54 	isc_mutex_t lock;
55 	isc_mem_t *mctx;
56 
57 	/* locked */
58 	isc_taskmgr_t *taskmgr;
59 	dns_dispatchmgr_t *dispatchmgr;
60 	dns_dispatch_t *dispatchv4;
61 	dns_dispatch_t *dispatchv6;
62 	atomic_bool exiting;
63 	isc_eventlist_t whenshutdown;
64 	unsigned int hash;
65 	isc_mutex_t locks[DNS_REQUEST_NLOCKS];
66 	dns_requestlist_t requests;
67 };
68 
69 struct dns_request {
70 	unsigned int magic;
71 	isc_refcount_t references;
72 
73 	unsigned int hash;
74 	isc_mem_t *mctx;
75 	int32_t flags;
76 	ISC_LINK(dns_request_t) link;
77 	isc_buffer_t *query;
78 	isc_buffer_t *answer;
79 	dns_requestevent_t *event;
80 	dns_dispatch_t *dispatch;
81 	dns_dispentry_t *dispentry;
82 	dns_requestmgr_t *requestmgr;
83 	isc_buffer_t *tsig;
84 	dns_tsigkey_t *tsigkey;
85 	isc_sockaddr_t destaddr;
86 	unsigned int timeout;
87 	unsigned int udpcount;
88 };
89 
90 #define DNS_REQUEST_F_CONNECTING 0x0001
91 #define DNS_REQUEST_F_SENDING	 0x0002
92 #define DNS_REQUEST_F_CANCELED	 0x0004
93 #define DNS_REQUEST_F_TCP	 0x0010
94 
95 #define DNS_REQUEST_CANCELED(r)	  (((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
96 #define DNS_REQUEST_CONNECTING(r) (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
97 #define DNS_REQUEST_SENDING(r)	  (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
98 
99 /***
100  *** Forward
101  ***/
102 
103 static void
104 mgr_destroy(dns_requestmgr_t *requestmgr);
105 static unsigned int
106 mgr_gethash(dns_requestmgr_t *requestmgr);
107 static void
108 send_shutdown_events(dns_requestmgr_t *requestmgr);
109 
110 static isc_result_t
111 req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options,
112 	   isc_mem_t *mctx);
113 static void
114 req_response(isc_result_t result, isc_region_t *region, void *arg);
115 static void
116 req_senddone(isc_result_t eresult, isc_region_t *region, void *arg);
117 static void
118 req_sendevent(dns_request_t *request, isc_result_t result);
119 static void
120 req_connected(isc_result_t eresult, isc_region_t *region, void *arg);
121 static void
122 req_attach(dns_request_t *source, dns_request_t **targetp);
123 static void
124 req_detach(dns_request_t **requestp);
125 static void
126 req_destroy(dns_request_t *request);
127 static void
128 req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
129 void
130 request_cancel(dns_request_t *request);
131 
132 /***
133  *** Public
134  ***/
135 
136 isc_result_t
137 dns_requestmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
138 		      dns_dispatchmgr_t *dispatchmgr,
139 		      dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
140 		      dns_requestmgr_t **requestmgrp) {
141 	dns_requestmgr_t *requestmgr;
142 	int i;
143 
144 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
145 
146 	REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
147 	REQUIRE(taskmgr != NULL);
148 	REQUIRE(dispatchmgr != NULL);
149 
150 	requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
151 	*requestmgr = (dns_requestmgr_t){ 0 };
152 
153 	isc_taskmgr_attach(taskmgr, &requestmgr->taskmgr);
154 	dns_dispatchmgr_attach(dispatchmgr, &requestmgr->dispatchmgr);
155 	isc_mutex_init(&requestmgr->lock);
156 
157 	for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
158 		isc_mutex_init(&requestmgr->locks[i]);
159 	}
160 	if (dispatchv4 != NULL) {
161 		dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
162 	}
163 	if (dispatchv6 != NULL) {
164 		dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
165 	}
166 	isc_mem_attach(mctx, &requestmgr->mctx);
167 
168 	isc_refcount_init(&requestmgr->references, 1);
169 
170 	ISC_LIST_INIT(requestmgr->whenshutdown);
171 	ISC_LIST_INIT(requestmgr->requests);
172 
173 	atomic_init(&requestmgr->exiting, false);
174 
175 	requestmgr->magic = REQUESTMGR_MAGIC;
176 
177 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
178 
179 	*requestmgrp = requestmgr;
180 	return (ISC_R_SUCCESS);
181 }
182 
183 void
184 dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
185 			    isc_event_t **eventp) {
186 	isc_task_t *tclone;
187 	isc_event_t *event;
188 
189 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
190 
191 	REQUIRE(VALID_REQUESTMGR(requestmgr));
192 	REQUIRE(eventp != NULL);
193 
194 	event = *eventp;
195 	*eventp = NULL;
196 
197 	LOCK(&requestmgr->lock);
198 
199 	if (atomic_load_acquire(&requestmgr->exiting)) {
200 		/*
201 		 * We're already shutdown.  Send the event.
202 		 */
203 		event->ev_sender = requestmgr;
204 		isc_task_send(task, &event);
205 	} else {
206 		tclone = NULL;
207 		isc_task_attach(task, &tclone);
208 		event->ev_sender = tclone;
209 		ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
210 	}
211 	UNLOCK(&requestmgr->lock);
212 }
213 
214 void
215 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
216 	dns_request_t *request;
217 
218 	REQUIRE(VALID_REQUESTMGR(requestmgr));
219 
220 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
221 
222 	if (!atomic_compare_exchange_strong(&requestmgr->exiting,
223 					    &(bool){ false }, true))
224 	{
225 		return;
226 	}
227 
228 	LOCK(&requestmgr->lock);
229 	for (request = ISC_LIST_HEAD(requestmgr->requests); request != NULL;
230 	     request = ISC_LIST_NEXT(request, link))
231 	{
232 		dns_request_cancel(request);
233 	}
234 
235 	if (ISC_LIST_EMPTY(requestmgr->requests)) {
236 		send_shutdown_events(requestmgr);
237 	}
238 
239 	UNLOCK(&requestmgr->lock);
240 }
241 
242 void
243 dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
244 	uint_fast32_t ref;
245 
246 	REQUIRE(VALID_REQUESTMGR(source));
247 	REQUIRE(targetp != NULL && *targetp == NULL);
248 
249 	REQUIRE(!atomic_load_acquire(&source->exiting));
250 
251 	ref = isc_refcount_increment(&source->references);
252 
253 	req_log(ISC_LOG_DEBUG(3),
254 		"dns_requestmgr_attach: %p: references = %" PRIuFAST32, source,
255 		ref + 1);
256 
257 	*targetp = source;
258 }
259 
260 void
261 dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
262 	dns_requestmgr_t *requestmgr = NULL;
263 	uint_fast32_t ref;
264 
265 	REQUIRE(requestmgrp != NULL && VALID_REQUESTMGR(*requestmgrp));
266 
267 	requestmgr = *requestmgrp;
268 	*requestmgrp = NULL;
269 
270 	ref = isc_refcount_decrement(&requestmgr->references);
271 
272 	req_log(ISC_LOG_DEBUG(3),
273 		"dns_requestmgr_detach: %p: references = %" PRIuFAST32,
274 		requestmgr, ref - 1);
275 
276 	if (ref == 1) {
277 		INSIST(ISC_LIST_EMPTY(requestmgr->requests));
278 		mgr_destroy(requestmgr);
279 	}
280 }
281 
282 /* FIXME */
283 static void
284 send_shutdown_events(dns_requestmgr_t *requestmgr) {
285 	isc_event_t *event, *next_event;
286 	isc_task_t *etask;
287 
288 	req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
289 
290 	/*
291 	 * Caller must be holding the manager lock.
292 	 */
293 	for (event = ISC_LIST_HEAD(requestmgr->whenshutdown); event != NULL;
294 	     event = next_event)
295 	{
296 		next_event = ISC_LIST_NEXT(event, ev_link);
297 		ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
298 		etask = event->ev_sender;
299 		event->ev_sender = requestmgr;
300 		isc_task_sendanddetach(&etask, &event);
301 	}
302 }
303 
304 static void
305 mgr_destroy(dns_requestmgr_t *requestmgr) {
306 	int i;
307 
308 	req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
309 
310 	isc_refcount_destroy(&requestmgr->references);
311 
312 	isc_mutex_destroy(&requestmgr->lock);
313 	for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
314 		isc_mutex_destroy(&requestmgr->locks[i]);
315 	}
316 	if (requestmgr->dispatchv4 != NULL) {
317 		dns_dispatch_detach(&requestmgr->dispatchv4);
318 	}
319 	if (requestmgr->dispatchv6 != NULL) {
320 		dns_dispatch_detach(&requestmgr->dispatchv6);
321 	}
322 	if (requestmgr->dispatchmgr != NULL) {
323 		dns_dispatchmgr_detach(&requestmgr->dispatchmgr);
324 	}
325 	if (requestmgr->taskmgr != NULL) {
326 		isc_taskmgr_detach(&requestmgr->taskmgr);
327 	}
328 	requestmgr->magic = 0;
329 	isc_mem_putanddetach(&requestmgr->mctx, requestmgr,
330 			     sizeof(*requestmgr));
331 }
332 
333 static unsigned int
334 mgr_gethash(dns_requestmgr_t *requestmgr) {
335 	req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
336 	/*
337 	 * Locked by caller.
338 	 */
339 	requestmgr->hash++;
340 	return (requestmgr->hash % DNS_REQUEST_NLOCKS);
341 }
342 
343 static void
344 req_send(dns_request_t *request) {
345 	isc_region_t r;
346 
347 	req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
348 
349 	REQUIRE(VALID_REQUEST(request));
350 
351 	isc_buffer_usedregion(request->query, &r);
352 
353 	request->flags |= DNS_REQUEST_F_SENDING;
354 
355 	/* detached in req_senddone() */
356 	req_attach(request, &(dns_request_t *){ NULL });
357 	dns_dispatch_send(request->dispentry, &r);
358 }
359 
360 static isc_result_t
361 new_request(isc_mem_t *mctx, dns_request_t **requestp) {
362 	dns_request_t *request = NULL;
363 
364 	request = isc_mem_get(mctx, sizeof(*request));
365 	*request = (dns_request_t){ 0 };
366 	ISC_LINK_INIT(request, link);
367 
368 	isc_refcount_init(&request->references, 1);
369 	isc_mem_attach(mctx, &request->mctx);
370 
371 	request->magic = REQUEST_MAGIC;
372 	*requestp = request;
373 	return (ISC_R_SUCCESS);
374 }
375 
376 static bool
377 isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) {
378 	dns_acl_t *blackhole;
379 	isc_netaddr_t netaddr;
380 	char netaddrstr[ISC_NETADDR_FORMATSIZE];
381 	int match;
382 	isc_result_t result;
383 
384 	blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
385 	if (blackhole == NULL) {
386 		return (false);
387 	}
388 
389 	isc_netaddr_fromsockaddr(&netaddr, destaddr);
390 	result = dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, NULL);
391 	if (result != ISC_R_SUCCESS || match <= 0) {
392 		return (false);
393 	}
394 
395 	isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
396 	req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
397 
398 	return (true);
399 }
400 
401 static isc_result_t
402 tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
403 	     const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
404 	     dns_dispatch_t **dispatchp) {
405 	isc_result_t result;
406 
407 	if (!newtcp) {
408 		result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
409 					     srcaddr, dispatchp);
410 		if (result == ISC_R_SUCCESS) {
411 			char peer[ISC_SOCKADDR_FORMATSIZE];
412 
413 			isc_sockaddr_format(destaddr, peer, sizeof(peer));
414 			req_log(ISC_LOG_DEBUG(1),
415 				"attached to TCP connection to %s", peer);
416 			return (result);
417 		}
418 	}
419 
420 	result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
421 					destaddr, dispatchp);
422 	return (result);
423 }
424 
425 static isc_result_t
426 udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
427 	     const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) {
428 	dns_dispatch_t *disp = NULL;
429 
430 	if (srcaddr == NULL) {
431 		switch (isc_sockaddr_pf(destaddr)) {
432 		case PF_INET:
433 			disp = requestmgr->dispatchv4;
434 			break;
435 
436 		case PF_INET6:
437 			disp = requestmgr->dispatchv6;
438 			break;
439 
440 		default:
441 			return (ISC_R_NOTIMPLEMENTED);
442 		}
443 		if (disp == NULL) {
444 			return (ISC_R_FAMILYNOSUPPORT);
445 		}
446 		dns_dispatch_attach(disp, dispatchp);
447 		return (ISC_R_SUCCESS);
448 	}
449 
450 	return (dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr,
451 				       dispatchp));
452 }
453 
454 static isc_result_t
455 get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr,
456 	     const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
457 	     dns_dispatch_t **dispatchp) {
458 	isc_result_t result;
459 
460 	if (tcp) {
461 		result = tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr,
462 				      dispatchp);
463 	} else {
464 		result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp);
465 	}
466 	return (result);
467 }
468 
469 isc_result_t
470 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
471 		      const isc_sockaddr_t *srcaddr,
472 		      const isc_sockaddr_t *destaddr, unsigned int options,
473 		      unsigned int timeout, unsigned int udptimeout,
474 		      unsigned int udpretries, isc_task_t *task,
475 		      isc_taskaction_t action, void *arg,
476 		      dns_request_t **requestp) {
477 	dns_request_t *request = NULL;
478 	isc_result_t result;
479 	isc_mem_t *mctx = NULL;
480 	dns_messageid_t id;
481 	bool tcp = false;
482 	bool newtcp = false;
483 	isc_region_t r;
484 	unsigned int dispopt = 0;
485 
486 	REQUIRE(VALID_REQUESTMGR(requestmgr));
487 	REQUIRE(msgbuf != NULL);
488 	REQUIRE(destaddr != NULL);
489 	REQUIRE(task != NULL);
490 	REQUIRE(action != NULL);
491 	REQUIRE(requestp != NULL && *requestp == NULL);
492 	REQUIRE(timeout > 0);
493 	REQUIRE(udpretries != UINT_MAX);
494 
495 	if (srcaddr != NULL) {
496 		REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
497 	}
498 
499 	mctx = requestmgr->mctx;
500 
501 	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
502 
503 	if (atomic_load_acquire(&requestmgr->exiting)) {
504 		return (ISC_R_SHUTTINGDOWN);
505 	}
506 
507 	if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
508 		return (DNS_R_BLACKHOLED);
509 	}
510 
511 	/* detached in dns_request_destroy() */
512 	result = new_request(mctx, &request);
513 	if (result != ISC_R_SUCCESS) {
514 		return (result);
515 	}
516 
517 	request->udpcount = udpretries + 1;
518 
519 	request->event = (dns_requestevent_t *)isc_event_allocate(
520 		mctx, task, DNS_EVENT_REQUESTDONE, action, arg,
521 		sizeof(dns_requestevent_t));
522 	isc_task_attach(task, &(isc_task_t *){ NULL });
523 	request->event->ev_sender = task;
524 	request->event->request = request;
525 	request->event->result = ISC_R_FAILURE;
526 
527 	isc_buffer_usedregion(msgbuf, &r);
528 	if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
529 		result = DNS_R_FORMERR;
530 		goto cleanup;
531 	}
532 
533 	if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) {
534 		tcp = true;
535 		request->timeout = timeout * 1000;
536 	} else {
537 		if (udptimeout == 0) {
538 			udptimeout = timeout / request->udpcount;
539 		}
540 		if (udptimeout == 0) {
541 			udptimeout = 1;
542 		}
543 		request->timeout = udptimeout * 1000;
544 	}
545 
546 	isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0));
547 	result = isc_buffer_copyregion(request->query, &r);
548 	if (result != ISC_R_SUCCESS) {
549 		goto cleanup;
550 	}
551 
552 	/* detached in req_connected() */
553 	req_attach(request, &(dns_request_t *){ NULL });
554 
555 again:
556 
557 	result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr,
558 			      &request->dispatch);
559 	if (result != ISC_R_SUCCESS) {
560 		goto detach;
561 	}
562 
563 	if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
564 		id = (r.base[0] << 8) | r.base[1];
565 		dispopt |= DNS_DISPATCHOPT_FIXEDID;
566 	}
567 
568 	result = dns_dispatch_add(request->dispatch, dispopt, request->timeout,
569 				  destaddr, req_connected, req_senddone,
570 				  req_response, request, &id,
571 				  &request->dispentry);
572 	if (result != ISC_R_SUCCESS) {
573 		if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
574 			newtcp = true;
575 			dns_dispatch_detach(&request->dispatch);
576 			goto again;
577 		}
578 
579 		goto detach;
580 	}
581 
582 	/* Add message ID. */
583 	isc_buffer_usedregion(request->query, &r);
584 	r.base[0] = (id >> 8) & 0xff;
585 	r.base[1] = id & 0xff;
586 
587 	LOCK(&requestmgr->lock);
588 	dns_requestmgr_attach(requestmgr, &request->requestmgr);
589 	request->hash = mgr_gethash(requestmgr);
590 	ISC_LIST_APPEND(requestmgr->requests, request, link);
591 	UNLOCK(&requestmgr->lock);
592 
593 	request->destaddr = *destaddr;
594 
595 	request->flags |= DNS_REQUEST_F_CONNECTING;
596 	if (tcp) {
597 		request->flags |= DNS_REQUEST_F_TCP;
598 	}
599 
600 	result = dns_dispatch_connect(request->dispentry);
601 	if (result != ISC_R_SUCCESS) {
602 		goto unlink;
603 	}
604 
605 	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request);
606 	*requestp = request;
607 	return (ISC_R_SUCCESS);
608 
609 unlink:
610 	LOCK(&requestmgr->lock);
611 	ISC_LIST_UNLINK(requestmgr->requests, request, link);
612 	UNLOCK(&requestmgr->lock);
613 
614 detach:
615 	/* connect failed, detach here */
616 	req_detach(&(dns_request_t *){ request });
617 
618 cleanup:
619 	isc_task_detach(&(isc_task_t *){ task });
620 	/* final detach to shut down request */
621 	req_detach(&request);
622 	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
623 		isc_result_totext(result));
624 	return (result);
625 }
626 
627 isc_result_t
628 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
629 		   const isc_sockaddr_t *srcaddr,
630 		   const isc_sockaddr_t *destaddr, unsigned int options,
631 		   dns_tsigkey_t *key, unsigned int timeout,
632 		   unsigned int udptimeout, unsigned int udpretries,
633 		   isc_task_t *task, isc_taskaction_t action, void *arg,
634 		   dns_request_t **requestp) {
635 	dns_request_t *request = NULL;
636 	isc_result_t result;
637 	isc_mem_t *mctx = NULL;
638 	dns_messageid_t id;
639 	bool tcp = false;
640 	bool connected = false;
641 
642 	REQUIRE(VALID_REQUESTMGR(requestmgr));
643 	REQUIRE(message != NULL);
644 	REQUIRE(destaddr != NULL);
645 	REQUIRE(task != NULL);
646 	REQUIRE(action != NULL);
647 	REQUIRE(requestp != NULL && *requestp == NULL);
648 	REQUIRE(timeout > 0);
649 	REQUIRE(udpretries != UINT_MAX);
650 
651 	mctx = requestmgr->mctx;
652 
653 	req_log(ISC_LOG_DEBUG(3), "dns_request_create");
654 
655 	if (atomic_load_acquire(&requestmgr->exiting)) {
656 		return (ISC_R_SHUTTINGDOWN);
657 	}
658 
659 	if (srcaddr != NULL &&
660 	    isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
661 	{
662 		return (ISC_R_FAMILYMISMATCH);
663 	}
664 
665 	if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
666 		return (DNS_R_BLACKHOLED);
667 	}
668 
669 	/* detached in dns_request_destroy() */
670 	result = new_request(mctx, &request);
671 	if (result != ISC_R_SUCCESS) {
672 		return (result);
673 	}
674 
675 	request->udpcount = udpretries + 1;
676 
677 	request->event = (dns_requestevent_t *)isc_event_allocate(
678 		mctx, task, DNS_EVENT_REQUESTDONE, action, arg,
679 		sizeof(dns_requestevent_t));
680 	isc_task_attach(task, &(isc_task_t *){ NULL });
681 	request->event->ev_sender = task;
682 	request->event->request = request;
683 	request->event->result = ISC_R_FAILURE;
684 
685 	if (key != NULL) {
686 		dns_tsigkey_attach(key, &request->tsigkey);
687 	}
688 
689 	result = dns_message_settsigkey(message, request->tsigkey);
690 	if (result != ISC_R_SUCCESS) {
691 		goto cleanup;
692 	}
693 
694 	if ((options & DNS_REQUESTOPT_TCP) != 0) {
695 		tcp = true;
696 		request->timeout = timeout * 1000;
697 	} else {
698 		if (udptimeout == 0) {
699 			udptimeout = timeout / request->udpcount;
700 		}
701 		if (udptimeout == 0) {
702 			udptimeout = 1;
703 		}
704 		request->timeout = udptimeout * 1000;
705 	}
706 
707 	/* detached in req_connected() */
708 	req_attach(request, &(dns_request_t *){ NULL });
709 
710 again:
711 	result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr,
712 			      &request->dispatch);
713 	if (result != ISC_R_SUCCESS) {
714 		goto detach;
715 	}
716 
717 	result = dns_dispatch_add(
718 		request->dispatch, 0, request->timeout, destaddr, req_connected,
719 		req_senddone, req_response, request, &id, &request->dispentry);
720 	if (result != ISC_R_SUCCESS) {
721 		goto detach;
722 	}
723 
724 	message->id = id;
725 	result = req_render(message, &request->query, options, mctx);
726 	if (result == DNS_R_USETCP && !tcp) {
727 		/*
728 		 * Try again using TCP.
729 		 */
730 		dns_message_renderreset(message);
731 		dns_dispatch_done(&request->dispentry);
732 		dns_dispatch_detach(&request->dispatch);
733 		options |= DNS_REQUESTOPT_TCP;
734 		tcp = true;
735 		goto again;
736 	}
737 	if (result != ISC_R_SUCCESS) {
738 		goto detach;
739 	}
740 
741 	result = dns_message_getquerytsig(message, mctx, &request->tsig);
742 	if (result != ISC_R_SUCCESS) {
743 		goto detach;
744 	}
745 
746 	LOCK(&requestmgr->lock);
747 	dns_requestmgr_attach(requestmgr, &request->requestmgr);
748 	request->hash = mgr_gethash(requestmgr);
749 	ISC_LIST_APPEND(requestmgr->requests, request, link);
750 	UNLOCK(&requestmgr->lock);
751 
752 	request->destaddr = *destaddr;
753 	if (tcp && connected) {
754 		req_send(request);
755 
756 		/* no need to call req_connected(), detach here */
757 		req_detach(&(dns_request_t *){ request });
758 	} else {
759 		request->flags |= DNS_REQUEST_F_CONNECTING;
760 		if (tcp) {
761 			request->flags |= DNS_REQUEST_F_TCP;
762 		}
763 
764 		result = dns_dispatch_connect(request->dispentry);
765 		if (result != ISC_R_SUCCESS) {
766 			goto unlink;
767 		}
768 	}
769 
770 	req_log(ISC_LOG_DEBUG(3), "dns_request_create: request %p", request);
771 	*requestp = request;
772 	return (ISC_R_SUCCESS);
773 
774 unlink:
775 	LOCK(&requestmgr->lock);
776 	ISC_LIST_UNLINK(requestmgr->requests, request, link);
777 	UNLOCK(&requestmgr->lock);
778 
779 detach:
780 	/* connect failed, detach here */
781 	req_detach(&(dns_request_t *){ request });
782 
783 cleanup:
784 	isc_task_detach(&(isc_task_t *){ task });
785 	/* final detach to shut down request */
786 	req_detach(&request);
787 	req_log(ISC_LOG_DEBUG(3), "dns_request_create: failed %s",
788 		isc_result_totext(result));
789 	return (result);
790 }
791 
792 static isc_result_t
793 req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options,
794 	   isc_mem_t *mctx) {
795 	isc_buffer_t *buf1 = NULL;
796 	isc_buffer_t *buf2 = NULL;
797 	isc_result_t result;
798 	isc_region_t r;
799 	dns_compress_t cctx;
800 	bool cleanup_cctx = false;
801 
802 	REQUIRE(bufferp != NULL && *bufferp == NULL);
803 
804 	req_log(ISC_LOG_DEBUG(3), "request_render");
805 
806 	/*
807 	 * Create buffer able to hold largest possible message.
808 	 */
809 	isc_buffer_allocate(mctx, &buf1, 65535);
810 
811 	result = dns_compress_init(&cctx, -1, mctx);
812 	if (result != ISC_R_SUCCESS) {
813 		return (result);
814 	}
815 	cleanup_cctx = true;
816 
817 	if ((options & DNS_REQUESTOPT_CASE) != 0) {
818 		dns_compress_setsensitive(&cctx, true);
819 	}
820 
821 	/*
822 	 * Render message.
823 	 */
824 	result = dns_message_renderbegin(message, &cctx, buf1);
825 	if (result != ISC_R_SUCCESS) {
826 		goto cleanup;
827 	}
828 	result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
829 	if (result != ISC_R_SUCCESS) {
830 		goto cleanup;
831 	}
832 	result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
833 	if (result != ISC_R_SUCCESS) {
834 		goto cleanup;
835 	}
836 	result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
837 	if (result != ISC_R_SUCCESS) {
838 		goto cleanup;
839 	}
840 	result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
841 	if (result != ISC_R_SUCCESS) {
842 		goto cleanup;
843 	}
844 	result = dns_message_renderend(message);
845 	if (result != ISC_R_SUCCESS) {
846 		goto cleanup;
847 	}
848 
849 	dns_compress_invalidate(&cctx);
850 	cleanup_cctx = false;
851 
852 	/*
853 	 * Copy rendered message to exact sized buffer.
854 	 */
855 	isc_buffer_usedregion(buf1, &r);
856 	if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) {
857 		result = DNS_R_USETCP;
858 		goto cleanup;
859 	}
860 	isc_buffer_allocate(mctx, &buf2, r.length);
861 	result = isc_buffer_copyregion(buf2, &r);
862 	if (result != ISC_R_SUCCESS) {
863 		goto cleanup;
864 	}
865 
866 	/*
867 	 * Cleanup and return.
868 	 */
869 	isc_buffer_free(&buf1);
870 	*bufferp = buf2;
871 	return (ISC_R_SUCCESS);
872 
873 cleanup:
874 	dns_message_renderreset(message);
875 	if (buf1 != NULL) {
876 		isc_buffer_free(&buf1);
877 	}
878 	if (buf2 != NULL) {
879 		isc_buffer_free(&buf2);
880 	}
881 	if (cleanup_cctx) {
882 		dns_compress_invalidate(&cctx);
883 	}
884 	return (result);
885 }
886 
887 void
888 request_cancel(dns_request_t *request) {
889 	if (!DNS_REQUEST_CANCELED(request)) {
890 		req_log(ISC_LOG_DEBUG(3), "request_cancel: request %p",
891 			request);
892 
893 		request->flags |= DNS_REQUEST_F_CANCELED;
894 		request->flags &= ~DNS_REQUEST_F_CONNECTING;
895 
896 		if (request->dispentry != NULL) {
897 			dns_dispatch_done(&request->dispentry);
898 		}
899 
900 		dns_dispatch_detach(&request->dispatch);
901 	}
902 }
903 
904 void
905 dns_request_cancel(dns_request_t *request) {
906 	REQUIRE(VALID_REQUEST(request));
907 
908 	req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
909 	LOCK(&request->requestmgr->locks[request->hash]);
910 	request_cancel(request);
911 	req_sendevent(request, ISC_R_CANCELED);
912 	UNLOCK(&request->requestmgr->locks[request->hash]);
913 }
914 
915 isc_result_t
916 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
917 			unsigned int options) {
918 	isc_result_t result;
919 
920 	REQUIRE(VALID_REQUEST(request));
921 	REQUIRE(request->answer != NULL);
922 
923 	req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
924 		request);
925 
926 	result = dns_message_setquerytsig(message, request->tsig);
927 	if (result != ISC_R_SUCCESS) {
928 		return (result);
929 	}
930 	result = dns_message_settsigkey(message, request->tsigkey);
931 	if (result != ISC_R_SUCCESS) {
932 		return (result);
933 	}
934 	result = dns_message_parse(message, request->answer, options);
935 	if (result != ISC_R_SUCCESS) {
936 		return (result);
937 	}
938 	if (request->tsigkey != NULL) {
939 		result = dns_tsig_verify(request->answer, message, NULL, NULL);
940 	}
941 	return (result);
942 }
943 
944 isc_buffer_t *
945 dns_request_getanswer(dns_request_t *request) {
946 	REQUIRE(VALID_REQUEST(request));
947 
948 	return (request->answer);
949 }
950 
951 bool
952 dns_request_usedtcp(dns_request_t *request) {
953 	REQUIRE(VALID_REQUEST(request));
954 
955 	return ((request->flags & DNS_REQUEST_F_TCP) != 0);
956 }
957 
958 void
959 dns_request_destroy(dns_request_t **requestp) {
960 	dns_request_t *request;
961 
962 	REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
963 
964 	request = *requestp;
965 	*requestp = NULL;
966 
967 	req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
968 
969 	LOCK(&request->requestmgr->lock);
970 	LOCK(&request->requestmgr->locks[request->hash]);
971 	ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
972 	UNLOCK(&request->requestmgr->locks[request->hash]);
973 	UNLOCK(&request->requestmgr->lock);
974 
975 	/*
976 	 * These should have been cleaned up before the completion
977 	 * event was sent.
978 	 */
979 	INSIST(request->dispentry == NULL);
980 	INSIST(request->dispatch == NULL);
981 
982 	/* final detach to shut down request */
983 	req_detach(&request);
984 }
985 
986 static void
987 req_connected(isc_result_t eresult, isc_region_t *region, void *arg) {
988 	dns_request_t *request = (dns_request_t *)arg;
989 
990 	UNUSED(region);
991 
992 	req_log(ISC_LOG_DEBUG(3), "req_connected: request %p: %s", request,
993 		isc_result_totext(eresult));
994 
995 	REQUIRE(VALID_REQUEST(request));
996 	REQUIRE(DNS_REQUEST_CONNECTING(request) ||
997 		DNS_REQUEST_CANCELED(request));
998 
999 	LOCK(&request->requestmgr->locks[request->hash]);
1000 	request->flags &= ~DNS_REQUEST_F_CONNECTING;
1001 
1002 	if (eresult == ISC_R_TIMEDOUT) {
1003 		dns_dispatch_done(&request->dispentry);
1004 		dns_dispatch_detach(&request->dispatch);
1005 		req_sendevent(request, eresult);
1006 	} else if (DNS_REQUEST_CANCELED(request)) {
1007 		req_sendevent(request, ISC_R_CANCELED);
1008 	} else if (eresult == ISC_R_SUCCESS) {
1009 		req_send(request);
1010 	} else {
1011 		request_cancel(request);
1012 		req_sendevent(request, ISC_R_CANCELED);
1013 	}
1014 	UNLOCK(&request->requestmgr->locks[request->hash]);
1015 
1016 	/* attached in dns_request_create/_createraw() */
1017 	req_detach(&(dns_request_t *){ request });
1018 }
1019 
1020 static void
1021 req_senddone(isc_result_t eresult, isc_region_t *region, void *arg) {
1022 	dns_request_t *request = (dns_request_t *)arg;
1023 
1024 	REQUIRE(VALID_REQUEST(request));
1025 	REQUIRE(DNS_REQUEST_SENDING(request));
1026 
1027 	UNUSED(region);
1028 
1029 	req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1030 
1031 	LOCK(&request->requestmgr->locks[request->hash]);
1032 	request->flags &= ~DNS_REQUEST_F_SENDING;
1033 
1034 	if (DNS_REQUEST_CANCELED(request)) {
1035 		if (eresult == ISC_R_TIMEDOUT) {
1036 			req_sendevent(request, eresult);
1037 		} else {
1038 			req_sendevent(request, ISC_R_CANCELED);
1039 		}
1040 	} else if (eresult != ISC_R_SUCCESS) {
1041 		request_cancel(request);
1042 		req_sendevent(request, ISC_R_CANCELED);
1043 	}
1044 
1045 	UNLOCK(&request->requestmgr->locks[request->hash]);
1046 
1047 	/* attached in req_send() */
1048 	req_detach(&request);
1049 }
1050 
1051 static void
1052 req_response(isc_result_t result, isc_region_t *region, void *arg) {
1053 	dns_request_t *request = (dns_request_t *)arg;
1054 
1055 	if (result == ISC_R_CANCELED) {
1056 		return;
1057 	}
1058 
1059 	req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1060 		isc_result_totext(result));
1061 
1062 	REQUIRE(VALID_REQUEST(request));
1063 
1064 	if (result == ISC_R_TIMEDOUT) {
1065 		LOCK(&request->requestmgr->locks[request->hash]);
1066 		if (request->udpcount > 1 &&
1067 		    (request->flags & DNS_REQUEST_F_TCP) == 0)
1068 		{
1069 			request->udpcount -= 1;
1070 			dns_dispatch_resume(request->dispentry,
1071 					    request->timeout);
1072 			if (!DNS_REQUEST_SENDING(request)) {
1073 				req_send(request);
1074 			}
1075 			UNLOCK(&request->requestmgr->locks[request->hash]);
1076 			return;
1077 		}
1078 
1079 		/* The lock is unlocked below */
1080 		goto done;
1081 	}
1082 
1083 	LOCK(&request->requestmgr->locks[request->hash]);
1084 
1085 	if (result != ISC_R_SUCCESS) {
1086 		goto done;
1087 	}
1088 
1089 	/*
1090 	 * Copy region to request.
1091 	 */
1092 	isc_buffer_allocate(request->mctx, &request->answer, region->length);
1093 	result = isc_buffer_copyregion(request->answer, region);
1094 	if (result != ISC_R_SUCCESS) {
1095 		isc_buffer_free(&request->answer);
1096 	}
1097 
1098 done:
1099 	/*
1100 	 * Cleanup.
1101 	 */
1102 	if (request->dispentry != NULL) {
1103 		dns_dispatch_done(&request->dispentry);
1104 	}
1105 	request_cancel(request);
1106 
1107 	/*
1108 	 * Send completion event.
1109 	 */
1110 	req_sendevent(request, result);
1111 	UNLOCK(&request->requestmgr->locks[request->hash]);
1112 }
1113 
1114 static void
1115 req_sendevent(dns_request_t *request, isc_result_t result) {
1116 	isc_task_t *task = NULL;
1117 
1118 	REQUIRE(VALID_REQUEST(request));
1119 
1120 	if (request->event == NULL) {
1121 		return;
1122 	}
1123 
1124 	req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1125 
1126 	/*
1127 	 * Lock held by caller.
1128 	 */
1129 	task = request->event->ev_sender;
1130 	request->event->ev_sender = request;
1131 	request->event->result = result;
1132 	isc_task_sendanddetach(&task, (isc_event_t **)(void *)&request->event);
1133 }
1134 
1135 static void
1136 req_attach(dns_request_t *source, dns_request_t **targetp) {
1137 	REQUIRE(VALID_REQUEST(source));
1138 	REQUIRE(targetp != NULL && *targetp == NULL);
1139 
1140 	isc_refcount_increment(&source->references);
1141 
1142 	*targetp = source;
1143 }
1144 
1145 static void
1146 req_detach(dns_request_t **requestp) {
1147 	dns_request_t *request = NULL;
1148 	uint_fast32_t ref;
1149 
1150 	REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1151 
1152 	request = *requestp;
1153 	*requestp = NULL;
1154 
1155 	ref = isc_refcount_decrement(&request->references);
1156 
1157 	if (request->requestmgr != NULL &&
1158 	    atomic_load_acquire(&request->requestmgr->exiting))
1159 	{
1160 		/* We are shutting down and this was last request */
1161 		LOCK(&request->requestmgr->lock);
1162 		if (ISC_LIST_EMPTY(request->requestmgr->requests)) {
1163 			send_shutdown_events(request->requestmgr);
1164 		}
1165 		UNLOCK(&request->requestmgr->lock);
1166 	}
1167 
1168 	if (ref == 1) {
1169 		req_destroy(request);
1170 	}
1171 }
1172 
1173 static void
1174 req_destroy(dns_request_t *request) {
1175 	REQUIRE(VALID_REQUEST(request));
1176 
1177 	req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1178 
1179 	isc_refcount_destroy(&request->references);
1180 
1181 	request->magic = 0;
1182 	if (request->query != NULL) {
1183 		isc_buffer_free(&request->query);
1184 	}
1185 	if (request->answer != NULL) {
1186 		isc_buffer_free(&request->answer);
1187 	}
1188 	if (request->event != NULL) {
1189 		isc_event_free((isc_event_t **)(void *)&request->event);
1190 	}
1191 	if (request->dispentry != NULL) {
1192 		dns_dispatch_done(&request->dispentry);
1193 	}
1194 	if (request->dispatch != NULL) {
1195 		dns_dispatch_detach(&request->dispatch);
1196 	}
1197 	if (request->tsig != NULL) {
1198 		isc_buffer_free(&request->tsig);
1199 	}
1200 	if (request->tsigkey != NULL) {
1201 		dns_tsigkey_detach(&request->tsigkey);
1202 	}
1203 	if (request->requestmgr != NULL) {
1204 		dns_requestmgr_detach(&request->requestmgr);
1205 	}
1206 	isc_mem_putanddetach(&request->mctx, request, sizeof(*request));
1207 }
1208 
1209 static void
1210 req_log(int level, const char *fmt, ...) {
1211 	va_list ap;
1212 
1213 	va_start(ap, fmt);
1214 	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST,
1215 		       level, fmt, ap);
1216 	va_end(ap);
1217 }
1218