xref: /netbsd-src/external/mpl/bind/dist/lib/dns/request.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: request.c,v 1.11 2025/01/26 16:25:24 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/async.h>
22 #include <isc/loop.h>
23 #include <isc/magic.h>
24 #include <isc/mem.h>
25 #include <isc/netmgr.h>
26 #include <isc/result.h>
27 #include <isc/thread.h>
28 #include <isc/tls.h>
29 #include <isc/util.h>
30 
31 #include <dns/acl.h>
32 #include <dns/compress.h>
33 #include <dns/dispatch.h>
34 #include <dns/log.h>
35 #include <dns/message.h>
36 #include <dns/rdata.h>
37 #include <dns/rdatastruct.h>
38 #include <dns/request.h>
39 #include <dns/transport.h>
40 #include <dns/tsig.h>
41 
42 #define REQUESTMGR_MAGIC      ISC_MAGIC('R', 'q', 'u', 'M')
43 #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
44 
45 #define REQUEST_MAGIC	       ISC_MAGIC('R', 'q', 'u', '!')
46 #define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC)
47 
48 typedef ISC_LIST(dns_request_t) dns_requestlist_t;
49 
50 struct dns_requestmgr {
51 	unsigned int magic;
52 	isc_mem_t *mctx;
53 	isc_refcount_t references;
54 	isc_loopmgr_t *loopmgr;
55 
56 	atomic_bool shuttingdown;
57 
58 	dns_dispatchmgr_t *dispatchmgr;
59 	dns_dispatchset_t *dispatches4;
60 	dns_dispatchset_t *dispatches6;
61 	dns_requestlist_t *requests;
62 };
63 
64 struct dns_request {
65 	unsigned int magic;
66 	isc_refcount_t references;
67 
68 	isc_mem_t *mctx;
69 	int32_t flags;
70 
71 	isc_loop_t *loop;
72 	unsigned int tid;
73 
74 	isc_result_t result;
75 	isc_job_cb cb;
76 	void *arg;
77 	ISC_LINK(dns_request_t) link;
78 	isc_buffer_t *query;
79 	isc_buffer_t *answer;
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 (1 << 0)
91 #define DNS_REQUEST_F_SENDING	 (1 << 1)
92 #define DNS_REQUEST_F_COMPLETE	 (1 << 2)
93 #define DNS_REQUEST_F_TCP	 (1 << 3)
94 
95 #define DNS_REQUEST_CONNECTING(r) (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
96 #define DNS_REQUEST_SENDING(r)	  (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
97 #define DNS_REQUEST_COMPLETE(r)	  (((r)->flags & DNS_REQUEST_F_COMPLETE) != 0)
98 
99 /***
100  *** Forward
101  ***/
102 
103 static isc_result_t
104 req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options,
105 	   isc_mem_t *mctx);
106 static void
107 req_response(isc_result_t result, isc_region_t *region, void *arg);
108 static void
109 req_senddone(isc_result_t eresult, isc_region_t *region, void *arg);
110 static void
111 req_cleanup(dns_request_t *request);
112 static void
113 req_sendevent(dns_request_t *request, isc_result_t result);
114 static void
115 req_connected(isc_result_t eresult, isc_region_t *region, void *arg);
116 static void
117 req_destroy(dns_request_t *request);
118 static void
119 req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
120 
121 /***
122  *** Public
123  ***/
124 
125 isc_result_t
126 dns_requestmgr_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
127 		      dns_dispatchmgr_t *dispatchmgr,
128 		      dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
129 		      dns_requestmgr_t **requestmgrp) {
130 	REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
131 	REQUIRE(dispatchmgr != NULL);
132 
133 	req_log(ISC_LOG_DEBUG(3), "%s", __func__);
134 
135 	dns_requestmgr_t *requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
136 	*requestmgr = (dns_requestmgr_t){
137 		.magic = REQUESTMGR_MAGIC,
138 		.loopmgr = loopmgr,
139 	};
140 	isc_mem_attach(mctx, &requestmgr->mctx);
141 
142 	uint32_t nloops = isc_loopmgr_nloops(requestmgr->loopmgr);
143 	requestmgr->requests = isc_mem_cget(requestmgr->mctx, nloops,
144 					    sizeof(requestmgr->requests[0]));
145 	for (size_t i = 0; i < nloops; i++) {
146 		ISC_LIST_INIT(requestmgr->requests[i]);
147 
148 		/* unreferenced in requests_shutdown() */
149 		isc_loop_ref(isc_loop_get(requestmgr->loopmgr, i));
150 	}
151 
152 	dns_dispatchmgr_attach(dispatchmgr, &requestmgr->dispatchmgr);
153 
154 	if (dispatchv4 != NULL) {
155 		dns_dispatchset_create(requestmgr->mctx, dispatchv4,
156 				       &requestmgr->dispatches4,
157 				       isc_loopmgr_nloops(requestmgr->loopmgr));
158 	}
159 	if (dispatchv6 != NULL) {
160 		dns_dispatchset_create(requestmgr->mctx, dispatchv6,
161 				       &requestmgr->dispatches6,
162 				       isc_loopmgr_nloops(requestmgr->loopmgr));
163 	}
164 
165 	isc_refcount_init(&requestmgr->references, 1);
166 
167 	req_log(ISC_LOG_DEBUG(3), "%s: %p", __func__, requestmgr);
168 
169 	*requestmgrp = requestmgr;
170 	return ISC_R_SUCCESS;
171 }
172 
173 static void
174 requests_shutdown(void *arg) {
175 	dns_requestmgr_t *requestmgr = arg;
176 	dns_request_t *request = NULL, *next = NULL;
177 	uint32_t tid = isc_tid();
178 
179 	ISC_LIST_FOREACH_SAFE (requestmgr->requests[tid], request, link, next) {
180 		req_log(ISC_LOG_DEBUG(3), "%s(%" PRIu32 ": request %p",
181 			__func__, tid, request);
182 		if (DNS_REQUEST_COMPLETE(request)) {
183 			/* The callback has been already scheduled */
184 			continue;
185 		}
186 		req_sendevent(request, ISC_R_SHUTTINGDOWN);
187 	}
188 
189 	isc_loop_unref(isc_loop_get(requestmgr->loopmgr, tid));
190 	dns_requestmgr_detach(&requestmgr);
191 }
192 
193 void
194 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
195 	bool first;
196 	REQUIRE(VALID_REQUESTMGR(requestmgr));
197 
198 	req_log(ISC_LOG_DEBUG(3), "%s: %p", __func__, requestmgr);
199 
200 	rcu_read_lock();
201 	first = atomic_compare_exchange_strong(&requestmgr->shuttingdown,
202 					       &(bool){ false }, true);
203 	rcu_read_unlock();
204 
205 	if (!first) {
206 		return;
207 	}
208 
209 	/*
210 	 * Wait until all dns_request_create{raw}() are finished, so
211 	 * there will be no new requests added to the lists.
212 	 */
213 	synchronize_rcu();
214 
215 	uint32_t tid = isc_tid();
216 	uint32_t nloops = isc_loopmgr_nloops(requestmgr->loopmgr);
217 	for (size_t i = 0; i < nloops; i++) {
218 		dns_requestmgr_ref(requestmgr);
219 
220 		if (i == tid) {
221 			/* Run the current loop synchronously */
222 			requests_shutdown(requestmgr);
223 			continue;
224 		}
225 
226 		isc_loop_t *loop = isc_loop_get(requestmgr->loopmgr, i);
227 		isc_async_run(loop, requests_shutdown, requestmgr);
228 	}
229 }
230 
231 static void
232 requestmgr_destroy(dns_requestmgr_t *requestmgr) {
233 	req_log(ISC_LOG_DEBUG(3), "%s", __func__);
234 
235 	INSIST(atomic_load(&requestmgr->shuttingdown));
236 
237 	size_t nloops = isc_loopmgr_nloops(requestmgr->loopmgr);
238 	for (size_t i = 0; i < nloops; i++) {
239 		INSIST(ISC_LIST_EMPTY(requestmgr->requests[i]));
240 	}
241 	isc_mem_cput(requestmgr->mctx, requestmgr->requests, nloops,
242 		     sizeof(requestmgr->requests[0]));
243 
244 	if (requestmgr->dispatches4 != NULL) {
245 		dns_dispatchset_destroy(&requestmgr->dispatches4);
246 	}
247 	if (requestmgr->dispatches6 != NULL) {
248 		dns_dispatchset_destroy(&requestmgr->dispatches6);
249 	}
250 	if (requestmgr->dispatchmgr != NULL) {
251 		dns_dispatchmgr_detach(&requestmgr->dispatchmgr);
252 	}
253 	requestmgr->magic = 0;
254 	isc_mem_putanddetach(&requestmgr->mctx, requestmgr,
255 			     sizeof(*requestmgr));
256 }
257 
258 #if DNS_REQUEST_TRACE
259 ISC_REFCOUNT_TRACE_IMPL(dns_requestmgr, requestmgr_destroy);
260 #else
261 ISC_REFCOUNT_IMPL(dns_requestmgr, requestmgr_destroy);
262 #endif
263 
264 static void
265 req_send(dns_request_t *request) {
266 	isc_region_t r;
267 
268 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
269 
270 	REQUIRE(VALID_REQUEST(request));
271 
272 	isc_buffer_usedregion(request->query, &r);
273 
274 	request->flags |= DNS_REQUEST_F_SENDING;
275 
276 	/* detached in req_senddone() */
277 	dns_request_ref(request);
278 	dns_dispatch_send(request->dispentry, &r);
279 }
280 
281 static dns_request_t *
282 new_request(isc_mem_t *mctx, isc_loop_t *loop, isc_job_cb cb, void *arg,
283 	    bool tcp, unsigned int timeout, unsigned int udptimeout,
284 	    unsigned int udpretries) {
285 	dns_request_t *request = isc_mem_get(mctx, sizeof(*request));
286 	*request = (dns_request_t){
287 		.magic = REQUEST_MAGIC,
288 		.loop = loop,
289 		.tid = isc_tid(),
290 		.cb = cb,
291 		.arg = arg,
292 		.link = ISC_LINK_INITIALIZER,
293 		.result = ISC_R_FAILURE,
294 		.udpcount = udpretries + 1,
295 	};
296 
297 	isc_refcount_init(&request->references, 1);
298 	isc_mem_attach(mctx, &request->mctx);
299 
300 	if (tcp) {
301 		request->timeout = timeout * 1000;
302 	} else {
303 		if (udptimeout == 0) {
304 			udptimeout = timeout / request->udpcount;
305 		}
306 		if (udptimeout == 0) {
307 			udptimeout = 1;
308 		}
309 		request->timeout = udptimeout * 1000;
310 	}
311 
312 	return request;
313 }
314 
315 static bool
316 isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) {
317 	dns_acl_t *blackhole;
318 	isc_netaddr_t netaddr;
319 	char netaddrstr[ISC_NETADDR_FORMATSIZE];
320 	int match;
321 	isc_result_t result;
322 
323 	blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
324 	if (blackhole == NULL) {
325 		return false;
326 	}
327 
328 	isc_netaddr_fromsockaddr(&netaddr, destaddr);
329 	result = dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, NULL);
330 	if (result != ISC_R_SUCCESS || match <= 0) {
331 		return false;
332 	}
333 
334 	isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
335 	req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
336 
337 	return true;
338 }
339 
340 static isc_result_t
341 tcp_dispatch(bool newtcp, dns_requestmgr_t *requestmgr,
342 	     const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
343 	     dns_transport_t *transport, dns_dispatch_t **dispatchp) {
344 	isc_result_t result;
345 
346 	if (!newtcp) {
347 		result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
348 					     srcaddr, transport, dispatchp);
349 		if (result == ISC_R_SUCCESS) {
350 			char peer[ISC_SOCKADDR_FORMATSIZE];
351 
352 			isc_sockaddr_format(destaddr, peer, sizeof(peer));
353 			req_log(ISC_LOG_DEBUG(1),
354 				"attached to TCP connection to %s", peer);
355 			return result;
356 		}
357 	}
358 
359 	result = dns_dispatch_createtcp(requestmgr->dispatchmgr, srcaddr,
360 					destaddr, transport, 0, dispatchp);
361 	return result;
362 }
363 
364 static isc_result_t
365 udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
366 	     const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) {
367 	dns_dispatch_t *disp = NULL;
368 
369 	if (srcaddr == NULL) {
370 		switch (isc_sockaddr_pf(destaddr)) {
371 		case PF_INET:
372 			disp = dns_dispatchset_get(requestmgr->dispatches4);
373 			break;
374 
375 		case PF_INET6:
376 			disp = dns_dispatchset_get(requestmgr->dispatches6);
377 			break;
378 
379 		default:
380 			return ISC_R_NOTIMPLEMENTED;
381 		}
382 		if (disp == NULL) {
383 			return ISC_R_FAMILYNOSUPPORT;
384 		}
385 		dns_dispatch_attach(disp, dispatchp);
386 		return ISC_R_SUCCESS;
387 	}
388 
389 	return dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr,
390 				      dispatchp);
391 }
392 
393 static isc_result_t
394 get_dispatch(bool tcp, bool newtcp, dns_requestmgr_t *requestmgr,
395 	     const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
396 	     dns_transport_t *transport, dns_dispatch_t **dispatchp) {
397 	isc_result_t result;
398 
399 	if (tcp) {
400 		result = tcp_dispatch(newtcp, requestmgr, srcaddr, destaddr,
401 				      transport, dispatchp);
402 	} else {
403 		result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp);
404 	}
405 	return result;
406 }
407 
408 isc_result_t
409 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
410 		      const isc_sockaddr_t *srcaddr,
411 		      const isc_sockaddr_t *destaddr,
412 		      dns_transport_t *transport,
413 		      isc_tlsctx_cache_t *tlsctx_cache, unsigned int options,
414 		      unsigned int timeout, unsigned int udptimeout,
415 		      unsigned int udpretries, isc_loop_t *loop, isc_job_cb cb,
416 		      void *arg, dns_request_t **requestp) {
417 	dns_request_t *request = NULL;
418 	isc_result_t result;
419 	isc_mem_t *mctx = NULL;
420 	dns_messageid_t id;
421 	bool tcp = false;
422 	bool newtcp = false;
423 	isc_region_t r;
424 	unsigned int dispopt = 0;
425 
426 	REQUIRE(VALID_REQUESTMGR(requestmgr));
427 	REQUIRE(msgbuf != NULL);
428 	REQUIRE(destaddr != NULL);
429 	REQUIRE(loop != NULL);
430 	REQUIRE(cb != NULL);
431 	REQUIRE(requestp != NULL && *requestp == NULL);
432 	REQUIRE(timeout > 0);
433 	REQUIRE(udpretries != UINT_MAX);
434 
435 	if (srcaddr != NULL) {
436 		REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
437 	}
438 
439 	mctx = requestmgr->mctx;
440 
441 	req_log(ISC_LOG_DEBUG(3), "%s", __func__);
442 
443 	rcu_read_lock();
444 
445 	if (atomic_load_acquire(&requestmgr->shuttingdown)) {
446 		result = ISC_R_SHUTTINGDOWN;
447 		goto done;
448 	}
449 
450 	if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
451 		result = DNS_R_BLACKHOLED;
452 		goto done;
453 	}
454 
455 	isc_buffer_usedregion(msgbuf, &r);
456 	if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
457 		result = DNS_R_FORMERR;
458 		goto done;
459 	}
460 
461 	if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) {
462 		tcp = true;
463 	}
464 
465 	request = new_request(mctx, loop, cb, arg, tcp, timeout, udptimeout,
466 			      udpretries);
467 
468 	isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0));
469 	result = isc_buffer_copyregion(request->query, &r);
470 	if (result != ISC_R_SUCCESS) {
471 		goto cleanup;
472 	}
473 
474 again:
475 	result = get_dispatch(tcp, newtcp, requestmgr, srcaddr, destaddr,
476 			      transport, &request->dispatch);
477 	if (result != ISC_R_SUCCESS) {
478 		goto cleanup;
479 	}
480 
481 	if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
482 		id = (r.base[0] << 8) | r.base[1];
483 		dispopt |= DNS_DISPATCHOPT_FIXEDID;
484 	}
485 
486 	result = dns_dispatch_add(
487 		request->dispatch, loop, dispopt, request->timeout, destaddr,
488 		transport, tlsctx_cache, req_connected, req_senddone,
489 		req_response, request, &id, &request->dispentry);
490 	if (result != ISC_R_SUCCESS) {
491 		if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
492 			dns_dispatch_detach(&request->dispatch);
493 			newtcp = true;
494 			goto again;
495 		}
496 
497 		goto cleanup;
498 	}
499 
500 	/* Add message ID. */
501 	isc_buffer_usedregion(request->query, &r);
502 	r.base[0] = (id >> 8) & 0xff;
503 	r.base[1] = id & 0xff;
504 
505 	request->destaddr = *destaddr;
506 	request->flags |= DNS_REQUEST_F_CONNECTING;
507 	if (tcp) {
508 		request->flags |= DNS_REQUEST_F_TCP;
509 	}
510 
511 	dns_requestmgr_attach(requestmgr, &request->requestmgr);
512 	ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link);
513 
514 	dns_request_ref(request); /* detached in req_connected() */
515 	result = dns_dispatch_connect(request->dispentry);
516 	if (result != ISC_R_SUCCESS) {
517 		dns_request_unref(request);
518 		goto cleanup;
519 	}
520 
521 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
522 	*requestp = request;
523 
524 cleanup:
525 	if (result != ISC_R_SUCCESS) {
526 		req_cleanup(request);
527 		dns_request_detach(&request);
528 		req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__,
529 			isc_result_totext(result));
530 	}
531 
532 done:
533 	rcu_read_unlock();
534 	return result;
535 }
536 
537 isc_result_t
538 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
539 		   const isc_sockaddr_t *srcaddr,
540 		   const isc_sockaddr_t *destaddr, dns_transport_t *transport,
541 		   isc_tlsctx_cache_t *tlsctx_cache, unsigned int options,
542 		   dns_tsigkey_t *key, unsigned int timeout,
543 		   unsigned int udptimeout, unsigned int udpretries,
544 		   isc_loop_t *loop, isc_job_cb cb, void *arg,
545 		   dns_request_t **requestp) {
546 	dns_request_t *request = NULL;
547 	isc_result_t result;
548 	isc_mem_t *mctx = NULL;
549 	dns_messageid_t id;
550 	bool tcp = false;
551 
552 	REQUIRE(VALID_REQUESTMGR(requestmgr));
553 	REQUIRE(message != NULL);
554 	REQUIRE(destaddr != NULL);
555 	REQUIRE(loop != NULL);
556 	REQUIRE(cb != NULL);
557 	REQUIRE(requestp != NULL && *requestp == NULL);
558 	REQUIRE(timeout > 0);
559 	REQUIRE(udpretries != UINT_MAX);
560 
561 	if (srcaddr != NULL &&
562 	    isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
563 	{
564 		return ISC_R_FAMILYMISMATCH;
565 	}
566 
567 	mctx = requestmgr->mctx;
568 
569 	req_log(ISC_LOG_DEBUG(3), "%s", __func__);
570 
571 	rcu_read_lock();
572 
573 	if (atomic_load_acquire(&requestmgr->shuttingdown)) {
574 		result = ISC_R_SHUTTINGDOWN;
575 		goto done;
576 	}
577 
578 	if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
579 		result = DNS_R_BLACKHOLED;
580 		goto done;
581 	}
582 
583 	if ((options & DNS_REQUESTOPT_TCP) != 0) {
584 		tcp = true;
585 	}
586 
587 	request = new_request(mctx, loop, cb, arg, tcp, timeout, udptimeout,
588 			      udpretries);
589 
590 	if (key != NULL) {
591 		dns_tsigkey_attach(key, &request->tsigkey);
592 	}
593 
594 	result = dns_message_settsigkey(message, request->tsigkey);
595 	if (result != ISC_R_SUCCESS) {
596 		goto cleanup;
597 	}
598 
599 again:
600 	result = get_dispatch(tcp, false, requestmgr, srcaddr, destaddr,
601 			      transport, &request->dispatch);
602 	if (result != ISC_R_SUCCESS) {
603 		goto cleanup;
604 	}
605 
606 	result = dns_dispatch_add(request->dispatch, loop, 0, request->timeout,
607 				  destaddr, transport, tlsctx_cache,
608 				  req_connected, req_senddone, req_response,
609 				  request, &id, &request->dispentry);
610 	if (result != ISC_R_SUCCESS) {
611 		goto cleanup;
612 	}
613 
614 	message->id = id;
615 	result = req_render(message, &request->query, options, mctx);
616 	if (result == DNS_R_USETCP && !tcp) {
617 		/* Try again using TCP. */
618 		dns_message_renderreset(message);
619 		dns_dispatch_done(&request->dispentry);
620 		dns_dispatch_detach(&request->dispatch);
621 		options |= DNS_REQUESTOPT_TCP;
622 		tcp = true;
623 		goto again;
624 	} else if (result != ISC_R_SUCCESS) {
625 		goto cleanup;
626 	}
627 
628 	result = dns_message_getquerytsig(message, mctx, &request->tsig);
629 	if (result != ISC_R_SUCCESS) {
630 		goto cleanup;
631 	}
632 
633 	request->destaddr = *destaddr;
634 	request->flags |= DNS_REQUEST_F_CONNECTING;
635 	if (tcp) {
636 		request->flags |= DNS_REQUEST_F_TCP;
637 	}
638 
639 	dns_requestmgr_attach(requestmgr, &request->requestmgr);
640 	ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link);
641 
642 	dns_request_ref(request); /* detached in req_connected() */
643 	result = dns_dispatch_connect(request->dispentry);
644 	if (result != ISC_R_SUCCESS) {
645 		dns_request_unref(request);
646 		goto cleanup;
647 	}
648 
649 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
650 	*requestp = request;
651 
652 cleanup:
653 	if (result != ISC_R_SUCCESS) {
654 		req_cleanup(request);
655 		dns_request_detach(&request);
656 		req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__,
657 			isc_result_totext(result));
658 	}
659 done:
660 	rcu_read_unlock();
661 
662 	return result;
663 }
664 
665 static isc_result_t
666 req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options,
667 	   isc_mem_t *mctx) {
668 	isc_buffer_t *buf1 = NULL;
669 	isc_buffer_t *buf2 = NULL;
670 	isc_result_t result;
671 	isc_region_t r;
672 	dns_compress_t cctx;
673 	unsigned int compflags;
674 
675 	REQUIRE(bufferp != NULL && *bufferp == NULL);
676 
677 	req_log(ISC_LOG_DEBUG(3), "%s", __func__);
678 
679 	/*
680 	 * Create buffer able to hold largest possible message.
681 	 */
682 	isc_buffer_allocate(mctx, &buf1, 65535);
683 
684 	compflags = 0;
685 	if ((options & DNS_REQUESTOPT_LARGE) != 0) {
686 		compflags |= DNS_COMPRESS_LARGE;
687 	}
688 	if ((options & DNS_REQUESTOPT_CASE) != 0) {
689 		compflags |= DNS_COMPRESS_CASE;
690 	}
691 	dns_compress_init(&cctx, mctx, compflags);
692 
693 	/*
694 	 * Render message.
695 	 */
696 	result = dns_message_renderbegin(message, &cctx, buf1);
697 	if (result != ISC_R_SUCCESS) {
698 		goto cleanup;
699 	}
700 	result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
701 	if (result != ISC_R_SUCCESS) {
702 		goto cleanup;
703 	}
704 	result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
705 	if (result != ISC_R_SUCCESS) {
706 		goto cleanup;
707 	}
708 	result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
709 	if (result != ISC_R_SUCCESS) {
710 		goto cleanup;
711 	}
712 	result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
713 	if (result != ISC_R_SUCCESS) {
714 		goto cleanup;
715 	}
716 	result = dns_message_renderend(message);
717 	if (result != ISC_R_SUCCESS) {
718 		goto cleanup;
719 	}
720 
721 	/*
722 	 * Copy rendered message to exact sized buffer.
723 	 */
724 	isc_buffer_usedregion(buf1, &r);
725 	if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) {
726 		result = DNS_R_USETCP;
727 		goto cleanup;
728 	}
729 	isc_buffer_allocate(mctx, &buf2, r.length);
730 	result = isc_buffer_copyregion(buf2, &r);
731 	if (result != ISC_R_SUCCESS) {
732 		goto cleanup;
733 	}
734 
735 	/*
736 	 * Cleanup and return.
737 	 */
738 	dns_compress_invalidate(&cctx);
739 	isc_buffer_free(&buf1);
740 	*bufferp = buf2;
741 	return ISC_R_SUCCESS;
742 
743 cleanup:
744 	dns_message_renderreset(message);
745 	dns_compress_invalidate(&cctx);
746 	if (buf1 != NULL) {
747 		isc_buffer_free(&buf1);
748 	}
749 	if (buf2 != NULL) {
750 		isc_buffer_free(&buf2);
751 	}
752 	return result;
753 }
754 
755 static void
756 request_cancel(dns_request_t *request) {
757 	REQUIRE(VALID_REQUEST(request));
758 	REQUIRE(request->tid == isc_tid());
759 
760 	if (DNS_REQUEST_COMPLETE(request)) {
761 		/* The request callback was already called */
762 		return;
763 	}
764 
765 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
766 	req_sendevent(request, ISC_R_CANCELED); /* call asynchronously */
767 }
768 
769 static void
770 req_cancel_cb(void *arg) {
771 	dns_request_t *request = arg;
772 
773 	request_cancel(request);
774 	dns_request_unref(request);
775 }
776 
777 void
778 dns_request_cancel(dns_request_t *request) {
779 	REQUIRE(VALID_REQUEST(request));
780 
781 	if (request->tid == isc_tid()) {
782 		request_cancel(request);
783 	} else {
784 		dns_request_ref(request);
785 		isc_async_run(request->loop, req_cancel_cb, request);
786 	}
787 }
788 
789 isc_result_t
790 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
791 			unsigned int options) {
792 	isc_result_t result;
793 
794 	REQUIRE(VALID_REQUEST(request));
795 	REQUIRE(request->tid == isc_tid());
796 	REQUIRE(request->answer != NULL);
797 
798 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
799 
800 	dns_message_setquerytsig(message, request->tsig);
801 	result = dns_message_settsigkey(message, request->tsigkey);
802 	if (result != ISC_R_SUCCESS) {
803 		return result;
804 	}
805 	result = dns_message_parse(message, request->answer, options);
806 	if (result != ISC_R_SUCCESS) {
807 		return result;
808 	}
809 	if (request->tsigkey != NULL) {
810 		result = dns_tsig_verify(request->answer, message, NULL, NULL);
811 	}
812 	return result;
813 }
814 
815 isc_buffer_t *
816 dns_request_getanswer(dns_request_t *request) {
817 	REQUIRE(VALID_REQUEST(request));
818 	REQUIRE(request->tid == isc_tid());
819 
820 	return request->answer;
821 }
822 
823 bool
824 dns_request_usedtcp(dns_request_t *request) {
825 	REQUIRE(VALID_REQUEST(request));
826 	REQUIRE(request->tid == isc_tid());
827 
828 	return (request->flags & DNS_REQUEST_F_TCP) != 0;
829 }
830 
831 void
832 dns_request_destroy(dns_request_t **requestp) {
833 	REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
834 
835 	dns_request_t *request = *requestp;
836 	*requestp = NULL;
837 
838 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
839 
840 	if (DNS_REQUEST_COMPLETE(request)) {
841 		dns_request_cancel(request);
842 	}
843 
844 	/* final detach to shut down request */
845 	dns_request_detach(&request);
846 }
847 
848 static void
849 req_connected(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED,
850 	      void *arg) {
851 	dns_request_t *request = (dns_request_t *)arg;
852 
853 	REQUIRE(VALID_REQUEST(request));
854 	REQUIRE(request->tid == isc_tid());
855 	REQUIRE(DNS_REQUEST_CONNECTING(request));
856 
857 	req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
858 		isc_result_totext(eresult));
859 
860 	request->flags &= ~DNS_REQUEST_F_CONNECTING;
861 
862 	if (DNS_REQUEST_COMPLETE(request)) {
863 		/* The request callback was already called */
864 		goto detach;
865 	}
866 
867 	if (eresult == ISC_R_SUCCESS) {
868 		req_send(request);
869 	} else {
870 		req_sendevent(request, eresult);
871 	}
872 
873 detach:
874 	/* attached in dns_request_create/_createraw() */
875 	dns_request_unref(request);
876 }
877 
878 static void
879 req_senddone(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED,
880 	     void *arg) {
881 	dns_request_t *request = (dns_request_t *)arg;
882 
883 	REQUIRE(VALID_REQUEST(request));
884 	REQUIRE(request->tid == isc_tid());
885 	REQUIRE(DNS_REQUEST_SENDING(request));
886 
887 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
888 
889 	request->flags &= ~DNS_REQUEST_F_SENDING;
890 
891 	if (DNS_REQUEST_COMPLETE(request)) {
892 		/* The request callback was already called */
893 		goto detach;
894 	}
895 
896 	if (eresult != ISC_R_SUCCESS) {
897 		req_sendevent(request, eresult);
898 	}
899 
900 detach:
901 	/* attached in req_send() */
902 	dns_request_unref(request);
903 }
904 
905 static void
906 req_response(isc_result_t eresult, isc_region_t *region, void *arg) {
907 	dns_request_t *request = (dns_request_t *)arg;
908 
909 	if (eresult == ISC_R_CANCELED) {
910 		return;
911 	}
912 
913 	REQUIRE(VALID_REQUEST(request));
914 	REQUIRE(request->tid == isc_tid());
915 
916 	req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
917 		isc_result_totext(eresult));
918 
919 	if (DNS_REQUEST_COMPLETE(request)) {
920 		/* The request callback was already called */
921 		return;
922 	}
923 
924 	switch (eresult) {
925 	case ISC_R_TIMEDOUT:
926 		if (request->udpcount > 1 && !dns_request_usedtcp(request)) {
927 			request->udpcount -= 1;
928 			dns_dispatch_resume(request->dispentry,
929 					    request->timeout);
930 			if (!DNS_REQUEST_SENDING(request)) {
931 				req_send(request);
932 			}
933 			return;
934 		}
935 		break;
936 	case ISC_R_SUCCESS:
937 		/* Copy region to request. */
938 		isc_buffer_allocate(request->mctx, &request->answer,
939 				    region->length);
940 		eresult = isc_buffer_copyregion(request->answer, region);
941 		if (eresult != ISC_R_SUCCESS) {
942 			isc_buffer_free(&request->answer);
943 		}
944 		break;
945 	default:
946 		break;
947 	}
948 
949 	req_sendevent(request, eresult);
950 }
951 
952 static void
953 req_sendevent_cb(void *arg) {
954 	dns_request_t *request = arg;
955 
956 	request->cb(request);
957 	dns_request_unref(request);
958 }
959 
960 static void
961 req_cleanup(dns_request_t *request) {
962 	if (ISC_LINK_LINKED(request, link)) {
963 		ISC_LIST_UNLINK(request->requestmgr->requests[request->tid],
964 				request, link);
965 	}
966 	if (request->dispentry != NULL) {
967 		dns_dispatch_done(&request->dispentry);
968 	}
969 	if (request->dispatch != NULL) {
970 		dns_dispatch_detach(&request->dispatch);
971 	}
972 }
973 
974 static void
975 req_sendevent(dns_request_t *request, isc_result_t result) {
976 	REQUIRE(VALID_REQUEST(request));
977 	REQUIRE(request->tid == isc_tid());
978 	REQUIRE(!DNS_REQUEST_COMPLETE(request));
979 
980 	request->flags |= DNS_REQUEST_F_COMPLETE;
981 
982 	req_cleanup(request);
983 
984 	req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request,
985 		isc_result_totext(result));
986 
987 	request->result = result;
988 
989 	/*
990 	 * Do not call request->cb directly as it introduces a dead lock
991 	 * between dns_zonemgr_shutdown and sendtoprimary in lib/dns/zone.c
992 	 * zone->lock.
993 	 */
994 	dns_request_ref(request);
995 	isc_async_run(request->loop, req_sendevent_cb, request);
996 }
997 
998 static void
999 req_destroy(dns_request_t *request) {
1000 	REQUIRE(VALID_REQUEST(request));
1001 	REQUIRE(request->tid == isc_tid());
1002 	REQUIRE(!ISC_LINK_LINKED(request, link));
1003 
1004 	req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request);
1005 
1006 	/*
1007 	 * These should have been cleaned up before the
1008 	 * completion event was sent.
1009 	 */
1010 	INSIST(!ISC_LINK_LINKED(request, link));
1011 	INSIST(request->dispentry == NULL);
1012 	INSIST(request->dispatch == NULL);
1013 
1014 	request->magic = 0;
1015 	if (request->query != NULL) {
1016 		isc_buffer_free(&request->query);
1017 	}
1018 	if (request->answer != NULL) {
1019 		isc_buffer_free(&request->answer);
1020 	}
1021 	if (request->tsig != NULL) {
1022 		isc_buffer_free(&request->tsig);
1023 	}
1024 	if (request->tsigkey != NULL) {
1025 		dns_tsigkey_detach(&request->tsigkey);
1026 	}
1027 	if (request->requestmgr != NULL) {
1028 		dns_requestmgr_detach(&request->requestmgr);
1029 	}
1030 	isc_mem_putanddetach(&request->mctx, request, sizeof(*request));
1031 }
1032 
1033 void *
1034 dns_request_getarg(dns_request_t *request) {
1035 	REQUIRE(VALID_REQUEST(request));
1036 	REQUIRE(request->tid == isc_tid());
1037 
1038 	return request->arg;
1039 }
1040 
1041 isc_result_t
1042 dns_request_getresult(dns_request_t *request) {
1043 	REQUIRE(VALID_REQUEST(request));
1044 	REQUIRE(request->tid == isc_tid());
1045 
1046 	return request->result;
1047 }
1048 
1049 #if DNS_REQUEST_TRACE
1050 ISC_REFCOUNT_TRACE_IMPL(dns_request, req_destroy);
1051 #else
1052 ISC_REFCOUNT_IMPL(dns_request, req_destroy);
1053 #endif
1054 
1055 static void
1056 req_log(int level, const char *fmt, ...) {
1057 	va_list ap;
1058 
1059 	va_start(ap, fmt);
1060 	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST,
1061 		       level, fmt, ap);
1062 	va_end(ap);
1063 }
1064