1 /* $NetBSD: client.c,v 1.15 2025/01/26 16:25:22 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/async.h> 20 #include <isc/buffer.h> 21 #include <isc/loop.h> 22 #include <isc/md.h> 23 #include <isc/mem.h> 24 #include <isc/mutex.h> 25 #include <isc/netmgr.h> 26 #include <isc/portset.h> 27 #include <isc/refcount.h> 28 #include <isc/result.h> 29 #include <isc/safe.h> 30 #include <isc/sockaddr.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/forward.h> 38 #include <dns/keytable.h> 39 #include <dns/message.h> 40 #include <dns/name.h> 41 #include <dns/rdata.h> 42 #include <dns/rdatalist.h> 43 #include <dns/rdataset.h> 44 #include <dns/rdatasetiter.h> 45 #include <dns/rdatastruct.h> 46 #include <dns/rdatatype.h> 47 #include <dns/request.h> 48 #include <dns/resolver.h> 49 #include <dns/tsig.h> 50 #include <dns/view.h> 51 52 #include <dst/dst.h> 53 54 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c') 55 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC) 56 57 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x') 58 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC) 59 60 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') 61 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) 62 63 #define CHECK(r) \ 64 do { \ 65 result = (r); \ 66 if (result != ISC_R_SUCCESS) \ 67 goto cleanup; \ 68 } while (0) 69 70 /*% 71 * DNS client object 72 */ 73 struct dns_client { 74 unsigned int magic; 75 unsigned int attributes; 76 isc_mem_t *mctx; 77 isc_loop_t *loop; 78 isc_nm_t *nm; 79 dns_dispatchmgr_t *dispatchmgr; 80 dns_dispatch_t *dispatchv4; 81 dns_dispatch_t *dispatchv6; 82 83 unsigned int find_timeout; 84 unsigned int find_udpretries; 85 uint8_t max_restarts; 86 87 isc_refcount_t references; 88 89 dns_view_t *view; 90 ISC_LIST(struct resctx) resctxs; 91 }; 92 93 #define DEF_FIND_TIMEOUT 5 94 #define DEF_FIND_UDPRETRIES 3 95 #define DEF_MAX_RESTARTS 11 96 97 /*% 98 * Internal state for a single name resolution procedure 99 */ 100 typedef struct resctx { 101 unsigned int magic; 102 dns_client_t *client; 103 bool want_dnssec; 104 bool want_validation; 105 bool want_cdflag; 106 bool want_tcp; 107 108 ISC_LINK(struct resctx) link; 109 dns_view_t *view; 110 unsigned int restarts; 111 dns_fixedname_t name; 112 dns_rdatatype_t type; 113 dns_fetch_t *fetch; 114 dns_namelist_t namelist; 115 isc_result_t result; 116 dns_clientresume_t *rev; 117 dns_rdataset_t *rdataset; 118 dns_rdataset_t *sigrdataset; 119 } resctx_t; 120 121 /*% 122 * Argument of an internal event for synchronous name resolution. 123 */ 124 typedef struct resarg { 125 isc_mem_t *mctx; 126 dns_client_t *client; 127 const dns_name_t *name; 128 129 isc_result_t result; 130 isc_result_t vresult; 131 dns_namelist_t *namelist; 132 dns_clientrestrans_t *trans; 133 dns_client_resolve_cb resolve_cb; 134 } resarg_t; 135 136 static void 137 client_resfind(resctx_t *rctx, dns_fetchresponse_t *event); 138 static void 139 destroyrestrans(dns_clientrestrans_t **transp); 140 141 /* 142 * Try honoring the operating system's preferred ephemeral port range. 143 */ 144 static isc_result_t 145 setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) { 146 isc_portset_t *v4portset = NULL, *v6portset = NULL; 147 in_port_t udpport_low, udpport_high; 148 isc_result_t result; 149 150 result = isc_portset_create(mctx, &v4portset); 151 if (result != ISC_R_SUCCESS) { 152 goto cleanup; 153 } 154 result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high); 155 if (result != ISC_R_SUCCESS) { 156 goto cleanup; 157 } 158 isc_portset_addrange(v4portset, udpport_low, udpport_high); 159 160 result = isc_portset_create(mctx, &v6portset); 161 if (result != ISC_R_SUCCESS) { 162 goto cleanup; 163 } 164 result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high); 165 if (result != ISC_R_SUCCESS) { 166 goto cleanup; 167 } 168 isc_portset_addrange(v6portset, udpport_low, udpport_high); 169 170 result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset); 171 172 cleanup: 173 if (v4portset != NULL) { 174 isc_portset_destroy(mctx, &v4portset); 175 } 176 if (v6portset != NULL) { 177 isc_portset_destroy(mctx, &v6portset); 178 } 179 180 return result; 181 } 182 183 static isc_result_t 184 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, 185 dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) { 186 dns_dispatch_t *disp = NULL; 187 isc_result_t result; 188 isc_sockaddr_t anyaddr; 189 190 if (localaddr == NULL) { 191 isc_sockaddr_anyofpf(&anyaddr, family); 192 localaddr = &anyaddr; 193 } 194 195 result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp); 196 if (result == ISC_R_SUCCESS) { 197 *dispp = disp; 198 } 199 200 return result; 201 } 202 203 static isc_result_t 204 createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_nm_t *nm, 205 isc_tlsctx_cache_t *tlsctx_client_cache, isc_loopmgr_t *loopmgr, 206 dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, 207 dns_dispatch_t *dispatchv6, dns_view_t **viewp) { 208 isc_result_t result; 209 dns_view_t *view = NULL; 210 211 result = dns_view_create(mctx, loopmgr, dispatchmgr, rdclass, 212 DNS_CLIENTVIEW_NAME, &view); 213 if (result != ISC_R_SUCCESS) { 214 return result; 215 } 216 217 /* Initialize view security roots */ 218 dns_view_initsecroots(view); 219 220 CHECK(dns_view_createresolver(view, nm, 0, tlsctx_client_cache, 221 dispatchv4, dispatchv6)); 222 CHECK(dns_db_create(mctx, CACHEDB_DEFAULT, dns_rootname, 223 dns_dbtype_cache, rdclass, 0, NULL, 224 &view->cachedb)); 225 226 *viewp = view; 227 return ISC_R_SUCCESS; 228 229 cleanup: 230 dns_view_detach(&view); 231 return result; 232 } 233 234 isc_result_t 235 dns_client_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, isc_nm_t *nm, 236 unsigned int options, isc_tlsctx_cache_t *tlsctx_client_cache, 237 dns_client_t **clientp, const isc_sockaddr_t *localaddr4, 238 const isc_sockaddr_t *localaddr6) { 239 isc_result_t result; 240 dns_client_t *client = NULL; 241 dns_dispatch_t *dispatchv4 = NULL; 242 dns_dispatch_t *dispatchv6 = NULL; 243 dns_view_t *view = NULL; 244 245 REQUIRE(mctx != NULL); 246 REQUIRE(nm != NULL); 247 REQUIRE(tlsctx_client_cache != NULL); 248 REQUIRE(clientp != NULL && *clientp == NULL); 249 250 UNUSED(options); 251 252 client = isc_mem_get(mctx, sizeof(*client)); 253 *client = (dns_client_t){ 254 .loop = isc_loop_get(loopmgr, 0), 255 .nm = nm, 256 .max_restarts = DEF_MAX_RESTARTS, 257 }; 258 259 result = dns_dispatchmgr_create(mctx, loopmgr, nm, 260 &client->dispatchmgr); 261 if (result != ISC_R_SUCCESS) { 262 goto cleanup_client; 263 } 264 (void)setsourceports(mctx, client->dispatchmgr); 265 266 /* 267 * If only one address family is specified, use it. 268 * If neither family is specified, or if both are, use both. 269 */ 270 client->dispatchv4 = NULL; 271 if (localaddr4 != NULL || localaddr6 == NULL) { 272 result = getudpdispatch(AF_INET, client->dispatchmgr, 273 &dispatchv4, localaddr4); 274 if (result == ISC_R_SUCCESS) { 275 client->dispatchv4 = dispatchv4; 276 } 277 } 278 279 client->dispatchv6 = NULL; 280 if (localaddr6 != NULL || localaddr4 == NULL) { 281 result = getudpdispatch(AF_INET6, client->dispatchmgr, 282 &dispatchv6, localaddr6); 283 if (result == ISC_R_SUCCESS) { 284 client->dispatchv6 = dispatchv6; 285 } 286 } 287 288 /* We need at least one of the dispatchers */ 289 if (dispatchv4 == NULL && dispatchv6 == NULL) { 290 INSIST(result != ISC_R_SUCCESS); 291 goto cleanup_dispatchmgr; 292 } 293 294 isc_refcount_init(&client->references, 1); 295 296 /* Create the default view for class IN */ 297 result = createview(mctx, dns_rdataclass_in, nm, tlsctx_client_cache, 298 isc_loop_getloopmgr(client->loop), 299 client->dispatchmgr, dispatchv4, dispatchv6, &view); 300 if (result != ISC_R_SUCCESS) { 301 goto cleanup_references; 302 } 303 304 client->view = view; 305 306 dns_view_freeze(view); /* too early? */ 307 308 ISC_LIST_INIT(client->resctxs); 309 310 isc_mem_attach(mctx, &client->mctx); 311 312 client->find_timeout = DEF_FIND_TIMEOUT; 313 client->find_udpretries = DEF_FIND_UDPRETRIES; 314 315 client->magic = DNS_CLIENT_MAGIC; 316 317 *clientp = client; 318 319 return ISC_R_SUCCESS; 320 321 cleanup_references: 322 isc_refcount_decrementz(&client->references); 323 isc_refcount_destroy(&client->references); 324 cleanup_dispatchmgr: 325 if (dispatchv4 != NULL) { 326 dns_dispatch_detach(&dispatchv4); 327 } 328 if (dispatchv6 != NULL) { 329 dns_dispatch_detach(&dispatchv6); 330 } 331 dns_dispatchmgr_detach(&client->dispatchmgr); 332 cleanup_client: 333 isc_mem_put(mctx, client, sizeof(*client)); 334 335 return result; 336 } 337 338 static void 339 destroyclient(dns_client_t *client) { 340 isc_refcount_destroy(&client->references); 341 342 dns_view_detach(&client->view); 343 344 if (client->dispatchv4 != NULL) { 345 dns_dispatch_detach(&client->dispatchv4); 346 } 347 if (client->dispatchv6 != NULL) { 348 dns_dispatch_detach(&client->dispatchv6); 349 } 350 351 dns_dispatchmgr_detach(&client->dispatchmgr); 352 353 client->magic = 0; 354 355 isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); 356 } 357 358 void 359 dns_client_detach(dns_client_t **clientp) { 360 dns_client_t *client = NULL; 361 362 REQUIRE(clientp != NULL); 363 REQUIRE(DNS_CLIENT_VALID(*clientp)); 364 365 client = *clientp; 366 *clientp = NULL; 367 368 if (isc_refcount_decrement(&client->references) == 1) { 369 destroyclient(client); 370 } 371 } 372 373 isc_result_t 374 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, 375 const dns_name_t *name_space, isc_sockaddrlist_t *addrs) { 376 isc_result_t result; 377 378 REQUIRE(DNS_CLIENT_VALID(client)); 379 REQUIRE(addrs != NULL); 380 REQUIRE(rdclass == dns_rdataclass_in); 381 382 if (name_space == NULL) { 383 name_space = dns_rootname; 384 } 385 386 result = dns_fwdtable_add(client->view->fwdtable, name_space, addrs, 387 dns_fwdpolicy_only); 388 389 return result; 390 } 391 392 void 393 dns_client_setmaxrestarts(dns_client_t *client, uint8_t max_restarts) { 394 REQUIRE(DNS_CLIENT_VALID(client)); 395 REQUIRE(max_restarts > 0); 396 397 client->max_restarts = max_restarts; 398 } 399 400 static isc_result_t 401 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 402 dns_rdataset_t *rdataset; 403 404 REQUIRE(mctx != NULL); 405 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); 406 407 rdataset = isc_mem_get(mctx, sizeof(*rdataset)); 408 409 dns_rdataset_init(rdataset); 410 411 *rdatasetp = rdataset; 412 413 return ISC_R_SUCCESS; 414 } 415 416 static void 417 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 418 dns_rdataset_t *rdataset; 419 420 REQUIRE(rdatasetp != NULL); 421 rdataset = *rdatasetp; 422 *rdatasetp = NULL; 423 REQUIRE(rdataset != NULL); 424 425 if (dns_rdataset_isassociated(rdataset)) { 426 dns_rdataset_disassociate(rdataset); 427 } 428 429 isc_mem_put(mctx, rdataset, sizeof(*rdataset)); 430 } 431 432 static void 433 fetch_done(void *arg) { 434 dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg; 435 resctx_t *rctx = resp->arg; 436 437 REQUIRE(RCTX_VALID(rctx)); 438 439 client_resfind(rctx, resp); 440 } 441 442 static isc_result_t 443 start_fetch(resctx_t *rctx) { 444 isc_result_t result; 445 int fopts = 0; 446 447 REQUIRE(rctx->fetch == NULL); 448 449 if (!rctx->want_cdflag) { 450 fopts |= DNS_FETCHOPT_NOCDFLAG; 451 } 452 if (!rctx->want_validation) { 453 fopts |= DNS_FETCHOPT_NOVALIDATE; 454 } 455 if (rctx->want_tcp) { 456 fopts |= DNS_FETCHOPT_TCP; 457 } 458 459 result = dns_resolver_createfetch( 460 rctx->view->resolver, dns_fixedname_name(&rctx->name), 461 rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL, 462 rctx->client->loop, fetch_done, rctx, rctx->rdataset, 463 rctx->sigrdataset, &rctx->fetch); 464 465 return result; 466 } 467 468 static isc_result_t 469 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep, 470 dns_name_t *foundname) { 471 isc_result_t result; 472 dns_name_t *name = dns_fixedname_name(&rctx->name); 473 dns_rdatatype_t type; 474 475 if (rctx->type == dns_rdatatype_rrsig) { 476 type = dns_rdatatype_any; 477 } else { 478 type = rctx->type; 479 } 480 481 result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp, 482 nodep, foundname, rctx->rdataset, 483 rctx->sigrdataset); 484 485 return result; 486 } 487 488 static void 489 client_resfind(resctx_t *rctx, dns_fetchresponse_t *resp) { 490 isc_mem_t *mctx = NULL; 491 isc_result_t tresult, result = ISC_R_SUCCESS; 492 isc_result_t vresult = ISC_R_SUCCESS; 493 bool want_restart; 494 bool send_event = false; 495 dns_name_t *name = NULL, *prefix = NULL; 496 dns_fixedname_t foundname, fixed; 497 dns_rdataset_t *trdataset = NULL; 498 dns_rdata_t rdata = DNS_RDATA_INIT; 499 unsigned int nlabels; 500 int order; 501 dns_namereln_t namereln; 502 dns_rdata_cname_t cname; 503 dns_rdata_dname_t dname; 504 505 REQUIRE(RCTX_VALID(rctx)); 506 507 mctx = rctx->view->mctx; 508 509 name = dns_fixedname_name(&rctx->name); 510 511 do { 512 dns_name_t *fname = NULL; 513 dns_name_t *ansname = NULL; 514 dns_db_t *db = NULL; 515 dns_dbnode_t *node = NULL; 516 517 rctx->restarts++; 518 want_restart = false; 519 520 if (resp == NULL) { 521 fname = dns_fixedname_initname(&foundname); 522 INSIST(!dns_rdataset_isassociated(rctx->rdataset)); 523 INSIST(rctx->sigrdataset == NULL || 524 !dns_rdataset_isassociated(rctx->sigrdataset)); 525 result = view_find(rctx, &db, &node, fname); 526 if (result == ISC_R_NOTFOUND) { 527 /* 528 * We don't know anything about the name. 529 * Launch a fetch. 530 */ 531 if (node != NULL) { 532 INSIST(db != NULL); 533 dns_db_detachnode(db, &node); 534 } 535 if (db != NULL) { 536 dns_db_detach(&db); 537 } 538 result = start_fetch(rctx); 539 if (result != ISC_R_SUCCESS) { 540 putrdataset(mctx, &rctx->rdataset); 541 if (rctx->sigrdataset != NULL) { 542 putrdataset(mctx, 543 &rctx->sigrdataset); 544 } 545 send_event = true; 546 } 547 goto done; 548 } 549 } else { 550 INSIST(resp != NULL); 551 INSIST(resp->fetch == rctx->fetch); 552 dns_resolver_destroyfetch(&rctx->fetch); 553 db = resp->db; 554 node = resp->node; 555 result = resp->result; 556 vresult = resp->vresult; 557 fname = resp->foundname; 558 INSIST(resp->rdataset == rctx->rdataset); 559 INSIST(resp->sigrdataset == rctx->sigrdataset); 560 isc_mem_putanddetach(&resp->mctx, resp, sizeof(*resp)); 561 } 562 563 /* 564 * Get some resource for copying the 565 * result. 566 */ 567 dns_name_t *aname = dns_fixedname_name(&rctx->name); 568 569 ansname = isc_mem_get(mctx, sizeof(*ansname)); 570 dns_name_init(ansname, NULL); 571 572 dns_name_dup(aname, mctx, ansname); 573 574 switch (result) { 575 case ISC_R_SUCCESS: 576 send_event = true; 577 /* 578 * This case is handled in the main line below. 579 */ 580 break; 581 case DNS_R_CNAME: 582 /* 583 * Add the CNAME to the answer list. 584 */ 585 trdataset = rctx->rdataset; 586 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 587 rctx->rdataset = NULL; 588 if (rctx->sigrdataset != NULL) { 589 ISC_LIST_APPEND(ansname->list, 590 rctx->sigrdataset, link); 591 rctx->sigrdataset = NULL; 592 } 593 ISC_LIST_APPEND(rctx->namelist, ansname, link); 594 ansname = NULL; 595 596 /* 597 * Copy the CNAME's target into the lookup's 598 * query name and start over. 599 */ 600 tresult = dns_rdataset_first(trdataset); 601 if (tresult != ISC_R_SUCCESS) { 602 goto done; 603 } 604 dns_rdataset_current(trdataset, &rdata); 605 tresult = dns_rdata_tostruct(&rdata, &cname, NULL); 606 dns_rdata_reset(&rdata); 607 if (tresult != ISC_R_SUCCESS) { 608 goto done; 609 } 610 dns_name_copy(&cname.cname, name); 611 dns_rdata_freestruct(&cname); 612 want_restart = true; 613 goto done; 614 case DNS_R_DNAME: 615 /* 616 * Add the DNAME to the answer list. 617 */ 618 trdataset = rctx->rdataset; 619 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 620 rctx->rdataset = NULL; 621 if (rctx->sigrdataset != NULL) { 622 ISC_LIST_APPEND(ansname->list, 623 rctx->sigrdataset, link); 624 rctx->sigrdataset = NULL; 625 } 626 ISC_LIST_APPEND(rctx->namelist, ansname, link); 627 ansname = NULL; 628 629 namereln = dns_name_fullcompare(name, fname, &order, 630 &nlabels); 631 INSIST(namereln == dns_namereln_subdomain); 632 /* 633 * Get the target name of the DNAME. 634 */ 635 tresult = dns_rdataset_first(trdataset); 636 if (tresult != ISC_R_SUCCESS) { 637 result = tresult; 638 goto done; 639 } 640 dns_rdataset_current(trdataset, &rdata); 641 tresult = dns_rdata_tostruct(&rdata, &dname, NULL); 642 dns_rdata_reset(&rdata); 643 if (tresult != ISC_R_SUCCESS) { 644 result = tresult; 645 goto done; 646 } 647 /* 648 * Construct the new query name and start over. 649 */ 650 prefix = dns_fixedname_initname(&fixed); 651 dns_name_split(name, nlabels, prefix, NULL); 652 tresult = dns_name_concatenate(prefix, &dname.dname, 653 name, NULL); 654 dns_rdata_freestruct(&dname); 655 if (tresult == ISC_R_SUCCESS) { 656 want_restart = true; 657 } else { 658 result = tresult; 659 } 660 goto done; 661 case DNS_R_NCACHENXDOMAIN: 662 case DNS_R_NCACHENXRRSET: 663 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 664 ISC_LIST_APPEND(rctx->namelist, ansname, link); 665 ansname = NULL; 666 rctx->rdataset = NULL; 667 /* What about sigrdataset? */ 668 if (rctx->sigrdataset != NULL) { 669 putrdataset(mctx, &rctx->sigrdataset); 670 } 671 send_event = true; 672 goto done; 673 default: 674 if (rctx->rdataset != NULL) { 675 putrdataset(mctx, &rctx->rdataset); 676 } 677 if (rctx->sigrdataset != NULL) { 678 putrdataset(mctx, &rctx->sigrdataset); 679 } 680 send_event = true; 681 goto done; 682 } 683 684 if (rctx->type == dns_rdatatype_any) { 685 int n = 0; 686 dns_rdatasetiter_t *rdsiter = NULL; 687 688 tresult = dns_db_allrdatasets(db, node, NULL, 0, 0, 689 &rdsiter); 690 if (tresult != ISC_R_SUCCESS) { 691 result = tresult; 692 goto done; 693 } 694 695 tresult = dns_rdatasetiter_first(rdsiter); 696 while (tresult == ISC_R_SUCCESS) { 697 dns_rdatasetiter_current(rdsiter, 698 rctx->rdataset); 699 if (rctx->rdataset->type != 0) { 700 ISC_LIST_APPEND(ansname->list, 701 rctx->rdataset, link); 702 n++; 703 rctx->rdataset = NULL; 704 } else { 705 /* 706 * We're not interested in this 707 * rdataset. 708 */ 709 dns_rdataset_disassociate( 710 rctx->rdataset); 711 } 712 tresult = dns_rdatasetiter_next(rdsiter); 713 714 if (tresult == ISC_R_SUCCESS && 715 rctx->rdataset == NULL) 716 { 717 tresult = getrdataset(mctx, 718 &rctx->rdataset); 719 if (tresult != ISC_R_SUCCESS) { 720 result = tresult; 721 POST(result); 722 break; 723 } 724 } 725 } 726 if (rctx->rdataset != NULL) { 727 putrdataset(mctx, &rctx->rdataset); 728 } 729 if (rctx->sigrdataset != NULL) { 730 putrdataset(mctx, &rctx->sigrdataset); 731 } 732 if (n == 0) { 733 /* 734 * We didn't match any rdatasets (which means 735 * something went wrong in this 736 * implementation). 737 */ 738 result = DNS_R_SERVFAIL; /* better code? */ 739 POST(result); 740 } else { 741 ISC_LIST_APPEND(rctx->namelist, ansname, link); 742 ansname = NULL; 743 } 744 dns_rdatasetiter_destroy(&rdsiter); 745 if (tresult != ISC_R_NOMORE) { 746 result = DNS_R_SERVFAIL; /* ditto */ 747 } else { 748 result = ISC_R_SUCCESS; 749 } 750 goto done; 751 } else { 752 /* 753 * This is the "normal" case -- an ordinary question 754 * to which we've got the answer. 755 */ 756 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 757 rctx->rdataset = NULL; 758 if (rctx->sigrdataset != NULL) { 759 ISC_LIST_APPEND(ansname->list, 760 rctx->sigrdataset, link); 761 rctx->sigrdataset = NULL; 762 } 763 ISC_LIST_APPEND(rctx->namelist, ansname, link); 764 ansname = NULL; 765 } 766 767 done: 768 /* 769 * Free temporary resources 770 */ 771 if (ansname != NULL) { 772 dns_rdataset_t *rdataset; 773 774 while ((rdataset = ISC_LIST_HEAD(ansname->list)) != 775 NULL) 776 { 777 ISC_LIST_UNLINK(ansname->list, rdataset, link); 778 putrdataset(mctx, &rdataset); 779 } 780 dns_name_free(ansname, mctx); 781 isc_mem_put(mctx, ansname, sizeof(*ansname)); 782 } 783 784 if (node != NULL) { 785 dns_db_detachnode(db, &node); 786 } 787 if (db != NULL) { 788 dns_db_detach(&db); 789 } 790 791 /* 792 * Limit the number of restarts. 793 */ 794 if (want_restart && 795 rctx->restarts == rctx->client->max_restarts) 796 { 797 want_restart = false; 798 result = ISC_R_QUOTA; 799 send_event = true; 800 } 801 802 /* 803 * Prepare further find with new resources 804 */ 805 if (want_restart) { 806 INSIST(rctx->rdataset == NULL && 807 rctx->sigrdataset == NULL); 808 809 result = getrdataset(mctx, &rctx->rdataset); 810 if (result == ISC_R_SUCCESS && rctx->want_dnssec) { 811 result = getrdataset(mctx, &rctx->sigrdataset); 812 if (result != ISC_R_SUCCESS) { 813 putrdataset(mctx, &rctx->rdataset); 814 } 815 } 816 817 if (result != ISC_R_SUCCESS) { 818 want_restart = false; 819 send_event = true; 820 } 821 } 822 } while (want_restart); 823 824 if (send_event) { 825 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) { 826 ISC_LIST_UNLINK(rctx->namelist, name, link); 827 ISC_LIST_APPEND(rctx->rev->answerlist, name, link); 828 } 829 830 rctx->rev->result = result; 831 rctx->rev->vresult = vresult; 832 isc_async_run(rctx->client->loop, rctx->rev->cb, rctx->rev); 833 } 834 } 835 836 static void 837 resolve_done(void *arg) { 838 dns_clientresume_t *rev = (dns_clientresume_t *)arg; 839 resarg_t *resarg = rev->arg; 840 dns_name_t *name = NULL; 841 isc_result_t result; 842 843 resarg->result = rev->result; 844 resarg->vresult = rev->vresult; 845 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) { 846 ISC_LIST_UNLINK(rev->answerlist, name, link); 847 ISC_LIST_APPEND(*resarg->namelist, name, link); 848 } 849 850 isc_mem_put(resarg->mctx, rev, sizeof(*rev)); 851 destroyrestrans(&resarg->trans); 852 853 result = resarg->result; 854 855 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) { 856 /* 857 * If this lookup failed due to some error in DNSSEC 858 * validation, return the validation error code. 859 * XXX: or should we pass the validation result separately? 860 */ 861 result = resarg->vresult; 862 } 863 864 resarg->resolve_cb(resarg->client, resarg->name, resarg->namelist, 865 result); 866 867 dns_client_detach(&resarg->client); 868 869 isc_mem_putanddetach(&resarg->mctx, resarg, sizeof(*resarg)); 870 } 871 872 static isc_result_t 873 startresolve(dns_client_t *client, const dns_name_t *name, 874 dns_rdataclass_t rdclass, dns_rdatatype_t type, 875 unsigned int options, isc_job_cb cb, void *arg, 876 dns_clientrestrans_t **transp) { 877 dns_clientresume_t *rev = NULL; 878 resctx_t *rctx = NULL; 879 isc_mem_t *mctx = NULL; 880 isc_result_t result; 881 dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; 882 bool want_dnssec, want_validation, want_cdflag, want_tcp; 883 884 REQUIRE(DNS_CLIENT_VALID(client)); 885 REQUIRE(transp != NULL && *transp == NULL); 886 REQUIRE(rdclass == dns_rdataclass_in); 887 888 mctx = client->mctx; 889 want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0); 890 want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0); 891 want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0); 892 want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0); 893 894 /* 895 * Prepare some intermediate resources 896 */ 897 rev = isc_mem_get(mctx, sizeof(*rev)); 898 *rev = (dns_clientresume_t){ 899 .result = DNS_R_SERVFAIL, 900 .answerlist = ISC_LIST_INITIALIZER, 901 .cb = cb, 902 .arg = arg, 903 }; 904 905 rctx = isc_mem_get(mctx, sizeof(*rctx)); 906 *rctx = (resctx_t){ 907 .client = client, 908 .rev = rev, 909 .type = type, 910 .want_dnssec = want_dnssec, 911 .want_validation = want_validation, 912 .want_cdflag = want_cdflag, 913 .want_tcp = want_tcp, 914 .namelist = ISC_LIST_INITIALIZER, 915 .link = ISC_LINK_INITIALIZER, 916 }; 917 918 result = getrdataset(mctx, &rdataset); 919 if (result != ISC_R_SUCCESS) { 920 goto cleanup; 921 } 922 rctx->rdataset = rdataset; 923 924 if (want_dnssec) { 925 result = getrdataset(mctx, &sigrdataset); 926 if (result != ISC_R_SUCCESS) { 927 goto cleanup; 928 } 929 } 930 rctx->sigrdataset = sigrdataset; 931 932 dns_fixedname_init(&rctx->name); 933 dns_name_copy(name, dns_fixedname_name(&rctx->name)); 934 935 dns_view_attach(client->view, &rctx->view); 936 937 rctx->magic = RCTX_MAGIC; 938 isc_refcount_increment(&client->references); 939 940 ISC_LIST_APPEND(client->resctxs, rctx, link); 941 942 *transp = (dns_clientrestrans_t *)rctx; 943 client_resfind(rctx, NULL); 944 945 return ISC_R_SUCCESS; 946 947 cleanup: 948 if (rdataset != NULL) { 949 putrdataset(client->mctx, &rdataset); 950 } 951 if (sigrdataset != NULL) { 952 putrdataset(client->mctx, &sigrdataset); 953 } 954 isc_mem_put(mctx, rctx, sizeof(*rctx)); 955 isc_mem_put(mctx, rev, sizeof(*rev)); 956 957 return result; 958 } 959 960 isc_result_t 961 dns_client_resolve(dns_client_t *client, const dns_name_t *name, 962 dns_rdataclass_t rdclass, dns_rdatatype_t type, 963 unsigned int options, dns_namelist_t *namelist, 964 dns_client_resolve_cb resolve_cb) { 965 isc_result_t result; 966 resarg_t *resarg = NULL; 967 968 REQUIRE(DNS_CLIENT_VALID(client)); 969 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist)); 970 REQUIRE(rdclass == dns_rdataclass_in); 971 972 resarg = isc_mem_get(client->mctx, sizeof(*resarg)); 973 974 *resarg = (resarg_t){ 975 .client = client, 976 .name = name, 977 .result = DNS_R_SERVFAIL, 978 .namelist = namelist, 979 .resolve_cb = resolve_cb, 980 }; 981 982 isc_mem_attach(client->mctx, &resarg->mctx); 983 984 result = startresolve(client, name, rdclass, type, options, 985 resolve_done, resarg, &resarg->trans); 986 if (result != ISC_R_SUCCESS) { 987 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 988 return result; 989 } 990 991 return result; 992 } 993 994 void 995 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) { 996 dns_name_t *name; 997 dns_rdataset_t *rdataset; 998 999 REQUIRE(DNS_CLIENT_VALID(client)); 1000 REQUIRE(namelist != NULL); 1001 1002 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) { 1003 ISC_LIST_UNLINK(*namelist, name, link); 1004 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) { 1005 ISC_LIST_UNLINK(name->list, rdataset, link); 1006 putrdataset(client->mctx, &rdataset); 1007 } 1008 dns_name_free(name, client->mctx); 1009 isc_mem_put(client->mctx, name, sizeof(*name)); 1010 } 1011 } 1012 1013 /*% 1014 * Destroy name resolution transaction state identified by '*transp'. 1015 * 1016 * The caller must have received the CLIENTRESDONE event (either because the 1017 * resolution completed or because cancelresolve() was called). 1018 */ 1019 static void 1020 destroyrestrans(dns_clientrestrans_t **transp) { 1021 resctx_t *rctx = NULL; 1022 isc_mem_t *mctx = NULL; 1023 dns_client_t *client = NULL; 1024 1025 REQUIRE(transp != NULL); 1026 1027 rctx = (resctx_t *)*transp; 1028 *transp = NULL; 1029 1030 REQUIRE(RCTX_VALID(rctx)); 1031 REQUIRE(rctx->fetch == NULL); 1032 1033 client = rctx->client; 1034 1035 REQUIRE(DNS_CLIENT_VALID(client)); 1036 1037 mctx = client->mctx; 1038 dns_view_detach(&rctx->view); 1039 1040 INSIST(ISC_LINK_LINKED(rctx, link)); 1041 ISC_LIST_UNLINK(client->resctxs, rctx, link); 1042 1043 INSIST(ISC_LIST_EMPTY(rctx->namelist)); 1044 1045 rctx->magic = 0; 1046 1047 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1048 } 1049 1050 isc_result_t 1051 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, 1052 dns_rdatatype_t rdtype, const dns_name_t *keyname, 1053 isc_buffer_t *databuf) { 1054 REQUIRE(DNS_CLIENT_VALID(client)); 1055 REQUIRE(rdclass == dns_rdataclass_in); 1056 1057 return dns_view_addtrustedkey(client->view, rdtype, keyname, databuf); 1058 } 1059