client.c revision 224090
1/* 2 * Copyright (C) 2009, 2010 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: client.c,v 1.12 2010-12-03 12:03:22 marka Exp $ */ 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 result, tresult; 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 result = ISC_R_SUCCESS; 745 name = dns_fixedname_name(&rctx->name); 746 747 do { 748 dns_name_t *fname = NULL; 749 dns_name_t *ansname = NULL; 750 dns_db_t *db = NULL; 751 dns_dbnode_t *node = NULL; 752 753 rctx->restarts++; 754 want_restart = ISC_FALSE; 755 756 if (event == NULL && !rctx->canceled) { 757 dns_fixedname_init(&foundname); 758 fname = dns_fixedname_name(&foundname); 759 INSIST(!dns_rdataset_isassociated(rctx->rdataset)); 760 INSIST(rctx->sigrdataset == NULL || 761 !dns_rdataset_isassociated(rctx->sigrdataset)); 762 result = view_find(rctx, &db, &node, fname); 763 if (result == ISC_R_NOTFOUND) { 764 /* 765 * We don't know anything about the name. 766 * Launch a fetch. 767 */ 768 if (node != NULL) { 769 INSIST(db != NULL); 770 dns_db_detachnode(db, &node); 771 } 772 if (db != NULL) 773 dns_db_detach(&db); 774 result = start_fetch(rctx); 775 if (result != ISC_R_SUCCESS) { 776 putrdataset(mctx, &rctx->rdataset); 777 if (rctx->sigrdataset != NULL) 778 putrdataset(mctx, 779 &rctx->sigrdataset); 780 send_event = ISC_TRUE; 781 } 782 goto done; 783 } 784 } else { 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 break; 969 } 970 } 971 } 972 if (n == 0) { 973 /* 974 * We didn't match any rdatasets (which means 975 * something went wrong in this 976 * implementation). 977 */ 978 result = DNS_R_SERVFAIL; /* better code? */ 979 } else { 980 ISC_LIST_APPEND(rctx->namelist, ansname, link); 981 ansname = NULL; 982 } 983 dns_rdatasetiter_destroy(&rdsiter); 984 if (tresult != ISC_R_NOMORE) 985 result = DNS_R_SERVFAIL; /* ditto */ 986 else 987 result = ISC_R_SUCCESS; 988 goto done; 989 } else { 990 /* 991 * This is the "normal" case -- an ordinary question 992 * to which we've got the answer. 993 */ 994 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link); 995 rctx->rdataset = NULL; 996 if (rctx->sigrdataset != NULL) { 997 ISC_LIST_APPEND(ansname->list, 998 rctx->sigrdataset, link); 999 rctx->sigrdataset = NULL; 1000 } 1001 ISC_LIST_APPEND(rctx->namelist, ansname, link); 1002 ansname = NULL; 1003 } 1004 1005 done: 1006 /* 1007 * Free temporary resources 1008 */ 1009 if (ansname != NULL) { 1010 dns_rdataset_t *rdataset; 1011 1012 while ((rdataset = ISC_LIST_HEAD(ansname->list)) 1013 != NULL) { 1014 ISC_LIST_UNLINK(ansname->list, rdataset, link); 1015 putrdataset(mctx, &rdataset); 1016 } 1017 dns_name_free(ansname, mctx); 1018 isc_mem_put(mctx, ansname, sizeof(*ansname)); 1019 } 1020 1021 if (node != NULL) 1022 dns_db_detachnode(db, &node); 1023 if (db != NULL) 1024 dns_db_detach(&db); 1025 if (event != NULL) 1026 isc_event_free(ISC_EVENT_PTR(&event)); 1027 1028 /* 1029 * Limit the number of restarts. 1030 */ 1031 if (want_restart && rctx->restarts == MAX_RESTARTS) { 1032 want_restart = ISC_FALSE; 1033 result = ISC_R_QUOTA; 1034 send_event = ISC_TRUE; 1035 } 1036 1037 /* 1038 * Prepare further find with new resources 1039 */ 1040 if (want_restart) { 1041 INSIST(rctx->rdataset == NULL && 1042 rctx->sigrdataset == NULL); 1043 1044 result = getrdataset(mctx, &rctx->rdataset); 1045 if (result == ISC_R_SUCCESS && rctx->want_dnssec) { 1046 result = getrdataset(mctx, &rctx->sigrdataset); 1047 if (result != ISC_R_SUCCESS) { 1048 putrdataset(mctx, &rctx->rdataset); 1049 } 1050 } 1051 1052 if (result != ISC_R_SUCCESS) { 1053 want_restart = ISC_FALSE; 1054 send_event = ISC_TRUE; 1055 } 1056 } 1057 } while (want_restart); 1058 1059 if (send_event) { 1060 isc_task_t *task; 1061 1062 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) { 1063 ISC_LIST_UNLINK(rctx->namelist, name, link); 1064 ISC_LIST_APPEND(rctx->event->answerlist, name, link); 1065 } 1066 1067 rctx->event->result = result; 1068 rctx->event->vresult = vresult; 1069 task = rctx->event->ev_sender; 1070 rctx->event->ev_sender = rctx; 1071 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event)); 1072 } 1073 1074 UNLOCK(&rctx->lock); 1075} 1076 1077static void 1078resolve_done(isc_task_t *task, isc_event_t *event) { 1079 resarg_t *resarg = event->ev_arg; 1080 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 1081 dns_name_t *name; 1082 1083 UNUSED(task); 1084 1085 LOCK(&resarg->lock); 1086 1087 resarg->result = rev->result; 1088 resarg->vresult = rev->vresult; 1089 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) { 1090 ISC_LIST_UNLINK(rev->answerlist, name, link); 1091 ISC_LIST_APPEND(*resarg->namelist, name, link); 1092 } 1093 1094 dns_client_destroyrestrans(&resarg->trans); 1095 isc_event_free(&event); 1096 1097 if (!resarg->canceled) { 1098 UNLOCK(&resarg->lock); 1099 1100 /* Exit from the internal event loop */ 1101 isc_app_ctxsuspend(resarg->actx); 1102 } else { 1103 /* 1104 * We have already exited from the loop (due to some 1105 * unexpected event). Just clean the arg up. 1106 */ 1107 UNLOCK(&resarg->lock); 1108 DESTROYLOCK(&resarg->lock); 1109 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg)); 1110 } 1111} 1112 1113isc_result_t 1114dns_client_resolve(dns_client_t *client, dns_name_t *name, 1115 dns_rdataclass_t rdclass, dns_rdatatype_t type, 1116 unsigned int options, dns_namelist_t *namelist) 1117{ 1118 isc_result_t result; 1119 isc_appctx_t *actx; 1120 resarg_t *resarg; 1121 1122 REQUIRE(DNS_CLIENT_VALID(client)); 1123 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist)); 1124 1125 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 1126 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) { 1127 /* 1128 * If the client is run under application's control, we need 1129 * to create a new running (sub)environment for this 1130 * particular resolution. 1131 */ 1132 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 1133 } else 1134 actx = client->actx; 1135 1136 resarg = isc_mem_get(client->mctx, sizeof(*resarg)); 1137 if (resarg == NULL) 1138 return (ISC_R_NOMEMORY); 1139 1140 result = isc_mutex_init(&resarg->lock); 1141 if (result != ISC_R_SUCCESS) { 1142 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1143 return (result); 1144 } 1145 1146 resarg->actx = actx; 1147 resarg->client = client; 1148 resarg->result = DNS_R_SERVFAIL; 1149 resarg->namelist = namelist; 1150 resarg->trans = NULL; 1151 resarg->canceled = ISC_FALSE; 1152 result = dns_client_startresolve(client, name, rdclass, type, options, 1153 client->task, resolve_done, resarg, 1154 &resarg->trans); 1155 if (result != ISC_R_SUCCESS) { 1156 DESTROYLOCK(&resarg->lock); 1157 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1158 return (result); 1159 } 1160 1161 /* 1162 * Start internal event loop. It blocks until the entire process 1163 * is completed. 1164 */ 1165 result = isc_app_ctxrun(actx); 1166 1167 LOCK(&resarg->lock); 1168 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) 1169 result = resarg->result; 1170 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) { 1171 /* 1172 * If this lookup failed due to some error in DNSSEC 1173 * validation, return the validation error code. 1174 * XXX: or should we pass the validation result separately? 1175 */ 1176 result = resarg->vresult; 1177 } 1178 if (resarg->trans != NULL) { 1179 /* 1180 * Unusual termination (perhaps due to signal). We need some 1181 * tricky cleanup process. 1182 */ 1183 resarg->canceled = ISC_TRUE; 1184 dns_client_cancelresolve(resarg->trans); 1185 1186 UNLOCK(&resarg->lock); 1187 1188 /* resarg will be freed in the event handler. */ 1189 } else { 1190 UNLOCK(&resarg->lock); 1191 1192 DESTROYLOCK(&resarg->lock); 1193 isc_mem_put(client->mctx, resarg, sizeof(*resarg)); 1194 } 1195 1196 return (result); 1197} 1198 1199isc_result_t 1200dns_client_startresolve(dns_client_t *client, dns_name_t *name, 1201 dns_rdataclass_t rdclass, dns_rdatatype_t type, 1202 unsigned int options, isc_task_t *task, 1203 isc_taskaction_t action, void *arg, 1204 dns_clientrestrans_t **transp) 1205{ 1206 dns_view_t *view = NULL; 1207 dns_clientresevent_t *event = NULL; 1208 resctx_t *rctx = NULL; 1209 isc_task_t *clone = NULL; 1210 isc_mem_t *mctx; 1211 isc_result_t result; 1212 dns_rdataset_t *rdataset, *sigrdataset; 1213 isc_boolean_t want_dnssec; 1214 1215 REQUIRE(DNS_CLIENT_VALID(client)); 1216 REQUIRE(transp != NULL && *transp == NULL); 1217 1218 LOCK(&client->lock); 1219 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1220 rdclass, &view); 1221 UNLOCK(&client->lock); 1222 if (result != ISC_R_SUCCESS) 1223 return (result); 1224 1225 mctx = client->mctx; 1226 rdataset = NULL; 1227 sigrdataset = NULL; 1228 want_dnssec = ISC_TF((options & DNS_CLIENTRESOPT_NODNSSEC) == 0); 1229 1230 /* 1231 * Prepare some intermediate resources 1232 */ 1233 clone = NULL; 1234 isc_task_attach(task, &clone); 1235 event = (dns_clientresevent_t *) 1236 isc_event_allocate(mctx, clone, DNS_EVENT_CLIENTRESDONE, 1237 action, arg, sizeof(*event)); 1238 if (event == NULL) { 1239 result = ISC_R_NOMEMORY; 1240 goto cleanup; 1241 } 1242 event->result = DNS_R_SERVFAIL; 1243 ISC_LIST_INIT(event->answerlist); 1244 1245 rctx = isc_mem_get(mctx, sizeof(*rctx)); 1246 if (rctx == NULL) 1247 result = ISC_R_NOMEMORY; 1248 else { 1249 result = isc_mutex_init(&rctx->lock); 1250 if (result != ISC_R_SUCCESS) { 1251 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1252 rctx = NULL; 1253 } 1254 } 1255 if (result != ISC_R_SUCCESS) 1256 goto cleanup; 1257 1258 result = getrdataset(mctx, &rdataset); 1259 if (result != ISC_R_SUCCESS) 1260 goto cleanup; 1261 rctx->rdataset = rdataset; 1262 1263 if (want_dnssec) { 1264 result = getrdataset(mctx, &sigrdataset); 1265 if (result != ISC_R_SUCCESS) 1266 goto cleanup; 1267 } 1268 rctx->sigrdataset = sigrdataset; 1269 1270 dns_fixedname_init(&rctx->name); 1271 result = dns_name_copy(name, dns_fixedname_name(&rctx->name), NULL); 1272 if (result != ISC_R_SUCCESS) 1273 goto cleanup; 1274 1275 rctx->client = client; 1276 ISC_LINK_INIT(rctx, link); 1277 rctx->canceled = ISC_FALSE; 1278 rctx->task = client->task; 1279 rctx->type = type; 1280 rctx->view = view; 1281 rctx->restarts = 0; 1282 rctx->fetch = NULL; 1283 rctx->want_dnssec = want_dnssec; 1284 ISC_LIST_INIT(rctx->namelist); 1285 rctx->event = event; 1286 1287 rctx->magic = RCTX_MAGIC; 1288 1289 LOCK(&client->lock); 1290 ISC_LIST_APPEND(client->resctxs, rctx, link); 1291 UNLOCK(&client->lock); 1292 1293 client_resfind(rctx, NULL); 1294 1295 *transp = (dns_clientrestrans_t *)rctx; 1296 1297 return (ISC_R_SUCCESS); 1298 1299 cleanup: 1300 if (rdataset != NULL) 1301 putrdataset(client->mctx, &rdataset); 1302 if (sigrdataset != NULL) 1303 putrdataset(client->mctx, &sigrdataset); 1304 if (rctx != NULL) { 1305 DESTROYLOCK(&rctx->lock); 1306 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1307 } 1308 if (event != NULL) 1309 isc_event_free(ISC_EVENT_PTR(&event)); 1310 isc_task_detach(&clone); 1311 dns_view_detach(&view); 1312 1313 return (result); 1314} 1315 1316void 1317dns_client_cancelresolve(dns_clientrestrans_t *trans) { 1318 resctx_t *rctx; 1319 1320 REQUIRE(trans != NULL); 1321 rctx = (resctx_t *)trans; 1322 REQUIRE(RCTX_VALID(rctx)); 1323 1324 LOCK(&rctx->lock); 1325 1326 if (!rctx->canceled) { 1327 rctx->canceled = ISC_TRUE; 1328 if (rctx->fetch != NULL) 1329 dns_resolver_cancelfetch(rctx->fetch); 1330 } 1331 1332 UNLOCK(&rctx->lock); 1333} 1334 1335void 1336dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) { 1337 dns_name_t *name; 1338 dns_rdataset_t *rdataset; 1339 1340 REQUIRE(DNS_CLIENT_VALID(client)); 1341 REQUIRE(namelist != NULL); 1342 1343 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) { 1344 ISC_LIST_UNLINK(*namelist, name, link); 1345 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) { 1346 ISC_LIST_UNLINK(name->list, rdataset, link); 1347 putrdataset(client->mctx, &rdataset); 1348 } 1349 dns_name_free(name, client->mctx); 1350 isc_mem_put(client->mctx, name, sizeof(*name)); 1351 } 1352} 1353 1354void 1355dns_client_destroyrestrans(dns_clientrestrans_t **transp) { 1356 resctx_t *rctx; 1357 isc_mem_t *mctx; 1358 dns_client_t *client; 1359 isc_boolean_t need_destroyclient = ISC_FALSE; 1360 1361 REQUIRE(transp != NULL); 1362 rctx = (resctx_t *)*transp; 1363 REQUIRE(RCTX_VALID(rctx)); 1364 REQUIRE(rctx->fetch == NULL); 1365 REQUIRE(rctx->event == NULL); 1366 client = rctx->client; 1367 REQUIRE(DNS_CLIENT_VALID(client)); 1368 1369 mctx = client->mctx; 1370 dns_view_detach(&rctx->view); 1371 1372 LOCK(&client->lock); 1373 1374 INSIST(ISC_LINK_LINKED(rctx, link)); 1375 ISC_LIST_UNLINK(client->resctxs, rctx, link); 1376 1377 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && 1378 ISC_LIST_EMPTY(client->reqctxs) && 1379 ISC_LIST_EMPTY(client->updatectxs)) 1380 need_destroyclient = ISC_TRUE; 1381 1382 UNLOCK(&client->lock); 1383 1384 INSIST(ISC_LIST_EMPTY(rctx->namelist)); 1385 1386 DESTROYLOCK(&rctx->lock); 1387 rctx->magic = 0; 1388 1389 isc_mem_put(mctx, rctx, sizeof(*rctx)); 1390 1391 if (need_destroyclient) 1392 destroyclient(&client); 1393 1394 *transp = NULL; 1395} 1396 1397isc_result_t 1398dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass, 1399 dns_name_t *keyname, isc_buffer_t *keydatabuf) 1400{ 1401 isc_result_t result; 1402 dns_view_t *view = NULL; 1403 dst_key_t *dstkey = NULL; 1404 dns_keytable_t *secroots = NULL; 1405 1406 REQUIRE(DNS_CLIENT_VALID(client)); 1407 1408 LOCK(&client->lock); 1409 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1410 rdclass, &view); 1411 UNLOCK(&client->lock); 1412 if (result != ISC_R_SUCCESS) 1413 goto cleanup; 1414 1415 result = dns_view_getsecroots(view, &secroots); 1416 if (result != ISC_R_SUCCESS) 1417 goto cleanup; 1418 1419 result = dst_key_fromdns(keyname, rdclass, keydatabuf, client->mctx, 1420 &dstkey); 1421 if (result != ISC_R_SUCCESS) 1422 goto cleanup; 1423 1424 result = dns_keytable_add(secroots, ISC_FALSE, &dstkey); 1425 1426 cleanup: 1427 if (dstkey != NULL) 1428 dst_key_free(&dstkey); 1429 if (view != NULL) 1430 dns_view_detach(&view); 1431 if (secroots != NULL) 1432 dns_keytable_detach(&secroots); 1433 return (result); 1434} 1435 1436/*% 1437 * Simple request routines 1438 */ 1439static void 1440request_done(isc_task_t *task, isc_event_t *event) { 1441 dns_requestevent_t *reqev = NULL; 1442 dns_request_t *request; 1443 isc_result_t result, eresult; 1444 reqctx_t *ctx; 1445 1446 UNUSED(task); 1447 1448 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1449 reqev = (dns_requestevent_t *)event; 1450 request = reqev->request; 1451 result = eresult = reqev->result; 1452 ctx = reqev->ev_arg; 1453 REQUIRE(REQCTX_VALID(ctx)); 1454 1455 isc_event_free(&event); 1456 1457 LOCK(&ctx->lock); 1458 1459 if (eresult == ISC_R_SUCCESS) { 1460 result = dns_request_getresponse(request, ctx->event->rmessage, 1461 ctx->parseoptions); 1462 } 1463 1464 if (ctx->tsigkey != NULL) 1465 dns_tsigkey_detach(&ctx->tsigkey); 1466 1467 if (ctx->canceled) 1468 ctx->event->result = ISC_R_CANCELED; 1469 else 1470 ctx->event->result = result; 1471 task = ctx->event->ev_sender; 1472 ctx->event->ev_sender = ctx; 1473 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event)); 1474 1475 UNLOCK(&ctx->lock); 1476} 1477 1478static void 1479localrequest_done(isc_task_t *task, isc_event_t *event) { 1480 reqarg_t *reqarg = event->ev_arg; 1481 dns_clientreqevent_t *rev =(dns_clientreqevent_t *)event; 1482 1483 UNUSED(task); 1484 1485 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE); 1486 1487 LOCK(&reqarg->lock); 1488 1489 reqarg->result = rev->result; 1490 dns_client_destroyreqtrans(&reqarg->trans); 1491 isc_event_free(&event); 1492 1493 if (!reqarg->canceled) { 1494 UNLOCK(&reqarg->lock); 1495 1496 /* Exit from the internal event loop */ 1497 isc_app_ctxsuspend(reqarg->actx); 1498 } else { 1499 /* 1500 * We have already exited from the loop (due to some 1501 * unexpected event). Just clean the arg up. 1502 */ 1503 UNLOCK(&reqarg->lock); 1504 DESTROYLOCK(&reqarg->lock); 1505 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg)); 1506 } 1507} 1508 1509isc_result_t 1510dns_client_request(dns_client_t *client, dns_message_t *qmessage, 1511 dns_message_t *rmessage, isc_sockaddr_t *server, 1512 unsigned int options, unsigned int parseoptions, 1513 dns_tsec_t *tsec, unsigned int timeout, 1514 unsigned int udptimeout, unsigned int udpretries) 1515{ 1516 isc_appctx_t *actx; 1517 reqarg_t *reqarg; 1518 isc_result_t result; 1519 1520 REQUIRE(DNS_CLIENT_VALID(client)); 1521 REQUIRE(qmessage != NULL); 1522 REQUIRE(rmessage != NULL); 1523 1524 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 1525 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0) { 1526 /* 1527 * If the client is run under application's control, we need 1528 * to create a new running (sub)environment for this 1529 * particular resolution. 1530 */ 1531 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 1532 } else 1533 actx = client->actx; 1534 1535 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg)); 1536 if (reqarg == NULL) 1537 return (ISC_R_NOMEMORY); 1538 1539 result = isc_mutex_init(&reqarg->lock); 1540 if (result != ISC_R_SUCCESS) { 1541 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1542 return (result); 1543 } 1544 1545 reqarg->actx = actx; 1546 reqarg->client = client; 1547 reqarg->trans = NULL; 1548 reqarg->canceled = ISC_FALSE; 1549 1550 result = dns_client_startrequest(client, qmessage, rmessage, server, 1551 options, parseoptions, tsec, timeout, 1552 udptimeout, udpretries, 1553 client->task, localrequest_done, 1554 reqarg, &reqarg->trans); 1555 if (result != ISC_R_SUCCESS) { 1556 DESTROYLOCK(&reqarg->lock); 1557 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1558 return (result); 1559 } 1560 1561 /* 1562 * Start internal event loop. It blocks until the entire process 1563 * is completed. 1564 */ 1565 result = isc_app_ctxrun(actx); 1566 1567 LOCK(&reqarg->lock); 1568 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) 1569 result = reqarg->result; 1570 if (reqarg->trans != NULL) { 1571 /* 1572 * Unusual termination (perhaps due to signal). We need some 1573 * tricky cleanup process. 1574 */ 1575 reqarg->canceled = ISC_TRUE; 1576 dns_client_cancelresolve(reqarg->trans); 1577 1578 UNLOCK(&reqarg->lock); 1579 1580 /* reqarg will be freed in the event handler. */ 1581 } else { 1582 UNLOCK(&reqarg->lock); 1583 1584 DESTROYLOCK(&reqarg->lock); 1585 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg)); 1586 } 1587 1588 return (result); 1589} 1590 1591isc_result_t 1592dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage, 1593 dns_message_t *rmessage, isc_sockaddr_t *server, 1594 unsigned int options, unsigned int parseoptions, 1595 dns_tsec_t *tsec, unsigned int timeout, 1596 unsigned int udptimeout, unsigned int udpretries, 1597 isc_task_t *task, isc_taskaction_t action, void *arg, 1598 dns_clientreqtrans_t **transp) 1599{ 1600 isc_result_t result; 1601 dns_view_t *view = NULL; 1602 isc_task_t *clone = NULL; 1603 dns_clientreqevent_t *event = NULL; 1604 reqctx_t *ctx = NULL; 1605 dns_tsectype_t tsectype = dns_tsectype_none; 1606 1607 UNUSED(options); 1608 1609 REQUIRE(DNS_CLIENT_VALID(client)); 1610 REQUIRE(qmessage != NULL); 1611 REQUIRE(rmessage != NULL); 1612 REQUIRE(transp != NULL && *transp == NULL); 1613 1614 if (tsec != NULL) { 1615 tsectype = dns_tsec_gettype(tsec); 1616 if (tsectype != dns_tsectype_tsig) 1617 return (ISC_R_NOTIMPLEMENTED); /* XXX */ 1618 } 1619 1620 LOCK(&client->lock); 1621 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 1622 qmessage->rdclass, &view); 1623 UNLOCK(&client->lock); 1624 if (result != ISC_R_SUCCESS) 1625 return (result); 1626 1627 clone = NULL; 1628 isc_task_attach(task, &clone); 1629 event = (dns_clientreqevent_t *) 1630 isc_event_allocate(client->mctx, clone, 1631 DNS_EVENT_CLIENTREQDONE, 1632 action, arg, sizeof(*event)); 1633 if (event == NULL) { 1634 result = ISC_R_NOMEMORY; 1635 goto cleanup; 1636 } 1637 1638 ctx = isc_mem_get(client->mctx, sizeof(*ctx)); 1639 if (ctx == NULL) 1640 result = ISC_R_NOMEMORY; 1641 else { 1642 result = isc_mutex_init(&ctx->lock); 1643 if (result != ISC_R_SUCCESS) { 1644 isc_mem_put(client->mctx, ctx, sizeof(*ctx)); 1645 ctx = NULL; 1646 } 1647 } 1648 if (result != ISC_R_SUCCESS) 1649 goto cleanup; 1650 1651 ctx->client = client; 1652 ISC_LINK_INIT(ctx, link); 1653 ctx->parseoptions = parseoptions; 1654 ctx->canceled = ISC_FALSE; 1655 ctx->event = event; 1656 ctx->event->rmessage = rmessage; 1657 ctx->tsigkey = NULL; 1658 if (tsec != NULL) 1659 dns_tsec_getkey(tsec, &ctx->tsigkey); 1660 1661 ctx->magic = REQCTX_MAGIC; 1662 1663 LOCK(&client->lock); 1664 ISC_LIST_APPEND(client->reqctxs, ctx, link); 1665 UNLOCK(&client->lock); 1666 1667 ctx->request = NULL; 1668 result = dns_request_createvia3(view->requestmgr, qmessage, NULL, 1669 server, options, ctx->tsigkey, 1670 timeout, udptimeout, udpretries, 1671 client->task, request_done, ctx, 1672 &ctx->request); 1673 if (result == ISC_R_SUCCESS) { 1674 dns_view_detach(&view); 1675 *transp = (dns_clientreqtrans_t *)ctx; 1676 return (ISC_R_SUCCESS); 1677 } 1678 1679 cleanup: 1680 if (ctx != NULL) { 1681 LOCK(&client->lock); 1682 ISC_LIST_UNLINK(client->reqctxs, ctx, link); 1683 UNLOCK(&client->lock); 1684 DESTROYLOCK(&ctx->lock); 1685 isc_mem_put(client->mctx, ctx, sizeof(*ctx)); 1686 } 1687 if (event != NULL) 1688 isc_event_free(ISC_EVENT_PTR(&event)); 1689 isc_task_detach(&clone); 1690 dns_view_detach(&view); 1691 1692 return (result); 1693} 1694 1695void 1696dns_client_cancelrequest(dns_clientreqtrans_t *trans) { 1697 reqctx_t *ctx; 1698 1699 REQUIRE(trans != NULL); 1700 ctx = (reqctx_t *)trans; 1701 REQUIRE(REQCTX_VALID(ctx)); 1702 1703 LOCK(&ctx->lock); 1704 1705 if (!ctx->canceled) { 1706 ctx->canceled = ISC_TRUE; 1707 if (ctx->request != NULL) 1708 dns_request_cancel(ctx->request); 1709 } 1710 1711 UNLOCK(&ctx->lock); 1712} 1713 1714void 1715dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) { 1716 reqctx_t *ctx; 1717 isc_mem_t *mctx; 1718 dns_client_t *client; 1719 isc_boolean_t need_destroyclient = ISC_FALSE; 1720 1721 REQUIRE(transp != NULL); 1722 ctx = (reqctx_t *)*transp; 1723 REQUIRE(REQCTX_VALID(ctx)); 1724 client = ctx->client; 1725 REQUIRE(DNS_CLIENT_VALID(client)); 1726 REQUIRE(ctx->event == NULL); 1727 REQUIRE(ctx->request != NULL); 1728 1729 dns_request_destroy(&ctx->request); 1730 mctx = client->mctx; 1731 1732 LOCK(&client->lock); 1733 1734 INSIST(ISC_LINK_LINKED(ctx, link)); 1735 ISC_LIST_UNLINK(client->reqctxs, ctx, link); 1736 1737 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && 1738 ISC_LIST_EMPTY(client->reqctxs) && 1739 ISC_LIST_EMPTY(client->updatectxs)) { 1740 need_destroyclient = ISC_TRUE; 1741 } 1742 1743 UNLOCK(&client->lock); 1744 1745 DESTROYLOCK(&ctx->lock); 1746 ctx->magic = 0; 1747 1748 isc_mem_put(mctx, ctx, sizeof(*ctx)); 1749 1750 if (need_destroyclient) 1751 destroyclient(&client); 1752 1753 *transp = NULL; 1754} 1755 1756/*% 1757 * Dynamic update routines 1758 */ 1759static isc_result_t 1760rcode2result(dns_rcode_t rcode) { 1761 /* XXX: isn't there a similar function? */ 1762 switch (rcode) { 1763 case dns_rcode_formerr: 1764 return (DNS_R_FORMERR); 1765 case dns_rcode_servfail: 1766 return (DNS_R_SERVFAIL); 1767 case dns_rcode_nxdomain: 1768 return (DNS_R_NXDOMAIN); 1769 case dns_rcode_notimp: 1770 return (DNS_R_NOTIMP); 1771 case dns_rcode_refused: 1772 return (DNS_R_REFUSED); 1773 case dns_rcode_yxdomain: 1774 return (DNS_R_YXDOMAIN); 1775 case dns_rcode_yxrrset: 1776 return (DNS_R_YXRRSET); 1777 case dns_rcode_nxrrset: 1778 return (DNS_R_NXRRSET); 1779 case dns_rcode_notauth: 1780 return (DNS_R_NOTAUTH); 1781 case dns_rcode_notzone: 1782 return (DNS_R_NOTZONE); 1783 case dns_rcode_badvers: 1784 return (DNS_R_BADVERS); 1785 } 1786 1787 return (ISC_R_FAILURE); 1788} 1789 1790static void 1791update_sendevent(updatectx_t *uctx, isc_result_t result) { 1792 isc_task_t *task; 1793 1794 dns_message_destroy(&uctx->updatemsg); 1795 if (uctx->tsigkey != NULL) 1796 dns_tsigkey_detach(&uctx->tsigkey); 1797 if (uctx->sig0key != NULL) 1798 dst_key_free(&uctx->sig0key); 1799 1800 if (uctx->canceled) 1801 uctx->event->result = ISC_R_CANCELED; 1802 else 1803 uctx->event->result = result; 1804 uctx->event->state = uctx->state; 1805 task = uctx->event->ev_sender; 1806 uctx->event->ev_sender = uctx; 1807 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event)); 1808} 1809 1810static void 1811update_done(isc_task_t *task, isc_event_t *event) { 1812 isc_result_t result; 1813 dns_requestevent_t *reqev = NULL; 1814 dns_request_t *request; 1815 dns_message_t *answer = NULL; 1816 updatectx_t *uctx = event->ev_arg; 1817 dns_client_t *client; 1818 unsigned int timeout; 1819 1820 UNUSED(task); 1821 1822 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 1823 reqev = (dns_requestevent_t *)event; 1824 request = reqev->request; 1825 REQUIRE(UCTX_VALID(uctx)); 1826 client = uctx->client; 1827 REQUIRE(DNS_CLIENT_VALID(client)); 1828 1829 result = reqev->result; 1830 if (result != ISC_R_SUCCESS) 1831 goto out; 1832 1833 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, 1834 &answer); 1835 if (result != ISC_R_SUCCESS) 1836 goto out; 1837 uctx->state = dns_clientupdatestate_done; 1838 result = dns_request_getresponse(request, answer, 1839 DNS_MESSAGEPARSE_PRESERVEORDER); 1840 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror) 1841 result = rcode2result(answer->rcode); 1842 1843 out: 1844 if (answer != NULL) 1845 dns_message_destroy(&answer); 1846 isc_event_free(&event); 1847 1848 LOCK(&uctx->lock); 1849 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link); 1850 dns_request_destroy(&uctx->updatereq); 1851 if (result != ISC_R_SUCCESS && !uctx->canceled && 1852 uctx->currentserver != NULL) { 1853 dns_message_renderreset(uctx->updatemsg); 1854 dns_message_settsigkey(uctx->updatemsg, NULL); 1855 1856 timeout = client->update_timeout / uctx->nservers; 1857 if (timeout < MIN_UPDATE_TIMEOUT) 1858 timeout = MIN_UPDATE_TIMEOUT; 1859 result = dns_request_createvia3(uctx->view->requestmgr, 1860 uctx->updatemsg, 1861 NULL, 1862 uctx->currentserver, 0, 1863 uctx->tsigkey, 1864 timeout, 1865 client->update_udptimeout, 1866 client->update_udpretries, 1867 client->task, 1868 update_done, uctx, 1869 &uctx->updatereq); 1870 UNLOCK(&uctx->lock); 1871 1872 if (result == ISC_R_SUCCESS) { 1873 /* XXX: should we keep the 'done' state here? */ 1874 uctx->state = dns_clientupdatestate_sent; 1875 return; 1876 } 1877 } else 1878 UNLOCK(&uctx->lock); 1879 1880 update_sendevent(uctx, result); 1881} 1882 1883static isc_result_t 1884send_update(updatectx_t *uctx) { 1885 isc_result_t result; 1886 dns_name_t *name = NULL; 1887 dns_rdataset_t *rdataset = NULL; 1888 dns_client_t *client = uctx->client; 1889 unsigned int timeout; 1890 1891 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL); 1892 1893 result = dns_message_gettempname(uctx->updatemsg, &name); 1894 if (result != ISC_R_SUCCESS) 1895 return (result); 1896 dns_name_init(name, NULL); 1897 dns_name_clone(uctx->zonename, name); 1898 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset); 1899 if (result != ISC_R_SUCCESS) { 1900 dns_message_puttempname(uctx->updatemsg, &name); 1901 return (result); 1902 } 1903 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); 1904 ISC_LIST_INIT(name->list); 1905 ISC_LIST_APPEND(name->list, rdataset, link); 1906 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE); 1907 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) { 1908 result = dns_message_setsig0key(uctx->updatemsg, 1909 uctx->sig0key); 1910 if (result != ISC_R_SUCCESS) 1911 return (result); 1912 } 1913 timeout = client->update_timeout / uctx->nservers; 1914 if (timeout < MIN_UPDATE_TIMEOUT) 1915 timeout = MIN_UPDATE_TIMEOUT; 1916 result = dns_request_createvia3(uctx->view->requestmgr, 1917 uctx->updatemsg, 1918 NULL, uctx->currentserver, 0, 1919 uctx->tsigkey, timeout, 1920 client->update_udptimeout, 1921 client->update_udpretries, 1922 client->task, update_done, uctx, 1923 &uctx->updatereq); 1924 if (result == ISC_R_SUCCESS && 1925 uctx->state == dns_clientupdatestate_prepare) { 1926 uctx->state = dns_clientupdatestate_sent; 1927 } 1928 1929 return (result); 1930} 1931 1932static void 1933resolveaddr_done(isc_task_t *task, isc_event_t *event) { 1934 isc_result_t result; 1935 int family; 1936 dns_rdatatype_t qtype; 1937 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 1938 dns_name_t *name; 1939 dns_rdataset_t *rdataset; 1940 updatectx_t *uctx; 1941 isc_boolean_t completed = ISC_FALSE; 1942 1943 UNUSED(task); 1944 1945 REQUIRE(event->ev_arg != NULL); 1946 uctx = *(updatectx_t **)event->ev_arg; 1947 REQUIRE(UCTX_VALID(uctx)); 1948 1949 if (event->ev_arg == &uctx->bp4) { 1950 family = AF_INET; 1951 qtype = dns_rdatatype_a; 1952 LOCK(&uctx->lock); 1953 dns_client_destroyrestrans(&uctx->restrans); 1954 UNLOCK(&uctx->lock); 1955 } else { 1956 INSIST(event->ev_arg == &uctx->bp6); 1957 family = AF_INET6; 1958 qtype = dns_rdatatype_aaaa; 1959 LOCK(&uctx->lock); 1960 dns_client_destroyrestrans(&uctx->restrans2); 1961 UNLOCK(&uctx->lock); 1962 } 1963 1964 result = rev->result; 1965 if (result != ISC_R_SUCCESS) 1966 goto done; 1967 1968 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 1969 name = ISC_LIST_NEXT(name, link)) { 1970 for (rdataset = ISC_LIST_HEAD(name->list); 1971 rdataset != NULL; 1972 rdataset = ISC_LIST_NEXT(rdataset, link)) { 1973 if (!dns_rdataset_isassociated(rdataset)) 1974 continue; 1975 if (rdataset->type != qtype) 1976 continue; 1977 1978 for (result = dns_rdataset_first(rdataset); 1979 result == ISC_R_SUCCESS; 1980 result = dns_rdataset_next(rdataset)) { 1981 dns_rdata_t rdata; 1982 dns_rdata_in_a_t rdata_a; 1983 dns_rdata_in_aaaa_t rdata_aaaa; 1984 isc_sockaddr_t *sa; 1985 1986 sa = isc_mem_get(uctx->client->mctx, 1987 sizeof(*sa)); 1988 if (sa == NULL) { 1989 /* 1990 * If we fail to get a sockaddr, 1991 we simply move forward with the 1992 * addresses we've got so far. 1993 */ 1994 goto done; 1995 } 1996 1997 dns_rdata_init(&rdata); 1998 switch (family) { 1999 case AF_INET: 2000 dns_rdataset_current(rdataset, &rdata); 2001 dns_rdata_tostruct(&rdata, &rdata_a, 2002 NULL); 2003 isc_sockaddr_fromin(sa, 2004 &rdata_a.in_addr, 2005 53); 2006 dns_rdata_freestruct(&rdata_a); 2007 break; 2008 case AF_INET6: 2009 dns_rdataset_current(rdataset, &rdata); 2010 dns_rdata_tostruct(&rdata, &rdata_aaaa, 2011 NULL); 2012 isc_sockaddr_fromin6(sa, 2013 &rdata_aaaa.in6_addr, 2014 53); 2015 dns_rdata_freestruct(&rdata_aaaa); 2016 break; 2017 } 2018 2019 ISC_LINK_INIT(sa, link); 2020 ISC_LIST_APPEND(uctx->servers, sa, link); 2021 uctx->nservers++; 2022 } 2023 } 2024 } 2025 2026 done: 2027 dns_client_freeresanswer(uctx->client, &rev->answerlist); 2028 isc_event_free(&event); 2029 2030 LOCK(&uctx->lock); 2031 if (uctx->restrans == NULL && uctx->restrans2 == NULL) 2032 completed = ISC_TRUE; 2033 UNLOCK(&uctx->lock); 2034 2035 if (completed) { 2036 INSIST(uctx->currentserver == NULL); 2037 uctx->currentserver = ISC_LIST_HEAD(uctx->servers); 2038 if (uctx->currentserver != NULL && !uctx->canceled) 2039 send_update(uctx); 2040 else { 2041 if (result == ISC_R_SUCCESS) 2042 result = ISC_R_NOTFOUND; 2043 update_sendevent(uctx, result); 2044 } 2045 } 2046} 2047 2048static isc_result_t 2049process_soa(updatectx_t *uctx, dns_rdataset_t *soaset, dns_name_t *soaname) { 2050 isc_result_t result; 2051 dns_rdata_t soarr = DNS_RDATA_INIT; 2052 dns_rdata_soa_t soa; 2053 dns_name_t primary; 2054 2055 result = dns_rdataset_first(soaset); 2056 if (result != ISC_R_SUCCESS) 2057 return (result); 2058 dns_rdata_init(&soarr); 2059 dns_rdataset_current(soaset, &soarr); 2060 result = dns_rdata_tostruct(&soarr, &soa, NULL); 2061 if (result != ISC_R_SUCCESS) 2062 return (result); 2063 2064 dns_name_init(&primary, NULL); 2065 dns_name_clone(&soa.origin, &primary); 2066 2067 if (uctx->zonename == NULL) { 2068 uctx->zonename = dns_fixedname_name(&uctx->zonefname); 2069 result = dns_name_copy(soaname, uctx->zonename, NULL); 2070 if (result != ISC_R_SUCCESS) 2071 goto out; 2072 } 2073 2074 if (uctx->currentserver != NULL) 2075 result = send_update(uctx); 2076 else { 2077 /* 2078 * Get addresses of the primary server. We don't use the ADB 2079 * feature so that we could avoid caching data. 2080 */ 2081 LOCK(&uctx->lock); 2082 uctx->bp4 = uctx; 2083 result = dns_client_startresolve(uctx->client, &primary, 2084 uctx->rdclass, 2085 dns_rdatatype_a, 2086 0, uctx->client->task, 2087 resolveaddr_done, &uctx->bp4, 2088 &uctx->restrans); 2089 if (result == ISC_R_SUCCESS) { 2090 uctx->bp6 = uctx; 2091 result = dns_client_startresolve(uctx->client, 2092 &primary, 2093 uctx->rdclass, 2094 dns_rdatatype_aaaa, 2095 0, uctx->client->task, 2096 resolveaddr_done, 2097 &uctx->bp6, 2098 &uctx->restrans2); 2099 } 2100 UNLOCK(&uctx->lock); 2101 } 2102 2103 out: 2104 dns_rdata_freestruct(&soa); 2105 2106 return (result); 2107} 2108 2109static void 2110receive_soa(isc_task_t *task, isc_event_t *event) { 2111 dns_requestevent_t *reqev = NULL; 2112 updatectx_t *uctx; 2113 dns_client_t *client; 2114 isc_result_t result, eresult; 2115 dns_request_t *request; 2116 dns_message_t *rcvmsg = NULL; 2117 dns_section_t section; 2118 dns_rdataset_t *soaset = NULL; 2119 int pass = 0; 2120 dns_name_t *name; 2121 dns_message_t *soaquery = NULL; 2122 isc_sockaddr_t *addr; 2123 isc_boolean_t seencname = ISC_FALSE; 2124 isc_boolean_t droplabel = ISC_FALSE; 2125 dns_name_t tname; 2126 unsigned int nlabels; 2127 2128 UNUSED(task); 2129 2130 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE); 2131 reqev = (dns_requestevent_t *)event; 2132 request = reqev->request; 2133 result = eresult = reqev->result; 2134 uctx = reqev->ev_arg; 2135 client = uctx->client; 2136 soaquery = uctx->soaquery; 2137 addr = uctx->currentserver; 2138 INSIST(addr != NULL); 2139 2140 isc_event_free(&event); 2141 2142 if (eresult != ISC_R_SUCCESS) { 2143 result = eresult; 2144 goto out; 2145 } 2146 2147 result = dns_message_create(uctx->client->mctx, 2148 DNS_MESSAGE_INTENTPARSE, &rcvmsg); 2149 if (result != ISC_R_SUCCESS) 2150 goto out; 2151 result = dns_request_getresponse(request, rcvmsg, 2152 DNS_MESSAGEPARSE_PRESERVEORDER); 2153 2154 if (result == DNS_R_TSIGERRORSET) { 2155 dns_request_t *newrequest = NULL; 2156 2157 /* Retry SOA request without TSIG */ 2158 dns_message_destroy(&rcvmsg); 2159 dns_message_renderreset(uctx->soaquery); 2160 result = dns_request_createvia3(uctx->view->requestmgr, 2161 uctx->soaquery, NULL, addr, 0, 2162 NULL, 2163 client->find_timeout * 20, 2164 client->find_timeout, 3, 2165 uctx->client->task, 2166 receive_soa, uctx, 2167 &newrequest); 2168 if (result == ISC_R_SUCCESS) { 2169 LOCK(&uctx->lock); 2170 dns_request_destroy(&uctx->soareq); 2171 uctx->soareq = newrequest; 2172 UNLOCK(&uctx->lock); 2173 2174 return; 2175 } 2176 goto out; 2177 } 2178 2179 section = DNS_SECTION_ANSWER; 2180 2181 if (rcvmsg->rcode != dns_rcode_noerror && 2182 rcvmsg->rcode != dns_rcode_nxdomain) { 2183 result = rcode2result(rcvmsg->rcode); 2184 goto out; 2185 } 2186 2187 lookforsoa: 2188 if (pass == 0) 2189 section = DNS_SECTION_ANSWER; 2190 else if (pass == 1) 2191 section = DNS_SECTION_AUTHORITY; 2192 else { 2193 droplabel = ISC_TRUE; 2194 goto out; 2195 } 2196 2197 result = dns_message_firstname(rcvmsg, section); 2198 if (result != ISC_R_SUCCESS) { 2199 pass++; 2200 goto lookforsoa; 2201 } 2202 while (result == ISC_R_SUCCESS) { 2203 name = NULL; 2204 dns_message_currentname(rcvmsg, section, &name); 2205 soaset = NULL; 2206 result = dns_message_findtype(name, dns_rdatatype_soa, 0, 2207 &soaset); 2208 if (result == ISC_R_SUCCESS) 2209 break; 2210 if (section == DNS_SECTION_ANSWER) { 2211 dns_rdataset_t *tset = NULL; 2212 if (dns_message_findtype(name, dns_rdatatype_cname, 0, 2213 &tset) == ISC_R_SUCCESS 2214 || 2215 dns_message_findtype(name, dns_rdatatype_dname, 0, 2216 &tset) == ISC_R_SUCCESS 2217 ) 2218 { 2219 seencname = ISC_TRUE; 2220 break; 2221 } 2222 } 2223 2224 result = dns_message_nextname(rcvmsg, section); 2225 } 2226 2227 if (soaset == NULL && !seencname) { 2228 pass++; 2229 goto lookforsoa; 2230 } 2231 2232 if (seencname) { 2233 droplabel = ISC_TRUE; 2234 goto out; 2235 } 2236 2237 result = process_soa(uctx, soaset, name); 2238 2239 out: 2240 if (droplabel) { 2241 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION); 2242 INSIST(result == ISC_R_SUCCESS); 2243 name = NULL; 2244 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name); 2245 nlabels = dns_name_countlabels(name); 2246 if (nlabels == 1) 2247 result = DNS_R_SERVFAIL; /* is there a better error? */ 2248 else { 2249 dns_name_init(&tname, NULL); 2250 dns_name_getlabelsequence(name, 1, nlabels - 1, 2251 &tname); 2252 dns_name_clone(&tname, name); 2253 dns_request_destroy(&request); 2254 LOCK(&uctx->lock); 2255 uctx->soareq = NULL; 2256 UNLOCK(&uctx->lock); 2257 dns_message_renderreset(soaquery); 2258 dns_message_settsigkey(soaquery, NULL); 2259 result = dns_request_createvia3(uctx->view->requestmgr, 2260 soaquery, NULL, 2261 uctx->currentserver, 0, 2262 uctx->tsigkey, 2263 client->find_timeout * 2264 20, 2265 client->find_timeout, 2266 3, client->task, 2267 receive_soa, uctx, 2268 &uctx->soareq); 2269 } 2270 } 2271 2272 if (!droplabel || result != ISC_R_SUCCESS) { 2273 dns_message_destroy(&uctx->soaquery); 2274 LOCK(&uctx->lock); 2275 dns_request_destroy(&uctx->soareq); 2276 UNLOCK(&uctx->lock); 2277 } 2278 2279 if (rcvmsg != NULL) 2280 dns_message_destroy(&rcvmsg); 2281 2282 if (result != ISC_R_SUCCESS) 2283 update_sendevent(uctx, result); 2284} 2285 2286static isc_result_t 2287request_soa(updatectx_t *uctx) { 2288 isc_result_t result; 2289 dns_message_t *soaquery = uctx->soaquery; 2290 dns_name_t *name = NULL; 2291 dns_rdataset_t *rdataset = NULL; 2292 2293 if (soaquery == NULL) { 2294 result = dns_message_create(uctx->client->mctx, 2295 DNS_MESSAGE_INTENTRENDER, 2296 &soaquery); 2297 if (result != ISC_R_SUCCESS) 2298 return (result); 2299 } 2300 soaquery->flags |= DNS_MESSAGEFLAG_RD; 2301 result = dns_message_gettempname(soaquery, &name); 2302 if (result != ISC_R_SUCCESS) 2303 goto fail; 2304 result = dns_message_gettemprdataset(soaquery, &rdataset); 2305 if (result != ISC_R_SUCCESS) 2306 goto fail; 2307 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa); 2308 dns_name_clone(uctx->firstname, name); 2309 ISC_LIST_APPEND(name->list, rdataset, link); 2310 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION); 2311 rdataset = NULL; 2312 name = NULL; 2313 2314 result = dns_request_createvia3(uctx->view->requestmgr, 2315 soaquery, NULL, uctx->currentserver, 0, 2316 uctx->tsigkey, 2317 uctx->client->find_timeout * 20, 2318 uctx->client->find_timeout, 3, 2319 uctx->client->task, receive_soa, uctx, 2320 &uctx->soareq); 2321 if (result == ISC_R_SUCCESS) { 2322 uctx->soaquery = soaquery; 2323 return (ISC_R_SUCCESS); 2324 } 2325 2326 fail: 2327 if (rdataset != NULL) { 2328 ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */ 2329 dns_message_puttemprdataset(soaquery, &rdataset); 2330 } 2331 if (name != NULL) 2332 dns_message_puttempname(soaquery, &name); 2333 dns_message_destroy(&soaquery); 2334 2335 return (result); 2336} 2337 2338static void 2339resolvesoa_done(isc_task_t *task, isc_event_t *event) { 2340 dns_clientresevent_t *rev = (dns_clientresevent_t *)event; 2341 updatectx_t *uctx; 2342 dns_name_t *name, tname; 2343 dns_rdataset_t *rdataset = NULL; 2344 isc_result_t result = rev->result; 2345 unsigned int nlabels; 2346 2347 UNUSED(task); 2348 2349 uctx = event->ev_arg; 2350 REQUIRE(UCTX_VALID(uctx)); 2351 2352 LOCK(&uctx->lock); 2353 dns_client_destroyrestrans(&uctx->restrans); 2354 UNLOCK(&uctx->lock); 2355 2356 uctx = event->ev_arg; 2357 if (result != ISC_R_SUCCESS && 2358 result != DNS_R_NCACHENXDOMAIN && 2359 result != DNS_R_NCACHENXRRSET) { 2360 /* XXX: what about DNSSEC failure? */ 2361 goto out; 2362 } 2363 2364 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL; 2365 name = ISC_LIST_NEXT(name, link)) { 2366 for (rdataset = ISC_LIST_HEAD(name->list); 2367 rdataset != NULL; 2368 rdataset = ISC_LIST_NEXT(rdataset, link)) { 2369 if (dns_rdataset_isassociated(rdataset) && 2370 rdataset->type == dns_rdatatype_soa) 2371 break; 2372 } 2373 } 2374 2375 if (rdataset == NULL) { 2376 /* Drop one label and retry resolution. */ 2377 nlabels = dns_name_countlabels(&uctx->soaqname); 2378 if (nlabels == 1) { 2379 result = DNS_R_SERVFAIL; /* is there a better error? */ 2380 goto out; 2381 } 2382 dns_name_init(&tname, NULL); 2383 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1, 2384 &tname); 2385 dns_name_clone(&tname, &uctx->soaqname); 2386 2387 result = dns_client_startresolve(uctx->client, &uctx->soaqname, 2388 uctx->rdclass, 2389 dns_rdatatype_soa, 0, 2390 uctx->client->task, 2391 resolvesoa_done, uctx, 2392 &uctx->restrans); 2393 } else 2394 result = process_soa(uctx, rdataset, &uctx->soaqname); 2395 2396 out: 2397 dns_client_freeresanswer(uctx->client, &rev->answerlist); 2398 isc_event_free(&event); 2399 2400 if (result != ISC_R_SUCCESS) 2401 update_sendevent(uctx, result); 2402} 2403 2404static isc_result_t 2405copy_name(isc_mem_t *mctx, dns_message_t *msg, dns_name_t *name, 2406 dns_name_t **newnamep) 2407{ 2408 isc_result_t result; 2409 dns_name_t *newname = NULL; 2410 isc_region_t r; 2411 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL; 2412 dns_rdatalist_t *rdatalist; 2413 dns_rdataset_t *rdataset, *newrdataset; 2414 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata; 2415 2416 result = dns_message_gettempname(msg, &newname); 2417 if (result != ISC_R_SUCCESS) 2418 return (result); 2419 result = isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE); 2420 if (result != ISC_R_SUCCESS) 2421 goto fail; 2422 dns_name_init(newname, NULL); 2423 dns_name_setbuffer(newname, namebuf); 2424 dns_message_takebuffer(msg, &namebuf); 2425 result = dns_name_copy(name, newname, NULL); 2426 if (result != ISC_R_SUCCESS) 2427 goto fail; 2428 2429 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 2430 rdataset = ISC_LIST_NEXT(rdataset, link)) { 2431 rdatalist = NULL; 2432 result = dns_message_gettemprdatalist(msg, &rdatalist); 2433 if (result != ISC_R_SUCCESS) 2434 goto fail; 2435 dns_rdatalist_init(rdatalist); 2436 rdatalist->type = rdataset->type; 2437 rdatalist->rdclass = rdataset->rdclass; 2438 rdatalist->covers = rdataset->covers; 2439 rdatalist->ttl = rdataset->ttl; 2440 2441 result = dns_rdataset_first(rdataset); 2442 while (result == ISC_R_SUCCESS) { 2443 dns_rdata_reset(&rdata); 2444 dns_rdataset_current(rdataset, &rdata); 2445 2446 newrdata = NULL; 2447 result = dns_message_gettemprdata(msg, &newrdata); 2448 if (result != ISC_R_SUCCESS) 2449 goto fail; 2450 dns_rdata_toregion(&rdata, &r); 2451 rdatabuf = NULL; 2452 result = isc_buffer_allocate(mctx, &rdatabuf, 2453 r.length); 2454 if (result != ISC_R_SUCCESS) 2455 goto fail; 2456 isc_buffer_putmem(rdatabuf, r.base, r.length); 2457 isc_buffer_usedregion(rdatabuf, &r); 2458 dns_rdata_init(newrdata); 2459 dns_rdata_fromregion(newrdata, rdata.rdclass, 2460 rdata.type, &r); 2461 newrdata->flags = rdata.flags; 2462 2463 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link); 2464 dns_message_takebuffer(msg, &rdatabuf); 2465 2466 result = dns_rdataset_next(rdataset); 2467 } 2468 2469 newrdataset = NULL; 2470 result = dns_message_gettemprdataset(msg, &newrdataset); 2471 if (result != ISC_R_SUCCESS) 2472 goto fail; 2473 dns_rdataset_init(newrdataset); 2474 dns_rdatalist_tordataset(rdatalist, newrdataset); 2475 2476 ISC_LIST_APPEND(newname->list, newrdataset, link); 2477 } 2478 2479 *newnamep = newname; 2480 2481 return (ISC_R_SUCCESS); 2482 2483 fail: 2484 dns_message_puttempname(msg, &newname); 2485 2486 return (result); 2487 2488} 2489 2490static void 2491internal_update_callback(isc_task_t *task, isc_event_t *event) { 2492 updatearg_t *uarg = event->ev_arg; 2493 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event; 2494 2495 UNUSED(task); 2496 2497 LOCK(&uarg->lock); 2498 2499 uarg->result = uev->result; 2500 2501 dns_client_destroyupdatetrans(&uarg->trans); 2502 isc_event_free(&event); 2503 2504 if (!uarg->canceled) { 2505 UNLOCK(&uarg->lock); 2506 2507 /* Exit from the internal event loop */ 2508 isc_app_ctxsuspend(uarg->actx); 2509 } else { 2510 /* 2511 * We have already exited from the loop (due to some 2512 * unexpected event). Just clean the arg up. 2513 */ 2514 UNLOCK(&uarg->lock); 2515 DESTROYLOCK(&uarg->lock); 2516 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg)); 2517 } 2518} 2519 2520isc_result_t 2521dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass, 2522 dns_name_t *zonename, dns_namelist_t *prerequisites, 2523 dns_namelist_t *updates, isc_sockaddrlist_t *servers, 2524 dns_tsec_t *tsec, unsigned int options) 2525{ 2526 isc_result_t result; 2527 isc_appctx_t *actx; 2528 updatearg_t *uarg; 2529 2530 REQUIRE(DNS_CLIENT_VALID(client)); 2531 2532 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 && 2533 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0) { 2534 /* 2535 * If the client is run under application's control, we need 2536 * to create a new running (sub)environment for this 2537 * particular resolution. 2538 */ 2539 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */ 2540 } else 2541 actx = client->actx; 2542 2543 uarg = isc_mem_get(client->mctx, sizeof(*uarg)); 2544 if (uarg == NULL) 2545 return (ISC_R_NOMEMORY); 2546 2547 result = isc_mutex_init(&uarg->lock); 2548 if (result != ISC_R_SUCCESS) { 2549 isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2550 return (result); 2551 } 2552 2553 uarg->actx = actx; 2554 uarg->client = client; 2555 uarg->result = ISC_R_FAILURE; 2556 uarg->trans = NULL; 2557 uarg->canceled = ISC_FALSE; 2558 2559 result = dns_client_startupdate(client, rdclass, zonename, 2560 prerequisites, updates, servers, 2561 tsec, options, client->task, 2562 internal_update_callback, uarg, 2563 &uarg->trans); 2564 if (result != ISC_R_SUCCESS) { 2565 DESTROYLOCK(&uarg->lock); 2566 isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2567 return (result); 2568 } 2569 2570 /* 2571 * Start internal event loop. It blocks until the entire process 2572 * is completed. 2573 */ 2574 result = isc_app_ctxrun(actx); 2575 2576 LOCK(&uarg->lock); 2577 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) 2578 result = uarg->result; 2579 2580 if (uarg->trans != NULL) { 2581 /* 2582 * Unusual termination (perhaps due to signal). We need some 2583 * tricky cleanup process. 2584 */ 2585 uarg->canceled = ISC_TRUE; 2586 dns_client_cancelupdate(uarg->trans); 2587 2588 UNLOCK(&uarg->lock); 2589 2590 /* uarg will be freed in the event handler. */ 2591 } else { 2592 UNLOCK(&uarg->lock); 2593 2594 DESTROYLOCK(&uarg->lock); 2595 isc_mem_put(client->mctx, uarg, sizeof(*uarg)); 2596 } 2597 2598 return (result); 2599} 2600 2601isc_result_t 2602dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass, 2603 dns_name_t *zonename, dns_namelist_t *prerequisites, 2604 dns_namelist_t *updates, isc_sockaddrlist_t *servers, 2605 dns_tsec_t *tsec, unsigned int options, 2606 isc_task_t *task, isc_taskaction_t action, void *arg, 2607 dns_clientupdatetrans_t **transp) 2608{ 2609 dns_view_t *view = NULL; 2610 isc_result_t result; 2611 dns_name_t *name, *newname; 2612 updatectx_t *uctx; 2613 isc_task_t *clone = NULL; 2614 dns_section_t section = DNS_SECTION_UPDATE; 2615 isc_sockaddr_t *server, *sa = NULL; 2616 dns_tsectype_t tsectype = dns_tsectype_none; 2617 2618 UNUSED(options); 2619 2620 REQUIRE(DNS_CLIENT_VALID(client)); 2621 REQUIRE(transp != NULL && *transp == NULL); 2622 REQUIRE(updates != NULL); 2623 REQUIRE(task != NULL); 2624 2625 if (tsec != NULL) { 2626 tsectype = dns_tsec_gettype(tsec); 2627 if (tsectype != dns_tsectype_tsig) 2628 return (ISC_R_NOTIMPLEMENTED); /* XXX */ 2629 } 2630 2631 LOCK(&client->lock); 2632 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME, 2633 rdclass, &view); 2634 UNLOCK(&client->lock); 2635 if (result != ISC_R_SUCCESS) 2636 return (result); 2637 2638 /* Create a context and prepare some resources */ 2639 uctx = isc_mem_get(client->mctx, sizeof(*uctx)); 2640 if (uctx == NULL) { 2641 dns_view_detach(&view); 2642 return (ISC_R_NOMEMORY); 2643 } 2644 result = isc_mutex_init(&uctx->lock); 2645 if (result != ISC_R_SUCCESS) { 2646 dns_view_detach(&view); 2647 isc_mem_put(client->mctx, uctx, sizeof(*uctx)); 2648 return (ISC_R_NOMEMORY); 2649 } 2650 clone = NULL; 2651 isc_task_attach(task, &clone); 2652 uctx->client = client; 2653 ISC_LINK_INIT(uctx, link); 2654 uctx->state = dns_clientupdatestate_prepare; 2655 uctx->view = view; 2656 uctx->rdclass = rdclass; 2657 uctx->canceled = ISC_FALSE; 2658 uctx->updatemsg = NULL; 2659 uctx->soaquery = NULL; 2660 uctx->updatereq = NULL; 2661 uctx->restrans = NULL; 2662 uctx->restrans2 = NULL; 2663 uctx->bp4 = NULL; 2664 uctx->bp6 = NULL; 2665 uctx->soareq = NULL; 2666 uctx->event = NULL; 2667 uctx->tsigkey = NULL; 2668 uctx->sig0key = NULL; 2669 uctx->zonename = NULL; 2670 dns_name_init(&uctx->soaqname, NULL); 2671 ISC_LIST_INIT(uctx->servers); 2672 uctx->nservers = 0; 2673 uctx->currentserver = NULL; 2674 dns_fixedname_init(&uctx->zonefname); 2675 if (tsec != NULL) 2676 dns_tsec_getkey(tsec, &uctx->tsigkey); 2677 uctx->event = (dns_clientupdateevent_t *) 2678 isc_event_allocate(client->mctx, clone, DNS_EVENT_UPDATEDONE, 2679 action, arg, sizeof(*uctx->event)); 2680 if (uctx->event == NULL) 2681 goto fail; 2682 if (zonename != NULL) { 2683 uctx->zonename = dns_fixedname_name(&uctx->zonefname); 2684 result = dns_name_copy(zonename, uctx->zonename, NULL); 2685 } 2686 if (servers != NULL) { 2687 for (server = ISC_LIST_HEAD(*servers); 2688 server != NULL; 2689 server = ISC_LIST_NEXT(server, link)) { 2690 sa = isc_mem_get(client->mctx, sizeof(*sa)); 2691 if (sa == NULL) 2692 goto fail; 2693 sa->type = server->type; 2694 sa->length = server->length; 2695 ISC_LINK_INIT(sa, link); 2696 ISC_LIST_APPEND(uctx->servers, sa, link); 2697 if (uctx->currentserver == NULL) 2698 uctx->currentserver = sa; 2699 uctx->nservers++; 2700 } 2701 } 2702 2703 /* Make update message */ 2704 result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER, 2705 &uctx->updatemsg); 2706 if (result != ISC_R_SUCCESS) 2707 goto fail; 2708 uctx->updatemsg->opcode = dns_opcode_update; 2709 2710 if (prerequisites != NULL) { 2711 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL; 2712 name = ISC_LIST_NEXT(name, link)) { 2713 newname = NULL; 2714 result = copy_name(client->mctx, uctx->updatemsg, 2715 name, &newname); 2716 if (result != ISC_R_SUCCESS) 2717 goto fail; 2718 dns_message_addname(uctx->updatemsg, newname, 2719 DNS_SECTION_PREREQUISITE); 2720 } 2721 } 2722 2723 for (name = ISC_LIST_HEAD(*updates); name != NULL; 2724 name = ISC_LIST_NEXT(name, link)) { 2725 newname = NULL; 2726 result = copy_name(client->mctx, uctx->updatemsg, name, 2727 &newname); 2728 if (result != ISC_R_SUCCESS) 2729 goto fail; 2730 dns_message_addname(uctx->updatemsg, newname, 2731 DNS_SECTION_UPDATE); 2732 } 2733 2734 uctx->firstname = NULL; 2735 result = dns_message_firstname(uctx->updatemsg, section); 2736 if (result == ISC_R_NOMORE) { 2737 section = DNS_SECTION_PREREQUISITE; 2738 result = dns_message_firstname(uctx->updatemsg, section); 2739 } 2740 if (result != ISC_R_SUCCESS) 2741 goto fail; 2742 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname); 2743 2744 uctx->magic = UCTX_MAGIC; 2745 2746 LOCK(&client->lock); 2747 ISC_LIST_APPEND(client->updatectxs, uctx, link); 2748 UNLOCK(&client->lock); 2749 2750 if (uctx->zonename != NULL && uctx->currentserver != NULL) { 2751 result = send_update(uctx); 2752 if (result != ISC_R_SUCCESS) 2753 goto fail; 2754 } else if (uctx->currentserver != NULL) { 2755 result = request_soa(uctx); 2756 if (result != ISC_R_SUCCESS) 2757 goto fail; 2758 } else { 2759 dns_name_clone(uctx->firstname, &uctx->soaqname); 2760 result = dns_client_startresolve(uctx->client, &uctx->soaqname, 2761 uctx->rdclass, 2762 dns_rdatatype_soa, 0, 2763 client->task, resolvesoa_done, 2764 uctx, &uctx->restrans); 2765 if (result != ISC_R_SUCCESS) 2766 goto fail; 2767 } 2768 2769 *transp = (dns_clientupdatetrans_t *)uctx; 2770 2771 return (ISC_R_SUCCESS); 2772 2773 fail: 2774 if (ISC_LINK_LINKED(uctx, link)) { 2775 LOCK(&client->lock); 2776 ISC_LIST_UNLINK(client->updatectxs, uctx, link); 2777 UNLOCK(&client->lock); 2778 } 2779 if (uctx->updatemsg != NULL) 2780 dns_message_destroy(&uctx->updatemsg); 2781 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { 2782 ISC_LIST_UNLINK(uctx->servers, sa, link); 2783 isc_mem_put(client->mctx, sa, sizeof(*sa)); 2784 } 2785 if (uctx->event != NULL) 2786 isc_event_free(ISC_EVENT_PTR(&uctx->event)); 2787 if (uctx->tsigkey != NULL) 2788 dns_tsigkey_detach(&uctx->tsigkey); 2789 isc_task_detach(&clone); 2790 DESTROYLOCK(&uctx->lock); 2791 uctx->magic = 0; 2792 isc_mem_put(client->mctx, uctx, sizeof(*uctx)); 2793 dns_view_detach(&view); 2794 2795 return (result); 2796} 2797 2798void 2799dns_client_cancelupdate(dns_clientupdatetrans_t *trans) { 2800 updatectx_t *uctx; 2801 2802 REQUIRE(trans != NULL); 2803 uctx = (updatectx_t *)trans; 2804 REQUIRE(UCTX_VALID(uctx)); 2805 2806 LOCK(&uctx->lock); 2807 2808 if (!uctx->canceled) { 2809 uctx->canceled = ISC_TRUE; 2810 if (uctx->updatereq != NULL) 2811 dns_request_cancel(uctx->updatereq); 2812 if (uctx->soareq != NULL) 2813 dns_request_cancel(uctx->soareq); 2814 if (uctx->restrans != NULL) 2815 dns_client_cancelresolve(uctx->restrans); 2816 if (uctx->restrans2 != NULL) 2817 dns_client_cancelresolve(uctx->restrans2); 2818 } 2819 2820 UNLOCK(&uctx->lock); 2821} 2822 2823void 2824dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) { 2825 updatectx_t *uctx; 2826 isc_mem_t *mctx; 2827 dns_client_t *client; 2828 isc_boolean_t need_destroyclient = ISC_FALSE; 2829 isc_sockaddr_t *sa; 2830 2831 REQUIRE(transp != NULL); 2832 uctx = (updatectx_t *)*transp; 2833 REQUIRE(UCTX_VALID(uctx)); 2834 client = uctx->client; 2835 REQUIRE(DNS_CLIENT_VALID(client)); 2836 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL && 2837 uctx->soareq == NULL && uctx->soaquery == NULL && 2838 uctx->event == NULL && uctx->tsigkey == NULL && 2839 uctx->sig0key == NULL); 2840 2841 mctx = client->mctx; 2842 dns_view_detach(&uctx->view); 2843 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) { 2844 ISC_LIST_UNLINK(uctx->servers, sa, link); 2845 isc_mem_put(mctx, sa, sizeof(*sa)); 2846 } 2847 2848 LOCK(&client->lock); 2849 2850 INSIST(ISC_LINK_LINKED(uctx, link)); 2851 ISC_LIST_UNLINK(client->updatectxs, uctx, link); 2852 2853 if (client->references == 0 && ISC_LIST_EMPTY(client->resctxs) && 2854 ISC_LIST_EMPTY(client->reqctxs) && 2855 ISC_LIST_EMPTY(client->updatectxs)) 2856 need_destroyclient = ISC_TRUE; 2857 2858 UNLOCK(&client->lock); 2859 2860 DESTROYLOCK(&uctx->lock); 2861 uctx->magic = 0; 2862 2863 isc_mem_put(mctx, uctx, sizeof(*uctx)); 2864 2865 if (need_destroyclient) 2866 destroyclient(&client); 2867 2868 *transp = NULL; 2869} 2870 2871isc_mem_t * 2872dns_client_mctx(dns_client_t *client) { 2873 2874 REQUIRE(DNS_CLIENT_VALID(client)); 2875 return (client->mctx); 2876} 2877 2878typedef struct { 2879 isc_buffer_t buffer; 2880 dns_rdataset_t rdataset; 2881 dns_rdatalist_t rdatalist; 2882 dns_rdata_t rdata; 2883 size_t size; 2884 isc_mem_t * mctx; 2885 unsigned char data[FLEXIBLE_ARRAY_MEMBER]; 2886} dns_client_updaterec_t; 2887 2888isc_result_t 2889dns_client_updaterec(dns_client_updateop_t op, dns_name_t *owner, 2890 dns_rdatatype_t type, dns_rdata_t *source, 2891 dns_ttl_t ttl, dns_name_t *target, 2892 dns_rdataset_t *rdataset, dns_rdatalist_t *rdatalist, 2893 dns_rdata_t *rdata, isc_mem_t *mctx) 2894{ 2895 dns_client_updaterec_t *updaterec = NULL; 2896 size_t size = offsetof(dns_client_updaterec_t, data); 2897 2898 REQUIRE(op < updateop_max); 2899 REQUIRE(owner != NULL); 2900 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) || 2901 (rdataset == NULL && rdatalist == NULL && rdata == NULL && 2902 mctx != NULL)); 2903 if (op == updateop_add) 2904 REQUIRE(source != NULL); 2905 if (source != NULL) { 2906 REQUIRE(source->type == type); 2907 REQUIRE(op == updateop_add || op == updateop_delete || 2908 op == updateop_exist); 2909 } 2910 2911 size += owner->length; 2912 if (source != NULL) 2913 size += source->length; 2914 2915 if (rdataset == NULL) { 2916 updaterec = isc_mem_get(mctx, size); 2917 if (updaterec == NULL) 2918 return (ISC_R_NOMEMORY); 2919 rdataset = &updaterec->rdataset; 2920 rdatalist = &updaterec->rdatalist; 2921 rdata = &updaterec->rdata; 2922 dns_rdataset_init(rdataset); 2923 dns_rdatalist_init(&updaterec->rdatalist); 2924 dns_rdata_init(&updaterec->rdata); 2925 isc_buffer_init(&updaterec->buffer, updaterec->data, 2926 size - offsetof(dns_client_updaterec_t, data)); 2927 dns_name_copy(owner, target, &updaterec->buffer); 2928 if (source != NULL) { 2929 isc_region_t r; 2930 dns_rdata_clone(source, rdata); 2931 dns_rdata_toregion(rdata, &r); 2932 rdata->data = isc_buffer_used(&updaterec->buffer); 2933 isc_buffer_copyregion(&updaterec->buffer, &r); 2934 } 2935 updaterec->mctx = NULL; 2936 isc_mem_attach(mctx, &updaterec->mctx); 2937 } else if (source != NULL) 2938 dns_rdata_clone(source, rdata); 2939 2940 switch (op) { 2941 case updateop_add: 2942 break; 2943 case updateop_delete: 2944 if (source != NULL) { 2945 ttl = 0; 2946 dns_rdata_makedelete(rdata); 2947 } else 2948 dns_rdata_deleterrset(rdata, type); 2949 break; 2950 case updateop_notexist: 2951 dns_rdata_notexist(rdata, type); 2952 break; 2953 case updateop_exist: 2954 if (source == NULL) { 2955 ttl = 0; 2956 dns_rdata_exists(rdata, type); 2957 } 2958 case updateop_none: 2959 break; 2960 default: 2961 INSIST(0); 2962 } 2963 2964 rdatalist->type = rdata->type; 2965 rdatalist->rdclass = rdata->rdclass; 2966 if (source != NULL) { 2967 rdatalist->covers = dns_rdata_covers(rdata); 2968 rdatalist->ttl = ttl; 2969 } 2970 ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 2971 dns_rdatalist_tordataset(rdatalist, rdataset); 2972 ISC_LIST_APPEND(target->list, rdataset, link); 2973 if (updaterec != NULL) { 2974 target->attributes |= DNS_NAMEATTR_HASUPDATEREC; 2975 dns_name_setbuffer(target, &updaterec->buffer); 2976 } 2977 if (op == updateop_add || op == updateop_delete) 2978 target->attributes |= DNS_NAMEATTR_UPDATE; 2979 else 2980 target->attributes |= DNS_NAMEATTR_PREREQUISITE; 2981 return (ISC_R_SUCCESS); 2982} 2983 2984void 2985dns_client_freeupdate(dns_name_t **namep) { 2986 dns_client_updaterec_t *updaterec; 2987 dns_rdatalist_t *rdatalist; 2988 dns_rdataset_t *rdataset; 2989 dns_rdata_t *rdata; 2990 dns_name_t *name; 2991 2992 REQUIRE(namep != NULL && *namep != NULL); 2993 2994 name = *namep; 2995 for (rdataset = ISC_LIST_HEAD(name->list); 2996 rdataset != NULL; 2997 rdataset = ISC_LIST_HEAD(name->list)) { 2998 ISC_LIST_UNLINK(name->list, rdataset, link); 2999 rdatalist = NULL; 3000 dns_rdatalist_fromrdataset(rdataset, &rdatalist); 3001 if (rdatalist == NULL) { 3002 dns_rdataset_disassociate(rdataset); 3003 continue; 3004 } 3005 for (rdata = ISC_LIST_HEAD(rdatalist->rdata); 3006 rdata != NULL; 3007 rdata = ISC_LIST_HEAD(rdatalist->rdata)) 3008 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link); 3009 dns_rdataset_disassociate(rdataset); 3010 } 3011 3012 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) { 3013 updaterec = (dns_client_updaterec_t *)name->buffer; 3014 INSIST(updaterec != NULL); 3015 isc_mem_putanddetach(&updaterec->mctx, updaterec, 3016 updaterec->size); 3017 *namep = NULL; 3018 } 3019} 3020