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