update.c revision 1.6
1/* $NetBSD: update.c,v 1.6 2019/11/27 05:48:43 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14#include <config.h> 15 16#include <stdbool.h> 17#include <inttypes.h> 18 19#include <isc/netaddr.h> 20#include <isc/print.h> 21#include <isc/serial.h> 22#include <isc/stats.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/keyvalues.h> 35#include <dns/message.h> 36#include <dns/nsec.h> 37#include <dns/nsec3.h> 38#include <dns/private.h> 39#include <dns/rdataclass.h> 40#include <dns/rdataset.h> 41#include <dns/rdatasetiter.h> 42#include <dns/rdatastruct.h> 43#include <dns/rdatatype.h> 44#include <dns/soa.h> 45#include <dns/ssu.h> 46#include <dns/tsig.h> 47#include <dns/update.h> 48#include <dns/view.h> 49#include <dns/zone.h> 50#include <dns/zt.h> 51 52#include <ns/client.h> 53#include <ns/interfacemgr.h> 54#include <ns/log.h> 55#include <ns/server.h> 56#include <ns/stats.h> 57#include <ns/update.h> 58 59#include <ns/pfilter.h> 60 61/*! \file 62 * \brief 63 * This module implements dynamic update as in RFC2136. 64 */ 65 66/* 67 * XXX TODO: 68 * - document strict minimality 69 */ 70 71/**************************************************************************/ 72 73/*% 74 * Log level for tracing dynamic update protocol requests. 75 */ 76#define LOGLEVEL_PROTOCOL ISC_LOG_INFO 77 78/*% 79 * Log level for low-level debug tracing. 80 */ 81#define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8) 82 83/*% 84 * Check an operation for failure. These macros all assume that 85 * the function using them has a 'result' variable and a 'failure' 86 * label. 87 */ 88#define CHECK(op) \ 89 do { result = (op); \ 90 if (result != ISC_R_SUCCESS) goto failure; \ 91 } while (0) 92 93/*% 94 * Fail unconditionally with result 'code', which must not 95 * be ISC_R_SUCCESS. The reason for failure presumably has 96 * been logged already. 97 * 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 102#define FAIL(code) \ 103 do { \ 104 result = (code); \ 105 if (result != ISC_R_SUCCESS) goto failure; \ 106 } while (0) 107 108/*% 109 * Fail unconditionally and log as a client error. 110 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 111 * from complaining about "end-of-loop code not reached". 112 */ 113#define FAILC(code, msg) \ 114 do { \ 115 const char *_what = "failed"; \ 116 result = (code); \ 117 switch (result) { \ 118 case DNS_R_NXDOMAIN: \ 119 case DNS_R_YXDOMAIN: \ 120 case DNS_R_YXRRSET: \ 121 case DNS_R_NXRRSET: \ 122 _what = "unsuccessful"; \ 123 } \ 124 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 125 "update %s: %s (%s)", _what, \ 126 msg, isc_result_totext(result)); \ 127 if (result != ISC_R_SUCCESS) goto failure; \ 128 } while (0) 129#define PREREQFAILC(code, msg) \ 130 do { \ 131 inc_stats(client, zone, ns_statscounter_updatebadprereq); \ 132 FAILC(code, msg); \ 133 } while (0) 134 135#define FAILN(code, name, msg) \ 136 do { \ 137 const char *_what = "failed"; \ 138 result = (code); \ 139 switch (result) { \ 140 case DNS_R_NXDOMAIN: \ 141 case DNS_R_YXDOMAIN: \ 142 case DNS_R_YXRRSET: \ 143 case DNS_R_NXRRSET: \ 144 _what = "unsuccessful"; \ 145 } \ 146 if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) { \ 147 char _nbuf[DNS_NAME_FORMATSIZE]; \ 148 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 149 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 150 "update %s: %s: %s (%s)", _what, _nbuf, \ 151 msg, isc_result_totext(result)); \ 152 } \ 153 if (result != ISC_R_SUCCESS) goto failure; \ 154 } while (0) 155#define PREREQFAILN(code, name, msg) \ 156 do { \ 157 inc_stats(client, zone, ns_statscounter_updatebadprereq); \ 158 FAILN(code, name, msg); \ 159 } while (0) 160 161#define FAILNT(code, name, type, msg) \ 162 do { \ 163 const char *_what = "failed"; \ 164 result = (code); \ 165 switch (result) { \ 166 case DNS_R_NXDOMAIN: \ 167 case DNS_R_YXDOMAIN: \ 168 case DNS_R_YXRRSET: \ 169 case DNS_R_NXRRSET: \ 170 _what = "unsuccessful"; \ 171 } \ 172 if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) { \ 173 char _nbuf[DNS_NAME_FORMATSIZE]; \ 174 char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \ 175 dns_name_format(name, _nbuf, sizeof(_nbuf)); \ 176 dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \ 177 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 178 "update %s: %s/%s: %s (%s)", \ 179 _what, _nbuf, _tbuf, msg, \ 180 isc_result_totext(result)); \ 181 } \ 182 if (result != ISC_R_SUCCESS) goto failure; \ 183 } while (0) 184#define PREREQFAILNT(code, name, type, msg) \ 185 do { \ 186 inc_stats(client, zone, ns_statscounter_updatebadprereq); \ 187 FAILNT(code, name, type, msg); \ 188 } while (0) 189 190/*% 191 * Fail unconditionally and log as a server error. 192 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler 193 * from complaining about "end-of-loop code not reached". 194 */ 195#define FAILS(code, msg) \ 196 do { \ 197 result = (code); \ 198 update_log(client, zone, LOGLEVEL_PROTOCOL, \ 199 "error: %s: %s", \ 200 msg, isc_result_totext(result)); \ 201 if (result != ISC_R_SUCCESS) goto failure; \ 202 } while (0) 203 204/* 205 * Return TRUE if NS_CLIENTATTR_TCP is set in the attributes other FALSE. 206 */ 207#define TCPCLIENT(client) (((client)->attributes & NS_CLIENTATTR_TCP) != 0) 208 209/**************************************************************************/ 210 211typedef struct rr rr_t; 212 213struct rr { 214 /* dns_name_t name; */ 215 uint32_t ttl; 216 dns_rdata_t rdata; 217}; 218 219typedef struct update_event update_event_t; 220 221struct update_event { 222 ISC_EVENT_COMMON(update_event_t); 223 dns_zone_t *zone; 224 isc_result_t result; 225 dns_message_t *answer; 226}; 227 228/*% 229 * Prepare an RR for the addition of the new RR 'ctx->update_rr', 230 * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting 231 * the RRs if it is replaced by the new RR or has a conflicting TTL. 232 * The necessary changes are appended to ctx->del_diff and ctx->add_diff; 233 * we need to do all deletions before any additions so that we don't run 234 * into transient states with conflicting TTLs. 235 */ 236 237typedef struct { 238 dns_db_t *db; 239 dns_dbversion_t *ver; 240 dns_diff_t *diff; 241 dns_name_t *name; 242 dns_name_t *oldname; 243 dns_rdata_t *update_rr; 244 dns_ttl_t update_rr_ttl; 245 bool ignore_add; 246 dns_diff_t del_diff; 247 dns_diff_t add_diff; 248} add_rr_prepare_ctx_t; 249 250/**************************************************************************/ 251/* 252 * Forward declarations. 253 */ 254 255static void update_action(isc_task_t *task, isc_event_t *event); 256static void updatedone_action(isc_task_t *task, isc_event_t *event); 257static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone); 258static void forward_done(isc_task_t *task, isc_event_t *event); 259static isc_result_t add_rr_prepare_action(void *data, rr_t *rr); 260 261/**************************************************************************/ 262 263static void 264update_log(ns_client_t *client, dns_zone_t *zone, 265 int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); 266 267static void 268update_log(ns_client_t *client, dns_zone_t *zone, 269 int level, const char *fmt, ...) 270{ 271 va_list ap; 272 char message[4096]; 273 char namebuf[DNS_NAME_FORMATSIZE]; 274 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 275 276 if (client == NULL) { 277 return; 278 } 279 280 if (isc_log_wouldlog(ns_lctx, level) == false) { 281 return; 282 } 283 284 va_start(ap, fmt); 285 vsnprintf(message, sizeof(message), fmt, ap); 286 va_end(ap); 287 288 if (zone != NULL) { 289 dns_name_format(dns_zone_getorigin(zone), namebuf, 290 sizeof(namebuf)); 291 dns_rdataclass_format(dns_zone_getclass(zone), classbuf, 292 sizeof(classbuf)); 293 294 ns_client_log(client, NS_LOGCATEGORY_UPDATE, 295 NS_LOGMODULE_UPDATE, 296 level, "updating zone '%s/%s': %s", 297 namebuf, classbuf, message); 298 } else { 299 ns_client_log(client, NS_LOGCATEGORY_UPDATE, 300 NS_LOGMODULE_UPDATE, 301 level, "%s", message); 302 } 303 304} 305 306static void 307update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) { 308 update_log(arg, zone, level, "%s", message); 309} 310 311/*% 312 * Increment updated-related statistics counters. 313 */ 314static inline void 315inc_stats(ns_client_t *client, dns_zone_t *zone, isc_statscounter_t counter) { 316 ns_stats_increment(client->sctx->nsstats, counter); 317 318 if (zone != NULL) { 319 isc_stats_t *zonestats = dns_zone_getrequeststats(zone); 320 if (zonestats != NULL) 321 isc_stats_increment(zonestats, counter); 322 } 323} 324 325/*% 326 * Check if we could have queried for the contents of this zone or 327 * if the zone is potentially updateable. 328 * If the zone can potentially be updated and the check failed then 329 * log a error otherwise we log a informational message. 330 */ 331static isc_result_t 332checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename, 333 dns_acl_t *updateacl, dns_ssutable_t *ssutable) 334{ 335 char namebuf[DNS_NAME_FORMATSIZE]; 336 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 337 int level; 338 isc_result_t result; 339 340 result = ns_client_checkaclsilent(client, NULL, queryacl, true); 341 if (result != ISC_R_SUCCESS) { 342 pfilter_notify(result, client, "queryacl"); 343 dns_name_format(zonename, namebuf, sizeof(namebuf)); 344 dns_rdataclass_format(client->view->rdclass, classbuf, 345 sizeof(classbuf)); 346 347 level = (updateacl == NULL && ssutable == NULL) ? 348 ISC_LOG_INFO : ISC_LOG_ERROR; 349 350 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 351 NS_LOGMODULE_UPDATE, level, 352 "update '%s/%s' denied due to allow-query", 353 namebuf, classbuf); 354 } else if (updateacl == NULL && ssutable == NULL) { 355 pfilter_notify(result, client, "updateacl"); 356 dns_name_format(zonename, namebuf, sizeof(namebuf)); 357 dns_rdataclass_format(client->view->rdclass, classbuf, 358 sizeof(classbuf)); 359 360 result = DNS_R_REFUSED; 361 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 362 NS_LOGMODULE_UPDATE, ISC_LOG_INFO, 363 "update '%s/%s' denied", namebuf, classbuf); 364 } 365 return (result); 366} 367 368/*% 369 * Override the default acl logging when checking whether a client 370 * can update the zone or whether we can forward the request to the 371 * master based on IP address. 372 * 373 * 'message' contains the type of operation that is being attempted. 374 * 'slave' indicates if this is a slave zone. If 'acl' is NULL then 375 * log at debug=3. 376 * If the zone has no access controls configured ('acl' == NULL && 377 * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise 378 * at error. 379 * 380 * If the request was signed log that we received it. 381 */ 382static isc_result_t 383checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message, 384 dns_name_t *zonename, bool slave, 385 bool has_ssutable) 386{ 387 char namebuf[DNS_NAME_FORMATSIZE]; 388 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 389 int level = ISC_LOG_ERROR; 390 const char *msg = "denied"; 391 isc_result_t result; 392 393 if (slave && acl == NULL) { 394 result = DNS_R_NOTIMP; 395 level = ISC_LOG_DEBUG(3); 396 msg = "disabled"; 397 } else { 398 result = ns_client_checkaclsilent(client, NULL, acl, false); 399 pfilter_notify(result, client, "updateacl"); 400 if (result == ISC_R_SUCCESS) { 401 level = ISC_LOG_DEBUG(3); 402 msg = "approved"; 403 } else if (acl == NULL && !has_ssutable) { 404 level = ISC_LOG_INFO; 405 } 406 } 407 408 if (client->signer != NULL) { 409 dns_name_format(client->signer, namebuf, sizeof(namebuf)); 410 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 411 NS_LOGMODULE_UPDATE, ISC_LOG_INFO, 412 "signer \"%s\" %s", namebuf, msg); 413 } 414 415 dns_name_format(zonename, namebuf, sizeof(namebuf)); 416 dns_rdataclass_format(client->view->rdclass, classbuf, 417 sizeof(classbuf)); 418 419 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY, 420 NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s", 421 message, namebuf, classbuf, msg); 422 return (result); 423} 424 425/*% 426 * Update a single RR in version 'ver' of 'db' and log the 427 * update in 'diff'. 428 * 429 * Ensures: 430 * \li '*tuple' == NULL. Either the tuple is freed, or its 431 * ownership has been transferred to the diff. 432 */ 433static isc_result_t 434do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver, 435 dns_diff_t *diff) 436{ 437 dns_diff_t temp_diff; 438 isc_result_t result; 439 440 /* 441 * Create a singleton diff. 442 */ 443 dns_diff_init(diff->mctx, &temp_diff); 444 ISC_LIST_APPEND(temp_diff.tuples, *tuple, link); 445 446 /* 447 * Apply it to the database. 448 */ 449 result = dns_diff_apply(&temp_diff, db, ver); 450 ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link); 451 if (result != ISC_R_SUCCESS) { 452 dns_difftuple_free(tuple); 453 return (result); 454 } 455 456 /* 457 * Merge it into the current pending journal entry. 458 */ 459 dns_diff_appendminimal(diff, tuple); 460 461 /* 462 * Do not clear temp_diff. 463 */ 464 return (ISC_R_SUCCESS); 465} 466 467/*% 468 * Perform the updates in 'updates' in version 'ver' of 'db' and log the 469 * update in 'diff'. 470 * 471 * Ensures: 472 * \li 'updates' is empty. 473 */ 474static isc_result_t 475do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver, 476 dns_diff_t *diff) 477{ 478 isc_result_t result; 479 while (! ISC_LIST_EMPTY(updates->tuples)) { 480 dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples); 481 ISC_LIST_UNLINK(updates->tuples, t, link); 482 CHECK(do_one_tuple(&t, db, ver, diff)); 483 } 484 return (ISC_R_SUCCESS); 485 486 failure: 487 dns_diff_clear(diff); 488 return (result); 489} 490 491static isc_result_t 492update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, 493 dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl, 494 dns_rdata_t *rdata) 495{ 496 dns_difftuple_t *tuple = NULL; 497 isc_result_t result; 498 result = dns_difftuple_create(diff->mctx, op, 499 name, ttl, rdata, &tuple); 500 if (result != ISC_R_SUCCESS) 501 return (result); 502 return (do_one_tuple(&tuple, db, ver, diff)); 503} 504 505/**************************************************************************/ 506/* 507 * Callback-style iteration over rdatasets and rdatas. 508 * 509 * foreach_rrset() can be used to iterate over the RRsets 510 * of a name and call a callback function with each 511 * one. Similarly, foreach_rr() can be used to iterate 512 * over the individual RRs at name, optionally restricted 513 * to RRs of a given type. 514 * 515 * The callback functions are called "actions" and take 516 * two arguments: a void pointer for passing arbitrary 517 * context information, and a pointer to the current RRset 518 * or RR. By convention, their names end in "_action". 519 */ 520 521/* 522 * XXXRTH We might want to make this public somewhere in libdns. 523 */ 524 525/*% 526 * Function type for foreach_rrset() iterator actions. 527 */ 528typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset); 529 530/*% 531 * Function type for foreach_rr() iterator actions. 532 */ 533typedef isc_result_t rr_func(void *data, rr_t *rr); 534 535/*% 536 * Internal context struct for foreach_node_rr(). 537 */ 538typedef struct { 539 rr_func * rr_action; 540 void * rr_action_data; 541} foreach_node_rr_ctx_t; 542 543/*% 544 * Internal helper function for foreach_node_rr(). 545 */ 546static isc_result_t 547foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) { 548 isc_result_t result; 549 foreach_node_rr_ctx_t *ctx = data; 550 for (result = dns_rdataset_first(rdataset); 551 result == ISC_R_SUCCESS; 552 result = dns_rdataset_next(rdataset)) 553 { 554 rr_t rr = { 0, DNS_RDATA_INIT }; 555 556 dns_rdataset_current(rdataset, &rr.rdata); 557 rr.ttl = rdataset->ttl; 558 result = (*ctx->rr_action)(ctx->rr_action_data, &rr); 559 if (result != ISC_R_SUCCESS) 560 return (result); 561 } 562 if (result != ISC_R_NOMORE) 563 return (result); 564 return (ISC_R_SUCCESS); 565} 566 567/*% 568 * For each rdataset of 'name' in 'ver' of 'db', call 'action' 569 * with the rdataset and 'action_data' as arguments. If the name 570 * does not exist, do nothing. 571 * 572 * If 'action' returns an error, abort iteration and return the error. 573 */ 574static isc_result_t 575foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 576 rrset_func *action, void *action_data) 577{ 578 isc_result_t result; 579 dns_dbnode_t *node; 580 dns_rdatasetiter_t *iter; 581 dns_clientinfomethods_t cm; 582 dns_clientinfo_t ci; 583 dns_dbversion_t *oldver = NULL; 584 585 dns_clientinfomethods_init(&cm, ns_client_sourceip); 586 587 /* 588 * Only set the clientinfo 'versionp' if the new version is 589 * different from the current version 590 */ 591 dns_db_currentversion(db, &oldver); 592 dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL); 593 dns_db_closeversion(db, &oldver, false); 594 595 node = NULL; 596 result = dns_db_findnodeext(db, name, false, &cm, &ci, &node); 597 if (result == ISC_R_NOTFOUND) 598 return (ISC_R_SUCCESS); 599 if (result != ISC_R_SUCCESS) 600 return (result); 601 602 iter = NULL; 603 result = dns_db_allrdatasets(db, node, ver, 604 (isc_stdtime_t) 0, &iter); 605 if (result != ISC_R_SUCCESS) 606 goto cleanup_node; 607 608 for (result = dns_rdatasetiter_first(iter); 609 result == ISC_R_SUCCESS; 610 result = dns_rdatasetiter_next(iter)) 611 { 612 dns_rdataset_t rdataset; 613 614 dns_rdataset_init(&rdataset); 615 dns_rdatasetiter_current(iter, &rdataset); 616 617 result = (*action)(action_data, &rdataset); 618 619 dns_rdataset_disassociate(&rdataset); 620 if (result != ISC_R_SUCCESS) 621 goto cleanup_iterator; 622 } 623 if (result == ISC_R_NOMORE) 624 result = ISC_R_SUCCESS; 625 626 cleanup_iterator: 627 dns_rdatasetiter_destroy(&iter); 628 629 cleanup_node: 630 dns_db_detachnode(db, &node); 631 632 return (result); 633} 634 635/*% 636 * For each RR of 'name' in 'ver' of 'db', call 'action' 637 * with the RR and 'action_data' as arguments. If the name 638 * does not exist, do nothing. 639 * 640 * If 'action' returns an error, abort iteration 641 * and return the error. 642 */ 643static isc_result_t 644foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 645 rr_func *rr_action, void *rr_action_data) 646{ 647 foreach_node_rr_ctx_t ctx; 648 ctx.rr_action = rr_action; 649 ctx.rr_action_data = rr_action_data; 650 return (foreach_rrset(db, ver, name, 651 foreach_node_rr_action, &ctx)); 652} 653 654 655/*% 656 * For each of the RRs specified by 'db', 'ver', 'name', 'type', 657 * (which can be dns_rdatatype_any to match any type), and 'covers', call 658 * 'action' with the RR and 'action_data' as arguments. If the name 659 * does not exist, or if no RRset of the given type exists at the name, 660 * do nothing. 661 * 662 * If 'action' returns an error, abort iteration and return the error. 663 */ 664static isc_result_t 665foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 666 dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action, 667 void *rr_action_data) 668{ 669 670 isc_result_t result; 671 dns_dbnode_t *node; 672 dns_rdataset_t rdataset; 673 dns_clientinfomethods_t cm; 674 dns_clientinfo_t ci; 675 dns_dbversion_t *oldver = NULL; 676 dns_fixedname_t fixed; 677 678 dns_clientinfomethods_init(&cm, ns_client_sourceip); 679 680 /* 681 * Only set the clientinfo 'versionp' if the new version is 682 * different from the current version 683 */ 684 dns_db_currentversion(db, &oldver); 685 dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL); 686 dns_db_closeversion(db, &oldver, false); 687 688 if (type == dns_rdatatype_any) 689 return (foreach_node_rr(db, ver, name, 690 rr_action, rr_action_data)); 691 692 node = NULL; 693 if (type == dns_rdatatype_nsec3 || 694 (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3)) 695 result = dns_db_findnsec3node(db, name, false, &node); 696 else 697 result = dns_db_findnodeext(db, name, false, 698 &cm, &ci, &node); 699 if (result == ISC_R_NOTFOUND) 700 return (ISC_R_SUCCESS); 701 if (result != ISC_R_SUCCESS) 702 return (result); 703 704 dns_rdataset_init(&rdataset); 705 result = dns_db_findrdataset(db, node, ver, type, covers, 706 (isc_stdtime_t) 0, &rdataset, NULL); 707 if (result == ISC_R_NOTFOUND) { 708 result = ISC_R_SUCCESS; 709 goto cleanup_node; 710 } 711 if (result != ISC_R_SUCCESS) 712 goto cleanup_node; 713 714 if (rr_action == add_rr_prepare_action) { 715 add_rr_prepare_ctx_t *ctx = rr_action_data; 716 717 ctx->oldname = dns_fixedname_initname(&fixed); 718 dns_name_copynf(name, ctx->oldname); 719 dns_rdataset_getownercase(&rdataset, ctx->oldname); 720 } 721 722 for (result = dns_rdataset_first(&rdataset); 723 result == ISC_R_SUCCESS; 724 result = dns_rdataset_next(&rdataset)) 725 { 726 rr_t rr = { 0, DNS_RDATA_INIT }; 727 dns_rdataset_current(&rdataset, &rr.rdata); 728 rr.ttl = rdataset.ttl; 729 result = (*rr_action)(rr_action_data, &rr); 730 if (result != ISC_R_SUCCESS) 731 goto cleanup_rdataset; 732 } 733 if (result != ISC_R_NOMORE) 734 goto cleanup_rdataset; 735 result = ISC_R_SUCCESS; 736 737 cleanup_rdataset: 738 dns_rdataset_disassociate(&rdataset); 739 cleanup_node: 740 dns_db_detachnode(db, &node); 741 742 return (result); 743} 744 745/**************************************************************************/ 746/* 747 * Various tests on the database contents (for prerequisites, etc). 748 */ 749 750/*% 751 * Function type for predicate functions that compare a database RR 'db_rr' 752 * against an update RR 'update_rr'. 753 */ 754typedef bool rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr); 755 756/*% 757 * Helper function for rrset_exists(). 758 */ 759static isc_result_t 760rrset_exists_action(void *data, rr_t *rr) { 761 UNUSED(data); 762 UNUSED(rr); 763 return (ISC_R_EXISTS); 764} 765 766/*% 767 * Utility macro for RR existence checking functions. 768 * 769 * If the variable 'result' has the value ISC_R_EXISTS or 770 * ISC_R_SUCCESS, set *exists to true or false, 771 * respectively, and return success. 772 * 773 * If 'result' has any other value, there was a failure. 774 * Return the failure result code and do not set *exists. 775 * 776 * This would be more readable as "do { if ... } while(0)", 777 * but that form generates tons of warnings on Solaris 2.6. 778 */ 779#define RETURN_EXISTENCE_FLAG \ 780 return ((result == ISC_R_EXISTS) ? \ 781 (*exists = true, ISC_R_SUCCESS) : \ 782 ((result == ISC_R_SUCCESS) ? \ 783 (*exists = false, ISC_R_SUCCESS) : \ 784 result)) 785 786/*% 787 * Set '*exists' to true iff an rrset of the given type exists, 788 * to false otherwise. 789 */ 790static isc_result_t 791rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 792 dns_rdatatype_t type, dns_rdatatype_t covers, 793 bool *exists) 794{ 795 isc_result_t result; 796 result = foreach_rr(db, ver, name, type, covers, 797 rrset_exists_action, NULL); 798 RETURN_EXISTENCE_FLAG; 799} 800 801/*% 802 * Helper function for cname_incompatible_rrset_exists. 803 */ 804static isc_result_t 805cname_compatibility_action(void *data, dns_rdataset_t *rrset) { 806 UNUSED(data); 807 if (rrset->type != dns_rdatatype_cname && 808 ! dns_rdatatype_atcname(rrset->type)) 809 { 810 return (ISC_R_EXISTS); 811 } 812 return (ISC_R_SUCCESS); 813} 814 815/*% 816 * Check whether there is an rrset incompatible with adding a CNAME RR, 817 * i.e., anything but another CNAME (which can be replaced) or a 818 * DNSSEC RR (which can coexist). 819 * 820 * If such an incompatible rrset exists, set '*exists' to true. 821 * Otherwise, set it to false. 822 */ 823static isc_result_t 824cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver, 825 dns_name_t *name, bool *exists) { 826 isc_result_t result; 827 result = foreach_rrset(db, ver, name, 828 cname_compatibility_action, NULL); 829 RETURN_EXISTENCE_FLAG; 830} 831 832/*% 833 * Helper function for rr_count(). 834 */ 835static isc_result_t 836count_rr_action(void *data, rr_t *rr) { 837 int *countp = data; 838 UNUSED(rr); 839 (*countp)++; 840 return (ISC_R_SUCCESS); 841} 842 843/*% 844 * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'. 845 */ 846static isc_result_t 847rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 848 dns_rdatatype_t type, dns_rdatatype_t covers, int *countp) 849{ 850 *countp = 0; 851 return (foreach_rr(db, ver, name, type, covers, 852 count_rr_action, countp)); 853} 854 855/*% 856 * Context struct and helper function for name_exists(). 857 */ 858 859static isc_result_t 860name_exists_action(void *data, dns_rdataset_t *rrset) { 861 UNUSED(data); 862 UNUSED(rrset); 863 return (ISC_R_EXISTS); 864} 865 866/*% 867 * Set '*exists' to true iff the given name exists, to false otherwise. 868 */ 869static isc_result_t 870name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 871 bool *exists) 872{ 873 isc_result_t result; 874 result = foreach_rrset(db, ver, name, 875 name_exists_action, NULL); 876 RETURN_EXISTENCE_FLAG; 877} 878 879/* 880 * 'ssu_check_t' is used to pass the arguments to 881 * dns_ssutable_checkrules() to the callback function 882 * ssu_checkrule(). 883 */ 884typedef struct { 885 /* The ownername of the record to be updated. */ 886 dns_name_t *name; 887 888 /* The signature's name if the request was signed. */ 889 dns_name_t *signer; 890 891 /* The address of the client. */ 892 isc_netaddr_t *addr; 893 894 /* The ACL environment */ 895 dns_aclenv_t *aclenv; 896 897 /* Whether the request was sent via TCP. */ 898 bool tcp; 899 900 /* The ssu table to check against. */ 901 dns_ssutable_t *table; 902 903 /* the key used for TKEY requests */ 904 dst_key_t *key; 905} ssu_check_t; 906 907static isc_result_t 908ssu_checkrule(void *data, dns_rdataset_t *rrset) { 909 ssu_check_t *ssuinfo = data; 910 bool result; 911 912 /* 913 * If we're deleting all records, it's ok to delete RRSIG and NSEC even 914 * if we're normally not allowed to. 915 */ 916 if (rrset->type == dns_rdatatype_rrsig || 917 rrset->type == dns_rdatatype_nsec) 918 return (ISC_R_SUCCESS); 919 result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer, 920 ssuinfo->name, ssuinfo->addr, 921 ssuinfo->tcp, ssuinfo->aclenv, 922 rrset->type, ssuinfo->key); 923 return (result == true ? ISC_R_SUCCESS : ISC_R_FAILURE); 924} 925 926static bool 927ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 928 dns_ssutable_t *ssutable, dns_name_t *signer, 929 isc_netaddr_t *addr, dns_aclenv_t *aclenv, bool tcp, 930 dst_key_t *key) 931{ 932 isc_result_t result; 933 ssu_check_t ssuinfo; 934 935 ssuinfo.name = name; 936 ssuinfo.table = ssutable; 937 ssuinfo.signer = signer; 938 ssuinfo.addr = addr; 939 ssuinfo.aclenv = aclenv; 940 ssuinfo.tcp = tcp; 941 ssuinfo.key = key; 942 result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo); 943 return (result == ISC_R_SUCCESS); 944} 945 946/**************************************************************************/ 947/* 948 * Checking of "RRset exists (value dependent)" prerequisites. 949 * 950 * In the RFC2136 section 3.2.5, this is the pseudocode involving 951 * a variable called "temp", a mapping of <name, type> tuples to rrsets. 952 * 953 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t" 954 * where each tuple has op==DNS_DIFFOP_EXISTS. 955 */ 956 957 958/*% 959 * Append a tuple asserting the existence of the RR with 960 * 'name' and 'rdata' to 'diff'. 961 */ 962static isc_result_t 963temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) { 964 isc_result_t result; 965 dns_difftuple_t *tuple = NULL; 966 967 REQUIRE(DNS_DIFF_VALID(diff)); 968 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS, 969 name, 0, rdata, &tuple)); 970 ISC_LIST_APPEND(diff->tuples, tuple, link); 971 failure: 972 return (result); 973} 974 975/*% 976 * Compare two rdatasets represented as sorted lists of tuples. 977 * All list elements must have the same owner name and type. 978 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset) 979 * if not. 980 */ 981static isc_result_t 982temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) { 983 for (;;) { 984 if (a == NULL || b == NULL) 985 break; 986 INSIST(a->op == DNS_DIFFOP_EXISTS && 987 b->op == DNS_DIFFOP_EXISTS); 988 INSIST(a->rdata.type == b->rdata.type); 989 INSIST(dns_name_equal(&a->name, &b->name)); 990 if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0) 991 return (DNS_R_NXRRSET); 992 a = ISC_LIST_NEXT(a, link); 993 b = ISC_LIST_NEXT(b, link); 994 } 995 if (a != NULL || b != NULL) 996 return (DNS_R_NXRRSET); 997 return (ISC_R_SUCCESS); 998} 999 1000/*% 1001 * A comparison function defining the sorting order for the entries 1002 * in the "temp" data structure. The major sort key is the owner name, 1003 * followed by the type and rdata. 1004 */ 1005static int 1006temp_order(const void *av, const void *bv) { 1007 dns_difftuple_t const * const *ap = av; 1008 dns_difftuple_t const * const *bp = bv; 1009 dns_difftuple_t const *a = *ap; 1010 dns_difftuple_t const *b = *bp; 1011 int r; 1012 r = dns_name_compare(&a->name, &b->name); 1013 if (r != 0) 1014 return (r); 1015 r = (b->rdata.type - a->rdata.type); 1016 if (r != 0) 1017 return (r); 1018 r = dns_rdata_casecompare(&a->rdata, &b->rdata); 1019 return (r); 1020} 1021 1022/*% 1023 * Check the "RRset exists (value dependent)" prerequisite information 1024 * in 'temp' against the contents of the database 'db'. 1025 * 1026 * Return ISC_R_SUCCESS if the prerequisites are satisfied, 1027 * rcode(dns_rcode_nxrrset) if not. 1028 * 1029 * 'temp' must be pre-sorted. 1030 */ 1031 1032static isc_result_t 1033temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db, 1034 dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep) 1035{ 1036 isc_result_t result; 1037 dns_name_t *name; 1038 dns_dbnode_t *node; 1039 dns_difftuple_t *t; 1040 dns_diff_t trash; 1041 1042 dns_diff_init(mctx, &trash); 1043 1044 /* 1045 * For each name and type in the prerequisites, 1046 * construct a sorted rdata list of the corresponding 1047 * database contents, and compare the lists. 1048 */ 1049 t = ISC_LIST_HEAD(temp->tuples); 1050 while (t != NULL) { 1051 name = &t->name; 1052 dns_name_copynf(name, tmpname); 1053 *typep = t->rdata.type; 1054 1055 /* A new unique name begins here. */ 1056 node = NULL; 1057 result = dns_db_findnode(db, name, false, &node); 1058 if (result == ISC_R_NOTFOUND) { 1059 dns_diff_clear(&trash); 1060 return (DNS_R_NXRRSET); 1061 } 1062 if (result != ISC_R_SUCCESS) { 1063 dns_diff_clear(&trash); 1064 return (result); 1065 } 1066 1067 /* A new unique type begins here. */ 1068 while (t != NULL && dns_name_equal(&t->name, name)) { 1069 dns_rdatatype_t type, covers; 1070 dns_rdataset_t rdataset; 1071 dns_diff_t d_rrs; /* Database RRs with 1072 this name and type */ 1073 dns_diff_t u_rrs; /* Update RRs with 1074 this name and type */ 1075 1076 *typep = type = t->rdata.type; 1077 if (type == dns_rdatatype_rrsig || 1078 type == dns_rdatatype_sig) 1079 covers = dns_rdata_covers(&t->rdata); 1080 else if (type == dns_rdatatype_any) { 1081 dns_db_detachnode(db, &node); 1082 dns_diff_clear(&trash); 1083 return (DNS_R_NXRRSET); 1084 } else 1085 covers = 0; 1086 1087 /* 1088 * Collect all database RRs for this name and type 1089 * onto d_rrs and sort them. 1090 */ 1091 dns_rdataset_init(&rdataset); 1092 result = dns_db_findrdataset(db, node, ver, type, 1093 covers, (isc_stdtime_t) 0, 1094 &rdataset, NULL); 1095 if (result != ISC_R_SUCCESS) { 1096 dns_db_detachnode(db, &node); 1097 dns_diff_clear(&trash); 1098 return (DNS_R_NXRRSET); 1099 } 1100 1101 dns_diff_init(mctx, &d_rrs); 1102 dns_diff_init(mctx, &u_rrs); 1103 1104 for (result = dns_rdataset_first(&rdataset); 1105 result == ISC_R_SUCCESS; 1106 result = dns_rdataset_next(&rdataset)) 1107 { 1108 dns_rdata_t rdata = DNS_RDATA_INIT; 1109 dns_rdataset_current(&rdataset, &rdata); 1110 result = temp_append(&d_rrs, name, &rdata); 1111 if (result != ISC_R_SUCCESS) 1112 goto failure; 1113 } 1114 if (result != ISC_R_NOMORE) 1115 goto failure; 1116 result = dns_diff_sort(&d_rrs, temp_order); 1117 if (result != ISC_R_SUCCESS) 1118 goto failure; 1119 1120 /* 1121 * Collect all update RRs for this name and type 1122 * onto u_rrs. No need to sort them here - 1123 * they are already sorted. 1124 */ 1125 while (t != NULL && 1126 dns_name_equal(&t->name, name) && 1127 t->rdata.type == type) 1128 { 1129 dns_difftuple_t *next = 1130 ISC_LIST_NEXT(t, link); 1131 ISC_LIST_UNLINK(temp->tuples, t, link); 1132 ISC_LIST_APPEND(u_rrs.tuples, t, link); 1133 t = next; 1134 } 1135 1136 /* Compare the two sorted lists. */ 1137 result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples), 1138 ISC_LIST_HEAD(d_rrs.tuples)); 1139 if (result != ISC_R_SUCCESS) 1140 goto failure; 1141 1142 /* 1143 * We are done with the tuples, but we can't free 1144 * them yet because "name" still points into one 1145 * of them. Move them on a temporary list. 1146 */ 1147 ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link); 1148 ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link); 1149 dns_rdataset_disassociate(&rdataset); 1150 1151 continue; 1152 1153 failure: 1154 dns_diff_clear(&d_rrs); 1155 dns_diff_clear(&u_rrs); 1156 dns_diff_clear(&trash); 1157 dns_rdataset_disassociate(&rdataset); 1158 dns_db_detachnode(db, &node); 1159 return (result); 1160 } 1161 1162 dns_db_detachnode(db, &node); 1163 } 1164 1165 dns_diff_clear(&trash); 1166 return (ISC_R_SUCCESS); 1167} 1168 1169/**************************************************************************/ 1170/* 1171 * Conditional deletion of RRs. 1172 */ 1173 1174/*% 1175 * Context structure for delete_if(). 1176 */ 1177 1178typedef struct { 1179 rr_predicate *predicate; 1180 dns_db_t *db; 1181 dns_dbversion_t *ver; 1182 dns_diff_t *diff; 1183 dns_name_t *name; 1184 dns_rdata_t *update_rr; 1185} conditional_delete_ctx_t; 1186 1187/*% 1188 * Predicate functions for delete_if(). 1189 */ 1190 1191/*% 1192 * Return true iff 'db_rr' is neither a SOA nor an NS RR nor 1193 * an RRSIG nor an NSEC3PARAM nor a NSEC. 1194 */ 1195static bool 1196type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1197 UNUSED(update_rr); 1198 return ((db_rr->type != dns_rdatatype_soa && 1199 db_rr->type != dns_rdatatype_ns && 1200 db_rr->type != dns_rdatatype_nsec3param && 1201 db_rr->type != dns_rdatatype_rrsig && 1202 db_rr->type != dns_rdatatype_nsec) ? 1203 true : false); 1204} 1205 1206/*% 1207 * Return true iff 'db_rr' is neither a RRSIG nor a NSEC. 1208 */ 1209static bool 1210type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1211 UNUSED(update_rr); 1212 return ((db_rr->type != dns_rdatatype_rrsig && 1213 db_rr->type != dns_rdatatype_nsec) ? 1214 true : false); 1215} 1216 1217/*% 1218 * Return true always. 1219 */ 1220static bool 1221true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1222 UNUSED(update_rr); 1223 UNUSED(db_rr); 1224 return (true); 1225} 1226 1227/*% 1228 * Return true iff the two RRs have identical rdata. 1229 */ 1230static bool 1231rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1232 /* 1233 * XXXRTH This is not a problem, but we should consider creating 1234 * dns_rdata_equal() (that used dns_name_equal()), since it 1235 * would be faster. Not a priority. 1236 */ 1237 return (dns_rdata_casecompare(update_rr, db_rr) == 0 ? 1238 true : false); 1239} 1240 1241/*% 1242 * Return true iff 'update_rr' should replace 'db_rr' according 1243 * to the special RFC2136 rules for CNAME, SOA, and WKS records. 1244 * 1245 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs 1246 * make little sense, so we replace those, too. 1247 * 1248 * Additionally replace RRSIG that have been generated by the same key 1249 * for the same type. This simplifies refreshing a offline KSK by not 1250 * requiring that the old RRSIG be deleted. It also simplifies key 1251 * rollover by only requiring that the new RRSIG be added. 1252 */ 1253static bool 1254replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) { 1255 dns_rdata_rrsig_t updatesig, dbsig; 1256 isc_result_t result; 1257 1258 if (db_rr->type != update_rr->type) 1259 return (false); 1260 if (db_rr->type == dns_rdatatype_cname) 1261 return (true); 1262 if (db_rr->type == dns_rdatatype_dname) 1263 return (true); 1264 if (db_rr->type == dns_rdatatype_soa) 1265 return (true); 1266 if (db_rr->type == dns_rdatatype_nsec) 1267 return (true); 1268 if (db_rr->type == dns_rdatatype_rrsig) { 1269 /* 1270 * Replace existing RRSIG with the same keyid, 1271 * covered and algorithm. 1272 */ 1273 result = dns_rdata_tostruct(db_rr, &dbsig, NULL); 1274 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1275 result = dns_rdata_tostruct(update_rr, &updatesig, NULL); 1276 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1277 if (dbsig.keyid == updatesig.keyid && 1278 dbsig.covered == updatesig.covered && 1279 dbsig.algorithm == updatesig.algorithm) 1280 return (true); 1281 } 1282 if (db_rr->type == dns_rdatatype_wks) { 1283 /* 1284 * Compare the address and protocol fields only. These 1285 * form the first five bytes of the RR data. Do a 1286 * raw binary comparison; unpacking the WKS RRs using 1287 * dns_rdata_tostruct() might be cleaner in some ways. 1288 */ 1289 INSIST(db_rr->length >= 5 && update_rr->length >= 5); 1290 return (memcmp(db_rr->data, update_rr->data, 5) == 0 ? 1291 true : false); 1292 } 1293 1294 if (db_rr->type == dns_rdatatype_nsec3param) { 1295 if (db_rr->length != update_rr->length) 1296 return (false); 1297 INSIST(db_rr->length >= 4 && update_rr->length >= 4); 1298 /* 1299 * Replace NSEC3PARAM records that only differ by the 1300 * flags field. 1301 */ 1302 if (db_rr->data[0] == update_rr->data[0] && 1303 memcmp(db_rr->data+2, update_rr->data+2, 1304 update_rr->length - 2) == 0) 1305 return (true); 1306 } 1307 return (false); 1308} 1309 1310/*% 1311 * Internal helper function for delete_if(). 1312 */ 1313static isc_result_t 1314delete_if_action(void *data, rr_t *rr) { 1315 conditional_delete_ctx_t *ctx = data; 1316 if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) { 1317 isc_result_t result; 1318 result = update_one_rr(ctx->db, ctx->ver, ctx->diff, 1319 DNS_DIFFOP_DEL, ctx->name, 1320 rr->ttl, &rr->rdata); 1321 return (result); 1322 } else { 1323 return (ISC_R_SUCCESS); 1324 } 1325} 1326 1327/*% 1328 * Conditionally delete RRs. Apply 'predicate' to the RRs 1329 * specified by 'db', 'ver', 'name', and 'type' (which can 1330 * be dns_rdatatype_any to match any type). Delete those 1331 * RRs for which the predicate returns true, and log the 1332 * deletions in 'diff'. 1333 */ 1334static isc_result_t 1335delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver, 1336 dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers, 1337 dns_rdata_t *update_rr, dns_diff_t *diff) 1338{ 1339 conditional_delete_ctx_t ctx; 1340 ctx.predicate = predicate; 1341 ctx.db = db; 1342 ctx.ver = ver; 1343 ctx.diff = diff; 1344 ctx.name = name; 1345 ctx.update_rr = update_rr; 1346 return (foreach_rr(db, ver, name, type, covers, 1347 delete_if_action, &ctx)); 1348} 1349 1350/**************************************************************************/ 1351 1352static isc_result_t 1353add_rr_prepare_action(void *data, rr_t *rr) { 1354 isc_result_t result = ISC_R_SUCCESS; 1355 add_rr_prepare_ctx_t *ctx = data; 1356 dns_difftuple_t *tuple = NULL; 1357 bool equal, case_equal, ttl_equal; 1358 1359 /* 1360 * Are the new and old cases equal? 1361 */ 1362 case_equal = dns_name_caseequal(ctx->name, ctx->oldname); 1363 1364 /* 1365 * Are the ttl's equal? 1366 */ 1367 ttl_equal = rr->ttl == ctx->update_rr_ttl; 1368 1369 /* 1370 * If the update RR is a "duplicate" of a existing RR, 1371 * the update should be silently ignored. 1372 */ 1373 equal = (dns_rdata_casecompare(&rr->rdata, ctx->update_rr) == 0); 1374 if (equal && case_equal && ttl_equal) { 1375 ctx->ignore_add = true; 1376 return (ISC_R_SUCCESS); 1377 } 1378 1379 /* 1380 * If this RR is "equal" to the update RR, it should 1381 * be deleted before the update RR is added. 1382 */ 1383 if (replaces_p(ctx->update_rr, &rr->rdata)) { 1384 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, 1385 ctx->oldname, rr->ttl, &rr->rdata, 1386 &tuple)); 1387 dns_diff_append(&ctx->del_diff, &tuple); 1388 return (ISC_R_SUCCESS); 1389 } 1390 1391 /* 1392 * If this RR differs in TTL or case from the update RR, 1393 * its TTL and case must be adjusted. 1394 */ 1395 if (!ttl_equal || !case_equal) { 1396 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL, 1397 ctx->oldname, rr->ttl, &rr->rdata, 1398 &tuple)); 1399 dns_diff_append(&ctx->del_diff, &tuple); 1400 if (!equal) { 1401 CHECK(dns_difftuple_create(ctx->add_diff.mctx, 1402 DNS_DIFFOP_ADD, ctx->name, 1403 ctx->update_rr_ttl, 1404 &rr->rdata, &tuple)); 1405 dns_diff_append(&ctx->add_diff, &tuple); 1406 } 1407 } 1408 failure: 1409 return (result); 1410} 1411 1412/**************************************************************************/ 1413/* 1414 * Miscellaneous subroutines. 1415 */ 1416 1417/*% 1418 * Extract a single update RR from 'section' of dynamic update message 1419 * 'msg', with consistency checking. 1420 * 1421 * Stores the owner name, rdata, and TTL of the update RR at 'name', 1422 * 'rdata', and 'ttl', respectively. 1423 */ 1424static void 1425get_current_rr(dns_message_t *msg, dns_section_t section, 1426 dns_rdataclass_t zoneclass, dns_name_t **name, 1427 dns_rdata_t *rdata, dns_rdatatype_t *covers, 1428 dns_ttl_t *ttl, dns_rdataclass_t *update_class) 1429{ 1430 dns_rdataset_t *rdataset; 1431 isc_result_t result; 1432 dns_message_currentname(msg, section, name); 1433 rdataset = ISC_LIST_HEAD((*name)->list); 1434 INSIST(rdataset != NULL); 1435 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); 1436 *covers = rdataset->covers; 1437 *ttl = rdataset->ttl; 1438 result = dns_rdataset_first(rdataset); 1439 INSIST(result == ISC_R_SUCCESS); 1440 dns_rdataset_current(rdataset, rdata); 1441 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); 1442 *update_class = rdata->rdclass; 1443 rdata->rdclass = zoneclass; 1444} 1445 1446/*% 1447 * Increment the SOA serial number of database 'db', version 'ver'. 1448 * Replace the SOA record in the database, and log the 1449 * change in 'diff'. 1450 */ 1451 1452 /* 1453 * XXXRTH Failures in this routine will be worth logging, when 1454 * we have a logging system. Failure to find the zonename 1455 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR(). 1456 */ 1457 1458static isc_result_t 1459update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, 1460 isc_mem_t *mctx, dns_updatemethod_t method) 1461{ 1462 dns_difftuple_t *deltuple = NULL; 1463 dns_difftuple_t *addtuple = NULL; 1464 uint32_t serial; 1465 isc_result_t result; 1466 1467 CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple)); 1468 CHECK(dns_difftuple_copy(deltuple, &addtuple)); 1469 addtuple->op = DNS_DIFFOP_ADD; 1470 1471 serial = dns_soa_getserial(&addtuple->rdata); 1472 serial = dns_update_soaserial(serial, method); 1473 dns_soa_setserial(serial, &addtuple->rdata); 1474 CHECK(do_one_tuple(&deltuple, db, ver, diff)); 1475 CHECK(do_one_tuple(&addtuple, db, ver, diff)); 1476 result = ISC_R_SUCCESS; 1477 1478 failure: 1479 if (addtuple != NULL) 1480 dns_difftuple_free(&addtuple); 1481 if (deltuple != NULL) 1482 dns_difftuple_free(&deltuple); 1483 return (result); 1484} 1485 1486/*% 1487 * Check that the new SOA record at 'update_rdata' does not 1488 * illegally cause the SOA serial number to decrease or stay 1489 * unchanged relative to the existing SOA in 'db'. 1490 * 1491 * Sets '*ok' to true if the update is legal, false if not. 1492 * 1493 * William King points out that RFC2136 is inconsistent about 1494 * the case where the serial number stays unchanged: 1495 * 1496 * section 3.4.2.2 requires a server to ignore a SOA update request 1497 * if the serial number on the update SOA is less_than_or_equal to 1498 * the zone SOA serial. 1499 * 1500 * section 3.6 requires a server to ignore a SOA update request if 1501 * the serial is less_than the zone SOA serial. 1502 * 1503 * Paul says 3.4.2.2 is correct. 1504 * 1505 */ 1506static isc_result_t 1507check_soa_increment(dns_db_t *db, dns_dbversion_t *ver, 1508 dns_rdata_t *update_rdata, bool *ok) 1509{ 1510 uint32_t db_serial; 1511 uint32_t update_serial; 1512 isc_result_t result; 1513 1514 update_serial = dns_soa_getserial(update_rdata); 1515 1516 result = dns_db_getsoaserial(db, ver, &db_serial); 1517 if (result != ISC_R_SUCCESS) 1518 return (result); 1519 1520 if (DNS_SERIAL_GE(db_serial, update_serial)) { 1521 *ok = false; 1522 } else { 1523 *ok = true; 1524 } 1525 1526 return (ISC_R_SUCCESS); 1527 1528} 1529 1530/**************************************************************************/ 1531/*% 1532 * The actual update code in all its glory. We try to follow 1533 * the RFC2136 pseudocode as closely as possible. 1534 */ 1535 1536static isc_result_t 1537send_update_event(ns_client_t *client, dns_zone_t *zone) { 1538 isc_result_t result = ISC_R_SUCCESS; 1539 update_event_t *event = NULL; 1540 isc_task_t *zonetask = NULL; 1541 ns_client_t *evclient; 1542 1543 event = (update_event_t *) 1544 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, 1545 update_action, NULL, sizeof(*event)); 1546 if (event == NULL) 1547 FAIL(ISC_R_NOMEMORY); 1548 event->zone = zone; 1549 event->result = ISC_R_SUCCESS; 1550 1551 evclient = NULL; 1552 ns_client_attach(client, &evclient); 1553 INSIST(client->nupdates == 0); 1554 client->nupdates++; 1555 event->ev_arg = evclient; 1556 1557 dns_zone_gettask(zone, &zonetask); 1558 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 1559 1560 failure: 1561 if (event != NULL) 1562 isc_event_free(ISC_EVENT_PTR(&event)); 1563 return (result); 1564} 1565 1566static void 1567respond(ns_client_t *client, isc_result_t result) { 1568 isc_result_t msg_result; 1569 1570 msg_result = dns_message_reply(client->message, true); 1571 if (msg_result != ISC_R_SUCCESS) 1572 goto msg_failure; 1573 client->message->rcode = dns_result_torcode(result); 1574 1575 ns_client_send(client); 1576 return; 1577 1578 msg_failure: 1579 isc_log_write(ns_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 1580 ISC_LOG_ERROR, 1581 "could not create update response message: %s", 1582 isc_result_totext(msg_result)); 1583 ns_client_next(client, msg_result); 1584} 1585 1586void 1587ns_update_start(ns_client_t *client, isc_result_t sigresult) { 1588 dns_message_t *request = client->message; 1589 isc_result_t result; 1590 dns_name_t *zonename; 1591 dns_rdataset_t *zone_rdataset; 1592 dns_zone_t *zone = NULL, *raw = NULL; 1593 1594 /* 1595 * Interpret the zone section. 1596 */ 1597 result = dns_message_firstname(request, DNS_SECTION_ZONE); 1598 if (result != ISC_R_SUCCESS) 1599 FAILC(DNS_R_FORMERR, "update zone section empty"); 1600 1601 /* 1602 * The zone section must contain exactly one "question", and 1603 * it must be of type SOA. 1604 */ 1605 zonename = NULL; 1606 dns_message_currentname(request, DNS_SECTION_ZONE, &zonename); 1607 zone_rdataset = ISC_LIST_HEAD(zonename->list); 1608 if (zone_rdataset->type != dns_rdatatype_soa) 1609 FAILC(DNS_R_FORMERR, 1610 "update zone section contains non-SOA"); 1611 if (ISC_LIST_NEXT(zone_rdataset, link) != NULL) 1612 FAILC(DNS_R_FORMERR, 1613 "update zone section contains multiple RRs"); 1614 1615 /* The zone section must have exactly one name. */ 1616 result = dns_message_nextname(request, DNS_SECTION_ZONE); 1617 if (result != ISC_R_NOMORE) 1618 FAILC(DNS_R_FORMERR, 1619 "update zone section contains multiple RRs"); 1620 1621 result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, 1622 &zone); 1623 if (result != ISC_R_SUCCESS) 1624 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); 1625 1626 /* 1627 * If there is a raw (unsigned) zone associated with this 1628 * zone then it processes the UPDATE request. 1629 */ 1630 dns_zone_getraw(zone, &raw); 1631 if (raw != NULL) { 1632 dns_zone_detach(&zone); 1633 dns_zone_attach(raw, &zone); 1634 dns_zone_detach(&raw); 1635 } 1636 1637 switch(dns_zone_gettype(zone)) { 1638 case dns_zone_master: 1639 case dns_zone_dlz: 1640 /* 1641 * We can now fail due to a bad signature as we now know 1642 * that we are the master. 1643 */ 1644 if (sigresult != ISC_R_SUCCESS) 1645 FAIL(sigresult); 1646 CHECK(send_update_event(client, zone)); 1647 break; 1648 case dns_zone_slave: 1649 case dns_zone_mirror: 1650 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone), 1651 "update forwarding", zonename, true, 1652 false)); 1653 CHECK(send_forward_event(client, zone)); 1654 break; 1655 default: 1656 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone"); 1657 } 1658 return; 1659 1660 failure: 1661 if (result == DNS_R_REFUSED) { 1662 INSIST(dns_zone_gettype(zone) == dns_zone_slave || 1663 dns_zone_gettype(zone) == dns_zone_mirror); 1664 inc_stats(client, zone, ns_statscounter_updaterej); 1665 } 1666 /* 1667 * We failed without having sent an update event to the zone. 1668 * We are still in the client task context, so we can 1669 * simply give an error response without switching tasks. 1670 */ 1671 respond(client, result); 1672 if (zone != NULL) 1673 dns_zone_detach(&zone); 1674} 1675 1676/*% 1677 * DS records are not allowed to exist without corresponding NS records, 1678 * RFC 3658, 2.2 Protocol Change, 1679 * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex". 1680 */ 1681 1682static isc_result_t 1683remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) { 1684 isc_result_t result; 1685 bool ns_exists; 1686 dns_difftuple_t *tupple; 1687 dns_diff_t temp_diff; 1688 1689 dns_diff_init(diff->mctx, &temp_diff); 1690 1691 for (tupple = ISC_LIST_HEAD(diff->tuples); 1692 tupple != NULL; 1693 tupple = ISC_LIST_NEXT(tupple, link)) { 1694 if (!((tupple->op == DNS_DIFFOP_DEL && 1695 tupple->rdata.type == dns_rdatatype_ns) || 1696 (tupple->op == DNS_DIFFOP_ADD && 1697 tupple->rdata.type == dns_rdatatype_ds))) 1698 continue; 1699 CHECK(rrset_exists(db, newver, &tupple->name, 1700 dns_rdatatype_ns, 0, &ns_exists)); 1701 if (ns_exists && 1702 !dns_name_equal(&tupple->name, dns_db_origin(db))) 1703 continue; 1704 CHECK(delete_if(true_p, db, newver, &tupple->name, 1705 dns_rdatatype_ds, 0, NULL, &temp_diff)); 1706 } 1707 result = ISC_R_SUCCESS; 1708 1709 failure: 1710 for (tupple = ISC_LIST_HEAD(temp_diff.tuples); 1711 tupple != NULL; 1712 tupple = ISC_LIST_HEAD(temp_diff.tuples)) { 1713 ISC_LIST_UNLINK(temp_diff.tuples, tupple, link); 1714 dns_diff_appendminimal(diff, &tupple); 1715 } 1716 return (result); 1717} 1718 1719/* 1720 * This implements the post load integrity checks for mx records. 1721 */ 1722static isc_result_t 1723check_mx(ns_client_t *client, dns_zone_t *zone, 1724 dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) 1725{ 1726 char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")]; 1727 char ownerbuf[DNS_NAME_FORMATSIZE]; 1728 char namebuf[DNS_NAME_FORMATSIZE]; 1729 char altbuf[DNS_NAME_FORMATSIZE]; 1730 dns_difftuple_t *t; 1731 dns_fixedname_t fixed; 1732 dns_name_t *foundname; 1733 dns_rdata_mx_t mx; 1734 dns_rdata_t rdata; 1735 bool ok = true; 1736 bool isaddress; 1737 isc_result_t result; 1738 struct in6_addr addr6; 1739 struct in_addr addr; 1740 dns_zoneopt_t options; 1741 1742 foundname = dns_fixedname_initname(&fixed); 1743 dns_rdata_init(&rdata); 1744 options = dns_zone_getoptions(zone); 1745 1746 for (t = ISC_LIST_HEAD(diff->tuples); 1747 t != NULL; 1748 t = ISC_LIST_NEXT(t, link)) { 1749 if (t->op != DNS_DIFFOP_ADD || 1750 t->rdata.type != dns_rdatatype_mx) 1751 continue; 1752 1753 result = dns_rdata_tostruct(&t->rdata, &mx, NULL); 1754 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1755 /* 1756 * Check if we will error out if we attempt to reload the 1757 * zone. 1758 */ 1759 dns_name_format(&mx.mx, namebuf, sizeof(namebuf)); 1760 dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf)); 1761 isaddress = false; 1762 if ((options & DNS_ZONEOPT_CHECKMX) != 0 && 1763 strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) { 1764 if (tmp[strlen(tmp) - 1] == '.') 1765 tmp[strlen(tmp) - 1] = '\0'; 1766 if (inet_pton(AF_INET, tmp, &addr) == 1 || 1767 inet_pton(AF_INET6, tmp, &addr6) == 1) 1768 isaddress = true; 1769 } 1770 1771 if (isaddress && (options & DNS_ZONEOPT_CHECKMXFAIL) != 0) { 1772 update_log(client, zone, ISC_LOG_ERROR, 1773 "%s/MX: '%s': %s", 1774 ownerbuf, namebuf, 1775 dns_result_totext(DNS_R_MXISADDRESS)); 1776 ok = false; 1777 } else if (isaddress) { 1778 update_log(client, zone, ISC_LOG_WARNING, 1779 "%s/MX: warning: '%s': %s", 1780 ownerbuf, namebuf, 1781 dns_result_totext(DNS_R_MXISADDRESS)); 1782 } 1783 1784 /* 1785 * Check zone integrity checks. 1786 */ 1787 if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0) 1788 continue; 1789 result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a, 1790 0, 0, NULL, foundname, NULL, NULL); 1791 if (result == ISC_R_SUCCESS) 1792 continue; 1793 1794 if (result == DNS_R_NXRRSET) { 1795 result = dns_db_find(db, &mx.mx, newver, 1796 dns_rdatatype_aaaa, 1797 0, 0, NULL, foundname, 1798 NULL, NULL); 1799 if (result == ISC_R_SUCCESS) 1800 continue; 1801 } 1802 1803 if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) { 1804 update_log(client, zone, ISC_LOG_ERROR, 1805 "%s/MX '%s' has no address records " 1806 "(A or AAAA)", ownerbuf, namebuf); 1807 ok = false; 1808 } else if (result == DNS_R_CNAME) { 1809 update_log(client, zone, ISC_LOG_ERROR, 1810 "%s/MX '%s' is a CNAME (illegal)", 1811 ownerbuf, namebuf); 1812 ok = false; 1813 } else if (result == DNS_R_DNAME) { 1814 dns_name_format(foundname, altbuf, sizeof altbuf); 1815 update_log(client, zone, ISC_LOG_ERROR, 1816 "%s/MX '%s' is below a DNAME '%s' (illegal)", 1817 ownerbuf, namebuf, altbuf); 1818 ok = false; 1819 } 1820 } 1821 return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED); 1822} 1823 1824static isc_result_t 1825rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, 1826 const dns_rdata_t *rdata, bool *flag) 1827{ 1828 dns_rdataset_t rdataset; 1829 dns_dbnode_t *node = NULL; 1830 isc_result_t result; 1831 1832 dns_rdataset_init(&rdataset); 1833 if (rdata->type == dns_rdatatype_nsec3) 1834 CHECK(dns_db_findnsec3node(db, name, false, &node)); 1835 else 1836 CHECK(dns_db_findnode(db, name, false, &node)); 1837 result = dns_db_findrdataset(db, node, ver, rdata->type, 0, 1838 (isc_stdtime_t) 0, &rdataset, NULL); 1839 if (result == ISC_R_NOTFOUND) { 1840 *flag = false; 1841 result = ISC_R_SUCCESS; 1842 goto failure; 1843 } 1844 1845 for (result = dns_rdataset_first(&rdataset); 1846 result == ISC_R_SUCCESS; 1847 result = dns_rdataset_next(&rdataset)) { 1848 dns_rdata_t myrdata = DNS_RDATA_INIT; 1849 dns_rdataset_current(&rdataset, &myrdata); 1850 if (!dns_rdata_casecompare(&myrdata, rdata)) 1851 break; 1852 } 1853 dns_rdataset_disassociate(&rdataset); 1854 if (result == ISC_R_SUCCESS) { 1855 *flag = true; 1856 } else if (result == ISC_R_NOMORE) { 1857 *flag = false; 1858 result = ISC_R_SUCCESS; 1859 } 1860 1861 failure: 1862 if (node != NULL) 1863 dns_db_detachnode(db, &node); 1864 return (result); 1865} 1866 1867static isc_result_t 1868get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype, 1869 unsigned int *iterationsp) 1870{ 1871 dns_dbnode_t *node = NULL; 1872 dns_rdata_nsec3param_t nsec3param; 1873 dns_rdataset_t rdataset; 1874 isc_result_t result; 1875 unsigned int iterations = 0; 1876 1877 dns_rdataset_init(&rdataset); 1878 1879 result = dns_db_getoriginnode(db, &node); 1880 if (result != ISC_R_SUCCESS) 1881 return (result); 1882 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 1883 0, (isc_stdtime_t) 0, &rdataset, NULL); 1884 if (result == ISC_R_NOTFOUND) 1885 goto try_private; 1886 if (result != ISC_R_SUCCESS) 1887 goto failure; 1888 1889 for (result = dns_rdataset_first(&rdataset); 1890 result == ISC_R_SUCCESS; 1891 result = dns_rdataset_next(&rdataset)) { 1892 dns_rdata_t rdata = DNS_RDATA_INIT; 1893 dns_rdataset_current(&rdataset, &rdata); 1894 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); 1895 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) 1896 continue; 1897 if (nsec3param.iterations > iterations) 1898 iterations = nsec3param.iterations; 1899 } 1900 if (result != ISC_R_NOMORE) 1901 goto failure; 1902 1903 dns_rdataset_disassociate(&rdataset); 1904 1905 try_private: 1906 if (privatetype == 0) 1907 goto success; 1908 1909 result = dns_db_findrdataset(db, node, ver, privatetype, 1910 0, (isc_stdtime_t) 0, &rdataset, NULL); 1911 if (result == ISC_R_NOTFOUND) 1912 goto success; 1913 if (result != ISC_R_SUCCESS) 1914 goto failure; 1915 1916 for (result = dns_rdataset_first(&rdataset); 1917 result == ISC_R_SUCCESS; 1918 result = dns_rdataset_next(&rdataset)) { 1919 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 1920 dns_rdata_t private = DNS_RDATA_INIT; 1921 dns_rdata_t rdata = DNS_RDATA_INIT; 1922 1923 dns_rdataset_current(&rdataset, &rdata); 1924 if (!dns_nsec3param_fromprivate(&private, &rdata, 1925 buf, sizeof(buf))) 1926 continue; 1927 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL)); 1928 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0) 1929 continue; 1930 if (nsec3param.iterations > iterations) 1931 iterations = nsec3param.iterations; 1932 } 1933 if (result != ISC_R_NOMORE) 1934 goto failure; 1935 1936 success: 1937 *iterationsp = iterations; 1938 result = ISC_R_SUCCESS; 1939 1940 failure: 1941 if (node != NULL) 1942 dns_db_detachnode(db, &node); 1943 if (dns_rdataset_isassociated(&rdataset)) 1944 dns_rdataset_disassociate(&rdataset); 1945 return (result); 1946} 1947 1948/* 1949 * Prevent the zone entering a inconsistent state where 1950 * NSEC only DNSKEYs are present with NSEC3 chains. 1951 */ 1952static isc_result_t 1953check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 1954 dns_dbversion_t *ver, dns_diff_t *diff) 1955{ 1956 dns_difftuple_t *tuple; 1957 bool nseconly = false, nsec3 = false; 1958 isc_result_t result; 1959 unsigned int iterations = 0, max; 1960 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); 1961 1962 /* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */ 1963 for (tuple = ISC_LIST_HEAD(diff->tuples); 1964 tuple != NULL; 1965 tuple = ISC_LIST_NEXT(tuple, link)) { 1966 if (tuple->op != DNS_DIFFOP_ADD) 1967 continue; 1968 1969 if (tuple->rdata.type == dns_rdatatype_dnskey) { 1970 uint8_t alg; 1971 alg = tuple->rdata.data[3]; 1972 if (alg == DST_ALG_RSASHA1) { 1973 nseconly = true; 1974 break; 1975 } 1976 } else if (tuple->rdata.type == dns_rdatatype_nsec3param) { 1977 nsec3 = true; 1978 break; 1979 } 1980 } 1981 1982 /* Check existing DB for NSEC-only DNSKEY */ 1983 if (!nseconly) { 1984 result = dns_nsec_nseconly(db, ver, &nseconly); 1985 1986 /* 1987 * An NSEC3PARAM update can proceed without a DNSKEY (it 1988 * will trigger a delayed change), so we can ignore 1989 * ISC_R_NOTFOUND here. 1990 */ 1991 if (result == ISC_R_NOTFOUND) 1992 result = ISC_R_SUCCESS; 1993 1994 CHECK(result); 1995 } 1996 1997 /* Check existing DB for NSEC3 */ 1998 if (!nsec3) 1999 CHECK(dns_nsec3_activex(db, ver, false, 2000 privatetype, &nsec3)); 2001 2002 /* Refuse to allow NSEC3 with NSEC-only keys */ 2003 if (nseconly && nsec3) { 2004 update_log(client, zone, ISC_LOG_ERROR, 2005 "NSEC only DNSKEYs and NSEC3 chains not allowed"); 2006 result = DNS_R_REFUSED; 2007 goto failure; 2008 } 2009 2010 /* Verify NSEC3 params */ 2011 CHECK(get_iterations(db, ver, privatetype, &iterations)); 2012 CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max)); 2013 if (max != 0 && iterations > max) { 2014 update_log(client, zone, ISC_LOG_ERROR, 2015 "too many NSEC3 iterations (%u) for " 2016 "weakest DNSKEY (%u)", iterations, max); 2017 result = DNS_R_REFUSED; 2018 goto failure; 2019 } 2020 2021 failure: 2022 return (result); 2023} 2024 2025/* 2026 * Delay NSEC3PARAM changes as they need to be applied to the whole zone. 2027 */ 2028static isc_result_t 2029add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, 2030 dns_dbversion_t *ver, dns_diff_t *diff) 2031{ 2032 isc_result_t result = ISC_R_SUCCESS; 2033 dns_difftuple_t *tuple, *newtuple = NULL, *next; 2034 dns_rdata_t rdata = DNS_RDATA_INIT; 2035 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1]; 2036 dns_diff_t temp_diff; 2037 dns_diffop_t op; 2038 bool flag; 2039 dns_name_t *name = dns_zone_getorigin(zone); 2040 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); 2041 uint32_t ttl = 0; 2042 bool ttl_good = false; 2043 2044 update_log(client, zone, ISC_LOG_DEBUG(3), 2045 "checking for NSEC3PARAM changes"); 2046 2047 dns_diff_init(diff->mctx, &temp_diff); 2048 2049 /* 2050 * Extract NSEC3PARAM tuples from list. 2051 */ 2052 for (tuple = ISC_LIST_HEAD(diff->tuples); 2053 tuple != NULL; 2054 tuple = next) { 2055 2056 next = ISC_LIST_NEXT(tuple, link); 2057 2058 if (tuple->rdata.type != dns_rdatatype_nsec3param || 2059 !dns_name_equal(name, &tuple->name)) 2060 continue; 2061 ISC_LIST_UNLINK(diff->tuples, tuple, link); 2062 ISC_LIST_APPEND(temp_diff.tuples, tuple, link); 2063 } 2064 2065 /* 2066 * Extract TTL changes pairs, we don't need to convert these to 2067 * delayed changes. 2068 */ 2069 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); 2070 tuple != NULL; tuple = next) { 2071 if (tuple->op == DNS_DIFFOP_ADD) { 2072 if (!ttl_good) { 2073 /* 2074 * Any adds here will contain the final 2075 * NSEC3PARAM RRset TTL. 2076 */ 2077 ttl = tuple->ttl; 2078 ttl_good = true; 2079 } 2080 /* 2081 * Walk the temp_diff list looking for the 2082 * corresponding delete. 2083 */ 2084 next = ISC_LIST_HEAD(temp_diff.tuples); 2085 while (next != NULL) { 2086 unsigned char *next_data = next->rdata.data; 2087 unsigned char *tuple_data = tuple->rdata.data; 2088 if (next->op == DNS_DIFFOP_DEL && 2089 next->rdata.length == tuple->rdata.length && 2090 !memcmp(next_data, tuple_data, 2091 next->rdata.length)) { 2092 ISC_LIST_UNLINK(temp_diff.tuples, next, 2093 link); 2094 ISC_LIST_APPEND(diff->tuples, next, 2095 link); 2096 break; 2097 } 2098 next = ISC_LIST_NEXT(next, link); 2099 } 2100 /* 2101 * If we have not found a pair move onto the next 2102 * tuple. 2103 */ 2104 if (next == NULL) { 2105 next = ISC_LIST_NEXT(tuple, link); 2106 continue; 2107 } 2108 /* 2109 * Find the next tuple to be processed before 2110 * unlinking then complete moving the pair to 'diff'. 2111 */ 2112 next = ISC_LIST_NEXT(tuple, link); 2113 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2114 ISC_LIST_APPEND(diff->tuples, tuple, link); 2115 } else 2116 next = ISC_LIST_NEXT(tuple, link); 2117 } 2118 2119 /* 2120 * Preserve any ongoing changes from a BIND 9.6.x upgrade. 2121 * 2122 * Any NSEC3PARAM records with flags other than OPTOUT named 2123 * in managing and should not be touched so revert such changes 2124 * taking into account any TTL change of the NSEC3PARAM RRset. 2125 */ 2126 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); 2127 tuple != NULL; tuple = next) { 2128 next = ISC_LIST_NEXT(tuple, link); 2129 if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) { 2130 /* 2131 * If we havn't had any adds then the tuple->ttl must 2132 * be the original ttl and should be used for any 2133 * future changes. 2134 */ 2135 if (!ttl_good) { 2136 ttl = tuple->ttl; 2137 ttl_good = true; 2138 } 2139 op = (tuple->op == DNS_DIFFOP_DEL) ? 2140 DNS_DIFFOP_ADD : DNS_DIFFOP_DEL; 2141 CHECK(dns_difftuple_create(diff->mctx, op, name, 2142 ttl, &tuple->rdata, 2143 &newtuple)); 2144 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2145 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2146 dns_diff_appendminimal(diff, &tuple); 2147 } 2148 } 2149 2150 /* 2151 * We now have just the actual changes to the NSEC3PARAM RRset. 2152 * Convert the adds to delayed adds and the deletions into delayed 2153 * deletions. 2154 */ 2155 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); 2156 tuple != NULL; tuple = next) { 2157 /* 2158 * If we havn't had any adds then the tuple->ttl must be the 2159 * original ttl and should be used for any future changes. 2160 */ 2161 if (!ttl_good) { 2162 ttl = tuple->ttl; 2163 ttl_good = true; 2164 } 2165 if (tuple->op == DNS_DIFFOP_ADD) { 2166 bool nseconly = false; 2167 2168 /* 2169 * Look for any deletes which match this ADD ignoring 2170 * flags. We don't need to explictly remove them as 2171 * they will be removed a side effect of processing 2172 * the add. 2173 */ 2174 next = ISC_LIST_HEAD(temp_diff.tuples); 2175 while (next != NULL) { 2176 unsigned char *next_data = next->rdata.data; 2177 unsigned char *tuple_data = tuple->rdata.data; 2178 if (next->op != DNS_DIFFOP_DEL || 2179 next->rdata.length != tuple->rdata.length || 2180 next_data[0] != tuple_data[0] || 2181 next_data[2] != tuple_data[2] || 2182 next_data[3] != tuple_data[3] || 2183 memcmp(next_data + 4, tuple_data + 4, 2184 tuple->rdata.length - 4)) { 2185 next = ISC_LIST_NEXT(next, link); 2186 continue; 2187 } 2188 ISC_LIST_UNLINK(temp_diff.tuples, next, link); 2189 ISC_LIST_APPEND(diff->tuples, next, link); 2190 next = ISC_LIST_HEAD(temp_diff.tuples); 2191 } 2192 2193 /* 2194 * Create a private-type record to signal that 2195 * we want a delayed NSEC3 chain add/delete 2196 */ 2197 dns_nsec3param_toprivate(&tuple->rdata, &rdata, 2198 privatetype, buf, sizeof(buf)); 2199 buf[2] |= DNS_NSEC3FLAG_CREATE; 2200 2201 /* 2202 * If the zone is not currently capable of 2203 * supporting an NSEC3 chain, then we set the 2204 * INITIAL flag to indicate that these parameters 2205 * are to be used later. 2206 */ 2207 result = dns_nsec_nseconly(db, ver, &nseconly); 2208 if (result == ISC_R_NOTFOUND || nseconly) 2209 buf[2] |= DNS_NSEC3FLAG_INITIAL; 2210 2211 /* 2212 * See if this CREATE request already exists. 2213 */ 2214 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2215 2216 if (!flag) { 2217 CHECK(dns_difftuple_create(diff->mctx, 2218 DNS_DIFFOP_ADD, 2219 name, 0, &rdata, 2220 &newtuple)); 2221 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2222 } 2223 2224 /* 2225 * Remove any existing CREATE request to add an 2226 * otherwise indentical chain with a reversed 2227 * OPTOUT state. 2228 */ 2229 buf[2] ^= DNS_NSEC3FLAG_OPTOUT; 2230 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2231 2232 if (flag) { 2233 CHECK(dns_difftuple_create(diff->mctx, 2234 DNS_DIFFOP_DEL, 2235 name, 0, &rdata, 2236 &newtuple)); 2237 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2238 } 2239 2240 /* 2241 * Find the next tuple to be processed and remove the 2242 * temporary add record. 2243 */ 2244 next = ISC_LIST_NEXT(tuple, link); 2245 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, 2246 name, ttl, &tuple->rdata, 2247 &newtuple)); 2248 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2249 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2250 dns_diff_appendminimal(diff, &tuple); 2251 dns_rdata_reset(&rdata); 2252 } else 2253 next = ISC_LIST_NEXT(tuple, link); 2254 } 2255 2256 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); 2257 tuple != NULL; tuple = next) { 2258 2259 INSIST(ttl_good); 2260 2261 next = ISC_LIST_NEXT(tuple, link); 2262 /* 2263 * See if we already have a REMOVE request in progress. 2264 */ 2265 dns_nsec3param_toprivate(&tuple->rdata, &rdata, privatetype, 2266 buf, sizeof(buf)); 2267 2268 buf[2] |= DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC; 2269 2270 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2271 if (!flag) { 2272 buf[2] &= ~DNS_NSEC3FLAG_NONSEC; 2273 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2274 } 2275 2276 if (!flag) { 2277 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, 2278 name, 0, &rdata, &newtuple)); 2279 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2280 } 2281 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 2282 ttl, &tuple->rdata, &newtuple)); 2283 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2284 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2285 dns_diff_appendminimal(diff, &tuple); 2286 dns_rdata_reset(&rdata); 2287 } 2288 2289 result = ISC_R_SUCCESS; 2290 failure: 2291 dns_diff_clear(&temp_diff); 2292 return (result); 2293} 2294 2295static isc_result_t 2296rollback_private(dns_db_t *db, dns_rdatatype_t privatetype, 2297 dns_dbversion_t *ver, dns_diff_t *diff) 2298{ 2299 dns_diff_t temp_diff; 2300 dns_diffop_t op; 2301 dns_difftuple_t *tuple, *newtuple = NULL, *next; 2302 dns_name_t *name = dns_db_origin(db); 2303 isc_mem_t *mctx = diff->mctx; 2304 isc_result_t result; 2305 2306 if (privatetype == 0) 2307 return (ISC_R_SUCCESS); 2308 2309 dns_diff_init(mctx, &temp_diff); 2310 2311 /* 2312 * Extract the changes to be rolled back. 2313 */ 2314 for (tuple = ISC_LIST_HEAD(diff->tuples); 2315 tuple != NULL; tuple = next) { 2316 2317 next = ISC_LIST_NEXT(tuple, link); 2318 2319 if (tuple->rdata.type != privatetype || 2320 !dns_name_equal(name, &tuple->name)) 2321 continue; 2322 2323 /* 2324 * Allow records which indicate that a zone has been 2325 * signed with a DNSKEY to be removed. 2326 */ 2327 if (tuple->op == DNS_DIFFOP_DEL && 2328 tuple->rdata.length == 5 && 2329 tuple->rdata.data[0] != 0 && 2330 tuple->rdata.data[4] != 0) 2331 continue; 2332 2333 ISC_LIST_UNLINK(diff->tuples, tuple, link); 2334 ISC_LIST_PREPEND(temp_diff.tuples, tuple, link); 2335 } 2336 2337 /* 2338 * Rollback the changes. 2339 */ 2340 while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) { 2341 op = (tuple->op == DNS_DIFFOP_DEL) ? 2342 DNS_DIFFOP_ADD : DNS_DIFFOP_DEL; 2343 CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl, 2344 &tuple->rdata, &newtuple)); 2345 CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff)); 2346 } 2347 result = ISC_R_SUCCESS; 2348 2349 failure: 2350 dns_diff_clear(&temp_diff); 2351 return (result); 2352} 2353 2354/* 2355 * Add records to cause the delayed signing of the zone by added DNSKEY 2356 * to remove the RRSIG records generated by a deleted DNSKEY. 2357 */ 2358static isc_result_t 2359add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype, 2360 dns_dbversion_t *ver, dns_diff_t *diff) 2361{ 2362 dns_difftuple_t *tuple, *newtuple = NULL, *next; 2363 dns_rdata_dnskey_t dnskey; 2364 dns_rdata_t rdata = DNS_RDATA_INIT; 2365 bool flag; 2366 isc_region_t r; 2367 isc_result_t result = ISC_R_SUCCESS; 2368 uint16_t keyid; 2369 unsigned char buf[5]; 2370 dns_name_t *name = dns_db_origin(db); 2371 dns_diff_t temp_diff; 2372 2373 dns_diff_init(diff->mctx, &temp_diff); 2374 2375 /* 2376 * Extract the DNSKEY tuples from the list. 2377 */ 2378 for (tuple = ISC_LIST_HEAD(diff->tuples); 2379 tuple != NULL; tuple = next) { 2380 2381 next = ISC_LIST_NEXT(tuple, link); 2382 2383 if (tuple->rdata.type != dns_rdatatype_dnskey) 2384 continue; 2385 2386 ISC_LIST_UNLINK(diff->tuples, tuple, link); 2387 ISC_LIST_APPEND(temp_diff.tuples, tuple, link); 2388 } 2389 2390 /* 2391 * Extract TTL changes pairs, we don't need signing records for these. 2392 */ 2393 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); 2394 tuple != NULL; tuple = next) { 2395 if (tuple->op == DNS_DIFFOP_ADD) { 2396 /* 2397 * Walk the temp_diff list looking for the 2398 * corresponding delete. 2399 */ 2400 next = ISC_LIST_HEAD(temp_diff.tuples); 2401 while (next != NULL) { 2402 unsigned char *next_data = next->rdata.data; 2403 unsigned char *tuple_data = tuple->rdata.data; 2404 if (next->op == DNS_DIFFOP_DEL && 2405 dns_name_equal(&tuple->name, &next->name) && 2406 next->rdata.length == tuple->rdata.length && 2407 !memcmp(next_data, tuple_data, 2408 next->rdata.length)) { 2409 ISC_LIST_UNLINK(temp_diff.tuples, next, 2410 link); 2411 ISC_LIST_APPEND(diff->tuples, next, 2412 link); 2413 break; 2414 } 2415 next = ISC_LIST_NEXT(next, link); 2416 } 2417 /* 2418 * If we have not found a pair move onto the next 2419 * tuple. 2420 */ 2421 if (next == NULL) { 2422 next = ISC_LIST_NEXT(tuple, link); 2423 continue; 2424 } 2425 /* 2426 * Find the next tuple to be processed before 2427 * unlinking then complete moving the pair to 'diff'. 2428 */ 2429 next = ISC_LIST_NEXT(tuple, link); 2430 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2431 ISC_LIST_APPEND(diff->tuples, tuple, link); 2432 } else 2433 next = ISC_LIST_NEXT(tuple, link); 2434 } 2435 2436 /* 2437 * Process the remaining DNSKEY entries. 2438 */ 2439 for (tuple = ISC_LIST_HEAD(temp_diff.tuples); 2440 tuple != NULL; 2441 tuple = ISC_LIST_HEAD(temp_diff.tuples)) { 2442 2443 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link); 2444 ISC_LIST_APPEND(diff->tuples, tuple, link); 2445 2446 result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL); 2447 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2448 if ((dnskey.flags & 2449 (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) 2450 != DNS_KEYOWNER_ZONE) 2451 continue; 2452 2453 dns_rdata_toregion(&tuple->rdata, &r); 2454 2455 keyid = dst_region_computeid(&r); 2456 2457 buf[0] = dnskey.algorithm; 2458 buf[1] = (keyid & 0xff00) >> 8; 2459 buf[2] = (keyid & 0xff); 2460 buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1; 2461 buf[4] = 0; 2462 rdata.data = buf; 2463 rdata.length = sizeof(buf); 2464 rdata.type = privatetype; 2465 rdata.rdclass = tuple->rdata.rdclass; 2466 2467 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2468 if (flag) 2469 continue; 2470 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, 2471 name, 0, &rdata, &newtuple)); 2472 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2473 INSIST(newtuple == NULL); 2474 /* 2475 * Remove any record which says this operation has already 2476 * completed. 2477 */ 2478 buf[4] = 1; 2479 CHECK(rr_exists(db, ver, name, &rdata, &flag)); 2480 if (flag) { 2481 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, 2482 name, 0, &rdata, &newtuple)); 2483 CHECK(do_one_tuple(&newtuple, db, ver, diff)); 2484 INSIST(newtuple == NULL); 2485 } 2486 } 2487 2488 failure: 2489 dns_diff_clear(&temp_diff); 2490 return (result); 2491} 2492 2493static bool 2494isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) { 2495 isc_result_t result; 2496 bool build_nsec, build_nsec3; 2497 2498 if (dns_db_issecure(db)) 2499 return (true); 2500 2501 result = dns_private_chains(db, ver, privatetype, 2502 &build_nsec, &build_nsec3); 2503 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2504 return (build_nsec || build_nsec3); 2505} 2506 2507static void 2508update_action(isc_task_t *task, isc_event_t *event) { 2509 update_event_t *uev = (update_event_t *) event; 2510 dns_zone_t *zone = uev->zone; 2511 ns_client_t *client = (ns_client_t *)event->ev_arg; 2512 isc_result_t result; 2513 dns_db_t *db = NULL; 2514 dns_dbversion_t *oldver = NULL; 2515 dns_dbversion_t *ver = NULL; 2516 dns_diff_t diff; /* Pending updates. */ 2517 dns_diff_t temp; /* Pending RR existence assertions. */ 2518 bool soa_serial_changed = false; 2519 isc_mem_t *mctx = client->mctx; 2520 dns_rdatatype_t covers; 2521 dns_message_t *request = client->message; 2522 dns_rdataclass_t zoneclass; 2523 dns_name_t *zonename; 2524 dns_ssutable_t *ssutable = NULL; 2525 dns_fixedname_t tmpnamefixed; 2526 dns_name_t *tmpname = NULL; 2527 dns_zoneopt_t options; 2528 dns_difftuple_t *tuple; 2529 dns_rdata_dnskey_t dnskey; 2530 bool had_dnskey; 2531 dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); 2532 dns_ttl_t maxttl = 0; 2533 uint32_t maxrecords; 2534 uint64_t records; 2535 dns_aclenv_t *env = ns_interfacemgr_getaclenv(client->interface->mgr); 2536 2537 INSIST(event->ev_type == DNS_EVENT_UPDATE); 2538 2539 dns_diff_init(mctx, &diff); 2540 dns_diff_init(mctx, &temp); 2541 2542 CHECK(dns_zone_getdb(zone, &db)); 2543 zonename = dns_db_origin(db); 2544 zoneclass = dns_db_class(db); 2545 dns_zone_getssutable(zone, &ssutable); 2546 2547 /* 2548 * Update message processing can leak record existance information 2549 * so check that we are allowed to query this zone. Additionally 2550 * if we would refuse all updates for this zone we bail out here. 2551 */ 2552 CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename, 2553 dns_zone_getupdateacl(zone), ssutable)); 2554 2555 /* 2556 * Get old and new versions now that queryacl has been checked. 2557 */ 2558 dns_db_currentversion(db, &oldver); 2559 CHECK(dns_db_newversion(db, &ver)); 2560 2561 /* 2562 * Check prerequisites. 2563 */ 2564 2565 for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE); 2566 result == ISC_R_SUCCESS; 2567 result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE)) 2568 { 2569 dns_name_t *name = NULL; 2570 dns_rdata_t rdata = DNS_RDATA_INIT; 2571 dns_ttl_t ttl; 2572 dns_rdataclass_t update_class; 2573 bool flag; 2574 2575 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass, 2576 &name, &rdata, &covers, &ttl, &update_class); 2577 2578 if (ttl != 0) 2579 PREREQFAILC(DNS_R_FORMERR, 2580 "prerequisite TTL is not zero"); 2581 2582 if (! dns_name_issubdomain(name, zonename)) 2583 PREREQFAILN(DNS_R_NOTZONE, name, 2584 "prerequisite name is out of zone"); 2585 2586 if (update_class == dns_rdataclass_any) { 2587 if (rdata.length != 0) 2588 PREREQFAILC(DNS_R_FORMERR, 2589 "class ANY prerequisite " 2590 "RDATA is not empty"); 2591 if (rdata.type == dns_rdatatype_any) { 2592 CHECK(name_exists(db, ver, name, &flag)); 2593 if (! flag) { 2594 PREREQFAILN(DNS_R_NXDOMAIN, name, 2595 "'name in use' " 2596 "prerequisite not " 2597 "satisfied"); 2598 } 2599 } else { 2600 CHECK(rrset_exists(db, ver, name, 2601 rdata.type, covers, &flag)); 2602 if (! flag) { 2603 /* RRset does not exist. */ 2604 PREREQFAILNT(DNS_R_NXRRSET, 2605 name, rdata.type, 2606 "'rrset exists (value independent)' " 2607 "prerequisite not satisfied"); 2608 } 2609 } 2610 } else if (update_class == dns_rdataclass_none) { 2611 if (rdata.length != 0) 2612 PREREQFAILC(DNS_R_FORMERR, 2613 "class NONE prerequisite " 2614 "RDATA is not empty"); 2615 if (rdata.type == dns_rdatatype_any) { 2616 CHECK(name_exists(db, ver, name, &flag)); 2617 if (flag) { 2618 PREREQFAILN(DNS_R_YXDOMAIN, name, 2619 "'name not in use' " 2620 "prerequisite not " 2621 "satisfied"); 2622 } 2623 } else { 2624 CHECK(rrset_exists(db, ver, name, 2625 rdata.type, covers, &flag)); 2626 if (flag) { 2627 /* RRset exists. */ 2628 PREREQFAILNT(DNS_R_YXRRSET, name, 2629 rdata.type, 2630 "'rrset does not exist' " 2631 "prerequisite not " 2632 "satisfied"); 2633 } 2634 } 2635 } else if (update_class == zoneclass) { 2636 /* "temp<rr.name, rr.type> += rr;" */ 2637 result = temp_append(&temp, name, &rdata); 2638 if (result != ISC_R_SUCCESS) { 2639 UNEXPECTED_ERROR(__FILE__, __LINE__, 2640 "temp entry creation failed: %s", 2641 dns_result_totext(result)); 2642 FAIL(ISC_R_UNEXPECTED); 2643 } 2644 } else { 2645 PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite"); 2646 } 2647 } 2648 if (result != ISC_R_NOMORE) 2649 FAIL(result); 2650 2651 /* 2652 * Perform the final check of the "rrset exists (value dependent)" 2653 * prerequisites. 2654 */ 2655 if (ISC_LIST_HEAD(temp.tuples) != NULL) { 2656 dns_rdatatype_t type; 2657 2658 /* 2659 * Sort the prerequisite records by owner name, 2660 * type, and rdata. 2661 */ 2662 result = dns_diff_sort(&temp, temp_order); 2663 if (result != ISC_R_SUCCESS) 2664 FAILC(result, "'RRset exists (value dependent)' " 2665 "prerequisite not satisfied"); 2666 2667 tmpname = dns_fixedname_initname(&tmpnamefixed); 2668 result = temp_check(mctx, &temp, db, ver, tmpname, &type); 2669 if (result != ISC_R_SUCCESS) 2670 FAILNT(result, tmpname, type, 2671 "'RRset exists (value dependent)' " 2672 "prerequisite not satisfied"); 2673 } 2674 2675 update_log(client, zone, LOGLEVEL_DEBUG, 2676 "prerequisites are OK"); 2677 2678 /* 2679 * Check Requestor's Permissions. It seems a bit silly to do this 2680 * only after prerequisite testing, but that is what RFC2136 says. 2681 */ 2682 if (ssutable == NULL) 2683 CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone), 2684 "update", zonename, false, false)); 2685 else if (client->signer == NULL && !TCPCLIENT(client)) 2686 CHECK(checkupdateacl(client, NULL, "update", zonename, 2687 false, true)); 2688 2689 if (dns_zone_getupdatedisabled(zone)) 2690 FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled " 2691 "because the zone is frozen. Use " 2692 "'rndc thaw' to re-enable updates."); 2693 2694 /* 2695 * Perform the Update Section Prescan. 2696 */ 2697 2698 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2699 result == ISC_R_SUCCESS; 2700 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2701 { 2702 dns_name_t *name = NULL; 2703 dns_rdata_t rdata = DNS_RDATA_INIT; 2704 dns_ttl_t ttl; 2705 dns_rdataclass_t update_class; 2706 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, 2707 &name, &rdata, &covers, &ttl, &update_class); 2708 2709 if (! dns_name_issubdomain(name, zonename)) 2710 FAILC(DNS_R_NOTZONE, 2711 "update RR is outside zone"); 2712 if (update_class == zoneclass) { 2713 /* 2714 * Check for meta-RRs. The RFC2136 pseudocode says 2715 * check for ANY|AXFR|MAILA|MAILB, but the text adds 2716 * "or any other QUERY metatype" 2717 */ 2718 if (dns_rdatatype_ismeta(rdata.type)) { 2719 FAILC(DNS_R_FORMERR, 2720 "meta-RR in update"); 2721 } 2722 result = dns_zone_checknames(zone, name, &rdata); 2723 if (result != ISC_R_SUCCESS) 2724 FAIL(DNS_R_REFUSED); 2725 } else if (update_class == dns_rdataclass_any) { 2726 if (ttl != 0 || rdata.length != 0 || 2727 (dns_rdatatype_ismeta(rdata.type) && 2728 rdata.type != dns_rdatatype_any)) 2729 FAILC(DNS_R_FORMERR, 2730 "meta-RR in update"); 2731 } else if (update_class == dns_rdataclass_none) { 2732 if (ttl != 0 || 2733 dns_rdatatype_ismeta(rdata.type)) 2734 FAILC(DNS_R_FORMERR, 2735 "meta-RR in update"); 2736 } else { 2737 update_log(client, zone, ISC_LOG_WARNING, 2738 "update RR has incorrect class %d", 2739 update_class); 2740 FAIL(DNS_R_FORMERR); 2741 } 2742 2743 /* 2744 * draft-ietf-dnsind-simple-secure-update-01 says 2745 * "Unlike traditional dynamic update, the client 2746 * is forbidden from updating NSEC records." 2747 */ 2748 if (rdata.type == dns_rdatatype_nsec3) { 2749 FAILC(DNS_R_REFUSED, 2750 "explicit NSEC3 updates are not allowed " 2751 "in secure zones"); 2752 } else if (rdata.type == dns_rdatatype_nsec) { 2753 FAILC(DNS_R_REFUSED, 2754 "explicit NSEC updates are not allowed " 2755 "in secure zones"); 2756 } else if (rdata.type == dns_rdatatype_rrsig && 2757 !dns_name_equal(name, zonename)) { 2758 FAILC(DNS_R_REFUSED, 2759 "explicit RRSIG updates are currently " 2760 "not supported in secure zones except " 2761 "at the apex"); 2762 } 2763 2764 if (ssutable != NULL) { 2765 isc_netaddr_t netaddr; 2766 dst_key_t *tsigkey = NULL; 2767 isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr); 2768 2769 if (client->message->tsigkey != NULL) 2770 tsigkey = client->message->tsigkey->key; 2771 2772 if (rdata.type != dns_rdatatype_any) { 2773 if (!dns_ssutable_checkrules 2774 (ssutable, client->signer, name, &netaddr, 2775 TCPCLIENT(client), 2776 env, rdata.type, tsigkey)) 2777 { 2778 FAILC(DNS_R_REFUSED, 2779 "rejected by secure update"); 2780 } 2781 } else { 2782 if (!ssu_checkall(db, ver, name, ssutable, 2783 client->signer, 2784 &netaddr, env, 2785 TCPCLIENT(client), 2786 tsigkey)) 2787 { 2788 FAILC(DNS_R_REFUSED, 2789 "rejected by secure update"); 2790 } 2791 } 2792 } 2793 } 2794 if (result != ISC_R_NOMORE) 2795 FAIL(result); 2796 2797 update_log(client, zone, LOGLEVEL_DEBUG, 2798 "update section prescan OK"); 2799 2800 /* 2801 * Process the Update Section. 2802 */ 2803 2804 options = dns_zone_getoptions(zone); 2805 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE); 2806 result == ISC_R_SUCCESS; 2807 result = dns_message_nextname(request, DNS_SECTION_UPDATE)) 2808 { 2809 dns_name_t *name = NULL; 2810 dns_rdata_t rdata = DNS_RDATA_INIT; 2811 dns_ttl_t ttl; 2812 dns_rdataclass_t update_class; 2813 bool flag; 2814 2815 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, 2816 &name, &rdata, &covers, &ttl, &update_class); 2817 2818 if (update_class == zoneclass) { 2819 2820 /* 2821 * RFC1123 doesn't allow MF and MD in master zones. 2822 */ 2823 if (rdata.type == dns_rdatatype_md || 2824 rdata.type == dns_rdatatype_mf) { 2825 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2826 2827 dns_rdatatype_format(rdata.type, typebuf, 2828 sizeof(typebuf)); 2829 update_log(client, zone, LOGLEVEL_PROTOCOL, 2830 "attempt to add %s ignored", 2831 typebuf); 2832 continue; 2833 } 2834 if ((rdata.type == dns_rdatatype_ns || 2835 rdata.type == dns_rdatatype_dname) && 2836 dns_name_iswildcard(name)) { 2837 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 2838 2839 dns_rdatatype_format(rdata.type, typebuf, 2840 sizeof(typebuf)); 2841 update_log(client, zone, 2842 LOGLEVEL_PROTOCOL, 2843 "attempt to add wildcard %s record " 2844 "ignored", typebuf); 2845 continue; 2846 } 2847 if (rdata.type == dns_rdatatype_cname) { 2848 CHECK(cname_incompatible_rrset_exists(db, ver, 2849 name, 2850 &flag)); 2851 if (flag) { 2852 update_log(client, zone, 2853 LOGLEVEL_PROTOCOL, 2854 "attempt to add CNAME " 2855 "alongside non-CNAME " 2856 "ignored"); 2857 continue; 2858 } 2859 } else { 2860 CHECK(rrset_exists(db, ver, name, 2861 dns_rdatatype_cname, 0, 2862 &flag)); 2863 if (flag && 2864 ! dns_rdatatype_atcname(rdata.type)) 2865 { 2866 update_log(client, zone, 2867 LOGLEVEL_PROTOCOL, 2868 "attempt to add non-CNAME " 2869 "alongside CNAME ignored"); 2870 continue; 2871 } 2872 } 2873 if (rdata.type == dns_rdatatype_soa) { 2874 bool ok; 2875 CHECK(rrset_exists(db, ver, name, 2876 dns_rdatatype_soa, 0, 2877 &flag)); 2878 if (! flag) { 2879 update_log(client, zone, 2880 LOGLEVEL_PROTOCOL, 2881 "attempt to create 2nd " 2882 "SOA ignored"); 2883 continue; 2884 } 2885 CHECK(check_soa_increment(db, ver, &rdata, 2886 &ok)); 2887 if (! ok) { 2888 update_log(client, zone, 2889 LOGLEVEL_PROTOCOL, 2890 "SOA update failed to " 2891 "increment serial, " 2892 "ignoring it"); 2893 continue; 2894 } 2895 soa_serial_changed = true; 2896 } 2897 2898 if (rdata.type == privatetype) { 2899 update_log(client, zone, LOGLEVEL_PROTOCOL, 2900 "attempt to add a private type " 2901 "(%u) record rejected internal " 2902 "use only", privatetype); 2903 continue; 2904 } 2905 2906 if (rdata.type == dns_rdatatype_nsec3param) { 2907 /* 2908 * Ignore attempts to add NSEC3PARAM records 2909 * with any flags other than OPTOUT. 2910 */ 2911 if ((rdata.data[1] & 2912 ~DNS_NSEC3FLAG_OPTOUT) != 0) 2913 { 2914 update_log(client, zone, 2915 LOGLEVEL_PROTOCOL, 2916 "attempt to add NSEC3PARAM " 2917 "record with non OPTOUT " 2918 "flag"); 2919 continue; 2920 } 2921 } 2922 2923 if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 && 2924 dns_name_internalwildcard(name)) { 2925 char namestr[DNS_NAME_FORMATSIZE]; 2926 dns_name_format(name, namestr, 2927 sizeof(namestr)); 2928 update_log(client, zone, LOGLEVEL_PROTOCOL, 2929 "warning: ownername '%s' contains " 2930 "a non-terminal wildcard", namestr); 2931 } 2932 2933 if ((options & DNS_ZONEOPT_CHECKTTL) != 0) { 2934 maxttl = dns_zone_getmaxttl(zone); 2935 if (ttl > maxttl) { 2936 ttl = maxttl; 2937 update_log(client, zone, 2938 LOGLEVEL_PROTOCOL, 2939 "reducing TTL to the " 2940 "configured max-zone-ttl %d", 2941 maxttl); 2942 } 2943 } 2944 2945 if (isc_log_wouldlog(ns_lctx, LOGLEVEL_PROTOCOL)) { 2946 char namestr[DNS_NAME_FORMATSIZE]; 2947 char typestr[DNS_RDATATYPE_FORMATSIZE]; 2948 char rdstr[2048]; 2949 isc_buffer_t buf; 2950 int len = 0; 2951 const char *truncated = ""; 2952 2953 dns_name_format(name, namestr, sizeof(namestr)); 2954 dns_rdatatype_format(rdata.type, typestr, 2955 sizeof(typestr)); 2956 isc_buffer_init(&buf, rdstr, sizeof(rdstr)); 2957 result = dns_rdata_totext(&rdata, NULL, &buf); 2958 if (result == ISC_R_NOSPACE) { 2959 len = (int)isc_buffer_usedlength(&buf); 2960 truncated = " [TRUNCATED]"; 2961 } else if (result != ISC_R_SUCCESS) { 2962 snprintf(rdstr, sizeof(rdstr), "[dns_" 2963 "rdata_totext failed: %s]", 2964 dns_result_totext(result)); 2965 len = strlen(rdstr); 2966 } else 2967 len = (int)isc_buffer_usedlength(&buf); 2968 update_log(client, zone, LOGLEVEL_PROTOCOL, 2969 "adding an RR at '%s' %s %.*s%s", 2970 namestr, typestr, len, rdstr, 2971 truncated); 2972 } 2973 2974 /* Prepare the affected RRset for the addition. */ 2975 { 2976 add_rr_prepare_ctx_t ctx; 2977 ctx.db = db; 2978 ctx.ver = ver; 2979 ctx.diff = &diff; 2980 ctx.name = name; 2981 ctx.oldname = name; 2982 ctx.update_rr = &rdata; 2983 ctx.update_rr_ttl = ttl; 2984 ctx.ignore_add = false; 2985 dns_diff_init(mctx, &ctx.del_diff); 2986 dns_diff_init(mctx, &ctx.add_diff); 2987 CHECK(foreach_rr(db, ver, name, rdata.type, 2988 covers, add_rr_prepare_action, 2989 &ctx)); 2990 2991 if (ctx.ignore_add) { 2992 dns_diff_clear(&ctx.del_diff); 2993 dns_diff_clear(&ctx.add_diff); 2994 } else { 2995 result = do_diff(&ctx.del_diff, db, ver, 2996 &diff); 2997 if (result == ISC_R_SUCCESS) { 2998 result = do_diff(&ctx.add_diff, 2999 db, ver, 3000 &diff); 3001 } 3002 if (result != ISC_R_SUCCESS) { 3003 dns_diff_clear(&ctx.del_diff); 3004 dns_diff_clear(&ctx.add_diff); 3005 goto failure; 3006 } 3007 CHECK(update_one_rr(db, ver, &diff, 3008 DNS_DIFFOP_ADD, 3009 name, ttl, &rdata)); 3010 } 3011 } 3012 } else if (update_class == dns_rdataclass_any) { 3013 if (rdata.type == dns_rdatatype_any) { 3014 if (isc_log_wouldlog(ns_lctx, 3015 LOGLEVEL_PROTOCOL)) 3016 { 3017 char namestr[DNS_NAME_FORMATSIZE]; 3018 dns_name_format(name, namestr, 3019 sizeof(namestr)); 3020 update_log(client, zone, 3021 LOGLEVEL_PROTOCOL, 3022 "delete all rrsets from " 3023 "name '%s'", namestr); 3024 } 3025 if (dns_name_equal(name, zonename)) { 3026 CHECK(delete_if(type_not_soa_nor_ns_p, 3027 db, ver, name, 3028 dns_rdatatype_any, 0, 3029 &rdata, &diff)); 3030 } else { 3031 CHECK(delete_if(type_not_dnssec, 3032 db, ver, name, 3033 dns_rdatatype_any, 0, 3034 &rdata, &diff)); 3035 } 3036 } else if (dns_name_equal(name, zonename) && 3037 (rdata.type == dns_rdatatype_soa || 3038 rdata.type == dns_rdatatype_ns)) { 3039 update_log(client, zone, LOGLEVEL_PROTOCOL, 3040 "attempt to delete all SOA " 3041 "or NS records ignored"); 3042 continue; 3043 } else { 3044 if (isc_log_wouldlog(ns_lctx, 3045 LOGLEVEL_PROTOCOL)) 3046 { 3047 char namestr[DNS_NAME_FORMATSIZE]; 3048 char typestr[DNS_RDATATYPE_FORMATSIZE]; 3049 dns_name_format(name, namestr, 3050 sizeof(namestr)); 3051 dns_rdatatype_format(rdata.type, 3052 typestr, 3053 sizeof(typestr)); 3054 update_log(client, zone, 3055 LOGLEVEL_PROTOCOL, 3056 "deleting rrset at '%s' %s", 3057 namestr, typestr); 3058 } 3059 CHECK(delete_if(true_p, db, ver, name, 3060 rdata.type, covers, &rdata, 3061 &diff)); 3062 } 3063 } else if (update_class == dns_rdataclass_none) { 3064 char namestr[DNS_NAME_FORMATSIZE]; 3065 char typestr[DNS_RDATATYPE_FORMATSIZE]; 3066 3067 /* 3068 * The (name == zonename) condition appears in 3069 * RFC2136 3.4.2.4 but is missing from the pseudocode. 3070 */ 3071 if (dns_name_equal(name, zonename)) { 3072 if (rdata.type == dns_rdatatype_soa) { 3073 update_log(client, zone, 3074 LOGLEVEL_PROTOCOL, 3075 "attempt to delete SOA " 3076 "ignored"); 3077 continue; 3078 } 3079 if (rdata.type == dns_rdatatype_ns) { 3080 int count; 3081 CHECK(rr_count(db, ver, name, 3082 dns_rdatatype_ns, 3083 0, &count)); 3084 if (count == 1) { 3085 update_log(client, zone, 3086 LOGLEVEL_PROTOCOL, 3087 "attempt to " 3088 "delete last " 3089 "NS ignored"); 3090 continue; 3091 } 3092 } 3093 } 3094 dns_name_format(name, namestr, sizeof(namestr)); 3095 dns_rdatatype_format(rdata.type, typestr, 3096 sizeof(typestr)); 3097 update_log(client, zone, LOGLEVEL_PROTOCOL, 3098 "deleting an RR at %s %s", namestr, typestr); 3099 CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type, 3100 covers, &rdata, &diff)); 3101 } 3102 } 3103 if (result != ISC_R_NOMORE) 3104 FAIL(result); 3105 3106 /* 3107 * Check that any changes to DNSKEY/NSEC3PARAM records make sense. 3108 * If they don't then back out all changes to DNSKEY/NSEC3PARAM 3109 * records. 3110 */ 3111 if (! ISC_LIST_EMPTY(diff.tuples)) 3112 CHECK(check_dnssec(client, zone, db, ver, &diff)); 3113 3114 if (! ISC_LIST_EMPTY(diff.tuples)) { 3115 unsigned int errors = 0; 3116 CHECK(dns_zone_nscheck(zone, db, ver, &errors)); 3117 if (errors != 0) { 3118 update_log(client, zone, LOGLEVEL_PROTOCOL, 3119 "update rejected: post update name server " 3120 "sanity check failed"); 3121 result = DNS_R_REFUSED; 3122 goto failure; 3123 } 3124 } 3125 if (! ISC_LIST_EMPTY(diff.tuples)) { 3126 result = dns_zone_cdscheck(zone, db, ver); 3127 if (result == DNS_R_BADCDS || result == DNS_R_BADCDNSKEY) { 3128 update_log(client, zone, LOGLEVEL_PROTOCOL, 3129 "update rejected: bad %s RRset", 3130 result == DNS_R_BADCDS ? "CDS" : "CDNSKEY"); 3131 result = DNS_R_REFUSED; 3132 goto failure; 3133 } 3134 if (result != ISC_R_SUCCESS) 3135 goto failure; 3136 3137 } 3138 3139 /* 3140 * If any changes were made, increment the SOA serial number, 3141 * update RRSIGs and NSECs (if zone is secure), and write the update 3142 * to the journal. 3143 */ 3144 if (! ISC_LIST_EMPTY(diff.tuples)) { 3145 char *journalfile; 3146 dns_journal_t *journal; 3147 bool has_dnskey; 3148 3149 /* 3150 * Increment the SOA serial, but only if it was not 3151 * changed as a result of an update operation. 3152 */ 3153 if (! soa_serial_changed) { 3154 CHECK(update_soa_serial(db, ver, &diff, mctx, 3155 dns_zone_getserialupdatemethod(zone))); 3156 } 3157 3158 CHECK(check_mx(client, zone, db, ver, &diff)); 3159 3160 CHECK(remove_orphaned_ds(db, ver, &diff)); 3161 3162 CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey, 3163 0, &has_dnskey)); 3164 3165#define ALLOW_SECURE_TO_INSECURE(zone) \ 3166 ((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0) 3167 3168 CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey, 3169 0, &had_dnskey)); 3170 if (!ALLOW_SECURE_TO_INSECURE(zone)) { 3171 if (had_dnskey && !has_dnskey) { 3172 update_log(client, zone, LOGLEVEL_PROTOCOL, 3173 "update rejected: all DNSKEY " 3174 "records removed and " 3175 "'dnssec-secure-to-insecure' " 3176 "not set"); 3177 result = DNS_R_REFUSED; 3178 goto failure; 3179 } 3180 } 3181 3182 CHECK(rollback_private(db, privatetype, ver, &diff)); 3183 3184 CHECK(add_signing_records(db, privatetype, ver, &diff)); 3185 3186 CHECK(add_nsec3param_records(client, zone, db, ver, &diff)); 3187 3188 if (had_dnskey && !has_dnskey) { 3189 /* 3190 * We are transitioning from secure to insecure. 3191 * Cause all NSEC3 chains to be deleted. When the 3192 * the last signature for the DNSKEY records are 3193 * remove any NSEC chain present will also be removed. 3194 */ 3195 CHECK(dns_nsec3param_deletechains(db, ver, zone, 3196 true, &diff)); 3197 } else if (has_dnskey && isdnssec(db, ver, privatetype)) { 3198 dns_update_log_t log; 3199 uint32_t interval = dns_zone_getsigvalidityinterval(zone); 3200 3201 log.func = update_log_cb; 3202 log.arg = client; 3203 result = dns_update_signatures(&log, zone, db, oldver, 3204 ver, &diff, 3205 interval); 3206 3207 if (result != ISC_R_SUCCESS) { 3208 update_log(client, zone, 3209 ISC_LOG_ERROR, 3210 "RRSIG/NSEC/NSEC3 update failed: %s", 3211 isc_result_totext(result)); 3212 goto failure; 3213 } 3214 } 3215 3216 maxrecords = dns_zone_getmaxrecords(zone); 3217 if (maxrecords != 0U) { 3218 result = dns_db_getsize(db, ver, &records, NULL); 3219 if (result == ISC_R_SUCCESS && records > maxrecords) { 3220 update_log(client, zone, ISC_LOG_ERROR, 3221 "records in zone (%" 3222 PRIu64 3223 ") exceeds max-records (%u)", 3224 records, maxrecords); 3225 result = DNS_R_TOOMANYRECORDS; 3226 goto failure; 3227 } 3228 } 3229 3230 journalfile = dns_zone_getjournal(zone); 3231 if (journalfile != NULL) { 3232 update_log(client, zone, LOGLEVEL_DEBUG, 3233 "writing journal %s", journalfile); 3234 3235 journal = NULL; 3236 result = dns_journal_open(mctx, journalfile, 3237 DNS_JOURNAL_CREATE, &journal); 3238 if (result != ISC_R_SUCCESS) 3239 FAILS(result, "journal open failed"); 3240 3241 result = dns_journal_write_transaction(journal, &diff); 3242 if (result != ISC_R_SUCCESS) { 3243 dns_journal_destroy(&journal); 3244 FAILS(result, "journal write failed"); 3245 } 3246 3247 dns_journal_destroy(&journal); 3248 } 3249 3250 /* 3251 * XXXRTH Just a note that this committing code will have 3252 * to change to handle databases that need two-phase 3253 * commit, but this isn't a priority. 3254 */ 3255 update_log(client, zone, LOGLEVEL_DEBUG, 3256 "committing update transaction"); 3257 3258 dns_db_closeversion(db, &ver, true); 3259 3260 /* 3261 * Mark the zone as dirty so that it will be written to disk. 3262 */ 3263 dns_zone_markdirty(zone); 3264 3265 /* 3266 * Notify slaves of the change we just made. 3267 */ 3268 dns_zone_notify(zone); 3269 3270 /* 3271 * Cause the zone to be signed with the key that we 3272 * have just added or have the corresponding signatures 3273 * deleted. 3274 * 3275 * Note: we are already committed to this course of action. 3276 */ 3277 for (tuple = ISC_LIST_HEAD(diff.tuples); 3278 tuple != NULL; 3279 tuple = ISC_LIST_NEXT(tuple, link)) { 3280 isc_region_t r; 3281 dns_secalg_t algorithm; 3282 uint16_t keyid; 3283 3284 if (tuple->rdata.type != dns_rdatatype_dnskey) 3285 continue; 3286 3287 dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL); 3288 if ((dnskey.flags & 3289 (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH)) 3290 != DNS_KEYOWNER_ZONE) 3291 continue; 3292 3293 dns_rdata_toregion(&tuple->rdata, &r); 3294 algorithm = dnskey.algorithm; 3295 keyid = dst_region_computeid(&r); 3296 3297 result = dns_zone_signwithkey(zone, algorithm, keyid, 3298 (tuple->op == DNS_DIFFOP_DEL)); 3299 if (result != ISC_R_SUCCESS) { 3300 update_log(client, zone, ISC_LOG_ERROR, 3301 "dns_zone_signwithkey failed: %s", 3302 dns_result_totext(result)); 3303 } 3304 } 3305 3306 /* 3307 * Cause the zone to add/delete NSEC3 chains for the 3308 * deferred NSEC3PARAM changes. 3309 * 3310 * Note: we are already committed to this course of action. 3311 */ 3312 for (tuple = ISC_LIST_HEAD(diff.tuples); 3313 tuple != NULL; 3314 tuple = ISC_LIST_NEXT(tuple, link)) { 3315 unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE]; 3316 dns_rdata_t rdata = DNS_RDATA_INIT; 3317 dns_rdata_nsec3param_t nsec3param; 3318 3319 if (tuple->rdata.type != privatetype || 3320 tuple->op != DNS_DIFFOP_ADD) 3321 continue; 3322 3323 if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata, 3324 buf, sizeof(buf))) 3325 continue; 3326 dns_rdata_tostruct(&rdata, &nsec3param, NULL); 3327 if (nsec3param.flags == 0) 3328 continue; 3329 3330 result = dns_zone_addnsec3chain(zone, &nsec3param); 3331 if (result != ISC_R_SUCCESS) { 3332 update_log(client, zone, ISC_LOG_ERROR, 3333 "dns_zone_addnsec3chain failed: %s", 3334 dns_result_totext(result)); 3335 } 3336 } 3337 } else { 3338 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request"); 3339 dns_db_closeversion(db, &ver, true); 3340 } 3341 result = ISC_R_SUCCESS; 3342 goto common; 3343 3344 failure: 3345 /* 3346 * The reason for failure should have been logged at this point. 3347 */ 3348 if (ver != NULL) { 3349 update_log(client, zone, LOGLEVEL_DEBUG, 3350 "rolling back"); 3351 dns_db_closeversion(db, &ver, false); 3352 } 3353 3354 common: 3355 dns_diff_clear(&temp); 3356 dns_diff_clear(&diff); 3357 3358 if (oldver != NULL) 3359 dns_db_closeversion(db, &oldver, false); 3360 3361 if (db != NULL) 3362 dns_db_detach(&db); 3363 3364 if (ssutable != NULL) 3365 dns_ssutable_detach(&ssutable); 3366 3367 isc_task_detach(&task); 3368 uev->result = result; 3369 if (zone != NULL) 3370 INSIST(uev->zone == zone); /* we use this later */ 3371 uev->ev_type = DNS_EVENT_UPDATEDONE; 3372 uev->ev_action = updatedone_action; 3373 isc_task_send(client->task, &event); 3374 3375 INSIST(ver == NULL); 3376 INSIST(event == NULL); 3377} 3378 3379static void 3380updatedone_action(isc_task_t *task, isc_event_t *event) { 3381 update_event_t *uev = (update_event_t *) event; 3382 ns_client_t *client = (ns_client_t *) event->ev_arg; 3383 3384 UNUSED(task); 3385 3386 INSIST(event->ev_type == DNS_EVENT_UPDATEDONE); 3387 INSIST(task == client->task); 3388 3389 INSIST(client->nupdates > 0); 3390 switch (uev->result) { 3391 case ISC_R_SUCCESS: 3392 inc_stats(client, uev->zone, ns_statscounter_updatedone); 3393 break; 3394 case DNS_R_REFUSED: 3395 inc_stats(client, uev->zone, ns_statscounter_updaterej); 3396 break; 3397 default: 3398 inc_stats(client, uev->zone, ns_statscounter_updatefail); 3399 break; 3400 } 3401 if (uev->zone != NULL) 3402 dns_zone_detach(&uev->zone); 3403 client->nupdates--; 3404 respond(client, uev->result); 3405 isc_event_free(&event); 3406 ns_client_detach(&client); 3407} 3408 3409/*% 3410 * Update forwarding support. 3411 */ 3412 3413static void 3414forward_fail(isc_task_t *task, isc_event_t *event) { 3415 ns_client_t *client = (ns_client_t *)event->ev_arg; 3416 3417 UNUSED(task); 3418 3419 INSIST(client->nupdates > 0); 3420 client->nupdates--; 3421 respond(client, DNS_R_SERVFAIL); 3422 isc_event_free(&event); 3423 ns_client_detach(&client); 3424} 3425 3426 3427static void 3428forward_callback(void *arg, isc_result_t result, dns_message_t *answer) { 3429 update_event_t *uev = arg; 3430 ns_client_t *client = uev->ev_arg; 3431 dns_zone_t *zone = uev->zone; 3432 3433 if (result != ISC_R_SUCCESS) { 3434 INSIST(answer == NULL); 3435 uev->ev_type = DNS_EVENT_UPDATEDONE; 3436 uev->ev_action = forward_fail; 3437 inc_stats(client, zone, ns_statscounter_updatefwdfail); 3438 } else { 3439 uev->ev_type = DNS_EVENT_UPDATEDONE; 3440 uev->ev_action = forward_done; 3441 uev->answer = answer; 3442 inc_stats(client, zone, ns_statscounter_updaterespfwd); 3443 } 3444 isc_task_send(client->task, ISC_EVENT_PTR(&uev)); 3445 dns_zone_detach(&zone); 3446} 3447 3448static void 3449forward_done(isc_task_t *task, isc_event_t *event) { 3450 update_event_t *uev = (update_event_t *) event; 3451 ns_client_t *client = (ns_client_t *)event->ev_arg; 3452 3453 UNUSED(task); 3454 3455 INSIST(client->nupdates > 0); 3456 client->nupdates--; 3457 ns_client_sendraw(client, uev->answer); 3458 dns_message_destroy(&uev->answer); 3459 isc_event_free(&event); 3460 ns_client_detach(&client); 3461} 3462 3463static void 3464forward_action(isc_task_t *task, isc_event_t *event) { 3465 update_event_t *uev = (update_event_t *) event; 3466 dns_zone_t *zone = uev->zone; 3467 ns_client_t *client = (ns_client_t *)event->ev_arg; 3468 isc_result_t result; 3469 3470 result = dns_zone_forwardupdate(zone, client->message, 3471 forward_callback, event); 3472 if (result != ISC_R_SUCCESS) { 3473 uev->ev_type = DNS_EVENT_UPDATEDONE; 3474 uev->ev_action = forward_fail; 3475 isc_task_send(client->task, &event); 3476 inc_stats(client, zone, ns_statscounter_updatefwdfail); 3477 dns_zone_detach(&zone); 3478 } else 3479 inc_stats(client, zone, ns_statscounter_updatereqfwd); 3480 isc_task_detach(&task); 3481} 3482 3483static isc_result_t 3484send_forward_event(ns_client_t *client, dns_zone_t *zone) { 3485 char namebuf[DNS_NAME_FORMATSIZE]; 3486 char classbuf[DNS_RDATACLASS_FORMATSIZE]; 3487 isc_result_t result = ISC_R_SUCCESS; 3488 update_event_t *event = NULL; 3489 isc_task_t *zonetask = NULL; 3490 ns_client_t *evclient; 3491 3492 /* 3493 * This may take some time so replace this client. 3494 */ 3495 if (!client->mortal && (client->attributes & NS_CLIENTATTR_TCP) == 0) 3496 CHECK(ns_client_replace(client)); 3497 3498 event = (update_event_t *) 3499 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE, 3500 forward_action, NULL, sizeof(*event)); 3501 if (event == NULL) 3502 FAIL(ISC_R_NOMEMORY); 3503 event->zone = zone; 3504 event->result = ISC_R_SUCCESS; 3505 3506 evclient = NULL; 3507 ns_client_attach(client, &evclient); 3508 INSIST(client->nupdates == 0); 3509 client->nupdates++; 3510 event->ev_arg = evclient; 3511 3512 dns_name_format(dns_zone_getorigin(zone), namebuf, 3513 sizeof(namebuf)); 3514 dns_rdataclass_format(dns_zone_getclass(zone), classbuf, 3515 sizeof(classbuf)); 3516 3517 ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, 3518 LOGLEVEL_PROTOCOL, "forwarding update for zone '%s/%s'", 3519 namebuf, classbuf); 3520 3521 dns_zone_gettask(zone, &zonetask); 3522 isc_task_send(zonetask, ISC_EVENT_PTR(&event)); 3523 3524 failure: 3525 if (event != NULL) 3526 isc_event_free(ISC_EVENT_PTR(&event)); 3527 return (result); 3528} 3529