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