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