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