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