2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: update.c,v 1.138.2.13 2009/07/28 15:54:31 marka Exp $ */
22 #include <isc/print.h>
23 #include <isc/stats.h>
24 #include <isc/string.h>
25 #include <isc/taskpool.h>
29 #include <dns/dbiterator.h>
31 #include <dns/dnssec.h>
32 #include <dns/events.h>
33 #include <dns/fixedname.h>
34 #include <dns/journal.h>
35 #include <dns/keyvalues.h>
36 #include <dns/message.h>
38 #include <dns/rdataclass.h>
39 #include <dns/rdataset.h>
40 #include <dns/rdatasetiter.h>
41 #include <dns/rdatastruct.h>
42 #include <dns/rdatatype.h>
49 #include <named/client.h>
50 #include <named/log.h>
51 #include <named/server.h>
52 #include <named/update.h>
56 * This module implements dynamic update as in RFC2136.
61 * - document strict minimality
64 /**************************************************************************/
67 * Log level for tracing dynamic update protocol requests.
69 #define LOGLEVEL_PROTOCOL ISC_LOG_INFO
72 * Log level for low-level debug tracing.
74 #define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8)
77 * Check an operation for failure. These macros all assume that
78 * the function using them has a 'result' variable and a 'failure'
83 if (result != ISC_R_SUCCESS) goto failure; \
87 * Fail unconditionally with result 'code', which must not
88 * be ISC_R_SUCCESS. The reason for failure presumably has
89 * been logged already.
91 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
92 * from complaining about "end-of-loop code not reached".
98 if (result != ISC_R_SUCCESS) goto failure; \
102 * Fail unconditionally and log as a client error.
103 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
104 * from complaining about "end-of-loop code not reached".
106 #define FAILC(code, msg) \
108 const char *_what = "failed"; \
111 case DNS_R_NXDOMAIN: \
112 case DNS_R_YXDOMAIN: \
113 case DNS_R_YXRRSET: \
114 case DNS_R_NXRRSET: \
115 _what = "unsuccessful"; \
117 update_log(client, zone, LOGLEVEL_PROTOCOL, \
118 "update %s: %s (%s)", _what, \
119 msg, isc_result_totext(result)); \
120 if (result != ISC_R_SUCCESS) goto failure; \
122 #define PREREQFAILC(code, msg) \
124 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
128 #define FAILN(code, name, msg) \
130 const char *_what = "failed"; \
133 case DNS_R_NXDOMAIN: \
134 case DNS_R_YXDOMAIN: \
135 case DNS_R_YXRRSET: \
136 case DNS_R_NXRRSET: \
137 _what = "unsuccessful"; \
139 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \
140 char _nbuf[DNS_NAME_FORMATSIZE]; \
141 dns_name_format(name, _nbuf, sizeof(_nbuf)); \
142 update_log(client, zone, LOGLEVEL_PROTOCOL, \
143 "update %s: %s: %s (%s)", _what, _nbuf, \
144 msg, isc_result_totext(result)); \
146 if (result != ISC_R_SUCCESS) goto failure; \
148 #define PREREQFAILN(code, name, msg) \
150 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
151 FAILN(code, name, msg); \
154 #define FAILNT(code, name, type, msg) \
156 const char *_what = "failed"; \
159 case DNS_R_NXDOMAIN: \
160 case DNS_R_YXDOMAIN: \
161 case DNS_R_YXRRSET: \
162 case DNS_R_NXRRSET: \
163 _what = "unsuccessful"; \
165 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \
166 char _nbuf[DNS_NAME_FORMATSIZE]; \
167 char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \
168 dns_name_format(name, _nbuf, sizeof(_nbuf)); \
169 dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
170 update_log(client, zone, LOGLEVEL_PROTOCOL, \
171 "update %s: %s/%s: %s (%s)", \
172 _what, _nbuf, _tbuf, msg, \
173 isc_result_totext(result)); \
175 if (result != ISC_R_SUCCESS) goto failure; \
177 #define PREREQFAILNT(code, name, type, msg) \
179 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
180 FAILNT(code, name, type, msg); \
184 * Fail unconditionally and log as a server error.
185 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
186 * from complaining about "end-of-loop code not reached".
188 #define FAILS(code, msg) \
191 update_log(client, zone, LOGLEVEL_PROTOCOL, \
193 msg, isc_result_totext(result)); \
194 if (result != ISC_R_SUCCESS) goto failure; \
197 /**************************************************************************/
199 typedef struct rr rr_t;
202 /* dns_name_t name; */
207 typedef struct update_event update_event_t;
209 struct update_event {
210 ISC_EVENT_COMMON(update_event_t);
213 dns_message_t *answer;
216 /**************************************************************************/
218 * Forward declarations.
221 static void update_action(isc_task_t *task, isc_event_t *event);
222 static void updatedone_action(isc_task_t *task, isc_event_t *event);
223 static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone);
224 static void forward_done(isc_task_t *task, isc_event_t *event);
226 /**************************************************************************/
229 update_log(ns_client_t *client, dns_zone_t *zone,
230 int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
233 update_log(ns_client_t *client, dns_zone_t *zone,
234 int level, const char *fmt, ...)
238 char namebuf[DNS_NAME_FORMATSIZE];
239 char classbuf[DNS_RDATACLASS_FORMATSIZE];
241 if (client == NULL || zone == NULL)
244 if (isc_log_wouldlog(ns_g_lctx, level) == ISC_FALSE)
247 dns_name_format(dns_zone_getorigin(zone), namebuf,
249 dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
253 vsnprintf(message, sizeof(message), fmt, ap);
256 ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
257 level, "updating zone '%s/%s': %s",
258 namebuf, classbuf, message);
262 * Increment updated-related statistics counters.
265 inc_stats(dns_zone_t *zone, isc_statscounter_t counter) {
266 isc_stats_increment(ns_g_server->nsstats, counter);
269 isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
270 if (zonestats != NULL)
271 isc_stats_increment(zonestats, counter);
276 * Override the default acl logging when checking whether a client
277 * can update the zone or whether we can forward the request to the
278 * master based on IP address.
280 * 'message' contains the type of operation that is being attempted.
281 * 'slave' indicates if this is a slave zone. If 'acl' is NULL then
283 * If the zone has no access controls configured ('acl' == NULL &&
284 * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise
287 * If the request was signed log that we received it.
290 checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message,
291 dns_name_t *zonename, isc_boolean_t slave,
292 isc_boolean_t has_ssutable)
294 char namebuf[DNS_NAME_FORMATSIZE];
295 char classbuf[DNS_RDATACLASS_FORMATSIZE];
296 int level = ISC_LOG_ERROR;
297 const char *msg = "denied";
300 if (slave && acl == NULL) {
301 result = DNS_R_NOTIMP;
302 level = ISC_LOG_DEBUG(3);
305 result = ns_client_checkaclsilent(client, NULL, acl, ISC_FALSE);
306 if (result == ISC_R_SUCCESS) {
307 level = ISC_LOG_DEBUG(3);
309 } else if (acl == NULL && !has_ssutable) {
310 level = ISC_LOG_INFO;
314 if (client->signer != NULL) {
315 dns_name_format(client->signer, namebuf, sizeof(namebuf));
316 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
317 NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
318 "signer \"%s\" %s", namebuf, msg);
321 dns_name_format(zonename, namebuf, sizeof(namebuf));
322 dns_rdataclass_format(client->view->rdclass, classbuf,
325 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
326 NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s",
327 message, namebuf, classbuf, msg);
332 * Update a single RR in version 'ver' of 'db' and log the
336 * \li '*tuple' == NULL. Either the tuple is freed, or its
337 * ownership has been transferred to the diff.
340 do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
343 dns_diff_t temp_diff;
347 * Create a singleton diff.
349 dns_diff_init(diff->mctx, &temp_diff);
350 ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
353 * Apply it to the database.
355 result = dns_diff_apply(&temp_diff, db, ver);
356 ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
357 if (result != ISC_R_SUCCESS) {
358 dns_difftuple_free(tuple);
363 * Merge it into the current pending journal entry.
365 dns_diff_appendminimal(diff, tuple);
368 * Do not clear temp_diff.
370 return (ISC_R_SUCCESS);
374 * Perform the updates in 'updates' in version 'ver' of 'db' and log the
378 * \li 'updates' is empty.
381 do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver,
385 while (! ISC_LIST_EMPTY(updates->tuples)) {
386 dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples);
387 ISC_LIST_UNLINK(updates->tuples, t, link);
388 CHECK(do_one_tuple(&t, db, ver, diff));
390 return (ISC_R_SUCCESS);
393 dns_diff_clear(diff);
398 update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
399 dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
402 dns_difftuple_t *tuple = NULL;
404 result = dns_difftuple_create(diff->mctx, op,
405 name, ttl, rdata, &tuple);
406 if (result != ISC_R_SUCCESS)
408 return (do_one_tuple(&tuple, db, ver, diff));
411 /**************************************************************************/
413 * Callback-style iteration over rdatasets and rdatas.
415 * foreach_rrset() can be used to iterate over the RRsets
416 * of a name and call a callback function with each
417 * one. Similarly, foreach_rr() can be used to iterate
418 * over the individual RRs at name, optionally restricted
419 * to RRs of a given type.
421 * The callback functions are called "actions" and take
422 * two arguments: a void pointer for passing arbitrary
423 * context information, and a pointer to the current RRset
424 * or RR. By convention, their names end in "_action".
428 * XXXRTH We might want to make this public somewhere in libdns.
432 * Function type for foreach_rrset() iterator actions.
434 typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
437 * Function type for foreach_rr() iterator actions.
439 typedef isc_result_t rr_func(void *data, rr_t *rr);
442 * Internal context struct for foreach_node_rr().
446 void * rr_action_data;
447 } foreach_node_rr_ctx_t;
450 * Internal helper function for foreach_node_rr().
453 foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
455 foreach_node_rr_ctx_t *ctx = data;
456 for (result = dns_rdataset_first(rdataset);
457 result == ISC_R_SUCCESS;
458 result = dns_rdataset_next(rdataset))
460 rr_t rr = { 0, DNS_RDATA_INIT };
462 dns_rdataset_current(rdataset, &rr.rdata);
463 rr.ttl = rdataset->ttl;
464 result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
465 if (result != ISC_R_SUCCESS)
468 if (result != ISC_R_NOMORE)
470 return (ISC_R_SUCCESS);
474 * For each rdataset of 'name' in 'ver' of 'db', call 'action'
475 * with the rdataset and 'action_data' as arguments. If the name
476 * does not exist, do nothing.
478 * If 'action' returns an error, abort iteration and return the error.
481 foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
482 rrset_func *action, void *action_data)
486 dns_rdatasetiter_t *iter;
489 result = dns_db_findnode(db, name, ISC_FALSE, &node);
490 if (result == ISC_R_NOTFOUND)
491 return (ISC_R_SUCCESS);
492 if (result != ISC_R_SUCCESS)
496 result = dns_db_allrdatasets(db, node, ver,
497 (isc_stdtime_t) 0, &iter);
498 if (result != ISC_R_SUCCESS)
501 for (result = dns_rdatasetiter_first(iter);
502 result == ISC_R_SUCCESS;
503 result = dns_rdatasetiter_next(iter))
505 dns_rdataset_t rdataset;
507 dns_rdataset_init(&rdataset);
508 dns_rdatasetiter_current(iter, &rdataset);
510 result = (*action)(action_data, &rdataset);
512 dns_rdataset_disassociate(&rdataset);
513 if (result != ISC_R_SUCCESS)
514 goto cleanup_iterator;
516 if (result == ISC_R_NOMORE)
517 result = ISC_R_SUCCESS;
520 dns_rdatasetiter_destroy(&iter);
523 dns_db_detachnode(db, &node);
529 * For each RR of 'name' in 'ver' of 'db', call 'action'
530 * with the RR and 'action_data' as arguments. If the name
531 * does not exist, do nothing.
533 * If 'action' returns an error, abort iteration
534 * and return the error.
537 foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
538 rr_func *rr_action, void *rr_action_data)
540 foreach_node_rr_ctx_t ctx;
541 ctx.rr_action = rr_action;
542 ctx.rr_action_data = rr_action_data;
543 return (foreach_rrset(db, ver, name,
544 foreach_node_rr_action, &ctx));
549 * For each of the RRs specified by 'db', 'ver', 'name', 'type',
550 * (which can be dns_rdatatype_any to match any type), and 'covers', call
551 * 'action' with the RR and 'action_data' as arguments. If the name
552 * does not exist, or if no RRset of the given type exists at the name,
555 * If 'action' returns an error, abort iteration and return the error.
558 foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
559 dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
560 void *rr_action_data)
565 dns_rdataset_t rdataset;
567 if (type == dns_rdatatype_any)
568 return (foreach_node_rr(db, ver, name,
569 rr_action, rr_action_data));
572 result = dns_db_findnode(db, name, ISC_FALSE, &node);
573 if (result == ISC_R_NOTFOUND)
574 return (ISC_R_SUCCESS);
575 if (result != ISC_R_SUCCESS)
578 dns_rdataset_init(&rdataset);
579 result = dns_db_findrdataset(db, node, ver, type, covers,
580 (isc_stdtime_t) 0, &rdataset, NULL);
581 if (result == ISC_R_NOTFOUND) {
582 result = ISC_R_SUCCESS;
585 if (result != ISC_R_SUCCESS)
588 for (result = dns_rdataset_first(&rdataset);
589 result == ISC_R_SUCCESS;
590 result = dns_rdataset_next(&rdataset))
592 rr_t rr = { 0, DNS_RDATA_INIT };
593 dns_rdataset_current(&rdataset, &rr.rdata);
594 rr.ttl = rdataset.ttl;
595 result = (*rr_action)(rr_action_data, &rr);
596 if (result != ISC_R_SUCCESS)
597 goto cleanup_rdataset;
599 if (result != ISC_R_NOMORE)
600 goto cleanup_rdataset;
601 result = ISC_R_SUCCESS;
604 dns_rdataset_disassociate(&rdataset);
606 dns_db_detachnode(db, &node);
611 /**************************************************************************/
613 * Various tests on the database contents (for prerequisites, etc).
617 * Function type for predicate functions that compare a database RR 'db_rr'
618 * against an update RR 'update_rr'.
620 typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
623 * Helper function for rrset_exists().
626 rrset_exists_action(void *data, rr_t *rr) {
629 return (ISC_R_EXISTS);
633 * Utility macro for RR existence checking functions.
635 * If the variable 'result' has the value ISC_R_EXISTS or
636 * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
637 * respectively, and return success.
639 * If 'result' has any other value, there was a failure.
640 * Return the failure result code and do not set *exists.
642 * This would be more readable as "do { if ... } while(0)",
643 * but that form generates tons of warnings on Solaris 2.6.
645 #define RETURN_EXISTENCE_FLAG \
646 return ((result == ISC_R_EXISTS) ? \
647 (*exists = ISC_TRUE, ISC_R_SUCCESS) : \
648 ((result == ISC_R_SUCCESS) ? \
649 (*exists = ISC_FALSE, ISC_R_SUCCESS) : \
653 * Set '*exists' to true iff an rrset of the given type exists,
654 * to false otherwise.
657 rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
658 dns_rdatatype_t type, dns_rdatatype_t covers,
659 isc_boolean_t *exists)
662 result = foreach_rr(db, ver, name, type, covers,
663 rrset_exists_action, NULL);
664 RETURN_EXISTENCE_FLAG;
668 * Set '*visible' to true if the RRset exists and is part of the
669 * visible zone. Otherwise '*visible' is set to false unless a
673 rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
674 dns_rdatatype_t type, isc_boolean_t *visible)
677 dns_fixedname_t fixed;
679 dns_fixedname_init(&fixed);
680 result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD,
681 (isc_stdtime_t) 0, NULL,
682 dns_fixedname_name(&fixed), NULL, NULL);
688 * Glue, obscured, deleted or replaced records.
690 case DNS_R_DELEGATION:
695 case DNS_R_EMPTYNAME:
696 case DNS_R_COVERINGNSEC:
697 *visible = ISC_FALSE;
698 result = ISC_R_SUCCESS;
707 * Helper function for cname_incompatible_rrset_exists.
710 cname_compatibility_action(void *data, dns_rdataset_t *rrset) {
712 if (rrset->type != dns_rdatatype_cname &&
713 ! dns_rdatatype_isdnssec(rrset->type))
714 return (ISC_R_EXISTS);
715 return (ISC_R_SUCCESS);
719 * Check whether there is an rrset incompatible with adding a CNAME RR,
720 * i.e., anything but another CNAME (which can be replaced) or a
721 * DNSSEC RR (which can coexist).
723 * If such an incompatible rrset exists, set '*exists' to ISC_TRUE.
724 * Otherwise, set it to ISC_FALSE.
727 cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
728 dns_name_t *name, isc_boolean_t *exists) {
730 result = foreach_rrset(db, ver, name,
731 cname_compatibility_action, NULL);
732 RETURN_EXISTENCE_FLAG;
736 * Helper function for rr_count().
739 count_rr_action(void *data, rr_t *rr) {
743 return (ISC_R_SUCCESS);
747 * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'.
750 rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
751 dns_rdatatype_t type, dns_rdatatype_t covers, int *countp)
754 return (foreach_rr(db, ver, name, type, covers,
755 count_rr_action, countp));
759 * Context struct and helper function for name_exists().
763 name_exists_action(void *data, dns_rdataset_t *rrset) {
766 return (ISC_R_EXISTS);
770 * Set '*exists' to true iff the given name exists, to false otherwise.
773 name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
774 isc_boolean_t *exists)
777 result = foreach_rrset(db, ver, name,
778 name_exists_action, NULL);
779 RETURN_EXISTENCE_FLAG;
785 dns_ssutable_t *table;
789 ssu_checkrule(void *data, dns_rdataset_t *rrset) {
790 ssu_check_t *ssuinfo = data;
791 isc_boolean_t result;
794 * If we're deleting all records, it's ok to delete RRSIG and NSEC even
795 * if we're normally not allowed to.
797 if (rrset->type == dns_rdatatype_rrsig ||
798 rrset->type == dns_rdatatype_nsec)
799 return (ISC_R_SUCCESS);
800 result = dns_ssutable_checkrules(ssuinfo->table, ssuinfo->signer,
801 ssuinfo->name, rrset->type);
802 return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE);
806 ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
807 dns_ssutable_t *ssutable, dns_name_t *signer)
813 ssuinfo.table = ssutable;
814 ssuinfo.signer = signer;
815 result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
816 return (ISC_TF(result == ISC_R_SUCCESS));
819 /**************************************************************************/
821 * Checking of "RRset exists (value dependent)" prerequisites.
823 * In the RFC2136 section 3.2.5, this is the pseudocode involving
824 * a variable called "temp", a mapping of <name, type> tuples to rrsets.
826 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
827 * where each tuple has op==DNS_DIFFOP_EXISTS.
832 * Append a tuple asserting the existence of the RR with
833 * 'name' and 'rdata' to 'diff'.
836 temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) {
838 dns_difftuple_t *tuple = NULL;
840 REQUIRE(DNS_DIFF_VALID(diff));
841 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS,
842 name, 0, rdata, &tuple));
843 ISC_LIST_APPEND(diff->tuples, tuple, link);
849 * Compare two rdatasets represented as sorted lists of tuples.
850 * All list elements must have the same owner name and type.
851 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset)
855 temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) {
857 if (a == NULL || b == NULL)
859 INSIST(a->op == DNS_DIFFOP_EXISTS &&
860 b->op == DNS_DIFFOP_EXISTS);
861 INSIST(a->rdata.type == b->rdata.type);
862 INSIST(dns_name_equal(&a->name, &b->name));
863 if (dns_rdata_compare(&a->rdata, &b->rdata) != 0)
864 return (DNS_R_NXRRSET);
865 a = ISC_LIST_NEXT(a, link);
866 b = ISC_LIST_NEXT(b, link);
868 if (a != NULL || b != NULL)
869 return (DNS_R_NXRRSET);
870 return (ISC_R_SUCCESS);
874 * A comparison function defining the sorting order for the entries
875 * in the "temp" data structure. The major sort key is the owner name,
876 * followed by the type and rdata.
879 temp_order(const void *av, const void *bv) {
880 dns_difftuple_t const * const *ap = av;
881 dns_difftuple_t const * const *bp = bv;
882 dns_difftuple_t const *a = *ap;
883 dns_difftuple_t const *b = *bp;
885 r = dns_name_compare(&a->name, &b->name);
888 r = (b->rdata.type - a->rdata.type);
891 r = dns_rdata_compare(&a->rdata, &b->rdata);
896 * Check the "RRset exists (value dependent)" prerequisite information
897 * in 'temp' against the contents of the database 'db'.
899 * Return ISC_R_SUCCESS if the prerequisites are satisfied,
900 * rcode(dns_rcode_nxrrset) if not.
902 * 'temp' must be pre-sorted.
906 temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
907 dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep)
915 dns_diff_init(mctx, &trash);
918 * For each name and type in the prerequisites,
919 * construct a sorted rdata list of the corresponding
920 * database contents, and compare the lists.
922 t = ISC_LIST_HEAD(temp->tuples);
925 (void)dns_name_copy(name, tmpname, NULL);
926 *typep = t->rdata.type;
928 /* A new unique name begins here. */
930 result = dns_db_findnode(db, name, ISC_FALSE, &node);
931 if (result == ISC_R_NOTFOUND) {
932 dns_diff_clear(&trash);
933 return (DNS_R_NXRRSET);
935 if (result != ISC_R_SUCCESS) {
936 dns_diff_clear(&trash);
940 /* A new unique type begins here. */
941 while (t != NULL && dns_name_equal(&t->name, name)) {
942 dns_rdatatype_t type, covers;
943 dns_rdataset_t rdataset;
944 dns_diff_t d_rrs; /* Database RRs with
945 this name and type */
946 dns_diff_t u_rrs; /* Update RRs with
947 this name and type */
949 *typep = type = t->rdata.type;
950 if (type == dns_rdatatype_rrsig ||
951 type == dns_rdatatype_sig)
952 covers = dns_rdata_covers(&t->rdata);
953 else if (type == dns_rdatatype_any) {
954 dns_db_detachnode(db, &node);
955 dns_diff_clear(&trash);
956 return (DNS_R_NXRRSET);
961 * Collect all database RRs for this name and type
962 * onto d_rrs and sort them.
964 dns_rdataset_init(&rdataset);
965 result = dns_db_findrdataset(db, node, ver, type,
966 covers, (isc_stdtime_t) 0,
968 if (result != ISC_R_SUCCESS) {
969 dns_db_detachnode(db, &node);
970 dns_diff_clear(&trash);
971 return (DNS_R_NXRRSET);
974 dns_diff_init(mctx, &d_rrs);
975 dns_diff_init(mctx, &u_rrs);
977 for (result = dns_rdataset_first(&rdataset);
978 result == ISC_R_SUCCESS;
979 result = dns_rdataset_next(&rdataset))
981 dns_rdata_t rdata = DNS_RDATA_INIT;
982 dns_rdataset_current(&rdataset, &rdata);
983 result = temp_append(&d_rrs, name, &rdata);
984 if (result != ISC_R_SUCCESS)
987 if (result != ISC_R_NOMORE)
989 result = dns_diff_sort(&d_rrs, temp_order);
990 if (result != ISC_R_SUCCESS)
994 * Collect all update RRs for this name and type
995 * onto u_rrs. No need to sort them here -
996 * they are already sorted.
999 dns_name_equal(&t->name, name) &&
1000 t->rdata.type == type)
1002 dns_difftuple_t *next =
1003 ISC_LIST_NEXT(t, link);
1004 ISC_LIST_UNLINK(temp->tuples, t, link);
1005 ISC_LIST_APPEND(u_rrs.tuples, t, link);
1009 /* Compare the two sorted lists. */
1010 result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples),
1011 ISC_LIST_HEAD(d_rrs.tuples));
1012 if (result != ISC_R_SUCCESS)
1016 * We are done with the tuples, but we can't free
1017 * them yet because "name" still points into one
1018 * of them. Move them on a temporary list.
1020 ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link);
1021 ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link);
1022 dns_rdataset_disassociate(&rdataset);
1027 dns_diff_clear(&d_rrs);
1028 dns_diff_clear(&u_rrs);
1029 dns_diff_clear(&trash);
1030 dns_rdataset_disassociate(&rdataset);
1031 dns_db_detachnode(db, &node);
1035 dns_db_detachnode(db, &node);
1038 dns_diff_clear(&trash);
1039 return (ISC_R_SUCCESS);
1042 /**************************************************************************/
1044 * Conditional deletion of RRs.
1048 * Context structure for delete_if().
1052 rr_predicate *predicate;
1054 dns_dbversion_t *ver;
1057 dns_rdata_t *update_rr;
1058 } conditional_delete_ctx_t;
1061 * Predicate functions for delete_if().
1065 * Return true iff 'db_rr' is neither a SOA nor an NS RR nor
1066 * an RRSIG nor a NSEC.
1068 static isc_boolean_t
1069 type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1071 return ((db_rr->type != dns_rdatatype_soa &&
1072 db_rr->type != dns_rdatatype_ns &&
1073 db_rr->type != dns_rdatatype_rrsig &&
1074 db_rr->type != dns_rdatatype_nsec) ?
1075 ISC_TRUE : ISC_FALSE);
1079 * Return true iff 'db_rr' is neither a RRSIG nor a NSEC.
1081 static isc_boolean_t
1082 type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1084 return ((db_rr->type != dns_rdatatype_rrsig &&
1085 db_rr->type != dns_rdatatype_nsec) ?
1086 ISC_TRUE : ISC_FALSE);
1090 * Return true always.
1092 static isc_boolean_t
1093 true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1100 * Return true if the record is a RRSIG.
1102 static isc_boolean_t
1103 rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1105 return ((db_rr->type == dns_rdatatype_rrsig) ?
1106 ISC_TRUE : ISC_FALSE);
1110 * Return true iff the two RRs have identical rdata.
1112 static isc_boolean_t
1113 rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1115 * XXXRTH This is not a problem, but we should consider creating
1116 * dns_rdata_equal() (that used dns_name_equal()), since it
1117 * would be faster. Not a priority.
1119 return (dns_rdata_compare(update_rr, db_rr) == 0 ?
1120 ISC_TRUE : ISC_FALSE);
1124 * Return true iff 'update_rr' should replace 'db_rr' according
1125 * to the special RFC2136 rules for CNAME, SOA, and WKS records.
1127 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
1128 * make little sense, so we replace those, too.
1130 static isc_boolean_t
1131 replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
1132 if (db_rr->type != update_rr->type)
1134 if (db_rr->type == dns_rdatatype_cname)
1136 if (db_rr->type == dns_rdatatype_dname)
1138 if (db_rr->type == dns_rdatatype_soa)
1140 if (db_rr->type == dns_rdatatype_nsec)
1142 if (db_rr->type == dns_rdatatype_wks) {
1144 * Compare the address and protocol fields only. These
1145 * form the first five bytes of the RR data. Do a
1146 * raw binary comparison; unpacking the WKS RRs using
1147 * dns_rdata_tostruct() might be cleaner in some ways,
1148 * but it would require us to pass around an mctx.
1150 INSIST(db_rr->length >= 5 && update_rr->length >= 5);
1151 return (memcmp(db_rr->data, update_rr->data, 5) == 0 ?
1152 ISC_TRUE : ISC_FALSE);
1158 * Internal helper function for delete_if().
1161 delete_if_action(void *data, rr_t *rr) {
1162 conditional_delete_ctx_t *ctx = data;
1163 if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
1164 isc_result_t result;
1165 result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
1166 DNS_DIFFOP_DEL, ctx->name,
1167 rr->ttl, &rr->rdata);
1170 return (ISC_R_SUCCESS);
1175 * Conditionally delete RRs. Apply 'predicate' to the RRs
1176 * specified by 'db', 'ver', 'name', and 'type' (which can
1177 * be dns_rdatatype_any to match any type). Delete those
1178 * RRs for which the predicate returns true, and log the
1179 * deletions in 'diff'.
1182 delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
1183 dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
1184 dns_rdata_t *update_rr, dns_diff_t *diff)
1186 conditional_delete_ctx_t ctx;
1187 ctx.predicate = predicate;
1192 ctx.update_rr = update_rr;
1193 return (foreach_rr(db, ver, name, type, covers,
1194 delete_if_action, &ctx));
1197 /**************************************************************************/
1199 * Prepare an RR for the addition of the new RR 'ctx->update_rr',
1200 * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting
1201 * the RRs if it is replaced by the new RR or has a conflicting TTL.
1202 * The necessary changes are appended to ctx->del_diff and ctx->add_diff;
1203 * we need to do all deletions before any additions so that we don't run
1204 * into transient states with conflicting TTLs.
1209 dns_dbversion_t *ver;
1212 dns_rdata_t *update_rr;
1213 dns_ttl_t update_rr_ttl;
1214 isc_boolean_t ignore_add;
1215 dns_diff_t del_diff;
1216 dns_diff_t add_diff;
1217 } add_rr_prepare_ctx_t;
1220 add_rr_prepare_action(void *data, rr_t *rr) {
1221 isc_result_t result = ISC_R_SUCCESS;
1222 add_rr_prepare_ctx_t *ctx = data;
1223 dns_difftuple_t *tuple = NULL;
1224 isc_boolean_t equal;
1227 * If the update RR is a "duplicate" of the update RR,
1228 * the update should be silently ignored.
1230 equal = ISC_TF(dns_rdata_compare(&rr->rdata, ctx->update_rr) == 0);
1231 if (equal && rr->ttl == ctx->update_rr_ttl) {
1232 ctx->ignore_add = ISC_TRUE;
1233 return (ISC_R_SUCCESS);
1237 * If this RR is "equal" to the update RR, it should
1238 * be deleted before the update RR is added.
1240 if (replaces_p(ctx->update_rr, &rr->rdata)) {
1241 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
1242 ctx->name, rr->ttl, &rr->rdata,
1244 dns_diff_append(&ctx->del_diff, &tuple);
1245 return (ISC_R_SUCCESS);
1249 * If this RR differs in TTL from the update RR,
1250 * its TTL must be adjusted.
1252 if (rr->ttl != ctx->update_rr_ttl) {
1253 CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
1254 ctx->name, rr->ttl, &rr->rdata,
1256 dns_diff_append(&ctx->del_diff, &tuple);
1258 CHECK(dns_difftuple_create(ctx->add_diff.mctx,
1259 DNS_DIFFOP_ADD, ctx->name,
1261 &rr->rdata, &tuple));
1262 dns_diff_append(&ctx->add_diff, &tuple);
1269 /**************************************************************************/
1271 * Miscellaneous subroutines.
1275 * Extract a single update RR from 'section' of dynamic update message
1276 * 'msg', with consistency checking.
1278 * Stores the owner name, rdata, and TTL of the update RR at 'name',
1279 * 'rdata', and 'ttl', respectively.
1282 get_current_rr(dns_message_t *msg, dns_section_t section,
1283 dns_rdataclass_t zoneclass, dns_name_t **name,
1284 dns_rdata_t *rdata, dns_rdatatype_t *covers,
1285 dns_ttl_t *ttl, dns_rdataclass_t *update_class)
1287 dns_rdataset_t *rdataset;
1288 isc_result_t result;
1289 dns_message_currentname(msg, section, name);
1290 rdataset = ISC_LIST_HEAD((*name)->list);
1291 INSIST(rdataset != NULL);
1292 INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
1293 *covers = rdataset->covers;
1294 *ttl = rdataset->ttl;
1295 result = dns_rdataset_first(rdataset);
1296 INSIST(result == ISC_R_SUCCESS);
1297 dns_rdataset_current(rdataset, rdata);
1298 INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
1299 *update_class = rdata->rdclass;
1300 rdata->rdclass = zoneclass;
1304 * Increment the SOA serial number of database 'db', version 'ver'.
1305 * Replace the SOA record in the database, and log the
1310 * XXXRTH Failures in this routine will be worth logging, when
1311 * we have a logging system. Failure to find the zonename
1312 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR().
1316 increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
1317 dns_diff_t *diff, isc_mem_t *mctx)
1319 dns_difftuple_t *deltuple = NULL;
1320 dns_difftuple_t *addtuple = NULL;
1321 isc_uint32_t serial;
1322 isc_result_t result;
1324 CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
1325 CHECK(dns_difftuple_copy(deltuple, &addtuple));
1326 addtuple->op = DNS_DIFFOP_ADD;
1328 serial = dns_soa_getserial(&addtuple->rdata);
1331 serial = (serial + 1) & 0xFFFFFFFF;
1335 dns_soa_setserial(serial, &addtuple->rdata);
1336 CHECK(do_one_tuple(&deltuple, db, ver, diff));
1337 CHECK(do_one_tuple(&addtuple, db, ver, diff));
1338 result = ISC_R_SUCCESS;
1341 if (addtuple != NULL)
1342 dns_difftuple_free(&addtuple);
1343 if (deltuple != NULL)
1344 dns_difftuple_free(&deltuple);
1349 * Check that the new SOA record at 'update_rdata' does not
1350 * illegally cause the SOA serial number to decrease or stay
1351 * unchanged relative to the existing SOA in 'db'.
1353 * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not.
1355 * William King points out that RFC2136 is inconsistent about
1356 * the case where the serial number stays unchanged:
1358 * section 3.4.2.2 requires a server to ignore a SOA update request
1359 * if the serial number on the update SOA is less_than_or_equal to
1360 * the zone SOA serial.
1362 * section 3.6 requires a server to ignore a SOA update request if
1363 * the serial is less_than the zone SOA serial.
1365 * Paul says 3.4.2.2 is correct.
1369 check_soa_increment(dns_db_t *db, dns_dbversion_t *ver,
1370 dns_rdata_t *update_rdata, isc_boolean_t *ok)
1372 isc_uint32_t db_serial;
1373 isc_uint32_t update_serial;
1374 isc_result_t result;
1376 update_serial = dns_soa_getserial(update_rdata);
1378 result = dns_db_getsoaserial(db, ver, &db_serial);
1379 if (result != ISC_R_SUCCESS)
1382 if (DNS_SERIAL_GE(db_serial, update_serial)) {
1388 return (ISC_R_SUCCESS);
1392 /**************************************************************************/
1394 * Incremental updating of NSECs and RRSIGs.
1397 #define MAXZONEKEYS 32 /*%< Maximum number of zone keys supported. */
1400 * We abuse the dns_diff_t type to represent a set of domain names
1401 * affected by the update.
1404 namelist_append_name(dns_diff_t *list, dns_name_t *name) {
1405 isc_result_t result;
1406 dns_difftuple_t *tuple = NULL;
1407 static dns_rdata_t dummy_rdata = DNS_RDATA_INIT;
1409 CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0,
1410 &dummy_rdata, &tuple));
1411 dns_diff_append(list, &tuple);
1417 namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
1419 isc_result_t result;
1420 dns_fixedname_t fixedname;
1422 dns_dbiterator_t *dbit = NULL;
1424 dns_fixedname_init(&fixedname);
1425 child = dns_fixedname_name(&fixedname);
1427 CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
1429 for (result = dns_dbiterator_seek(dbit, name);
1430 result == ISC_R_SUCCESS;
1431 result = dns_dbiterator_next(dbit))
1433 dns_dbnode_t *node = NULL;
1434 CHECK(dns_dbiterator_current(dbit, &node, child));
1435 dns_db_detachnode(db, &node);
1436 if (! dns_name_issubdomain(child, name))
1438 CHECK(namelist_append_name(affected, child));
1440 if (result == ISC_R_NOMORE)
1441 result = ISC_R_SUCCESS;
1444 dns_dbiterator_destroy(&dbit);
1451 * Helper function for non_nsec_rrset_exists().
1454 is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
1456 if (!(rrset->type == dns_rdatatype_nsec ||
1457 (rrset->type == dns_rdatatype_rrsig &&
1458 rrset->covers == dns_rdatatype_nsec)))
1459 return (ISC_R_EXISTS);
1460 return (ISC_R_SUCCESS);
1464 * Check whether there is an rrset other than a NSEC or RRSIG NSEC,
1465 * i.e., anything that justifies the continued existence of a name
1466 * after a secure update.
1468 * If such an rrset exists, set '*exists' to ISC_TRUE.
1469 * Otherwise, set it to ISC_FALSE.
1472 non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
1473 dns_name_t *name, isc_boolean_t *exists)
1475 isc_result_t result;
1476 result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
1477 RETURN_EXISTENCE_FLAG;
1481 * A comparison function for sorting dns_diff_t:s by name.
1484 name_order(const void *av, const void *bv) {
1485 dns_difftuple_t const * const *ap = av;
1486 dns_difftuple_t const * const *bp = bv;
1487 dns_difftuple_t const *a = *ap;
1488 dns_difftuple_t const *b = *bp;
1489 return (dns_name_compare(&a->name, &b->name));
1493 uniqify_name_list(dns_diff_t *list) {
1494 isc_result_t result;
1495 dns_difftuple_t *p, *q;
1497 CHECK(dns_diff_sort(list, name_order));
1499 p = ISC_LIST_HEAD(list->tuples);
1502 q = ISC_LIST_NEXT(p, link);
1503 if (q == NULL || ! dns_name_equal(&p->name, &q->name))
1505 ISC_LIST_UNLINK(list->tuples, q, link);
1506 dns_difftuple_free(&q);
1508 p = ISC_LIST_NEXT(p, link);
1515 is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1516 isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure)
1518 isc_result_t result;
1519 dns_fixedname_t foundname;
1520 dns_fixedname_init(&foundname);
1521 result = dns_db_find(db, name, ver, dns_rdatatype_any,
1522 DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
1523 (isc_stdtime_t) 0, NULL,
1524 dns_fixedname_name(&foundname),
1526 if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
1529 if (unsecure != NULL)
1530 *unsecure = ISC_FALSE;
1531 return (ISC_R_SUCCESS);
1532 } else if (result == DNS_R_ZONECUT) {
1535 if (unsecure != NULL) {
1537 * We are at the zonecut. Check to see if there
1540 if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
1541 (isc_stdtime_t) 0, NULL,
1542 dns_fixedname_name(&foundname),
1543 NULL, NULL) == DNS_R_NXRRSET)
1544 *unsecure = ISC_TRUE;
1546 *unsecure = ISC_FALSE;
1548 return (ISC_R_SUCCESS);
1549 } else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
1550 result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
1553 if (unsecure != NULL)
1554 *unsecure = ISC_FALSE;
1555 return (ISC_R_SUCCESS);
1562 if (unsecure != NULL)
1563 *unsecure = ISC_FALSE;
1569 * Find the next/previous name that has a NSEC record.
1570 * In other words, skip empty database nodes and names that
1571 * have had their NSECs removed because they are obscured by
1575 next_active(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1576 dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname,
1577 isc_boolean_t forward)
1579 isc_result_t result;
1580 dns_dbiterator_t *dbit = NULL;
1581 isc_boolean_t has_nsec;
1582 unsigned int wraps = 0;
1584 CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
1586 CHECK(dns_dbiterator_seek(dbit, oldname));
1588 dns_dbnode_t *node = NULL;
1591 result = dns_dbiterator_next(dbit);
1593 result = dns_dbiterator_prev(dbit);
1594 if (result == ISC_R_NOMORE) {
1599 CHECK(dns_dbiterator_first(dbit));
1601 CHECK(dns_dbiterator_last(dbit));
1604 update_log(client, zone, ISC_LOG_ERROR,
1605 "secure zone with no NSECs");
1606 result = DNS_R_BADZONE;
1610 CHECK(dns_dbiterator_current(dbit, &node, newname));
1611 dns_db_detachnode(db, &node);
1614 * The iterator may hold the tree lock, and
1615 * rrset_exists() calls dns_db_findnode() which
1616 * may try to reacquire it. To avoid deadlock
1617 * we must pause the iterator first.
1619 CHECK(dns_dbiterator_pause(dbit));
1620 CHECK(rrset_exists(db, ver, newname,
1621 dns_rdatatype_nsec, 0, &has_nsec));
1623 } while (! has_nsec);
1626 dns_dbiterator_destroy(&dbit);
1632 * Add a NSEC record for "name", recording the change in "diff".
1633 * The existing NSEC is removed.
1636 add_nsec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1637 dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl,
1640 isc_result_t result;
1641 dns_dbnode_t *node = NULL;
1642 unsigned char buffer[DNS_NSEC_BUFFERSIZE];
1643 dns_rdata_t rdata = DNS_RDATA_INIT;
1644 dns_difftuple_t *tuple = NULL;
1645 dns_fixedname_t fixedname;
1648 dns_fixedname_init(&fixedname);
1649 target = dns_fixedname_name(&fixedname);
1652 * Find the successor name, aka NSEC target.
1654 CHECK(next_active(client, zone, db, ver, name, target, ISC_TRUE));
1657 * Create the NSEC RDATA.
1659 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1660 dns_rdata_init(&rdata);
1661 CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
1662 dns_db_detachnode(db, &node);
1665 * Delete the old NSEC and record the change.
1667 CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0,
1670 * Add the new NSEC and record the change.
1672 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
1673 nsecttl, &rdata, &tuple));
1674 CHECK(do_one_tuple(&tuple, db, ver, diff));
1675 INSIST(tuple == NULL);
1679 dns_db_detachnode(db, &node);
1684 * Add a placeholder NSEC record for "name", recording the change in "diff".
1687 add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1690 isc_result_t result;
1691 dns_difftuple_t *tuple = NULL;
1693 unsigned char data[1] = { 0 }; /* The root domain, no bits. */
1694 dns_rdata_t rdata = DNS_RDATA_INIT;
1697 r.length = sizeof(data);
1698 dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
1699 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
1701 CHECK(do_one_tuple(&tuple, db, ver, diff));
1707 find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
1708 isc_mem_t *mctx, unsigned int maxkeys,
1709 dst_key_t **keys, unsigned int *nkeys)
1711 isc_result_t result;
1712 dns_dbnode_t *node = NULL;
1713 const char *directory = dns_zone_getkeydirectory(zone);
1714 CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1715 CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
1716 directory, mctx, maxkeys, keys, nkeys));
1719 dns_db_detachnode(db, &node);
1723 static isc_boolean_t
1724 ksk_sanity(dns_db_t *db, dns_dbversion_t *ver) {
1725 isc_boolean_t ret = ISC_FALSE;
1726 isc_boolean_t have_ksk = ISC_FALSE, have_nonksk = ISC_FALSE;
1727 isc_result_t result;
1728 dns_dbnode_t *node = NULL;
1729 dns_rdataset_t rdataset;
1730 dns_rdata_t rdata = DNS_RDATA_INIT;
1731 dns_rdata_dnskey_t dnskey;
1733 dns_rdataset_init(&rdataset);
1734 CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1735 CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
1737 CHECK(dns_rdataset_first(&rdataset));
1738 while (result == ISC_R_SUCCESS && (!have_ksk || !have_nonksk)) {
1739 dns_rdataset_current(&rdataset, &rdata);
1740 CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL));
1741 if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
1742 == DNS_KEYOWNER_ZONE) {
1743 if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0)
1744 have_ksk = ISC_TRUE;
1746 have_nonksk = ISC_TRUE;
1748 dns_rdata_reset(&rdata);
1749 result = dns_rdataset_next(&rdataset);
1751 if (have_ksk && have_nonksk)
1754 if (dns_rdataset_isassociated(&rdataset))
1755 dns_rdataset_disassociate(&rdataset);
1757 dns_db_detachnode(db, &node);
1762 * Add RRSIG records for an RRset, recording the change in "diff".
1765 add_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1766 dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type,
1767 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1768 isc_stdtime_t inception, isc_stdtime_t expire,
1769 isc_boolean_t check_ksk)
1771 isc_result_t result;
1772 dns_dbnode_t *node = NULL;
1773 dns_rdataset_t rdataset;
1774 dns_rdata_t sig_rdata = DNS_RDATA_INIT;
1775 isc_buffer_t buffer;
1776 unsigned char data[1024]; /* XXX */
1778 isc_boolean_t added_sig = ISC_FALSE;
1779 isc_mem_t *mctx = client->mctx;
1781 dns_rdataset_init(&rdataset);
1782 isc_buffer_init(&buffer, data, sizeof(data));
1784 /* Get the rdataset to sign. */
1785 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1786 CHECK(dns_db_findrdataset(db, node, ver, type, 0,
1787 (isc_stdtime_t) 0, &rdataset, NULL));
1788 dns_db_detachnode(db, &node);
1790 for (i = 0; i < nkeys; i++) {
1792 if (check_ksk && type != dns_rdatatype_dnskey &&
1793 (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0)
1796 if (!dst_key_isprivate(keys[i]))
1799 /* Calculate the signature, creating a RRSIG RDATA. */
1800 CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
1801 &inception, &expire,
1802 mctx, &buffer, &sig_rdata));
1804 /* Update the database and journal with the RRSIG. */
1805 /* XXX inefficient - will cause dataset merging */
1806 CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name,
1807 rdataset.ttl, &sig_rdata));
1808 dns_rdata_reset(&sig_rdata);
1809 added_sig = ISC_TRUE;
1812 update_log(client, zone, ISC_LOG_ERROR,
1813 "found no private keys, "
1814 "unable to generate any signatures");
1815 result = ISC_R_NOTFOUND;
1819 if (dns_rdataset_isassociated(&rdataset))
1820 dns_rdataset_disassociate(&rdataset);
1822 dns_db_detachnode(db, &node);
1827 add_exposed_sigs(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1828 dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut,
1829 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1830 isc_stdtime_t inception, isc_stdtime_t expire,
1831 isc_boolean_t check_ksk)
1833 isc_result_t result;
1835 dns_rdatasetiter_t *iter;
1838 result = dns_db_findnode(db, name, ISC_FALSE, &node);
1839 if (result == ISC_R_NOTFOUND)
1840 return (ISC_R_SUCCESS);
1841 if (result != ISC_R_SUCCESS)
1845 result = dns_db_allrdatasets(db, node, ver,
1846 (isc_stdtime_t) 0, &iter);
1847 if (result != ISC_R_SUCCESS)
1850 for (result = dns_rdatasetiter_first(iter);
1851 result == ISC_R_SUCCESS;
1852 result = dns_rdatasetiter_next(iter))
1854 dns_rdataset_t rdataset;
1855 dns_rdatatype_t type;
1858 dns_rdataset_init(&rdataset);
1859 dns_rdatasetiter_current(iter, &rdataset);
1860 type = rdataset.type;
1861 dns_rdataset_disassociate(&rdataset);
1864 * We don't need to sign unsigned NSEC records at the cut
1865 * as they are handled elsewhere.
1867 if ((type == dns_rdatatype_rrsig) ||
1868 (cut && type != dns_rdatatype_ds))
1870 result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
1872 if (result != ISC_R_SUCCESS)
1873 goto cleanup_iterator;
1876 result = add_sigs(client, zone, db, ver, name, type, diff,
1877 keys, nkeys, inception, expire, check_ksk);
1878 if (result != ISC_R_SUCCESS)
1879 goto cleanup_iterator;
1881 if (result == ISC_R_NOMORE)
1882 result = ISC_R_SUCCESS;
1885 dns_rdatasetiter_destroy(&iter);
1888 dns_db_detachnode(db, &node);
1894 * Update RRSIG and NSEC records affected by an update. The original
1895 * update, including the SOA serial update but excluding the RRSIG & NSEC
1896 * changes, is in "diff" and has already been applied to "newver" of "db".
1897 * The database version prior to the update is "oldver".
1899 * The necessary RRSIG and NSEC changes will be applied to "newver"
1900 * and added (as a minimal diff) to "diff".
1902 * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
1905 update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
1906 dns_dbversion_t *oldver, dns_dbversion_t *newver,
1907 dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
1909 isc_result_t result;
1911 dns_diff_t diffnames;
1912 dns_diff_t affected;
1913 dns_diff_t sig_diff;
1914 dns_diff_t nsec_diff;
1915 dns_diff_t nsec_mindiff;
1917 dst_key_t *zone_keys[MAXZONEKEYS];
1918 unsigned int nkeys = 0;
1920 isc_stdtime_t now, inception, expire;
1922 dns_rdata_soa_t soa;
1923 dns_rdata_t rdata = DNS_RDATA_INIT;
1924 dns_rdataset_t rdataset;
1925 dns_dbnode_t *node = NULL;
1926 isc_boolean_t check_ksk;
1929 dns_diff_init(client->mctx, &diffnames);
1930 dns_diff_init(client->mctx, &affected);
1932 dns_diff_init(client->mctx, &sig_diff);
1933 dns_diff_init(client->mctx, &nsec_diff);
1934 dns_diff_init(client->mctx, &nsec_mindiff);
1936 result = find_zone_keys(zone, db, newver, client->mctx,
1937 MAXZONEKEYS, zone_keys, &nkeys);
1938 if (result != ISC_R_SUCCESS) {
1939 update_log(client, zone, ISC_LOG_ERROR,
1940 "could not get zone keys for secure dynamic update");
1944 isc_stdtime_get(&now);
1945 inception = now - 3600; /* Allow for some clock skew. */
1946 expire = now + sigvalidityinterval;
1949 * Do we look at the KSK flag on the DNSKEY to determining which
1950 * keys sign which RRsets? First check the zone option then
1951 * check the keys flags to make sure at least one has a ksk set
1954 check_ksk = ISC_TF((dns_zone_getoptions(zone) &
1955 DNS_ZONEOPT_UPDATECHECKKSK) != 0);
1957 check_ksk = ksk_sanity(db, newver);
1960 * Get the NSEC's TTL from the SOA MINIMUM field.
1962 CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1963 dns_rdataset_init(&rdataset);
1964 CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0,
1965 (isc_stdtime_t) 0, &rdataset, NULL));
1966 CHECK(dns_rdataset_first(&rdataset));
1967 dns_rdataset_current(&rdataset, &rdata);
1968 CHECK(dns_rdata_tostruct(&rdata, &soa, NULL));
1969 nsecttl = soa.minimum;
1970 dns_rdataset_disassociate(&rdataset);
1971 dns_db_detachnode(db, &node);
1974 * Find all RRsets directly affected by the update, and
1975 * update their RRSIGs. Also build a list of names affected
1976 * by the update in "diffnames".
1978 CHECK(dns_diff_sort(diff, temp_order));
1980 t = ISC_LIST_HEAD(diff->tuples);
1982 dns_name_t *name = &t->name;
1983 /* Now "name" is a new, unique name affected by the update. */
1985 CHECK(namelist_append_name(&diffnames, name));
1987 while (t != NULL && dns_name_equal(&t->name, name)) {
1988 dns_rdatatype_t type;
1989 type = t->rdata.type;
1992 * Now "name" and "type" denote a new unique RRset
1993 * affected by the update.
1996 /* Don't sign RRSIGs. */
1997 if (type == dns_rdatatype_rrsig)
2001 * Delete all old RRSIGs covering this type, since they
2002 * are all invalid when the signed RRset has changed.
2003 * We may not be able to recreate all of them - tough.
2005 CHECK(delete_if(true_p, db, newver, name,
2006 dns_rdatatype_rrsig, type,
2010 * If this RRset is still visible after the update,
2011 * add a new signature for it.
2013 CHECK(rrset_visible(db, newver, name, type, &flag));
2015 CHECK(add_sigs(client, zone, db, newver, name,
2016 type, &sig_diff, zone_keys,
2017 nkeys, inception, expire,
2021 /* Skip any other updates to the same RRset. */
2023 dns_name_equal(&t->name, name) &&
2024 t->rdata.type == type)
2026 t = ISC_LIST_NEXT(t, link);
2031 /* Remove orphaned NSECs and RRSIG NSECs. */
2032 for (t = ISC_LIST_HEAD(diffnames.tuples);
2034 t = ISC_LIST_NEXT(t, link))
2036 CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag));
2038 CHECK(delete_if(true_p, db, newver, &t->name,
2039 dns_rdatatype_any, 0,
2045 * When a name is created or deleted, its predecessor needs to
2046 * have its NSEC updated.
2048 for (t = ISC_LIST_HEAD(diffnames.tuples);
2050 t = ISC_LIST_NEXT(t, link))
2052 isc_boolean_t existed, exists;
2053 dns_fixedname_t fixedname;
2054 dns_name_t *prevname;
2056 dns_fixedname_init(&fixedname);
2057 prevname = dns_fixedname_name(&fixedname);
2059 CHECK(name_exists(db, oldver, &t->name, &existed));
2060 CHECK(name_exists(db, newver, &t->name, &exists));
2061 if (exists == existed)
2065 * Find the predecessor.
2066 * When names become obscured or unobscured in this update
2067 * transaction, we may find the wrong predecessor because
2068 * the NSECs have not yet been updated to reflect the delegation
2069 * change. This should not matter because in this case,
2070 * the correct predecessor is either the delegation node or
2071 * a newly unobscured node, and those nodes are on the
2072 * "affected" list in any case.
2074 CHECK(next_active(client, zone, db, newver,
2075 &t->name, prevname, ISC_FALSE));
2076 CHECK(namelist_append_name(&affected, prevname));
2080 * Find names potentially affected by delegation changes
2081 * (obscured by adding an NS or DNAME, or unobscured by
2084 for (t = ISC_LIST_HEAD(diffnames.tuples);
2086 t = ISC_LIST_NEXT(t, link))
2088 isc_boolean_t ns_existed, dname_existed;
2089 isc_boolean_t ns_exists, dname_exists;
2091 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_ns, 0,
2093 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_dname, 0,
2095 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0,
2097 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0,
2099 if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
2102 * There was a delegation change. Mark all subdomains
2103 * of t->name as potentially needing a NSEC update.
2105 CHECK(namelist_append_subdomain(db, &t->name, &affected));
2108 ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link);
2109 INSIST(ISC_LIST_EMPTY(diffnames.tuples));
2111 CHECK(uniqify_name_list(&affected));
2114 * Determine which names should have NSECs, and delete/create
2115 * NSECs to make it so. We don't know the final NSEC targets yet,
2116 * so we just create placeholder NSECs with arbitrary contents
2117 * to indicate that their respective owner names should be part of
2120 for (t = ISC_LIST_HEAD(affected.tuples);
2122 t = ISC_LIST_NEXT(t, link))
2124 isc_boolean_t exists;
2125 dns_name_t *name = &t->name;
2127 CHECK(name_exists(db, newver, name, &exists));
2130 CHECK(is_active(db, newver, name, &flag, &cut, NULL));
2133 * This name is obscured. Delete any
2134 * existing NSEC record.
2136 CHECK(delete_if(true_p, db, newver, name,
2137 dns_rdatatype_nsec, 0,
2139 CHECK(delete_if(rrsig_p, db, newver, name,
2140 dns_rdatatype_any, 0, NULL, diff));
2143 * This name is not obscured. It should have a NSEC.
2145 CHECK(rrset_exists(db, newver, name,
2146 dns_rdatatype_nsec, 0, &flag));
2148 CHECK(add_placeholder_nsec(db, newver, &t->name,
2150 CHECK(add_exposed_sigs(client, zone, db, newver, name,
2151 cut, diff, zone_keys, nkeys,
2152 inception, expire, check_ksk));
2157 * Now we know which names are part of the NSEC chain.
2158 * Make them all point at their correct targets.
2160 for (t = ISC_LIST_HEAD(affected.tuples);
2162 t = ISC_LIST_NEXT(t, link))
2164 CHECK(rrset_exists(db, newver, &t->name,
2165 dns_rdatatype_nsec, 0, &flag));
2168 * There is a NSEC, but we don't know if it is correct.
2169 * Delete it and create a correct one to be sure.
2170 * If the update was unnecessary, the diff minimization
2171 * will take care of eliminating it from the journal,
2174 * The RRSIG bit should always be set in the NSECs
2175 * we generate, because they will all get RRSIG NSECs.
2176 * (XXX what if the zone keys are missing?).
2177 * Because the RRSIG NSECs have not necessarily been
2178 * created yet, the correctness of the bit mask relies
2179 * on the assumption that NSECs are only created if
2180 * there is other data, and if there is other data,
2181 * there are other RRSIGs.
2183 CHECK(add_nsec(client, zone, db, newver, &t->name,
2184 nsecttl, &nsec_diff));
2189 * Minimize the set of NSEC updates so that we don't
2190 * have to regenerate the RRSIG NSECs for NSECs that were
2191 * replaced with identical ones.
2193 while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
2194 ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
2195 dns_diff_appendminimal(&nsec_mindiff, &t);
2198 /* Update RRSIG NSECs. */
2199 for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
2201 t = ISC_LIST_NEXT(t, link))
2203 if (t->op == DNS_DIFFOP_DEL) {
2204 CHECK(delete_if(true_p, db, newver, &t->name,
2205 dns_rdatatype_rrsig, dns_rdatatype_nsec,
2207 } else if (t->op == DNS_DIFFOP_ADD) {
2208 CHECK(add_sigs(client, zone, db, newver, &t->name,
2209 dns_rdatatype_nsec, &sig_diff,
2210 zone_keys, nkeys, inception, expire,
2217 /* Record our changes for the journal. */
2218 while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
2219 ISC_LIST_UNLINK(sig_diff.tuples, t, link);
2220 dns_diff_appendminimal(diff, &t);
2222 while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
2223 ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
2224 dns_diff_appendminimal(diff, &t);
2227 INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
2228 INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
2229 INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
2232 dns_diff_clear(&sig_diff);
2233 dns_diff_clear(&nsec_diff);
2234 dns_diff_clear(&nsec_mindiff);
2236 dns_diff_clear(&affected);
2237 dns_diff_clear(&diffnames);
2239 for (i = 0; i < nkeys; i++)
2240 dst_key_free(&zone_keys[i]);
2246 /**************************************************************************/
2248 * The actual update code in all its glory. We try to follow
2249 * the RFC2136 pseudocode as closely as possible.
2253 send_update_event(ns_client_t *client, dns_zone_t *zone) {
2254 isc_result_t result = ISC_R_SUCCESS;
2255 update_event_t *event = NULL;
2256 isc_task_t *zonetask = NULL;
2257 ns_client_t *evclient;
2259 event = (update_event_t *)
2260 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
2261 update_action, NULL, sizeof(*event));
2263 FAIL(ISC_R_NOMEMORY);
2265 event->result = ISC_R_SUCCESS;
2268 ns_client_attach(client, &evclient);
2269 INSIST(client->nupdates == 0);
2271 event->ev_arg = evclient;
2273 dns_zone_gettask(zone, &zonetask);
2274 isc_task_send(zonetask, ISC_EVENT_PTR(&event));
2278 isc_event_free(ISC_EVENT_PTR(&event));
2283 respond(ns_client_t *client, isc_result_t result) {
2284 isc_result_t msg_result;
2286 msg_result = dns_message_reply(client->message, ISC_TRUE);
2287 if (msg_result != ISC_R_SUCCESS)
2289 client->message->rcode = dns_result_torcode(result);
2291 ns_client_send(client);
2295 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
2297 "could not create update response message: %s",
2298 isc_result_totext(msg_result));
2299 ns_client_next(client, msg_result);
2303 ns_update_start(ns_client_t *client, isc_result_t sigresult) {
2304 dns_message_t *request = client->message;
2305 isc_result_t result;
2306 dns_name_t *zonename;
2307 dns_rdataset_t *zone_rdataset;
2308 dns_zone_t *zone = NULL;
2311 * Interpret the zone section.
2313 result = dns_message_firstname(request, DNS_SECTION_ZONE);
2314 if (result != ISC_R_SUCCESS)
2315 FAILC(DNS_R_FORMERR, "update zone section empty");
2318 * The zone section must contain exactly one "question", and
2319 * it must be of type SOA.
2322 dns_message_currentname(request, DNS_SECTION_ZONE, &zonename);
2323 zone_rdataset = ISC_LIST_HEAD(zonename->list);
2324 if (zone_rdataset->type != dns_rdatatype_soa)
2325 FAILC(DNS_R_FORMERR,
2326 "update zone section contains non-SOA");
2327 if (ISC_LIST_NEXT(zone_rdataset, link) != NULL)
2328 FAILC(DNS_R_FORMERR,
2329 "update zone section contains multiple RRs");
2331 /* The zone section must have exactly one name. */
2332 result = dns_message_nextname(request, DNS_SECTION_ZONE);
2333 if (result != ISC_R_NOMORE)
2334 FAILC(DNS_R_FORMERR,
2335 "update zone section contains multiple RRs");
2337 result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
2339 if (result != ISC_R_SUCCESS)
2340 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
2342 switch(dns_zone_gettype(zone)) {
2343 case dns_zone_master:
2345 * We can now fail due to a bad signature as we now know
2346 * that we are the master.
2348 if (sigresult != ISC_R_SUCCESS)
2350 CHECK(send_update_event(client, zone));
2352 case dns_zone_slave:
2353 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
2354 "update forwarding", zonename, ISC_TRUE,
2356 CHECK(send_forward_event(client, zone));
2359 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
2364 if (result == DNS_R_REFUSED) {
2365 INSIST(dns_zone_gettype(zone) == dns_zone_slave);
2366 inc_stats(zone, dns_nsstatscounter_updaterej);
2369 * We failed without having sent an update event to the zone.
2370 * We are still in the client task context, so we can
2371 * simply give an error response without switching tasks.
2373 respond(client, result);
2375 dns_zone_detach(&zone);
2379 * DS records are not allowed to exist without corresponding NS records,
2380 * draft-ietf-dnsext-delegation-signer-11.txt, 2.2 Protocol Change,
2381 * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
2385 remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) {
2386 isc_result_t result;
2387 isc_boolean_t ns_exists;
2388 dns_difftuple_t *tupple;
2389 dns_diff_t temp_diff;
2391 dns_diff_init(diff->mctx, &temp_diff);
2393 for (tupple = ISC_LIST_HEAD(diff->tuples);
2395 tupple = ISC_LIST_NEXT(tupple, link)) {
2396 if (!((tupple->op == DNS_DIFFOP_DEL &&
2397 tupple->rdata.type == dns_rdatatype_ns) ||
2398 (tupple->op == DNS_DIFFOP_ADD &&
2399 tupple->rdata.type == dns_rdatatype_ds)))
2401 CHECK(rrset_exists(db, newver, &tupple->name,
2402 dns_rdatatype_ns, 0, &ns_exists));
2404 !dns_name_equal(&tupple->name, dns_db_origin(db)))
2406 CHECK(delete_if(true_p, db, newver, &tupple->name,
2407 dns_rdatatype_ds, 0, NULL, &temp_diff));
2409 result = ISC_R_SUCCESS;
2412 for (tupple = ISC_LIST_HEAD(temp_diff.tuples);
2414 tupple = ISC_LIST_HEAD(temp_diff.tuples)) {
2415 ISC_LIST_UNLINK(temp_diff.tuples, tupple, link);
2416 dns_diff_appendminimal(diff, &tupple);
2422 * This implements the post load integrity checks for mx records.
2425 check_mx(ns_client_t *client, dns_zone_t *zone,
2426 dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff)
2428 char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
2429 char ownerbuf[DNS_NAME_FORMATSIZE];
2430 char namebuf[DNS_NAME_FORMATSIZE];
2431 char altbuf[DNS_NAME_FORMATSIZE];
2433 dns_fixedname_t fixed;
2434 dns_name_t *foundname;
2437 isc_boolean_t ok = ISC_TRUE;
2438 isc_boolean_t isaddress;
2439 isc_result_t result;
2440 struct in6_addr addr6;
2441 struct in_addr addr;
2442 unsigned int options;
2444 dns_fixedname_init(&fixed);
2445 foundname = dns_fixedname_name(&fixed);
2446 dns_rdata_init(&rdata);
2447 options = dns_zone_getoptions(zone);
2449 for (t = ISC_LIST_HEAD(diff->tuples);
2451 t = ISC_LIST_NEXT(t, link)) {
2452 if (t->op != DNS_DIFFOP_ADD ||
2453 t->rdata.type != dns_rdatatype_mx)
2456 result = dns_rdata_tostruct(&t->rdata, &mx, NULL);
2457 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2459 * Check if we will error out if we attempt to reload the
2462 dns_name_format(&mx.mx, namebuf, sizeof(namebuf));
2463 dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf));
2464 isaddress = ISC_FALSE;
2465 if ((options & DNS_RDATA_CHECKMX) != 0 &&
2466 strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) {
2467 if (tmp[strlen(tmp) - 1] == '.')
2468 tmp[strlen(tmp) - 1] = '\0';
2469 if (inet_aton(tmp, &addr) == 1 ||
2470 inet_pton(AF_INET6, tmp, &addr6) == 1)
2471 isaddress = ISC_TRUE;
2474 if (isaddress && (options & DNS_RDATA_CHECKMXFAIL) != 0) {
2475 update_log(client, zone, ISC_LOG_ERROR,
2478 dns_result_totext(DNS_R_MXISADDRESS));
2480 } else if (isaddress) {
2481 update_log(client, zone, ISC_LOG_WARNING,
2482 "%s/MX: warning: '%s': %s",
2484 dns_result_totext(DNS_R_MXISADDRESS));
2488 * Check zone integrity checks.
2490 if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0)
2492 result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a,
2493 0, 0, NULL, foundname, NULL, NULL);
2494 if (result == ISC_R_SUCCESS)
2497 if (result == DNS_R_NXRRSET) {
2498 result = dns_db_find(db, &mx.mx, newver,
2500 0, 0, NULL, foundname,
2502 if (result == ISC_R_SUCCESS)
2506 if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
2507 update_log(client, zone, ISC_LOG_ERROR,
2508 "%s/MX '%s' has no address records "
2509 "(A or AAAA)", ownerbuf, namebuf);
2511 } else if (result == DNS_R_CNAME) {
2512 update_log(client, zone, ISC_LOG_ERROR,
2513 "%s/MX '%s' is a CNAME (illegal)",
2516 } else if (result == DNS_R_DNAME) {
2517 dns_name_format(foundname, altbuf, sizeof altbuf);
2518 update_log(client, zone, ISC_LOG_ERROR,
2519 "%s/MX '%s' is below a DNAME '%s' (illegal)",
2520 ownerbuf, namebuf, altbuf);
2524 return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
2528 update_action(isc_task_t *task, isc_event_t *event) {
2529 update_event_t *uev = (update_event_t *) event;
2530 dns_zone_t *zone = uev->zone;
2531 ns_client_t *client = (ns_client_t *)event->ev_arg;
2533 isc_result_t result;
2534 dns_db_t *db = NULL;
2535 dns_dbversion_t *oldver = NULL;
2536 dns_dbversion_t *ver = NULL;
2537 dns_diff_t diff; /* Pending updates. */
2538 dns_diff_t temp; /* Pending RR existence assertions. */
2539 isc_boolean_t soa_serial_changed = ISC_FALSE;
2540 isc_mem_t *mctx = client->mctx;
2541 dns_rdatatype_t covers;
2542 dns_message_t *request = client->message;
2543 dns_rdataclass_t zoneclass;
2544 dns_name_t *zonename;
2545 dns_ssutable_t *ssutable = NULL;
2546 dns_fixedname_t tmpnamefixed;
2547 dns_name_t *tmpname = NULL;
2548 unsigned int options;
2550 INSIST(event->ev_type == DNS_EVENT_UPDATE);
2552 dns_diff_init(mctx, &diff);
2553 dns_diff_init(mctx, &temp);
2555 CHECK(dns_zone_getdb(zone, &db));
2556 zonename = dns_db_origin(db);
2557 zoneclass = dns_db_class(db);
2558 dns_zone_getssutable(zone, &ssutable);
2559 dns_db_currentversion(db, &oldver);
2560 CHECK(dns_db_newversion(db, &ver));
2563 * Check prerequisites.
2566 for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
2567 result == ISC_R_SUCCESS;
2568 result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
2570 dns_name_t *name = NULL;
2571 dns_rdata_t rdata = DNS_RDATA_INIT;
2573 dns_rdataclass_t update_class;
2576 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
2577 &name, &rdata, &covers, &ttl, &update_class);
2580 PREREQFAILC(DNS_R_FORMERR,
2581 "prerequisite TTL is not zero");
2583 if (! dns_name_issubdomain(name, zonename))
2584 PREREQFAILN(DNS_R_NOTZONE, name,
2585 "prerequisite name is out of zone");
2587 if (update_class == dns_rdataclass_any) {
2588 if (rdata.length != 0)
2589 PREREQFAILC(DNS_R_FORMERR,
2590 "class ANY prerequisite "
2591 "RDATA is not empty");
2592 if (rdata.type == dns_rdatatype_any) {
2593 CHECK(name_exists(db, ver, name, &flag));
2595 PREREQFAILN(DNS_R_NXDOMAIN, name,
2601 CHECK(rrset_exists(db, ver, name,
2602 rdata.type, covers, &flag));
2604 /* RRset does not exist. */
2605 PREREQFAILNT(DNS_R_NXRRSET, name, rdata.type,
2606 "'rrset exists (value independent)' "
2607 "prerequisite not satisfied");
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));
2618 PREREQFAILN(DNS_R_YXDOMAIN, name,
2619 "'name not in use' "
2624 CHECK(rrset_exists(db, ver, name,
2625 rdata.type, covers, &flag));
2628 PREREQFAILNT(DNS_R_YXRRSET, name,
2630 "'rrset does not exist' "
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);
2645 PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite");
2648 if (result != ISC_R_NOMORE)
2653 * Perform the final check of the "rrset exists (value dependent)"
2656 if (ISC_LIST_HEAD(temp.tuples) != NULL) {
2657 dns_rdatatype_t type;
2660 * Sort the prerequisite records by owner name,
2663 result = dns_diff_sort(&temp, temp_order);
2664 if (result != ISC_R_SUCCESS)
2665 FAILC(result, "'RRset exists (value dependent)' "
2666 "prerequisite not satisfied");
2668 dns_fixedname_init(&tmpnamefixed);
2669 tmpname = dns_fixedname_name(&tmpnamefixed);
2670 result = temp_check(mctx, &temp, db, ver, tmpname, &type);
2671 if (result != ISC_R_SUCCESS)
2672 FAILNT(result, tmpname, type,
2673 "'RRset exists (value dependent)' "
2674 "prerequisite not satisfied");
2677 update_log(client, zone, LOGLEVEL_DEBUG,
2678 "prerequisites are OK");
2681 * Check Requestor's Permissions. It seems a bit silly to do this
2682 * only after prerequisite testing, but that is what RFC2136 says.
2684 result = ISC_R_SUCCESS;
2685 if (ssutable == NULL)
2686 CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
2687 "update", zonename, ISC_FALSE, ISC_FALSE));
2688 else if (client->signer == NULL)
2689 CHECK(checkupdateacl(client, NULL, "update", zonename,
2690 ISC_FALSE, ISC_TRUE));
2692 if (dns_zone_getupdatedisabled(zone))
2693 FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
2694 "because the zone is frozen. Use "
2695 "'rndc thaw' to re-enable updates.");
2698 * Perform the Update Section Prescan.
2701 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
2702 result == ISC_R_SUCCESS;
2703 result = dns_message_nextname(request, DNS_SECTION_UPDATE))
2705 dns_name_t *name = NULL;
2706 dns_rdata_t rdata = DNS_RDATA_INIT;
2708 dns_rdataclass_t update_class;
2709 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
2710 &name, &rdata, &covers, &ttl, &update_class);
2712 if (! dns_name_issubdomain(name, zonename))
2713 FAILC(DNS_R_NOTZONE,
2714 "update RR is outside zone");
2715 if (update_class == zoneclass) {
2717 * Check for meta-RRs. The RFC2136 pseudocode says
2718 * check for ANY|AXFR|MAILA|MAILB, but the text adds
2719 * "or any other QUERY metatype"
2721 if (dns_rdatatype_ismeta(rdata.type)) {
2722 FAILC(DNS_R_FORMERR,
2723 "meta-RR in update");
2725 result = dns_zone_checknames(zone, name, &rdata);
2726 if (result != ISC_R_SUCCESS)
2727 FAIL(DNS_R_REFUSED);
2728 } else if (update_class == dns_rdataclass_any) {
2729 if (ttl != 0 || rdata.length != 0 ||
2730 (dns_rdatatype_ismeta(rdata.type) &&
2731 rdata.type != dns_rdatatype_any))
2732 FAILC(DNS_R_FORMERR,
2733 "meta-RR in update");
2734 } else if (update_class == dns_rdataclass_none) {
2736 dns_rdatatype_ismeta(rdata.type))
2737 FAILC(DNS_R_FORMERR,
2738 "meta-RR in update");
2740 update_log(client, zone, ISC_LOG_WARNING,
2741 "update RR has incorrect class %d",
2743 FAIL(DNS_R_FORMERR);
2746 * draft-ietf-dnsind-simple-secure-update-01 says
2747 * "Unlike traditional dynamic update, the client
2748 * is forbidden from updating NSEC records."
2750 if (dns_db_issecure(db)) {
2751 if (rdata.type == dns_rdatatype_nsec) {
2752 FAILC(DNS_R_REFUSED,
2753 "explicit NSEC updates are not allowed "
2756 else if (rdata.type == dns_rdatatype_rrsig) {
2757 FAILC(DNS_R_REFUSED,
2758 "explicit RRSIG updates are currently not "
2759 "supported in secure zones");
2763 if (ssutable != NULL && client->signer != NULL) {
2764 if (rdata.type != dns_rdatatype_any) {
2765 if (!dns_ssutable_checkrules(ssutable,
2768 FAILC(DNS_R_REFUSED,
2769 "rejected by secure update");
2772 if (!ssu_checkall(db, ver, name, ssutable,
2774 FAILC(DNS_R_REFUSED,
2775 "rejected by secure update");
2779 if (result != ISC_R_NOMORE)
2782 update_log(client, zone, LOGLEVEL_DEBUG,
2783 "update section prescan OK");
2786 * Process the Update Section.
2789 options = dns_zone_getoptions(zone);
2790 for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
2791 result == ISC_R_SUCCESS;
2792 result = dns_message_nextname(request, DNS_SECTION_UPDATE))
2794 dns_name_t *name = NULL;
2795 dns_rdata_t rdata = DNS_RDATA_INIT;
2797 dns_rdataclass_t update_class;
2800 get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
2801 &name, &rdata, &covers, &ttl, &update_class);
2803 if (update_class == zoneclass) {
2806 * RFC1123 doesn't allow MF and MD in master zones. */
2807 if (rdata.type == dns_rdatatype_md ||
2808 rdata.type == dns_rdatatype_mf) {
2809 char typebuf[DNS_RDATATYPE_FORMATSIZE];
2811 dns_rdatatype_format(rdata.type, typebuf,
2813 update_log(client, zone, LOGLEVEL_PROTOCOL,
2814 "attempt to add %s ignored",
2818 if (rdata.type == dns_rdatatype_ns &&
2819 dns_name_iswildcard(name)) {
2820 update_log(client, zone,
2822 "attempt to add wildcard NS record"
2826 if (rdata.type == dns_rdatatype_cname) {
2827 CHECK(cname_incompatible_rrset_exists(db, ver,
2831 update_log(client, zone,
2833 "attempt to add CNAME "
2834 "alongside non-CNAME "
2839 CHECK(rrset_exists(db, ver, name,
2840 dns_rdatatype_cname, 0,
2843 ! dns_rdatatype_isdnssec(rdata.type))
2845 update_log(client, zone,
2847 "attempt to add non-CNAME "
2848 "alongside CNAME ignored");
2852 if (rdata.type == dns_rdatatype_soa) {
2854 CHECK(rrset_exists(db, ver, name,
2855 dns_rdatatype_soa, 0,
2858 update_log(client, zone,
2860 "attempt to create 2nd "
2864 CHECK(check_soa_increment(db, ver, &rdata,
2867 update_log(client, zone,
2869 "SOA update failed to "
2870 "increment serial, "
2874 soa_serial_changed = ISC_TRUE;
2876 if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
2877 dns_name_internalwildcard(name)) {
2878 char namestr[DNS_NAME_FORMATSIZE];
2879 dns_name_format(name, namestr,
2881 update_log(client, zone, LOGLEVEL_PROTOCOL,
2882 "warning: ownername '%s' contains "
2883 "a non-terminal wildcard", namestr);
2886 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {
2887 char namestr[DNS_NAME_FORMATSIZE];
2888 char typestr[DNS_RDATATYPE_FORMATSIZE];
2889 dns_name_format(name, namestr,
2891 dns_rdatatype_format(rdata.type, typestr,
2893 update_log(client, zone, LOGLEVEL_PROTOCOL,
2894 "adding an RR at '%s' %s",
2898 /* Prepare the affected RRset for the addition. */
2900 add_rr_prepare_ctx_t ctx;
2905 ctx.update_rr = &rdata;
2906 ctx.update_rr_ttl = ttl;
2907 ctx.ignore_add = ISC_FALSE;
2908 dns_diff_init(mctx, &ctx.del_diff);
2909 dns_diff_init(mctx, &ctx.add_diff);
2910 CHECK(foreach_rr(db, ver, name, rdata.type,
2911 covers, add_rr_prepare_action,
2914 if (ctx.ignore_add) {
2915 dns_diff_clear(&ctx.del_diff);
2916 dns_diff_clear(&ctx.add_diff);
2918 CHECK(do_diff(&ctx.del_diff, db, ver, &diff));
2919 CHECK(do_diff(&ctx.add_diff, db, ver, &diff));
2920 CHECK(update_one_rr(db, ver, &diff,
2922 name, ttl, &rdata));
2925 } else if (update_class == dns_rdataclass_any) {
2926 if (rdata.type == dns_rdatatype_any) {
2927 if (isc_log_wouldlog(ns_g_lctx,
2930 char namestr[DNS_NAME_FORMATSIZE];
2931 dns_name_format(name, namestr,
2933 update_log(client, zone,
2935 "delete all rrsets from "
2936 "name '%s'", namestr);
2938 if (dns_name_equal(name, zonename)) {
2939 CHECK(delete_if(type_not_soa_nor_ns_p,
2941 dns_rdatatype_any, 0,
2944 CHECK(delete_if(type_not_dnssec,
2946 dns_rdatatype_any, 0,
2949 } else if (dns_name_equal(name, zonename) &&
2950 (rdata.type == dns_rdatatype_soa ||
2951 rdata.type == dns_rdatatype_ns)) {
2952 update_log(client, zone, LOGLEVEL_PROTOCOL,
2953 "attempt to delete all SOA "
2954 "or NS records ignored");
2957 if (isc_log_wouldlog(ns_g_lctx,
2960 char namestr[DNS_NAME_FORMATSIZE];
2961 char typestr[DNS_RDATATYPE_FORMATSIZE];
2962 dns_name_format(name, namestr,
2964 dns_rdatatype_format(rdata.type,
2967 update_log(client, zone,
2969 "deleting rrset at '%s' %s",
2972 CHECK(delete_if(true_p, db, ver, name,
2973 rdata.type, covers, &rdata,
2976 } else if (update_class == dns_rdataclass_none) {
2978 * The (name == zonename) condition appears in
2979 * RFC2136 3.4.2.4 but is missing from the pseudocode.
2981 if (dns_name_equal(name, zonename)) {
2982 if (rdata.type == dns_rdatatype_soa) {
2983 update_log(client, zone,
2985 "attempt to delete SOA "
2989 if (rdata.type == dns_rdatatype_ns) {
2991 CHECK(rr_count(db, ver, name,
2995 update_log(client, zone,
3004 update_log(client, zone,
3007 CHECK(delete_if(rr_equal_p, db, ver, name,
3008 rdata.type, covers, &rdata, &diff));
3011 if (result != ISC_R_NOMORE)
3015 * If any changes were made, increment the SOA serial number,
3016 * update RRSIGs and NSECs (if zone is secure), and write the update
3019 if (! ISC_LIST_EMPTY(diff.tuples)) {
3021 dns_journal_t *journal;
3024 * Increment the SOA serial, but only if it was not
3025 * changed as a result of an update operation.
3027 if (! soa_serial_changed) {
3028 CHECK(increment_soa_serial(db, ver, &diff, mctx));
3031 CHECK(check_mx(client, zone, db, ver, &diff));
3033 CHECK(remove_orphaned_ds(db, ver, &diff));
3035 if (dns_db_issecure(db)) {
3036 result = update_signatures(client, zone, db, oldver,
3038 dns_zone_getsigvalidityinterval(zone));
3039 if (result != ISC_R_SUCCESS) {
3040 update_log(client, zone,
3042 "RRSIG/NSEC update failed: %s",
3043 isc_result_totext(result));
3048 journalfile = dns_zone_getjournal(zone);
3049 if (journalfile != NULL) {
3050 update_log(client, zone, LOGLEVEL_DEBUG,
3051 "writing journal %s", journalfile);
3054 result = dns_journal_open(mctx, journalfile,
3055 ISC_TRUE, &journal);
3056 if (result != ISC_R_SUCCESS)
3057 FAILS(result, "journal open failed");
3059 result = dns_journal_write_transaction(journal, &diff);
3060 if (result != ISC_R_SUCCESS) {
3061 dns_journal_destroy(&journal);
3062 FAILS(result, "journal write failed");
3065 dns_journal_destroy(&journal);
3069 * XXXRTH Just a note that this committing code will have
3070 * to change to handle databases that need two-phase
3071 * commit, but this isn't a priority.
3073 update_log(client, zone, LOGLEVEL_DEBUG,
3074 "committing update transaction");
3075 dns_db_closeversion(db, &ver, ISC_TRUE);
3078 * Mark the zone as dirty so that it will be written to disk.
3080 dns_zone_markdirty(zone);
3083 * Notify slaves of the change we just made.
3085 dns_zone_notify(zone);
3087 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
3088 dns_db_closeversion(db, &ver, ISC_TRUE);
3090 result = ISC_R_SUCCESS;
3095 * The reason for failure should have been logged at this point.
3098 update_log(client, zone, LOGLEVEL_DEBUG,
3100 dns_db_closeversion(db, &ver, ISC_FALSE);
3104 dns_diff_clear(&temp);
3105 dns_diff_clear(&diff);
3108 dns_db_closeversion(db, &oldver, ISC_FALSE);
3113 if (ssutable != NULL)
3114 dns_ssutable_detach(&ssutable);
3116 isc_task_detach(&task);
3117 uev->result = result;
3119 INSIST(uev->zone == zone); /* we use this later */
3120 uev->ev_type = DNS_EVENT_UPDATEDONE;
3121 uev->ev_action = updatedone_action;
3122 isc_task_send(client->task, &event);
3123 INSIST(event == NULL);
3127 updatedone_action(isc_task_t *task, isc_event_t *event) {
3128 update_event_t *uev = (update_event_t *) event;
3129 ns_client_t *client = (ns_client_t *) event->ev_arg;
3133 INSIST(event->ev_type == DNS_EVENT_UPDATEDONE);
3134 INSIST(task == client->task);
3136 INSIST(client->nupdates > 0);
3137 switch (uev->result) {
3139 inc_stats(uev->zone, dns_nsstatscounter_updatedone);
3142 inc_stats(uev->zone, dns_nsstatscounter_updaterej);
3145 inc_stats(uev->zone, dns_nsstatscounter_updatefail);
3148 if (uev->zone != NULL)
3149 dns_zone_detach(&uev->zone);
3151 respond(client, uev->result);
3152 isc_event_free(&event);
3153 ns_client_detach(&client);
3157 * Update forwarding support.
3161 forward_fail(isc_task_t *task, isc_event_t *event) {
3162 ns_client_t *client = (ns_client_t *)event->ev_arg;
3166 INSIST(client->nupdates > 0);
3168 respond(client, DNS_R_SERVFAIL);
3169 isc_event_free(&event);
3170 ns_client_detach(&client);
3175 forward_callback(void *arg, isc_result_t result, dns_message_t *answer) {
3176 update_event_t *uev = arg;
3177 ns_client_t *client = uev->ev_arg;
3178 dns_zone_t *zone = uev->zone;
3180 if (result != ISC_R_SUCCESS) {
3181 INSIST(answer == NULL);
3182 uev->ev_type = DNS_EVENT_UPDATEDONE;
3183 uev->ev_action = forward_fail;
3184 inc_stats(zone, dns_nsstatscounter_updatefwdfail);
3186 uev->ev_type = DNS_EVENT_UPDATEDONE;
3187 uev->ev_action = forward_done;
3188 uev->answer = answer;
3189 inc_stats(zone, dns_nsstatscounter_updaterespfwd);
3191 isc_task_send(client->task, ISC_EVENT_PTR(&uev));
3192 dns_zone_detach(&zone);
3196 forward_done(isc_task_t *task, isc_event_t *event) {
3197 update_event_t *uev = (update_event_t *) event;
3198 ns_client_t *client = (ns_client_t *)event->ev_arg;
3202 INSIST(client->nupdates > 0);
3204 ns_client_sendraw(client, uev->answer);
3205 dns_message_destroy(&uev->answer);
3206 isc_event_free(&event);
3207 ns_client_detach(&client);
3211 forward_action(isc_task_t *task, isc_event_t *event) {
3212 update_event_t *uev = (update_event_t *) event;
3213 dns_zone_t *zone = uev->zone;
3214 ns_client_t *client = (ns_client_t *)event->ev_arg;
3215 isc_result_t result;
3217 result = dns_zone_forwardupdate(zone, client->message,
3218 forward_callback, event);
3219 if (result != ISC_R_SUCCESS) {
3220 uev->ev_type = DNS_EVENT_UPDATEDONE;
3221 uev->ev_action = forward_fail;
3222 isc_task_send(client->task, &event);
3223 inc_stats(zone, dns_nsstatscounter_updatefwdfail);
3224 dns_zone_detach(&zone);
3226 inc_stats(zone, dns_nsstatscounter_updatereqfwd);
3227 isc_task_detach(&task);
3231 send_forward_event(ns_client_t *client, dns_zone_t *zone) {
3232 isc_result_t result = ISC_R_SUCCESS;
3233 update_event_t *event = NULL;
3234 isc_task_t *zonetask = NULL;
3235 ns_client_t *evclient;
3237 event = (update_event_t *)
3238 isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
3239 forward_action, NULL, sizeof(*event));
3241 FAIL(ISC_R_NOMEMORY);
3243 event->result = ISC_R_SUCCESS;
3246 ns_client_attach(client, &evclient);
3247 INSIST(client->nupdates == 0);
3249 event->ev_arg = evclient;
3251 dns_zone_gettask(zone, &zonetask);
3252 isc_task_send(zonetask, ISC_EVENT_PTR(&event));
3256 isc_event_free(ISC_EVENT_PTR(&event));