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