1/* $NetBSD: client.c,v 1.13 2024/02/21 22:52:05 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#include <stdbool.h> 17#include <stddef.h> 18 19#include <isc/app.h> 20#include <isc/buffer.h> 21#include <isc/md.h> 22#include <isc/mem.h> 23#include <isc/mutex.h> 24#include <isc/portset.h> 25#include <isc/refcount.h> 26#include <isc/result.h> 27#include <isc/safe.h> 28#include <isc/sockaddr.h> 29#include <isc/task.h> 30#include <isc/timer.h> 31#include <isc/util.h> 32 33#include <dns/adb.h> 34#include <dns/client.h> 35#include <dns/db.h> 36#include <dns/dispatch.h> 37#include <dns/events.h> 38#include <dns/forward.h> 39#include <dns/keytable.h> 40#include <dns/message.h> 41#include <dns/name.h> 42#include <dns/rdata.h> 43#include <dns/rdatalist.h> 44#include <dns/rdataset.h> 45#include <dns/rdatasetiter.h> 46#include <dns/rdatastruct.h> 47#include <dns/rdatatype.h> 48#include <dns/request.h> 49#include <dns/resolver.h> 50#include <dns/tsec.h> 51#include <dns/tsig.h> 52#include <dns/view.h> 53 54#include <dst/dst.h> 55 56#define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c') 57#define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC) 58 59#define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x') 60#define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC) 61 62#define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') 63#define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) 64 65#define MAX_RESTARTS 16 66 67#ifdef TUNE_LARGE 68#define RESOLVER_NTASKS 523 69#else /* ifdef TUNE_LARGE */ 70#define RESOLVER_NTASKS 31 71#endif /* TUNE_LARGE */ 72 73#define CHECK(r) \ 74 do { \ 75 result = (r); \ 76 if (result != ISC_R_SUCCESS) \ 77 goto cleanup; \ 78 } while (0) 79 80/*% 81 * DNS client object 82 */ 83struct dns_client { 84 /* Unlocked */ 85 unsigned int magic; 86 unsigned int attributes; 87 isc_mutex_t lock; 88 isc_mem_t *mctx; 89 isc_appctx_t *actx; 90 isc_taskmgr_t *taskmgr; 91 isc_task_t *task; 92 isc_nm_t *nm; 93 isc_timermgr_t *timermgr; 94 dns_dispatchmgr_t *dispatchmgr; 95 dns_dispatch_t *dispatchv4; 96 dns_dispatch_t *dispatchv6; 97 98 unsigned int find_timeout; 99 unsigned int find_udpretries; 100 101 isc_refcount_t references; 102 103 /* Locked */ 104 dns_viewlist_t viewlist; 105 ISC_LIST(struct resctx) resctxs; 106}; 107 108#define DEF_FIND_TIMEOUT 5 109#define DEF_FIND_UDPRETRIES 3 110 111/*% 112 * Internal state for a single name resolution procedure 113 */ 114typedef struct resctx { 115 /* Unlocked */ 116 unsigned int magic; 117 isc_mutex_t lock; 118 dns_client_t *client; 119 bool want_dnssec; 120 bool want_validation; 121 bool want_cdflag; 122 bool want_tcp; 123 124 /* Locked */ 125 ISC_LINK(struct resctx) link; 126 isc_task_t *task; 127 dns_view_t *view; 128 unsigned int restarts; 129 dns_fixedname_t name; 130 dns_rdatatype_t type; 131 dns_fetch_t *fetch; 132 dns_namelist_t namelist; 133 isc_result_t result; 134 dns_clientresevent_t *event; 135 bool canceled; 136 dns_rdataset_t *rdataset; 137 dns_rdataset_t *sigrdataset; 138} resctx_t; 139 140/*% 141 * Argument of an internal event for synchronous name resolution. 142 */ 143typedef struct resarg { 144 /* Unlocked */ 145 isc_appctx_t *actx; 146 dns_client_t *client; 147 isc_mutex_t lock; 148 149 /* Locked */ 150 isc_result_t result; 151 isc_result_t vresult; 152 dns_namelist_t *namelist; 153 dns_clientrestrans_t *trans; 154 bool canceled; 155} resarg_t; 156 157static void 158client_resfind(resctx_t *rctx, dns_fetchevent_t *event); 159static void 160cancelresolve(dns_clientrestrans_t *trans); 161static void 162destroyrestrans(dns_clientrestrans_t **transp); 163 164/* 165 * Try honoring the operating system's preferred ephemeral port range. 166 */ 167static isc_result_t 168setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) { 169 isc_portset_t *v4portset = NULL, *v6portset = NULL; 170 in_port_t udpport_low, udpport_high; 171 isc_result_t result; 172 173 result = isc_portset_create(mctx, &v4portset); 174 if (result != ISC_R_SUCCESS) { 175 goto cleanup; 176 } 177 result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high); 178 if (result != ISC_R_SUCCESS) { 179 goto cleanup; 180 } 181 isc_portset_addrange(v4portset, udpport_low, udpport_high); 182 183 result = isc_portset_create(mctx, &v6portset); 184 if (result != ISC_R_SUCCESS) { 185 goto cleanup; 186 } 187 result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high); 188 if (result != ISC_R_SUCCESS) { 189 goto cleanup; 190 } 191 isc_portset_addrange(v6portset, udpport_low, udpport_high); 192 193 result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset); 194 195cleanup: 196 if (v4portset != NULL) { 197 isc_portset_destroy(mctx, &v4portset); 198 } 199 if (v6portset != NULL) { 200 isc_portset_destroy(mctx, &v6portset); 201 } 202 203 return (result); 204} 205 206static isc_result_t 207getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, 208 dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { 209 dns_dispatch_t *disp = NULL; 210 isc_result_t result; 211 isc_sockaddr_t anyaddr; 212 213 if (localaddr == NULL) { 214 isc_sockaddr_anyofpf(&anyaddr, family); 215 localaddr = &anyaddr; 216 } 217 218 result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp); 219 if (result == ISC_R_SUCCESS) { 220 *dispp = disp; 221 } 222 223 return (result); 224} 225 226static isc_result_t 227createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr, 228 unsigned int ntasks, isc_nm_t *nm, isc_timermgr_t *timermgr, 229 dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, 230 dns_dispatch_t *dispatchv6, dns_view_t **viewp) { 231 isc_result_t result; 232 dns_view_t *view = NULL; 233 234 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view); 235 if (result != ISC_R_SUCCESS) { 236 return (result); 237 } 238 239 /* Initialize view security roots */ 240 result = dns_view_initsecroots(view, mctx); 241 if (result != ISC_R_SUCCESS) { 242 dns_view_detach(&view); 243 return (result); 244 } 245 246 result = dns_view_createresolver(view, taskmgr, ntasks, 1, nm, timermgr, 247 0, dispatchmgr, dispatchv4, 248 dispatchv6); 249 if (result != ISC_R_SUCCESS) { 250 dns_view_detach(&view); 251 return (result); 252 } 253 254 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache, 255 rdclass, 0, NULL, &view->cachedb); 256 if (result != ISC_R_SUCCESS) { 257 dns_view_detach(&view); 258 return (result); 259 } 260 261 *viewp = view; 262 return (ISC_R_SUCCESS); 263} 264 265isc_result_t 266dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, 267 isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options, 268 dns_client_t **clientp, const isc_sockaddr_t *localaddr4, 269 const isc_sockaddr_t *localaddr6) { 270 isc_result_t result; 271 dns_client_t *client = NULL; 272 dns_dispatch_t *dispatchv4 = NULL; 273 dns_dispatch_t *dispatchv6 = NULL; 274 dns_view_t *view = NULL; 275 276 REQUIRE(mctx != NULL); 277 REQUIRE(taskmgr != NULL); 278 REQUIRE(timermgr != NULL); 279 REQUIRE(nm != NULL); 280 REQUIRE(clientp != NULL && *clientp == NULL); 281 282 UNUSED(options); 283 284 client = isc_mem_get(mctx, sizeof(*client)); 285 *client = (dns_client_t){ 286 .actx = actx, .taskmgr = taskmgr, .timermgr = timermgr, .nm = nm 287 }; 288 289 isc_mutex_init(&client->lock); 290 291 result = isc_task_create(client->taskmgr, 0, &client->task); 292 if (result != ISC_R_SUCCESS) { 293 goto cleanup_lock; 294 } 295 296 result = dns_dispatchmgr_create(mctx, nm, &client->dispatchmgr); 297 if (result != ISC_R_SUCCESS) { 298 goto cleanup_task; 299 } 300 (void)setsourceports(mctx, client->dispatchmgr); 301 302 /* 303 * If only one address family is specified, use it. 304 * If neither family is specified, or if both are, use both. 305 */ 306 client->dispatchv4 = NULL; 307 if (localaddr4 != NULL || localaddr6 == NULL) { 308 result = getudpdispatch(AF_INET, client->dispatchmgr, 309 &dispatchv4, localaddr4); 310 if (result == ISC_R_SUCCESS) { 311 client->dispatchv4 = dispatchv4; 312 } 313 } 314 315 client->dispatchv6 = NULL; 316 if (localaddr6 != NULL || localaddr4 == NULL) { 317 result = getudpdispatch(AF_INET6, client->dispatchmgr, 318 &dispatchv6, localaddr6); 319 if (result == ISC_R_SUCCESS) { 320 client->dispatchv6 = dispatchv6; 321 } 322 } 323 324 /* We need at least one of the dispatchers */ 325 if (dispatchv4 == NULL && dispatchv6 == NULL) { 326 INSIST(result != ISC_R_SUCCESS); 327 goto cleanup_dispatchmgr; 328 } 329 330 isc_refcount_init(&client->references, 1); 331 332 /* Create the default view for class IN */ 333 result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS, 334 nm, timermgr, client->dispatchmgr, dispatchv4, 335 dispatchv6, &view); 336 if (result != ISC_R_SUCCESS) { 337 goto cleanup_references; 338 } 339 340 ISC_LIST_INIT(client->viewlist); 341 ISC_LIST_APPEND(client->viewlist, view, link); 342 343 dns_view_freeze(view); /* too early? */ 344 345 ISC_LIST_INIT(client->resctxs); 346 347 isc_mem_attach(mctx, &client->mctx); 348 349 client->find_timeout = DEF_FIND_TIMEOUT; 350 client->find_udpretries = DEF_FIND_UDPRETRIES; 351 352 client->magic = DNS_CLIENT_MAGIC; 353 354 *clientp = client; 355 356 return (ISC_R_SUCCESS); 357 358cleanup_references: 359 isc_refcount_decrementz(&client->references); 360 isc_refcount_destroy(&client->references); 361cleanup_dispatchmgr: 362 if (dispatchv4 != NULL) { 363 dns_dispatch_detach(&dispatchv4); 364 } 365 if (dispatchv6 != NULL) { 366 dns_dispatch_detach(&dispatchv6); 367 } 368 dns_dispatchmgr_detach(&client->dispatchmgr); 369cleanup_task: 370 isc_task_detach(&client->task); 371cleanup_lock: 372 isc_mutex_destroy(&client->lock); 373 isc_mem_put(mctx, client, sizeof(*client)); 374 375 return (result); 376} 377 378static void 379destroyclient(dns_client_t *client) { 380 dns_view_t *view = NULL; 381 382 isc_refcount_destroy(&client->references); 383 384 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) { 385 ISC_LIST_UNLINK(client->viewlist, view, link); 386 dns_view_detach(&view); 387 } 388 389 if (client->dispatchv4 != NULL) { 390 dns_dispatch_detach(&client->dispatchv4); 391 } 392 if (client->dispatchv6 != NULL) { 393 dns_dispatch_detach(&client->dispatchv6); 394 } 395 396 dns_dispatchmgr_detach(&client->dispatchmgr); 397 398 isc_task_detach(&client->task); 399 400 isc_mutex_destroy(&client->lock); 401 client->magic = 0; 402 403 isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); 404} 405 406void 407dns_client_detach(dns_client_t **clientp) { 408 dns_client_t *client = NULL; 409 410 REQUIRE(clientp != NULL); 411 REQUIRE(DNS_CLIENT_VALID(*clientp)); 412 413 client = *clientp; 414 *clientp = NULL; 415 416 if (isc_refcount_decrement(&client->references) == 1) { 417 destroyclient(client); 418 } 419} 420 421isc_result_t 422dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, 423 const dns_name_t *name_space, isc_sockaddrlist_t *addrs) { 424 isc_result_t result; 425 dns_view_t *view = NULL; 426 427 REQUIRE(DNS_CLIENT_VALID(client)); 428 REQUIRE(addrs != NULL); 429 430 if (name_space == NULL) { 431 name_space = dns_rootname; 432 } 433 434 LOCK(&client->lock); 435 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 436 rdclass, &view); 437 if (result != ISC_R_SUCCESS) { 438 UNLOCK(&client->lock); 439 return (result); 440 } 441 UNLOCK(&client->lock); 442 443 result = dns_fwdtable_add(view->fwdtable, name_space, addrs, 444 dns_fwdpolicy_only); 445 446 dns_view_detach(&view); 447 448 return (result); 449} 450 451isc_result_t 452dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass, 453 const dns_name_t *name_space) { 454 isc_result_t result; 455 dns_view_t *view = NULL; 456 457 REQUIRE(DNS_CLIENT_VALID(client)); 458 459 if (name_space == NULL) { 460 name_space = dns_rootname; 461 } 462 463 LOCK(&client->lock); 464 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 465 rdclass, &view); 466 if (result != ISC_R_SUCCESS) { 467 UNLOCK(&client->lock); 468 return (result); 469 } 470 UNLOCK(&client->lock); 471 472 result = dns_fwdtable_delete(view->fwdtable, name_space); 473 474 dns_view_detach(&view); 475 476 return (result); 477} 478 479static isc_result_t 480getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 481 dns_rdataset_t *rdataset; 482 483 REQUIRE(mctx != NULL); 484 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); 485 486 rdataset = isc_mem_get(mctx, sizeof(*rdataset)); 487 488 dns_rdataset_init(rdataset); 489 490 *rdatasetp = rdataset; 491 492 return (ISC_R_SUCCESS); 493} 494 495static void 496putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 497 dns_rdataset_t *rdataset; 498 499 REQUIRE(rdatasetp != NULL); 500 rdataset = *rdatasetp; 501 *rdatasetp = NULL; 502 REQUIRE(rdataset != NULL); 503 504 if (dns_rdataset_isassociated(rdataset)) { 505 dns_rdataset_disassociate(rdataset); 506 } 507 508 isc_mem_put(mctx, rdataset, sizeof(*rdataset)); 509} 510 511static void 512fetch_done(isc_task_t *task, isc_event_t *event) { 513 resctx_t *rctx = event->ev_arg; 514 dns_fetchevent_t *fevent; 515 516 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); 517 REQUIRE(RCTX_VALID(rctx)); 518 REQUIRE(rctx->task == task); 519 fevent = (dns_fetchevent_t *)event; 520 521 client_resfind(rctx, fevent); 522} 523 524static isc_result_t 525start_fetch(resctx_t *rctx) { 526 isc_result_t result; 527 int fopts = 0; 528 529 /* 530 * The caller must be holding the rctx's lock. 531 */ 532 533 REQUIRE(rctx->fetch == NULL); 534 535 if (!rctx->want_cdflag) { 536 fopts |= DNS_FETCHOPT_NOCDFLAG; 537 } 538 if (!rctx->want_validation) { 539 fopts |= DNS_FETCHOPT_NOVALIDATE; 540 } 541 if (rctx->want_tcp) { 542 fopts |= DNS_FETCHOPT_TCP; 543 } 544 545 result = dns_resolver_createfetch( 546 rctx->view->resolver, dns_fixedname_name(&rctx->name), 547 rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL, 548 rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset, 549 &rctx->fetch); 550 551 return (result); 552} 553 554static isc_result_t 555view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep, 556 dns_name_t *foundname) { 557 isc_result_t result; 558 dns_name_t *name = dns_fixedname_name(&rctx->name); 559 dns_rdatatype_t type; 560 561 if (rctx->type == dns_rdatatype_rrsig) { 562 type = dns_rdatatype_any; 563 } else { 564 type = rctx->type; 565 } 566 567 result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp, 568 nodep, foundname, rctx->rdataset, 569 rctx->sigrdataset); 570 571 return (result); 572} 573 574static void 575client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { 576 isc_mem_t *mctx; 577 isc_result_t tresult, result = ISC_R_SUCCESS; 578 isc_result_t vresult = ISC_R_SUCCESS; 579 bool want_restart; 580 bool send_event = false; 581 dns_name_t *name = NULL, *prefix = NULL; 582 dns_fixedname_t foundname, fixed; 583 dns_rdataset_t *trdataset = NULL; 584 dns_rdata_t rdata = DNS_RDATA_INIT; 585 unsigned int nlabels; 586 int order; 587 dns_namereln_t namereln; 588 dns_rdata_cname_t cname; 589 dns_rdata_dname_t dname; 590 591 REQUIRE(RCTX_VALID(rctx)); 592 593 LOCK(&rctx->lock); 594 595 mctx = rctx->view->mctx; 596 597 name = dns_fixedname_name(&rctx->name); 598 599 do { 600 dns_name_t *fname = NULL; 601 dns_name_t *ansname = NULL; 602 dns_db_t *db = NULL; 603 dns_dbnode_t *node = NULL; 604 605 rctx->restarts++; 606 want_restart = false; 607 608 if (event == NULL && !rctx->canceled) { 609 fname = dns_fixedname_initname(&foundname); 610 INSIST(!dns_rdataset_isassociated(rctx->rdataset)); 611 INSIST(rctx->sigrdataset == NULL || 612 !dns_rdataset_isassociated(rctx->sigrdataset)); 613 result = view_find(rctx, &db, &node, fname); 614 if (result == ISC_R_NOTFOUND) { 615 /* 616 * We don't know anything about the name. 617 * Launch a fetch. 618 */ 619 if (node != NULL) { 620 INSIST(db != NULL); 621 dns_db_detachnode(db, &node); 622 } 623 if (db != NULL) { 624 dns_db_detach(&db); 625 } 626 result = start_fetch(rctx); 627 if (result != ISC_R_SUCCESS) { 628 putrdataset(mctx, &rctx->rdataset); 629 if (rctx->sigrdataset != NULL) { 630 putrdataset(mctx, 631 &rctx->sigrdataset); 632 } 633 send_event = true; 634 } 635 goto done; 636 } 637 } else { 638 INSIST(event != NULL); 639 INSIST(event->fetch == rctx->fetch); 640 dns_resolver_destroyfetch(&rctx->fetch); 641 db = event->db; 642 node = event->node; 643 result = event->result; 644 vresult = event->vresult; 645 fname = event->foundname; 646 INSIST(event->rdataset == rctx->rdataset); 647 INSIST(event->sigrdataset == rctx->sigrdataset); 648 } 649 650 /* 651 * If we've been canceled, forget about the result. 652 */ 653 if (rctx->canceled) { 654 result = ISC_R_CANCELED; 655 } else { 656 /* 657 * Otherwise, get some resource for copying the 658 * result. 659 */ 660 dns_name_t *aname = dns_fixedname_name(&rctx->name); 661 662 ansname = isc_mem_get(mctx, sizeof(*ansname)); 663 dns_name_init(ansname, NULL); 664 665 dns_name_dup(aname, mctx, ansname); 666 } 667 668 switch (result) { 669 case ISC_R_SUCCESS: 670 send_event = true; 671 /* 672 * This case is handled in the main line below. 673 */ 674 break; 675 case DNS_R_CNAME: 676 /* 677 * Add the CNAME to the answer list. 678 */ 679 trdataset = rctx->rdataset; 680 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 681 rctx->rdataset = NULL; 682 if (rctx->sigrdataset != NULL) { 683 ISC_LIST_APPEND(ansname->list, 684 rctx->sigrdataset, link); 685 rctx->sigrdataset = NULL; 686 } 687 ISC_LIST_APPEND(rctx->namelist, ansname, link); 688 ansname = NULL; 689 690 /* 691 * Copy the CNAME's target into the lookup's 692 * query name and start over. 693 */ 694 tresult = dns_rdataset_first(trdataset); 695 if (tresult != ISC_R_SUCCESS) { 696 goto done; 697 } 698 dns_rdataset_current(trdataset, &rdata); 699 tresult = dns_rdata_tostruct(&rdata, &cname, NULL); 700 dns_rdata_reset(&rdata); 701 if (tresult != ISC_R_SUCCESS) { 702 goto done; 703 } 704 dns_name_copy(&cname.cname, name); 705 dns_rdata_freestruct(&cname); 706 want_restart = true; 707 goto done; 708 case DNS_R_DNAME: 709 /* 710 * Add the DNAME to the answer list. 711 */ 712 trdataset = rctx->rdataset; 713 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 714 rctx->rdataset = NULL; 715 if (rctx->sigrdataset != NULL) { 716 ISC_LIST_APPEND(ansname->list, 717 rctx->sigrdataset, link); 718 rctx->sigrdataset = NULL; 719 } 720 ISC_LIST_APPEND(rctx->namelist, ansname, link); 721 ansname = NULL; 722 723 namereln = dns_name_fullcompare(name, fname, &order, 724 &nlabels); 725 INSIST(namereln == dns_namereln_subdomain); 726 /* 727 * Get the target name of the DNAME. 728 */ 729 tresult = dns_rdataset_first(trdataset); 730 if (tresult != ISC_R_SUCCESS) { 731 result = tresult; 732 goto done; 733 } 734 dns_rdataset_current(trdataset, &rdata); 735 tresult = dns_rdata_tostruct(&rdata, &dname, NULL); 736 dns_rdata_reset(&rdata); 737 if (tresult != ISC_R_SUCCESS) { 738 result = tresult; 739 goto done; 740 } 741 /* 742 * Construct the new query name and start over. 743 */ 744 prefix = dns_fixedname_initname(&fixed); 745 dns_name_split(name, nlabels, prefix, NULL); 746 tresult = dns_name_concatenate(prefix, &dname.dname, 747 name, NULL); 748 dns_rdata_freestruct(&dname); 749 if (tresult == ISC_R_SUCCESS) { 750 want_restart = true; 751 } else { 752 result = tresult; 753 } 754 goto done; 755 case DNS_R_NCACHENXDOMAIN: 756 case DNS_R_NCACHENXRRSET: 757 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 758 ISC_LIST_APPEND(rctx->namelist, ansname, link); 759 ansname = NULL; 760 rctx->rdataset = NULL; 761 /* What about sigrdataset? */ 762 if (rctx->sigrdataset != NULL) { 763 putrdataset(mctx, &rctx->sigrdataset); 764 } 765 send_event = true; 766 goto done; 767 default: 768 if (rctx->rdataset != NULL) { 769 putrdataset(mctx, &rctx->rdataset); 770 } 771 if (rctx->sigrdataset != NULL) { 772 putrdataset(mctx, &rctx->sigrdataset); 773 } 774 send_event = true; 775 goto done; 776 } 777 778 if (rctx->type == dns_rdatatype_any) { 779 int n = 0; 780 dns_rdatasetiter_t *rdsiter = NULL; 781 782 tresult = dns_db_allrdatasets(db, node, NULL, 0, 0, 783 &rdsiter); 784 if (tresult != ISC_R_SUCCESS) { 785 result = tresult; 786 goto done; 787 } 788 789 tresult = dns_rdatasetiter_first(rdsiter); 790 while (tresult == ISC_R_SUCCESS) { 791 dns_rdatasetiter_current(rdsiter, 792 rctx->rdataset); 793 if (rctx->rdataset->type != 0) { 794 ISC_LIST_APPEND(ansname->list, 795 rctx->rdataset, link); 796 n++; 797 rctx->rdataset = NULL; 798 } else { 799 /* 800 * We're not interested in this 801 * rdataset. 802 */ 803 dns_rdataset_disassociate( 804 rctx->rdataset); 805 } 806 tresult = dns_rdatasetiter_next(rdsiter); 807 808 if (tresult == ISC_R_SUCCESS && 809 rctx->rdataset == NULL) 810 { 811 tresult = getrdataset(mctx, 812 &rctx->rdataset); 813 if (tresult != ISC_R_SUCCESS) { 814 result = tresult; 815 POST(result); 816 break; 817 } 818 } 819 } 820 if (rctx->rdataset != NULL) { 821 putrdataset(mctx, &rctx->rdataset); 822 } 823 if (rctx->sigrdataset != NULL) { 824 putrdataset(mctx, &rctx->sigrdataset); 825 } 826 if (n == 0) { 827 /* 828 * We didn't match any rdatasets (which means 829 * something went wrong in this 830 * implementation). 831 */ 832 result = DNS_R_SERVFAIL; /* better code? */ 833 POST(result); 834 } else { 835 ISC_LIST_APPEND(rctx->namelist, ansname, link); 836 ansname = NULL; 837 } 838 dns_rdatasetiter_destroy(&rdsiter); 839 if (tresult != ISC_R_NOMORE) { 840 result = DNS_R_SERVFAIL; /* ditto */ 841 } else { 842 result = ISC_R_SUCCESS; 843 } 844 goto done; 845 } else { 846 /* 847 * This is the "normal" case -- an ordinary question 848 * to which we've got the answer. 849 */ 850 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 851 rctx->rdataset = NULL; 852 if (rctx->sigrdataset != NULL) { 853 ISC_LIST_APPEND(ansname->list, 854 rctx->sigrdataset, link); 855 rctx->sigrdataset = NULL; 856 } 857 ISC_LIST_APPEND(rctx->namelist, ansname, link); 858 ansname = NULL; 859 } 860 861 done: 862 /* 863 * Free temporary resources 864 */ 865 if (ansname != NULL) { 866 dns_rdataset_t *rdataset; 867 868 while ((rdataset = ISC_LIST_HEAD(ansname->list)) != 869 NULL) 870 { 871 ISC_LIST_UNLINK(ansname->list, rdataset, link); 872 putrdataset(mctx, &rdataset); 873 } 874 dns_name_free(ansname, mctx); 875 isc_mem_put(mctx, ansname, sizeof(*ansname)); 876 } 877 878 if (node != NULL) { 879 dns_db_detachnode(db, &node); 880 } 881 if (db != NULL) { 882 dns_db_detach(&db); 883 } 884 if (event != NULL) { 885 isc_event_free(ISC_EVENT_PTR(&event)); 886 } 887 888 /* 889 * Limit the number of restarts. 890 */ 891 if (want_restart && rctx->restarts == MAX_RESTARTS) { 892 want_restart = false; 893 result = ISC_R_QUOTA; 894 send_event = true; 895 } 896 897 /* 898 * Prepare further find with new resources 899 */ 900 if (want_restart) { 901 INSIST(rctx->rdataset == NULL && 902 rctx->sigrdataset == NULL); 903 904 result = getrdataset(mctx, &rctx->rdataset); 905 if (result == ISC_R_SUCCESS && rctx->want_dnssec) { 906 result = getrdataset(mctx, &rctx->sigrdataset); 907 if (result != ISC_R_SUCCESS) { 908 putrdataset(mctx, &rctx->rdataset); 909 } 910 } 911 912 if (result != ISC_R_SUCCESS) { 913 want_restart = false; 914 send_event = true; 915 } 916 } 917 } while (want_restart); 918 919 if (send_event) { 920 isc_task_t *task; 921 922 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) { 923 ISC_LIST_UNLINK(rctx->namelist, name, link); 924 ISC_LIST_APPEND(rctx->event->answerlist, name, link); 925 } 926 927 rctx->event->result = result; 928 rctx->event->vresult = vresult; 929 task = rctx->event->ev_sender; 930 rctx->event->ev_sender = rctx; 931 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event)); 932 } 933 934 UNLOCK(&rctx->lock); 935} 936 937static void 938suspend(isc_task_t *task, isc_event_t *event) { 939 isc_appctx_t *actx = event->ev_arg; 940 941 UNUSED(task); 942 943 isc_app_ctxsuspend(actx); 944 isc_event_free(&event); 945} 946 947static void 948resolve_done(isc_task_t *task, isc_event_t *event) { 949 resarg_t *resarg = event->ev_arg; 950 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 951 dns_name_t *name = NULL; 952 dns_client_t *client = resarg->client; 953 isc_result_t result; 954 955 UNUSED(task); 956 957 LOCK(&resarg->lock); 958 959 resarg->result = rev->result; 960 resarg->vresult = rev->vresult; 961 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) { 962 ISC_LIST_UNLINK(rev->answerlist, name, link); 963 ISC_LIST_APPEND(*resarg->namelist, name, link); 964 } 965 966 destroyrestrans(&resarg->trans); 967 isc_event_free(&event); 968 resarg->client = NULL; 969 970 if (!resarg->canceled) { 971 UNLOCK(&resarg->lock); 972 973 /* 974 * We may or may not be running. isc__appctx_onrun will 975 * fail if we are currently running otherwise we post a 976 * action to call isc_app_ctxsuspend when we do start 977 * running. 978 */ 979 result = isc_app_ctxonrun(resarg->actx, client->mctx, task, 980 suspend, resarg->actx); 981 if (result == ISC_R_ALREADYRUNNING) { 982 isc_app_ctxsuspend(resarg->actx); 983 } 984 } else { 985 /* 986 * We have already exited from the loop (due to some 987 * unexpected event). Just clean the arg up. 988 */ 989 UNLOCK(&resarg->lock); 990 isc_mutex_destroy(&resarg->lock); 991 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 992 } 993 994 dns_client_detach(&client); 995} 996 997isc_result_t 998dns_client_resolve(dns_client_t *client, const dns_name_t *name, 999 dns_rdataclass_t rdclass, dns_rdatatype_t type, 1000 unsigned int options, dns_namelist_t *namelist) { 1001 isc_result_t result; 1002 resarg_t *resarg = NULL; 1003 1004 REQUIRE(DNS_CLIENT_VALID(client)); 1005 REQUIRE(client->actx != NULL); 1006 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist)); 1007 1008 resarg = isc_mem_get(client->mctx, sizeof(*resarg)); 1009 1010 *resarg = (resarg_t){ 1011 .actx = client->actx, 1012 .client = client, 1013 .result = DNS_R_SERVFAIL, 1014 .namelist = namelist, 1015 }; 1016 1017 isc_mutex_init(&resarg->lock); 1018 1019 result = dns_client_startresolve(client, name, rdclass, type, options, 1020 client->task, resolve_done, resarg, 1021 &resarg->trans); 1022 if (result != ISC_R_SUCCESS) { 1023 isc_mutex_destroy(&resarg->lock); 1024 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1025 return (result); 1026 } 1027 1028 /* 1029 * Start internal event loop. It blocks until the entire process 1030 * is completed. 1031 */ 1032 result = isc_app_ctxrun(client->actx); 1033 1034 LOCK(&resarg->lock); 1035 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) { 1036 result = resarg->result; 1037 } 1038 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) { 1039 /* 1040 * If this lookup failed due to some error in DNSSEC 1041 * validation, return the validation error code. 1042 * XXX: or should we pass the validation result separately? 1043 */ 1044 result = resarg->vresult; 1045 } 1046 if (resarg->trans != NULL) { 1047 /* 1048 * Unusual termination (perhaps due to signal). We need some 1049 * tricky cleanup process. 1050 */ 1051 resarg->canceled = true; 1052 cancelresolve(resarg->trans); 1053 1054 UNLOCK(&resarg->lock); 1055 1056 /* resarg will be freed in the event handler. */ 1057 } else { 1058 UNLOCK(&resarg->lock); 1059 1060 isc_mutex_destroy(&resarg->lock); 1061 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1062 } 1063 1064 return (result); 1065} 1066 1067isc_result_t 1068dns_client_startresolve(dns_client_t *client, const dns_name_t *name, 1069 dns_rdataclass_t rdclass, dns_rdatatype_t type, 1070 unsigned int options, isc_task_t *task, 1071 isc_taskaction_t action, void *arg, 1072 dns_clientrestrans_t **transp) { 1073 dns_view_t *view = NULL; 1074 dns_clientresevent_t *event = NULL; 1075 resctx_t *rctx = NULL; 1076 isc_task_t *tclone = NULL; 1077 isc_mem_t *mctx; 1078 isc_result_t result; 1079 dns_rdataset_t *rdataset, *sigrdataset; 1080 bool want_dnssec, want_validation, want_cdflag, want_tcp; 1081 1082 REQUIRE(DNS_CLIENT_VALID(client)); 1083 REQUIRE(transp != NULL && *transp == NULL); 1084 1085 LOCK(&client->lock); 1086 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1087 rdclass, &view); 1088 UNLOCK(&client->lock); 1089 if (result != ISC_R_SUCCESS) { 1090 return (result); 1091 } 1092 1093 mctx = client->mctx; 1094 rdataset = NULL; 1095 sigrdataset = NULL; 1096 want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0); 1097 want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0); 1098 want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0); 1099 want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0); 1100 1101 /* 1102 * Prepare some intermediate resources 1103 */ 1104 tclone = NULL; 1105 isc_task_attach(task, &tclone); 1106 event = (dns_clientresevent_t *)isc_event_allocate( 1107 mctx, tclone, DNS_EVENT_CLIENTRESDONE, action, arg, 1108 sizeof(*event)); 1109 event->result = DNS_R_SERVFAIL; 1110 ISC_LIST_INIT(event->answerlist); 1111 1112 rctx = isc_mem_get(mctx, sizeof(*rctx)); 1113 isc_mutex_init(&rctx->lock); 1114 1115 result = getrdataset(mctx, &rdataset); 1116 if (result != ISC_R_SUCCESS) { 1117 goto cleanup; 1118 } 1119 rctx->rdataset = rdataset; 1120 1121 if (want_dnssec) { 1122 result = getrdataset(mctx, &sigrdataset); 1123 if (result != ISC_R_SUCCESS) { 1124 goto cleanup; 1125 } 1126 } 1127 rctx->sigrdataset = sigrdataset; 1128 1129 dns_fixedname_init(&rctx->name); 1130 dns_name_copy(name, dns_fixedname_name(&rctx->name)); 1131 1132 rctx->client = client; 1133 ISC_LINK_INIT(rctx, link); 1134 rctx->canceled = false; 1135 rctx->task = client->task; 1136 rctx->type = type; 1137 rctx->view = view; 1138 rctx->restarts = 0; 1139 rctx->fetch = NULL; 1140 rctx->want_dnssec = want_dnssec; 1141 rctx->want_validation = want_validation; 1142 rctx->want_cdflag = want_cdflag; 1143 rctx->want_tcp = want_tcp; 1144 ISC_LIST_INIT(rctx->namelist); 1145 rctx->event = event; 1146 1147 rctx->magic = RCTX_MAGIC; 1148 isc_refcount_increment(&client->references); 1149 1150 LOCK(&client->lock); 1151 ISC_LIST_APPEND(client->resctxs, rctx, link); 1152 UNLOCK(&client->lock); 1153 1154 *transp = (dns_clientrestrans_t *)rctx; 1155 client_resfind(rctx, NULL); 1156 1157 return (ISC_R_SUCCESS); 1158 1159cleanup: 1160 if (rdataset != NULL) { 1161 putrdataset(client->mctx, &rdataset); 1162 } 1163 if (sigrdataset != NULL) { 1164 putrdataset(client->mctx, &sigrdataset); 1165 } 1166 isc_mutex_destroy(&rctx->lock); 1167 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1168 isc_event_free(ISC_EVENT_PTR(&event)); 1169 isc_task_detach(&tclone); 1170 dns_view_detach(&view); 1171 1172 return (result); 1173} 1174 1175/*%< 1176 * Cancel an ongoing resolution procedure started via 1177 * dns_client_startresolve(). 1178 * 1179 * If the resolution procedure has not completed, post its CLIENTRESDONE 1180 * event with a result code of #ISC_R_CANCELED. 1181 */ 1182static void 1183cancelresolve(dns_clientrestrans_t *trans) { 1184 resctx_t *rctx = NULL; 1185 1186 REQUIRE(trans != NULL); 1187 rctx = (resctx_t *)trans; 1188 REQUIRE(RCTX_VALID(rctx)); 1189 1190 LOCK(&rctx->lock); 1191 1192 if (!rctx->canceled) { 1193 rctx->canceled = true; 1194 if (rctx->fetch != NULL) { 1195 dns_resolver_cancelfetch(rctx->fetch); 1196 } 1197 } 1198 1199 UNLOCK(&rctx->lock); 1200} 1201 1202void 1203dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) { 1204 dns_name_t *name; 1205 dns_rdataset_t *rdataset; 1206 1207 REQUIRE(DNS_CLIENT_VALID(client)); 1208 REQUIRE(namelist != NULL); 1209 1210 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) { 1211 ISC_LIST_UNLINK(*namelist, name, link); 1212 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) { 1213 ISC_LIST_UNLINK(name->list, rdataset, link); 1214 putrdataset(client->mctx, &rdataset); 1215 } 1216 dns_name_free(name, client->mctx); 1217 isc_mem_put(client->mctx, name, sizeof(*name)); 1218 } 1219} 1220 1221/*% 1222 * Destroy name resolution transaction state identified by '*transp'. 1223 * 1224 * The caller must have received the CLIENTRESDONE event (either because the 1225 * resolution completed or because cancelresolve() was called). 1226 */ 1227static void 1228destroyrestrans(dns_clientrestrans_t **transp) { 1229 resctx_t *rctx = NULL; 1230 isc_mem_t *mctx = NULL; 1231 dns_client_t *client = NULL; 1232 1233 REQUIRE(transp != NULL); 1234 1235 rctx = (resctx_t *)*transp; 1236 *transp = NULL; 1237 1238 REQUIRE(RCTX_VALID(rctx)); 1239 REQUIRE(rctx->fetch == NULL); 1240 REQUIRE(rctx->event == NULL); 1241 1242 client = rctx->client; 1243 1244 REQUIRE(DNS_CLIENT_VALID(client)); 1245 1246 mctx = client->mctx; 1247 dns_view_detach(&rctx->view); 1248 1249 /* 1250 * Wait for the lock in client_resfind to be released before 1251 * destroying the lock. 1252 */ 1253 LOCK(&rctx->lock); 1254 UNLOCK(&rctx->lock); 1255 1256 LOCK(&client->lock); 1257 1258 INSIST(ISC_LINK_LINKED(rctx, link)); 1259 ISC_LIST_UNLINK(client->resctxs, rctx, link); 1260 1261 UNLOCK(&client->lock); 1262 1263 INSIST(ISC_LIST_EMPTY(rctx->namelist)); 1264 1265 isc_mutex_destroy(&rctx->lock); 1266 rctx->magic = 0; 1267 1268 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1269} 1270 1271isc_result_t 1272dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, 1273 dns_rdatatype_t rdtype, const dns_name_t *keyname, 1274 isc_buffer_t *databuf) { 1275 isc_result_t result; 1276 dns_view_t *view = NULL; 1277 dns_keytable_t *secroots = NULL; 1278 dns_name_t *name = NULL; 1279 char rdatabuf[DST_KEY_MAXSIZE]; 1280 unsigned char digest[ISC_MAX_MD_SIZE]; 1281 dns_rdata_ds_t ds; 1282 dns_decompress_t dctx; 1283 dns_rdata_t rdata; 1284 isc_buffer_t b; 1285 1286 REQUIRE(DNS_CLIENT_VALID(client)); 1287 1288 LOCK(&client->lock); 1289 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1290 rdclass, &view); 1291 UNLOCK(&client->lock); 1292 CHECK(result); 1293 1294 CHECK(dns_view_getsecroots(view, &secroots)); 1295 1296 DE_CONST(keyname, name); 1297 1298 if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) { 1299 result = ISC_R_NOTIMPLEMENTED; 1300 goto cleanup; 1301 } 1302 1303 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1304 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE); 1305 dns_rdata_init(&rdata); 1306 isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf)); 1307 CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, databuf, &dctx, 0, 1308 &b)); 1309 dns_decompress_invalidate(&dctx); 1310 1311 if (rdtype == dns_rdatatype_ds) { 1312 CHECK(dns_rdata_tostruct(&rdata, &ds, NULL)); 1313 } else { 1314 CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, 1315 digest, &ds)); 1316 } 1317 1318 CHECK(dns_keytable_add(secroots, false, false, name, &ds, NULL, NULL)); 1319 1320cleanup: 1321 if (view != NULL) { 1322 dns_view_detach(&view); 1323 } 1324 if (secroots != NULL) { 1325 dns_keytable_detach(&secroots); 1326 } 1327 return (result); 1328} 1329