update.c revision 135446
1/* 2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: update.c,v 1.88.2.5.2.23 2004/07/23 02:56:52 marka Exp $ */ 19 20#include <config.h> 21 22#include <isc/print.h> 23#include <isc/string.h> 24#include <isc/taskpool.h> 25#include <isc/util.h> 26 27#include <dns/db.h> 28#include <dns/dbiterator.h> 29#include <dns/diff.h> 30#include <dns/dnssec.h> 31#include <dns/events.h> 32#include <dns/fixedname.h> 33#include <dns/journal.h> 34#include <dns/message.h> 35#include <dns/nsec.h> 36#include <dns/rdataclass.h> 37#include <dns/rdataset.h> 38#include <dns/rdatasetiter.h> 39#include <dns/rdatatype.h> 40#include <dns/soa.h> 41#include <dns/ssu.h> 42#include <dns/view.h> 43#include <dns/zone.h> 44#include <dns/zt.h> 45 46#include <named/client.h> 47#include <named/log.h> 48#include <named/update.h> 49 50/* 51 * This module implements dynamic update as in RFC2136. 52 */ 53 54/* 55 XXX TODO: 56 - document strict minimality 57*/ 58 59/**************************************************************************/ 60 61/* 62 * Log level for tracing dynamic update protocol requests. 63 */ 64#define LOGLEVEL_PROTOCOL ISC_LOG_INFO 65 66/* 67 * Log level for low-level debug tracing. 68 */ 69#define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8) 70 71/* 72 * Check an operation for failure. These macros all assume that 73 * the function using them has a 'result' variable and a 'failure' 74 * label. 75 */ 76#define CHECK(op) \ 77 do { result = (op); \ 78 if (result != ISC_R_SUCCESS) goto failure; \ 79 } while (0) 80 81/* 82 * Fail unconditionally with result 'code', which must not 83 * be ISC_R_SUCCESS. The reason for failure presumably has 84 * been logged already. 85 * 86 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 87 * from complaining about "end-of-loop code not reached". 88 */ 89 90#define FAIL(code) \ 91 do { \ 92 result = (code); \ 93 if (result != ISC_R_SUCCESS) goto failure; \ 94 } while (0) 95 96/* 97 * Fail unconditionally and log as a client error. 98 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 99 * from complaining about "end-of-loop code not reached". 100 */ 101#define FAILC(code, msg) \ 102 do { \ 103 const char *_what = "failed"; \ 104 result = (code); \ 105 switch (result) { \ 106 case DNS_R_NXDOMAIN: \ 107 case DNS_R_YXDOMAIN: \ 108 case DNS_R_YXRRSET: \ 109 case DNS_R_NXRRSET: \ 110 _what = "unsuccessful"; \ 111 } \ 112 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 113 "update %s: %s (%s)", _what, \ 114 msg, isc_result_totext(result)); \ 115 if (result != ISC_R_SUCCESS) goto failure; \ 116 } while (0) 117 118#define FAILN(code, name, msg) \ 119 do { \ 120 const char *_what = "failed"; \ 121 result = (code); \ 122 switch (result) { \ 123 case DNS_R_NXDOMAIN: \ 124 case DNS_R_YXDOMAIN: \ 125 case DNS_R_YXRRSET: \ 126 case DNS_R_NXRRSET: \ 127 _what = "unsuccessful"; \ 128 } \ 129 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ 130 char _nbuf[DNS_NAME_FORMATSIZE]; \ 131 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 132 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 133 "update %s: %s: %s (%s)", _what, _nbuf, \ 134 msg, isc_result_totext(result)); \ 135 } \ 136 if (result != ISC_R_SUCCESS) goto failure; \ 137 } while (0) 138 139#define FAILNT(code, name, type, msg) \ 140 do { \ 141 const char *_what = "failed"; \ 142 result = (code); \ 143 switch (result) { \ 144 case DNS_R_NXDOMAIN: \ 145 case DNS_R_YXDOMAIN: \ 146 case DNS_R_YXRRSET: \ 147 case DNS_R_NXRRSET: \ 148 _what = "unsuccessful"; \ 149 } \ 150 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ 151 char _nbuf[DNS_NAME_FORMATSIZE]; \ 152 char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \ 153 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 154 dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \ 155 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 156 "update %s: %s/%s: %s (%s)", \ 157 _what, _nbuf, _tbuf, msg, \ 158 isc_result_totext(result)); \ 159 } \ 160 if (result != ISC_R_SUCCESS) goto failure; \ 161 } while (0) 162/* 163 * Fail unconditionally and log as a server error. 164 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 165 * from complaining about "end-of-loop code not reached". 166 */ 167#define FAILS(code, msg) \ 168 do { \ 169 result = (code); \ 170 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 171 "error: %s: %s", \ 172 msg, isc_result_totext(result)); \ 173 if (result != ISC_R_SUCCESS) goto failure; \ 174 } while (0) 175 176/**************************************************************************/ 177 178typedef struct rr rr_t; 179 180struct rr { 181 /* dns_name_t name; */ 182 isc_uint32_t ttl; 183 dns_rdata_t rdata; 184}; 185 186typedef struct update_event update_event_t; 187 188struct update_event { 189 ISC_EVENT_COMMON(update_event_t); 190 dns_zone_t *zone; 191 isc_result_t result; 192 dns_message_t *answer; 193}; 194 195/**************************************************************************/ 196/* 197 * Forward declarations. 198 */ 199 200static void update_action(isc_task_t *task, isc_event_t *event); 201static void updatedone_action(isc_task_t *task, isc_event_t *event); 202static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone); 203static void forward_done(isc_task_t *task, isc_event_t *event); 204 205/**************************************************************************/ 206 207static void 208update_log(ns_client_t *client, dns_zone_t *zone, 209 int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); 210 211static void 212update_log(ns_client_t *client, dns_zone_t *zone, 213 int level, const char *fmt, ...) 214{ 215 va_list ap; 216 char message[4096]; 217 char namebuf[DNS_NAME_FORMATSIZE]; 218 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 219 220 if (client == NULL || zone == NULL) 221 return; 222 223 if (isc_log_wouldlog(ns_g_lctx, level) == ISC_FALSE) 224 return; 225 226 dns_name_format(dns_zone_getorigin(zone), namebuf, 227 sizeof(namebuf)); 228 dns_rdataclass_format(dns_zone_getclass(zone), classbuf, 229 sizeof(classbuf)); 230 231 va_start(ap, fmt); 232 vsnprintf(message, sizeof(message), fmt, ap); 233 va_end(ap); 234 235 ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 236 level, "updating zone '%s/%s': %s", 237 namebuf, classbuf, message); 238} 239 240static isc_result_t 241checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message, 242 dns_name_t *zonename, isc_boolean_t slave) 243{ 244 char namebuf[DNS_NAME_FORMATSIZE]; 245 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 246 int level = ISC_LOG_ERROR; 247 const char *msg = "denied"; 248 isc_result_t result; 249 250 if (slave && acl == NULL) { 251 result = DNS_R_NOTIMP; 252 level = ISC_LOG_DEBUG(3); 253 msg = "disabled"; 254 } else 255 result = ns_client_checkaclsilent(client, acl, ISC_FALSE); 256 257 if (result == ISC_R_SUCCESS) { 258 level = ISC_LOG_DEBUG(3); 259 msg = "approved"; 260 } 261 262 dns_name_format(zonename, namebuf, sizeof(namebuf)); 263 dns_rdataclass_format(client->view->rdclass, classbuf, 264 sizeof(classbuf)); 265 266 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 267 NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s", 268 message, namebuf, classbuf, msg); 269 return (result); 270} 271 272/* 273 * Update a single RR in version 'ver' of 'db' and log the 274 * update in 'diff'. 275 * 276 * Ensures: 277 * '*tuple' == NULL. Either the tuple is freed, or its 278 * ownership has been transferred to the diff. 279 */ 280static isc_result_t 281do_one_tuple(dns_difftuple_t **tuple, 282 dns_db_t *db, dns_dbversion_t *ver, 283 dns_diff_t *diff) 284{ 285 dns_diff_t temp_diff; 286 isc_result_t result; 287 288 /* 289 * Create a singleton diff. 290 */ 291 dns_diff_init(diff->mctx, &temp_diff); 292 ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); 293 294 /* 295 * Apply it to the database. 296 */ 297 result = dns_diff_apply(&temp_diff, db, ver); 298 ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); 299 if (result != ISC_R_SUCCESS) { 300 dns_difftuple_free(tuple); 301 return (result); 302 } 303 304 /* 305 * Merge it into the current pending journal entry. 306 */ 307 dns_diff_appendminimal(diff, tuple); 308 309 /* 310 * Do not clear temp_diff. 311 */ 312 return (ISC_R_SUCCESS); 313} 314 315/* 316 * Perform the updates in 'updates' in version 'ver' of 'db' and log the 317 * update in 'diff'. 318 * 319 * Ensures: 320 * 'updates' is empty. 321 */ 322static isc_result_t 323do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver, 324 dns_diff_t *diff) 325{ 326 isc_result_t result; 327 while (! ISC_LIST_EMPTY(updates->tuples)) { 328 dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples); 329 ISC_LIST_UNLINK(updates->tuples, t, link); 330 CHECK(do_one_tuple(&t, db, ver, diff)); 331 } 332 return (ISC_R_SUCCESS); 333 334 failure: 335 dns_diff_clear(diff); 336 return (result); 337} 338 339static isc_result_t 340update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, 341 dns_diffop_t op, dns_name_t *name, 342 dns_ttl_t ttl, dns_rdata_t *rdata) 343{ 344 dns_difftuple_t *tuple = NULL; 345 isc_result_t result; 346 result = dns_difftuple_create(diff->mctx, op, 347 name, ttl, rdata, &tuple); 348 if (result != ISC_R_SUCCESS) 349 return (result); 350 return (do_one_tuple(&tuple, db, ver, diff)); 351} 352 353/**************************************************************************/ 354/* 355 * Callback-style iteration over rdatasets and rdatas. 356 * 357 * foreach_rrset() can be used to iterate over the RRsets 358 * of a name and call a callback function with each 359 * one. Similarly, foreach_rr() can be used to iterate 360 * over the individual RRs at name, optionally restricted 361 * to RRs of a given type. 362 * 363 * The callback functions are called "actions" and take 364 * two arguments: a void pointer for passing arbitrary 365 * context information, and a pointer to the current RRset 366 * or RR. By convention, their names end in "_action". 367 */ 368 369/* 370 * XXXRTH We might want to make this public somewhere in libdns. 371 */ 372 373/* 374 * Function type for foreach_rrset() iterator actions. 375 */ 376typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset); 377 378/* 379 * Function type for foreach_rr() iterator actions. 380 */ 381typedef isc_result_t rr_func(void *data, rr_t *rr); 382 383/* 384 * Internal context struct for foreach_node_rr(). 385 */ 386typedef struct { 387 rr_func * rr_action; 388 void * rr_action_data; 389} foreach_node_rr_ctx_t; 390 391/* 392 * Internal helper function for foreach_node_rr(). 393 */ 394static isc_result_t 395foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) { 396 isc_result_t result; 397 foreach_node_rr_ctx_t *ctx = data; 398 for (result = dns_rdataset_first(rdataset); 399 result == ISC_R_SUCCESS; 400 result = dns_rdataset_next(rdataset)) 401 { 402 rr_t rr = { 0, DNS_RDATA_INIT }; 403 404 dns_rdataset_current(rdataset, &rr.rdata); 405 rr.ttl = rdataset->ttl; 406 result = (*ctx->rr_action)(ctx->rr_action_data, &rr); 407 if (result != ISC_R_SUCCESS) 408 return (result); 409 } 410 if (result != ISC_R_NOMORE) 411 return (result); 412 return (ISC_R_SUCCESS); 413} 414 415/* 416 * For each rdataset of 'name' in 'ver' of 'db', call 'action' 417 * with the rdataset and 'action_data' as arguments. If the name 418 * does not exist, do nothing. 419 * 420 * If 'action' returns an error, abort iteration and return the error. 421 */ 422static isc_result_t 423foreach_rrset(dns_db_t *db, 424 dns_dbversion_t *ver, 425 dns_name_t *name, 426 rrset_func *action, 427 void *action_data) 428{ 429 isc_result_t result; 430 dns_dbnode_t *node; 431 dns_rdatasetiter_t *iter; 432 433 node = NULL; 434 result = dns_db_findnode(db, name, ISC_FALSE, &node); 435 if (result == ISC_R_NOTFOUND) 436 return (ISC_R_SUCCESS); 437 if (result != ISC_R_SUCCESS) 438 return (result); 439 440 iter = NULL; 441 result = dns_db_allrdatasets(db, node, ver, 442 (isc_stdtime_t) 0, &iter); 443 if (result != ISC_R_SUCCESS) 444 goto cleanup_node; 445 446 for (result = dns_rdatasetiter_first(iter); 447 result == ISC_R_SUCCESS; 448 result = dns_rdatasetiter_next(iter)) 449 { 450 dns_rdataset_t rdataset; 451 452 dns_rdataset_init(&rdataset); 453 dns_rdatasetiter_current(iter, &rdataset); 454 455 result = (*action)(action_data, &rdataset); 456 457 dns_rdataset_disassociate(&rdataset); 458 if (result != ISC_R_SUCCESS) 459 goto cleanup_iterator; 460 } 461 if (result == ISC_R_NOMORE) 462 result = ISC_R_SUCCESS; 463 464 cleanup_iterator: 465 dns_rdatasetiter_destroy(&iter); 466 467 cleanup_node: 468 dns_db_detachnode(db, &node); 469 470 return (result); 471} 472 473/* 474 * For each RR of 'name' in 'ver' of 'db', call 'action' 475 * with the RR and 'action_data' as arguments. If the name 476 * does not exist, do nothing. 477 * 478 * If 'action' returns an error, abort iteration 479 * and return the error. 480 */ 481static isc_result_t 482foreach_node_rr(dns_db_t *db, 483 dns_dbversion_t *ver, 484 dns_name_t *name, 485 rr_func *rr_action, 486 void *rr_action_data) 487{ 488 foreach_node_rr_ctx_t ctx; 489 ctx.rr_action = rr_action; 490 ctx.rr_action_data = rr_action_data; 491 return (foreach_rrset(db, ver, name, 492 foreach_node_rr_action, &ctx)); 493} 494 495 496/* 497 * For each of the RRs specified by 'db', 'ver', 'name', 'type', 498 * (which can be dns_rdatatype_any to match any type), and 'covers', call 499 * 'action' with the RR and 'action_data' as arguments. If the name 500 * does not exist, or if no RRset of the given type exists at the name, 501 * do nothing. 502 * 503 * If 'action' returns an error, abort iteration and return the error. 504 */ 505static isc_result_t 506foreach_rr(dns_db_t *db, 507 dns_dbversion_t *ver, 508 dns_name_t *name, 509 dns_rdatatype_t type, 510 dns_rdatatype_t covers, 511 rr_func *rr_action, 512 void *rr_action_data) 513{ 514 515 isc_result_t result; 516 dns_dbnode_t *node; 517 dns_rdataset_t rdataset; 518 519 if (type == dns_rdatatype_any) 520 return (foreach_node_rr(db, ver, name, 521 rr_action, rr_action_data)); 522 523 node = NULL; 524 result = dns_db_findnode(db, name, ISC_FALSE, &node); 525 if (result == ISC_R_NOTFOUND) 526 return (ISC_R_SUCCESS); 527 if (result != ISC_R_SUCCESS) 528 return (result); 529 530 dns_rdataset_init(&rdataset); 531 result = dns_db_findrdataset(db, node, ver, type, covers, 532 (isc_stdtime_t) 0, &rdataset, NULL); 533 if (result == ISC_R_NOTFOUND) { 534 result = ISC_R_SUCCESS; 535 goto cleanup_node; 536 } 537 if (result != ISC_R_SUCCESS) 538 goto cleanup_node; 539 540 for (result = dns_rdataset_first(&rdataset); 541 result == ISC_R_SUCCESS; 542 result = dns_rdataset_next(&rdataset)) 543 { 544 rr_t rr = { 0, DNS_RDATA_INIT }; 545 dns_rdataset_current(&rdataset, &rr.rdata); 546 rr.ttl = rdataset.ttl; 547 result = (*rr_action)(rr_action_data, &rr); 548 if (result != ISC_R_SUCCESS) 549 goto cleanup_rdataset; 550 } 551 if (result != ISC_R_NOMORE) 552 goto cleanup_rdataset; 553 result = ISC_R_SUCCESS; 554 555 cleanup_rdataset: 556 dns_rdataset_disassociate(&rdataset); 557 cleanup_node: 558 dns_db_detachnode(db, &node); 559 560 return (result); 561} 562 563/**************************************************************************/ 564/* 565 * Various tests on the database contents (for prerequisites, etc). 566 */ 567 568/* 569 * Function type for predicate functions that compare a database RR 'db_rr' 570 * against an update RR 'update_rr'. 571 */ 572typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr); 573 574/* 575 * Helper function for rrset_exists(). 576 */ 577static isc_result_t 578rrset_exists_action(void *data, rr_t *rr) { 579 UNUSED(data); 580 UNUSED(rr); 581 return (ISC_R_EXISTS); 582} 583 584/* 585 * Utility macro for RR existence checking functions. 586 * 587 * If the variable 'result' has the value ISC_R_EXISTS or 588 * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE, 589 * respectively, and return success. 590 * 591 * If 'result' has any other value, there was a failure. 592 * Return the failure result code and do not set *exists. 593 * 594 * This would be more readable as "do { if ... } while(0)", 595 * but that form generates tons of warnings on Solaris 2.6. 596 */ 597#define RETURN_EXISTENCE_FLAG \ 598 return ((result == ISC_R_EXISTS) ? \ 599 (*exists = ISC_TRUE, ISC_R_SUCCESS) : \ 600 ((result == ISC_R_SUCCESS) ? \ 601 (*exists = ISC_FALSE, ISC_R_SUCCESS) : \ 602 result)) 603 604/* 605 * Set '*exists' to true iff an rrset of the given type exists, 606 * to false otherwise. 607 */ 608static isc_result_t 609rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 610 dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, 611 isc_boolean_t *exists) 612{ 613 isc_result_t result; 614 result = foreach_rr(db, ver, name, type, covers, 615 rrset_exists_action, NULL); 616 RETURN_EXISTENCE_FLAG; 617} 618 619/* 620 * Helper function for cname_incompatible_rrset_exists. 621 */ 622static isc_result_t 623cname_compatibility_action(void *data, dns_rdataset_t *rrset) { 624 UNUSED(data); 625 if (rrset->type != dns_rdatatype_cname && 626 ! dns_rdatatype_isdnssec(rrset->type)) 627 return (ISC_R_EXISTS); 628 return (ISC_R_SUCCESS); 629} 630 631/* 632 * Check whether there is an rrset incompatible with adding a CNAME RR, 633 * i.e., anything but another CNAME (which can be replaced) or a 634 * DNSSEC RR (which can coexist). 635 * 636 * If such an incompatible rrset exists, set '*exists' to ISC_TRUE. 637 * Otherwise, set it to ISC_FALSE. 638 */ 639static isc_result_t 640cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 641 dns_name_t *name, isc_boolean_t *exists) { 642 isc_result_t result; 643 result = foreach_rrset(db, ver, name, 644 cname_compatibility_action, NULL); 645 RETURN_EXISTENCE_FLAG; 646} 647 648/* 649 * Helper function for rr_count(). 650 */ 651static isc_result_t 652count_rr_action(void *data, rr_t *rr) { 653 int *countp = data; 654 UNUSED(rr); 655 (*countp)++; 656 return (ISC_R_SUCCESS); 657} 658 659/* 660 * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'. 661 */ 662static isc_result_t 663rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 664 dns_rdatatype_t type, dns_rdatatype_t covers, int *countp) 665{ 666 *countp = 0; 667 return (foreach_rr(db, ver, name, type, covers, 668 count_rr_action, countp)); 669} 670 671/* 672 * Context struct and helper function for name_exists(). 673 */ 674 675static isc_result_t 676name_exists_action(void *data, dns_rdataset_t *rrset) { 677 UNUSED(data); 678 UNUSED(rrset); 679 return (ISC_R_EXISTS); 680} 681 682/* 683 * Set '*exists' to true iff the given name exists, to false otherwise. 684 */ 685static isc_result_t 686name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 687 isc_boolean_t *exists) 688{ 689 isc_result_t result; 690 result = foreach_rrset(db, ver, name, 691 name_exists_action, NULL); 692 RETURN_EXISTENCE_FLAG; 693} 694 695typedef struct { 696 dns_name_t *name, *signer; 697 dns_ssutable_t *table; 698} ssu_check_t; 699 700static isc_result_t 701ssu_checkrule(void *data, dns_rdataset_t *rrset) { 702 ssu_check_t *ssuinfo = data; 703 isc_boolean_t result; 704 705 /* 706 * If we're deleting all records, it's ok to delete RRSIG and NSEC even 707 * if we're normally not allowed to. 708 */ 709 if (rrset->type == dns_rdatatype_rrsig || 710 rrset->type == dns_rdatatype_nsec) 711 return (ISC_TRUE); 712 result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer, 713 ssuinfo->name, rrset->type); 714 return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE); 715} 716 717static isc_boolean_t 718ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 719 dns_ssutable_t *ssutable, dns_name_t *signer) 720{ 721 isc_result_t result; 722 ssu_check_t ssuinfo; 723 724 ssuinfo.name = name; 725 ssuinfo.table = ssutable; 726 ssuinfo.signer = signer; 727 result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); 728 return (ISC_TF(result == ISC_R_SUCCESS)); 729} 730 731/**************************************************************************/ 732/* 733 * Checking of "RRset exists (value dependent)" prerequisites. 734 * 735 * In the RFC2136 section 3.2.5, this is the pseudocode involving 736 * a variable called "temp", a mapping of <name, type> tuples to rrsets. 737 * 738 * Here, we represent the "temp" data structure as (non-minimial) "dns_diff_t" 739 * where each typle has op==DNS_DIFFOP_EXISTS. 740 */ 741 742 743/* 744 * Append a tuple asserting the existence of the RR with 745 * 'name' and 'rdata' to 'diff'. 746 */ 747static isc_result_t 748temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) { 749 isc_result_t result; 750 dns_difftuple_t *tuple = NULL; 751 752 REQUIRE(DNS_DIFF_VALID(diff)); 753 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, 754 name, 0, rdata, &tuple)); 755 ISC_LIST_APPEND(diff->tuples, tuple, link); 756 failure: 757 return (result); 758} 759 760/* 761 * Compare two rdatasets represented as sorted lists of tuples. 762 * All list elements must have the same owner name and type. 763 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset) 764 * if not. 765 */ 766static isc_result_t 767temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { 768 for (;;) { 769 if (a == NULL || b == NULL) 770 break; 771 INSIST(a->op == DNS_DIFFOP_EXISTS && 772 b->op == DNS_DIFFOP_EXISTS); 773 INSIST(a->rdata.type == b->rdata.type); 774 INSIST(dns_name_equal(&a->name, &b->name)); 775 if (dns_rdata_compare(&a->rdata, &b->rdata) != 0) 776 return (DNS_R_NXRRSET); 777 a = ISC_LIST_NEXT(a, link); 778 b = ISC_LIST_NEXT(b, link); 779 } 780 if (a != NULL || b != NULL) 781 return (DNS_R_NXRRSET); 782 return (ISC_R_SUCCESS); 783} 784 785/* 786 * A comparison function defining the sorting order for the entries 787 * in the "temp" data structure. The major sort key is the owner name, 788 * followed by the type and rdata. 789 */ 790static int 791temp_order(const void *av, const void *bv) { 792 dns_difftuple_t const * const *ap = av; 793 dns_difftuple_t const * const *bp = bv; 794 dns_difftuple_t const *a = *ap; 795 dns_difftuple_t const *b = *bp; 796 int r; 797 r = dns_name_compare(&a->name, &b->name); 798 if (r != 0) 799 return (r); 800 r = (b->rdata.type - a->rdata.type); 801 if (r != 0) 802 return (r); 803 r = dns_rdata_compare(&a->rdata, &b->rdata); 804 return (r); 805} 806 807/* 808 * Check the "RRset exists (value dependent)" prerequisite information 809 * in 'temp' against the contents of the database 'db'. 810 * 811 * Return ISC_R_SUCCESS if the prerequisites are satisfied, 812 * rcode(dns_rcode_nxrrset) if not. 813 * 814 * 'temp' must be pre-sorted. 815 */ 816 817static isc_result_t 818temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, 819 dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep) 820{ 821 isc_result_t result; 822 dns_name_t *name; 823 dns_dbnode_t *node; 824 dns_difftuple_t *t; 825 dns_diff_t trash; 826 827 dns_diff_init(mctx, &trash); 828 829 /* 830 * For each name and type in the prerequisites, 831 * construct a sorted rdata list of the corresponding 832 * database contents, and compare the lists. 833 */ 834 t = ISC_LIST_HEAD(temp->tuples); 835 while (t != NULL) { 836 name = &t->name; 837 (void)dns_name_copy(name, tmpname, NULL); 838 *typep = t->rdata.type; 839 840 /* A new unique name begins here. */ 841 node = NULL; 842 result = dns_db_findnode(db, name, ISC_FALSE, &node); 843 if (result == ISC_R_NOTFOUND) 844 return (DNS_R_NXRRSET); 845 if (result != ISC_R_SUCCESS) 846 return (result); 847 848 /* A new unique type begins here. */ 849 while (t != NULL && dns_name_equal(&t->name, name)) { 850 dns_rdatatype_t type, covers; 851 dns_rdataset_t rdataset; 852 dns_diff_t d_rrs; /* Database RRs with 853 this name and type */ 854 dns_diff_t u_rrs; /* Update RRs with 855 this name and type */ 856 857 *typep = type = t->rdata.type; 858 if (type == dns_rdatatype_rrsig || 859 type == dns_rdatatype_sig) 860 covers = dns_rdata_covers(&t->rdata); 861 else 862 covers = 0; 863 864 /* 865 * Collect all database RRs for this name and type 866 * onto d_rrs and sort them. 867 */ 868 dns_rdataset_init(&rdataset); 869 result = dns_db_findrdataset(db, node, ver, type, 870 covers, (isc_stdtime_t) 0, 871 &rdataset, NULL); 872 if (result != ISC_R_SUCCESS) { 873 dns_db_detachnode(db, &node); 874 return (DNS_R_NXRRSET); 875 } 876 877 dns_diff_init(mctx, &d_rrs); 878 dns_diff_init(mctx, &u_rrs); 879 880 for (result = dns_rdataset_first(&rdataset); 881 result == ISC_R_SUCCESS; 882 result = dns_rdataset_next(&rdataset)) 883 { 884 dns_rdata_t rdata = DNS_RDATA_INIT; 885 dns_rdataset_current(&rdataset, &rdata); 886 result = temp_append(&d_rrs, name, &rdata); 887 if (result != ISC_R_SUCCESS) 888 goto failure; 889 } 890 if (result != ISC_R_NOMORE) 891 goto failure; 892 result = dns_diff_sort(&d_rrs, temp_order); 893 if (result != ISC_R_SUCCESS) 894 goto failure; 895 896 /* 897 * Collect all update RRs for this name and type 898 * onto u_rrs. No need to sort them here - 899 * they are already sorted. 900 */ 901 while (t != NULL && 902 dns_name_equal(&t->name, name) && 903 t->rdata.type == type) 904 { 905 dns_difftuple_t *next = 906 ISC_LIST_NEXT(t, link); 907 ISC_LIST_UNLINK(temp->tuples, t, link); 908 ISC_LIST_APPEND(u_rrs.tuples, t, link); 909 t = next; 910 } 911 912 /* Compare the two sorted lists. */ 913 result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples), 914 ISC_LIST_HEAD(d_rrs.tuples)); 915 if (result != ISC_R_SUCCESS) 916 goto failure; 917 918 /* 919 * We are done with the tuples, but we can't free 920 * them yet because "name" still points into one 921 * of them. Move them on a temporary list. 922 */ 923 ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link); 924 ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link); 925 dns_rdataset_disassociate(&rdataset); 926 927 continue; 928 929 failure: 930 dns_diff_clear(&d_rrs); 931 dns_diff_clear(&u_rrs); 932 dns_diff_clear(&trash); 933 dns_rdataset_disassociate(&rdataset); 934 dns_db_detachnode(db, &node); 935 return (result); 936 } 937 938 dns_db_detachnode(db, &node); 939 } 940 941 dns_diff_clear(&trash); 942 return (ISC_R_SUCCESS); 943} 944 945/**************************************************************************/ 946/* 947 * Conditional deletion of RRs. 948 */ 949 950/* 951 * Context structure for delete_if(). 952 */ 953 954typedef struct { 955 rr_predicate *predicate; 956 dns_db_t *db; 957 dns_dbversion_t *ver; 958 dns_diff_t *diff; 959 dns_name_t *name; 960 dns_rdata_t *update_rr; 961} conditional_delete_ctx_t; 962 963/* 964 * Predicate functions for delete_if(). 965 */ 966 967/* 968 * Return true iff 'update_rr' is neither a SOA nor an NS RR. 969 */ 970static isc_boolean_t 971type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 972 UNUSED(update_rr); 973 return ((db_rr->type != dns_rdatatype_soa && 974 db_rr->type != dns_rdatatype_ns) ? 975 ISC_TRUE : ISC_FALSE); 976} 977 978/* 979 * Return true always. 980 */ 981static isc_boolean_t 982true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 983 UNUSED(update_rr); 984 UNUSED(db_rr); 985 return (ISC_TRUE); 986} 987 988/* 989 * Return true iff the two RRs have identical rdata. 990 */ 991static isc_boolean_t 992rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 993 /* 994 * XXXRTH This is not a problem, but we should consider creating 995 * dns_rdata_equal() (that used dns_name_equal()), since it 996 * would be faster. Not a priority. 997 */ 998 return (dns_rdata_compare(update_rr, db_rr) == 0 ? 999 ISC_TRUE : ISC_FALSE); 1000} 1001 1002/* 1003 * Return true iff 'update_rr' should replace 'db_rr' according 1004 * to the special RFC2136 rules for CNAME, SOA, and WKS records. 1005 * 1006 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs 1007 * make little sense, so we replace those, too. 1008 */ 1009static isc_boolean_t 1010replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1011 if (db_rr->type != update_rr->type) 1012 return (ISC_FALSE); 1013 if (db_rr->type == dns_rdatatype_cname) 1014 return (ISC_TRUE); 1015 if (db_rr->type == dns_rdatatype_dname) 1016 return (ISC_TRUE); 1017 if (db_rr->type == dns_rdatatype_soa) 1018 return (ISC_TRUE); 1019 if (db_rr->type == dns_rdatatype_nsec) 1020 return (ISC_TRUE); 1021 if (db_rr->type == dns_rdatatype_wks) { 1022 /* 1023 * Compare the address and protocol fields only. These 1024 * form the first five bytes of the RR data. Do a 1025 * raw binary comparison; unpacking the WKS RRs using 1026 * dns_rdata_tostruct() might be cleaner in some ways, 1027 * but it would require us to pass around an mctx. 1028 */ 1029 INSIST(db_rr->length >= 5 && update_rr->length >= 5); 1030 return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? 1031 ISC_TRUE : ISC_FALSE); 1032 } 1033 return (ISC_FALSE); 1034} 1035 1036/* 1037 * Internal helper function for delete_if(). 1038 */ 1039static isc_result_t 1040delete_if_action(void *data, rr_t *rr) { 1041 conditional_delete_ctx_t *ctx = data; 1042 if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) { 1043 isc_result_t result; 1044 result = update_one_rr(ctx->db, ctx->ver, ctx->diff, 1045 DNS_DIFFOP_DEL, ctx->name, 1046 rr->ttl, &rr->rdata); 1047 return (result); 1048 } else { 1049 return (ISC_R_SUCCESS); 1050 } 1051} 1052 1053/* 1054 * Conditionally delete RRs. Apply 'predicate' to the RRs 1055 * specified by 'db', 'ver', 'name', and 'type' (which can 1056 * be dns_rdatatype_any to match any type). Delete those 1057 * RRs for which the predicate returns true, and log the 1058 * deletions in 'diff'. 1059 */ 1060static isc_result_t 1061delete_if(rr_predicate *predicate, 1062 dns_db_t *db, 1063 dns_dbversion_t *ver, 1064 dns_name_t *name, 1065 dns_rdatatype_t type, 1066 dns_rdatatype_t covers, 1067 dns_rdata_t *update_rr, 1068 dns_diff_t *diff) 1069{ 1070 conditional_delete_ctx_t ctx; 1071 ctx.predicate = predicate; 1072 ctx.db = db; 1073 ctx.ver = ver; 1074 ctx.diff = diff; 1075 ctx.name = name; 1076 ctx.update_rr = update_rr; 1077 return (foreach_rr(db, ver, name, type, covers, 1078 delete_if_action, &ctx)); 1079} 1080 1081/**************************************************************************/ 1082/* 1083 * Prepare an RR for the addition of the new RR 'ctx->update_rr', 1084 * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting 1085 * the RRs if it is replaced by the new RR or has a conflicting TTL. 1086 * The necessary changes are appended to ctx->del_diff and ctx->add_diff; 1087 * we need to do all deletions before any additions so that we don't run 1088 * into transient states with conflicting TTLs. 1089 */ 1090 1091typedef struct { 1092 dns_db_t *db; 1093 dns_dbversion_t *ver; 1094 dns_diff_t *diff; 1095 dns_name_t *name; 1096 dns_rdata_t *update_rr; 1097 dns_ttl_t update_rr_ttl; 1098 isc_boolean_t ignore_add; 1099 dns_diff_t del_diff; 1100 dns_diff_t add_diff; 1101} add_rr_prepare_ctx_t; 1102 1103static isc_result_t 1104add_rr_prepare_action(void *data, rr_t *rr) { 1105 isc_result_t result = ISC_R_SUCCESS; 1106 add_rr_prepare_ctx_t *ctx = data; 1107 dns_difftuple_t *tuple = NULL; 1108 isc_boolean_t equal; 1109 1110 /* 1111 * If the update RR is a "duplicate" of the update RR, 1112 * the update should be silently ignored. 1113 */ 1114 equal = ISC_TF(dns_rdata_compare(&rr->rdata, ctx->update_rr) == 0); 1115 if (equal && rr->ttl == ctx->update_rr_ttl) { 1116 ctx->ignore_add = ISC_TRUE; 1117 return (ISC_R_SUCCESS); 1118 } 1119 1120 /* 1121 * If this RR is "equal" to the update RR, it should 1122 * be deleted before the update RR is added. 1123 */ 1124 if (replaces_p(ctx->update_rr, &rr->rdata)) { 1125 CHECK(dns_difftuple_create(ctx->del_diff.mctx, 1126 DNS_DIFFOP_DEL, ctx->name, 1127 rr->ttl, 1128 &rr->rdata, 1129 &tuple)); 1130 dns_diff_append(&ctx->del_diff, &tuple); 1131 return (ISC_R_SUCCESS); 1132 } 1133 1134 /* 1135 * If this RR differs in TTL from the update RR, 1136 * its TTL must be adjusted. 1137 */ 1138 if (rr->ttl != ctx->update_rr_ttl) { 1139 CHECK(dns_difftuple_create(ctx->del_diff.mctx, 1140 DNS_DIFFOP_DEL, ctx->name, 1141 rr->ttl, 1142 &rr->rdata, 1143 &tuple)); 1144 dns_diff_append(&ctx->del_diff, &tuple); 1145 if (!equal) { 1146 CHECK(dns_difftuple_create(ctx->add_diff.mctx, 1147 DNS_DIFFOP_ADD, ctx->name, 1148 ctx->update_rr_ttl, 1149 &rr->rdata, 1150 &tuple)); 1151 dns_diff_append(&ctx->add_diff, &tuple); 1152 } 1153 } 1154 failure: 1155 return (result); 1156} 1157 1158/**************************************************************************/ 1159/* 1160 * Miscellaneous subroutines. 1161 */ 1162 1163/* 1164 * Extract a single update RR from 'section' of dynamic update message 1165 * 'msg', with consistency checking. 1166 * 1167 * Stores the owner name, rdata, and TTL of the update RR at 'name', 1168 * 'rdata', and 'ttl', respectively. 1169 */ 1170static void 1171get_current_rr(dns_message_t *msg, dns_section_t section, 1172 dns_rdataclass_t zoneclass, 1173 dns_name_t **name, dns_rdata_t *rdata, dns_rdatatype_t *covers, 1174 dns_ttl_t *ttl, 1175 dns_rdataclass_t *update_class) 1176{ 1177 dns_rdataset_t *rdataset; 1178 isc_result_t result; 1179 dns_message_currentname(msg, section, name); 1180 rdataset = ISC_LIST_HEAD((*name)->list); 1181 INSIST(rdataset != NULL); 1182 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); 1183 *covers = rdataset->covers; 1184 *ttl = rdataset->ttl; 1185 result = dns_rdataset_first(rdataset); 1186 INSIST(result == ISC_R_SUCCESS); 1187 dns_rdataset_current(rdataset, rdata); 1188 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); 1189 *update_class = rdata->rdclass; 1190 rdata->rdclass = zoneclass; 1191} 1192 1193/* 1194 * Increment the SOA serial number of database 'db', version 'ver'. 1195 * Replace the SOA record in the database, and log the 1196 * change in 'diff'. 1197 */ 1198 1199 /* 1200 * XXXRTH Failures in this routine will be worth logging, when 1201 * we have a logging system. Failure to find the zonename 1202 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR(). 1203 */ 1204 1205static isc_result_t 1206increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver, 1207 dns_diff_t *diff, isc_mem_t *mctx) 1208{ 1209 dns_difftuple_t *deltuple = NULL; 1210 dns_difftuple_t *addtuple = NULL; 1211 isc_uint32_t serial; 1212 isc_result_t result; 1213 1214 CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); 1215 CHECK(dns_difftuple_copy(deltuple, &addtuple)); 1216 addtuple->op = DNS_DIFFOP_ADD; 1217 1218 serial = dns_soa_getserial(&addtuple->rdata); 1219 1220 /* RFC1982 */ 1221 serial = (serial + 1) & 0xFFFFFFFF; 1222 if (serial == 0) 1223 serial = 1; 1224 1225 dns_soa_setserial(serial, &addtuple->rdata); 1226 CHECK(do_one_tuple(&deltuple, db, ver, diff)); 1227 CHECK(do_one_tuple(&addtuple, db, ver, diff)); 1228 result = ISC_R_SUCCESS; 1229 1230 failure: 1231 if (addtuple != NULL) 1232 dns_difftuple_free(&addtuple); 1233 if (deltuple != NULL) 1234 dns_difftuple_free(&deltuple); 1235 return (result); 1236} 1237 1238/* 1239 * Check that the new SOA record at 'update_rdata' does not 1240 * illegally cause the SOA serial number to decrease or stay 1241 * unchanged relative to the existing SOA in 'db'. 1242 * 1243 * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not. 1244 * 1245 * William King points out that RFC2136 is inconsistent about 1246 * the case where the serial number stays unchanged: 1247 * 1248 * section 3.4.2.2 requires a server to ignore a SOA update request 1249 * if the serial number on the update SOA is less_than_or_equal to 1250 * the zone SOA serial. 1251 * 1252 * section 3.6 requires a server to ignore a SOA update request if 1253 * the serial is less_than the zone SOA serial. 1254 * 1255 * Paul says 3.4.2.2 is correct. 1256 * 1257 */ 1258static isc_result_t 1259check_soa_increment(dns_db_t *db, dns_dbversion_t *ver, 1260 dns_rdata_t *update_rdata, 1261 isc_boolean_t *ok) 1262{ 1263 isc_uint32_t db_serial; 1264 isc_uint32_t update_serial; 1265 isc_result_t result; 1266 1267 update_serial = dns_soa_getserial(update_rdata); 1268 1269 result = dns_db_getsoaserial(db, ver, &db_serial); 1270 if (result != ISC_R_SUCCESS) 1271 return (result); 1272 1273 if (DNS_SERIAL_GE(db_serial, update_serial)) { 1274 *ok = ISC_FALSE; 1275 } else { 1276 *ok = ISC_TRUE; 1277 } 1278 1279 return (ISC_R_SUCCESS); 1280 1281} 1282 1283/**************************************************************************/ 1284/* 1285 * Incremental updating of NSECs and RRSIGs. 1286 */ 1287 1288#define MAXZONEKEYS 32 /* Maximum number of zone keys supported. */ 1289 1290/* 1291 * We abuse the dns_diff_t type to represent a set of domain names 1292 * affected by the update. 1293 */ 1294static isc_result_t 1295namelist_append_name(dns_diff_t *list, dns_name_t *name) { 1296 isc_result_t result; 1297 dns_difftuple_t *tuple = NULL; 1298 static dns_rdata_t dummy_rdata = { NULL, 0, 0, 0, 0, 1299 { (void*)(-1), (void*)(-1) } }; 1300 CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0, 1301 &dummy_rdata, &tuple)); 1302 dns_diff_append(list, &tuple); 1303 failure: 1304 return (result); 1305} 1306 1307static isc_result_t 1308namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected) 1309{ 1310 isc_result_t result; 1311 dns_fixedname_t fixedname; 1312 dns_name_t *child; 1313 dns_dbiterator_t *dbit = NULL; 1314 1315 dns_fixedname_init(&fixedname); 1316 child = dns_fixedname_name(&fixedname); 1317 1318 CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); 1319 1320 for (result = dns_dbiterator_seek(dbit, name); 1321 result == ISC_R_SUCCESS; 1322 result = dns_dbiterator_next(dbit)) 1323 { 1324 dns_dbnode_t *node = NULL; 1325 CHECK(dns_dbiterator_current(dbit, &node, child)); 1326 dns_db_detachnode(db, &node); 1327 if (! dns_name_issubdomain(child, name)) 1328 break; 1329 CHECK(namelist_append_name(affected, child)); 1330 } 1331 if (result == ISC_R_NOMORE) 1332 result = ISC_R_SUCCESS; 1333 failure: 1334 if (dbit != NULL) 1335 dns_dbiterator_destroy(&dbit); 1336 return (result); 1337} 1338 1339 1340 1341/* 1342 * Helper function for non_nsec_rrset_exists(). 1343 */ 1344static isc_result_t 1345is_non_nsec_action(void *data, dns_rdataset_t *rrset) { 1346 UNUSED(data); 1347 if (!(rrset->type == dns_rdatatype_nsec || 1348 (rrset->type == dns_rdatatype_rrsig && 1349 rrset->covers == dns_rdatatype_nsec))) 1350 return (ISC_R_EXISTS); 1351 return (ISC_R_SUCCESS); 1352} 1353 1354/* 1355 * Check whether there is an rrset other than a NSEC or RRSIG NSEC, 1356 * i.e., anything that justifies the continued existence of a name 1357 * after a secure update. 1358 * 1359 * If such an rrset exists, set '*exists' to ISC_TRUE. 1360 * Otherwise, set it to ISC_FALSE. 1361 */ 1362static isc_result_t 1363non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 1364 dns_name_t *name, isc_boolean_t *exists) 1365{ 1366 isc_result_t result; 1367 result = foreach_rrset(db, ver, name, 1368 is_non_nsec_action, NULL); 1369 RETURN_EXISTENCE_FLAG; 1370} 1371 1372/* 1373 * A comparison function for sorting dns_diff_t:s by name. 1374 */ 1375static int 1376name_order(const void *av, const void *bv) { 1377 dns_difftuple_t const * const *ap = av; 1378 dns_difftuple_t const * const *bp = bv; 1379 dns_difftuple_t const *a = *ap; 1380 dns_difftuple_t const *b = *bp; 1381 return (dns_name_compare(&a->name, &b->name)); 1382} 1383 1384static isc_result_t 1385uniqify_name_list(dns_diff_t *list) { 1386 isc_result_t result; 1387 dns_difftuple_t *p, *q; 1388 1389 CHECK(dns_diff_sort(list, name_order)); 1390 1391 p = ISC_LIST_HEAD(list->tuples); 1392 while (p != NULL) { 1393 do { 1394 q = ISC_LIST_NEXT(p, link); 1395 if (q == NULL || ! dns_name_equal(&p->name, &q->name)) 1396 break; 1397 ISC_LIST_UNLINK(list->tuples, q, link); 1398 dns_difftuple_free(&q); 1399 } while (1); 1400 p = ISC_LIST_NEXT(p, link); 1401 } 1402 failure: 1403 return (result); 1404} 1405 1406 1407static isc_result_t 1408is_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1409 isc_boolean_t *flag) 1410{ 1411 isc_result_t result; 1412 dns_fixedname_t foundname; 1413 dns_fixedname_init(&foundname); 1414 result = dns_db_find(db, name, ver, dns_rdatatype_any, 1415 DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD, 1416 (isc_stdtime_t) 0, NULL, 1417 dns_fixedname_name(&foundname), 1418 NULL, NULL); 1419 if (result == ISC_R_SUCCESS) { 1420 *flag = ISC_FALSE; 1421 return (ISC_R_SUCCESS); 1422 } else if (result == DNS_R_ZONECUT) { 1423 /* 1424 * We are at the zonecut. The name will have an NSEC, but 1425 * non-delegation will be omitted from the type bit map. 1426 */ 1427 *flag = ISC_FALSE; 1428 return (ISC_R_SUCCESS); 1429 } else if (result == DNS_R_GLUE || result == DNS_R_DNAME) { 1430 *flag = ISC_TRUE; 1431 return (ISC_R_SUCCESS); 1432 } else { 1433 return (result); 1434 } 1435} 1436 1437/* 1438 * Find the next/previous name that has a NSEC record. 1439 * In other words, skip empty database nodes and names that 1440 * have had their NSECs removed because they are obscured by 1441 * a zone cut. 1442 */ 1443static isc_result_t 1444next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1445 dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname, 1446 isc_boolean_t forward) 1447{ 1448 isc_result_t result; 1449 dns_dbiterator_t *dbit = NULL; 1450 isc_boolean_t has_nsec; 1451 unsigned int wraps = 0; 1452 1453 CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit)); 1454 1455 CHECK(dns_dbiterator_seek(dbit, oldname)); 1456 do { 1457 dns_dbnode_t *node = NULL; 1458 1459 if (forward) 1460 result = dns_dbiterator_next(dbit); 1461 else 1462 result = dns_dbiterator_prev(dbit); 1463 if (result == ISC_R_NOMORE) { 1464 /* 1465 * Wrap around. 1466 */ 1467 if (forward) 1468 CHECK(dns_dbiterator_first(dbit)); 1469 else 1470 CHECK(dns_dbiterator_last(dbit)); 1471 wraps++; 1472 if (wraps == 2) { 1473 update_log(client, zone, ISC_LOG_ERROR, 1474 "secure zone with no NSECs"); 1475 result = DNS_R_BADZONE; 1476 goto failure; 1477 } 1478 } 1479 CHECK(dns_dbiterator_current(dbit, &node, newname)); 1480 dns_db_detachnode(db, &node); 1481 1482 /* 1483 * The iterator may hold the tree lock, and 1484 * rrset_exists() calls dns_db_findnode() which 1485 * may try to reacquire it. To avoid deadlock 1486 * we must pause the iterator first. 1487 */ 1488 CHECK(dns_dbiterator_pause(dbit)); 1489 CHECK(rrset_exists(db, ver, newname, 1490 dns_rdatatype_nsec, 0, &has_nsec)); 1491 1492 } while (! has_nsec); 1493 failure: 1494 if (dbit != NULL) 1495 dns_dbiterator_destroy(&dbit); 1496 1497 return (result); 1498} 1499 1500/* 1501 * Add a NSEC record for "name", recording the change in "diff". 1502 * The existing NSEC is removed. 1503 */ 1504static isc_result_t 1505add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1506 dns_dbversion_t *ver, dns_name_t *name, dns_diff_t *diff) 1507{ 1508 isc_result_t result; 1509 dns_dbnode_t *node = NULL; 1510 unsigned char buffer[DNS_NSEC_BUFFERSIZE]; 1511 dns_rdata_t rdata = DNS_RDATA_INIT; 1512 dns_difftuple_t *tuple = NULL; 1513 dns_fixedname_t fixedname; 1514 dns_name_t *target; 1515 1516 dns_fixedname_init(&fixedname); 1517 target = dns_fixedname_name(&fixedname); 1518 1519 /* 1520 * Find the successor name, aka NSEC target. 1521 */ 1522 CHECK(next_active(client, zone, db, ver, name, target, ISC_TRUE)); 1523 1524 /* 1525 * Create the NSEC RDATA. 1526 */ 1527 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); 1528 dns_rdata_init(&rdata); 1529 CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata)); 1530 dns_db_detachnode(db, &node); 1531 1532 /* 1533 * Delete the old NSEC and record the change. 1534 */ 1535 CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0, 1536 NULL, diff)); 1537 /* 1538 * Add the new NSEC and record the change. 1539 */ 1540 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 1541 3600, /* XXXRTH */ 1542 &rdata, &tuple)); 1543 CHECK(do_one_tuple(&tuple, db, ver, diff)); 1544 INSIST(tuple == NULL); 1545 1546 failure: 1547 if (node != NULL) 1548 dns_db_detachnode(db, &node); 1549 return (result); 1550} 1551 1552/* 1553 * Add a placeholder NSEC record for "name", recording the change in "diff". 1554 */ 1555static isc_result_t 1556add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1557 dns_diff_t *diff) { 1558 isc_result_t result; 1559 dns_difftuple_t *tuple = NULL; 1560 isc_region_t r; 1561 unsigned char data[1] = { 0 }; /* The root domain, no bits. */ 1562 dns_rdata_t rdata = DNS_RDATA_INIT; 1563 1564 r.base = data; 1565 r.length = sizeof(data); 1566 dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r); 1567 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0, 1568 &rdata, &tuple)); 1569 CHECK(do_one_tuple(&tuple, db, ver, diff)); 1570 failure: 1571 return (result); 1572} 1573 1574static isc_result_t 1575find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, 1576 isc_mem_t *mctx, unsigned int maxkeys, 1577 dst_key_t **keys, unsigned int *nkeys) 1578{ 1579 isc_result_t result; 1580 dns_dbnode_t *node = NULL; 1581 const char *directory = dns_zone_getkeydirectory(zone); 1582 CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); 1583 CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), 1584 directory, mctx, maxkeys, keys, nkeys)); 1585 failure: 1586 if (node != NULL) 1587 dns_db_detachnode(db, &node); 1588 return (result); 1589} 1590 1591/* 1592 * Add RRSIG records for an RRset, recording the change in "diff". 1593 */ 1594static isc_result_t 1595add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1596 dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys, 1597 unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t inception, 1598 isc_stdtime_t expire) 1599{ 1600 isc_result_t result; 1601 dns_dbnode_t *node = NULL; 1602 dns_rdataset_t rdataset; 1603 dns_rdata_t sig_rdata = DNS_RDATA_INIT; 1604 isc_buffer_t buffer; 1605 unsigned char data[1024]; /* XXX */ 1606 unsigned int i; 1607 1608 dns_rdataset_init(&rdataset); 1609 isc_buffer_init(&buffer, data, sizeof(data)); 1610 1611 /* Get the rdataset to sign. */ 1612 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); 1613 CHECK(dns_db_findrdataset(db, node, ver, type, 0, 1614 (isc_stdtime_t) 0, 1615 &rdataset, NULL)); 1616 dns_db_detachnode(db, &node); 1617 1618 for (i = 0; i < nkeys; i++) { 1619 /* Calculate the signature, creating a RRSIG RDATA. */ 1620 CHECK(dns_dnssec_sign(name, &rdataset, keys[i], 1621 &inception, &expire, 1622 mctx, &buffer, &sig_rdata)); 1623 1624 /* Update the database and journal with the RRSIG. */ 1625 /* XXX inefficient - will cause dataset merging */ 1626 CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name, 1627 rdataset.ttl, &sig_rdata)); 1628 dns_rdata_reset(&sig_rdata); 1629 } 1630 1631 failure: 1632 if (dns_rdataset_isassociated(&rdataset)) 1633 dns_rdataset_disassociate(&rdataset); 1634 if (node != NULL) 1635 dns_db_detachnode(db, &node); 1636 return (result); 1637} 1638 1639/* 1640 * Update RRSIG and NSEC records affected by an update. The original 1641 * update, including the SOA serial update but exluding the RRSIG & NSEC 1642 * changes, is in "diff" and has already been applied to "newver" of "db". 1643 * The database version prior to the update is "oldver". 1644 * 1645 * The necessary RRSIG and NSEC changes will be applied to "newver" 1646 * and added (as a minimal diff) to "diff". 1647 * 1648 * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds. 1649 */ 1650static isc_result_t 1651update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1652 dns_dbversion_t *oldver, dns_dbversion_t *newver, 1653 dns_diff_t *diff, isc_uint32_t sigvalidityinterval) 1654{ 1655 isc_result_t result; 1656 dns_difftuple_t *t; 1657 dns_diff_t diffnames; 1658 dns_diff_t affected; 1659 dns_diff_t sig_diff; 1660 dns_diff_t nsec_diff; 1661 dns_diff_t nsec_mindiff; 1662 isc_boolean_t flag; 1663 dst_key_t *zone_keys[MAXZONEKEYS]; 1664 unsigned int nkeys = 0; 1665 unsigned int i; 1666 isc_stdtime_t now, inception, expire; 1667 1668 dns_diff_init(client->mctx, &diffnames); 1669 dns_diff_init(client->mctx, &affected); 1670 1671 dns_diff_init(client->mctx, &sig_diff); 1672 dns_diff_init(client->mctx, &nsec_diff); 1673 dns_diff_init(client->mctx, &nsec_mindiff); 1674 1675 result = find_zone_keys(zone, db, newver, client->mctx, 1676 MAXZONEKEYS, zone_keys, &nkeys); 1677 if (result != ISC_R_SUCCESS) { 1678 update_log(client, zone, ISC_LOG_ERROR, 1679 "could not get zone keys for secure dynamic update"); 1680 goto failure; 1681 } 1682 1683 isc_stdtime_get(&now); 1684 inception = now - 3600; /* Allow for some clock skew. */ 1685 expire = now + sigvalidityinterval; 1686 1687 /* 1688 * Find all RRsets directly affected by the update, and 1689 * update their RRSIGs. Also build a list of names affected 1690 * by the update in "diffnames". 1691 */ 1692 CHECK(dns_diff_sort(diff, temp_order)); 1693 1694 t = ISC_LIST_HEAD(diff->tuples); 1695 while (t != NULL) { 1696 dns_name_t *name = &t->name; 1697 /* Now "name" is a new, unique name affected by the update. */ 1698 1699 CHECK(namelist_append_name(&diffnames, name)); 1700 1701 while (t != NULL && dns_name_equal(&t->name, name)) { 1702 dns_rdatatype_t type; 1703 type = t->rdata.type; 1704 1705 /* 1706 * Now "name" and "type" denote a new unique RRset 1707 * affected by the update. 1708 */ 1709 1710 /* Don't sign RRSIGs. */ 1711 if (type == dns_rdatatype_rrsig) 1712 goto skip; 1713 1714 /* 1715 * Delete all old RRSIGs covering this type, since they 1716 * are all invalid when the signed RRset has changed. 1717 * We may not be able to recreate all of them - tough. 1718 */ 1719 CHECK(delete_if(true_p, db, newver, name, 1720 dns_rdatatype_rrsig, type, 1721 NULL, &sig_diff)); 1722 1723 /* 1724 * If this RRset still exists after the update, 1725 * add a new signature for it. 1726 */ 1727 CHECK(rrset_exists(db, newver, name, type, 0, &flag)); 1728 if (flag) { 1729 CHECK(add_sigs(db, newver, name, type, 1730 &sig_diff, zone_keys, nkeys, 1731 client->mctx, inception, 1732 expire)); 1733 } 1734 skip: 1735 /* Skip any other updates to the same RRset. */ 1736 while (t != NULL && 1737 dns_name_equal(&t->name, name) && 1738 t->rdata.type == type) 1739 { 1740 t = ISC_LIST_NEXT(t, link); 1741 } 1742 } 1743 } 1744 1745 /* Remove orphaned NSECs and RRSIG NSECs. */ 1746 for (t = ISC_LIST_HEAD(diffnames.tuples); 1747 t != NULL; 1748 t = ISC_LIST_NEXT(t, link)) 1749 { 1750 CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag)); 1751 if (! flag) { 1752 CHECK(delete_if(true_p, db, newver, &t->name, 1753 dns_rdatatype_any, 0, 1754 NULL, &sig_diff)); 1755 } 1756 } 1757 1758 /* 1759 * When a name is created or deleted, its predecessor needs to 1760 * have its NSEC updated. 1761 */ 1762 for (t = ISC_LIST_HEAD(diffnames.tuples); 1763 t != NULL; 1764 t = ISC_LIST_NEXT(t, link)) 1765 { 1766 isc_boolean_t existed, exists; 1767 dns_fixedname_t fixedname; 1768 dns_name_t *prevname; 1769 1770 dns_fixedname_init(&fixedname); 1771 prevname = dns_fixedname_name(&fixedname); 1772 1773 CHECK(name_exists(db, oldver, &t->name, &existed)); 1774 CHECK(name_exists(db, newver, &t->name, &exists)); 1775 if (exists == existed) 1776 continue; 1777 1778 /* 1779 * Find the predecessor. 1780 * When names become obscured or unobscured in this update 1781 * transaction, we may find the wrong predecessor because 1782 * the NSECs have not yet been updated to reflect the delegation 1783 * change. This should not matter because in this case, 1784 * the correct predecessor is either the delegation node or 1785 * a newly unobscured node, and those nodes are on the 1786 * "affected" list in any case. 1787 */ 1788 CHECK(next_active(client, zone, db, newver, 1789 &t->name, prevname, ISC_FALSE)); 1790 CHECK(namelist_append_name(&affected, prevname)); 1791 } 1792 1793 /* 1794 * Find names potentially affected by delegation changes 1795 * (obscured by adding an NS or DNAME, or unobscured by 1796 * removing one). 1797 */ 1798 for (t = ISC_LIST_HEAD(diffnames.tuples); 1799 t != NULL; 1800 t = ISC_LIST_NEXT(t, link)) 1801 { 1802 isc_boolean_t ns_existed, dname_existed; 1803 isc_boolean_t ns_exists, dname_exists; 1804 1805 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_ns, 0, 1806 &ns_existed)); 1807 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_dname, 0, 1808 &dname_existed)); 1809 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, 1810 &ns_exists)); 1811 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0, 1812 &dname_exists)); 1813 if ((ns_exists || dname_exists) == (ns_existed || dname_existed)) 1814 continue; 1815 /* 1816 * There was a delegation change. Mark all subdomains 1817 * of t->name as potentially needing a NSEC update. 1818 */ 1819 CHECK(namelist_append_subdomain(db, &t->name, &affected)); 1820 } 1821 1822 ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link); 1823 INSIST(ISC_LIST_EMPTY(diffnames.tuples)); 1824 1825 CHECK(uniqify_name_list(&affected)); 1826 1827 /* 1828 * Determine which names should have NSECs, and delete/create 1829 * NSECs to make it so. We don't know the final NSEC targets yet, 1830 * so we just create placeholder NSECs with arbitrary contents 1831 * to indicate that their respective owner names should be part of 1832 * the NSEC chain. 1833 */ 1834 for (t = ISC_LIST_HEAD(affected.tuples); 1835 t != NULL; 1836 t = ISC_LIST_NEXT(t, link)) 1837 { 1838 isc_boolean_t exists; 1839 CHECK(name_exists(db, newver, &t->name, &exists)); 1840 if (! exists) 1841 continue; 1842 CHECK(is_glue(db, newver, &t->name, &flag)); 1843 if (flag) { 1844 /* 1845 * This name is obscured. Delete any 1846 * existing NSEC record. 1847 */ 1848 CHECK(delete_if(true_p, db, newver, &t->name, 1849 dns_rdatatype_nsec, 0, 1850 NULL, &nsec_diff)); 1851 } else { 1852 /* 1853 * This name is not obscured. It should have a NSEC. 1854 */ 1855 CHECK(rrset_exists(db, newver, &t->name, 1856 dns_rdatatype_nsec, 0, &flag)); 1857 if (! flag) 1858 CHECK(add_placeholder_nsec(db, newver, &t->name, 1859 diff)); 1860 } 1861 } 1862 1863 /* 1864 * Now we know which names are part of the NSEC chain. 1865 * Make them all point at their correct targets. 1866 */ 1867 for (t = ISC_LIST_HEAD(affected.tuples); 1868 t != NULL; 1869 t = ISC_LIST_NEXT(t, link)) 1870 { 1871 CHECK(rrset_exists(db, newver, &t->name, 1872 dns_rdatatype_nsec, 0, &flag)); 1873 if (flag) { 1874 /* 1875 * There is a NSEC, but we don't know if it is correct. 1876 * Delete it and create a correct one to be sure. 1877 * If the update was unnecessary, the diff minimization 1878 * will take care of eliminating it from the journal, 1879 * IXFRs, etc. 1880 * 1881 * The RRSIG bit should always be set in the NSECs 1882 * we generate, because they will all get RRSIG NSECs. 1883 * (XXX what if the zone keys are missing?). 1884 * Because the RRSIG NSECs have not necessarily been 1885 * created yet, the correctness of the bit mask relies 1886 * on the assumption that NSECs are only created if 1887 * there is other data, and if there is other data, 1888 * there are other RRSIGs. 1889 */ 1890 CHECK(add_nsec(client, zone, db, newver, 1891 &t->name, &nsec_diff)); 1892 } 1893 } 1894 1895 /* 1896 * Minimize the set of NSEC updates so that we don't 1897 * have to regenerate the RRSIG NSECs for NSECs that were 1898 * replaced with identical ones. 1899 */ 1900 while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) { 1901 ISC_LIST_UNLINK(nsec_diff.tuples, t, link); 1902 dns_diff_appendminimal(&nsec_mindiff, &t); 1903 } 1904 1905 /* Update RRSIG NSECs. */ 1906 for (t = ISC_LIST_HEAD(nsec_mindiff.tuples); 1907 t != NULL; 1908 t = ISC_LIST_NEXT(t, link)) 1909 { 1910 if (t->op == DNS_DIFFOP_DEL) { 1911 CHECK(delete_if(true_p, db, newver, &t->name, 1912 dns_rdatatype_rrsig, dns_rdatatype_nsec, 1913 NULL, &sig_diff)); 1914 } else if (t->op == DNS_DIFFOP_ADD) { 1915 CHECK(add_sigs(db, newver, &t->name, dns_rdatatype_nsec, 1916 &sig_diff, zone_keys, nkeys, 1917 client->mctx, inception, expire)); 1918 } else { 1919 INSIST(0); 1920 } 1921 } 1922 1923 /* Record our changes for the journal. */ 1924 while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) { 1925 ISC_LIST_UNLINK(sig_diff.tuples, t, link); 1926 dns_diff_appendminimal(diff, &t); 1927 } 1928 while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) { 1929 ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link); 1930 dns_diff_appendminimal(diff, &t); 1931 } 1932 1933 INSIST(ISC_LIST_EMPTY(sig_diff.tuples)); 1934 INSIST(ISC_LIST_EMPTY(nsec_diff.tuples)); 1935 INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples)); 1936 1937 failure: 1938 dns_diff_clear(&sig_diff); 1939 dns_diff_clear(&nsec_diff); 1940 dns_diff_clear(&nsec_mindiff); 1941 1942 dns_diff_clear(&affected); 1943 dns_diff_clear(&diffnames); 1944 1945 for (i = 0; i < nkeys; i++) 1946 dst_key_free(&zone_keys[i]); 1947 1948 return (result); 1949} 1950 1951 1952/**************************************************************************/ 1953/* 1954 * The actual update code in all its glory. We try to follow 1955 * the RFC2136 pseudocode as closely as possible. 1956 */ 1957 1958static isc_result_t 1959send_update_event(ns_client_t *client, dns_zone_t *zone) { 1960 isc_result_t result = ISC_R_SUCCESS; 1961 update_event_t *event = NULL; 1962 isc_task_t *zonetask = NULL; 1963 ns_client_t *evclient; 1964 1965 event = (update_event_t *) 1966 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, 1967 update_action, NULL, sizeof(*event)); 1968 if (event == NULL) 1969 FAIL(ISC_R_NOMEMORY); 1970 event->zone = zone; 1971 event->result = ISC_R_SUCCESS; 1972 1973 evclient = NULL; 1974 ns_client_attach(client, &evclient); 1975 INSIST(client->nupdates == 0); 1976 client->nupdates++; 1977 event->ev_arg = evclient; 1978 1979 dns_zone_gettask(zone, &zonetask); 1980 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 1981 1982 failure: 1983 if (event != NULL) 1984 isc_event_free(ISC_EVENT_PTR(&event)); 1985 return (result); 1986} 1987 1988static void 1989respond(ns_client_t *client, isc_result_t result) { 1990 isc_result_t msg_result; 1991 1992 msg_result = dns_message_reply(client->message, ISC_TRUE); 1993 if (msg_result != ISC_R_SUCCESS) 1994 goto msg_failure; 1995 client->message->rcode = dns_result_torcode(result); 1996 1997 ns_client_send(client); 1998 return; 1999 2000 msg_failure: 2001 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 2002 ISC_LOG_ERROR, 2003 "could not create update response message: %s", 2004 isc_result_totext(msg_result)); 2005 ns_client_next(client, msg_result); 2006} 2007 2008void 2009ns_update_start(ns_client_t *client, isc_result_t sigresult) { 2010 dns_message_t *request = client->message; 2011 isc_result_t result; 2012 dns_name_t *zonename; 2013 dns_rdataset_t *zone_rdataset; 2014 dns_zone_t *zone = NULL; 2015 2016 /* 2017 * Interpret the zone section. 2018 */ 2019 result = dns_message_firstname(request, DNS_SECTION_ZONE); 2020 if (result != ISC_R_SUCCESS) 2021 FAILC(DNS_R_FORMERR, 2022 "update zone section empty"); 2023 2024 /* 2025 * The zone section must contain exactly one "question", and 2026 * it must be of type SOA. 2027 */ 2028 zonename = NULL; 2029 dns_message_currentname(request, DNS_SECTION_ZONE, &zonename); 2030 zone_rdataset = ISC_LIST_HEAD(zonename->list); 2031 if (zone_rdataset->type != dns_rdatatype_soa) 2032 FAILC(DNS_R_FORMERR, 2033 "update zone section contains non-SOA"); 2034 if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) 2035 FAILC(DNS_R_FORMERR, 2036 "update zone section contains multiple RRs"); 2037 2038 /* The zone section must have exactly one name. */ 2039 result = dns_message_nextname(request, DNS_SECTION_ZONE); 2040 if (result != ISC_R_NOMORE) 2041 FAILC(DNS_R_FORMERR, 2042 "update zone section contains multiple RRs"); 2043 2044 result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, 2045 &zone); 2046 if (result != ISC_R_SUCCESS) 2047 FAILC(DNS_R_NOTAUTH, 2048 "not authoritative for update zone"); 2049 2050 switch(dns_zone_gettype(zone)) { 2051 case dns_zone_master: 2052 /* 2053 * We can now fail due to a bad signature as we now know 2054 * that we are the master. 2055 */ 2056 if (sigresult != ISC_R_SUCCESS) 2057 FAIL(sigresult); 2058 CHECK(send_update_event(client, zone)); 2059 break; 2060 case dns_zone_slave: 2061 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone), 2062 "update forwarding", zonename, ISC_TRUE)); 2063 CHECK(send_forward_event(client, zone)); 2064 break; 2065 default: 2066 FAILC(DNS_R_NOTAUTH, 2067 "not authoritative for update zone"); 2068 } 2069 return; 2070 2071 failure: 2072 /* 2073 * We failed without having sent an update event to the zone. 2074 * We are still in the client task context, so we can 2075 * simply give an error response without switching tasks. 2076 */ 2077 respond(client, result); 2078 if (zone != NULL) 2079 dns_zone_detach(&zone); 2080} 2081 2082/* 2083 * DS records are not allowed to exist without corresponding NS records, 2084 * draft-ietf-dnsext-delegation-signer-11.txt, 2.2 Protocol Change, 2085 * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex". 2086 */ 2087 2088static isc_result_t 2089remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) { 2090 isc_result_t result; 2091 isc_boolean_t ns_exists, ds_exists; 2092 dns_difftuple_t *t; 2093 2094 for (t = ISC_LIST_HEAD(diff->tuples); 2095 t != NULL; 2096 t = ISC_LIST_NEXT(t, link)) { 2097 if (t->op != DNS_DIFFOP_DEL || 2098 t->rdata.type != dns_rdatatype_ns) 2099 continue; 2100 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0, 2101 &ns_exists)); 2102 if (ns_exists) 2103 continue; 2104 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ds, 0, 2105 &ds_exists)); 2106 if (!ds_exists) 2107 continue; 2108 CHECK(delete_if(true_p, db, newver, &t->name, 2109 dns_rdatatype_ds, 0, NULL, diff)); 2110 } 2111 return (ISC_R_SUCCESS); 2112 2113 failure: 2114 return (result); 2115} 2116 2117static void 2118update_action(isc_task_t *task, isc_event_t *event) { 2119 update_event_t *uev = (update_event_t *) event; 2120 dns_zone_t *zone = uev->zone; 2121 ns_client_t *client = (ns_client_t *)event->ev_arg; 2122 2123 isc_result_t result; 2124 dns_db_t *db = NULL; 2125 dns_dbversion_t *oldver = NULL; 2126 dns_dbversion_t *ver = NULL; 2127 dns_diff_t diff; /* Pending updates. */ 2128 dns_diff_t temp; /* Pending RR existence assertions. */ 2129 isc_boolean_t soa_serial_changed = ISC_FALSE; 2130 isc_mem_t *mctx = client->mctx; 2131 dns_rdatatype_t covers; 2132 dns_message_t *request = client->message; 2133 dns_rdataclass_t zoneclass; 2134 dns_name_t *zonename; 2135 dns_ssutable_t *ssutable = NULL; 2136 dns_fixedname_t tmpnamefixed; 2137 dns_name_t *tmpname = NULL; 2138 2139 INSIST(event->ev_type == DNS_EVENT_UPDATE); 2140 2141 dns_diff_init(mctx, &diff); 2142 dns_diff_init(mctx, &temp); 2143 2144 CHECK(dns_zone_getdb(zone, &db)); 2145 zonename = dns_db_origin(db); 2146 zoneclass = dns_db_class(db); 2147 dns_zone_getssutable(zone, &ssutable); 2148 dns_db_currentversion(db, &oldver); 2149 CHECK(dns_db_newversion(db, &ver)); 2150 2151 /* 2152 * Check prerequisites. 2153 */ 2154 2155 for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE); 2156 result == ISC_R_SUCCESS; 2157 result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE)) 2158 { 2159 dns_name_t *name = NULL; 2160 dns_rdata_t rdata = DNS_RDATA_INIT; 2161 dns_ttl_t ttl; 2162 dns_rdataclass_t update_class; 2163 isc_boolean_t flag; 2164 2165 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass, 2166 &name, &rdata, &covers, &ttl, &update_class); 2167 2168 if (ttl != 0) 2169 FAILC(DNS_R_FORMERR, "prerequisite TTL is not zero"); 2170 2171 if (! dns_name_issubdomain(name, zonename)) 2172 FAILN(DNS_R_NOTZONE, name, 2173 "prerequisite name is out of zone"); 2174 2175 if (update_class == dns_rdataclass_any) { 2176 if (rdata.length != 0) 2177 FAILC(DNS_R_FORMERR, 2178 "class ANY prerequisite " 2179 "RDATA is not empty"); 2180 if (rdata.type == dns_rdatatype_any) { 2181 CHECK(name_exists(db, ver, name, &flag)); 2182 if (! flag) { 2183 FAILN(DNS_R_NXDOMAIN, name, 2184 "'name in use' prerequisite " 2185 "not satisfied"); 2186 } 2187 } else { 2188 CHECK(rrset_exists(db, ver, name, 2189 rdata.type, covers, &flag)); 2190 if (! flag) { 2191 /* RRset does not exist. */ 2192 FAILNT(DNS_R_NXRRSET, name, rdata.type, 2193 "'rrset exists (value independent)' " 2194 "prerequisite not satisfied"); 2195 } 2196 } 2197 } else if (update_class == dns_rdataclass_none) { 2198 if (rdata.length != 0) 2199 FAILC(DNS_R_FORMERR, 2200 "class NONE prerequisite " 2201 "RDATA is not empty"); 2202 if (rdata.type == dns_rdatatype_any) { 2203 CHECK(name_exists(db, ver, name, &flag)); 2204 if (flag) { 2205 FAILN(DNS_R_YXDOMAIN, name, 2206 "'name not in use' prerequisite " 2207 "not satisfied"); 2208 } 2209 } else { 2210 CHECK(rrset_exists(db, ver, name, 2211 rdata.type, covers, &flag)); 2212 if (flag) { 2213 /* RRset exists. */ 2214 FAILNT(DNS_R_YXRRSET, name, rdata.type, 2215 "'rrset does not exist' " 2216 "prerequisite not satisfied"); 2217 } 2218 } 2219 } else if (update_class == zoneclass) { 2220 /* "temp<rr.name, rr.type> += rr;" */ 2221 result = temp_append(&temp, name, &rdata); 2222 if (result != ISC_R_SUCCESS) { 2223 UNEXPECTED_ERROR(__FILE__, __LINE__, 2224 "temp entry creation failed: %s", 2225 dns_result_totext(result)); 2226 FAIL(ISC_R_UNEXPECTED); 2227 } 2228 } else { 2229 FAILC(DNS_R_FORMERR, "malformed prerequisite"); 2230 } 2231 } 2232 if (result != ISC_R_NOMORE) 2233 FAIL(result); 2234 2235 2236 /* 2237 * Perform the final check of the "rrset exists (value dependent)" 2238 * prerequisites. 2239 */ 2240 if (ISC_LIST_HEAD(temp.tuples) != NULL) { 2241 dns_rdatatype_t type; 2242 2243 /* 2244 * Sort the prerequisite records by owner name, 2245 * type, and rdata. 2246 */ 2247 result = dns_diff_sort(&temp, temp_order); 2248 if (result != ISC_R_SUCCESS) 2249 FAILC(result, "'RRset exists (value dependent)' " 2250 "prerequisite not satisfied"); 2251 2252 dns_fixedname_init(&tmpnamefixed); 2253 tmpname = dns_fixedname_name(&tmpnamefixed); 2254 result = temp_check(mctx, &temp, db, ver, tmpname, &type); 2255 if (result != ISC_R_SUCCESS) 2256 FAILNT(result, tmpname, type, 2257 "'RRset exists (value dependent)' " 2258 "prerequisite not satisfied"); 2259 } 2260 2261 update_log(client, zone, LOGLEVEL_DEBUG, 2262 "prerequisites are OK"); 2263 2264 /* 2265 * Check Requestor's Permissions. It seems a bit silly to do this 2266 * only after prerequisite testing, but that is what RFC2136 says. 2267 */ 2268 result = ISC_R_SUCCESS; 2269 if (ssutable == NULL) 2270 CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), 2271 "update", zonename, ISC_FALSE)); 2272 else if (client->signer == NULL) 2273 CHECK(checkupdateacl(client, NULL, "update", zonename, 2274 ISC_FALSE)); 2275 2276 if (dns_zone_getupdatedisabled(zone)) 2277 FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled"); 2278 2279 /* 2280 * Perform the Update Section Prescan. 2281 */ 2282 2283 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2284 result == ISC_R_SUCCESS; 2285 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2286 { 2287 dns_name_t *name = NULL; 2288 dns_rdata_t rdata = DNS_RDATA_INIT; 2289 dns_ttl_t ttl; 2290 dns_rdataclass_t update_class; 2291 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, 2292 &name, &rdata, &covers, &ttl, &update_class); 2293 2294 if (! dns_name_issubdomain(name, zonename)) 2295 FAILC(DNS_R_NOTZONE, 2296 "update RR is outside zone"); 2297 if (update_class == zoneclass) { 2298 /* 2299 * Check for meta-RRs. The RFC2136 pseudocode says 2300 * check for ANY|AXFR|MAILA|MAILB, but the text adds 2301 * "or any other QUERY metatype" 2302 */ 2303 if (dns_rdatatype_ismeta(rdata.type)) { 2304 FAILC(DNS_R_FORMERR, 2305 "meta-RR in update"); 2306 } 2307 result = dns_zone_checknames(zone, name, &rdata); 2308 if (result != ISC_R_SUCCESS) 2309 FAIL(DNS_R_REFUSED); 2310 } else if (update_class == dns_rdataclass_any) { 2311 if (ttl != 0 || rdata.length != 0 || 2312 (dns_rdatatype_ismeta(rdata.type) && 2313 rdata.type != dns_rdatatype_any)) 2314 FAILC(DNS_R_FORMERR, 2315 "meta-RR in update"); 2316 } else if (update_class == dns_rdataclass_none) { 2317 if (ttl != 0 || 2318 dns_rdatatype_ismeta(rdata.type)) 2319 FAILC(DNS_R_FORMERR, 2320 "meta-RR in update"); 2321 } else { 2322 update_log(client, zone, ISC_LOG_WARNING, 2323 "update RR has incorrect class %d", 2324 update_class); 2325 FAIL(DNS_R_FORMERR); 2326 } 2327 /* 2328 * draft-ietf-dnsind-simple-secure-update-01 says 2329 * "Unlike traditional dynamic update, the client 2330 * is forbidden from updating NSEC records." 2331 */ 2332 if (dns_db_issecure(db)) { 2333 if (rdata.type == dns_rdatatype_nsec) { 2334 FAILC(DNS_R_REFUSED, 2335 "explicit NSEC updates are not allowed " 2336 "in secure zones"); 2337 } 2338 else if (rdata.type == dns_rdatatype_rrsig) { 2339 FAILC(DNS_R_REFUSED, 2340 "explicit RRSIG updates are currently not " 2341 "supported in secure zones"); 2342 } 2343 } 2344 2345 if (ssutable != NULL && client->signer != NULL) { 2346 if (rdata.type != dns_rdatatype_any) { 2347 if (!dns_ssutable_checkrules(ssutable, 2348 client->signer, 2349 name, rdata.type)) 2350 FAILC(DNS_R_REFUSED, 2351 "rejected by secure update"); 2352 } 2353 else { 2354 if (!ssu_checkall(db, ver, name, ssutable, 2355 client->signer)) 2356 FAILC(DNS_R_REFUSED, 2357 "rejected by secure update"); 2358 } 2359 } 2360 } 2361 if (result != ISC_R_NOMORE) 2362 FAIL(result); 2363 2364 update_log(client, zone, LOGLEVEL_DEBUG, 2365 "update section prescan OK"); 2366 2367 /* 2368 * Process the Update Section. 2369 */ 2370 2371 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2372 result == ISC_R_SUCCESS; 2373 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2374 { 2375 dns_name_t *name = NULL; 2376 dns_rdata_t rdata = DNS_RDATA_INIT; 2377 dns_ttl_t ttl; 2378 dns_rdataclass_t update_class; 2379 isc_boolean_t flag; 2380 2381 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, 2382 &name, &rdata, &covers, &ttl, &update_class); 2383 2384 if (update_class == zoneclass) { 2385 2386 /* 2387 * RFC 1123 doesn't allow MF and MD in master zones. */ 2388 if (rdata.type == dns_rdatatype_md || 2389 rdata.type == dns_rdatatype_mf) { 2390 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2391 2392 dns_rdatatype_format(rdata.type, typebuf, 2393 sizeof(typebuf)); 2394 update_log(client, zone, LOGLEVEL_PROTOCOL, 2395 "attempt to add %s ignored", 2396 typebuf); 2397 continue; 2398 } 2399 if (rdata.type == dns_rdatatype_ns && 2400 dns_name_iswildcard(name)) { 2401 update_log(client, zone, 2402 LOGLEVEL_PROTOCOL, 2403 "attempt to add wildcard NS record" 2404 "ignored"); 2405 continue; 2406 } 2407 if (rdata.type == dns_rdatatype_cname) { 2408 CHECK(cname_incompatible_rrset_exists(db, ver, 2409 name, 2410 &flag)); 2411 if (flag) { 2412 update_log(client, zone, 2413 LOGLEVEL_PROTOCOL, 2414 "attempt to add CNAME " 2415 "alongside non-CNAME " 2416 "ignored"); 2417 continue; 2418 } 2419 } else { 2420 CHECK(rrset_exists(db, ver, name, 2421 dns_rdatatype_cname, 0, 2422 &flag)); 2423 if (flag && 2424 ! dns_rdatatype_isdnssec(rdata.type)) 2425 { 2426 update_log(client, zone, 2427 LOGLEVEL_PROTOCOL, 2428 "attempt to add non-CNAME " 2429 "alongside CNAME ignored"); 2430 continue; 2431 } 2432 } 2433 if (rdata.type == dns_rdatatype_soa) { 2434 isc_boolean_t ok; 2435 CHECK(rrset_exists(db, ver, name, 2436 dns_rdatatype_soa, 0, 2437 &flag)); 2438 if (! flag) { 2439 update_log(client, zone, 2440 LOGLEVEL_PROTOCOL, 2441 "attempt to create 2nd " 2442 "SOA ignored"); 2443 continue; 2444 } 2445 CHECK(check_soa_increment(db, ver, &rdata, 2446 &ok)); 2447 if (! ok) { 2448 update_log(client, zone, 2449 LOGLEVEL_PROTOCOL, 2450 "SOA update failed to " 2451 "increment serial, " 2452 "ignoring it"); 2453 continue; 2454 } 2455 soa_serial_changed = ISC_TRUE; 2456 } 2457 2458 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { 2459 char namestr[DNS_NAME_FORMATSIZE]; 2460 char typestr[DNS_RDATATYPE_FORMATSIZE]; 2461 dns_name_format(name, namestr, 2462 sizeof(namestr)); 2463 dns_rdatatype_format(rdata.type, typestr, 2464 sizeof(typestr)); 2465 update_log(client, zone, 2466 LOGLEVEL_PROTOCOL, 2467 "adding an RR at '%s' %s", 2468 namestr, typestr); 2469 } 2470 2471 /* Prepare the affected RRset for the addition. */ 2472 { 2473 add_rr_prepare_ctx_t ctx; 2474 ctx.db = db; 2475 ctx.ver = ver; 2476 ctx.diff = &diff; 2477 ctx.name = name; 2478 ctx.update_rr = &rdata; 2479 ctx.update_rr_ttl = ttl; 2480 ctx.ignore_add = ISC_FALSE; 2481 dns_diff_init(mctx, &ctx.del_diff); 2482 dns_diff_init(mctx, &ctx.add_diff); 2483 CHECK(foreach_rr(db, ver, name, rdata.type, 2484 covers, add_rr_prepare_action, 2485 &ctx)); 2486 2487 if (ctx.ignore_add) { 2488 dns_diff_clear(&ctx.del_diff); 2489 dns_diff_clear(&ctx.add_diff); 2490 } else { 2491 CHECK(do_diff(&ctx.del_diff, db, ver, &diff)); 2492 CHECK(do_diff(&ctx.add_diff, db, ver, &diff)); 2493 CHECK(update_one_rr(db, ver, &diff, 2494 DNS_DIFFOP_ADD, 2495 name, ttl, &rdata)); 2496 } 2497 } 2498 } else if (update_class == dns_rdataclass_any) { 2499 if (rdata.type == dns_rdatatype_any) { 2500 if (isc_log_wouldlog(ns_g_lctx, 2501 LOGLEVEL_PROTOCOL)) 2502 { 2503 char namestr[DNS_NAME_FORMATSIZE]; 2504 dns_name_format(name, namestr, 2505 sizeof(namestr)); 2506 update_log(client, zone, 2507 LOGLEVEL_PROTOCOL, 2508 "delete all rrsets from " 2509 "name '%s'", namestr); 2510 } 2511 if (dns_name_equal(name, zonename)) { 2512 CHECK(delete_if(type_not_soa_nor_ns_p, 2513 db, ver, name, 2514 dns_rdatatype_any, 0, 2515 &rdata, &diff)); 2516 } else { 2517 CHECK(delete_if(true_p, db, ver, name, 2518 dns_rdatatype_any, 0, 2519 &rdata, &diff)); 2520 } 2521 } else if (dns_name_equal(name, zonename) && 2522 (rdata.type == dns_rdatatype_soa || 2523 rdata.type == dns_rdatatype_ns)) { 2524 update_log(client, zone, 2525 LOGLEVEL_PROTOCOL, 2526 "attempt to delete all SOA " 2527 "or NS records ignored"); 2528 continue; 2529 } else { 2530 if (isc_log_wouldlog(ns_g_lctx, 2531 LOGLEVEL_PROTOCOL)) 2532 { 2533 char namestr[DNS_NAME_FORMATSIZE]; 2534 char typestr[DNS_RDATATYPE_FORMATSIZE]; 2535 dns_name_format(name, namestr, 2536 sizeof(namestr)); 2537 dns_rdatatype_format(rdata.type, 2538 typestr, 2539 sizeof(typestr)); 2540 update_log(client, zone, 2541 LOGLEVEL_PROTOCOL, 2542 "deleting rrset at '%s' %s", 2543 namestr, typestr); 2544 } 2545 CHECK(delete_if(true_p, db, ver, name, 2546 rdata.type, covers, &rdata, 2547 &diff)); 2548 } 2549 } else if (update_class == dns_rdataclass_none) { 2550 /* 2551 * The (name == zonename) condition appears in 2552 * RFC2136 3.4.2.4 but is missing from the pseudocode. 2553 */ 2554 if (dns_name_equal(name, zonename)) { 2555 if (rdata.type == dns_rdatatype_soa) { 2556 update_log(client, zone, 2557 LOGLEVEL_PROTOCOL, 2558 "attempt to delete SOA " 2559 "ignored"); 2560 continue; 2561 } 2562 if (rdata.type == dns_rdatatype_ns) { 2563 int count; 2564 CHECK(rr_count(db, ver, name, 2565 dns_rdatatype_ns, 2566 0, &count)); 2567 if (count == 1) { 2568 update_log(client, zone, 2569 LOGLEVEL_PROTOCOL, 2570 "attempt to " 2571 "delete last " 2572 "NS ignored"); 2573 continue; 2574 } 2575 } 2576 } 2577 update_log(client, zone, 2578 LOGLEVEL_PROTOCOL, 2579 "deleting an RR"); 2580 CHECK(delete_if(rr_equal_p, db, ver, name, 2581 rdata.type, covers, &rdata, &diff)); 2582 } 2583 } 2584 if (result != ISC_R_NOMORE) 2585 FAIL(result); 2586 2587 /* 2588 * If any changes were made, increment the SOA serial number, 2589 * update RRSIGs and NSECs (if zone is secure), and write the update 2590 * to the journal. 2591 */ 2592 if (! ISC_LIST_EMPTY(diff.tuples)) { 2593 char *journalfile; 2594 dns_journal_t *journal; 2595 2596 /* 2597 * Increment the SOA serial, but only if it was not 2598 * changed as a result of an update operation. 2599 */ 2600 if (! soa_serial_changed) { 2601 CHECK(increment_soa_serial(db, ver, &diff, mctx)); 2602 } 2603 2604 CHECK(remove_orphaned_ds(db, ver, &diff)); 2605 2606 if (dns_db_issecure(db)) { 2607 result = update_signatures(client, zone, db, oldver, 2608 ver, &diff, 2609 dns_zone_getsigvalidityinterval(zone)); 2610 if (result != ISC_R_SUCCESS) { 2611 update_log(client, zone, 2612 ISC_LOG_ERROR, 2613 "RRSIG/NSEC update failed: %s", 2614 isc_result_totext(result)); 2615 goto failure; 2616 } 2617 } 2618 2619 journalfile = dns_zone_getjournal(zone); 2620 if (journalfile != NULL) { 2621 update_log(client, zone, LOGLEVEL_DEBUG, 2622 "writing journal %s", journalfile); 2623 2624 journal = NULL; 2625 result = dns_journal_open(mctx, journalfile, 2626 ISC_TRUE, &journal); 2627 if (result != ISC_R_SUCCESS) 2628 FAILS(result, "journal open failed"); 2629 2630 result = dns_journal_write_transaction(journal, &diff); 2631 if (result != ISC_R_SUCCESS) { 2632 dns_journal_destroy(&journal); 2633 FAILS(result, "journal write failed"); 2634 } 2635 2636 dns_journal_destroy(&journal); 2637 } 2638 2639 /* 2640 * XXXRTH Just a note that this committing code will have 2641 * to change to handle databases that need two-phase 2642 * commit, but this isn't a priority. 2643 */ 2644 update_log(client, zone, LOGLEVEL_DEBUG, 2645 "committing update transaction"); 2646 dns_db_closeversion(db, &ver, ISC_TRUE); 2647 2648 /* 2649 * Mark the zone as dirty so that it will be written to disk. 2650 */ 2651 dns_zone_markdirty(zone); 2652 2653 /* 2654 * Notify slaves of the change we just made. 2655 */ 2656 dns_zone_notify(zone); 2657 } else { 2658 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request"); 2659 dns_db_closeversion(db, &ver, ISC_TRUE); 2660 } 2661 result = ISC_R_SUCCESS; 2662 goto common; 2663 2664 failure: 2665 /* 2666 * The reason for failure should have been logged at this point. 2667 */ 2668 if (ver != NULL) { 2669 update_log(client, zone, LOGLEVEL_DEBUG, 2670 "rolling back"); 2671 dns_db_closeversion(db, &ver, ISC_FALSE); 2672 } 2673 2674 common: 2675 dns_diff_clear(&temp); 2676 dns_diff_clear(&diff); 2677 2678 if (oldver != NULL) 2679 dns_db_closeversion(db, &oldver, ISC_FALSE); 2680 2681 if (db != NULL) 2682 dns_db_detach(&db); 2683 2684 if (ssutable != NULL) 2685 dns_ssutable_detach(&ssutable); 2686 2687 if (zone != NULL) 2688 dns_zone_detach(&zone); 2689 2690 isc_task_detach(&task); 2691 uev->result = result; 2692 uev->ev_type = DNS_EVENT_UPDATEDONE; 2693 uev->ev_action = updatedone_action; 2694 isc_task_send(client->task, &event); 2695 INSIST(event == NULL); 2696} 2697 2698static void 2699updatedone_action(isc_task_t *task, isc_event_t *event) { 2700 update_event_t *uev = (update_event_t *) event; 2701 ns_client_t *client = (ns_client_t *) event->ev_arg; 2702 2703 UNUSED(task); 2704 2705 INSIST(event->ev_type == DNS_EVENT_UPDATEDONE); 2706 INSIST(task == client->task); 2707 2708 INSIST(client->nupdates > 0); 2709 client->nupdates--; 2710 respond(client, uev->result); 2711 ns_client_detach(&client); 2712 isc_event_free(&event); 2713} 2714 2715/* 2716 * Update forwarding support. 2717 */ 2718 2719static void 2720forward_fail(isc_task_t *task, isc_event_t *event) { 2721 ns_client_t *client = (ns_client_t *)event->ev_arg; 2722 2723 UNUSED(task); 2724 2725 INSIST(client->nupdates > 0); 2726 client->nupdates--; 2727 respond(client, DNS_R_SERVFAIL); 2728 ns_client_detach(&client); 2729 isc_event_free(&event); 2730} 2731 2732 2733static void 2734forward_callback(void *arg, isc_result_t result, dns_message_t *answer) { 2735 update_event_t *uev = arg; 2736 ns_client_t *client = uev->ev_arg; 2737 2738 if (result != ISC_R_SUCCESS) { 2739 INSIST(answer == NULL); 2740 uev->ev_type = DNS_EVENT_UPDATEDONE; 2741 uev->ev_action = forward_fail; 2742 } else { 2743 uev->ev_type = DNS_EVENT_UPDATEDONE; 2744 uev->ev_action = forward_done; 2745 uev->answer = answer; 2746 } 2747 isc_task_send(client->task, ISC_EVENT_PTR(&uev)); 2748} 2749 2750static void 2751forward_done(isc_task_t *task, isc_event_t *event) { 2752 update_event_t *uev = (update_event_t *) event; 2753 ns_client_t *client = (ns_client_t *)event->ev_arg; 2754 2755 UNUSED(task); 2756 2757 INSIST(client->nupdates > 0); 2758 client->nupdates--; 2759 ns_client_sendraw(client, uev->answer); 2760 dns_message_destroy(&uev->answer); 2761 isc_event_free(&event); 2762 ns_client_detach(&client); 2763} 2764 2765static void 2766forward_action(isc_task_t *task, isc_event_t *event) { 2767 update_event_t *uev = (update_event_t *) event; 2768 dns_zone_t *zone = uev->zone; 2769 ns_client_t *client = (ns_client_t *)event->ev_arg; 2770 isc_result_t result; 2771 2772 result = dns_zone_forwardupdate(zone, client->message, 2773 forward_callback, event); 2774 if (result != ISC_R_SUCCESS) { 2775 uev->ev_type = DNS_EVENT_UPDATEDONE; 2776 uev->ev_action = forward_fail; 2777 isc_task_send(client->task, &event); 2778 } 2779 dns_zone_detach(&zone); 2780 isc_task_detach(&task); 2781} 2782 2783static isc_result_t 2784send_forward_event(ns_client_t *client, dns_zone_t *zone) { 2785 isc_result_t result = ISC_R_SUCCESS; 2786 update_event_t *event = NULL; 2787 isc_task_t *zonetask = NULL; 2788 ns_client_t *evclient; 2789 2790 event = (update_event_t *) 2791 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, 2792 forward_action, NULL, sizeof(*event)); 2793 if (event == NULL) 2794 FAIL(ISC_R_NOMEMORY); 2795 event->zone = zone; 2796 event->result = ISC_R_SUCCESS; 2797 2798 evclient = NULL; 2799 ns_client_attach(client, &evclient); 2800 INSIST(client->nupdates == 0); 2801 client->nupdates++; 2802 event->ev_arg = evclient; 2803 2804 dns_zone_gettask(zone, &zonetask); 2805 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 2806 2807 failure: 2808 if (event != NULL) 2809 isc_event_free(ISC_EVENT_PTR(&event)); 2810 return (result); 2811} 2812