xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/request.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1 /*	$NetBSD: request.c,v 1.1 2024/02/18 20:57:33 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/task.h>
24 #include <isc/timer.h>
25 #include <isc/util.h>
26 
27 #include <dns/acl.h>
28 #include <dns/compress.h>
29 #include <dns/dispatch.h>
30 #include <dns/events.h>
31 #include <dns/log.h>
32 #include <dns/message.h>
33 #include <dns/rdata.h>
34 #include <dns/rdatastruct.h>
35 #include <dns/request.h>
36 #include <dns/result.h>
37 #include <dns/tsig.h>
38 
39 #define REQUESTMGR_MAGIC      ISC_MAGIC('R', 'q', 'u', 'M')
40 #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC)
41 
42 #define REQUEST_MAGIC	       ISC_MAGIC('R', 'q', 'u', '!')
43 #define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC)
44 
45 typedef ISC_LIST(dns_request_t) dns_requestlist_t;
46 
47 #define DNS_REQUEST_NLOCKS 7
48 
49 struct dns_requestmgr {
50 	unsigned int magic;
51 	isc_mutex_t lock;
52 	isc_mem_t *mctx;
53 
54 	/* locked */
55 	int32_t eref;
56 	int32_t iref;
57 	isc_timermgr_t *timermgr;
58 	isc_socketmgr_t *socketmgr;
59 	isc_taskmgr_t *taskmgr;
60 	dns_dispatchmgr_t *dispatchmgr;
61 	dns_dispatch_t *dispatchv4;
62 	dns_dispatch_t *dispatchv6;
63 	bool exiting;
64 	isc_eventlist_t whenshutdown;
65 	unsigned int hash;
66 	isc_mutex_t locks[DNS_REQUEST_NLOCKS];
67 	dns_requestlist_t requests;
68 };
69 
70 struct dns_request {
71 	unsigned int magic;
72 	unsigned int hash;
73 	isc_mem_t *mctx;
74 	int32_t flags;
75 	ISC_LINK(dns_request_t) link;
76 	isc_buffer_t *query;
77 	isc_buffer_t *answer;
78 	dns_requestevent_t *event;
79 	dns_dispatch_t *dispatch;
80 	dns_dispentry_t *dispentry;
81 	isc_timer_t *timer;
82 	dns_requestmgr_t *requestmgr;
83 	isc_buffer_t *tsig;
84 	dns_tsigkey_t *tsigkey;
85 	isc_event_t ctlevent;
86 	bool canceling; /* ctlevent outstanding */
87 	isc_sockaddr_t destaddr;
88 	unsigned int udpcount;
89 	isc_dscp_t dscp;
90 };
91 
92 #define DNS_REQUEST_F_CONNECTING 0x0001
93 #define DNS_REQUEST_F_SENDING	 0x0002
94 #define DNS_REQUEST_F_CANCELED                                                \
95 	0x0004				 /*%< ctlevent received, or otherwise \
96 					  * synchronously canceled */
97 #define DNS_REQUEST_F_TIMEDOUT	  0x0008 /*%< canceled due to a timeout */
98 #define DNS_REQUEST_F_TCP	  0x0010 /*%< This request used TCP */
99 #define DNS_REQUEST_CANCELED(r)	  (((r)->flags & DNS_REQUEST_F_CANCELED) != 0)
100 #define DNS_REQUEST_CONNECTING(r) (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0)
101 #define DNS_REQUEST_SENDING(r)	  (((r)->flags & DNS_REQUEST_F_SENDING) != 0)
102 #define DNS_REQUEST_TIMEDOUT(r)	  (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0)
103 
104 /***
105  *** Forward
106  ***/
107 
108 static void
109 mgr_destroy(dns_requestmgr_t *requestmgr);
110 static void
111 mgr_shutdown(dns_requestmgr_t *requestmgr);
112 static unsigned int
113 mgr_gethash(dns_requestmgr_t *requestmgr);
114 static void
115 send_shutdown_events(dns_requestmgr_t *requestmgr);
116 
117 static isc_result_t
118 req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options,
119 	   isc_mem_t *mctx);
120 static void
121 req_senddone(isc_task_t *task, isc_event_t *event);
122 static void
123 req_response(isc_task_t *task, isc_event_t *event);
124 static void
125 req_timeout(isc_task_t *task, isc_event_t *event);
126 static isc_socket_t *
127 req_getsocket(dns_request_t *request);
128 static void
129 req_connected(isc_task_t *task, isc_event_t *event);
130 static void
131 req_sendevent(dns_request_t *request, isc_result_t result);
132 static void
133 req_cancel(dns_request_t *request);
134 static void
135 req_destroy(dns_request_t *request);
136 static void
137 req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
138 static void
139 do_cancel(isc_task_t *task, isc_event_t *event);
140 
141 /***
142  *** Public
143  ***/
144 
145 isc_result_t
dns_requestmgr_create(isc_mem_t * mctx,isc_timermgr_t * timermgr,isc_socketmgr_t * socketmgr,isc_taskmgr_t * taskmgr,dns_dispatchmgr_t * dispatchmgr,dns_dispatch_t * dispatchv4,dns_dispatch_t * dispatchv6,dns_requestmgr_t ** requestmgrp)146 dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr,
147 		      isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
148 		      dns_dispatchmgr_t *dispatchmgr,
149 		      dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6,
150 		      dns_requestmgr_t **requestmgrp) {
151 	dns_requestmgr_t *requestmgr;
152 	int i;
153 	unsigned int dispattr;
154 
155 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create");
156 
157 	REQUIRE(requestmgrp != NULL && *requestmgrp == NULL);
158 	REQUIRE(timermgr != NULL);
159 	REQUIRE(socketmgr != NULL);
160 	REQUIRE(taskmgr != NULL);
161 	REQUIRE(dispatchmgr != NULL);
162 
163 	if (dispatchv4 != NULL) {
164 		dispattr = dns_dispatch_getattributes(dispatchv4);
165 		REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
166 	}
167 	if (dispatchv6 != NULL) {
168 		dispattr = dns_dispatch_getattributes(dispatchv6);
169 		REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0);
170 	}
171 
172 	requestmgr = isc_mem_get(mctx, sizeof(*requestmgr));
173 
174 	isc_mutex_init(&requestmgr->lock);
175 
176 	for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
177 		isc_mutex_init(&requestmgr->locks[i]);
178 	}
179 	requestmgr->timermgr = timermgr;
180 	requestmgr->socketmgr = socketmgr;
181 	requestmgr->taskmgr = taskmgr;
182 	requestmgr->dispatchmgr = dispatchmgr;
183 	requestmgr->dispatchv4 = NULL;
184 	if (dispatchv4 != NULL) {
185 		dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4);
186 	}
187 	requestmgr->dispatchv6 = NULL;
188 	if (dispatchv6 != NULL) {
189 		dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6);
190 	}
191 	requestmgr->mctx = NULL;
192 	isc_mem_attach(mctx, &requestmgr->mctx);
193 	requestmgr->eref = 1; /* implicit attach */
194 	requestmgr->iref = 0;
195 	ISC_LIST_INIT(requestmgr->whenshutdown);
196 	ISC_LIST_INIT(requestmgr->requests);
197 	requestmgr->exiting = false;
198 	requestmgr->hash = 0;
199 	requestmgr->magic = REQUESTMGR_MAGIC;
200 
201 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr);
202 
203 	*requestmgrp = requestmgr;
204 	return (ISC_R_SUCCESS);
205 }
206 
207 void
dns_requestmgr_whenshutdown(dns_requestmgr_t * requestmgr,isc_task_t * task,isc_event_t ** eventp)208 dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task,
209 			    isc_event_t **eventp) {
210 	isc_task_t *tclone;
211 	isc_event_t *event;
212 
213 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown");
214 
215 	REQUIRE(VALID_REQUESTMGR(requestmgr));
216 	REQUIRE(eventp != NULL);
217 
218 	event = *eventp;
219 	*eventp = NULL;
220 
221 	LOCK(&requestmgr->lock);
222 
223 	if (requestmgr->exiting) {
224 		/*
225 		 * We're already shutdown.  Send the event.
226 		 */
227 		event->ev_sender = requestmgr;
228 		isc_task_send(task, &event);
229 	} else {
230 		tclone = NULL;
231 		isc_task_attach(task, &tclone);
232 		event->ev_sender = tclone;
233 		ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link);
234 	}
235 	UNLOCK(&requestmgr->lock);
236 }
237 
238 void
dns_requestmgr_shutdown(dns_requestmgr_t * requestmgr)239 dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) {
240 	REQUIRE(VALID_REQUESTMGR(requestmgr));
241 
242 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr);
243 
244 	LOCK(&requestmgr->lock);
245 	mgr_shutdown(requestmgr);
246 	UNLOCK(&requestmgr->lock);
247 }
248 
249 static void
mgr_shutdown(dns_requestmgr_t * requestmgr)250 mgr_shutdown(dns_requestmgr_t *requestmgr) {
251 	dns_request_t *request;
252 
253 	/*
254 	 * Caller holds lock.
255 	 */
256 	if (!requestmgr->exiting) {
257 		requestmgr->exiting = true;
258 		for (request = ISC_LIST_HEAD(requestmgr->requests);
259 		     request != NULL; request = ISC_LIST_NEXT(request, link))
260 		{
261 			dns_request_cancel(request);
262 		}
263 		if (requestmgr->iref == 0) {
264 			INSIST(ISC_LIST_EMPTY(requestmgr->requests));
265 			send_shutdown_events(requestmgr);
266 		}
267 	}
268 }
269 
270 static void
requestmgr_attach(dns_requestmgr_t * source,dns_requestmgr_t ** targetp)271 requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
272 	/*
273 	 * Locked by caller.
274 	 */
275 
276 	REQUIRE(VALID_REQUESTMGR(source));
277 	REQUIRE(targetp != NULL && *targetp == NULL);
278 
279 	REQUIRE(!source->exiting);
280 
281 	source->iref++;
282 	*targetp = source;
283 
284 	req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d",
285 		source, source->eref, source->iref);
286 }
287 
288 static void
requestmgr_detach(dns_requestmgr_t ** requestmgrp)289 requestmgr_detach(dns_requestmgr_t **requestmgrp) {
290 	dns_requestmgr_t *requestmgr;
291 	bool need_destroy = false;
292 
293 	REQUIRE(requestmgrp != NULL);
294 	requestmgr = *requestmgrp;
295 	*requestmgrp = NULL;
296 	REQUIRE(VALID_REQUESTMGR(requestmgr));
297 
298 	LOCK(&requestmgr->lock);
299 	INSIST(requestmgr->iref > 0);
300 	requestmgr->iref--;
301 
302 	req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d",
303 		requestmgr, requestmgr->eref, requestmgr->iref);
304 
305 	if (requestmgr->iref == 0 && requestmgr->exiting) {
306 		INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL);
307 		send_shutdown_events(requestmgr);
308 		if (requestmgr->eref == 0) {
309 			need_destroy = true;
310 		}
311 	}
312 	UNLOCK(&requestmgr->lock);
313 
314 	if (need_destroy) {
315 		mgr_destroy(requestmgr);
316 	}
317 }
318 
319 void
dns_requestmgr_attach(dns_requestmgr_t * source,dns_requestmgr_t ** targetp)320 dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) {
321 	REQUIRE(VALID_REQUESTMGR(source));
322 	REQUIRE(targetp != NULL && *targetp == NULL);
323 	REQUIRE(!source->exiting);
324 
325 	LOCK(&source->lock);
326 	source->eref++;
327 	*targetp = source;
328 	UNLOCK(&source->lock);
329 
330 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d",
331 		source, source->eref, source->iref);
332 }
333 
334 void
dns_requestmgr_detach(dns_requestmgr_t ** requestmgrp)335 dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) {
336 	dns_requestmgr_t *requestmgr;
337 	bool need_destroy = false;
338 
339 	REQUIRE(requestmgrp != NULL);
340 	requestmgr = *requestmgrp;
341 	*requestmgrp = NULL;
342 	REQUIRE(VALID_REQUESTMGR(requestmgr));
343 
344 	LOCK(&requestmgr->lock);
345 	INSIST(requestmgr->eref > 0);
346 	requestmgr->eref--;
347 
348 	req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d",
349 		requestmgr, requestmgr->eref, requestmgr->iref);
350 
351 	if (requestmgr->eref == 0 && requestmgr->iref == 0) {
352 		INSIST(requestmgr->exiting &&
353 		       ISC_LIST_HEAD(requestmgr->requests) == NULL);
354 		need_destroy = true;
355 	}
356 	UNLOCK(&requestmgr->lock);
357 
358 	if (need_destroy) {
359 		mgr_destroy(requestmgr);
360 	}
361 }
362 
363 static void
send_shutdown_events(dns_requestmgr_t * requestmgr)364 send_shutdown_events(dns_requestmgr_t *requestmgr) {
365 	isc_event_t *event, *next_event;
366 	isc_task_t *etask;
367 
368 	req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr);
369 
370 	/*
371 	 * Caller must be holding the manager lock.
372 	 */
373 	for (event = ISC_LIST_HEAD(requestmgr->whenshutdown); event != NULL;
374 	     event = next_event)
375 	{
376 		next_event = ISC_LIST_NEXT(event, ev_link);
377 		ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link);
378 		etask = event->ev_sender;
379 		event->ev_sender = requestmgr;
380 		isc_task_sendanddetach(&etask, &event);
381 	}
382 }
383 
384 static void
mgr_destroy(dns_requestmgr_t * requestmgr)385 mgr_destroy(dns_requestmgr_t *requestmgr) {
386 	int i;
387 
388 	req_log(ISC_LOG_DEBUG(3), "mgr_destroy");
389 
390 	REQUIRE(requestmgr->eref == 0);
391 	REQUIRE(requestmgr->iref == 0);
392 
393 	isc_mutex_destroy(&requestmgr->lock);
394 	for (i = 0; i < DNS_REQUEST_NLOCKS; i++) {
395 		isc_mutex_destroy(&requestmgr->locks[i]);
396 	}
397 	if (requestmgr->dispatchv4 != NULL) {
398 		dns_dispatch_detach(&requestmgr->dispatchv4);
399 	}
400 	if (requestmgr->dispatchv6 != NULL) {
401 		dns_dispatch_detach(&requestmgr->dispatchv6);
402 	}
403 	requestmgr->magic = 0;
404 	isc_mem_putanddetach(&requestmgr->mctx, requestmgr,
405 			     sizeof(*requestmgr));
406 }
407 
408 static unsigned int
mgr_gethash(dns_requestmgr_t * requestmgr)409 mgr_gethash(dns_requestmgr_t *requestmgr) {
410 	req_log(ISC_LOG_DEBUG(3), "mgr_gethash");
411 	/*
412 	 * Locked by caller.
413 	 */
414 	requestmgr->hash++;
415 	return (requestmgr->hash % DNS_REQUEST_NLOCKS);
416 }
417 
418 static isc_result_t
req_send(dns_request_t * request,isc_task_t * task,const isc_sockaddr_t * address)419 req_send(dns_request_t *request, isc_task_t *task,
420 	 const isc_sockaddr_t *address) {
421 	isc_region_t r;
422 	isc_socket_t *sock;
423 	isc_socketevent_t *sendevent;
424 	isc_result_t result;
425 
426 	req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request);
427 
428 	REQUIRE(VALID_REQUEST(request));
429 	sock = req_getsocket(request);
430 	isc_buffer_usedregion(request->query, &r);
431 	/*
432 	 * We could connect the socket when we are using an exclusive dispatch
433 	 * as we do in resolver.c, but we prefer implementation simplicity
434 	 * at this moment.
435 	 */
436 	sendevent = isc_socket_socketevent(request->mctx, sock,
437 					   ISC_SOCKEVENT_SENDDONE, req_senddone,
438 					   request);
439 	if (sendevent == NULL) {
440 		return (ISC_R_NOMEMORY);
441 	}
442 	if (request->dscp == -1) {
443 		sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP;
444 		sendevent->dscp = 0;
445 	} else {
446 		sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP;
447 		sendevent->dscp = request->dscp;
448 	}
449 
450 	request->flags |= DNS_REQUEST_F_SENDING;
451 	result = isc_socket_sendto2(sock, &r, task, address, NULL, sendevent,
452 				    0);
453 	INSIST(result == ISC_R_SUCCESS);
454 	return (result);
455 }
456 
457 static isc_result_t
new_request(isc_mem_t * mctx,dns_request_t ** requestp)458 new_request(isc_mem_t *mctx, dns_request_t **requestp) {
459 	dns_request_t *request;
460 
461 	request = isc_mem_get(mctx, sizeof(*request));
462 
463 	/*
464 	 * Zero structure.
465 	 */
466 	request->magic = 0;
467 	request->mctx = NULL;
468 	request->flags = 0;
469 	ISC_LINK_INIT(request, link);
470 	request->query = NULL;
471 	request->answer = NULL;
472 	request->event = NULL;
473 	request->dispatch = NULL;
474 	request->dispentry = NULL;
475 	request->timer = NULL;
476 	request->requestmgr = NULL;
477 	request->tsig = NULL;
478 	request->tsigkey = NULL;
479 	request->dscp = -1;
480 	ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL,
481 		       DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL, NULL,
482 		       NULL);
483 	request->canceling = false;
484 	request->udpcount = 0;
485 
486 	isc_mem_attach(mctx, &request->mctx);
487 
488 	request->magic = REQUEST_MAGIC;
489 	*requestp = request;
490 	return (ISC_R_SUCCESS);
491 }
492 
493 static bool
isblackholed(dns_dispatchmgr_t * dispatchmgr,const isc_sockaddr_t * destaddr)494 isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) {
495 	dns_acl_t *blackhole;
496 	isc_netaddr_t netaddr;
497 	int match;
498 	bool drop = false;
499 	char netaddrstr[ISC_NETADDR_FORMATSIZE];
500 
501 	blackhole = dns_dispatchmgr_getblackhole(dispatchmgr);
502 	if (blackhole != NULL) {
503 		isc_netaddr_fromsockaddr(&netaddr, destaddr);
504 		if (dns_acl_match(&netaddr, NULL, blackhole, NULL, &match,
505 				  NULL) == ISC_R_SUCCESS &&
506 		    match > 0)
507 		{
508 			drop = true;
509 		}
510 	}
511 	if (drop) {
512 		isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr));
513 		req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr);
514 	}
515 	return (drop);
516 }
517 
518 static isc_result_t
create_tcp_dispatch(bool newtcp,bool share,dns_requestmgr_t * requestmgr,const isc_sockaddr_t * srcaddr,const isc_sockaddr_t * destaddr,isc_dscp_t dscp,bool * connected,dns_dispatch_t ** dispatchp)519 create_tcp_dispatch(bool newtcp, bool share, dns_requestmgr_t *requestmgr,
520 		    const isc_sockaddr_t *srcaddr,
521 		    const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
522 		    bool *connected, dns_dispatch_t **dispatchp) {
523 	isc_result_t result;
524 	isc_socket_t *sock = NULL;
525 	isc_sockaddr_t src;
526 	unsigned int attrs;
527 	isc_sockaddr_t bind_any;
528 
529 	if (!newtcp && share) {
530 		result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
531 					     srcaddr, connected, dispatchp);
532 		if (result == ISC_R_SUCCESS) {
533 			char peer[ISC_SOCKADDR_FORMATSIZE];
534 
535 			isc_sockaddr_format(destaddr, peer, sizeof(peer));
536 			req_log(ISC_LOG_DEBUG(1),
537 				"attached to %s TCP "
538 				"connection to %s",
539 				*connected ? "existing" : "pending", peer);
540 			return (result);
541 		}
542 	} else if (!newtcp) {
543 		result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr,
544 					     srcaddr, NULL, dispatchp);
545 		if (result == ISC_R_SUCCESS) {
546 			char peer[ISC_SOCKADDR_FORMATSIZE];
547 
548 			*connected = true;
549 			isc_sockaddr_format(destaddr, peer, sizeof(peer));
550 			req_log(ISC_LOG_DEBUG(1),
551 				"attached to existing TCP "
552 				"connection to %s",
553 				peer);
554 			return (result);
555 		}
556 	}
557 
558 	result = isc_socket_create(requestmgr->socketmgr,
559 				   isc_sockaddr_pf(destaddr),
560 				   isc_sockettype_tcp, &sock);
561 	if (result != ISC_R_SUCCESS) {
562 		return (result);
563 	}
564 #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT
565 	if (srcaddr == NULL) {
566 		isc_sockaddr_anyofpf(&bind_any, isc_sockaddr_pf(destaddr));
567 		result = isc_socket_bind(sock, &bind_any, 0);
568 	} else {
569 		src = *srcaddr;
570 		isc_sockaddr_setport(&src, 0);
571 		result = isc_socket_bind(sock, &src, 0);
572 	}
573 	if (result != ISC_R_SUCCESS) {
574 		goto cleanup;
575 	}
576 #endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */
577 
578 	attrs = 0;
579 	attrs |= DNS_DISPATCHATTR_TCP;
580 	if (isc_sockaddr_pf(destaddr) == AF_INET) {
581 		attrs |= DNS_DISPATCHATTR_IPV4;
582 	} else {
583 		attrs |= DNS_DISPATCHATTR_IPV6;
584 	}
585 	attrs |= DNS_DISPATCHATTR_MAKEQUERY;
586 
587 	isc_socket_dscp(sock, dscp);
588 	result = dns_dispatch_createtcp(
589 		requestmgr->dispatchmgr, sock, requestmgr->taskmgr, srcaddr,
590 		destaddr, 4096, 32768, 32768, 16411, 16433, attrs, dispatchp);
591 cleanup:
592 	isc_socket_detach(&sock);
593 	return (result);
594 }
595 
596 static isc_result_t
find_udp_dispatch(dns_requestmgr_t * requestmgr,const isc_sockaddr_t * srcaddr,const isc_sockaddr_t * destaddr,dns_dispatch_t ** dispatchp)597 find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr,
598 		  const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) {
599 	dns_dispatch_t *disp = NULL;
600 	unsigned int attrs, attrmask;
601 
602 	if (srcaddr == NULL) {
603 		switch (isc_sockaddr_pf(destaddr)) {
604 		case PF_INET:
605 			disp = requestmgr->dispatchv4;
606 			break;
607 
608 		case PF_INET6:
609 			disp = requestmgr->dispatchv6;
610 			break;
611 
612 		default:
613 			return (ISC_R_NOTIMPLEMENTED);
614 		}
615 		if (disp == NULL) {
616 			return (ISC_R_FAMILYNOSUPPORT);
617 		}
618 		dns_dispatch_attach(disp, dispatchp);
619 		return (ISC_R_SUCCESS);
620 	}
621 	attrs = 0;
622 	attrs |= DNS_DISPATCHATTR_UDP;
623 	switch (isc_sockaddr_pf(srcaddr)) {
624 	case PF_INET:
625 		attrs |= DNS_DISPATCHATTR_IPV4;
626 		break;
627 
628 	case PF_INET6:
629 		attrs |= DNS_DISPATCHATTR_IPV6;
630 		break;
631 
632 	default:
633 		return (ISC_R_NOTIMPLEMENTED);
634 	}
635 	attrmask = 0;
636 	attrmask |= DNS_DISPATCHATTR_UDP;
637 	attrmask |= DNS_DISPATCHATTR_TCP;
638 	attrmask |= DNS_DISPATCHATTR_IPV4;
639 	attrmask |= DNS_DISPATCHATTR_IPV6;
640 	return (dns_dispatch_getudp(requestmgr->dispatchmgr,
641 				    requestmgr->socketmgr, requestmgr->taskmgr,
642 				    srcaddr, 4096, 32768, 32768, 16411, 16433,
643 				    attrs, attrmask, dispatchp));
644 }
645 
646 static isc_result_t
get_dispatch(bool tcp,bool newtcp,bool share,dns_requestmgr_t * requestmgr,const isc_sockaddr_t * srcaddr,const isc_sockaddr_t * destaddr,isc_dscp_t dscp,bool * connected,dns_dispatch_t ** dispatchp)647 get_dispatch(bool tcp, bool newtcp, bool share, dns_requestmgr_t *requestmgr,
648 	     const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr,
649 	     isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) {
650 	isc_result_t result;
651 
652 	if (tcp) {
653 		result = create_tcp_dispatch(newtcp, share, requestmgr, srcaddr,
654 					     destaddr, dscp, connected,
655 					     dispatchp);
656 	} else {
657 		result = find_udp_dispatch(requestmgr, srcaddr, destaddr,
658 					   dispatchp);
659 	}
660 	return (result);
661 }
662 
663 static isc_result_t
set_timer(isc_timer_t * timer,unsigned int timeout,unsigned int udpresend)664 set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) {
665 	isc_time_t expires;
666 	isc_interval_t interval;
667 	isc_result_t result;
668 	isc_timertype_t timertype;
669 
670 	isc_interval_set(&interval, timeout, 0);
671 	result = isc_time_nowplusinterval(&expires, &interval);
672 	isc_interval_set(&interval, udpresend, 0);
673 
674 	timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once;
675 	if (result == ISC_R_SUCCESS) {
676 		result = isc_timer_reset(timer, timertype, &expires, &interval,
677 					 false);
678 	}
679 	return (result);
680 }
681 
682 isc_result_t
dns_request_createraw(dns_requestmgr_t * requestmgr,isc_buffer_t * msgbuf,const isc_sockaddr_t * srcaddr,const isc_sockaddr_t * destaddr,isc_dscp_t dscp,unsigned int options,unsigned int timeout,unsigned int udptimeout,unsigned int udpretries,isc_task_t * task,isc_taskaction_t action,void * arg,dns_request_t ** requestp)683 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf,
684 		      const isc_sockaddr_t *srcaddr,
685 		      const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
686 		      unsigned int options, unsigned int timeout,
687 		      unsigned int udptimeout, unsigned int udpretries,
688 		      isc_task_t *task, isc_taskaction_t action, void *arg,
689 		      dns_request_t **requestp) {
690 	dns_request_t *request = NULL;
691 	isc_task_t *tclone = NULL;
692 	isc_socket_t *sock = NULL;
693 	isc_result_t result;
694 	isc_mem_t *mctx;
695 	dns_messageid_t id;
696 	bool tcp = false;
697 	bool newtcp = false;
698 	bool share = false;
699 	isc_region_t r;
700 	bool connected = false;
701 	unsigned int dispopt = 0;
702 
703 	REQUIRE(VALID_REQUESTMGR(requestmgr));
704 	REQUIRE(msgbuf != NULL);
705 	REQUIRE(destaddr != NULL);
706 	REQUIRE(task != NULL);
707 	REQUIRE(action != NULL);
708 	REQUIRE(requestp != NULL && *requestp == NULL);
709 	REQUIRE(timeout > 0);
710 	if (srcaddr != NULL) {
711 		REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr));
712 	}
713 
714 	mctx = requestmgr->mctx;
715 
716 	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw");
717 
718 	if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
719 		return (DNS_R_BLACKHOLED);
720 	}
721 
722 	request = NULL;
723 	result = new_request(mctx, &request);
724 	if (result != ISC_R_SUCCESS) {
725 		return (result);
726 	}
727 
728 	if (udptimeout == 0 && udpretries != 0) {
729 		udptimeout = timeout / (udpretries + 1);
730 		if (udptimeout == 0) {
731 			udptimeout = 1;
732 		}
733 	}
734 	request->udpcount = udpretries;
735 	request->dscp = dscp;
736 
737 	/*
738 	 * Create timer now.  We will set it below once.
739 	 */
740 	result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
741 				  NULL, NULL, task, req_timeout, request,
742 				  &request->timer);
743 	if (result != ISC_R_SUCCESS) {
744 		goto cleanup;
745 	}
746 
747 	request->event = (dns_requestevent_t *)isc_event_allocate(
748 		mctx, task, DNS_EVENT_REQUESTDONE, action, arg,
749 		sizeof(dns_requestevent_t));
750 	isc_task_attach(task, &tclone);
751 	request->event->ev_sender = task;
752 	request->event->request = request;
753 	request->event->result = ISC_R_FAILURE;
754 
755 	isc_buffer_usedregion(msgbuf, &r);
756 	if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) {
757 		result = DNS_R_FORMERR;
758 		goto cleanup;
759 	}
760 
761 	if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) {
762 		tcp = true;
763 	}
764 	share = (options & DNS_REQUESTOPT_SHARE);
765 
766 again:
767 	result = get_dispatch(tcp, newtcp, share, requestmgr, srcaddr, destaddr,
768 			      dscp, &connected, &request->dispatch);
769 	if (result != ISC_R_SUCCESS) {
770 		goto cleanup;
771 	}
772 
773 	if ((options & DNS_REQUESTOPT_FIXEDID) != 0) {
774 		id = (r.base[0] << 8) | r.base[1];
775 		dispopt |= DNS_DISPATCHOPT_FIXEDID;
776 	}
777 
778 	result = dns_dispatch_addresponse(
779 		request->dispatch, dispopt, destaddr, task, req_response,
780 		request, &id, &request->dispentry, requestmgr->socketmgr);
781 	if (result != ISC_R_SUCCESS) {
782 		if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) {
783 			newtcp = true;
784 			connected = false;
785 			dns_dispatch_detach(&request->dispatch);
786 			goto again;
787 		}
788 		goto cleanup;
789 	}
790 
791 	sock = req_getsocket(request);
792 	INSIST(sock != NULL);
793 
794 	isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0));
795 	if (tcp) {
796 		isc_buffer_putuint16(request->query, (uint16_t)r.length);
797 	}
798 	result = isc_buffer_copyregion(request->query, &r);
799 	if (result != ISC_R_SUCCESS) {
800 		goto cleanup;
801 	}
802 
803 	/* Add message ID. */
804 	isc_buffer_usedregion(request->query, &r);
805 	if (tcp) {
806 		isc_region_consume(&r, 2);
807 	}
808 	r.base[0] = (id >> 8) & 0xff;
809 	r.base[1] = id & 0xff;
810 
811 	LOCK(&requestmgr->lock);
812 	if (requestmgr->exiting) {
813 		UNLOCK(&requestmgr->lock);
814 		result = ISC_R_SHUTTINGDOWN;
815 		goto cleanup;
816 	}
817 	requestmgr_attach(requestmgr, &request->requestmgr);
818 	request->hash = mgr_gethash(requestmgr);
819 	ISC_LIST_APPEND(requestmgr->requests, request, link);
820 	UNLOCK(&requestmgr->lock);
821 
822 	result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
823 	if (result != ISC_R_SUCCESS) {
824 		goto unlink;
825 	}
826 
827 	request->destaddr = *destaddr;
828 	if (tcp && !connected) {
829 		result = isc_socket_connect(sock, destaddr, task, req_connected,
830 					    request);
831 		if (result != ISC_R_SUCCESS) {
832 			goto unlink;
833 		}
834 		request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP;
835 	} else {
836 		result = req_send(request, task, connected ? NULL : destaddr);
837 		if (result != ISC_R_SUCCESS) {
838 			goto unlink;
839 		}
840 	}
841 
842 	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request);
843 	*requestp = request;
844 	return (ISC_R_SUCCESS);
845 
846 unlink:
847 	LOCK(&requestmgr->lock);
848 	ISC_LIST_UNLINK(requestmgr->requests, request, link);
849 	UNLOCK(&requestmgr->lock);
850 
851 cleanup:
852 	if (tclone != NULL) {
853 		isc_task_detach(&tclone);
854 	}
855 	req_destroy(request);
856 	req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s",
857 		dns_result_totext(result));
858 	return (result);
859 }
860 
861 isc_result_t
dns_request_create(dns_requestmgr_t * requestmgr,dns_message_t * message,const isc_sockaddr_t * address,unsigned int options,dns_tsigkey_t * key,unsigned int timeout,isc_task_t * task,isc_taskaction_t action,void * arg,dns_request_t ** requestp)862 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message,
863 		   const isc_sockaddr_t *address, unsigned int options,
864 		   dns_tsigkey_t *key, unsigned int timeout, isc_task_t *task,
865 		   isc_taskaction_t action, void *arg,
866 		   dns_request_t **requestp) {
867 	return (dns_request_createvia(requestmgr, message, NULL, address, -1,
868 				      options, key, timeout, 0, 0, task, action,
869 				      arg, requestp));
870 }
871 
872 isc_result_t
dns_request_createvia(dns_requestmgr_t * requestmgr,dns_message_t * message,const isc_sockaddr_t * srcaddr,const isc_sockaddr_t * destaddr,isc_dscp_t dscp,unsigned int options,dns_tsigkey_t * key,unsigned int timeout,unsigned int udptimeout,unsigned int udpretries,isc_task_t * task,isc_taskaction_t action,void * arg,dns_request_t ** requestp)873 dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message,
874 		      const isc_sockaddr_t *srcaddr,
875 		      const isc_sockaddr_t *destaddr, isc_dscp_t dscp,
876 		      unsigned int options, dns_tsigkey_t *key,
877 		      unsigned int timeout, unsigned int udptimeout,
878 		      unsigned int udpretries, isc_task_t *task,
879 		      isc_taskaction_t action, void *arg,
880 		      dns_request_t **requestp) {
881 	dns_request_t *request = NULL;
882 	isc_task_t *tclone = NULL;
883 	isc_socket_t *sock = NULL;
884 	isc_result_t result;
885 	isc_mem_t *mctx;
886 	dns_messageid_t id;
887 	bool tcp;
888 	bool share;
889 	bool settsigkey = true;
890 	bool connected = false;
891 
892 	REQUIRE(VALID_REQUESTMGR(requestmgr));
893 	REQUIRE(message != NULL);
894 	REQUIRE(destaddr != NULL);
895 	REQUIRE(task != NULL);
896 	REQUIRE(action != NULL);
897 	REQUIRE(requestp != NULL && *requestp == NULL);
898 	REQUIRE(timeout > 0);
899 
900 	mctx = requestmgr->mctx;
901 
902 	req_log(ISC_LOG_DEBUG(3), "dns_request_createvia");
903 
904 	if (srcaddr != NULL &&
905 	    isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr))
906 	{
907 		return (ISC_R_FAMILYMISMATCH);
908 	}
909 
910 	if (isblackholed(requestmgr->dispatchmgr, destaddr)) {
911 		return (DNS_R_BLACKHOLED);
912 	}
913 
914 	request = NULL;
915 	result = new_request(mctx, &request);
916 	if (result != ISC_R_SUCCESS) {
917 		return (result);
918 	}
919 
920 	if (udptimeout == 0 && udpretries != 0) {
921 		udptimeout = timeout / (udpretries + 1);
922 		if (udptimeout == 0) {
923 			udptimeout = 1;
924 		}
925 	}
926 	request->udpcount = udpretries;
927 	request->dscp = dscp;
928 
929 	/*
930 	 * Create timer now.  We will set it below once.
931 	 */
932 	result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive,
933 				  NULL, NULL, task, req_timeout, request,
934 				  &request->timer);
935 	if (result != ISC_R_SUCCESS) {
936 		goto cleanup;
937 	}
938 
939 	request->event = (dns_requestevent_t *)isc_event_allocate(
940 		mctx, task, DNS_EVENT_REQUESTDONE, action, arg,
941 		sizeof(dns_requestevent_t));
942 	isc_task_attach(task, &tclone);
943 	request->event->ev_sender = task;
944 	request->event->request = request;
945 	request->event->result = ISC_R_FAILURE;
946 	if (key != NULL) {
947 		dns_tsigkey_attach(key, &request->tsigkey);
948 	}
949 
950 use_tcp:
951 	tcp = ((options & DNS_REQUESTOPT_TCP) != 0);
952 	share = ((options & DNS_REQUESTOPT_SHARE) != 0);
953 	result = get_dispatch(tcp, false, share, requestmgr, srcaddr, destaddr,
954 			      dscp, &connected, &request->dispatch);
955 	if (result != ISC_R_SUCCESS) {
956 		goto cleanup;
957 	}
958 
959 	result = dns_dispatch_addresponse(
960 		request->dispatch, 0, destaddr, task, req_response, request,
961 		&id, &request->dispentry, requestmgr->socketmgr);
962 	if (result != ISC_R_SUCCESS) {
963 		goto cleanup;
964 	}
965 	sock = req_getsocket(request);
966 	INSIST(sock != NULL);
967 
968 	message->id = id;
969 	if (settsigkey) {
970 		result = dns_message_settsigkey(message, request->tsigkey);
971 		if (result != ISC_R_SUCCESS) {
972 			goto cleanup;
973 		}
974 	}
975 	result = req_render(message, &request->query, options, mctx);
976 	if (result == DNS_R_USETCP && (options & DNS_REQUESTOPT_TCP) == 0) {
977 		/*
978 		 * Try again using TCP.
979 		 */
980 		dns_message_renderreset(message);
981 		dns_dispatch_removeresponse(&request->dispentry, NULL);
982 		dns_dispatch_detach(&request->dispatch);
983 		sock = NULL;
984 		options |= DNS_REQUESTOPT_TCP;
985 		settsigkey = false;
986 		goto use_tcp;
987 	}
988 	if (result != ISC_R_SUCCESS) {
989 		goto cleanup;
990 	}
991 
992 	result = dns_message_getquerytsig(message, mctx, &request->tsig);
993 	if (result != ISC_R_SUCCESS) {
994 		goto cleanup;
995 	}
996 
997 	LOCK(&requestmgr->lock);
998 	if (requestmgr->exiting) {
999 		UNLOCK(&requestmgr->lock);
1000 		result = ISC_R_SHUTTINGDOWN;
1001 		goto cleanup;
1002 	}
1003 	requestmgr_attach(requestmgr, &request->requestmgr);
1004 	request->hash = mgr_gethash(requestmgr);
1005 	ISC_LIST_APPEND(requestmgr->requests, request, link);
1006 	UNLOCK(&requestmgr->lock);
1007 
1008 	result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout);
1009 	if (result != ISC_R_SUCCESS) {
1010 		goto unlink;
1011 	}
1012 
1013 	request->destaddr = *destaddr;
1014 	if (tcp && !connected) {
1015 		result = isc_socket_connect(sock, destaddr, task, req_connected,
1016 					    request);
1017 		if (result != ISC_R_SUCCESS) {
1018 			goto unlink;
1019 		}
1020 		request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP;
1021 	} else {
1022 		result = req_send(request, task, connected ? NULL : destaddr);
1023 		if (result != ISC_R_SUCCESS) {
1024 			goto unlink;
1025 		}
1026 	}
1027 
1028 	req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request);
1029 	*requestp = request;
1030 	return (ISC_R_SUCCESS);
1031 
1032 unlink:
1033 	LOCK(&requestmgr->lock);
1034 	ISC_LIST_UNLINK(requestmgr->requests, request, link);
1035 	UNLOCK(&requestmgr->lock);
1036 
1037 cleanup:
1038 	if (tclone != NULL) {
1039 		isc_task_detach(&tclone);
1040 	}
1041 	req_destroy(request);
1042 	req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s",
1043 		dns_result_totext(result));
1044 	return (result);
1045 }
1046 
1047 static isc_result_t
req_render(dns_message_t * message,isc_buffer_t ** bufferp,unsigned int options,isc_mem_t * mctx)1048 req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options,
1049 	   isc_mem_t *mctx) {
1050 	isc_buffer_t *buf1 = NULL;
1051 	isc_buffer_t *buf2 = NULL;
1052 	isc_result_t result;
1053 	isc_region_t r;
1054 	bool tcp = false;
1055 	dns_compress_t cctx;
1056 	bool cleanup_cctx = false;
1057 
1058 	REQUIRE(bufferp != NULL && *bufferp == NULL);
1059 
1060 	req_log(ISC_LOG_DEBUG(3), "request_render");
1061 
1062 	/*
1063 	 * Create buffer able to hold largest possible message.
1064 	 */
1065 	isc_buffer_allocate(mctx, &buf1, 65535);
1066 
1067 	result = dns_compress_init(&cctx, -1, mctx);
1068 	if (result != ISC_R_SUCCESS) {
1069 		return (result);
1070 	}
1071 	cleanup_cctx = true;
1072 
1073 	if ((options & DNS_REQUESTOPT_CASE) != 0) {
1074 		dns_compress_setsensitive(&cctx, true);
1075 	}
1076 
1077 	/*
1078 	 * Render message.
1079 	 */
1080 	result = dns_message_renderbegin(message, &cctx, buf1);
1081 	if (result != ISC_R_SUCCESS) {
1082 		goto cleanup;
1083 	}
1084 	result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0);
1085 	if (result != ISC_R_SUCCESS) {
1086 		goto cleanup;
1087 	}
1088 	result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0);
1089 	if (result != ISC_R_SUCCESS) {
1090 		goto cleanup;
1091 	}
1092 	result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0);
1093 	if (result != ISC_R_SUCCESS) {
1094 		goto cleanup;
1095 	}
1096 	result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0);
1097 	if (result != ISC_R_SUCCESS) {
1098 		goto cleanup;
1099 	}
1100 	result = dns_message_renderend(message);
1101 	if (result != ISC_R_SUCCESS) {
1102 		goto cleanup;
1103 	}
1104 
1105 	dns_compress_invalidate(&cctx);
1106 	cleanup_cctx = false;
1107 
1108 	/*
1109 	 * Copy rendered message to exact sized buffer.
1110 	 */
1111 	isc_buffer_usedregion(buf1, &r);
1112 	if ((options & DNS_REQUESTOPT_TCP) != 0) {
1113 		tcp = true;
1114 	} else if (r.length > 512) {
1115 		result = DNS_R_USETCP;
1116 		goto cleanup;
1117 	}
1118 	isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0));
1119 	if (tcp) {
1120 		isc_buffer_putuint16(buf2, (uint16_t)r.length);
1121 	}
1122 	result = isc_buffer_copyregion(buf2, &r);
1123 	if (result != ISC_R_SUCCESS) {
1124 		goto cleanup;
1125 	}
1126 
1127 	/*
1128 	 * Cleanup and return.
1129 	 */
1130 	isc_buffer_free(&buf1);
1131 	*bufferp = buf2;
1132 	return (ISC_R_SUCCESS);
1133 
1134 cleanup:
1135 	dns_message_renderreset(message);
1136 	if (buf1 != NULL) {
1137 		isc_buffer_free(&buf1);
1138 	}
1139 	if (buf2 != NULL) {
1140 		isc_buffer_free(&buf2);
1141 	}
1142 	if (cleanup_cctx) {
1143 		dns_compress_invalidate(&cctx);
1144 	}
1145 	return (result);
1146 }
1147 
1148 /*
1149  * If this request is no longer waiting for events,
1150  * send the completion event.  This will ultimately
1151  * cause the request to be destroyed.
1152  *
1153  * Requires:
1154  *	'request' is locked by the caller.
1155  */
1156 static void
send_if_done(dns_request_t * request,isc_result_t result)1157 send_if_done(dns_request_t *request, isc_result_t result) {
1158 	if (request->event != NULL && !request->canceling) {
1159 		req_sendevent(request, result);
1160 	}
1161 }
1162 
1163 /*
1164  * Handle the control event.
1165  */
1166 static void
do_cancel(isc_task_t * task,isc_event_t * event)1167 do_cancel(isc_task_t *task, isc_event_t *event) {
1168 	dns_request_t *request = event->ev_arg;
1169 	UNUSED(task);
1170 	INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL);
1171 	LOCK(&request->requestmgr->locks[request->hash]);
1172 	request->canceling = false;
1173 	if (!DNS_REQUEST_CANCELED(request)) {
1174 		req_cancel(request);
1175 	}
1176 	send_if_done(request, ISC_R_CANCELED);
1177 	UNLOCK(&request->requestmgr->locks[request->hash]);
1178 }
1179 
1180 void
dns_request_cancel(dns_request_t * request)1181 dns_request_cancel(dns_request_t *request) {
1182 	REQUIRE(VALID_REQUEST(request));
1183 
1184 	req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request);
1185 
1186 	REQUIRE(VALID_REQUEST(request));
1187 
1188 	LOCK(&request->requestmgr->locks[request->hash]);
1189 	if (!request->canceling && !DNS_REQUEST_CANCELED(request)) {
1190 		isc_event_t *ev = &request->ctlevent;
1191 		isc_task_send(request->event->ev_sender, &ev);
1192 		request->canceling = true;
1193 	}
1194 	UNLOCK(&request->requestmgr->locks[request->hash]);
1195 }
1196 
1197 isc_result_t
dns_request_getresponse(dns_request_t * request,dns_message_t * message,unsigned int options)1198 dns_request_getresponse(dns_request_t *request, dns_message_t *message,
1199 			unsigned int options) {
1200 	isc_result_t result;
1201 
1202 	REQUIRE(VALID_REQUEST(request));
1203 	REQUIRE(request->answer != NULL);
1204 
1205 	req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p",
1206 		request);
1207 
1208 	result = dns_message_setquerytsig(message, request->tsig);
1209 	if (result != ISC_R_SUCCESS) {
1210 		return (result);
1211 	}
1212 	result = dns_message_settsigkey(message, request->tsigkey);
1213 	if (result != ISC_R_SUCCESS) {
1214 		return (result);
1215 	}
1216 	result = dns_message_parse(message, request->answer, options);
1217 	if (result != ISC_R_SUCCESS) {
1218 		return (result);
1219 	}
1220 	if (request->tsigkey != NULL) {
1221 		result = dns_tsig_verify(request->answer, message, NULL, NULL);
1222 	}
1223 	return (result);
1224 }
1225 
1226 isc_buffer_t *
dns_request_getanswer(dns_request_t * request)1227 dns_request_getanswer(dns_request_t *request) {
1228 	REQUIRE(VALID_REQUEST(request));
1229 
1230 	return (request->answer);
1231 }
1232 
1233 bool
dns_request_usedtcp(dns_request_t * request)1234 dns_request_usedtcp(dns_request_t *request) {
1235 	REQUIRE(VALID_REQUEST(request));
1236 
1237 	return ((request->flags & DNS_REQUEST_F_TCP) != 0);
1238 }
1239 
1240 void
dns_request_destroy(dns_request_t ** requestp)1241 dns_request_destroy(dns_request_t **requestp) {
1242 	dns_request_t *request;
1243 
1244 	REQUIRE(requestp != NULL && VALID_REQUEST(*requestp));
1245 
1246 	request = *requestp;
1247 	*requestp = NULL;
1248 
1249 	req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request);
1250 
1251 	LOCK(&request->requestmgr->lock);
1252 	LOCK(&request->requestmgr->locks[request->hash]);
1253 	ISC_LIST_UNLINK(request->requestmgr->requests, request, link);
1254 	INSIST(!DNS_REQUEST_CONNECTING(request));
1255 	INSIST(!DNS_REQUEST_SENDING(request));
1256 	UNLOCK(&request->requestmgr->locks[request->hash]);
1257 	UNLOCK(&request->requestmgr->lock);
1258 
1259 	/*
1260 	 * These should have been cleaned up by req_cancel() before
1261 	 * the completion event was sent.
1262 	 */
1263 	INSIST(!ISC_LINK_LINKED(request, link));
1264 	INSIST(request->dispentry == NULL);
1265 	INSIST(request->dispatch == NULL);
1266 	INSIST(request->timer == NULL);
1267 
1268 	req_destroy(request);
1269 }
1270 
1271 /***
1272  *** Private: request.
1273  ***/
1274 
1275 static isc_socket_t *
req_getsocket(dns_request_t * request)1276 req_getsocket(dns_request_t *request) {
1277 	unsigned int dispattr;
1278 	isc_socket_t *sock;
1279 
1280 	dispattr = dns_dispatch_getattributes(request->dispatch);
1281 	if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1282 		INSIST(request->dispentry != NULL);
1283 		sock = dns_dispatch_getentrysocket(request->dispentry);
1284 	} else {
1285 		sock = dns_dispatch_getsocket(request->dispatch);
1286 	}
1287 
1288 	return (sock);
1289 }
1290 
1291 static void
req_connected(isc_task_t * task,isc_event_t * event)1292 req_connected(isc_task_t *task, isc_event_t *event) {
1293 	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1294 	isc_result_t result;
1295 	dns_request_t *request = event->ev_arg;
1296 
1297 	REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
1298 	REQUIRE(VALID_REQUEST(request));
1299 	REQUIRE(DNS_REQUEST_CONNECTING(request));
1300 
1301 	req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request);
1302 
1303 	result = sevent->result;
1304 	isc_event_free(&event);
1305 
1306 	LOCK(&request->requestmgr->locks[request->hash]);
1307 	request->flags &= ~DNS_REQUEST_F_CONNECTING;
1308 
1309 	if (DNS_REQUEST_CANCELED(request)) {
1310 		/*
1311 		 * Send delayed event.
1312 		 */
1313 		if (DNS_REQUEST_TIMEDOUT(request)) {
1314 			send_if_done(request, ISC_R_TIMEDOUT);
1315 		} else {
1316 			send_if_done(request, ISC_R_CANCELED);
1317 		}
1318 	} else {
1319 		dns_dispatch_starttcp(request->dispatch);
1320 		if (result == ISC_R_SUCCESS) {
1321 			result = req_send(request, task, NULL);
1322 		}
1323 
1324 		if (result != ISC_R_SUCCESS) {
1325 			req_cancel(request);
1326 			send_if_done(request, ISC_R_CANCELED);
1327 		}
1328 	}
1329 	UNLOCK(&request->requestmgr->locks[request->hash]);
1330 }
1331 
1332 static void
req_senddone(isc_task_t * task,isc_event_t * event)1333 req_senddone(isc_task_t *task, isc_event_t *event) {
1334 	isc_socketevent_t *sevent = (isc_socketevent_t *)event;
1335 	dns_request_t *request = event->ev_arg;
1336 	isc_result_t result = sevent->result;
1337 
1338 	REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
1339 	REQUIRE(VALID_REQUEST(request));
1340 	REQUIRE(DNS_REQUEST_SENDING(request));
1341 
1342 	req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request);
1343 
1344 	UNUSED(task);
1345 
1346 	isc_event_free(&event);
1347 
1348 	LOCK(&request->requestmgr->locks[request->hash]);
1349 	request->flags &= ~DNS_REQUEST_F_SENDING;
1350 
1351 	if (DNS_REQUEST_CANCELED(request)) {
1352 		/*
1353 		 * Send delayed event.
1354 		 */
1355 		if (DNS_REQUEST_TIMEDOUT(request)) {
1356 			send_if_done(request, ISC_R_TIMEDOUT);
1357 		} else {
1358 			send_if_done(request, ISC_R_CANCELED);
1359 		}
1360 	} else if (result != ISC_R_SUCCESS) {
1361 		req_cancel(request);
1362 		send_if_done(request, ISC_R_CANCELED);
1363 	}
1364 	UNLOCK(&request->requestmgr->locks[request->hash]);
1365 }
1366 
1367 static void
req_response(isc_task_t * task,isc_event_t * event)1368 req_response(isc_task_t *task, isc_event_t *event) {
1369 	isc_result_t result;
1370 	dns_request_t *request = event->ev_arg;
1371 	dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
1372 	isc_region_t r;
1373 
1374 	REQUIRE(VALID_REQUEST(request));
1375 	REQUIRE(event->ev_type == DNS_EVENT_DISPATCH);
1376 
1377 	UNUSED(task);
1378 
1379 	req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request,
1380 		dns_result_totext(devent->result));
1381 
1382 	LOCK(&request->requestmgr->locks[request->hash]);
1383 	result = devent->result;
1384 	if (result != ISC_R_SUCCESS) {
1385 		goto done;
1386 	}
1387 
1388 	/*
1389 	 * Copy buffer to request.
1390 	 */
1391 	isc_buffer_usedregion(&devent->buffer, &r);
1392 	isc_buffer_allocate(request->mctx, &request->answer, r.length);
1393 	result = isc_buffer_copyregion(request->answer, &r);
1394 	if (result != ISC_R_SUCCESS) {
1395 		isc_buffer_free(&request->answer);
1396 	}
1397 done:
1398 	/*
1399 	 * Cleanup.
1400 	 */
1401 	dns_dispatch_removeresponse(&request->dispentry, &devent);
1402 	req_cancel(request);
1403 	/*
1404 	 * Send completion event.
1405 	 */
1406 	send_if_done(request, result);
1407 	UNLOCK(&request->requestmgr->locks[request->hash]);
1408 }
1409 
1410 static void
req_timeout(isc_task_t * task,isc_event_t * event)1411 req_timeout(isc_task_t *task, isc_event_t *event) {
1412 	dns_request_t *request = event->ev_arg;
1413 	isc_result_t result;
1414 	isc_eventtype_t ev_type = event->ev_type;
1415 
1416 	REQUIRE(VALID_REQUEST(request));
1417 
1418 	req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request);
1419 
1420 	UNUSED(task);
1421 
1422 	isc_event_free(&event);
1423 
1424 	LOCK(&request->requestmgr->locks[request->hash]);
1425 	if (ev_type == ISC_TIMEREVENT_TICK && request->udpcount-- != 0) {
1426 		if (!DNS_REQUEST_SENDING(request)) {
1427 			result = req_send(request, task, &request->destaddr);
1428 			if (result != ISC_R_SUCCESS) {
1429 				req_cancel(request);
1430 				send_if_done(request, result);
1431 			}
1432 		}
1433 	} else {
1434 		request->flags |= DNS_REQUEST_F_TIMEDOUT;
1435 		req_cancel(request);
1436 		send_if_done(request, ISC_R_TIMEDOUT);
1437 	}
1438 	UNLOCK(&request->requestmgr->locks[request->hash]);
1439 }
1440 
1441 static void
req_sendevent(dns_request_t * request,isc_result_t result)1442 req_sendevent(dns_request_t *request, isc_result_t result) {
1443 	isc_task_t *task;
1444 
1445 	REQUIRE(VALID_REQUEST(request));
1446 
1447 	req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request);
1448 
1449 	/*
1450 	 * Lock held by caller.
1451 	 */
1452 	task = request->event->ev_sender;
1453 	request->event->ev_sender = request;
1454 	request->event->result = result;
1455 	isc_task_sendanddetach(&task, (isc_event_t **)(void *)&request->event);
1456 }
1457 
1458 static void
req_destroy(dns_request_t * request)1459 req_destroy(dns_request_t *request) {
1460 	REQUIRE(VALID_REQUEST(request));
1461 
1462 	req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request);
1463 
1464 	request->magic = 0;
1465 	if (request->query != NULL) {
1466 		isc_buffer_free(&request->query);
1467 	}
1468 	if (request->answer != NULL) {
1469 		isc_buffer_free(&request->answer);
1470 	}
1471 	if (request->event != NULL) {
1472 		isc_event_free((isc_event_t **)(void *)&request->event);
1473 	}
1474 	if (request->dispentry != NULL) {
1475 		dns_dispatch_removeresponse(&request->dispentry, NULL);
1476 	}
1477 	if (request->dispatch != NULL) {
1478 		dns_dispatch_detach(&request->dispatch);
1479 	}
1480 	if (request->timer != NULL) {
1481 		isc_timer_destroy(&request->timer);
1482 	}
1483 	if (request->tsig != NULL) {
1484 		isc_buffer_free(&request->tsig);
1485 	}
1486 	if (request->tsigkey != NULL) {
1487 		dns_tsigkey_detach(&request->tsigkey);
1488 	}
1489 	if (request->requestmgr != NULL) {
1490 		requestmgr_detach(&request->requestmgr);
1491 	}
1492 	isc_mem_putanddetach(&request->mctx, request, sizeof(*request));
1493 }
1494 
1495 /*
1496  * Stop the current request.  Must be called from the request's task.
1497  */
1498 static void
req_cancel(dns_request_t * request)1499 req_cancel(dns_request_t *request) {
1500 	isc_socket_t *sock;
1501 	unsigned int dispattr;
1502 
1503 	REQUIRE(VALID_REQUEST(request));
1504 
1505 	req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request);
1506 
1507 	/*
1508 	 * Lock held by caller.
1509 	 */
1510 	request->flags |= DNS_REQUEST_F_CANCELED;
1511 
1512 	if (request->timer != NULL) {
1513 		isc_timer_destroy(&request->timer);
1514 	}
1515 	dispattr = dns_dispatch_getattributes(request->dispatch);
1516 	sock = NULL;
1517 	if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) {
1518 		if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
1519 			if (request->dispentry != NULL) {
1520 				sock = dns_dispatch_getentrysocket(
1521 					request->dispentry);
1522 			}
1523 		} else {
1524 			sock = dns_dispatch_getsocket(request->dispatch);
1525 		}
1526 		if (DNS_REQUEST_CONNECTING(request) && sock != NULL) {
1527 			isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT);
1528 		}
1529 		if (DNS_REQUEST_SENDING(request) && sock != NULL) {
1530 			isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND);
1531 		}
1532 	}
1533 	if (request->dispentry != NULL) {
1534 		dns_dispatch_removeresponse(&request->dispentry, NULL);
1535 	}
1536 	dns_dispatch_detach(&request->dispatch);
1537 }
1538 
1539 static void
req_log(int level,const char * fmt,...)1540 req_log(int level, const char *fmt, ...) {
1541 	va_list ap;
1542 
1543 	va_start(ap, fmt);
1544 	isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST,
1545 		       level, fmt, ap);
1546 	va_end(ap);
1547 }
1548