/contrib/bind9/bin/named/update.c
C | 4501 lines | 3106 code | 477 blank | 918 comment | 892 complexity | 9efd4520648bfa750d627d72b8b713d9 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/* 2 * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1999-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or 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.186.16.7 2011/11/03 02:55:34 each Exp $ */ 19 20#include <config.h> 21 22#include <isc/netaddr.h> 23#include <isc/print.h> 24#include <isc/serial.h> 25#include <isc/stats.h> 26#include <isc/string.h> 27#include <isc/taskpool.h> 28#include <isc/util.h> 29 30#include <dns/db.h> 31#include <dns/dbiterator.h> 32#include <dns/diff.h> 33#include <dns/dnssec.h> 34#include <dns/events.h> 35#include <dns/fixedname.h> 36#include <dns/journal.h> 37#include <dns/keyvalues.h> 38#include <dns/message.h> 39#include <dns/nsec.h> 40#include <dns/nsec3.h> 41#include <dns/private.h> 42#include <dns/rdataclass.h> 43#include <dns/rdataset.h> 44#include <dns/rdatasetiter.h> 45#include <dns/rdatastruct.h> 46#include <dns/rdatatype.h> 47#include <dns/soa.h> 48#include <dns/ssu.h> 49#include <dns/tsig.h> 50#include <dns/view.h> 51#include <dns/zone.h> 52#include <dns/zt.h> 53 54#include <named/client.h> 55#include <named/log.h> 56#include <named/server.h> 57#include <named/update.h> 58 59/*! \file 60 * \brief 61 * This module implements dynamic update as in RFC2136. 62 */ 63 64/* 65 * XXX TODO: 66 * - document strict minimality 67 */ 68 69/**************************************************************************/ 70 71/*% 72 * Log level for tracing dynamic update protocol requests. 73 */ 74#define LOGLEVEL_PROTOCOL ISC_LOG_INFO 75 76/*% 77 * Log level for low-level debug tracing. 78 */ 79#define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8) 80 81/*% 82 * Check an operation for failure. These macros all assume that 83 * the function using them has a 'result' variable and a 'failure' 84 * label. 85 */ 86#define CHECK(op) \ 87 do { result = (op); \ 88 if (result != ISC_R_SUCCESS) goto failure; \ 89 } while (0) 90 91/*% 92 * Fail unconditionally with result 'code', which must not 93 * be ISC_R_SUCCESS. The reason for failure presumably has 94 * been logged already. 95 * 96 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 97 * from complaining about "end-of-loop code not reached". 98 */ 99 100#define FAIL(code) \ 101 do { \ 102 result = (code); \ 103 if (result != ISC_R_SUCCESS) goto failure; \ 104 } while (0) 105 106/*% 107 * Fail unconditionally and log as a client error. 108 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 109 * from complaining about "end-of-loop code not reached". 110 */ 111#define FAILC(code, msg) \ 112 do { \ 113 const char *_what = "failed"; \ 114 result = (code); \ 115 switch (result) { \ 116 case DNS_R_NXDOMAIN: \ 117 case DNS_R_YXDOMAIN: \ 118 case DNS_R_YXRRSET: \ 119 case DNS_R_NXRRSET: \ 120 _what = "unsuccessful"; \ 121 } \ 122 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 123 "update %s: %s (%s)", _what, \ 124 msg, isc_result_totext(result)); \ 125 if (result != ISC_R_SUCCESS) goto failure; \ 126 } while (0) 127#define PREREQFAILC(code, msg) \ 128 do { \ 129 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ 130 FAILC(code, msg); \ 131 } while (0) 132 133#define FAILN(code, name, msg) \ 134 do { \ 135 const char *_what = "failed"; \ 136 result = (code); \ 137 switch (result) { \ 138 case DNS_R_NXDOMAIN: \ 139 case DNS_R_YXDOMAIN: \ 140 case DNS_R_YXRRSET: \ 141 case DNS_R_NXRRSET: \ 142 _what = "unsuccessful"; \ 143 } \ 144 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ 145 char _nbuf[DNS_NAME_FORMATSIZE]; \ 146 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 147 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 148 "update %s: %s: %s (%s)", _what, _nbuf, \ 149 msg, isc_result_totext(result)); \ 150 } \ 151 if (result != ISC_R_SUCCESS) goto failure; \ 152 } while (0) 153#define PREREQFAILN(code, name, msg) \ 154 do { \ 155 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ 156 FAILN(code, name, msg); \ 157 } while (0) 158 159#define FAILNT(code, name, type, msg) \ 160 do { \ 161 const char *_what = "failed"; \ 162 result = (code); \ 163 switch (result) { \ 164 case DNS_R_NXDOMAIN: \ 165 case DNS_R_YXDOMAIN: \ 166 case DNS_R_YXRRSET: \ 167 case DNS_R_NXRRSET: \ 168 _what = "unsuccessful"; \ 169 } \ 170 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \ 171 char _nbuf[DNS_NAME_FORMATSIZE]; \ 172 char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \ 173 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 174 dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \ 175 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 176 "update %s: %s/%s: %s (%s)", \ 177 _what, _nbuf, _tbuf, msg, \ 178 isc_result_totext(result)); \ 179 } \ 180 if (result != ISC_R_SUCCESS) goto failure; \ 181 } while (0) 182#define PREREQFAILNT(code, name, type, msg) \ 183 do { \ 184 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \ 185 FAILNT(code, name, type, msg); \ 186 } while (0) 187 188/*% 189 * Fail unconditionally and log as a server error. 190 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 191 * from complaining about "end-of-loop code not reached". 192 */ 193#define FAILS(code, msg) \ 194 do { \ 195 result = (code); \ 196 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 197 "error: %s: %s", \ 198 msg, isc_result_totext(result)); \ 199 if (result != ISC_R_SUCCESS) goto failure; \ 200 } while (0) 201 202/* 203 * Return TRUE if NS_CLIENTATTR_TCP is set in the attributes other FALSE. 204 */ 205#define TCPCLIENT(client) (((client)->attributes & NS_CLIENTATTR_TCP) != 0) 206 207/**************************************************************************/ 208 209typedef struct rr rr_t; 210 211struct rr { 212 /* dns_name_t name; */ 213 isc_uint32_t ttl; 214 dns_rdata_t rdata; 215}; 216 217typedef struct update_event update_event_t; 218 219struct update_event { 220 ISC_EVENT_COMMON(update_event_t); 221 dns_zone_t *zone; 222 isc_result_t result; 223 dns_message_t *answer; 224}; 225 226/**************************************************************************/ 227/* 228 * Forward declarations. 229 */ 230 231static void update_action(isc_task_t *task, isc_event_t *event); 232static void updatedone_action(isc_task_t *task, isc_event_t *event); 233static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone); 234static void forward_done(isc_task_t *task, isc_event_t *event); 235 236/**************************************************************************/ 237 238static void 239update_log(ns_client_t *client, dns_zone_t *zone, 240 int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); 241 242static void 243update_log(ns_client_t *client, dns_zone_t *zone, 244 int level, const char *fmt, ...) 245{ 246 va_list ap; 247 char message[4096]; 248 char namebuf[DNS_NAME_FORMATSIZE]; 249 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 250 251 if (client == NULL || zone == NULL) 252 return; 253 254 if (isc_log_wouldlog(ns_g_lctx, level) == ISC_FALSE) 255 return; 256 257 dns_name_format(dns_zone_getorigin(zone), namebuf, 258 sizeof(namebuf)); 259 dns_rdataclass_format(dns_zone_getclass(zone), classbuf, 260 sizeof(classbuf)); 261 262 va_start(ap, fmt); 263 vsnprintf(message, sizeof(message), fmt, ap); 264 va_end(ap); 265 266 ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 267 level, "updating zone '%s/%s': %s", 268 namebuf, classbuf, message); 269} 270 271/*% 272 * Increment updated-related statistics counters. 273 */ 274static inline void 275inc_stats(dns_zone_t *zone, isc_statscounter_t counter) { 276 isc_stats_increment(ns_g_server->nsstats, counter); 277 278 if (zone != NULL) { 279 isc_stats_t *zonestats = dns_zone_getrequeststats(zone); 280 if (zonestats != NULL) 281 isc_stats_increment(zonestats, counter); 282 } 283} 284 285/*% 286 * Check if we could have queried for the contents of this zone or 287 * if the zone is potentially updateable. 288 * If the zone can potentially be updated and the check failed then 289 * log a error otherwise we log a informational message. 290 */ 291static isc_result_t 292checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename, 293 dns_acl_t *updateacl, dns_ssutable_t *ssutable) 294{ 295 char namebuf[DNS_NAME_FORMATSIZE]; 296 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 297 int level; 298 isc_result_t result; 299 300 result = ns_client_checkaclsilent(client, NULL, queryacl, ISC_TRUE); 301 if (result != ISC_R_SUCCESS) { 302 dns_name_format(zonename, namebuf, sizeof(namebuf)); 303 dns_rdataclass_format(client->view->rdclass, classbuf, 304 sizeof(classbuf)); 305 306 level = (updateacl == NULL && ssutable == NULL) ? 307 ISC_LOG_INFO : ISC_LOG_ERROR; 308 309 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 310 NS_LOGMODULE_UPDATE, level, 311 "update '%s/%s' denied due to allow-query", 312 namebuf, classbuf); 313 } else if (updateacl == NULL && ssutable == NULL) { 314 dns_name_format(zonename, namebuf, sizeof(namebuf)); 315 dns_rdataclass_format(client->view->rdclass, classbuf, 316 sizeof(classbuf)); 317 318 result = DNS_R_REFUSED; 319 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 320 NS_LOGMODULE_UPDATE, ISC_LOG_INFO, 321 "update '%s/%s' denied", namebuf, classbuf); 322 } 323 return (result); 324} 325 326/*% 327 * Override the default acl logging when checking whether a client 328 * can update the zone or whether we can forward the request to the 329 * master based on IP address. 330 * 331 * 'message' contains the type of operation that is being attempted. 332 * 'slave' indicates if this is a slave zone. If 'acl' is NULL then 333 * log at debug=3. 334 * If the zone has no access controls configured ('acl' == NULL && 335 * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise 336 * at error. 337 * 338 * If the request was signed log that we received it. 339 */ 340static isc_result_t 341checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message, 342 dns_name_t *zonename, isc_boolean_t slave, 343 isc_boolean_t has_ssutable) 344{ 345 char namebuf[DNS_NAME_FORMATSIZE]; 346 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 347 int level = ISC_LOG_ERROR; 348 const char *msg = "denied"; 349 isc_result_t result; 350 351 if (slave && acl == NULL) { 352 result = DNS_R_NOTIMP; 353 level = ISC_LOG_DEBUG(3); 354 msg = "disabled"; 355 } else { 356 result = ns_client_checkaclsilent(client, NULL, acl, ISC_FALSE); 357 if (result == ISC_R_SUCCESS) { 358 level = ISC_LOG_DEBUG(3); 359 msg = "approved"; 360 } else if (acl == NULL && !has_ssutable) { 361 level = ISC_LOG_INFO; 362 } 363 } 364 365 if (client->signer != NULL) { 366 dns_name_format(client->signer, namebuf, sizeof(namebuf)); 367 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 368 NS_LOGMODULE_UPDATE, ISC_LOG_INFO, 369 "signer \"%s\" %s", namebuf, msg); 370 } 371 372 dns_name_format(zonename, namebuf, sizeof(namebuf)); 373 dns_rdataclass_format(client->view->rdclass, classbuf, 374 sizeof(classbuf)); 375 376 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 377 NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s", 378 message, namebuf, classbuf, msg); 379 return (result); 380} 381 382/*% 383 * Update a single RR in version 'ver' of 'db' and log the 384 * update in 'diff'. 385 * 386 * Ensures: 387 * \li '*tuple' == NULL. Either the tuple is freed, or its 388 * ownership has been transferred to the diff. 389 */ 390static isc_result_t 391do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, 392 dns_diff_t *diff) 393{ 394 dns_diff_t temp_diff; 395 isc_result_t result; 396 397 /* 398 * Create a singleton diff. 399 */ 400 dns_diff_init(diff->mctx, &temp_diff); 401 temp_diff.resign = diff->resign; 402 ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); 403 404 /* 405 * Apply it to the database. 406 */ 407 result = dns_diff_apply(&temp_diff, db, ver); 408 ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); 409 if (result != ISC_R_SUCCESS) { 410 dns_difftuple_free(tuple); 411 return (result); 412 } 413 414 /* 415 * Merge it into the current pending journal entry. 416 */ 417 dns_diff_appendminimal(diff, tuple); 418 419 /* 420 * Do not clear temp_diff. 421 */ 422 return (ISC_R_SUCCESS); 423} 424 425/*% 426 * Perform the updates in 'updates' in version 'ver' of 'db' and log the 427 * update in 'diff'. 428 * 429 * Ensures: 430 * \li 'updates' is empty. 431 */ 432static isc_result_t 433do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver, 434 dns_diff_t *diff) 435{ 436 isc_result_t result; 437 while (! ISC_LIST_EMPTY(updates->tuples)) { 438 dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples); 439 ISC_LIST_UNLINK(updates->tuples, t, link); 440 CHECK(do_one_tuple(&t, db, ver, diff)); 441 } 442 return (ISC_R_SUCCESS); 443 444 failure: 445 dns_diff_clear(diff); 446 return (result); 447} 448 449static isc_result_t 450update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, 451 dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, 452 dns_rdata_t *rdata) 453{ 454 dns_difftuple_t *tuple = NULL; 455 isc_result_t result; 456 result = dns_difftuple_create(diff->mctx, op, 457 name, ttl, rdata, &tuple); 458 if (result != ISC_R_SUCCESS) 459 return (result); 460 return (do_one_tuple(&tuple, db, ver, diff)); 461} 462 463/**************************************************************************/ 464/* 465 * Callback-style iteration over rdatasets and rdatas. 466 * 467 * foreach_rrset() can be used to iterate over the RRsets 468 * of a name and call a callback function with each 469 * one. Similarly, foreach_rr() can be used to iterate 470 * over the individual RRs at name, optionally restricted 471 * to RRs of a given type. 472 * 473 * The callback functions are called "actions" and take 474 * two arguments: a void pointer for passing arbitrary 475 * context information, and a pointer to the current RRset 476 * or RR. By convention, their names end in "_action". 477 */ 478 479/* 480 * XXXRTH We might want to make this public somewhere in libdns. 481 */ 482 483/*% 484 * Function type for foreach_rrset() iterator actions. 485 */ 486typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset); 487 488/*% 489 * Function type for foreach_rr() iterator actions. 490 */ 491typedef isc_result_t rr_func(void *data, rr_t *rr); 492 493/*% 494 * Internal context struct for foreach_node_rr(). 495 */ 496typedef struct { 497 rr_func * rr_action; 498 void * rr_action_data; 499} foreach_node_rr_ctx_t; 500 501/*% 502 * Internal helper function for foreach_node_rr(). 503 */ 504static isc_result_t 505foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) { 506 isc_result_t result; 507 foreach_node_rr_ctx_t *ctx = data; 508 for (result = dns_rdataset_first(rdataset); 509 result == ISC_R_SUCCESS; 510 result = dns_rdataset_next(rdataset)) 511 { 512 rr_t rr = { 0, DNS_RDATA_INIT }; 513 514 dns_rdataset_current(rdataset, &rr.rdata); 515 rr.ttl = rdataset->ttl; 516 result = (*ctx->rr_action)(ctx->rr_action_data, &rr); 517 if (result != ISC_R_SUCCESS) 518 return (result); 519 } 520 if (result != ISC_R_NOMORE) 521 return (result); 522 return (ISC_R_SUCCESS); 523} 524 525/*% 526 * For each rdataset of 'name' in 'ver' of 'db', call 'action' 527 * with the rdataset and 'action_data' as arguments. If the name 528 * does not exist, do nothing. 529 * 530 * If 'action' returns an error, abort iteration and return the error. 531 */ 532static isc_result_t 533foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 534 rrset_func *action, void *action_data) 535{ 536 isc_result_t result; 537 dns_dbnode_t *node; 538 dns_rdatasetiter_t *iter; 539 540 node = NULL; 541 result = dns_db_findnode(db, name, ISC_FALSE, &node); 542 if (result == ISC_R_NOTFOUND) 543 return (ISC_R_SUCCESS); 544 if (result != ISC_R_SUCCESS) 545 return (result); 546 547 iter = NULL; 548 result = dns_db_allrdatasets(db, node, ver, 549 (isc_stdtime_t) 0, &iter); 550 if (result != ISC_R_SUCCESS) 551 goto cleanup_node; 552 553 for (result = dns_rdatasetiter_first(iter); 554 result == ISC_R_SUCCESS; 555 result = dns_rdatasetiter_next(iter)) 556 { 557 dns_rdataset_t rdataset; 558 559 dns_rdataset_init(&rdataset); 560 dns_rdatasetiter_current(iter, &rdataset); 561 562 result = (*action)(action_data, &rdataset); 563 564 dns_rdataset_disassociate(&rdataset); 565 if (result != ISC_R_SUCCESS) 566 goto cleanup_iterator; 567 } 568 if (result == ISC_R_NOMORE) 569 result = ISC_R_SUCCESS; 570 571 cleanup_iterator: 572 dns_rdatasetiter_destroy(&iter); 573 574 cleanup_node: 575 dns_db_detachnode(db, &node); 576 577 return (result); 578} 579 580/*% 581 * For each RR of 'name' in 'ver' of 'db', call 'action' 582 * with the RR and 'action_data' as arguments. If the name 583 * does not exist, do nothing. 584 * 585 * If 'action' returns an error, abort iteration 586 * and return the error. 587 */ 588static isc_result_t 589foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 590 rr_func *rr_action, void *rr_action_data) 591{ 592 foreach_node_rr_ctx_t ctx; 593 ctx.rr_action = rr_action; 594 ctx.rr_action_data = rr_action_data; 595 return (foreach_rrset(db, ver, name, 596 foreach_node_rr_action, &ctx)); 597} 598 599 600/*% 601 * For each of the RRs specified by 'db', 'ver', 'name', 'type', 602 * (which can be dns_rdatatype_any to match any type), and 'covers', call 603 * 'action' with the RR and 'action_data' as arguments. If the name 604 * does not exist, or if no RRset of the given type exists at the name, 605 * do nothing. 606 * 607 * If 'action' returns an error, abort iteration and return the error. 608 */ 609static isc_result_t 610foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 611 dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action, 612 void *rr_action_data) 613{ 614 615 isc_result_t result; 616 dns_dbnode_t *node; 617 dns_rdataset_t rdataset; 618 619 if (type == dns_rdatatype_any) 620 return (foreach_node_rr(db, ver, name, 621 rr_action, rr_action_data)); 622 623 node = NULL; 624 if (type == dns_rdatatype_nsec3 || 625 (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3)) 626 result = dns_db_findnsec3node(db, name, ISC_FALSE, &node); 627 else 628 result = dns_db_findnode(db, name, ISC_FALSE, &node); 629 if (result == ISC_R_NOTFOUND) 630 return (ISC_R_SUCCESS); 631 if (result != ISC_R_SUCCESS) 632 return (result); 633 634 dns_rdataset_init(&rdataset); 635 result = dns_db_findrdataset(db, node, ver, type, covers, 636 (isc_stdtime_t) 0, &rdataset, NULL); 637 if (result == ISC_R_NOTFOUND) { 638 result = ISC_R_SUCCESS; 639 goto cleanup_node; 640 } 641 if (result != ISC_R_SUCCESS) 642 goto cleanup_node; 643 644 for (result = dns_rdataset_first(&rdataset); 645 result == ISC_R_SUCCESS; 646 result = dns_rdataset_next(&rdataset)) 647 { 648 rr_t rr = { 0, DNS_RDATA_INIT }; 649 dns_rdataset_current(&rdataset, &rr.rdata); 650 rr.ttl = rdataset.ttl; 651 result = (*rr_action)(rr_action_data, &rr); 652 if (result != ISC_R_SUCCESS) 653 goto cleanup_rdataset; 654 } 655 if (result != ISC_R_NOMORE) 656 goto cleanup_rdataset; 657 result = ISC_R_SUCCESS; 658 659 cleanup_rdataset: 660 dns_rdataset_disassociate(&rdataset); 661 cleanup_node: 662 dns_db_detachnode(db, &node); 663 664 return (result); 665} 666 667/**************************************************************************/ 668/* 669 * Various tests on the database contents (for prerequisites, etc). 670 */ 671 672/*% 673 * Function type for predicate functions that compare a database RR 'db_rr' 674 * against an update RR 'update_rr'. 675 */ 676typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr); 677 678/*% 679 * Helper function for rrset_exists(). 680 */ 681static isc_result_t 682rrset_exists_action(void *data, rr_t *rr) { 683 UNUSED(data); 684 UNUSED(rr); 685 return (ISC_R_EXISTS); 686} 687 688/*% 689 * Utility macro for RR existence checking functions. 690 * 691 * If the variable 'result' has the value ISC_R_EXISTS or 692 * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE, 693 * respectively, and return success. 694 * 695 * If 'result' has any other value, there was a failure. 696 * Return the failure result code and do not set *exists. 697 * 698 * This would be more readable as "do { if ... } while(0)", 699 * but that form generates tons of warnings on Solaris 2.6. 700 */ 701#define RETURN_EXISTENCE_FLAG \ 702 return ((result == ISC_R_EXISTS) ? \ 703 (*exists = ISC_TRUE, ISC_R_SUCCESS) : \ 704 ((result == ISC_R_SUCCESS) ? \ 705 (*exists = ISC_FALSE, ISC_R_SUCCESS) : \ 706 result)) 707 708/*% 709 * Set '*exists' to true iff an rrset of the given type exists, 710 * to false otherwise. 711 */ 712static isc_result_t 713rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 714 dns_rdatatype_t type, dns_rdatatype_t covers, 715 isc_boolean_t *exists) 716{ 717 isc_result_t result; 718 result = foreach_rr(db, ver, name, type, covers, 719 rrset_exists_action, NULL); 720 RETURN_EXISTENCE_FLAG; 721} 722 723/*% 724 * Set '*visible' to true if the RRset exists and is part of the 725 * visible zone. Otherwise '*visible' is set to false unless a 726 * error occurs. 727 */ 728static isc_result_t 729rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 730 dns_rdatatype_t type, isc_boolean_t *visible) 731{ 732 isc_result_t result; 733 dns_fixedname_t fixed; 734 735 dns_fixedname_init(&fixed); 736 result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD, 737 (isc_stdtime_t) 0, NULL, 738 dns_fixedname_name(&fixed), NULL, NULL); 739 switch (result) { 740 case ISC_R_SUCCESS: 741 *visible = ISC_TRUE; 742 break; 743 /* 744 * Glue, obscured, deleted or replaced records. 745 */ 746 case DNS_R_DELEGATION: 747 case DNS_R_DNAME: 748 case DNS_R_CNAME: 749 case DNS_R_NXDOMAIN: 750 case DNS_R_NXRRSET: 751 case DNS_R_EMPTYNAME: 752 case DNS_R_COVERINGNSEC: 753 *visible = ISC_FALSE; 754 result = ISC_R_SUCCESS; 755 break; 756 default: 757 break; 758 } 759 return (result); 760} 761 762/*% 763 * Helper function for cname_incompatible_rrset_exists. 764 */ 765static isc_result_t 766cname_compatibility_action(void *data, dns_rdataset_t *rrset) { 767 UNUSED(data); 768 if (rrset->type != dns_rdatatype_cname && 769 ! dns_rdatatype_isdnssec(rrset->type)) 770 return (ISC_R_EXISTS); 771 return (ISC_R_SUCCESS); 772} 773 774/*% 775 * Check whether there is an rrset incompatible with adding a CNAME RR, 776 * i.e., anything but another CNAME (which can be replaced) or a 777 * DNSSEC RR (which can coexist). 778 * 779 * If such an incompatible rrset exists, set '*exists' to ISC_TRUE. 780 * Otherwise, set it to ISC_FALSE. 781 */ 782static isc_result_t 783cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 784 dns_name_t *name, isc_boolean_t *exists) { 785 isc_result_t result; 786 result = foreach_rrset(db, ver, name, 787 cname_compatibility_action, NULL); 788 RETURN_EXISTENCE_FLAG; 789} 790 791/*% 792 * Helper function for rr_count(). 793 */ 794static isc_result_t 795count_rr_action(void *data, rr_t *rr) { 796 int *countp = data; 797 UNUSED(rr); 798 (*countp)++; 799 return (ISC_R_SUCCESS); 800} 801 802/*% 803 * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'. 804 */ 805static isc_result_t 806rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 807 dns_rdatatype_t type, dns_rdatatype_t covers, int *countp) 808{ 809 *countp = 0; 810 return (foreach_rr(db, ver, name, type, covers, 811 count_rr_action, countp)); 812} 813 814/*% 815 * Context struct and helper function for name_exists(). 816 */ 817 818static isc_result_t 819name_exists_action(void *data, dns_rdataset_t *rrset) { 820 UNUSED(data); 821 UNUSED(rrset); 822 return (ISC_R_EXISTS); 823} 824 825/*% 826 * Set '*exists' to true iff the given name exists, to false otherwise. 827 */ 828static isc_result_t 829name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 830 isc_boolean_t *exists) 831{ 832 isc_result_t result; 833 result = foreach_rrset(db, ver, name, 834 name_exists_action, NULL); 835 RETURN_EXISTENCE_FLAG; 836} 837 838/* 839 * 'ssu_check_t' is used to pass the arguments to 840 * dns_ssutable_checkrules() to the callback function 841 * ssu_checkrule(). 842 */ 843typedef struct { 844 /* The ownername of the record to be updated. */ 845 dns_name_t *name; 846 847 /* The signature's name if the request was signed. */ 848 dns_name_t *signer; 849 850 /* The address of the client if the request was received via TCP. */ 851 isc_netaddr_t *tcpaddr; 852 853 /* The ssu table to check against. */ 854 dns_ssutable_t *table; 855 856 /* the key used for TKEY requests */ 857 dst_key_t *key; 858} ssu_check_t; 859 860static isc_result_t 861ssu_checkrule(void *data, dns_rdataset_t *rrset) { 862 ssu_check_t *ssuinfo = data; 863 isc_boolean_t result; 864 865 /* 866 * If we're deleting all records, it's ok to delete RRSIG and NSEC even 867 * if we're normally not allowed to. 868 */ 869 if (rrset->type == dns_rdatatype_rrsig || 870 rrset->type == dns_rdatatype_nsec) 871 return (ISC_R_SUCCESS); 872 result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer, 873 ssuinfo->name, ssuinfo->tcpaddr, 874 rrset->type, ssuinfo->key); 875 return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE); 876} 877 878static isc_boolean_t 879ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 880 dns_ssutable_t *ssutable, dns_name_t *signer, 881 isc_netaddr_t *tcpaddr, dst_key_t *key) 882{ 883 isc_result_t result; 884 ssu_check_t ssuinfo; 885 886 ssuinfo.name = name; 887 ssuinfo.table = ssutable; 888 ssuinfo.signer = signer; 889 ssuinfo.tcpaddr = tcpaddr; 890 ssuinfo.key = key; 891 result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); 892 return (ISC_TF(result == ISC_R_SUCCESS)); 893} 894 895/**************************************************************************/ 896/* 897 * Checking of "RRset exists (value dependent)" prerequisites. 898 * 899 * In the RFC2136 section 3.2.5, this is the pseudocode involving 900 * a variable called "temp", a mapping of <name, type> tuples to rrsets. 901 * 902 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t" 903 * where each tuple has op==DNS_DIFFOP_EXISTS. 904 */ 905 906 907/*% 908 * Append a tuple asserting the existence of the RR with 909 * 'name' and 'rdata' to 'diff'. 910 */ 911static isc_result_t 912temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) { 913 isc_result_t result; 914 dns_difftuple_t *tuple = NULL; 915 916 REQUIRE(DNS_DIFF_VALID(diff)); 917 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, 918 name, 0, rdata, &tuple)); 919 ISC_LIST_APPEND(diff->tuples, tuple, link); 920 failure: 921 return (result); 922} 923 924/*% 925 * Compare two rdatasets represented as sorted lists of tuples. 926 * All list elements must have the same owner name and type. 927 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset) 928 * if not. 929 */ 930static isc_result_t 931temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { 932 for (;;) { 933 if (a == NULL || b == NULL) 934 break; 935 INSIST(a->op == DNS_DIFFOP_EXISTS && 936 b->op == DNS_DIFFOP_EXISTS); 937 INSIST(a->rdata.type == b->rdata.type); 938 INSIST(dns_name_equal(&a->name, &b->name)); 939 if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0) 940 return (DNS_R_NXRRSET); 941 a = ISC_LIST_NEXT(a, link); 942 b = ISC_LIST_NEXT(b, link); 943 } 944 if (a != NULL || b != NULL) 945 return (DNS_R_NXRRSET); 946 return (ISC_R_SUCCESS); 947} 948 949/*% 950 * A comparison function defining the sorting order for the entries 951 * in the "temp" data structure. The major sort key is the owner name, 952 * followed by the type and rdata. 953 */ 954static int 955temp_order(const void *av, const void *bv) { 956 dns_difftuple_t const * const *ap = av; 957 dns_difftuple_t const * const *bp = bv; 958 dns_difftuple_t const *a = *ap; 959 dns_difftuple_t const *b = *bp; 960 int r; 961 r = dns_name_compare(&a->name, &b->name); 962 if (r != 0) 963 return (r); 964 r = (b->rdata.type - a->rdata.type); 965 if (r != 0) 966 return (r); 967 r = dns_rdata_casecompare(&a->rdata, &b->rdata); 968 return (r); 969} 970 971/*% 972 * Check the "RRset exists (value dependent)" prerequisite information 973 * in 'temp' against the contents of the database 'db'. 974 * 975 * Return ISC_R_SUCCESS if the prerequisites are satisfied, 976 * rcode(dns_rcode_nxrrset) if not. 977 * 978 * 'temp' must be pre-sorted. 979 */ 980 981static isc_result_t 982temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, 983 dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep) 984{ 985 isc_result_t result; 986 dns_name_t *name; 987 dns_dbnode_t *node; 988 dns_difftuple_t *t; 989 dns_diff_t trash; 990 991 dns_diff_init(mctx, &trash); 992 993 /* 994 * For each name and type in the prerequisites, 995 * construct a sorted rdata list of the corresponding 996 * database contents, and compare the lists. 997 */ 998 t = ISC_LIST_HEAD(temp->tuples); 999 while (t != NULL) { 1000 name = &t->name; 1001 (void)dns_name_copy(name, tmpname, NULL); 1002 *typep = t->rdata.type; 1003 1004 /* A new unique name begins here. */ 1005 node = NULL; 1006 result = dns_db_findnode(db, name, ISC_FALSE, &node); 1007 if (result == ISC_R_NOTFOUND) { 1008 dns_diff_clear(&trash); 1009 return (DNS_R_NXRRSET); 1010 } 1011 if (result != ISC_R_SUCCESS) { 1012 dns_diff_clear(&trash); 1013 return (result); 1014 } 1015 1016 /* A new unique type begins here. */ 1017 while (t != NULL && dns_name_equal(&t->name, name)) { 1018 dns_rdatatype_t type, covers; 1019 dns_rdataset_t rdataset; 1020 dns_diff_t d_rrs; /* Database RRs with 1021 this name and type */ 1022 dns_diff_t u_rrs; /* Update RRs with 1023 this name and type */ 1024 1025 *typep = type = t->rdata.type; 1026 if (type == dns_rdatatype_rrsig || 1027 type == dns_rdatatype_sig) 1028 covers = dns_rdata_covers(&t->rdata); 1029 else if (type == dns_rdatatype_any) { 1030 dns_db_detachnode(db, &node); 1031 dns_diff_clear(&trash); 1032 return (DNS_R_NXRRSET); 1033 } else 1034 covers = 0; 1035 1036 /* 1037 * Collect all database RRs for this name and type 1038 * onto d_rrs and sort them. 1039 */ 1040 dns_rdataset_init(&rdataset); 1041 result = dns_db_findrdataset(db, node, ver, type, 1042 covers, (isc_stdtime_t) 0, 1043 &rdataset, NULL); 1044 if (result != ISC_R_SUCCESS) { 1045 dns_db_detachnode(db, &node); 1046 dns_diff_clear(&trash); 1047 return (DNS_R_NXRRSET); 1048 } 1049 1050 dns_diff_init(mctx, &d_rrs); 1051 dns_diff_init(mctx, &u_rrs); 1052 1053 for (result = dns_rdataset_first(&rdataset); 1054 result == ISC_R_SUCCESS; 1055 result = dns_rdataset_next(&rdataset)) 1056 { 1057 dns_rdata_t rdata = DNS_RDATA_INIT; 1058 dns_rdataset_current(&rdataset, &rdata); 1059 result = temp_append(&d_rrs, name, &rdata); 1060 if (result != ISC_R_SUCCESS) 1061 goto failure; 1062 } 1063 if (result != ISC_R_NOMORE) 1064 goto failure; 1065 result = dns_diff_sort(&d_rrs, temp_order); 1066 if (result != ISC_R_SUCCESS) 1067 goto failure; 1068 1069 /* 1070 * Collect all update RRs for this name and type 1071 * onto u_rrs. No need to sort them here - 1072 * they are already sorted. 1073 */ 1074 while (t != NULL && 1075 dns_name_equal(&t->name, name) && 1076 t->rdata.type == type) 1077 { 1078 dns_difftuple_t *next = 1079 ISC_LIST_NEXT(t, link); 1080 ISC_LIST_UNLINK(temp->tuples, t, link); 1081 ISC_LIST_APPEND(u_rrs.tuples, t, link); 1082 t = next; 1083 } 1084 1085 /* Compare the two sorted lists. */ 1086 result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples), 1087 ISC_LIST_HEAD(d_rrs.tuples)); 1088 if (result != ISC_R_SUCCESS) 1089 goto failure; 1090 1091 /* 1092 * We are done with the tuples, but we can't free 1093 * them yet because "name" still points into one 1094 * of them. Move them on a temporary list. 1095 */ 1096 ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link); 1097 ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link); 1098 dns_rdataset_disassociate(&rdataset); 1099 1100 continue; 1101 1102 failure: 1103 dns_diff_clear(&d_rrs); 1104 dns_diff_clear(&u_rrs); 1105 dns_diff_clear(&trash); 1106 dns_rdataset_disassociate(&rdataset); 1107 dns_db_detachnode(db, &node); 1108 return (result); 1109 } 1110 1111 dns_db_detachnode(db, &node); 1112 } 1113 1114 dns_diff_clear(&trash); 1115 return (ISC_R_SUCCESS); 1116} 1117 1118/**************************************************************************/ 1119/* 1120 * Conditional deletion of RRs. 1121 */ 1122 1123/*% 1124 * Context structure for delete_if(). 1125 */ 1126 1127typedef struct { 1128 rr_predicate *predicate; 1129 dns_db_t *db; 1130 dns_dbversion_t *ver; 1131 dns_diff_t *diff; 1132 dns_name_t *name; 1133 dns_rdata_t *update_rr; 1134} conditional_delete_ctx_t; 1135 1136/*% 1137 * Predicate functions for delete_if(). 1138 */ 1139 1140/*% 1141 * Return true iff 'db_rr' is neither a SOA nor an NS RR nor 1142 * an RRSIG nor an NSEC3PARAM nor a NSEC. 1143 */ 1144static isc_boolean_t 1145type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1146 UNUSED(update_rr); 1147 return ((db_rr->type != dns_rdatatype_soa && 1148 db_rr->type != dns_rdatatype_ns && 1149 db_rr->type != dns_rdatatype_nsec3param && 1150 db_rr->type != dns_rdatatype_rrsig && 1151 db_rr->type != dns_rdatatype_nsec) ? 1152 ISC_TRUE : ISC_FALSE); 1153} 1154 1155/*% 1156 * Return true iff 'db_rr' is neither a RRSIG nor a NSEC. 1157 */ 1158static isc_boolean_t 1159type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1160 UNUSED(update_rr); 1161 return ((db_rr->type != dns_rdatatype_rrsig && 1162 db_rr->type != dns_rdatatype_nsec) ? 1163 ISC_TRUE : ISC_FALSE); 1164} 1165 1166/*% 1167 * Return true always. 1168 */ 1169static isc_boolean_t 1170true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1171 UNUSED(update_rr); 1172 UNUSED(db_rr); 1173 return (ISC_TRUE); 1174} 1175 1176/*% 1177 * Return true if the record is a RRSIG. 1178 */ 1179static isc_boolean_t 1180rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1181 UNUSED(update_rr); 1182 return ((db_rr->type == dns_rdatatype_rrsig) ? 1183 ISC_TRUE : ISC_FALSE); 1184} 1185 1186/*% 1187 * Return true iff the two RRs have identical rdata. 1188 */ 1189static isc_boolean_t 1190rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1191 /* 1192 * XXXRTH This is not a problem, but we should consider creating 1193 * dns_rdata_equal() (that used dns_name_equal()), since it 1194 * would be faster. Not a priority. 1195 */ 1196 return (dns_rdata_casecompare(update_rr, db_rr) == 0 ? 1197 ISC_TRUE : ISC_FALSE); 1198} 1199 1200/*% 1201 * Return true iff 'update_rr' should replace 'db_rr' according 1202 * to the special RFC2136 rules for CNAME, SOA, and WKS records. 1203 * 1204 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs 1205 * make little sense, so we replace those, too. 1206 * 1207 * Additionally replace RRSIG that have been generated by the same key 1208 * for the same type. This simplifies refreshing a offline KSK by not 1209 * requiring that the old RRSIG be deleted. It also simplifies key 1210 * rollover by only requiring that the new RRSIG be added. 1211 */ 1212static isc_boolean_t 1213replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1214 dns_rdata_rrsig_t updatesig, dbsig; 1215 isc_result_t result; 1216 1217 if (db_rr->type != update_rr->type) 1218 return (ISC_FALSE); 1219 if (db_rr->type == dns_rdatatype_cname) 1220 return (ISC_TRUE); 1221 if (db_rr->type == dns_rdatatype_dname) 1222 return (ISC_TRUE); 1223 if (db_rr->type == dns_rdatatype_soa) 1224 return (ISC_TRUE); 1225 if (db_rr->type == dns_rdatatype_nsec) 1226 return (ISC_TRUE); 1227 if (db_rr->type == dns_rdatatype_rrsig) { 1228 /* 1229 * Replace existing RRSIG with the same keyid, 1230 * covered and algorithm. 1231 */ 1232 result = dns_rdata_tostruct(db_rr, &dbsig, NULL); 1233 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1234 result = dns_rdata_tostruct(update_rr, &updatesig, NULL); 1235 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1236 if (dbsig.keyid == updatesig.keyid && 1237 dbsig.covered == updatesig.covered && 1238 dbsig.algorithm == updatesig.algorithm) 1239 return (ISC_TRUE); 1240 } 1241 if (db_rr->type == dns_rdatatype_wks) { 1242 /* 1243 * Compare the address and protocol fields only. These 1244 * form the first five bytes of the RR data. Do a 1245 * raw binary comparison; unpacking the WKS RRs using 1246 * dns_rdata_tostruct() might be cleaner in some ways. 1247 */ 1248 INSIST(db_rr->length >= 5 && update_rr->length >= 5); 1249 return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? 1250 ISC_TRUE : ISC_FALSE); 1251 } 1252 1253 if (db_rr->type == dns_rdatatype_nsec3param) { 1254 if (db_rr->length != update_rr->length) 1255 return (ISC_FALSE); 1256 INSIST(db_rr->length >= 4 && update_rr->length >= 4); 1257 /* 1258 * Replace NSEC3PARAM records that only differ by the 1259 * flags field. 1260 */ 1261 if (db_rr->data[0] == update_rr->data[0] && 1262 memcmp(db_rr->data+2, update_rr->data+2, 1263 update_rr->length - 2) == 0) 1264 return (ISC_TRUE); 1265 } 1266 return (ISC_FALSE); 1267} 1268 1269/*% 1270 * Internal helper function for delete_if(). 1271 */ 1272static isc_result_t 1273delete_if_action(void *data, rr_t *rr) { 1274 conditional_delete_ctx_t *ctx = data; 1275 if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) { 1276 isc_result_t result; 1277 result = update_one_rr(ctx->db, ctx->ver, ctx->diff, 1278 DNS_DIFFOP_DEL, ctx->name, 1279 rr->ttl, &rr->rdata); 1280 return (result); 1281 } else { 1282 return (ISC_R_SUCCESS); 1283 } 1284} 1285 1286/*% 1287 * Conditionally delete RRs. Apply 'predicate' to the RRs 1288 * specified by 'db', 'ver', 'name', and 'type' (which can 1289 * be dns_rdatatype_any to match any type). Delete those 1290 * RRs for which the predicate returns true, and log the 1291 * deletions in 'diff'. 1292 */ 1293static isc_result_t 1294delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver, 1295 dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, 1296 dns_rdata_t *update_rr, dns_diff_t *diff) 1297{ 1298 conditional_delete_ctx_t ctx; 1299 ctx.predicate = predicate; 1300 ctx.db = db; 1301 ctx.ver = ver; 1302 ctx.diff = diff; 1303 ctx.name = name; 1304 ctx.update_rr = update_rr; 1305 return (foreach_rr(db, ver, name, type, covers, 1306 delete_if_action, &ctx)); 1307} 1308 1309/**************************************************************************/ 1310/*% 1311 * Prepare an RR for the addition of the new RR 'ctx->update_rr', 1312 * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting 1313 * the RRs if it is replaced by the new RR or has a conflicting TTL. 1314 * The necessary changes are appended to ctx->del_diff and ctx->add_diff; 1315 * we need to do all deletions before any additions so that we don't run 1316 * into transient states with conflicting TTLs. 1317 */ 1318 1319typedef struct { 1320 dns_db_t *db; 1321 dns_dbversion_t *ver; 1322 dns_diff_t *diff; 1323 dns_name_t *name; 1324 dns_rdata_t *update_rr; 1325 dns_ttl_t update_rr_ttl; 1326 isc_boolean_t ignore_add; 1327 dns_diff_t del_diff; 1328 dns_diff_t add_diff; 1329} add_rr_prepare_ctx_t; 1330 1331static isc_result_t 1332add_rr_prepare_action(void *data, rr_t *rr) { 1333 isc_result_t result = ISC_R_SUCCESS; 1334 add_rr_prepare_ctx_t *ctx = data; 1335 dns_difftuple_t *tuple = NULL; 1336 isc_boolean_t equal; 1337 1338 /* 1339 * If the update RR is a "duplicate" of the update RR, 1340 * the update should be silently ignored. 1341 */ 1342 equal = ISC_TF(dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0); 1343 if (equal && rr->ttl == ctx->update_rr_ttl) { 1344 ctx->ignore_add = ISC_TRUE; 1345 return (ISC_R_SUCCESS); 1346 } 1347 1348 /* 1349 * If this RR is "equal" to the update RR, it should 1350 * be deleted before the update RR is added. 1351 */ 1352 if (replaces_p(ctx->update_rr, &rr->rdata)) { 1353 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, 1354 ctx->name, rr->ttl, &rr->rdata, 1355 &tuple)); 1356 dns_diff_append(&ctx->del_diff, &tuple); 1357 return (ISC_R_SUCCESS); 1358 } 1359 1360 /* 1361 * If this RR differs in TTL from the update RR, 1362 * its TTL must be adjusted. 1363 */ 1364 if (rr->ttl != ctx->update_rr_ttl) { 1365 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, 1366 ctx->name, rr->ttl, &rr->rdata, 1367 &tuple)); 1368 dns_diff_append(&ctx->del_diff, &tuple); 1369 if (!equal) { 1370 CHECK(dns_difftuple_create(ctx->add_diff.mctx, 1371 DNS_DIFFOP_ADD, ctx->name, 1372 ctx->update_rr_ttl, 1373 &rr->rdata, &tuple)); 1374 dns_diff_append(&ctx->add_diff, &tuple); 1375 } 1376 } 1377 failure: 1378 return (result); 1379} 1380 1381/**************************************************************************/ 1382/* 1383 * Miscellaneous subroutines. 1384 */ 1385 1386/*% 1387 * Extract a single update RR from 'section' of dynamic update message 1388 * 'msg', with consistency checking. 1389 * 1390 * Stores the owner name, rdata, and TTL of the update RR at 'name', 1391 * 'rdata', and 'ttl', respectively. 1392 */ 1393static void 1394get_current_rr(dns_message_t *msg, dns_section_t section, 1395 dns_rdataclass_t zoneclass, dns_name_t **name, 1396 dns_rdata_t *rdata, dns_rdatatype_t *covers, 1397 dns_ttl_t *ttl, dns_rdataclass_t *update_class) 1398{ 1399 dns_rdataset_t *rdataset; 1400 isc_result_t result; 1401 dns_message_currentname(msg, section, name); 1402 rdataset = ISC_LIST_HEAD((*name)->list); 1403 INSIST(rdataset != NULL); 1404 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); 1405 *covers = rdataset->covers; 1406 *ttl = rdataset->ttl; 1407 result = dns_rdataset_first(rdataset); 1408 INSIST(result == ISC_R_SUCCESS); 1409 dns_rdataset_current(rdataset, rdata); 1410 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); 1411 *update_class = rdata->rdclass; 1412 rdata->rdclass = zoneclass; 1413} 1414 1415/*% 1416 * Increment the SOA serial number of database 'db', version 'ver'. 1417 * Replace the SOA record in the database, and log the 1418 * change in 'diff'. 1419 */ 1420 1421 /* 1422 * XXXRTH Failures in this routine will be worth logging, when 1423 * we have a logging system. Failure to find the zonename 1424 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR(). 1425 */ 1426 1427static isc_result_t 1428increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver, 1429 dns_diff_t *diff, isc_mem_t *mctx) 1430{ 1431 dns_difftuple_t *deltuple = NULL; 1432 dns_difftuple_t *addtuple = NULL; 1433 isc_uint32_t serial; 1434 isc_result_t result; 1435 1436 CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); 1437 CHECK(dns_difftuple_copy(deltuple, &addtuple)); 1438 addtuple->op = DNS_DIFFOP_ADD; 1439 1440 serial = dns_soa_getserial(&addtuple->rdata); 1441 1442 /* RFC1982 */ 1443 serial = (serial + 1) & 0xFFFFFFFF; 1444 if (serial == 0) 1445 serial = 1; 1446 1447 dns_soa_setserial(serial, &addtuple->rdata); 1448 CHECK(do_one_tuple(&deltuple, db, ver, diff)); 1449 CHECK(do_one_tuple(&addtuple, db, ver, diff)); 1450 result = ISC_R_SUCCESS; 1451 1452 failure: 1453 if (addtuple != NULL) 1454 dns_difftuple_free(&addtuple); 1455 if (deltuple != NULL) 1456 dns_difftuple_free(&deltuple); 1457 return (result); 1458} 1459 1460/*% 1461 * Check that the new SOA record at 'update_rdata' does not 1462 * illegally cause the SOA serial number to decrease or stay 1463 * unchanged relative to the existing SOA in 'db'. 1464 * 1465 * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not. 1466 * 1467 * William King points out that RFC2136 is inconsistent about 1468 * the case where the serial number stays unchanged: 1469 * 1470 * section 3.4.2.2 requires a server to ignore a SOA update request 1471 * if the serial number on the update SOA is less_than_or_equal to 1472 * the zone SOA serial. 1473 * 1474 * section 3.6 requires a server to ignore a SOA update request if 1475 * the serial is less_than the zone SOA serial. 1476 * 1477 * Paul says 3.4.2.2 is correct. 1478 * 1479 */ 1480static isc_result_t 1481check_soa_increment(dns_db_t *db, dns_dbversion_t *ver, 1482 dns_rdata_t *update_rdata, isc_boolean_t *ok) 1483{ 1484 isc_uint32_t db_serial; 1485 isc_uint32_t update_serial; 1486 isc_result_t result; 1487 1488 update_serial = dns_soa_getserial(update_rdata); 1489 1490 result = dns_db_getsoaserial(db, ver, &db_serial); 1491 if (result != ISC_R_SUCCESS) 1492 return (result); 1493 1494 if (DNS_SERIAL_GE(db_serial, update_serial)) { 1495 *ok = ISC_FALSE; 1496 } else { 1497 *ok = ISC_TRUE; 1498 } 1499 1500 return (ISC_R_SUCCESS); 1501 1502} 1503 1504/**************************************************************************/ 1505/* 1506 * Incremental updating of NSECs and RRSIGs. 1507 */ 1508 1509/*% 1510 * We abuse the dns_diff_t type to represent a set of domain names 1511 * affected by the update. 1512 */ 1513static isc_result_t 1514namelist_append_name(dns_diff_t *list, dns_name_t *name) { 1515 isc_result_t result; 1516 dns_difftuple_t *tuple = NULL; 1517 static dns_rdata_t dummy_rdata = DNS_RDATA_INIT; 1518 1519 CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0, 1520 &dummy_rdata, &tuple)); 1521 dns_diff_append(list, &tuple); 1522 failure: 1523 return (result); 1524} 1525 1526static isc_result_t 1527namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected) 1528{ 1529 isc_result_t result; 1530 dns_fixedname_t fixedname; 1531 dns_name_t *child; 1532 dns_dbiterator_t *dbit = NULL; 1533 1534 dns_fixedname_init(&fixedname); 1535 child = dns_fixedname_name(&fixedname); 1536 1537 CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit)); 1538 1539 for (result = dns_dbiterator_seek(dbit, name); 1540 result == ISC_R_SUCCESS; 1541 result = dns_dbiterator_next(dbit)) 1542 { 1543 dns_dbnode_t *node = NULL; 1544 CHECK(dns_dbiterator_current(dbit, &node, child)); 1545 dns_db_detachnode(db, &node); 1546 if (! dns_name_issubdomain(child, name)) 1547 break; 1548 CHECK(namelist_append_name(affected, child)); 1549 } 1550 if (result == ISC_R_NOMORE) 1551 result = ISC_R_SUCCESS; 1552 failure: 1553 if (dbit != NULL) 1554 dns_dbiterator_destroy(&dbit); 1555 return (result); 1556} 1557 1558 1559 1560/*% 1561 * Helper function for non_nsec_rrset_exists(). 1562 */ 1563static isc_result_t 1564is_non_nsec_action(void *data, dns_rdataset_t *rrset) { 1565 UNUSED(data); 1566 if (!(rrset->type == dns_rdatatype_nsec || 1567 rrset->type == dns_rdatatype_nsec3 || 1568 (rrset->type == dns_rdatatype_rrsig && 1569 (rrset->covers == dns_rdatatype_nsec || 1570 rrset->covers == dns_rdatatype_nsec3)))) 1571 return (ISC_R_EXISTS); 1572 return (ISC_R_SUCCESS); 1573} 1574 1575/*% 1576 * Check whether there is an rrset other than a NSEC or RRSIG NSEC, 1577 * i.e., anything that justifies the continued existence of a name 1578 * after a secure update. 1579 * 1580 * If such an rrset exists, set '*exists' to ISC_TRUE. 1581 * Otherwise, set it to ISC_FALSE. 1582 */ 1583static isc_result_t 1584non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 1585 dns_name_t *name, isc_boolean_t *exists) 1586{ 1587 isc_result_t result; 1588 result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL); 1589 RETURN_EXISTENCE_FLAG; 1590} 1591 1592/*% 1593 * A comparison function for sorting dns_diff_t:s by name. 1594 */ 1595static int 1596name_order(const void *av, const void *bv) { 1597 dns_difftuple_t const * const *ap = av; 1598 dns_difftuple_t const * const *bp = bv; 1599 dns_difftuple_t const *a = *ap; 1600 dns_difftuple_t const *b = *bp; 1601 return (dns_name_compare(&a->name, &b->name)); 1602} 1603 1604static isc_result_t 1605uniqify_name_list(dns_diff_t *list) { 1606 isc_result_t result; 1607 dns_difftuple_t *p, *q; 1608 1609 CHECK(dns_diff_sort(list, name_order)); 1610 1611 p = ISC_LIST_HEAD(list->tuples); 1612 while (p != NULL) { 1613 do { 1614 q = ISC_LIST_NEXT(p, link); 1615 if (q == NULL || ! dns_name_equal(&p->name, &q->name)) 1616 break; 1617 ISC_LIST_UNLINK(list->tuples, q, link); 1618 dns_difftuple_free(&q); 1619 } while (1); 1620 p = ISC_LIST_NEXT(p, link); 1621 } 1622 failure: 1623 return (result); 1624} 1625 1626static isc_result_t 1627is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1628 isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure) 1629{ 1630 isc_result_t result; 1631 dns_fixedname_t foundname; 1632 dns_fixedname_init(&foundname); 1633 result = dns_db_find(db, name, ver, dns_rdatatype_any, 1634 DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD, 1635 (isc_stdtime_t) 0, NULL, 1636 dns_fixedname_name(&foundname), 1637 NULL, NULL); 1638 if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) { 1639 *flag = ISC_TRUE; 1640 *cut = ISC_FALSE; 1641 if (unsecure != NULL) 1642 *unsecure = ISC_FALSE; 1643 return (ISC_R_SUCCESS); 1644 } else if (result == DNS_R_ZONECUT) { 1645 *flag = ISC_TRUE; 1646 *cut = ISC_TRUE; 1647 if (unsecure != NULL) { 1648 /* 1649 * We are at the zonecut. Check to see if there 1650 * is a DS RRset. 1651 */ 1652 if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0, 1653 (isc_stdtime_t) 0, NULL, 1654 dns_fixedname_name(&foundname), 1655 NULL, NULL) == DNS_R_NXRRSET) 1656 *unsecure = ISC_TRUE; 1657 else 1658 *unsecure = ISC_FALSE; 1659 } 1660 return (ISC_R_SUCCESS); 1661 } else if (result == DNS_R_GLUE || result == DNS_R_DNAME || 1662 result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) { 1663 *flag = ISC_FALSE; 1664 *cut = ISC_FALSE; 1665 if (unsecure != NULL) 1666 *unsecure = ISC_FALSE; 1667 return (ISC_R_SUCCESS); 1668 } else { 1669 /* 1670 * Silence compiler. 1671 */ 1672 *flag = ISC_FALSE; 1673 *cut = ISC_FALSE; 1674 if (unsecure != NULL) 1675 *unsecure = ISC_FALSE; 1676 return (result); 1677 } 1678} 1679 1680/*% 1681 * Find the next/previous name that has a NSEC record. 1682 * In other words, skip empty database nodes and names that 1683 * have had their NSECs removed because they are obscured by 1684 * a zone cut. 1685 */ 1686static isc_result_t 1687next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1688 dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname, 1689 isc_boolean_t forward) 1690{ 1691 isc_result_t result; 1692 dns_dbiterator_t *dbit = NULL; 1693 isc_boolean_t has_nsec = ISC_FALSE; 1694 unsigned int wraps = 0; 1695 isc_boolean_t secure = dns_db_issecure(db); 1696 1697 CHECK(dns_db_createiterator(db, 0, &dbit)); 1698 1699 CHECK(dns_dbiterator_seek(dbit, oldname)); 1700 do { 1701 dns_dbnode_t *node = NULL; 1702 1703 if (forward) 1704 result = dns_dbiterator_next(dbit); 1705 else 1706 result = dns_dbiterator_prev(dbit); 1707 if (result == ISC_R_NOMORE) { 1708 /* 1709 * Wrap around. 1710 */ 1711 if (forward) 1712 CHECK(dns_dbiterator_first(dbit)); 1713 else 1714 CHECK(dns_dbiterator_last(dbit)); 1715 wraps++; 1716 if (wraps == 2) { 1717 update_log(client, zone, ISC_LOG_ERROR, 1718 "secure zone with no NSECs"); 1719 result = DNS_R_BADZONE; 1720 goto failure; 1721 } 1722 } 1723 CHECK(dns_dbiterator_current(dbit, &node, newname)); 1724 dns_db_detachnode(db, &node); 1725 1726 /* 1727 * The iterator may hold the tree lock, and 1728 * rrset_exists() calls dns_db_findnode() which 1729 * may try to reacquire it. To avoid deadlock 1730 * we must pause the iterator first. 1731 */ 1732 CHECK(dns_dbiterator_pause(dbit)); 1733 if (secure) { 1734 CHECK(rrset_exists(db, ver, newname, 1735 dns_rdatatype_nsec, 0, &has_nsec)); 1736 } else { 1737 dns_fixedname_t ffound; 1738 dns_name_t *found; 1739 dns_fixedname_init(&ffound); 1740 found = dns_fixedname_name(&ffound); 1741 result = dns_db_find(db, newname, ver, 1742 dns_rdatatype_soa, 1743 DNS_DBFIND_NOWILD, 0, NULL, found, 1744 NULL, NULL); 1745 if (result == ISC_R_SUCCESS || 1746 result == DNS_R_EMPTYNAME || 1747 result == DNS_R_NXRRSET || 1748 result == DNS_R_CNAME || 1749 (result == DNS_R_DELEGATION && 1750 dns_name_equal(newname, found))) { 1751 has_nsec = ISC_TRUE; 1752 result = ISC_R_SUCCESS; 1753 } else if (result != DNS_R_NXDOMAIN) 1754 break; 1755 } 1756 } while (! has_nsec); 1757 failure: 1758 if (dbit != NULL) 1759 dns_dbiterator_destroy(&dbit); 1760 1761 return (result); 1762} 1763 1764/*% 1765 * Add a NSEC record for "name", recording the change in "diff". 1766 * The existing NSEC is removed. 1767 */ 1768static isc_result_t 1769add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1770 dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl, 1771 dns_diff_t *diff) 1772{ 1773 isc_result_t result; 1774 dns_dbnode_t *node = NULL; 1775 unsigned char buffer[DNS_NSEC_BUFFERSIZE]; 1776 dns_rdata_t rdata = DNS_RDATA_INIT; 1777 dns_difftuple_t *tuple = NULL; 1778 dns_fixedname_t fixedname; 1779 dns_name_t *target; 1780 1781 dns_fixedname_init(&fixedname); 1782 target = dns_fixedname_name(&fixedname); 1783 1784 /* 1785 * Find the successor name, aka NSEC target. 1786 */ 1787 CHECK(next_active(client, zone, db, ver, name, target, ISC_TRUE)); 1788 1789 /* 1790 * Create the NSEC RDATA. 1791 */ 1792 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node)); 1793 dns_rdata_init(&rdata); 1794 CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata)); 1795 dns_db_detachnode(db, &node); 1796 1797 /* 1798 * Delete the old NSEC and record the change. 1799 */ 1800 CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0, 1801 NULL, diff)); 1802 /* 1803 * Add the new NSEC and record the change. 1804 */ 1805 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 1806 nsecttl, &rdata, &tuple)); 1807 CHECK(do_one_tuple(&tuple, db, ver, diff)); 1808 INSIST(tuple == NULL); 1809 1810 failure: 1811 if (node != NULL) 1812 dns_db_detachnode(db, &node); 1813 return (result); 1814} 1815 1816/*% 1817 * Add a placeholder NSEC record for "name", recording the change in "diff". 1818 */ 1819static isc_result_t 1820add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1821 dns_diff_t *diff) 1822{ 1823 isc_result_t result; 1824 dns_difftuple_t *tuple = NULL; 1825 isc_region_t r; 1826 unsigned char data[1] = { 0 }; /* The root domain, no bits. */ 1827 dns_rdata_t rdata = DNS_RDATA_INIT; 1828 1829 r.base = data; 1830 r.length = si…
Large files files are truncated, but you can click here to view the full file