1 /* $NetBSD: request.c,v 1.15 2026/05/20 16:53:45 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_cancel() */ 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_cancel(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_CANCELED); 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_cancel(requestmgr); 223 continue; 224 } 225 226 isc_loop_t *loop = isc_loop_get(requestmgr->loopmgr, i); 227 isc_async_run(loop, requests_cancel, 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(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, 342 const isc_sockaddr_t *destaddr, dns_transport_t *transport, 343 unsigned int dispopt, dns_dispatch_t **dispatchp) { 344 return dns_dispatch_createtcp( 345 requestmgr->dispatchmgr, srcaddr, destaddr, transport, 346 DNS_DISPATCHTYPE_REQUEST, dispopt, dispatchp); 347 } 348 349 static isc_result_t 350 udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, 351 const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) { 352 dns_dispatch_t *disp = NULL; 353 354 if (srcaddr == NULL) { 355 switch (isc_sockaddr_pf(destaddr)) { 356 case PF_INET: 357 disp = dns_dispatchset_get(requestmgr->dispatches4); 358 break; 359 360 case PF_INET6: 361 disp = dns_dispatchset_get(requestmgr->dispatches6); 362 break; 363 364 default: 365 return ISC_R_NOTIMPLEMENTED; 366 } 367 if (disp == NULL) { 368 return ISC_R_FAMILYNOSUPPORT; 369 } 370 dns_dispatch_attach(disp, dispatchp); 371 return ISC_R_SUCCESS; 372 } 373 374 return dns_dispatch_createudp(requestmgr->dispatchmgr, srcaddr, 375 dispatchp); 376 } 377 378 static isc_result_t 379 get_dispatch(bool tcp, dns_requestmgr_t *requestmgr, 380 const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, 381 dns_transport_t *transport, unsigned int dispopt, 382 dns_dispatch_t **dispatchp) { 383 isc_result_t result; 384 385 if (tcp) { 386 result = tcp_dispatch(requestmgr, srcaddr, destaddr, transport, 387 dispopt, dispatchp); 388 } else { 389 result = udp_dispatch(requestmgr, srcaddr, destaddr, dispatchp); 390 } 391 return result; 392 } 393 394 isc_result_t 395 dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, 396 const isc_sockaddr_t *srcaddr, 397 const isc_sockaddr_t *destaddr, 398 dns_transport_t *transport, 399 isc_tlsctx_cache_t *tlsctx_cache, unsigned int options, 400 unsigned int timeout, unsigned int udptimeout, 401 unsigned int udpretries, isc_loop_t *loop, isc_job_cb cb, 402 void *arg, dns_request_t **requestp) { 403 dns_request_t *request = NULL; 404 isc_result_t result; 405 isc_mem_t *mctx = NULL; 406 dns_messageid_t id; 407 bool tcp = false; 408 isc_region_t r; 409 unsigned int dispopt = 0; 410 411 REQUIRE(VALID_REQUESTMGR(requestmgr)); 412 REQUIRE(msgbuf != NULL); 413 REQUIRE(destaddr != NULL); 414 REQUIRE(loop != NULL); 415 REQUIRE(cb != NULL); 416 REQUIRE(requestp != NULL && *requestp == NULL); 417 REQUIRE(timeout > 0); 418 REQUIRE(udpretries != UINT_MAX); 419 420 if (srcaddr != NULL) { 421 REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr)); 422 } 423 424 mctx = requestmgr->mctx; 425 426 req_log(ISC_LOG_DEBUG(3), "%s", __func__); 427 428 rcu_read_lock(); 429 430 if (atomic_load_acquire(&requestmgr->shuttingdown)) { 431 result = ISC_R_SHUTTINGDOWN; 432 goto done; 433 } 434 435 if (isblackholed(requestmgr->dispatchmgr, destaddr)) { 436 result = DNS_R_BLACKHOLED; 437 goto done; 438 } 439 440 isc_buffer_usedregion(msgbuf, &r); 441 if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) { 442 result = DNS_R_FORMERR; 443 goto done; 444 } 445 446 if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) { 447 tcp = true; 448 } 449 450 request = new_request(mctx, loop, cb, arg, tcp, timeout, udptimeout, 451 udpretries); 452 453 isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); 454 result = isc_buffer_copyregion(request->query, &r); 455 if (result != ISC_R_SUCCESS) { 456 goto cleanup; 457 } 458 459 if ((options & DNS_REQUESTOPT_FIXEDID) != 0) { 460 id = (r.base[0] << 8) | r.base[1]; 461 dispopt |= DNS_DISPATCHOPT_FIXEDID; 462 } 463 464 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport, 465 dispopt, &request->dispatch); 466 if (result != ISC_R_SUCCESS) { 467 goto cleanup; 468 } 469 470 result = dns_dispatch_add( 471 request->dispatch, loop, dispopt, request->timeout, destaddr, 472 transport, tlsctx_cache, req_connected, req_senddone, 473 req_response, request, &id, &request->dispentry); 474 if (result != ISC_R_SUCCESS) { 475 goto cleanup; 476 } 477 478 /* Add message ID. */ 479 isc_buffer_usedregion(request->query, &r); 480 r.base[0] = (id >> 8) & 0xff; 481 r.base[1] = id & 0xff; 482 483 request->destaddr = *destaddr; 484 request->flags |= DNS_REQUEST_F_CONNECTING; 485 if (tcp) { 486 request->flags |= DNS_REQUEST_F_TCP; 487 } 488 489 dns_requestmgr_attach(requestmgr, &request->requestmgr); 490 ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link); 491 492 dns_request_ref(request); /* detached in req_connected() */ 493 result = dns_dispatch_connect(request->dispentry); 494 if (result != ISC_R_SUCCESS) { 495 dns_request_unref(request); 496 goto cleanup; 497 } 498 499 req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request); 500 *requestp = request; 501 502 cleanup: 503 if (result != ISC_R_SUCCESS) { 504 req_cleanup(request); 505 dns_request_detach(&request); 506 req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__, 507 isc_result_totext(result)); 508 } 509 510 done: 511 rcu_read_unlock(); 512 return result; 513 } 514 515 isc_result_t 516 dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message, 517 const isc_sockaddr_t *srcaddr, 518 const isc_sockaddr_t *destaddr, dns_transport_t *transport, 519 isc_tlsctx_cache_t *tlsctx_cache, unsigned int options, 520 dns_tsigkey_t *key, unsigned int timeout, 521 unsigned int udptimeout, unsigned int udpretries, 522 isc_loop_t *loop, isc_job_cb cb, void *arg, 523 dns_request_t **requestp) { 524 dns_request_t *request = NULL; 525 isc_result_t result; 526 isc_mem_t *mctx = NULL; 527 dns_messageid_t id; 528 bool tcp = false; 529 530 REQUIRE(VALID_REQUESTMGR(requestmgr)); 531 REQUIRE(message != NULL); 532 REQUIRE(destaddr != NULL); 533 REQUIRE(loop != NULL); 534 REQUIRE(cb != NULL); 535 REQUIRE(requestp != NULL && *requestp == NULL); 536 REQUIRE(timeout > 0); 537 REQUIRE(udpretries != UINT_MAX); 538 539 if (srcaddr != NULL && 540 isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr)) 541 { 542 return ISC_R_FAMILYMISMATCH; 543 } 544 545 mctx = requestmgr->mctx; 546 547 req_log(ISC_LOG_DEBUG(3), "%s", __func__); 548 549 rcu_read_lock(); 550 551 if (atomic_load_acquire(&requestmgr->shuttingdown)) { 552 result = ISC_R_SHUTTINGDOWN; 553 goto done; 554 } 555 556 if (isblackholed(requestmgr->dispatchmgr, destaddr)) { 557 result = DNS_R_BLACKHOLED; 558 goto done; 559 } 560 561 if ((options & DNS_REQUESTOPT_TCP) != 0) { 562 tcp = true; 563 } 564 565 request = new_request(mctx, loop, cb, arg, tcp, timeout, udptimeout, 566 udpretries); 567 568 if (key != NULL) { 569 dns_tsigkey_attach(key, &request->tsigkey); 570 } 571 572 result = dns_message_settsigkey(message, request->tsigkey); 573 if (result != ISC_R_SUCCESS) { 574 goto cleanup; 575 } 576 577 again: 578 result = get_dispatch(tcp, requestmgr, srcaddr, destaddr, transport, 0, 579 &request->dispatch); 580 if (result != ISC_R_SUCCESS) { 581 goto cleanup; 582 } 583 584 result = dns_dispatch_add(request->dispatch, loop, 0, request->timeout, 585 destaddr, transport, tlsctx_cache, 586 req_connected, req_senddone, req_response, 587 request, &id, &request->dispentry); 588 if (result != ISC_R_SUCCESS) { 589 goto cleanup; 590 } 591 592 message->id = id; 593 result = req_render(message, &request->query, options, mctx); 594 if (result == DNS_R_USETCP && !tcp) { 595 /* Try again using TCP. */ 596 dns_message_renderreset(message); 597 dns_dispatch_done(&request->dispentry); 598 dns_dispatch_detach(&request->dispatch); 599 options |= DNS_REQUESTOPT_TCP; 600 tcp = true; 601 goto again; 602 } else if (result != ISC_R_SUCCESS) { 603 goto cleanup; 604 } 605 606 result = dns_message_getquerytsig(message, mctx, &request->tsig); 607 if (result != ISC_R_SUCCESS) { 608 goto cleanup; 609 } 610 611 request->destaddr = *destaddr; 612 request->flags |= DNS_REQUEST_F_CONNECTING; 613 if (tcp) { 614 request->flags |= DNS_REQUEST_F_TCP; 615 } 616 617 dns_requestmgr_attach(requestmgr, &request->requestmgr); 618 ISC_LIST_APPEND(requestmgr->requests[request->tid], request, link); 619 620 dns_request_ref(request); /* detached in req_connected() */ 621 result = dns_dispatch_connect(request->dispentry); 622 if (result != ISC_R_SUCCESS) { 623 dns_request_unref(request); 624 goto cleanup; 625 } 626 627 req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request); 628 *requestp = request; 629 630 cleanup: 631 if (result != ISC_R_SUCCESS) { 632 dns_message_settsigkey(message, NULL); 633 req_cleanup(request); 634 dns_request_detach(&request); 635 req_log(ISC_LOG_DEBUG(3), "%s: failed %s", __func__, 636 isc_result_totext(result)); 637 } 638 done: 639 rcu_read_unlock(); 640 641 return result; 642 } 643 644 static isc_result_t 645 req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, 646 isc_mem_t *mctx) { 647 isc_buffer_t *buf1 = NULL; 648 isc_buffer_t *buf2 = NULL; 649 isc_result_t result; 650 isc_region_t r; 651 dns_compress_t cctx; 652 unsigned int compflags; 653 654 REQUIRE(bufferp != NULL && *bufferp == NULL); 655 656 req_log(ISC_LOG_DEBUG(3), "%s", __func__); 657 658 /* 659 * Create buffer able to hold largest possible message. 660 */ 661 isc_buffer_allocate(mctx, &buf1, 65535); 662 663 compflags = 0; 664 if ((options & DNS_REQUESTOPT_LARGE) != 0) { 665 compflags |= DNS_COMPRESS_LARGE; 666 } 667 if ((options & DNS_REQUESTOPT_CASE) != 0) { 668 compflags |= DNS_COMPRESS_CASE; 669 } 670 dns_compress_init(&cctx, mctx, compflags); 671 672 /* 673 * Render message. 674 */ 675 result = dns_message_renderbegin(message, &cctx, buf1); 676 if (result != ISC_R_SUCCESS) { 677 goto cleanup; 678 } 679 result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0); 680 if (result != ISC_R_SUCCESS) { 681 goto cleanup; 682 } 683 result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0); 684 if (result != ISC_R_SUCCESS) { 685 goto cleanup; 686 } 687 result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0); 688 if (result != ISC_R_SUCCESS) { 689 goto cleanup; 690 } 691 result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0); 692 if (result != ISC_R_SUCCESS) { 693 goto cleanup; 694 } 695 result = dns_message_renderend(message); 696 if (result != ISC_R_SUCCESS) { 697 goto cleanup; 698 } 699 700 /* 701 * Copy rendered message to exact sized buffer. 702 */ 703 isc_buffer_usedregion(buf1, &r); 704 if ((options & DNS_REQUESTOPT_TCP) == 0 && r.length > 512) { 705 result = DNS_R_USETCP; 706 goto cleanup; 707 } 708 isc_buffer_allocate(mctx, &buf2, r.length); 709 result = isc_buffer_copyregion(buf2, &r); 710 if (result != ISC_R_SUCCESS) { 711 goto cleanup; 712 } 713 714 /* 715 * Cleanup and return. 716 */ 717 dns_compress_invalidate(&cctx); 718 isc_buffer_free(&buf1); 719 *bufferp = buf2; 720 return ISC_R_SUCCESS; 721 722 cleanup: 723 dns_message_renderreset(message); 724 dns_compress_invalidate(&cctx); 725 if (buf1 != NULL) { 726 isc_buffer_free(&buf1); 727 } 728 if (buf2 != NULL) { 729 isc_buffer_free(&buf2); 730 } 731 return result; 732 } 733 734 static void 735 request_cancel(dns_request_t *request) { 736 REQUIRE(VALID_REQUEST(request)); 737 REQUIRE(request->tid == isc_tid()); 738 739 if (DNS_REQUEST_COMPLETE(request)) { 740 /* The request callback was already called */ 741 return; 742 } 743 744 req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request); 745 req_sendevent(request, ISC_R_CANCELED); /* call asynchronously */ 746 } 747 748 static void 749 req_cancel_cb(void *arg) { 750 dns_request_t *request = arg; 751 752 request_cancel(request); 753 dns_request_unref(request); 754 } 755 756 void 757 dns_request_cancel(dns_request_t *request) { 758 REQUIRE(VALID_REQUEST(request)); 759 760 if (request->tid == isc_tid()) { 761 request_cancel(request); 762 } else { 763 dns_request_ref(request); 764 isc_async_run(request->loop, req_cancel_cb, request); 765 } 766 } 767 768 isc_result_t 769 dns_request_getresponse(dns_request_t *request, dns_message_t *message, 770 unsigned int options) { 771 isc_result_t result; 772 773 REQUIRE(VALID_REQUEST(request)); 774 REQUIRE(request->tid == isc_tid()); 775 REQUIRE(request->answer != NULL); 776 777 req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request); 778 779 dns_message_setquerytsig(message, request->tsig); 780 result = dns_message_settsigkey(message, request->tsigkey); 781 if (result != ISC_R_SUCCESS) { 782 return result; 783 } 784 result = dns_message_parse(message, request->answer, options); 785 if (result != ISC_R_SUCCESS) { 786 return result; 787 } 788 if (request->tsigkey != NULL) { 789 result = dns_tsig_verify(request->answer, message, NULL, NULL); 790 } 791 return result; 792 } 793 794 isc_buffer_t * 795 dns_request_getanswer(dns_request_t *request) { 796 REQUIRE(VALID_REQUEST(request)); 797 REQUIRE(request->tid == isc_tid()); 798 799 return request->answer; 800 } 801 802 bool 803 dns_request_usedtcp(dns_request_t *request) { 804 REQUIRE(VALID_REQUEST(request)); 805 REQUIRE(request->tid == isc_tid()); 806 807 return (request->flags & DNS_REQUEST_F_TCP) != 0; 808 } 809 810 void 811 dns_request_destroy(dns_request_t **requestp) { 812 REQUIRE(requestp != NULL && VALID_REQUEST(*requestp)); 813 814 dns_request_t *request = *requestp; 815 *requestp = NULL; 816 817 req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request); 818 819 if (DNS_REQUEST_COMPLETE(request)) { 820 dns_request_cancel(request); 821 } 822 823 /* final detach to shut down request */ 824 dns_request_detach(&request); 825 } 826 827 static void 828 req_connected(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED, 829 void *arg) { 830 dns_request_t *request = (dns_request_t *)arg; 831 832 REQUIRE(VALID_REQUEST(request)); 833 REQUIRE(request->tid == isc_tid()); 834 REQUIRE(DNS_REQUEST_CONNECTING(request)); 835 836 req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request, 837 isc_result_totext(eresult)); 838 839 request->flags &= ~DNS_REQUEST_F_CONNECTING; 840 841 if (DNS_REQUEST_COMPLETE(request)) { 842 /* The request callback was already called */ 843 goto detach; 844 } 845 846 if (eresult == ISC_R_SUCCESS) { 847 req_send(request); 848 } else { 849 req_sendevent(request, eresult); 850 } 851 852 detach: 853 /* attached in dns_request_create/_createraw() */ 854 dns_request_unref(request); 855 } 856 857 static void 858 req_senddone(isc_result_t eresult, isc_region_t *region ISC_ATTR_UNUSED, 859 void *arg) { 860 dns_request_t *request = (dns_request_t *)arg; 861 862 REQUIRE(VALID_REQUEST(request)); 863 REQUIRE(request->tid == isc_tid()); 864 REQUIRE(DNS_REQUEST_SENDING(request)); 865 866 req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request); 867 868 request->flags &= ~DNS_REQUEST_F_SENDING; 869 870 if (DNS_REQUEST_COMPLETE(request)) { 871 /* The request callback was already called */ 872 goto detach; 873 } 874 875 if (eresult != ISC_R_SUCCESS) { 876 req_sendevent(request, eresult); 877 } 878 879 detach: 880 /* attached in req_send() */ 881 dns_request_unref(request); 882 } 883 884 static void 885 req_response(isc_result_t eresult, isc_region_t *region, void *arg) { 886 dns_request_t *request = (dns_request_t *)arg; 887 888 if (eresult == ISC_R_CANCELED) { 889 return; 890 } 891 892 REQUIRE(VALID_REQUEST(request)); 893 REQUIRE(request->tid == isc_tid()); 894 895 req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request, 896 isc_result_totext(eresult)); 897 898 if (DNS_REQUEST_COMPLETE(request)) { 899 /* The request callback was already called */ 900 return; 901 } 902 903 switch (eresult) { 904 case ISC_R_TIMEDOUT: 905 if (request->udpcount > 1 && !dns_request_usedtcp(request)) { 906 request->udpcount -= 1; 907 dns_dispatch_resume(request->dispentry, 908 request->timeout); 909 if (!DNS_REQUEST_SENDING(request)) { 910 req_send(request); 911 } 912 return; 913 } 914 break; 915 case ISC_R_SUCCESS: 916 /* Copy region to request. */ 917 isc_buffer_allocate(request->mctx, &request->answer, 918 region->length); 919 eresult = isc_buffer_copyregion(request->answer, region); 920 if (eresult != ISC_R_SUCCESS) { 921 isc_buffer_free(&request->answer); 922 } 923 break; 924 default: 925 break; 926 } 927 928 req_sendevent(request, eresult); 929 } 930 931 static void 932 req_sendevent_cb(void *arg) { 933 dns_request_t *request = arg; 934 935 request->cb(request); 936 dns_request_unref(request); 937 } 938 939 static void 940 req_cleanup(dns_request_t *request) { 941 if (ISC_LINK_LINKED(request, link)) { 942 ISC_LIST_UNLINK(request->requestmgr->requests[request->tid], 943 request, link); 944 } 945 if (request->dispentry != NULL) { 946 dns_dispatch_done(&request->dispentry); 947 } 948 if (request->dispatch != NULL) { 949 dns_dispatch_detach(&request->dispatch); 950 } 951 } 952 953 static void 954 req_sendevent(dns_request_t *request, isc_result_t result) { 955 REQUIRE(VALID_REQUEST(request)); 956 REQUIRE(request->tid == isc_tid()); 957 REQUIRE(!DNS_REQUEST_COMPLETE(request)); 958 959 request->flags |= DNS_REQUEST_F_COMPLETE; 960 961 req_cleanup(request); 962 963 req_log(ISC_LOG_DEBUG(3), "%s: request %p: %s", __func__, request, 964 isc_result_totext(result)); 965 966 request->result = result; 967 968 /* 969 * Do not call request->cb directly as it introduces a dead lock 970 * between dns_zonemgr_shutdown and sendtoprimary in lib/dns/zone.c 971 * zone->lock. 972 */ 973 dns_request_ref(request); 974 isc_async_run(request->loop, req_sendevent_cb, request); 975 } 976 977 static void 978 req_destroy(dns_request_t *request) { 979 REQUIRE(VALID_REQUEST(request)); 980 REQUIRE(request->tid == isc_tid()); 981 REQUIRE(!ISC_LINK_LINKED(request, link)); 982 983 req_log(ISC_LOG_DEBUG(3), "%s: request %p", __func__, request); 984 985 /* 986 * These should have been cleaned up before the 987 * completion event was sent. 988 */ 989 INSIST(!ISC_LINK_LINKED(request, link)); 990 INSIST(request->dispentry == NULL); 991 INSIST(request->dispatch == NULL); 992 993 request->magic = 0; 994 if (request->query != NULL) { 995 isc_buffer_free(&request->query); 996 } 997 if (request->answer != NULL) { 998 isc_buffer_free(&request->answer); 999 } 1000 if (request->tsig != NULL) { 1001 isc_buffer_free(&request->tsig); 1002 } 1003 if (request->tsigkey != NULL) { 1004 dns_tsigkey_detach(&request->tsigkey); 1005 } 1006 if (request->requestmgr != NULL) { 1007 dns_requestmgr_detach(&request->requestmgr); 1008 } 1009 isc_mem_putanddetach(&request->mctx, request, sizeof(*request)); 1010 } 1011 1012 void * 1013 dns_request_getarg(dns_request_t *request) { 1014 REQUIRE(VALID_REQUEST(request)); 1015 REQUIRE(request->tid == isc_tid()); 1016 1017 return request->arg; 1018 } 1019 1020 isc_result_t 1021 dns_request_getresult(dns_request_t *request) { 1022 REQUIRE(VALID_REQUEST(request)); 1023 REQUIRE(request->tid == isc_tid()); 1024 1025 return request->result; 1026 } 1027 1028 #if DNS_REQUEST_TRACE 1029 ISC_REFCOUNT_TRACE_IMPL(dns_request, req_destroy); 1030 #else 1031 ISC_REFCOUNT_IMPL(dns_request, req_destroy); 1032 #endif 1033 1034 static void 1035 req_log(int level, const char *fmt, ...) { 1036 va_list ap; 1037 1038 va_start(ap, fmt); 1039 isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST, 1040 level, fmt, ap); 1041 va_end(ap); 1042 } 1043