1 /* $NetBSD: client.c,v 1.12 2023/01/25 21:43:30 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/safe.h> 27 #include <isc/sockaddr.h> 28 #include <isc/socket.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/result.h> 51 #include <dns/tsec.h> 52 #include <dns/tsig.h> 53 #include <dns/view.h> 54 55 #include <dst/dst.h> 56 57 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c') 58 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC) 59 60 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x') 61 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC) 62 63 #define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x') 64 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC) 65 66 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x') 67 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC) 68 69 #define MAX_RESTARTS 16 70 71 #ifdef TUNE_LARGE 72 #define RESOLVER_NTASKS 523 73 #else /* ifdef TUNE_LARGE */ 74 #define RESOLVER_NTASKS 31 75 #endif /* TUNE_LARGE */ 76 77 #define CHECK(r) \ 78 do { \ 79 result = (r); \ 80 if (result != ISC_R_SUCCESS) \ 81 goto cleanup; \ 82 } while (0) 83 84 /*% 85 * DNS client object 86 */ 87 struct dns_client { 88 /* Unlocked */ 89 unsigned int magic; 90 unsigned int attributes; 91 isc_mutex_t lock; 92 isc_mem_t *mctx; 93 isc_appctx_t *actx; 94 isc_taskmgr_t *taskmgr; 95 isc_task_t *task; 96 isc_socketmgr_t *socketmgr; 97 isc_timermgr_t *timermgr; 98 dns_dispatchmgr_t *dispatchmgr; 99 dns_dispatch_t *dispatchv4; 100 dns_dispatch_t *dispatchv6; 101 102 unsigned int update_timeout; 103 unsigned int update_udptimeout; 104 unsigned int update_udpretries; 105 unsigned int find_timeout; 106 unsigned int find_udpretries; 107 108 isc_refcount_t references; 109 110 /* Locked */ 111 dns_viewlist_t viewlist; 112 ISC_LIST(struct resctx) resctxs; 113 ISC_LIST(struct reqctx) reqctxs; 114 ISC_LIST(struct updatectx) updatectxs; 115 }; 116 117 /*% 118 * Timeout/retry constants for dynamic update borrowed from nsupdate 119 */ 120 #define DEF_UPDATE_TIMEOUT 300 121 #define MIN_UPDATE_TIMEOUT 30 122 #define DEF_UPDATE_UDPTIMEOUT 3 123 #define DEF_UPDATE_UDPRETRIES 3 124 125 #define DEF_FIND_TIMEOUT 5 126 #define DEF_FIND_UDPRETRIES 3 127 128 #define DNS_CLIENTATTR_OWNCTX 0x01 129 130 /*% 131 * Internal state for a single name resolution procedure 132 */ 133 typedef struct resctx { 134 /* Unlocked */ 135 unsigned int magic; 136 isc_mutex_t lock; 137 dns_client_t *client; 138 bool want_dnssec; 139 bool want_validation; 140 bool want_cdflag; 141 bool want_tcp; 142 143 /* Locked */ 144 ISC_LINK(struct resctx) link; 145 isc_task_t *task; 146 dns_view_t *view; 147 unsigned int restarts; 148 dns_fixedname_t name; 149 dns_rdatatype_t type; 150 dns_fetch_t *fetch; 151 dns_namelist_t namelist; 152 isc_result_t result; 153 dns_clientresevent_t *event; 154 bool canceled; 155 dns_rdataset_t *rdataset; 156 dns_rdataset_t *sigrdataset; 157 } resctx_t; 158 159 /*% 160 * Argument of an internal event for synchronous name resolution. 161 */ 162 typedef struct resarg { 163 /* Unlocked */ 164 isc_appctx_t *actx; 165 dns_client_t *client; 166 isc_mutex_t lock; 167 168 /* Locked */ 169 isc_result_t result; 170 isc_result_t vresult; 171 dns_namelist_t *namelist; 172 dns_clientrestrans_t *trans; 173 bool canceled; 174 } resarg_t; 175 176 /*% 177 * Internal state for a single DNS request 178 */ 179 typedef struct reqctx { 180 /* Unlocked */ 181 unsigned int magic; 182 isc_mutex_t lock; 183 dns_client_t *client; 184 unsigned int parseoptions; 185 186 /* Locked */ 187 ISC_LINK(struct reqctx) link; 188 bool canceled; 189 dns_tsigkey_t *tsigkey; 190 dns_request_t *request; 191 dns_clientreqevent_t *event; 192 } reqctx_t; 193 194 /*% 195 * Argument of an internal event for synchronous DNS request. 196 */ 197 typedef struct reqarg { 198 /* Unlocked */ 199 isc_appctx_t *actx; 200 dns_client_t *client; 201 isc_mutex_t lock; 202 203 /* Locked */ 204 isc_result_t result; 205 dns_clientreqtrans_t *trans; 206 bool canceled; 207 } reqarg_t; 208 209 /*% 210 * Argument of an internal event for synchronous name resolution. 211 */ 212 typedef struct updatearg { 213 /* Unlocked */ 214 isc_appctx_t *actx; 215 dns_client_t *client; 216 isc_mutex_t lock; 217 218 /* Locked */ 219 isc_result_t result; 220 dns_clientupdatetrans_t *trans; 221 bool canceled; 222 } updatearg_t; 223 224 /*% 225 * Internal state for a single dynamic update procedure 226 */ 227 typedef struct updatectx { 228 /* Unlocked */ 229 unsigned int magic; 230 isc_mutex_t lock; 231 dns_client_t *client; 232 bool want_tcp; 233 234 /* Locked */ 235 dns_request_t *updatereq; 236 dns_request_t *soareq; 237 dns_clientrestrans_t *restrans; 238 dns_clientrestrans_t *restrans2; 239 bool canceled; 240 241 /* Task Locked */ 242 ISC_LINK(struct updatectx) link; 243 dns_clientupdatestate_t state; 244 dns_rdataclass_t rdclass; 245 dns_view_t *view; 246 dns_message_t *updatemsg; 247 dns_message_t *soaquery; 248 dns_clientupdateevent_t *event; 249 dns_tsigkey_t *tsigkey; 250 dst_key_t *sig0key; 251 dns_name_t *firstname; 252 dns_name_t soaqname; 253 dns_fixedname_t zonefname; 254 dns_name_t *zonename; 255 isc_sockaddrlist_t servers; 256 unsigned int nservers; 257 isc_sockaddr_t *currentserver; 258 struct updatectx *bp4; 259 struct updatectx *bp6; 260 } updatectx_t; 261 262 static isc_result_t 263 request_soa(updatectx_t *uctx); 264 static void 265 client_resfind(resctx_t *rctx, dns_fetchevent_t *event); 266 static isc_result_t 267 send_update(updatectx_t *uctx); 268 269 /* 270 * Try honoring the operating system's preferred ephemeral port range. 271 */ 272 static isc_result_t 273 setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) { 274 isc_portset_t *v4portset = NULL, *v6portset = NULL; 275 in_port_t udpport_low, udpport_high; 276 isc_result_t result; 277 278 result = isc_portset_create(mctx, &v4portset); 279 if (result != ISC_R_SUCCESS) { 280 goto cleanup; 281 } 282 result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high); 283 if (result != ISC_R_SUCCESS) { 284 goto cleanup; 285 } 286 isc_portset_addrange(v4portset, udpport_low, udpport_high); 287 288 result = isc_portset_create(mctx, &v6portset); 289 if (result != ISC_R_SUCCESS) { 290 goto cleanup; 291 } 292 result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high); 293 if (result != ISC_R_SUCCESS) { 294 goto cleanup; 295 } 296 isc_portset_addrange(v6portset, udpport_low, udpport_high); 297 298 result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset); 299 300 cleanup: 301 if (v4portset != NULL) { 302 isc_portset_destroy(mctx, &v4portset); 303 } 304 if (v6portset != NULL) { 305 isc_portset_destroy(mctx, &v6portset); 306 } 307 308 return (result); 309 } 310 311 static isc_result_t 312 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr, 313 isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, 314 bool is_shared, dns_dispatch_t **dispp, 315 const isc_sockaddr_t *localaddr) { 316 unsigned int attrs, attrmask; 317 dns_dispatch_t *disp; 318 unsigned buffersize, maxbuffers, maxrequests, buckets, increment; 319 isc_result_t result; 320 isc_sockaddr_t anyaddr; 321 322 attrs = 0; 323 attrs |= DNS_DISPATCHATTR_UDP; 324 switch (family) { 325 case AF_INET: 326 attrs |= DNS_DISPATCHATTR_IPV4; 327 break; 328 case AF_INET6: 329 attrs |= DNS_DISPATCHATTR_IPV6; 330 break; 331 default: 332 UNREACHABLE(); 333 } 334 attrmask = 0; 335 attrmask |= DNS_DISPATCHATTR_UDP; 336 attrmask |= DNS_DISPATCHATTR_TCP; 337 attrmask |= DNS_DISPATCHATTR_IPV4; 338 attrmask |= DNS_DISPATCHATTR_IPV6; 339 340 if (localaddr == NULL) { 341 isc_sockaddr_anyofpf(&anyaddr, family); 342 localaddr = &anyaddr; 343 } 344 345 buffersize = 4096; 346 maxbuffers = is_shared ? 1000 : 8; 347 maxrequests = 32768; 348 buckets = is_shared ? 16411 : 3; 349 increment = is_shared ? 16433 : 5; 350 351 disp = NULL; 352 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, localaddr, 353 buffersize, maxbuffers, maxrequests, 354 buckets, increment, attrs, attrmask, 355 &disp); 356 if (result == ISC_R_SUCCESS) { 357 *dispp = disp; 358 } 359 360 return (result); 361 } 362 363 static isc_result_t 364 createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, unsigned int options, 365 isc_taskmgr_t *taskmgr, unsigned int ntasks, 366 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, 367 dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, 368 dns_dispatch_t *dispatchv6, dns_view_t **viewp) { 369 isc_result_t result; 370 dns_view_t *view = NULL; 371 const char *dbtype; 372 373 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view); 374 if (result != ISC_R_SUCCESS) { 375 return (result); 376 } 377 378 /* Initialize view security roots */ 379 result = dns_view_initsecroots(view, mctx); 380 if (result != ISC_R_SUCCESS) { 381 dns_view_detach(&view); 382 return (result); 383 } 384 385 result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr, 386 timermgr, 0, dispatchmgr, dispatchv4, 387 dispatchv6); 388 if (result != ISC_R_SUCCESS) { 389 dns_view_detach(&view); 390 return (result); 391 } 392 393 /* 394 * Set cache DB. 395 * XXX: it may be better if specific DB implementations can be 396 * specified via some configuration knob. 397 */ 398 if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0) { 399 dbtype = "rbt"; 400 } else { 401 dbtype = "ecdb"; 402 } 403 result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache, 404 rdclass, 0, NULL, &view->cachedb); 405 if (result != ISC_R_SUCCESS) { 406 dns_view_detach(&view); 407 return (result); 408 } 409 410 *viewp = view; 411 return (ISC_R_SUCCESS); 412 } 413 414 415 isc_result_t 416 dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr, 417 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, 418 unsigned int options, dns_client_t **clientp, 419 const isc_sockaddr_t *localaddr4, 420 const isc_sockaddr_t *localaddr6) { 421 isc_result_t result; 422 dns_client_t *client; 423 dns_dispatchmgr_t *dispatchmgr = NULL; 424 dns_dispatch_t *dispatchv4 = NULL; 425 dns_dispatch_t *dispatchv6 = NULL; 426 dns_view_t *view = NULL; 427 428 REQUIRE(mctx != NULL); 429 REQUIRE(taskmgr != NULL); 430 REQUIRE(timermgr != NULL); 431 REQUIRE(socketmgr != NULL); 432 REQUIRE(clientp != NULL && *clientp == NULL); 433 434 client = isc_mem_get(mctx, sizeof(*client)); 435 436 isc_mutex_init(&client->lock); 437 438 client->actx = actx; 439 client->taskmgr = taskmgr; 440 client->socketmgr = socketmgr; 441 client->timermgr = timermgr; 442 443 client->task = NULL; 444 result = isc_task_create(client->taskmgr, 0, &client->task); 445 if (result != ISC_R_SUCCESS) { 446 goto cleanup_lock; 447 } 448 449 result = dns_dispatchmgr_create(mctx, &dispatchmgr); 450 if (result != ISC_R_SUCCESS) { 451 goto cleanup_task; 452 } 453 client->dispatchmgr = dispatchmgr; 454 (void)setsourceports(mctx, dispatchmgr); 455 456 /* 457 * If only one address family is specified, use it. 458 * If neither family is specified, or if both are, use both. 459 */ 460 client->dispatchv4 = NULL; 461 if (localaddr4 != NULL || localaddr6 == NULL) { 462 result = getudpdispatch(AF_INET, dispatchmgr, socketmgr, 463 taskmgr, true, &dispatchv4, localaddr4); 464 if (result == ISC_R_SUCCESS) { 465 client->dispatchv4 = dispatchv4; 466 } 467 } 468 469 client->dispatchv6 = NULL; 470 if (localaddr6 != NULL || localaddr4 == NULL) { 471 result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr, 472 taskmgr, true, &dispatchv6, localaddr6); 473 if (result == ISC_R_SUCCESS) { 474 client->dispatchv6 = dispatchv6; 475 } 476 } 477 478 /* We need at least one of the dispatchers */ 479 if (dispatchv4 == NULL && dispatchv6 == NULL) { 480 INSIST(result != ISC_R_SUCCESS); 481 goto cleanup_dispatchmgr; 482 } 483 484 isc_refcount_init(&client->references, 1); 485 486 /* Create the default view for class IN */ 487 result = createview(mctx, dns_rdataclass_in, options, taskmgr, 488 RESOLVER_NTASKS, socketmgr, timermgr, dispatchmgr, 489 dispatchv4, dispatchv6, &view); 490 if (result != ISC_R_SUCCESS) { 491 goto cleanup_references; 492 } 493 494 ISC_LIST_INIT(client->viewlist); 495 ISC_LIST_APPEND(client->viewlist, view, link); 496 497 dns_view_freeze(view); /* too early? */ 498 499 ISC_LIST_INIT(client->resctxs); 500 ISC_LIST_INIT(client->reqctxs); 501 ISC_LIST_INIT(client->updatectxs); 502 503 client->mctx = NULL; 504 isc_mem_attach(mctx, &client->mctx); 505 506 client->update_timeout = DEF_UPDATE_TIMEOUT; 507 client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT; 508 client->update_udpretries = DEF_UPDATE_UDPRETRIES; 509 client->find_timeout = DEF_FIND_TIMEOUT; 510 client->find_udpretries = DEF_FIND_UDPRETRIES; 511 client->attributes = 0; 512 513 client->magic = DNS_CLIENT_MAGIC; 514 515 *clientp = client; 516 517 return (ISC_R_SUCCESS); 518 519 cleanup_references: 520 isc_refcount_decrementz(&client->references); 521 isc_refcount_destroy(&client->references); 522 cleanup_dispatchmgr: 523 if (dispatchv4 != NULL) { 524 dns_dispatch_detach(&dispatchv4); 525 } 526 if (dispatchv6 != NULL) { 527 dns_dispatch_detach(&dispatchv6); 528 } 529 dns_dispatchmgr_destroy(&dispatchmgr); 530 cleanup_task: 531 isc_task_detach(&client->task); 532 cleanup_lock: 533 isc_mutex_destroy(&client->lock); 534 isc_mem_put(mctx, client, sizeof(*client)); 535 536 return (result); 537 } 538 539 static void 540 destroyclient(dns_client_t *client) { 541 dns_view_t *view; 542 543 isc_refcount_destroy(&client->references); 544 545 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) { 546 ISC_LIST_UNLINK(client->viewlist, view, link); 547 dns_view_detach(&view); 548 } 549 550 if (client->dispatchv4 != NULL) { 551 dns_dispatch_detach(&client->dispatchv4); 552 } 553 if (client->dispatchv6 != NULL) { 554 dns_dispatch_detach(&client->dispatchv6); 555 } 556 557 dns_dispatchmgr_destroy(&client->dispatchmgr); 558 559 isc_task_detach(&client->task); 560 client->magic = 0; 561 562 isc_mem_putanddetach(&client->mctx, client, sizeof(*client)); 563 } 564 565 void 566 dns_client_destroy(dns_client_t **clientp) { 567 dns_client_t *client; 568 569 REQUIRE(clientp != NULL); 570 client = *clientp; 571 *clientp = NULL; 572 REQUIRE(DNS_CLIENT_VALID(client)); 573 574 if (isc_refcount_decrement(&client->references) == 1) { 575 destroyclient(client); 576 } 577 } 578 579 isc_result_t 580 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass, 581 const dns_name_t *name_space, isc_sockaddrlist_t *addrs) { 582 isc_result_t result; 583 dns_view_t *view = NULL; 584 585 REQUIRE(DNS_CLIENT_VALID(client)); 586 REQUIRE(addrs != NULL); 587 588 if (name_space == NULL) { 589 name_space = dns_rootname; 590 } 591 592 LOCK(&client->lock); 593 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 594 rdclass, &view); 595 if (result != ISC_R_SUCCESS) { 596 UNLOCK(&client->lock); 597 return (result); 598 } 599 UNLOCK(&client->lock); 600 601 result = dns_fwdtable_add(view->fwdtable, name_space, addrs, 602 dns_fwdpolicy_only); 603 604 dns_view_detach(&view); 605 606 return (result); 607 } 608 609 isc_result_t 610 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass, 611 const dns_name_t *name_space) { 612 isc_result_t result; 613 dns_view_t *view = NULL; 614 615 REQUIRE(DNS_CLIENT_VALID(client)); 616 617 if (name_space == NULL) { 618 name_space = dns_rootname; 619 } 620 621 LOCK(&client->lock); 622 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 623 rdclass, &view); 624 if (result != ISC_R_SUCCESS) { 625 UNLOCK(&client->lock); 626 return (result); 627 } 628 UNLOCK(&client->lock); 629 630 result = dns_fwdtable_delete(view->fwdtable, name_space); 631 632 dns_view_detach(&view); 633 634 return (result); 635 } 636 637 static isc_result_t 638 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 639 dns_rdataset_t *rdataset; 640 641 REQUIRE(mctx != NULL); 642 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL); 643 644 rdataset = isc_mem_get(mctx, sizeof(*rdataset)); 645 646 dns_rdataset_init(rdataset); 647 648 *rdatasetp = rdataset; 649 650 return (ISC_R_SUCCESS); 651 } 652 653 static void 654 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) { 655 dns_rdataset_t *rdataset; 656 657 REQUIRE(rdatasetp != NULL); 658 rdataset = *rdatasetp; 659 *rdatasetp = NULL; 660 REQUIRE(rdataset != NULL); 661 662 if (dns_rdataset_isassociated(rdataset)) { 663 dns_rdataset_disassociate(rdataset); 664 } 665 666 isc_mem_put(mctx, rdataset, sizeof(*rdataset)); 667 } 668 669 static void 670 fetch_done(isc_task_t *task, isc_event_t *event) { 671 resctx_t *rctx = event->ev_arg; 672 dns_fetchevent_t *fevent; 673 674 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); 675 REQUIRE(RCTX_VALID(rctx)); 676 REQUIRE(rctx->task == task); 677 fevent = (dns_fetchevent_t *)event; 678 679 client_resfind(rctx, fevent); 680 } 681 682 static isc_result_t 683 start_fetch(resctx_t *rctx) { 684 isc_result_t result; 685 int fopts = 0; 686 687 /* 688 * The caller must be holding the rctx's lock. 689 */ 690 691 REQUIRE(rctx->fetch == NULL); 692 693 if (!rctx->want_cdflag) { 694 fopts |= DNS_FETCHOPT_NOCDFLAG; 695 } 696 if (!rctx->want_validation) { 697 fopts |= DNS_FETCHOPT_NOVALIDATE; 698 } 699 if (rctx->want_tcp) { 700 fopts |= DNS_FETCHOPT_TCP; 701 } 702 703 result = dns_resolver_createfetch( 704 rctx->view->resolver, dns_fixedname_name(&rctx->name), 705 rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL, 706 rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset, 707 &rctx->fetch); 708 709 return (result); 710 } 711 712 static isc_result_t 713 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep, 714 dns_name_t *foundname) { 715 isc_result_t result; 716 dns_name_t *name = dns_fixedname_name(&rctx->name); 717 dns_rdatatype_t type; 718 719 if (rctx->type == dns_rdatatype_rrsig) { 720 type = dns_rdatatype_any; 721 } else { 722 type = rctx->type; 723 } 724 725 result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp, 726 nodep, foundname, rctx->rdataset, 727 rctx->sigrdataset); 728 729 return (result); 730 } 731 732 static void 733 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) { 734 isc_mem_t *mctx; 735 isc_result_t tresult, result = ISC_R_SUCCESS; 736 isc_result_t vresult = ISC_R_SUCCESS; 737 bool want_restart; 738 bool send_event = false; 739 dns_name_t *name, *prefix; 740 dns_fixedname_t foundname, fixed; 741 dns_rdataset_t *trdataset; 742 dns_rdata_t rdata = DNS_RDATA_INIT; 743 unsigned int nlabels; 744 int order; 745 dns_namereln_t namereln; 746 dns_rdata_cname_t cname; 747 dns_rdata_dname_t dname; 748 749 REQUIRE(RCTX_VALID(rctx)); 750 751 LOCK(&rctx->lock); 752 753 mctx = rctx->view->mctx; 754 755 name = dns_fixedname_name(&rctx->name); 756 757 do { 758 dns_name_t *fname = NULL; 759 dns_name_t *ansname = NULL; 760 dns_db_t *db = NULL; 761 dns_dbnode_t *node = NULL; 762 763 rctx->restarts++; 764 want_restart = false; 765 766 if (event == NULL && !rctx->canceled) { 767 fname = dns_fixedname_initname(&foundname); 768 INSIST(!dns_rdataset_isassociated(rctx->rdataset)); 769 INSIST(rctx->sigrdataset == NULL || 770 !dns_rdataset_isassociated(rctx->sigrdataset)); 771 result = view_find(rctx, &db, &node, fname); 772 if (result == ISC_R_NOTFOUND) { 773 /* 774 * We don't know anything about the name. 775 * Launch a fetch. 776 */ 777 if (node != NULL) { 778 INSIST(db != NULL); 779 dns_db_detachnode(db, &node); 780 } 781 if (db != NULL) { 782 dns_db_detach(&db); 783 } 784 result = start_fetch(rctx); 785 if (result != ISC_R_SUCCESS) { 786 putrdataset(mctx, &rctx->rdataset); 787 if (rctx->sigrdataset != NULL) { 788 putrdataset(mctx, 789 &rctx->sigrdataset); 790 } 791 send_event = true; 792 } 793 goto done; 794 } 795 } else { 796 INSIST(event != NULL); 797 INSIST(event->fetch == rctx->fetch); 798 dns_resolver_destroyfetch(&rctx->fetch); 799 db = event->db; 800 node = event->node; 801 result = event->result; 802 vresult = event->vresult; 803 fname = dns_fixedname_name(&event->foundname); 804 INSIST(event->rdataset == rctx->rdataset); 805 INSIST(event->sigrdataset == rctx->sigrdataset); 806 } 807 808 /* 809 * If we've been canceled, forget about the result. 810 */ 811 if (rctx->canceled) { 812 result = ISC_R_CANCELED; 813 } else { 814 /* 815 * Otherwise, get some resource for copying the 816 * result. 817 */ 818 dns_name_t *aname = dns_fixedname_name(&rctx->name); 819 820 ansname = isc_mem_get(mctx, sizeof(*ansname)); 821 dns_name_init(ansname, NULL); 822 823 dns_name_dup(aname, mctx, ansname); 824 } 825 826 switch (result) { 827 case ISC_R_SUCCESS: 828 send_event = true; 829 /* 830 * This case is handled in the main line below. 831 */ 832 break; 833 case DNS_R_CNAME: 834 /* 835 * Add the CNAME to the answer list. 836 */ 837 trdataset = rctx->rdataset; 838 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 839 rctx->rdataset = NULL; 840 if (rctx->sigrdataset != NULL) { 841 ISC_LIST_APPEND(ansname->list, 842 rctx->sigrdataset, link); 843 rctx->sigrdataset = NULL; 844 } 845 ISC_LIST_APPEND(rctx->namelist, ansname, link); 846 ansname = NULL; 847 848 /* 849 * Copy the CNAME's target into the lookup's 850 * query name and start over. 851 */ 852 tresult = dns_rdataset_first(trdataset); 853 if (tresult != ISC_R_SUCCESS) { 854 goto done; 855 } 856 dns_rdataset_current(trdataset, &rdata); 857 tresult = dns_rdata_tostruct(&rdata, &cname, NULL); 858 dns_rdata_reset(&rdata); 859 if (tresult != ISC_R_SUCCESS) { 860 goto done; 861 } 862 dns_name_copynf(&cname.cname, name); 863 dns_rdata_freestruct(&cname); 864 want_restart = true; 865 goto done; 866 case DNS_R_DNAME: 867 /* 868 * Add the DNAME to the answer list. 869 */ 870 trdataset = rctx->rdataset; 871 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 872 rctx->rdataset = NULL; 873 if (rctx->sigrdataset != NULL) { 874 ISC_LIST_APPEND(ansname->list, 875 rctx->sigrdataset, link); 876 rctx->sigrdataset = NULL; 877 } 878 ISC_LIST_APPEND(rctx->namelist, ansname, link); 879 ansname = NULL; 880 881 namereln = dns_name_fullcompare(name, fname, &order, 882 &nlabels); 883 INSIST(namereln == dns_namereln_subdomain); 884 /* 885 * Get the target name of the DNAME. 886 */ 887 tresult = dns_rdataset_first(trdataset); 888 if (tresult != ISC_R_SUCCESS) { 889 result = tresult; 890 goto done; 891 } 892 dns_rdataset_current(trdataset, &rdata); 893 tresult = dns_rdata_tostruct(&rdata, &dname, NULL); 894 dns_rdata_reset(&rdata); 895 if (tresult != ISC_R_SUCCESS) { 896 result = tresult; 897 goto done; 898 } 899 /* 900 * Construct the new query name and start over. 901 */ 902 prefix = dns_fixedname_initname(&fixed); 903 dns_name_split(name, nlabels, prefix, NULL); 904 tresult = dns_name_concatenate(prefix, &dname.dname, 905 name, NULL); 906 dns_rdata_freestruct(&dname); 907 if (tresult == ISC_R_SUCCESS) { 908 want_restart = true; 909 } else { 910 result = tresult; 911 } 912 goto done; 913 case DNS_R_NCACHENXDOMAIN: 914 case DNS_R_NCACHENXRRSET: 915 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 916 ISC_LIST_APPEND(rctx->namelist, ansname, link); 917 ansname = NULL; 918 rctx->rdataset = NULL; 919 /* What about sigrdataset? */ 920 if (rctx->sigrdataset != NULL) { 921 putrdataset(mctx, &rctx->sigrdataset); 922 } 923 send_event = true; 924 goto done; 925 default: 926 if (rctx->rdataset != NULL) { 927 putrdataset(mctx, &rctx->rdataset); 928 } 929 if (rctx->sigrdataset != NULL) { 930 putrdataset(mctx, &rctx->sigrdataset); 931 } 932 send_event = true; 933 goto done; 934 } 935 936 if (rctx->type == dns_rdatatype_any) { 937 int n = 0; 938 dns_rdatasetiter_t *rdsiter = NULL; 939 940 tresult = dns_db_allrdatasets(db, node, NULL, 0, 0, 941 &rdsiter); 942 if (tresult != ISC_R_SUCCESS) { 943 result = tresult; 944 goto done; 945 } 946 947 tresult = dns_rdatasetiter_first(rdsiter); 948 while (tresult == ISC_R_SUCCESS) { 949 dns_rdatasetiter_current(rdsiter, 950 rctx->rdataset); 951 if (rctx->rdataset->type != 0) { 952 ISC_LIST_APPEND(ansname->list, 953 rctx->rdataset, link); 954 n++; 955 rctx->rdataset = NULL; 956 } else { 957 /* 958 * We're not interested in this 959 * rdataset. 960 */ 961 dns_rdataset_disassociate( 962 rctx->rdataset); 963 } 964 tresult = dns_rdatasetiter_next(rdsiter); 965 966 if (tresult == ISC_R_SUCCESS && 967 rctx->rdataset == NULL) 968 { 969 tresult = getrdataset(mctx, 970 &rctx->rdataset); 971 if (tresult != ISC_R_SUCCESS) { 972 result = tresult; 973 POST(result); 974 break; 975 } 976 } 977 } 978 if (rctx->rdataset != NULL) { 979 putrdataset(mctx, &rctx->rdataset); 980 } 981 if (rctx->sigrdataset != NULL) { 982 putrdataset(mctx, &rctx->sigrdataset); 983 } 984 if (n == 0) { 985 /* 986 * We didn't match any rdatasets (which means 987 * something went wrong in this 988 * implementation). 989 */ 990 result = DNS_R_SERVFAIL; /* better code? */ 991 POST(result); 992 } else { 993 ISC_LIST_APPEND(rctx->namelist, ansname, link); 994 ansname = NULL; 995 } 996 dns_rdatasetiter_destroy(&rdsiter); 997 if (tresult != ISC_R_NOMORE) { 998 result = DNS_R_SERVFAIL; /* ditto */ 999 } else { 1000 result = ISC_R_SUCCESS; 1001 } 1002 goto done; 1003 } else { 1004 /* 1005 * This is the "normal" case -- an ordinary question 1006 * to which we've got the answer. 1007 */ 1008 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 1009 rctx->rdataset = NULL; 1010 if (rctx->sigrdataset != NULL) { 1011 ISC_LIST_APPEND(ansname->list, 1012 rctx->sigrdataset, link); 1013 rctx->sigrdataset = NULL; 1014 } 1015 ISC_LIST_APPEND(rctx->namelist, ansname, link); 1016 ansname = NULL; 1017 } 1018 1019 done: 1020 /* 1021 * Free temporary resources 1022 */ 1023 if (ansname != NULL) { 1024 dns_rdataset_t *rdataset; 1025 1026 while ((rdataset = ISC_LIST_HEAD(ansname->list)) != 1027 NULL) 1028 { 1029 ISC_LIST_UNLINK(ansname->list, rdataset, link); 1030 putrdataset(mctx, &rdataset); 1031 } 1032 dns_name_free(ansname, mctx); 1033 isc_mem_put(mctx, ansname, sizeof(*ansname)); 1034 } 1035 1036 if (node != NULL) { 1037 dns_db_detachnode(db, &node); 1038 } 1039 if (db != NULL) { 1040 dns_db_detach(&db); 1041 } 1042 if (event != NULL) { 1043 isc_event_free(ISC_EVENT_PTR(&event)); 1044 } 1045 1046 /* 1047 * Limit the number of restarts. 1048 */ 1049 if (want_restart && rctx->restarts == MAX_RESTARTS) { 1050 want_restart = false; 1051 result = ISC_R_QUOTA; 1052 send_event = true; 1053 } 1054 1055 /* 1056 * Prepare further find with new resources 1057 */ 1058 if (want_restart) { 1059 INSIST(rctx->rdataset == NULL && 1060 rctx->sigrdataset == NULL); 1061 1062 result = getrdataset(mctx, &rctx->rdataset); 1063 if (result == ISC_R_SUCCESS && rctx->want_dnssec) { 1064 result = getrdataset(mctx, &rctx->sigrdataset); 1065 if (result != ISC_R_SUCCESS) { 1066 putrdataset(mctx, &rctx->rdataset); 1067 } 1068 } 1069 1070 if (result != ISC_R_SUCCESS) { 1071 want_restart = false; 1072 send_event = true; 1073 } 1074 } 1075 } while (want_restart); 1076 1077 if (send_event) { 1078 isc_task_t *task; 1079 1080 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) { 1081 ISC_LIST_UNLINK(rctx->namelist, name, link); 1082 ISC_LIST_APPEND(rctx->event->answerlist, name, link); 1083 } 1084 1085 rctx->event->result = result; 1086 rctx->event->vresult = vresult; 1087 task = rctx->event->ev_sender; 1088 rctx->event->ev_sender = rctx; 1089 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event)); 1090 } 1091 1092 UNLOCK(&rctx->lock); 1093 } 1094 1095 static void 1096 suspend(isc_task_t *task, isc_event_t *event) { 1097 isc_appctx_t *actx = event->ev_arg; 1098 1099 UNUSED(task); 1100 1101 isc_app_ctxsuspend(actx); 1102 isc_event_free(&event); 1103 } 1104 1105 static void 1106 resolve_done(isc_task_t *task, isc_event_t *event) { 1107 resarg_t *resarg = event->ev_arg; 1108 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 1109 dns_name_t *name; 1110 isc_result_t result; 1111 1112 UNUSED(task); 1113 1114 LOCK(&resarg->lock); 1115 1116 resarg->result = rev->result; 1117 resarg->vresult = rev->vresult; 1118 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) { 1119 ISC_LIST_UNLINK(rev->answerlist, name, link); 1120 ISC_LIST_APPEND(*resarg->namelist, name, link); 1121 } 1122 1123 dns_client_destroyrestrans(&resarg->trans); 1124 isc_event_free(&event); 1125 1126 if (!resarg->canceled) { 1127 UNLOCK(&resarg->lock); 1128 1129 /* 1130 * We may or may not be running. isc__appctx_onrun will 1131 * fail if we are currently running otherwise we post a 1132 * action to call isc_app_ctxsuspend when we do start 1133 * running. 1134 */ 1135 result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx, 1136 task, suspend, resarg->actx); 1137 if (result == ISC_R_ALREADYRUNNING) { 1138 isc_app_ctxsuspend(resarg->actx); 1139 } 1140 } else { 1141 /* 1142 * We have already exited from the loop (due to some 1143 * unexpected event). Just clean the arg up. 1144 */ 1145 UNLOCK(&resarg->lock); 1146 isc_mutex_destroy(&resarg->lock); 1147 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg)); 1148 } 1149 } 1150 1151 isc_result_t 1152 dns_client_resolve(dns_client_t *client, const dns_name_t *name, 1153 dns_rdataclass_t rdclass, dns_rdatatype_t type, 1154 unsigned int options, dns_namelist_t *namelist) { 1155 isc_result_t result; 1156 isc_appctx_t *actx; 1157 resarg_t *resarg; 1158 1159 REQUIRE(DNS_CLIENT_VALID(client)); 1160 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist)); 1161 1162 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 1163 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) 1164 { 1165 /* 1166 * If the client is run under application's control, we need 1167 * to create a new running (sub)environment for this 1168 * particular resolution. 1169 */ 1170 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 1171 } else { 1172 actx = client->actx; 1173 } 1174 1175 resarg = isc_mem_get(client->mctx, sizeof(*resarg)); 1176 1177 isc_mutex_init(&resarg->lock); 1178 1179 resarg->actx = actx; 1180 resarg->client = client; 1181 resarg->result = DNS_R_SERVFAIL; 1182 resarg->namelist = namelist; 1183 resarg->trans = NULL; 1184 resarg->canceled = false; 1185 result = dns_client_startresolve(client, name, rdclass, type, options, 1186 client->task, resolve_done, resarg, 1187 &resarg->trans); 1188 if (result != ISC_R_SUCCESS) { 1189 isc_mutex_destroy(&resarg->lock); 1190 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1191 return (result); 1192 } 1193 1194 /* 1195 * Start internal event loop. It blocks until the entire process 1196 * is completed. 1197 */ 1198 result = isc_app_ctxrun(actx); 1199 1200 LOCK(&resarg->lock); 1201 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) { 1202 result = resarg->result; 1203 } 1204 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) { 1205 /* 1206 * If this lookup failed due to some error in DNSSEC 1207 * validation, return the validation error code. 1208 * XXX: or should we pass the validation result separately? 1209 */ 1210 result = resarg->vresult; 1211 } 1212 if (resarg->trans != NULL) { 1213 /* 1214 * Unusual termination (perhaps due to signal). We need some 1215 * tricky cleanup process. 1216 */ 1217 resarg->canceled = true; 1218 dns_client_cancelresolve(resarg->trans); 1219 1220 UNLOCK(&resarg->lock); 1221 1222 /* resarg will be freed in the event handler. */ 1223 } else { 1224 UNLOCK(&resarg->lock); 1225 1226 isc_mutex_destroy(&resarg->lock); 1227 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1228 } 1229 1230 return (result); 1231 } 1232 1233 isc_result_t 1234 dns_client_startresolve(dns_client_t *client, const dns_name_t *name, 1235 dns_rdataclass_t rdclass, dns_rdatatype_t type, 1236 unsigned int options, isc_task_t *task, 1237 isc_taskaction_t action, void *arg, 1238 dns_clientrestrans_t **transp) { 1239 dns_view_t *view = NULL; 1240 dns_clientresevent_t *event = NULL; 1241 resctx_t *rctx = NULL; 1242 isc_task_t *tclone = NULL; 1243 isc_mem_t *mctx; 1244 isc_result_t result; 1245 dns_rdataset_t *rdataset, *sigrdataset; 1246 bool want_dnssec, want_validation, want_cdflag, want_tcp; 1247 1248 REQUIRE(DNS_CLIENT_VALID(client)); 1249 REQUIRE(transp != NULL && *transp == NULL); 1250 1251 LOCK(&client->lock); 1252 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1253 rdclass, &view); 1254 UNLOCK(&client->lock); 1255 if (result != ISC_R_SUCCESS) { 1256 return (result); 1257 } 1258 1259 mctx = client->mctx; 1260 rdataset = NULL; 1261 sigrdataset = NULL; 1262 want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0); 1263 want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0); 1264 want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0); 1265 want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0); 1266 1267 /* 1268 * Prepare some intermediate resources 1269 */ 1270 tclone = NULL; 1271 isc_task_attach(task, &tclone); 1272 event = (dns_clientresevent_t *)isc_event_allocate( 1273 mctx, tclone, DNS_EVENT_CLIENTRESDONE, action, arg, 1274 sizeof(*event)); 1275 event->result = DNS_R_SERVFAIL; 1276 ISC_LIST_INIT(event->answerlist); 1277 1278 rctx = isc_mem_get(mctx, sizeof(*rctx)); 1279 isc_mutex_init(&rctx->lock); 1280 1281 result = getrdataset(mctx, &rdataset); 1282 if (result != ISC_R_SUCCESS) { 1283 goto cleanup; 1284 } 1285 rctx->rdataset = rdataset; 1286 1287 if (want_dnssec) { 1288 result = getrdataset(mctx, &sigrdataset); 1289 if (result != ISC_R_SUCCESS) { 1290 goto cleanup; 1291 } 1292 } 1293 rctx->sigrdataset = sigrdataset; 1294 1295 dns_fixedname_init(&rctx->name); 1296 dns_name_copynf(name, dns_fixedname_name(&rctx->name)); 1297 1298 rctx->client = client; 1299 ISC_LINK_INIT(rctx, link); 1300 rctx->canceled = false; 1301 rctx->task = client->task; 1302 rctx->type = type; 1303 rctx->view = view; 1304 rctx->restarts = 0; 1305 rctx->fetch = NULL; 1306 rctx->want_dnssec = want_dnssec; 1307 rctx->want_validation = want_validation; 1308 rctx->want_cdflag = want_cdflag; 1309 rctx->want_tcp = want_tcp; 1310 ISC_LIST_INIT(rctx->namelist); 1311 rctx->event = event; 1312 1313 rctx->magic = RCTX_MAGIC; 1314 isc_refcount_increment(&client->references); 1315 1316 LOCK(&client->lock); 1317 ISC_LIST_APPEND(client->resctxs, rctx, link); 1318 UNLOCK(&client->lock); 1319 1320 *transp = (dns_clientrestrans_t *)rctx; 1321 client_resfind(rctx, NULL); 1322 1323 return (ISC_R_SUCCESS); 1324 1325 cleanup: 1326 if (rdataset != NULL) { 1327 putrdataset(client->mctx, &rdataset); 1328 } 1329 if (sigrdataset != NULL) { 1330 putrdataset(client->mctx, &sigrdataset); 1331 } 1332 isc_mutex_destroy(&rctx->lock); 1333 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1334 isc_event_free(ISC_EVENT_PTR(&event)); 1335 isc_task_detach(&tclone); 1336 dns_view_detach(&view); 1337 1338 return (result); 1339 } 1340 1341 void 1342 dns_client_cancelresolve(dns_clientrestrans_t *trans) { 1343 resctx_t *rctx; 1344 1345 REQUIRE(trans != NULL); 1346 rctx = (resctx_t *)trans; 1347 REQUIRE(RCTX_VALID(rctx)); 1348 1349 LOCK(&rctx->lock); 1350 1351 if (!rctx->canceled) { 1352 rctx->canceled = true; 1353 if (rctx->fetch != NULL) { 1354 dns_resolver_cancelfetch(rctx->fetch); 1355 } 1356 } 1357 1358 UNLOCK(&rctx->lock); 1359 } 1360 1361 void 1362 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) { 1363 dns_name_t *name; 1364 dns_rdataset_t *rdataset; 1365 1366 REQUIRE(DNS_CLIENT_VALID(client)); 1367 REQUIRE(namelist != NULL); 1368 1369 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) { 1370 ISC_LIST_UNLINK(*namelist, name, link); 1371 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) { 1372 ISC_LIST_UNLINK(name->list, rdataset, link); 1373 putrdataset(client->mctx, &rdataset); 1374 } 1375 dns_name_free(name, client->mctx); 1376 isc_mem_put(client->mctx, name, sizeof(*name)); 1377 } 1378 } 1379 1380 void 1381 dns_client_destroyrestrans(dns_clientrestrans_t **transp) { 1382 resctx_t *rctx; 1383 isc_mem_t *mctx; 1384 dns_client_t *client; 1385 1386 REQUIRE(transp != NULL); 1387 rctx = (resctx_t *)*transp; 1388 *transp = NULL; 1389 REQUIRE(RCTX_VALID(rctx)); 1390 REQUIRE(rctx->fetch == NULL); 1391 REQUIRE(rctx->event == NULL); 1392 client = rctx->client; 1393 REQUIRE(DNS_CLIENT_VALID(client)); 1394 1395 mctx = client->mctx; 1396 dns_view_detach(&rctx->view); 1397 1398 /* 1399 * Wait for the lock in client_resfind to be released before 1400 * destroying the lock. 1401 */ 1402 LOCK(&rctx->lock); 1403 UNLOCK(&rctx->lock); 1404 1405 LOCK(&client->lock); 1406 1407 INSIST(ISC_LINK_LINKED(rctx, link)); 1408 ISC_LIST_UNLINK(client->resctxs, rctx, link); 1409 1410 UNLOCK(&client->lock); 1411 1412 INSIST(ISC_LIST_EMPTY(rctx->namelist)); 1413 1414 isc_mutex_destroy(&rctx->lock); 1415 rctx->magic = 0; 1416 1417 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1418 1419 dns_client_destroy(&client); 1420 } 1421 1422 isc_result_t 1423 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, 1424 dns_rdatatype_t rdtype, const dns_name_t *keyname, 1425 isc_buffer_t *databuf) { 1426 isc_result_t result; 1427 dns_view_t *view = NULL; 1428 dns_keytable_t *secroots = NULL; 1429 dns_name_t *name = NULL; 1430 char rdatabuf[DST_KEY_MAXSIZE]; 1431 unsigned char digest[ISC_MAX_MD_SIZE]; 1432 dns_rdata_ds_t ds; 1433 dns_decompress_t dctx; 1434 dns_rdata_t rdata; 1435 isc_buffer_t b; 1436 1437 REQUIRE(DNS_CLIENT_VALID(client)); 1438 1439 LOCK(&client->lock); 1440 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1441 rdclass, &view); 1442 UNLOCK(&client->lock); 1443 CHECK(result); 1444 1445 CHECK(dns_view_getsecroots(view, &secroots)); 1446 1447 DE_CONST(keyname, name); 1448 1449 if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) { 1450 result = ISC_R_NOTIMPLEMENTED; 1451 goto cleanup; 1452 } 1453 1454 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf)); 1455 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE); 1456 dns_rdata_init(&rdata); 1457 isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf)); 1458 CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, databuf, &dctx, 0, 1459 &b)); 1460 dns_decompress_invalidate(&dctx); 1461 1462 if (rdtype == dns_rdatatype_ds) { 1463 CHECK(dns_rdata_tostruct(&rdata, &ds, NULL)); 1464 } else { 1465 CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256, 1466 digest, &ds)); 1467 } 1468 1469 CHECK(dns_keytable_add(secroots, false, false, name, &ds)); 1470 1471 cleanup: 1472 if (view != NULL) { 1473 dns_view_detach(&view); 1474 } 1475 if (secroots != NULL) { 1476 dns_keytable_detach(&secroots); 1477 } 1478 return (result); 1479 } 1480 1481 /*% 1482 * Simple request routines 1483 */ 1484 static void 1485 request_done(isc_task_t *task, isc_event_t *event) { 1486 dns_requestevent_t *reqev = NULL; 1487 dns_request_t *request; 1488 isc_result_t result, eresult; 1489 reqctx_t *ctx; 1490 1491 UNUSED(task); 1492 1493 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1494 reqev = (dns_requestevent_t *)event; 1495 request = reqev->request; 1496 result = eresult = reqev->result; 1497 ctx = reqev->ev_arg; 1498 REQUIRE(REQCTX_VALID(ctx)); 1499 1500 isc_event_free(&event); 1501 1502 LOCK(&ctx->lock); 1503 1504 if (eresult == ISC_R_SUCCESS) { 1505 result = dns_request_getresponse(request, ctx->event->rmessage, 1506 ctx->parseoptions); 1507 } 1508 1509 if (ctx->tsigkey != NULL) { 1510 dns_tsigkey_detach(&ctx->tsigkey); 1511 } 1512 1513 if (ctx->canceled) { 1514 ctx->event->result = ISC_R_CANCELED; 1515 } else { 1516 ctx->event->result = result; 1517 } 1518 task = ctx->event->ev_sender; 1519 ctx->event->ev_sender = ctx; 1520 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event)); 1521 1522 UNLOCK(&ctx->lock); 1523 } 1524 1525 static void 1526 localrequest_done(isc_task_t *task, isc_event_t *event) { 1527 reqarg_t *reqarg = event->ev_arg; 1528 dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event; 1529 1530 UNUSED(task); 1531 1532 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE); 1533 1534 LOCK(&reqarg->lock); 1535 1536 reqarg->result = rev->result; 1537 dns_client_destroyreqtrans(&reqarg->trans); 1538 isc_event_free(&event); 1539 1540 if (!reqarg->canceled) { 1541 UNLOCK(&reqarg->lock); 1542 1543 /* Exit from the internal event loop */ 1544 isc_app_ctxsuspend(reqarg->actx); 1545 } else { 1546 /* 1547 * We have already exited from the loop (due to some 1548 * unexpected event). Just clean the arg up. 1549 */ 1550 UNLOCK(&reqarg->lock); 1551 isc_mutex_destroy(&reqarg->lock); 1552 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg)); 1553 } 1554 } 1555 1556 isc_result_t 1557 dns_client_request(dns_client_t *client, dns_message_t *qmessage, 1558 dns_message_t *rmessage, const isc_sockaddr_t *server, 1559 unsigned int options, unsigned int parseoptions, 1560 dns_tsec_t *tsec, unsigned int timeout, 1561 unsigned int udptimeout, unsigned int udpretries) { 1562 isc_appctx_t *actx; 1563 reqarg_t *reqarg; 1564 isc_result_t result; 1565 1566 REQUIRE(DNS_CLIENT_VALID(client)); 1567 REQUIRE(qmessage != NULL); 1568 REQUIRE(rmessage != NULL); 1569 1570 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 1571 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) 1572 { 1573 /* 1574 * If the client is run under application's control, we need 1575 * to create a new running (sub)environment for this 1576 * particular resolution. 1577 */ 1578 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 1579 } else { 1580 actx = client->actx; 1581 } 1582 1583 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg)); 1584 1585 isc_mutex_init(&reqarg->lock); 1586 1587 reqarg->actx = actx; 1588 reqarg->client = client; 1589 reqarg->trans = NULL; 1590 reqarg->canceled = false; 1591 1592 result = dns_client_startrequest( 1593 client, qmessage, rmessage, server, options, parseoptions, tsec, 1594 timeout, udptimeout, udpretries, client->task, 1595 localrequest_done, reqarg, &reqarg->trans); 1596 if (result != ISC_R_SUCCESS) { 1597 isc_mutex_destroy(&reqarg->lock); 1598 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1599 return (result); 1600 } 1601 1602 /* 1603 * Start internal event loop. It blocks until the entire process 1604 * is completed. 1605 */ 1606 result = isc_app_ctxrun(actx); 1607 1608 LOCK(&reqarg->lock); 1609 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) { 1610 result = reqarg->result; 1611 } 1612 if (reqarg->trans != NULL) { 1613 /* 1614 * Unusual termination (perhaps due to signal). We need some 1615 * tricky cleanup process. 1616 */ 1617 reqarg->canceled = true; 1618 dns_client_cancelresolve(reqarg->trans); 1619 1620 UNLOCK(&reqarg->lock); 1621 1622 /* reqarg will be freed in the event handler. */ 1623 } else { 1624 UNLOCK(&reqarg->lock); 1625 1626 isc_mutex_destroy(&reqarg->lock); 1627 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1628 } 1629 1630 return (result); 1631 } 1632 1633 isc_result_t 1634 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage, 1635 dns_message_t *rmessage, const isc_sockaddr_t *server, 1636 unsigned int options, unsigned int parseoptions, 1637 dns_tsec_t *tsec, unsigned int timeout, 1638 unsigned int udptimeout, unsigned int udpretries, 1639 isc_task_t *task, isc_taskaction_t action, void *arg, 1640 dns_clientreqtrans_t **transp) { 1641 isc_result_t result; 1642 dns_view_t *view = NULL; 1643 isc_task_t *tclone = NULL; 1644 dns_clientreqevent_t *event = NULL; 1645 reqctx_t *ctx = NULL; 1646 dns_tsectype_t tsectype = dns_tsectype_none; 1647 unsigned int reqoptions; 1648 1649 REQUIRE(DNS_CLIENT_VALID(client)); 1650 REQUIRE(qmessage != NULL); 1651 REQUIRE(rmessage != NULL); 1652 REQUIRE(transp != NULL && *transp == NULL); 1653 1654 if (tsec != NULL) { 1655 tsectype = dns_tsec_gettype(tsec); 1656 if (tsectype != dns_tsectype_tsig) { 1657 return (ISC_R_NOTIMPLEMENTED); /* XXX */ 1658 } 1659 } 1660 1661 LOCK(&client->lock); 1662 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1663 qmessage->rdclass, &view); 1664 UNLOCK(&client->lock); 1665 if (result != ISC_R_SUCCESS) { 1666 return (result); 1667 } 1668 1669 reqoptions = 0; 1670 if ((options & DNS_CLIENTREQOPT_TCP) != 0) { 1671 reqoptions |= DNS_REQUESTOPT_TCP; 1672 } 1673 1674 tclone = NULL; 1675 isc_task_attach(task, &tclone); 1676 event = (dns_clientreqevent_t *)isc_event_allocate( 1677 client->mctx, tclone, DNS_EVENT_CLIENTREQDONE, action, arg, 1678 sizeof(*event)); 1679 1680 ctx = isc_mem_get(client->mctx, sizeof(*ctx)); 1681 isc_mutex_init(&ctx->lock); 1682 1683 ctx->client = client; 1684 ISC_LINK_INIT(ctx, link); 1685 ctx->parseoptions = parseoptions; 1686 ctx->canceled = false; 1687 ctx->event = event; 1688 ctx->event->rmessage = rmessage; 1689 ctx->tsigkey = NULL; 1690 if (tsec != NULL) { 1691 dns_tsec_getkey(tsec, &ctx->tsigkey); 1692 } 1693 1694 ctx->magic = REQCTX_MAGIC; 1695 1696 LOCK(&client->lock); 1697 ISC_LIST_APPEND(client->reqctxs, ctx, link); 1698 isc_refcount_increment(&client->references); 1699 UNLOCK(&client->lock); 1700 1701 ctx->request = NULL; 1702 result = dns_request_createvia(view->requestmgr, qmessage, NULL, server, 1703 -1, reqoptions, ctx->tsigkey, timeout, 1704 udptimeout, udpretries, client->task, 1705 request_done, ctx, &ctx->request); 1706 if (result == ISC_R_SUCCESS) { 1707 dns_view_detach(&view); 1708 *transp = (dns_clientreqtrans_t *)ctx; 1709 return (ISC_R_SUCCESS); 1710 } 1711 1712 isc_refcount_decrement1(&client->references); 1713 1714 LOCK(&client->lock); 1715 ISC_LIST_UNLINK(client->reqctxs, ctx, link); 1716 UNLOCK(&client->lock); 1717 isc_mutex_destroy(&ctx->lock); 1718 isc_mem_put(client->mctx, ctx, sizeof(*ctx)); 1719 1720 isc_event_free(ISC_EVENT_PTR(&event)); 1721 isc_task_detach(&tclone); 1722 dns_view_detach(&view); 1723 1724 return (result); 1725 } 1726 1727 void 1728 dns_client_cancelrequest(dns_clientreqtrans_t *trans) { 1729 reqctx_t *ctx; 1730 1731 REQUIRE(trans != NULL); 1732 ctx = (reqctx_t *)trans; 1733 REQUIRE(REQCTX_VALID(ctx)); 1734 1735 LOCK(&ctx->lock); 1736 1737 if (!ctx->canceled) { 1738 ctx->canceled = true; 1739 if (ctx->request != NULL) { 1740 dns_request_cancel(ctx->request); 1741 } 1742 } 1743 1744 UNLOCK(&ctx->lock); 1745 } 1746 1747 void 1748 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) { 1749 reqctx_t *ctx; 1750 isc_mem_t *mctx; 1751 dns_client_t *client; 1752 1753 REQUIRE(transp != NULL); 1754 ctx = (reqctx_t *)*transp; 1755 *transp = NULL; 1756 REQUIRE(REQCTX_VALID(ctx)); 1757 client = ctx->client; 1758 REQUIRE(DNS_CLIENT_VALID(client)); 1759 REQUIRE(ctx->event == NULL); 1760 REQUIRE(ctx->request != NULL); 1761 1762 dns_request_destroy(&ctx->request); 1763 mctx = client->mctx; 1764 1765 LOCK(&client->lock); 1766 1767 INSIST(ISC_LINK_LINKED(ctx, link)); 1768 ISC_LIST_UNLINK(client->reqctxs, ctx, link); 1769 1770 UNLOCK(&client->lock); 1771 1772 isc_mutex_destroy(&ctx->lock); 1773 ctx->magic = 0; 1774 1775 isc_mem_put(mctx, ctx, sizeof(*ctx)); 1776 1777 dns_client_destroy(&client); 1778 } 1779 1780 /*% 1781 * Dynamic update routines 1782 */ 1783 static isc_result_t 1784 rcode2result(dns_rcode_t rcode) { 1785 /* XXX: isn't there a similar function? */ 1786 switch (rcode) { 1787 case dns_rcode_formerr: 1788 return (DNS_R_FORMERR); 1789 case dns_rcode_servfail: 1790 return (DNS_R_SERVFAIL); 1791 case dns_rcode_nxdomain: 1792 return (DNS_R_NXDOMAIN); 1793 case dns_rcode_notimp: 1794 return (DNS_R_NOTIMP); 1795 case dns_rcode_refused: 1796 return (DNS_R_REFUSED); 1797 case dns_rcode_yxdomain: 1798 return (DNS_R_YXDOMAIN); 1799 case dns_rcode_yxrrset: 1800 return (DNS_R_YXRRSET); 1801 case dns_rcode_nxrrset: 1802 return (DNS_R_NXRRSET); 1803 case dns_rcode_notauth: 1804 return (DNS_R_NOTAUTH); 1805 case dns_rcode_notzone: 1806 return (DNS_R_NOTZONE); 1807 case dns_rcode_badvers: 1808 return (DNS_R_BADVERS); 1809 } 1810 1811 return (ISC_R_FAILURE); 1812 } 1813 1814 static void 1815 update_sendevent(updatectx_t *uctx, isc_result_t result) { 1816 isc_task_t *task; 1817 1818 dns_message_detach(&uctx->updatemsg); 1819 if (uctx->tsigkey != NULL) { 1820 dns_tsigkey_detach(&uctx->tsigkey); 1821 } 1822 if (uctx->sig0key != NULL) { 1823 dst_key_free(&uctx->sig0key); 1824 } 1825 1826 if (uctx->canceled) { 1827 uctx->event->result = ISC_R_CANCELED; 1828 } else { 1829 uctx->event->result = result; 1830 } 1831 uctx->event->state = uctx->state; 1832 task = uctx->event->ev_sender; 1833 uctx->event->ev_sender = uctx; 1834 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event)); 1835 } 1836 1837 static void 1838 update_done(isc_task_t *task, isc_event_t *event) { 1839 isc_result_t result; 1840 dns_requestevent_t *reqev = NULL; 1841 dns_request_t *request; 1842 dns_message_t *answer = NULL; 1843 updatectx_t *uctx = event->ev_arg; 1844 dns_client_t *client; 1845 unsigned int timeout, reqoptions; 1846 1847 UNUSED(task); 1848 1849 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1850 reqev = (dns_requestevent_t *)event; 1851 request = reqev->request; 1852 REQUIRE(UCTX_VALID(uctx)); 1853 client = uctx->client; 1854 REQUIRE(DNS_CLIENT_VALID(client)); 1855 1856 result = reqev->result; 1857 if (result != ISC_R_SUCCESS) { 1858 goto out; 1859 } 1860 1861 dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, &answer); 1862 uctx->state = dns_clientupdatestate_done; 1863 result = dns_request_getresponse(request, answer, 1864 DNS_MESSAGEPARSE_PRESERVEORDER); 1865 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror) { 1866 result = rcode2result(answer->rcode); 1867 } 1868 1869 out: 1870 if (answer != NULL) { 1871 dns_message_detach(&answer); 1872 } 1873 isc_event_free(&event); 1874 1875 LOCK(&uctx->lock); 1876 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link); 1877 dns_request_destroy(&uctx->updatereq); 1878 /* 1879 * Moving on to the next server shouldn't change the result 1880 * for NXDOMAIN, YXDOMAIN, NXRRSET and YXRRSET as they 1881 * indicate a prerequisite failure. REFUSED should also 1882 * be consistent across all servers but often isn't as that 1883 * is policy rather that zone content driven (slaves that 1884 * aren't willing to forward should return NOTIMPL). NOTZONE 1885 * indicates that we stuffed up the request construction so 1886 * don't retry. 1887 */ 1888 if (result != ISC_R_SUCCESS && result != DNS_R_NXDOMAIN && 1889 result != DNS_R_YXDOMAIN && result != DNS_R_YXRRSET && 1890 result != DNS_R_NXRRSET && result != DNS_R_NOTZONE && 1891 !uctx->canceled && uctx->currentserver != NULL) 1892 { 1893 dns_message_renderreset(uctx->updatemsg); 1894 dns_message_settsigkey(uctx->updatemsg, NULL); 1895 1896 timeout = client->update_timeout / uctx->nservers; 1897 if (timeout < MIN_UPDATE_TIMEOUT) { 1898 timeout = MIN_UPDATE_TIMEOUT; 1899 } 1900 reqoptions = 0; 1901 if (uctx->want_tcp) { 1902 reqoptions |= DNS_REQUESTOPT_TCP; 1903 } 1904 result = dns_request_createvia( 1905 uctx->view->requestmgr, uctx->updatemsg, NULL, 1906 uctx->currentserver, -1, reqoptions, uctx->tsigkey, 1907 timeout, client->update_udptimeout, 1908 client->update_udpretries, client->task, update_done, 1909 uctx, &uctx->updatereq); 1910 UNLOCK(&uctx->lock); 1911 1912 if (result == ISC_R_SUCCESS) { 1913 /* XXX: should we keep the 'done' state here? */ 1914 uctx->state = dns_clientupdatestate_sent; 1915 return; 1916 } 1917 } else { 1918 UNLOCK(&uctx->lock); 1919 } 1920 1921 update_sendevent(uctx, result); 1922 } 1923 1924 static isc_result_t 1925 send_update(updatectx_t *uctx) { 1926 isc_result_t result; 1927 dns_name_t *name = NULL; 1928 dns_rdataset_t *rdataset = NULL; 1929 dns_client_t *client = uctx->client; 1930 unsigned int timeout, reqoptions; 1931 1932 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL); 1933 1934 result = dns_message_gettempname(uctx->updatemsg, &name); 1935 if (result != ISC_R_SUCCESS) { 1936 return (result); 1937 } 1938 dns_name_init(name, NULL); 1939 dns_name_clone(uctx->zonename, name); 1940 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset); 1941 if (result != ISC_R_SUCCESS) { 1942 dns_message_puttempname(uctx->updatemsg, &name); 1943 return (result); 1944 } 1945 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); 1946 ISC_LIST_INIT(name->list); 1947 ISC_LIST_APPEND(name->list, rdataset, link); 1948 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE); 1949 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) { 1950 result = dns_message_setsig0key(uctx->updatemsg, uctx->sig0key); 1951 if (result != ISC_R_SUCCESS) { 1952 return (result); 1953 } 1954 } 1955 timeout = client->update_timeout / uctx->nservers; 1956 if (timeout < MIN_UPDATE_TIMEOUT) { 1957 timeout = MIN_UPDATE_TIMEOUT; 1958 } 1959 reqoptions = 0; 1960 if (uctx->want_tcp) { 1961 reqoptions |= DNS_REQUESTOPT_TCP; 1962 } 1963 result = dns_request_createvia( 1964 uctx->view->requestmgr, uctx->updatemsg, NULL, 1965 uctx->currentserver, -1, reqoptions, uctx->tsigkey, timeout, 1966 client->update_udptimeout, client->update_udpretries, 1967 client->task, update_done, uctx, &uctx->updatereq); 1968 if (result == ISC_R_SUCCESS && 1969 uctx->state == dns_clientupdatestate_prepare) { 1970 uctx->state = dns_clientupdatestate_sent; 1971 } 1972 1973 return (result); 1974 } 1975 1976 static void 1977 resolveaddr_done(isc_task_t *task, isc_event_t *event) { 1978 isc_result_t result; 1979 int family; 1980 dns_rdatatype_t qtype; 1981 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 1982 dns_name_t *name; 1983 dns_rdataset_t *rdataset; 1984 updatectx_t *uctx; 1985 bool completed = false; 1986 1987 UNUSED(task); 1988 1989 REQUIRE(event->ev_arg != NULL); 1990 uctx = *(updatectx_t **)event->ev_arg; 1991 REQUIRE(UCTX_VALID(uctx)); 1992 1993 if (event->ev_arg == &uctx->bp4) { 1994 family = AF_INET; 1995 qtype = dns_rdatatype_a; 1996 LOCK(&uctx->lock); 1997 dns_client_destroyrestrans(&uctx->restrans); 1998 UNLOCK(&uctx->lock); 1999 } else { 2000 INSIST(event->ev_arg == &uctx->bp6); 2001 family = AF_INET6; 2002 qtype = dns_rdatatype_aaaa; 2003 LOCK(&uctx->lock); 2004 dns_client_destroyrestrans(&uctx->restrans2); 2005 UNLOCK(&uctx->lock); 2006 } 2007 2008 result = rev->result; 2009 if (result != ISC_R_SUCCESS) { 2010 goto done; 2011 } 2012 2013 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 2014 name = ISC_LIST_NEXT(name, link)) 2015 { 2016 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 2017 rdataset = ISC_LIST_NEXT(rdataset, link)) 2018 { 2019 if (!dns_rdataset_isassociated(rdataset)) { 2020 continue; 2021 } 2022 if (rdataset->type != qtype) { 2023 continue; 2024 } 2025 2026 for (result = dns_rdataset_first(rdataset); 2027 result == ISC_R_SUCCESS; 2028 result = dns_rdataset_next(rdataset)) 2029 { 2030 dns_rdata_t rdata; 2031 dns_rdata_in_a_t rdata_a; 2032 dns_rdata_in_aaaa_t rdata_aaaa; 2033 isc_sockaddr_t *sa; 2034 2035 sa = isc_mem_get(uctx->client->mctx, 2036 sizeof(*sa)); 2037 2038 dns_rdata_init(&rdata); 2039 switch (family) { 2040 case AF_INET: 2041 dns_rdataset_current(rdataset, &rdata); 2042 result = dns_rdata_tostruct( 2043 &rdata, &rdata_a, NULL); 2044 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2045 isc_sockaddr_fromin( 2046 sa, &rdata_a.in_addr, 53); 2047 dns_rdata_freestruct(&rdata_a); 2048 break; 2049 case AF_INET6: 2050 dns_rdataset_current(rdataset, &rdata); 2051 result = dns_rdata_tostruct( 2052 &rdata, &rdata_aaaa, NULL); 2053 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2054 isc_sockaddr_fromin6( 2055 sa, &rdata_aaaa.in6_addr, 53); 2056 dns_rdata_freestruct(&rdata_aaaa); 2057 break; 2058 } 2059 2060 ISC_LINK_INIT(sa, link); 2061 ISC_LIST_APPEND(uctx->servers, sa, link); 2062 uctx->nservers++; 2063 } 2064 } 2065 } 2066 2067 done: 2068 dns_client_freeresanswer(uctx->client, &rev->answerlist); 2069 isc_event_free(&event); 2070 2071 LOCK(&uctx->lock); 2072 if (uctx->restrans == NULL && uctx->restrans2 == NULL) { 2073 completed = true; 2074 } 2075 UNLOCK(&uctx->lock); 2076 2077 if (completed) { 2078 INSIST(uctx->currentserver == NULL); 2079 uctx->currentserver = ISC_LIST_HEAD(uctx->servers); 2080 if (uctx->currentserver != NULL && !uctx->canceled) { 2081 send_update(uctx); 2082 } else { 2083 if (result == ISC_R_SUCCESS) { 2084 result = ISC_R_NOTFOUND; 2085 } 2086 update_sendevent(uctx, result); 2087 } 2088 } 2089 } 2090 2091 static isc_result_t 2092 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, 2093 const dns_name_t *soaname) { 2094 isc_result_t result; 2095 dns_rdata_t soarr = DNS_RDATA_INIT; 2096 dns_rdata_soa_t soa; 2097 dns_name_t primary; 2098 unsigned int resoptions; 2099 2100 result = dns_rdataset_first(soaset); 2101 if (result != ISC_R_SUCCESS) { 2102 return (result); 2103 } 2104 dns_rdata_init(&soarr); 2105 dns_rdataset_current(soaset, &soarr); 2106 result = dns_rdata_tostruct(&soarr, &soa, NULL); 2107 if (result != ISC_R_SUCCESS) { 2108 return (result); 2109 } 2110 2111 dns_name_init(&primary, NULL); 2112 dns_name_clone(&soa.origin, &primary); 2113 2114 if (uctx->zonename == NULL) { 2115 uctx->zonename = dns_fixedname_name(&uctx->zonefname); 2116 dns_name_copynf(soaname, uctx->zonename); 2117 } 2118 2119 if (uctx->currentserver != NULL) { 2120 result = send_update(uctx); 2121 } else { 2122 /* 2123 * Get addresses of the primary server. We don't use the ADB 2124 * feature so that we could avoid caching data. 2125 */ 2126 LOCK(&uctx->lock); 2127 uctx->bp4 = uctx; 2128 resoptions = 0; 2129 if (uctx->want_tcp) { 2130 resoptions |= DNS_CLIENTRESOPT_TCP; 2131 } 2132 result = dns_client_startresolve( 2133 uctx->client, &primary, uctx->rdclass, dns_rdatatype_a, 2134 resoptions, uctx->client->task, resolveaddr_done, 2135 &uctx->bp4, &uctx->restrans); 2136 if (result == ISC_R_SUCCESS) { 2137 uctx->bp6 = uctx; 2138 result = dns_client_startresolve( 2139 uctx->client, &primary, uctx->rdclass, 2140 dns_rdatatype_aaaa, resoptions, 2141 uctx->client->task, resolveaddr_done, 2142 &uctx->bp6, &uctx->restrans2); 2143 } 2144 UNLOCK(&uctx->lock); 2145 } 2146 2147 dns_rdata_freestruct(&soa); 2148 2149 return (result); 2150 } 2151 2152 static void 2153 receive_soa(isc_task_t *task, isc_event_t *event) { 2154 dns_requestevent_t *reqev = NULL; 2155 updatectx_t *uctx; 2156 dns_client_t *client; 2157 isc_result_t result, eresult; 2158 dns_request_t *request; 2159 dns_message_t *rcvmsg = NULL; 2160 dns_section_t section; 2161 dns_rdataset_t *soaset = NULL; 2162 int pass = 0; 2163 dns_name_t *name; 2164 dns_message_t *soaquery = NULL; 2165 isc_sockaddr_t *addr; 2166 bool seencname = false; 2167 bool droplabel = false; 2168 dns_name_t tname; 2169 unsigned int nlabels, reqoptions; 2170 2171 UNUSED(task); 2172 2173 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2174 reqev = (dns_requestevent_t *)event; 2175 request = reqev->request; 2176 result = eresult = reqev->result; 2177 POST(result); 2178 uctx = reqev->ev_arg; 2179 client = uctx->client; 2180 soaquery = uctx->soaquery; 2181 addr = uctx->currentserver; 2182 INSIST(addr != NULL); 2183 2184 isc_event_free(&event); 2185 2186 if (eresult != ISC_R_SUCCESS) { 2187 result = eresult; 2188 goto out; 2189 } 2190 2191 dns_message_create(uctx->client->mctx, DNS_MESSAGE_INTENTPARSE, 2192 &rcvmsg); 2193 result = dns_request_getresponse(request, rcvmsg, 2194 DNS_MESSAGEPARSE_PRESERVEORDER); 2195 2196 if (result == DNS_R_TSIGERRORSET) { 2197 dns_request_t *newrequest = NULL; 2198 2199 /* Retry SOA request without TSIG */ 2200 dns_message_detach(&rcvmsg); 2201 dns_message_renderreset(uctx->soaquery); 2202 reqoptions = 0; 2203 if (uctx->want_tcp) { 2204 reqoptions |= DNS_REQUESTOPT_TCP; 2205 } 2206 result = dns_request_createvia( 2207 uctx->view->requestmgr, uctx->soaquery, NULL, addr, -1, 2208 reqoptions, NULL, client->find_timeout * 20, 2209 client->find_timeout, 3, uctx->client->task, 2210 receive_soa, uctx, &newrequest); 2211 if (result == ISC_R_SUCCESS) { 2212 LOCK(&uctx->lock); 2213 dns_request_destroy(&uctx->soareq); 2214 uctx->soareq = newrequest; 2215 UNLOCK(&uctx->lock); 2216 2217 return; 2218 } 2219 goto out; 2220 } 2221 2222 section = DNS_SECTION_ANSWER; 2223 POST(section); 2224 2225 if (rcvmsg->rcode != dns_rcode_noerror && 2226 rcvmsg->rcode != dns_rcode_nxdomain) { 2227 result = rcode2result(rcvmsg->rcode); 2228 goto out; 2229 } 2230 2231 lookforsoa: 2232 if (pass == 0) { 2233 section = DNS_SECTION_ANSWER; 2234 } else if (pass == 1) { 2235 section = DNS_SECTION_AUTHORITY; 2236 } else { 2237 droplabel = true; 2238 goto out; 2239 } 2240 2241 result = dns_message_firstname(rcvmsg, section); 2242 if (result != ISC_R_SUCCESS) { 2243 pass++; 2244 goto lookforsoa; 2245 } 2246 while (result == ISC_R_SUCCESS) { 2247 name = NULL; 2248 dns_message_currentname(rcvmsg, section, &name); 2249 soaset = NULL; 2250 result = dns_message_findtype(name, dns_rdatatype_soa, 0, 2251 &soaset); 2252 if (result == ISC_R_SUCCESS) { 2253 break; 2254 } 2255 if (section == DNS_SECTION_ANSWER) { 2256 dns_rdataset_t *tset = NULL; 2257 if (dns_message_findtype(name, dns_rdatatype_cname, 0, 2258 &tset) == ISC_R_SUCCESS || 2259 dns_message_findtype(name, dns_rdatatype_dname, 0, 2260 &tset) == ISC_R_SUCCESS) 2261 { 2262 seencname = true; 2263 break; 2264 } 2265 } 2266 2267 result = dns_message_nextname(rcvmsg, section); 2268 } 2269 2270 if (soaset == NULL && !seencname) { 2271 pass++; 2272 goto lookforsoa; 2273 } 2274 2275 if (seencname) { 2276 droplabel = true; 2277 goto out; 2278 } 2279 2280 result = process_soa(uctx, soaset, name); 2281 2282 out: 2283 if (droplabel) { 2284 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 2285 INSIST(result == ISC_R_SUCCESS); 2286 name = NULL; 2287 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 2288 nlabels = dns_name_countlabels(name); 2289 if (nlabels == 1) { 2290 result = DNS_R_SERVFAIL; /* is there a better error? */ 2291 } else { 2292 dns_name_init(&tname, NULL); 2293 dns_name_getlabelsequence(name, 1, nlabels - 1, &tname); 2294 dns_name_clone(&tname, name); 2295 dns_request_destroy(&request); 2296 LOCK(&uctx->lock); 2297 uctx->soareq = NULL; 2298 UNLOCK(&uctx->lock); 2299 dns_message_renderreset(soaquery); 2300 dns_message_settsigkey(soaquery, NULL); 2301 reqoptions = 0; 2302 if (uctx->want_tcp) { 2303 reqoptions |= DNS_REQUESTOPT_TCP; 2304 } 2305 result = dns_request_createvia( 2306 uctx->view->requestmgr, soaquery, NULL, 2307 uctx->currentserver, -1, reqoptions, 2308 uctx->tsigkey, client->find_timeout * 20, 2309 client->find_timeout, 3, client->task, 2310 receive_soa, uctx, &uctx->soareq); 2311 } 2312 } 2313 2314 if (!droplabel || result != ISC_R_SUCCESS) { 2315 dns_message_detach(&uctx->soaquery); 2316 LOCK(&uctx->lock); 2317 dns_request_destroy(&uctx->soareq); 2318 UNLOCK(&uctx->lock); 2319 } 2320 2321 if (rcvmsg != NULL) { 2322 dns_message_detach(&rcvmsg); 2323 } 2324 2325 if (result != ISC_R_SUCCESS) { 2326 update_sendevent(uctx, result); 2327 } 2328 } 2329 2330 static isc_result_t 2331 request_soa(updatectx_t *uctx) { 2332 isc_result_t result; 2333 dns_message_t *soaquery = uctx->soaquery; 2334 dns_name_t *name = NULL; 2335 dns_rdataset_t *rdataset = NULL; 2336 unsigned int reqoptions; 2337 2338 if (soaquery == NULL) { 2339 dns_message_create(uctx->client->mctx, DNS_MESSAGE_INTENTRENDER, 2340 &soaquery); 2341 } 2342 soaquery->flags |= DNS_MESSAGEFLAG_RD; 2343 result = dns_message_gettempname(soaquery, &name); 2344 if (result != ISC_R_SUCCESS) { 2345 goto fail; 2346 } 2347 result = dns_message_gettemprdataset(soaquery, &rdataset); 2348 if (result != ISC_R_SUCCESS) { 2349 goto fail; 2350 } 2351 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); 2352 dns_name_clone(uctx->firstname, name); 2353 ISC_LIST_APPEND(name->list, rdataset, link); 2354 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 2355 rdataset = NULL; 2356 name = NULL; 2357 reqoptions = 0; 2358 if (uctx->want_tcp) { 2359 reqoptions |= DNS_REQUESTOPT_TCP; 2360 } 2361 2362 result = dns_request_createvia( 2363 uctx->view->requestmgr, soaquery, NULL, uctx->currentserver, -1, 2364 reqoptions, uctx->tsigkey, uctx->client->find_timeout * 20, 2365 uctx->client->find_timeout, 3, uctx->client->task, receive_soa, 2366 uctx, &uctx->soareq); 2367 if (result == ISC_R_SUCCESS) { 2368 uctx->soaquery = soaquery; 2369 return (ISC_R_SUCCESS); 2370 } 2371 2372 fail: 2373 if (rdataset != NULL) { 2374 ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */ 2375 dns_message_puttemprdataset(soaquery, &rdataset); 2376 } 2377 if (name != NULL) { 2378 dns_message_puttempname(soaquery, &name); 2379 } 2380 dns_message_detach(&soaquery); 2381 2382 return (result); 2383 } 2384 2385 static void 2386 resolvesoa_done(isc_task_t *task, isc_event_t *event) { 2387 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 2388 updatectx_t *uctx; 2389 dns_name_t *name, tname; 2390 dns_rdataset_t *rdataset = NULL; 2391 isc_result_t result = rev->result; 2392 unsigned int nlabels, resoptions; 2393 2394 UNUSED(task); 2395 2396 uctx = event->ev_arg; 2397 REQUIRE(UCTX_VALID(uctx)); 2398 2399 LOCK(&uctx->lock); 2400 dns_client_destroyrestrans(&uctx->restrans); 2401 UNLOCK(&uctx->lock); 2402 2403 uctx = event->ev_arg; 2404 if (result != ISC_R_SUCCESS && result != DNS_R_NCACHENXDOMAIN && 2405 result != DNS_R_NCACHENXRRSET) 2406 { 2407 /* XXX: what about DNSSEC failure? */ 2408 goto out; 2409 } 2410 2411 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 2412 name = ISC_LIST_NEXT(name, link)) 2413 { 2414 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 2415 rdataset = ISC_LIST_NEXT(rdataset, link)) 2416 { 2417 if (dns_rdataset_isassociated(rdataset) && 2418 rdataset->type == dns_rdatatype_soa) { 2419 break; 2420 } 2421 } 2422 } 2423 2424 if (rdataset == NULL) { 2425 /* Drop one label and retry resolution. */ 2426 nlabels = dns_name_countlabels(&uctx->soaqname); 2427 if (nlabels == 1) { 2428 result = DNS_R_SERVFAIL; /* is there a better error? */ 2429 goto out; 2430 } 2431 dns_name_init(&tname, NULL); 2432 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1, 2433 &tname); 2434 dns_name_clone(&tname, &uctx->soaqname); 2435 resoptions = 0; 2436 if (uctx->want_tcp) { 2437 resoptions |= DNS_CLIENTRESOPT_TCP; 2438 } 2439 2440 result = dns_client_startresolve( 2441 uctx->client, &uctx->soaqname, uctx->rdclass, 2442 dns_rdatatype_soa, resoptions, uctx->client->task, 2443 resolvesoa_done, uctx, &uctx->restrans); 2444 } else { 2445 result = process_soa(uctx, rdataset, &uctx->soaqname); 2446 } 2447 2448 out: 2449 dns_client_freeresanswer(uctx->client, &rev->answerlist); 2450 isc_event_free(&event); 2451 2452 if (result != ISC_R_SUCCESS) { 2453 update_sendevent(uctx, result); 2454 } 2455 } 2456 2457 static isc_result_t 2458 copy_name(isc_mem_t *mctx, dns_message_t *msg, const dns_name_t *name, 2459 dns_name_t **newnamep) { 2460 isc_result_t result; 2461 dns_name_t *newname = NULL; 2462 isc_region_t r; 2463 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL; 2464 dns_rdatalist_t *rdatalist; 2465 dns_rdataset_t *rdataset, *newrdataset; 2466 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata; 2467 2468 result = dns_message_gettempname(msg, &newname); 2469 if (result != ISC_R_SUCCESS) { 2470 return (result); 2471 } 2472 isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 2473 dns_name_init(newname, NULL); 2474 dns_name_setbuffer(newname, namebuf); 2475 dns_message_takebuffer(msg, &namebuf); 2476 dns_name_copynf(name, newname); 2477 2478 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 2479 rdataset = ISC_LIST_NEXT(rdataset, link)) 2480 { 2481 rdatalist = NULL; 2482 result = dns_message_gettemprdatalist(msg, &rdatalist); 2483 if (result != ISC_R_SUCCESS) { 2484 goto fail; 2485 } 2486 dns_rdatalist_init(rdatalist); 2487 rdatalist->type = rdataset->type; 2488 rdatalist->rdclass = rdataset->rdclass; 2489 rdatalist->covers = rdataset->covers; 2490 rdatalist->ttl = rdataset->ttl; 2491 2492 result = dns_rdataset_first(rdataset); 2493 while (result == ISC_R_SUCCESS) { 2494 dns_rdata_reset(&rdata); 2495 dns_rdataset_current(rdataset, &rdata); 2496 2497 newrdata = NULL; 2498 result = dns_message_gettemprdata(msg, &newrdata); 2499 if (result != ISC_R_SUCCESS) { 2500 goto fail; 2501 } 2502 dns_rdata_toregion(&rdata, &r); 2503 rdatabuf = NULL; 2504 isc_buffer_allocate(mctx, &rdatabuf, r.length); 2505 isc_buffer_putmem(rdatabuf, r.base, r.length); 2506 isc_buffer_usedregion(rdatabuf, &r); 2507 dns_rdata_init(newrdata); 2508 dns_rdata_fromregion(newrdata, rdata.rdclass, 2509 rdata.type, &r); 2510 newrdata->flags = rdata.flags; 2511 2512 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link); 2513 dns_message_takebuffer(msg, &rdatabuf); 2514 2515 result = dns_rdataset_next(rdataset); 2516 } 2517 2518 newrdataset = NULL; 2519 result = dns_message_gettemprdataset(msg, &newrdataset); 2520 if (result != ISC_R_SUCCESS) { 2521 goto fail; 2522 } 2523 dns_rdatalist_tordataset(rdatalist, newrdataset); 2524 2525 ISC_LIST_APPEND(newname->list, newrdataset, link); 2526 } 2527 2528 *newnamep = newname; 2529 2530 return (ISC_R_SUCCESS); 2531 2532 fail: 2533 dns_message_puttempname(msg, &newname); 2534 2535 return (result); 2536 } 2537 2538 static void 2539 internal_update_callback(isc_task_t *task, isc_event_t *event) { 2540 updatearg_t *uarg = event->ev_arg; 2541 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event; 2542 2543 UNUSED(task); 2544 2545 LOCK(&uarg->lock); 2546 2547 uarg->result = uev->result; 2548 2549 dns_client_destroyupdatetrans(&uarg->trans); 2550 isc_event_free(&event); 2551 2552 if (!uarg->canceled) { 2553 UNLOCK(&uarg->lock); 2554 2555 /* Exit from the internal event loop */ 2556 isc_app_ctxsuspend(uarg->actx); 2557 } else { 2558 /* 2559 * We have already exited from the loop (due to some 2560 * unexpected event). Just clean the arg up. 2561 */ 2562 UNLOCK(&uarg->lock); 2563 isc_mutex_destroy(&uarg->lock); 2564 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg)); 2565 } 2566 } 2567 2568 isc_result_t 2569 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass, 2570 const dns_name_t *zonename, dns_namelist_t *prerequisites, 2571 dns_namelist_t *updates, isc_sockaddrlist_t *servers, 2572 dns_tsec_t *tsec, unsigned int options) { 2573 isc_result_t result; 2574 isc_appctx_t *actx; 2575 updatearg_t *uarg; 2576 2577 REQUIRE(DNS_CLIENT_VALID(client)); 2578 2579 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 2580 (options & DNS_CLIENTUPDOPT_ALLOWRUN) == 0) 2581 { 2582 /* 2583 * If the client is run under application's control, we need 2584 * to create a new running (sub)environment for this 2585 * particular update. 2586 */ 2587 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 2588 } else { 2589 actx = client->actx; 2590 } 2591 2592 uarg = isc_mem_get(client->mctx, sizeof(*uarg)); 2593 2594 isc_mutex_init(&uarg->lock); 2595 2596 uarg->actx = actx; 2597 uarg->client = client; 2598 uarg->result = ISC_R_FAILURE; 2599 uarg->trans = NULL; 2600 uarg->canceled = false; 2601 2602 result = dns_client_startupdate( 2603 client, rdclass, zonename, prerequisites, updates, servers, 2604 tsec, options, client->task, internal_update_callback, uarg, 2605 &uarg->trans); 2606 if (result != ISC_R_SUCCESS) { 2607 isc_mutex_destroy(&uarg->lock); 2608 isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2609 return (result); 2610 } 2611 2612 /* 2613 * Start internal event loop. It blocks until the entire process 2614 * is completed. 2615 */ 2616 result = isc_app_ctxrun(actx); 2617 2618 LOCK(&uarg->lock); 2619 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) { 2620 result = uarg->result; 2621 } 2622 2623 if (uarg->trans != NULL) { 2624 /* 2625 * Unusual termination (perhaps due to signal). We need some 2626 * tricky cleanup process. 2627 */ 2628 uarg->canceled = true; 2629 dns_client_cancelupdate(uarg->trans); 2630 2631 UNLOCK(&uarg->lock); 2632 2633 /* uarg will be freed in the event handler. */ 2634 } else { 2635 UNLOCK(&uarg->lock); 2636 2637 isc_mutex_destroy(&uarg->lock); 2638 isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2639 } 2640 2641 return (result); 2642 } 2643 2644 static void 2645 startupdate(isc_task_t *task, isc_event_t *event) { 2646 updatectx_t *uctx; 2647 isc_result_t result; 2648 unsigned int resoptions; 2649 2650 REQUIRE(event != NULL); 2651 2652 UNUSED(task); 2653 2654 uctx = event->ev_arg; 2655 2656 if (uctx->zonename != NULL && uctx->currentserver != NULL) { 2657 result = send_update(uctx); 2658 if (result != ISC_R_SUCCESS) { 2659 goto fail; 2660 } 2661 } else if (uctx->currentserver != NULL) { 2662 result = request_soa(uctx); 2663 if (result != ISC_R_SUCCESS) { 2664 goto fail; 2665 } 2666 } else { 2667 resoptions = 0; 2668 if (uctx->want_tcp) { 2669 resoptions |= DNS_CLIENTRESOPT_TCP; 2670 } 2671 dns_name_clone(uctx->firstname, &uctx->soaqname); 2672 result = dns_client_startresolve( 2673 uctx->client, &uctx->soaqname, uctx->rdclass, 2674 dns_rdatatype_soa, resoptions, uctx->client->task, 2675 resolvesoa_done, uctx, &uctx->restrans); 2676 if (result != ISC_R_SUCCESS) { 2677 goto fail; 2678 } 2679 } 2680 2681 isc_event_free(&event); 2682 2683 fail: 2684 if (result != ISC_R_SUCCESS) { 2685 update_sendevent(uctx, result); 2686 } 2687 } 2688 2689 isc_result_t 2690 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass, 2691 const dns_name_t *zonename, 2692 dns_namelist_t *prerequisites, dns_namelist_t *updates, 2693 isc_sockaddrlist_t *servers, dns_tsec_t *tsec, 2694 unsigned int options, isc_task_t *task, 2695 isc_taskaction_t action, void *arg, 2696 dns_clientupdatetrans_t **transp) { 2697 dns_view_t *view = NULL; 2698 isc_result_t result; 2699 dns_name_t *name, *newname; 2700 updatectx_t *uctx; 2701 isc_task_t *tclone = NULL; 2702 dns_section_t section = DNS_SECTION_UPDATE; 2703 isc_sockaddr_t *server, *sa = NULL; 2704 dns_tsectype_t tsectype = dns_tsectype_none; 2705 bool want_tcp; 2706 2707 UNUSED(options); 2708 2709 REQUIRE(DNS_CLIENT_VALID(client)); 2710 REQUIRE(transp != NULL && *transp == NULL); 2711 REQUIRE(updates != NULL); 2712 REQUIRE(task != NULL); 2713 2714 if (tsec != NULL) { 2715 tsectype = dns_tsec_gettype(tsec); 2716 if (tsectype != dns_tsectype_tsig) { 2717 return (ISC_R_NOTIMPLEMENTED); /* XXX */ 2718 } 2719 } 2720 2721 LOCK(&client->lock); 2722 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 2723 rdclass, &view); 2724 UNLOCK(&client->lock); 2725 if (result != ISC_R_SUCCESS) { 2726 return (result); 2727 } 2728 2729 want_tcp = ((options & DNS_CLIENTUPDOPT_TCP) != 0); 2730 2731 /* 2732 * Create a context and prepare some resources. 2733 */ 2734 2735 uctx = isc_mem_get(client->mctx, sizeof(*uctx)); 2736 2737 isc_mutex_init(&uctx->lock); 2738 2739 tclone = NULL; 2740 isc_task_attach(task, &tclone); 2741 uctx->client = client; 2742 ISC_LINK_INIT(uctx, link); 2743 uctx->state = dns_clientupdatestate_prepare; 2744 uctx->view = view; 2745 uctx->rdclass = rdclass; 2746 uctx->canceled = false; 2747 uctx->updatemsg = NULL; 2748 uctx->soaquery = NULL; 2749 uctx->updatereq = NULL; 2750 uctx->restrans = NULL; 2751 uctx->restrans2 = NULL; 2752 uctx->bp4 = NULL; 2753 uctx->bp6 = NULL; 2754 uctx->soareq = NULL; 2755 uctx->event = NULL; 2756 uctx->tsigkey = NULL; 2757 uctx->sig0key = NULL; 2758 uctx->zonename = NULL; 2759 uctx->want_tcp = want_tcp; 2760 dns_name_init(&uctx->soaqname, NULL); 2761 ISC_LIST_INIT(uctx->servers); 2762 uctx->nservers = 0; 2763 uctx->currentserver = NULL; 2764 dns_fixedname_init(&uctx->zonefname); 2765 if (tsec != NULL) { 2766 dns_tsec_getkey(tsec, &uctx->tsigkey); 2767 } 2768 uctx->event = (dns_clientupdateevent_t *)isc_event_allocate( 2769 client->mctx, tclone, DNS_EVENT_UPDATEDONE, action, arg, 2770 sizeof(*uctx->event)); 2771 if (zonename != NULL) { 2772 uctx->zonename = dns_fixedname_name(&uctx->zonefname); 2773 dns_name_copynf(zonename, uctx->zonename); 2774 } 2775 if (servers != NULL) { 2776 for (server = ISC_LIST_HEAD(*servers); server != NULL; 2777 server = ISC_LIST_NEXT(server, link)) 2778 { 2779 sa = isc_mem_get(client->mctx, sizeof(*sa)); 2780 sa->type = server->type; 2781 sa->length = server->length; 2782 ISC_LINK_INIT(sa, link); 2783 ISC_LIST_APPEND(uctx->servers, sa, link); 2784 if (uctx->currentserver == NULL) { 2785 uctx->currentserver = sa; 2786 } 2787 uctx->nservers++; 2788 } 2789 } 2790 2791 /* Make update message */ 2792 dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER, 2793 &uctx->updatemsg); 2794 uctx->updatemsg->opcode = dns_opcode_update; 2795 2796 if (prerequisites != NULL) { 2797 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL; 2798 name = ISC_LIST_NEXT(name, link)) 2799 { 2800 newname = NULL; 2801 result = copy_name(client->mctx, uctx->updatemsg, name, 2802 &newname); 2803 if (result != ISC_R_SUCCESS) { 2804 goto fail; 2805 } 2806 dns_message_addname(uctx->updatemsg, newname, 2807 DNS_SECTION_PREREQUISITE); 2808 } 2809 } 2810 2811 for (name = ISC_LIST_HEAD(*updates); name != NULL; 2812 name = ISC_LIST_NEXT(name, link)) 2813 { 2814 newname = NULL; 2815 result = copy_name(client->mctx, uctx->updatemsg, name, 2816 &newname); 2817 if (result != ISC_R_SUCCESS) { 2818 goto fail; 2819 } 2820 dns_message_addname(uctx->updatemsg, newname, 2821 DNS_SECTION_UPDATE); 2822 } 2823 2824 uctx->firstname = NULL; 2825 result = dns_message_firstname(uctx->updatemsg, section); 2826 if (result == ISC_R_NOMORE) { 2827 section = DNS_SECTION_PREREQUISITE; 2828 result = dns_message_firstname(uctx->updatemsg, section); 2829 } 2830 if (result != ISC_R_SUCCESS) { 2831 goto fail; 2832 } 2833 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname); 2834 2835 uctx->magic = UCTX_MAGIC; 2836 2837 LOCK(&client->lock); 2838 ISC_LIST_APPEND(client->updatectxs, uctx, link); 2839 isc_refcount_increment(&client->references); 2840 UNLOCK(&client->lock); 2841 2842 *transp = (dns_clientupdatetrans_t *)uctx; 2843 result = isc_app_ctxonrun(client->actx, client->mctx, client->task, 2844 startupdate, uctx); 2845 if (result == ISC_R_ALREADYRUNNING) { 2846 isc_event_t *event; 2847 event = isc_event_allocate(client->mctx, dns_client_startupdate, 2848 DNS_EVENT_STARTUPDATE, startupdate, 2849 uctx, sizeof(*event)); 2850 result = ISC_R_SUCCESS; 2851 isc_task_send(task, &event); 2852 } 2853 if (result == ISC_R_SUCCESS) { 2854 return (result); 2855 } 2856 2857 isc_refcount_decrement1(&client->references); 2858 *transp = NULL; 2859 2860 fail: 2861 if (ISC_LINK_LINKED(uctx, link)) { 2862 LOCK(&client->lock); 2863 ISC_LIST_UNLINK(client->updatectxs, uctx, link); 2864 UNLOCK(&client->lock); 2865 } 2866 if (uctx->updatemsg != NULL) { 2867 dns_message_detach(&uctx->updatemsg); 2868 } 2869 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { 2870 ISC_LIST_UNLINK(uctx->servers, sa, link); 2871 isc_mem_put(client->mctx, sa, sizeof(*sa)); 2872 } 2873 if (uctx->event != NULL) { 2874 isc_event_free(ISC_EVENT_PTR(&uctx->event)); 2875 } 2876 if (uctx->tsigkey != NULL) { 2877 dns_tsigkey_detach(&uctx->tsigkey); 2878 } 2879 isc_task_detach(&tclone); 2880 isc_mutex_destroy(&uctx->lock); 2881 uctx->magic = 0; 2882 isc_mem_put(client->mctx, uctx, sizeof(*uctx)); 2883 dns_view_detach(&view); 2884 2885 return (result); 2886 } 2887 2888 void 2889 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) { 2890 updatectx_t *uctx; 2891 2892 REQUIRE(trans != NULL); 2893 uctx = (updatectx_t *)trans; 2894 REQUIRE(UCTX_VALID(uctx)); 2895 2896 LOCK(&uctx->lock); 2897 2898 if (!uctx->canceled) { 2899 uctx->canceled = true; 2900 if (uctx->updatereq != NULL) { 2901 dns_request_cancel(uctx->updatereq); 2902 } 2903 if (uctx->soareq != NULL) { 2904 dns_request_cancel(uctx->soareq); 2905 } 2906 if (uctx->restrans != NULL) { 2907 dns_client_cancelresolve(uctx->restrans); 2908 } 2909 if (uctx->restrans2 != NULL) { 2910 dns_client_cancelresolve(uctx->restrans2); 2911 } 2912 } 2913 2914 UNLOCK(&uctx->lock); 2915 } 2916 2917 void 2918 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) { 2919 updatectx_t *uctx; 2920 isc_mem_t *mctx; 2921 dns_client_t *client; 2922 isc_sockaddr_t *sa; 2923 2924 REQUIRE(transp != NULL); 2925 uctx = (updatectx_t *)*transp; 2926 *transp = NULL; 2927 REQUIRE(UCTX_VALID(uctx)); 2928 client = uctx->client; 2929 REQUIRE(DNS_CLIENT_VALID(client)); 2930 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL && 2931 uctx->soareq == NULL && uctx->soaquery == NULL && 2932 uctx->event == NULL && uctx->tsigkey == NULL && 2933 uctx->sig0key == NULL); 2934 2935 mctx = client->mctx; 2936 dns_view_detach(&uctx->view); 2937 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { 2938 ISC_LIST_UNLINK(uctx->servers, sa, link); 2939 isc_mem_put(mctx, sa, sizeof(*sa)); 2940 } 2941 2942 LOCK(&client->lock); 2943 2944 INSIST(ISC_LINK_LINKED(uctx, link)); 2945 ISC_LIST_UNLINK(client->updatectxs, uctx, link); 2946 2947 UNLOCK(&client->lock); 2948 2949 isc_mutex_destroy(&uctx->lock); 2950 uctx->magic = 0; 2951 2952 isc_mem_put(mctx, uctx, sizeof(*uctx)); 2953 2954 dns_client_destroy(&client); 2955 } 2956 2957 isc_mem_t * 2958 dns_client_mctx(dns_client_t *client) { 2959 REQUIRE(DNS_CLIENT_VALID(client)); 2960 return (client->mctx); 2961 } 2962 2963 typedef struct { 2964 isc_buffer_t buffer; 2965 dns_rdataset_t rdataset; 2966 dns_rdatalist_t rdatalist; 2967 dns_rdata_t rdata; 2968 size_t size; 2969 isc_mem_t *mctx; 2970 unsigned char data[FLEXIBLE_ARRAY_MEMBER]; 2971 } dns_client_updaterec_t; 2972 2973 isc_result_t 2974 dns_client_updaterec(dns_client_updateop_t op, const dns_name_t *owner, 2975 dns_rdatatype_t type, dns_rdata_t *source, dns_ttl_t ttl, 2976 dns_name_t *target, dns_rdataset_t *rdataset, 2977 dns_rdatalist_t *rdatalist, dns_rdata_t *rdata, 2978 isc_mem_t *mctx) { 2979 dns_client_updaterec_t *updaterec = NULL; 2980 size_t size = offsetof(dns_client_updaterec_t, data); 2981 2982 REQUIRE(op < updateop_max); 2983 REQUIRE(owner != NULL); 2984 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) || 2985 (rdataset == NULL && rdatalist == NULL && rdata == NULL && 2986 mctx != NULL)); 2987 if (op == updateop_add) { 2988 REQUIRE(source != NULL); 2989 } 2990 if (source != NULL) { 2991 REQUIRE(source->type == type); 2992 REQUIRE(op == updateop_add || op == updateop_delete || 2993 op == updateop_exist); 2994 } 2995 2996 size += owner->length; 2997 if (source != NULL) { 2998 size += source->length; 2999 } 3000 3001 if (rdataset == NULL) { 3002 updaterec = isc_mem_get(mctx, size); 3003 rdataset = &updaterec->rdataset; 3004 rdatalist = &updaterec->rdatalist; 3005 rdata = &updaterec->rdata; 3006 dns_rdataset_init(rdataset); 3007 dns_rdatalist_init(&updaterec->rdatalist); 3008 dns_rdata_init(&updaterec->rdata); 3009 isc_buffer_init( 3010 &updaterec->buffer, updaterec->data, 3011 (unsigned int)(size - 3012 offsetof(dns_client_updaterec_t, data))); 3013 dns_name_copy(owner, target, &updaterec->buffer); 3014 if (source != NULL) { 3015 isc_region_t r; 3016 dns_rdata_clone(source, rdata); 3017 dns_rdata_toregion(rdata, &r); 3018 rdata->data = isc_buffer_used(&updaterec->buffer); 3019 isc_buffer_copyregion(&updaterec->buffer, &r); 3020 } 3021 updaterec->mctx = NULL; 3022 isc_mem_attach(mctx, &updaterec->mctx); 3023 } else if (source != NULL) { 3024 dns_rdata_clone(source, rdata); 3025 } 3026 3027 switch (op) { 3028 case updateop_add: 3029 break; 3030 case updateop_delete: 3031 if (source != NULL) { 3032 ttl = 0; 3033 dns_rdata_makedelete(rdata); 3034 } else { 3035 dns_rdata_deleterrset(rdata, type); 3036 } 3037 break; 3038 case updateop_notexist: 3039 dns_rdata_notexist(rdata, type); 3040 break; 3041 case updateop_exist: 3042 if (source == NULL) { 3043 ttl = 0; 3044 dns_rdata_exists(rdata, type); 3045 } 3046 case updateop_none: 3047 break; 3048 default: 3049 INSIST(0); 3050 ISC_UNREACHABLE(); 3051 } 3052 3053 rdatalist->type = rdata->type; 3054 rdatalist->rdclass = rdata->rdclass; 3055 if (source != NULL) { 3056 rdatalist->covers = dns_rdata_covers(rdata); 3057 rdatalist->ttl = ttl; 3058 } 3059 ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 3060 dns_rdatalist_tordataset(rdatalist, rdataset); 3061 ISC_LIST_APPEND(target->list, rdataset, link); 3062 if (updaterec != NULL) { 3063 target->attributes |= DNS_NAMEATTR_HASUPDATEREC; 3064 dns_name_setbuffer(target, &updaterec->buffer); 3065 } 3066 if (op == updateop_add || op == updateop_delete) { 3067 target->attributes |= DNS_NAMEATTR_UPDATE; 3068 } else { 3069 target->attributes |= DNS_NAMEATTR_PREREQUISITE; 3070 } 3071 return (ISC_R_SUCCESS); 3072 } 3073 3074 void 3075 dns_client_freeupdate(dns_name_t **namep) { 3076 dns_client_updaterec_t *updaterec; 3077 dns_rdatalist_t *rdatalist; 3078 dns_rdataset_t *rdataset; 3079 dns_rdata_t *rdata; 3080 dns_name_t *name; 3081 3082 REQUIRE(namep != NULL && *namep != NULL); 3083 3084 name = *namep; 3085 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 3086 rdataset = ISC_LIST_HEAD(name->list)) 3087 { 3088 ISC_LIST_UNLINK(name->list, rdataset, link); 3089 rdatalist = NULL; 3090 dns_rdatalist_fromrdataset(rdataset, &rdatalist); 3091 if (rdatalist == NULL) { 3092 dns_rdataset_disassociate(rdataset); 3093 continue; 3094 } 3095 for (rdata = ISC_LIST_HEAD(rdatalist->rdata); rdata != NULL; 3096 rdata = ISC_LIST_HEAD(rdatalist->rdata)) 3097 { 3098 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link); 3099 } 3100 dns_rdataset_disassociate(rdataset); 3101 } 3102 3103 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) { 3104 updaterec = (dns_client_updaterec_t *)name->buffer; 3105 INSIST(updaterec != NULL); 3106 isc_mem_putanddetach(&updaterec->mctx, updaterec, 3107 updaterec->size); 3108 *namep = NULL; 3109 } 3110 } 3111