4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: update.c,v 1.176 2009/12/04 21:09:32 marka Exp */
24 #include <isc/netaddr.h>
25 #include <isc/print.h>
26 #include <isc/serial.h>
27 #include <isc/stats.h>
28 #include <isc/string.h>
29 #include <isc/taskpool.h>
33 #include <dns/dbiterator.h>
35 #include <dns/dnssec.h>
36 #include <dns/events.h>
37 #include <dns/fixedname.h>
38 #include <dns/journal.h>
39 #include <dns/keyvalues.h>
40 #include <dns/message.h>
42 #include <dns/nsec3.h>
43 #include <dns/private.h>
44 #include <dns/rdataclass.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatasetiter.h>
47 #include <dns/rdatastruct.h>
48 #include <dns/rdatatype.h>
55 #include <named/client.h>
56 #include <named/log.h>
57 #include <named/server.h>
58 #include <named/update.h>
62 * This module implements dynamic update as in RFC2136.
67 * - document strict minimality
70 /**************************************************************************/
73 * Log level for tracing dynamic update protocol requests.
75 #define LOGLEVEL_PROTOCOL ISC_LOG_INFO
78 * Log level for low-level debug tracing.
80 #define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8)
83 * Check an operation for failure. These macros all assume that
84 * the function using them has a 'result' variable and a 'failure'
89 if (result != ISC_R_SUCCESS) goto failure; \
93 * Fail unconditionally with result 'code', which must not
94 * be ISC_R_SUCCESS. The reason for failure presumably has
95 * been logged already.
97 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
98 * from complaining about "end-of-loop code not reached".
104 if (result != ISC_R_SUCCESS) goto failure; \
108 * Fail unconditionally and log as a client error.
109 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
110 * from complaining about "end-of-loop code not reached".
112 #define FAILC(code, msg) \
114 const char *_what = "failed"; \
117 case DNS_R_NXDOMAIN: \
118 case DNS_R_YXDOMAIN: \
119 case DNS_R_YXRRSET: \
120 case DNS_R_NXRRSET: \
121 _what = "unsuccessful"; \
123 update_log(client, zone, LOGLEVEL_PROTOCOL, \
124 "update %s: %s (%s)", _what, \
125 msg, isc_result_totext(result)); \
126 if (result != ISC_R_SUCCESS) goto failure; \
128 #define PREREQFAILC(code, msg) \
130 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
134 #define FAILN(code, name, msg) \
136 const char *_what = "failed"; \
139 case DNS_R_NXDOMAIN: \
140 case DNS_R_YXDOMAIN: \
141 case DNS_R_YXRRSET: \
142 case DNS_R_NXRRSET: \
143 _what = "unsuccessful"; \
145 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \
146 char _nbuf[DNS_NAME_FORMATSIZE]; \
147 dns_name_format(name, _nbuf, sizeof(_nbuf)); \
148 update_log(client, zone, LOGLEVEL_PROTOCOL, \
149 "update %s: %s: %s (%s)", _what, _nbuf, \
150 msg, isc_result_totext(result)); \
152 if (result != ISC_R_SUCCESS) goto failure; \
154 #define PREREQFAILN(code, name, msg) \
156 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
157 FAILN(code, name, msg); \
160 #define FAILNT(code, name, type, msg) \
162 const char *_what = "failed"; \
165 case DNS_R_NXDOMAIN: \
166 case DNS_R_YXDOMAIN: \
167 case DNS_R_YXRRSET: \
168 case DNS_R_NXRRSET: \
169 _what = "unsuccessful"; \
171 if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) { \
172 char _nbuf[DNS_NAME_FORMATSIZE]; \
173 char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \
174 dns_name_format(name, _nbuf, sizeof(_nbuf)); \
175 dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
176 update_log(client, zone, LOGLEVEL_PROTOCOL, \
177 "update %s: %s/%s: %s (%s)", \
178 _what, _nbuf, _tbuf, msg, \
179 isc_result_totext(result)); \
181 if (result != ISC_R_SUCCESS) goto failure; \
183 #define PREREQFAILNT(code, name, type, msg) \
185 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
186 FAILNT(code, name, type, msg); \
190 * Fail unconditionally and log as a server error.
191 * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
192 * from complaining about "end-of-loop code not reached".
194 #define FAILS(code, msg) \
197 update_log(client, zone, LOGLEVEL_PROTOCOL, \
199 msg, isc_result_totext(result)); \
200 if (result != ISC_R_SUCCESS) goto failure; \
204 * Return TRUE if NS_CLIENTATTR_TCP is set in the attributes other FALSE.
206 #define TCPCLIENT(client) (((client)->attributes & NS_CLIENTATTR_TCP) != 0)
208 /**************************************************************************/
210 typedef struct rr rr_t
;
213 /* dns_name_t name; */
218 typedef struct update_event update_event_t
;
220 struct update_event
{
221 ISC_EVENT_COMMON(update_event_t
);
224 dns_message_t
*answer
;
227 /**************************************************************************/
229 * Forward declarations.
232 static void update_action(isc_task_t
*task
, isc_event_t
*event
);
233 static void updatedone_action(isc_task_t
*task
, isc_event_t
*event
);
234 static isc_result_t
send_forward_event(ns_client_t
*client
, dns_zone_t
*zone
);
235 static void forward_done(isc_task_t
*task
, isc_event_t
*event
);
237 /**************************************************************************/
240 update_log(ns_client_t
*client
, dns_zone_t
*zone
,
241 int level
, const char *fmt
, ...) ISC_FORMAT_PRINTF(4, 5);
244 update_log(ns_client_t
*client
, dns_zone_t
*zone
,
245 int level
, const char *fmt
, ...)
249 char namebuf
[DNS_NAME_FORMATSIZE
];
250 char classbuf
[DNS_RDATACLASS_FORMATSIZE
];
252 if (client
== NULL
|| zone
== NULL
)
255 if (isc_log_wouldlog(ns_g_lctx
, level
) == ISC_FALSE
)
258 dns_name_format(dns_zone_getorigin(zone
), namebuf
,
260 dns_rdataclass_format(dns_zone_getclass(zone
), classbuf
,
264 vsnprintf(message
, sizeof(message
), fmt
, ap
);
267 ns_client_log(client
, NS_LOGCATEGORY_UPDATE
, NS_LOGMODULE_UPDATE
,
268 level
, "updating zone '%s/%s': %s",
269 namebuf
, classbuf
, message
);
273 * Increment updated-related statistics counters.
276 inc_stats(dns_zone_t
*zone
, isc_statscounter_t counter
) {
277 isc_stats_increment(ns_g_server
->nsstats
, counter
);
280 isc_stats_t
*zonestats
= dns_zone_getrequeststats(zone
);
281 if (zonestats
!= NULL
)
282 isc_stats_increment(zonestats
, counter
);
287 * Check if we could have queried for the contents of this zone or
288 * if the zone is potentially updateable.
289 * If the zone can potentially be updated and the check failed then
290 * log a error otherwise we log a informational message.
293 checkqueryacl(ns_client_t
*client
, dns_acl_t
*queryacl
, dns_name_t
*zonename
,
294 dns_acl_t
*updateacl
, dns_ssutable_t
*ssutable
)
296 char namebuf
[DNS_NAME_FORMATSIZE
];
297 char classbuf
[DNS_RDATACLASS_FORMATSIZE
];
301 result
= ns_client_checkaclsilent(client
, NULL
, queryacl
, ISC_TRUE
);
302 if (result
!= ISC_R_SUCCESS
) {
303 dns_name_format(zonename
, namebuf
, sizeof(namebuf
));
304 dns_rdataclass_format(client
->view
->rdclass
, classbuf
,
307 level
= (updateacl
== NULL
&& ssutable
== NULL
) ?
308 ISC_LOG_INFO
: ISC_LOG_ERROR
;
310 ns_client_log(client
, NS_LOGCATEGORY_UPDATE_SECURITY
,
311 NS_LOGMODULE_UPDATE
, level
,
312 "update '%s/%s' denied due to allow-query",
314 } else if (updateacl
== NULL
&& ssutable
== NULL
) {
315 dns_name_format(zonename
, namebuf
, sizeof(namebuf
));
316 dns_rdataclass_format(client
->view
->rdclass
, classbuf
,
319 result
= DNS_R_REFUSED
;
320 ns_client_log(client
, NS_LOGCATEGORY_UPDATE_SECURITY
,
321 NS_LOGMODULE_UPDATE
, ISC_LOG_INFO
,
322 "update '%s/%s' denied", namebuf
, classbuf
);
328 * Override the default acl logging when checking whether a client
329 * can update the zone or whether we can forward the request to the
330 * master based on IP address.
332 * 'message' contains the type of operation that is being attempted.
333 * 'slave' indicates if this is a slave zone. If 'acl' is NULL then
335 * If the zone has no access controls configured ('acl' == NULL &&
336 * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise
339 * If the request was signed log that we received it.
342 checkupdateacl(ns_client_t
*client
, dns_acl_t
*acl
, const char *message
,
343 dns_name_t
*zonename
, isc_boolean_t slave
,
344 isc_boolean_t has_ssutable
)
346 char namebuf
[DNS_NAME_FORMATSIZE
];
347 char classbuf
[DNS_RDATACLASS_FORMATSIZE
];
348 int level
= ISC_LOG_ERROR
;
349 const char *msg
= "denied";
352 if (slave
&& acl
== NULL
) {
353 result
= DNS_R_NOTIMP
;
354 level
= ISC_LOG_DEBUG(3);
357 result
= ns_client_checkaclsilent(client
, NULL
, acl
, ISC_FALSE
);
358 if (result
== ISC_R_SUCCESS
) {
359 level
= ISC_LOG_DEBUG(3);
361 } else if (acl
== NULL
&& !has_ssutable
) {
362 level
= ISC_LOG_INFO
;
366 if (client
->signer
!= NULL
) {
367 dns_name_format(client
->signer
, namebuf
, sizeof(namebuf
));
368 ns_client_log(client
, NS_LOGCATEGORY_UPDATE_SECURITY
,
369 NS_LOGMODULE_UPDATE
, ISC_LOG_INFO
,
370 "signer \"%s\" %s", namebuf
, msg
);
373 dns_name_format(zonename
, namebuf
, sizeof(namebuf
));
374 dns_rdataclass_format(client
->view
->rdclass
, classbuf
,
377 ns_client_log(client
, NS_LOGCATEGORY_UPDATE_SECURITY
,
378 NS_LOGMODULE_UPDATE
, level
, "%s '%s/%s' %s",
379 message
, namebuf
, classbuf
, msg
);
384 * Update a single RR in version 'ver' of 'db' and log the
388 * \li '*tuple' == NULL. Either the tuple is freed, or its
389 * ownership has been transferred to the diff.
392 do_one_tuple(dns_difftuple_t
**tuple
, dns_db_t
*db
, dns_dbversion_t
*ver
,
395 dns_diff_t temp_diff
;
399 * Create a singleton diff.
401 dns_diff_init(diff
->mctx
, &temp_diff
);
402 temp_diff
.resign
= diff
->resign
;
403 ISC_LIST_APPEND(temp_diff
.tuples
, *tuple
, link
);
406 * Apply it to the database.
408 result
= dns_diff_apply(&temp_diff
, db
, ver
);
409 ISC_LIST_UNLINK(temp_diff
.tuples
, *tuple
, link
);
410 if (result
!= ISC_R_SUCCESS
) {
411 dns_difftuple_free(tuple
);
416 * Merge it into the current pending journal entry.
418 dns_diff_appendminimal(diff
, tuple
);
421 * Do not clear temp_diff.
423 return (ISC_R_SUCCESS
);
427 * Perform the updates in 'updates' in version 'ver' of 'db' and log the
431 * \li 'updates' is empty.
434 do_diff(dns_diff_t
*updates
, dns_db_t
*db
, dns_dbversion_t
*ver
,
438 while (! ISC_LIST_EMPTY(updates
->tuples
)) {
439 dns_difftuple_t
*t
= ISC_LIST_HEAD(updates
->tuples
);
440 ISC_LIST_UNLINK(updates
->tuples
, t
, link
);
441 CHECK(do_one_tuple(&t
, db
, ver
, diff
));
443 return (ISC_R_SUCCESS
);
446 dns_diff_clear(diff
);
451 update_one_rr(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_diff_t
*diff
,
452 dns_diffop_t op
, dns_name_t
*name
, dns_ttl_t ttl
,
455 dns_difftuple_t
*tuple
= NULL
;
457 result
= dns_difftuple_create(diff
->mctx
, op
,
458 name
, ttl
, rdata
, &tuple
);
459 if (result
!= ISC_R_SUCCESS
)
461 return (do_one_tuple(&tuple
, db
, ver
, diff
));
464 /**************************************************************************/
466 * Callback-style iteration over rdatasets and rdatas.
468 * foreach_rrset() can be used to iterate over the RRsets
469 * of a name and call a callback function with each
470 * one. Similarly, foreach_rr() can be used to iterate
471 * over the individual RRs at name, optionally restricted
472 * to RRs of a given type.
474 * The callback functions are called "actions" and take
475 * two arguments: a void pointer for passing arbitrary
476 * context information, and a pointer to the current RRset
477 * or RR. By convention, their names end in "_action".
481 * XXXRTH We might want to make this public somewhere in libdns.
485 * Function type for foreach_rrset() iterator actions.
487 typedef isc_result_t
rrset_func(void *data
, dns_rdataset_t
*rrset
);
490 * Function type for foreach_rr() iterator actions.
492 typedef isc_result_t
rr_func(void *data
, rr_t
*rr
);
495 * Internal context struct for foreach_node_rr().
499 void * rr_action_data
;
500 } foreach_node_rr_ctx_t
;
503 * Internal helper function for foreach_node_rr().
506 foreach_node_rr_action(void *data
, dns_rdataset_t
*rdataset
) {
508 foreach_node_rr_ctx_t
*ctx
= data
;
509 for (result
= dns_rdataset_first(rdataset
);
510 result
== ISC_R_SUCCESS
;
511 result
= dns_rdataset_next(rdataset
))
513 rr_t rr
= { 0, DNS_RDATA_INIT
};
515 dns_rdataset_current(rdataset
, &rr
.rdata
);
516 rr
.ttl
= rdataset
->ttl
;
517 result
= (*ctx
->rr_action
)(ctx
->rr_action_data
, &rr
);
518 if (result
!= ISC_R_SUCCESS
)
521 if (result
!= ISC_R_NOMORE
)
523 return (ISC_R_SUCCESS
);
527 * For each rdataset of 'name' in 'ver' of 'db', call 'action'
528 * with the rdataset and 'action_data' as arguments. If the name
529 * does not exist, do nothing.
531 * If 'action' returns an error, abort iteration and return the error.
534 foreach_rrset(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
535 rrset_func
*action
, void *action_data
)
539 dns_rdatasetiter_t
*iter
;
542 result
= dns_db_findnode(db
, name
, ISC_FALSE
, &node
);
543 if (result
== ISC_R_NOTFOUND
)
544 return (ISC_R_SUCCESS
);
545 if (result
!= ISC_R_SUCCESS
)
549 result
= dns_db_allrdatasets(db
, node
, ver
,
550 (isc_stdtime_t
) 0, &iter
);
551 if (result
!= ISC_R_SUCCESS
)
554 for (result
= dns_rdatasetiter_first(iter
);
555 result
== ISC_R_SUCCESS
;
556 result
= dns_rdatasetiter_next(iter
))
558 dns_rdataset_t rdataset
;
560 dns_rdataset_init(&rdataset
);
561 dns_rdatasetiter_current(iter
, &rdataset
);
563 result
= (*action
)(action_data
, &rdataset
);
565 dns_rdataset_disassociate(&rdataset
);
566 if (result
!= ISC_R_SUCCESS
)
567 goto cleanup_iterator
;
569 if (result
== ISC_R_NOMORE
)
570 result
= ISC_R_SUCCESS
;
573 dns_rdatasetiter_destroy(&iter
);
576 dns_db_detachnode(db
, &node
);
582 * For each RR of 'name' in 'ver' of 'db', call 'action'
583 * with the RR and 'action_data' as arguments. If the name
584 * does not exist, do nothing.
586 * If 'action' returns an error, abort iteration
587 * and return the error.
590 foreach_node_rr(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
591 rr_func
*rr_action
, void *rr_action_data
)
593 foreach_node_rr_ctx_t ctx
;
594 ctx
.rr_action
= rr_action
;
595 ctx
.rr_action_data
= rr_action_data
;
596 return (foreach_rrset(db
, ver
, name
,
597 foreach_node_rr_action
, &ctx
));
602 * For each of the RRs specified by 'db', 'ver', 'name', 'type',
603 * (which can be dns_rdatatype_any to match any type), and 'covers', call
604 * 'action' with the RR and 'action_data' as arguments. If the name
605 * does not exist, or if no RRset of the given type exists at the name,
608 * If 'action' returns an error, abort iteration and return the error.
611 foreach_rr(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
612 dns_rdatatype_t type
, dns_rdatatype_t covers
, rr_func
*rr_action
,
613 void *rr_action_data
)
618 dns_rdataset_t rdataset
;
620 if (type
== dns_rdatatype_any
)
621 return (foreach_node_rr(db
, ver
, name
,
622 rr_action
, rr_action_data
));
625 if (type
== dns_rdatatype_nsec3
||
626 (type
== dns_rdatatype_rrsig
&& covers
== dns_rdatatype_nsec3
))
627 result
= dns_db_findnsec3node(db
, name
, ISC_FALSE
, &node
);
629 result
= dns_db_findnode(db
, name
, ISC_FALSE
, &node
);
630 if (result
== ISC_R_NOTFOUND
)
631 return (ISC_R_SUCCESS
);
632 if (result
!= ISC_R_SUCCESS
)
635 dns_rdataset_init(&rdataset
);
636 result
= dns_db_findrdataset(db
, node
, ver
, type
, covers
,
637 (isc_stdtime_t
) 0, &rdataset
, NULL
);
638 if (result
== ISC_R_NOTFOUND
) {
639 result
= ISC_R_SUCCESS
;
642 if (result
!= ISC_R_SUCCESS
)
645 for (result
= dns_rdataset_first(&rdataset
);
646 result
== ISC_R_SUCCESS
;
647 result
= dns_rdataset_next(&rdataset
))
649 rr_t rr
= { 0, DNS_RDATA_INIT
};
650 dns_rdataset_current(&rdataset
, &rr
.rdata
);
651 rr
.ttl
= rdataset
.ttl
;
652 result
= (*rr_action
)(rr_action_data
, &rr
);
653 if (result
!= ISC_R_SUCCESS
)
654 goto cleanup_rdataset
;
656 if (result
!= ISC_R_NOMORE
)
657 goto cleanup_rdataset
;
658 result
= ISC_R_SUCCESS
;
661 dns_rdataset_disassociate(&rdataset
);
663 dns_db_detachnode(db
, &node
);
668 /**************************************************************************/
670 * Various tests on the database contents (for prerequisites, etc).
674 * Function type for predicate functions that compare a database RR 'db_rr'
675 * against an update RR 'update_rr'.
677 typedef isc_boolean_t
rr_predicate(dns_rdata_t
*update_rr
, dns_rdata_t
*db_rr
);
680 * Helper function for rrset_exists().
683 rrset_exists_action(void *data
, rr_t
*rr
) {
686 return (ISC_R_EXISTS
);
690 * Utility macro for RR existence checking functions.
692 * If the variable 'result' has the value ISC_R_EXISTS or
693 * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
694 * respectively, and return success.
696 * If 'result' has any other value, there was a failure.
697 * Return the failure result code and do not set *exists.
699 * This would be more readable as "do { if ... } while(0)",
700 * but that form generates tons of warnings on Solaris 2.6.
702 #define RETURN_EXISTENCE_FLAG \
703 return ((result == ISC_R_EXISTS) ? \
704 (*exists = ISC_TRUE, ISC_R_SUCCESS) : \
705 ((result == ISC_R_SUCCESS) ? \
706 (*exists = ISC_FALSE, ISC_R_SUCCESS) : \
710 * Set '*exists' to true iff an rrset of the given type exists,
711 * to false otherwise.
714 rrset_exists(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
715 dns_rdatatype_t type
, dns_rdatatype_t covers
,
716 isc_boolean_t
*exists
)
719 result
= foreach_rr(db
, ver
, name
, type
, covers
,
720 rrset_exists_action
, NULL
);
721 RETURN_EXISTENCE_FLAG
;
725 * Set '*visible' to true if the RRset exists and is part of the
726 * visible zone. Otherwise '*visible' is set to false unless a
730 rrset_visible(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
731 dns_rdatatype_t type
, isc_boolean_t
*visible
)
734 dns_fixedname_t fixed
;
736 dns_fixedname_init(&fixed
);
737 result
= dns_db_find(db
, name
, ver
, type
, DNS_DBFIND_NOWILD
,
738 (isc_stdtime_t
) 0, NULL
,
739 dns_fixedname_name(&fixed
), NULL
, NULL
);
745 * Glue, obscured, deleted or replaced records.
747 case DNS_R_DELEGATION
:
752 case DNS_R_EMPTYNAME
:
753 case DNS_R_COVERINGNSEC
:
754 *visible
= ISC_FALSE
;
755 result
= ISC_R_SUCCESS
;
764 * Helper function for cname_incompatible_rrset_exists.
767 cname_compatibility_action(void *data
, dns_rdataset_t
*rrset
) {
769 if (rrset
->type
!= dns_rdatatype_cname
&&
770 ! dns_rdatatype_isdnssec(rrset
->type
))
771 return (ISC_R_EXISTS
);
772 return (ISC_R_SUCCESS
);
776 * Check whether there is an rrset incompatible with adding a CNAME RR,
777 * i.e., anything but another CNAME (which can be replaced) or a
778 * DNSSEC RR (which can coexist).
780 * If such an incompatible rrset exists, set '*exists' to ISC_TRUE.
781 * Otherwise, set it to ISC_FALSE.
784 cname_incompatible_rrset_exists(dns_db_t
*db
, dns_dbversion_t
*ver
,
785 dns_name_t
*name
, isc_boolean_t
*exists
) {
787 result
= foreach_rrset(db
, ver
, name
,
788 cname_compatibility_action
, NULL
);
789 RETURN_EXISTENCE_FLAG
;
793 * Helper function for rr_count().
796 count_rr_action(void *data
, rr_t
*rr
) {
800 return (ISC_R_SUCCESS
);
804 * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'.
807 rr_count(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
808 dns_rdatatype_t type
, dns_rdatatype_t covers
, int *countp
)
811 return (foreach_rr(db
, ver
, name
, type
, covers
,
812 count_rr_action
, countp
));
816 * Context struct and helper function for name_exists().
820 name_exists_action(void *data
, dns_rdataset_t
*rrset
) {
823 return (ISC_R_EXISTS
);
827 * Set '*exists' to true iff the given name exists, to false otherwise.
830 name_exists(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
831 isc_boolean_t
*exists
)
834 result
= foreach_rrset(db
, ver
, name
,
835 name_exists_action
, NULL
);
836 RETURN_EXISTENCE_FLAG
;
840 * 'ssu_check_t' is used to pass the arguments to
841 * dns_ssutable_checkrules() to the callback function
845 /* The ownername of the record to be updated. */
848 /* The signature's name if the request was signed. */
851 /* The address of the client if the request was received via TCP. */
852 isc_netaddr_t
*tcpaddr
;
854 /* The ssu table to check against. */
855 dns_ssutable_t
*table
;
859 ssu_checkrule(void *data
, dns_rdataset_t
*rrset
) {
860 ssu_check_t
*ssuinfo
= data
;
861 isc_boolean_t result
;
864 * If we're deleting all records, it's ok to delete RRSIG and NSEC even
865 * if we're normally not allowed to.
867 if (rrset
->type
== dns_rdatatype_rrsig
||
868 rrset
->type
== dns_rdatatype_nsec
)
869 return (ISC_R_SUCCESS
);
870 result
= dns_ssutable_checkrules(ssuinfo
->table
, ssuinfo
->signer
,
871 ssuinfo
->name
, ssuinfo
->tcpaddr
,
873 return (result
== ISC_TRUE
? ISC_R_SUCCESS
: ISC_R_FAILURE
);
877 ssu_checkall(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
878 dns_ssutable_t
*ssutable
, dns_name_t
*signer
,
879 isc_netaddr_t
*tcpaddr
)
885 ssuinfo
.table
= ssutable
;
886 ssuinfo
.signer
= signer
;
887 ssuinfo
.tcpaddr
= tcpaddr
;
888 result
= foreach_rrset(db
, ver
, name
, ssu_checkrule
, &ssuinfo
);
889 return (ISC_TF(result
== ISC_R_SUCCESS
));
892 /**************************************************************************/
894 * Checking of "RRset exists (value dependent)" prerequisites.
896 * In the RFC2136 section 3.2.5, this is the pseudocode involving
897 * a variable called "temp", a mapping of <name, type> tuples to rrsets.
899 * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
900 * where each tuple has op==DNS_DIFFOP_EXISTS.
905 * Append a tuple asserting the existence of the RR with
906 * 'name' and 'rdata' to 'diff'.
909 temp_append(dns_diff_t
*diff
, dns_name_t
*name
, dns_rdata_t
*rdata
) {
911 dns_difftuple_t
*tuple
= NULL
;
913 REQUIRE(DNS_DIFF_VALID(diff
));
914 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_EXISTS
,
915 name
, 0, rdata
, &tuple
));
916 ISC_LIST_APPEND(diff
->tuples
, tuple
, link
);
922 * Compare two rdatasets represented as sorted lists of tuples.
923 * All list elements must have the same owner name and type.
924 * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset)
928 temp_check_rrset(dns_difftuple_t
*a
, dns_difftuple_t
*b
) {
930 if (a
== NULL
|| b
== NULL
)
932 INSIST(a
->op
== DNS_DIFFOP_EXISTS
&&
933 b
->op
== DNS_DIFFOP_EXISTS
);
934 INSIST(a
->rdata
.type
== b
->rdata
.type
);
935 INSIST(dns_name_equal(&a
->name
, &b
->name
));
936 if (dns_rdata_casecompare(&a
->rdata
, &b
->rdata
) != 0)
937 return (DNS_R_NXRRSET
);
938 a
= ISC_LIST_NEXT(a
, link
);
939 b
= ISC_LIST_NEXT(b
, link
);
941 if (a
!= NULL
|| b
!= NULL
)
942 return (DNS_R_NXRRSET
);
943 return (ISC_R_SUCCESS
);
947 * A comparison function defining the sorting order for the entries
948 * in the "temp" data structure. The major sort key is the owner name,
949 * followed by the type and rdata.
952 temp_order(const void *av
, const void *bv
) {
953 dns_difftuple_t
const * const *ap
= av
;
954 dns_difftuple_t
const * const *bp
= bv
;
955 dns_difftuple_t
const *a
= *ap
;
956 dns_difftuple_t
const *b
= *bp
;
958 r
= dns_name_compare(&a
->name
, &b
->name
);
961 r
= (b
->rdata
.type
- a
->rdata
.type
);
964 r
= dns_rdata_casecompare(&a
->rdata
, &b
->rdata
);
969 * Check the "RRset exists (value dependent)" prerequisite information
970 * in 'temp' against the contents of the database 'db'.
972 * Return ISC_R_SUCCESS if the prerequisites are satisfied,
973 * rcode(dns_rcode_nxrrset) if not.
975 * 'temp' must be pre-sorted.
979 temp_check(isc_mem_t
*mctx
, dns_diff_t
*temp
, dns_db_t
*db
,
980 dns_dbversion_t
*ver
, dns_name_t
*tmpname
, dns_rdatatype_t
*typep
)
988 dns_diff_init(mctx
, &trash
);
991 * For each name and type in the prerequisites,
992 * construct a sorted rdata list of the corresponding
993 * database contents, and compare the lists.
995 t
= ISC_LIST_HEAD(temp
->tuples
);
998 (void)dns_name_copy(name
, tmpname
, NULL
);
999 *typep
= t
->rdata
.type
;
1001 /* A new unique name begins here. */
1003 result
= dns_db_findnode(db
, name
, ISC_FALSE
, &node
);
1004 if (result
== ISC_R_NOTFOUND
) {
1005 dns_diff_clear(&trash
);
1006 return (DNS_R_NXRRSET
);
1008 if (result
!= ISC_R_SUCCESS
) {
1009 dns_diff_clear(&trash
);
1013 /* A new unique type begins here. */
1014 while (t
!= NULL
&& dns_name_equal(&t
->name
, name
)) {
1015 dns_rdatatype_t type
, covers
;
1016 dns_rdataset_t rdataset
;
1017 dns_diff_t d_rrs
; /* Database RRs with
1018 this name and type */
1019 dns_diff_t u_rrs
; /* Update RRs with
1020 this name and type */
1022 *typep
= type
= t
->rdata
.type
;
1023 if (type
== dns_rdatatype_rrsig
||
1024 type
== dns_rdatatype_sig
)
1025 covers
= dns_rdata_covers(&t
->rdata
);
1026 else if (type
== dns_rdatatype_any
) {
1027 dns_db_detachnode(db
, &node
);
1028 dns_diff_clear(&trash
);
1029 return (DNS_R_NXRRSET
);
1034 * Collect all database RRs for this name and type
1035 * onto d_rrs and sort them.
1037 dns_rdataset_init(&rdataset
);
1038 result
= dns_db_findrdataset(db
, node
, ver
, type
,
1039 covers
, (isc_stdtime_t
) 0,
1041 if (result
!= ISC_R_SUCCESS
) {
1042 dns_db_detachnode(db
, &node
);
1043 dns_diff_clear(&trash
);
1044 return (DNS_R_NXRRSET
);
1047 dns_diff_init(mctx
, &d_rrs
);
1048 dns_diff_init(mctx
, &u_rrs
);
1050 for (result
= dns_rdataset_first(&rdataset
);
1051 result
== ISC_R_SUCCESS
;
1052 result
= dns_rdataset_next(&rdataset
))
1054 dns_rdata_t rdata
= DNS_RDATA_INIT
;
1055 dns_rdataset_current(&rdataset
, &rdata
);
1056 result
= temp_append(&d_rrs
, name
, &rdata
);
1057 if (result
!= ISC_R_SUCCESS
)
1060 if (result
!= ISC_R_NOMORE
)
1062 result
= dns_diff_sort(&d_rrs
, temp_order
);
1063 if (result
!= ISC_R_SUCCESS
)
1067 * Collect all update RRs for this name and type
1068 * onto u_rrs. No need to sort them here -
1069 * they are already sorted.
1072 dns_name_equal(&t
->name
, name
) &&
1073 t
->rdata
.type
== type
)
1075 dns_difftuple_t
*next
=
1076 ISC_LIST_NEXT(t
, link
);
1077 ISC_LIST_UNLINK(temp
->tuples
, t
, link
);
1078 ISC_LIST_APPEND(u_rrs
.tuples
, t
, link
);
1082 /* Compare the two sorted lists. */
1083 result
= temp_check_rrset(ISC_LIST_HEAD(u_rrs
.tuples
),
1084 ISC_LIST_HEAD(d_rrs
.tuples
));
1085 if (result
!= ISC_R_SUCCESS
)
1089 * We are done with the tuples, but we can't free
1090 * them yet because "name" still points into one
1091 * of them. Move them on a temporary list.
1093 ISC_LIST_APPENDLIST(trash
.tuples
, u_rrs
.tuples
, link
);
1094 ISC_LIST_APPENDLIST(trash
.tuples
, d_rrs
.tuples
, link
);
1095 dns_rdataset_disassociate(&rdataset
);
1100 dns_diff_clear(&d_rrs
);
1101 dns_diff_clear(&u_rrs
);
1102 dns_diff_clear(&trash
);
1103 dns_rdataset_disassociate(&rdataset
);
1104 dns_db_detachnode(db
, &node
);
1108 dns_db_detachnode(db
, &node
);
1111 dns_diff_clear(&trash
);
1112 return (ISC_R_SUCCESS
);
1115 /**************************************************************************/
1117 * Conditional deletion of RRs.
1121 * Context structure for delete_if().
1125 rr_predicate
*predicate
;
1127 dns_dbversion_t
*ver
;
1130 dns_rdata_t
*update_rr
;
1131 } conditional_delete_ctx_t
;
1134 * Predicate functions for delete_if().
1138 * Return true iff 'db_rr' is neither a SOA nor an NS RR nor
1139 * an RRSIG nor an NSEC3PARAM nor a NSEC.
1141 static isc_boolean_t
1142 type_not_soa_nor_ns_p(dns_rdata_t
*update_rr
, dns_rdata_t
*db_rr
) {
1144 return ((db_rr
->type
!= dns_rdatatype_soa
&&
1145 db_rr
->type
!= dns_rdatatype_ns
&&
1146 db_rr
->type
!= dns_rdatatype_nsec3param
&&
1147 db_rr
->type
!= dns_rdatatype_rrsig
&&
1148 db_rr
->type
!= dns_rdatatype_nsec
) ?
1149 ISC_TRUE
: ISC_FALSE
);
1153 * Return true iff 'db_rr' is neither a RRSIG nor a NSEC.
1155 static isc_boolean_t
1156 type_not_dnssec(dns_rdata_t
*update_rr
, dns_rdata_t
*db_rr
) {
1158 return ((db_rr
->type
!= dns_rdatatype_rrsig
&&
1159 db_rr
->type
!= dns_rdatatype_nsec
) ?
1160 ISC_TRUE
: ISC_FALSE
);
1164 * Return true always.
1166 static isc_boolean_t
1167 true_p(dns_rdata_t
*update_rr
, dns_rdata_t
*db_rr
) {
1174 * Return true if the record is a RRSIG.
1176 static isc_boolean_t
1177 rrsig_p(dns_rdata_t
*update_rr
, dns_rdata_t
*db_rr
) {
1179 return ((db_rr
->type
== dns_rdatatype_rrsig
) ?
1180 ISC_TRUE
: ISC_FALSE
);
1184 * Return true iff the two RRs have identical rdata.
1186 static isc_boolean_t
1187 rr_equal_p(dns_rdata_t
*update_rr
, dns_rdata_t
*db_rr
) {
1189 * XXXRTH This is not a problem, but we should consider creating
1190 * dns_rdata_equal() (that used dns_name_equal()), since it
1191 * would be faster. Not a priority.
1193 return (dns_rdata_casecompare(update_rr
, db_rr
) == 0 ?
1194 ISC_TRUE
: ISC_FALSE
);
1198 * Return true iff 'update_rr' should replace 'db_rr' according
1199 * to the special RFC2136 rules for CNAME, SOA, and WKS records.
1201 * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
1202 * make little sense, so we replace those, too.
1204 * Additionally replace RRSIG that have been generated by the same key
1205 * for the same type. This simplifies refreshing a offline KSK by not
1206 * requiring that the old RRSIG be deleted. It also simplifies key
1207 * rollover by only requiring that the new RRSIG be added.
1209 static isc_boolean_t
1210 replaces_p(dns_rdata_t
*update_rr
, dns_rdata_t
*db_rr
) {
1211 dns_rdata_rrsig_t updatesig
, dbsig
;
1212 isc_result_t result
;
1214 if (db_rr
->type
!= update_rr
->type
)
1216 if (db_rr
->type
== dns_rdatatype_cname
)
1218 if (db_rr
->type
== dns_rdatatype_dname
)
1220 if (db_rr
->type
== dns_rdatatype_soa
)
1222 if (db_rr
->type
== dns_rdatatype_nsec
)
1224 if (db_rr
->type
== dns_rdatatype_rrsig
) {
1226 * Replace existing RRSIG with the same keyid,
1227 * covered and algorithm.
1229 result
= dns_rdata_tostruct(db_rr
, &dbsig
, NULL
);
1230 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1231 result
= dns_rdata_tostruct(update_rr
, &updatesig
, NULL
);
1232 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
1233 if (dbsig
.keyid
== updatesig
.keyid
&&
1234 dbsig
.covered
== updatesig
.covered
&&
1235 dbsig
.algorithm
== updatesig
.algorithm
)
1238 if (db_rr
->type
== dns_rdatatype_wks
) {
1240 * Compare the address and protocol fields only. These
1241 * form the first five bytes of the RR data. Do a
1242 * raw binary comparison; unpacking the WKS RRs using
1243 * dns_rdata_tostruct() might be cleaner in some ways.
1245 INSIST(db_rr
->length
>= 5 && update_rr
->length
>= 5);
1246 return (memcmp(db_rr
->data
, update_rr
->data
, 5) == 0 ?
1247 ISC_TRUE
: ISC_FALSE
);
1250 if (db_rr
->type
== dns_rdatatype_nsec3param
) {
1251 if (db_rr
->length
!= update_rr
->length
)
1253 INSIST(db_rr
->length
>= 4 && update_rr
->length
>= 4);
1255 * Replace records added in this UPDATE request.
1257 if (db_rr
->data
[0] == update_rr
->data
[0] &&
1258 (db_rr
->data
[1] & DNS_NSEC3FLAG_UPDATE
) != 0 &&
1259 (update_rr
->data
[1] & DNS_NSEC3FLAG_UPDATE
) != 0 &&
1260 memcmp(db_rr
->data
+2, update_rr
->data
+2,
1261 update_rr
->length
- 2) == 0)
1268 * Internal helper function for delete_if().
1271 delete_if_action(void *data
, rr_t
*rr
) {
1272 conditional_delete_ctx_t
*ctx
= data
;
1273 if ((*ctx
->predicate
)(ctx
->update_rr
, &rr
->rdata
)) {
1274 isc_result_t result
;
1275 result
= update_one_rr(ctx
->db
, ctx
->ver
, ctx
->diff
,
1276 DNS_DIFFOP_DEL
, ctx
->name
,
1277 rr
->ttl
, &rr
->rdata
);
1280 return (ISC_R_SUCCESS
);
1285 * Conditionally delete RRs. Apply 'predicate' to the RRs
1286 * specified by 'db', 'ver', 'name', and 'type' (which can
1287 * be dns_rdatatype_any to match any type). Delete those
1288 * RRs for which the predicate returns true, and log the
1289 * deletions in 'diff'.
1292 delete_if(rr_predicate
*predicate
, dns_db_t
*db
, dns_dbversion_t
*ver
,
1293 dns_name_t
*name
, dns_rdatatype_t type
, dns_rdatatype_t covers
,
1294 dns_rdata_t
*update_rr
, dns_diff_t
*diff
)
1296 conditional_delete_ctx_t ctx
;
1297 ctx
.predicate
= predicate
;
1302 ctx
.update_rr
= update_rr
;
1303 return (foreach_rr(db
, ver
, name
, type
, covers
,
1304 delete_if_action
, &ctx
));
1307 /**************************************************************************/
1309 * Prepare an RR for the addition of the new RR 'ctx->update_rr',
1310 * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting
1311 * the RRs if it is replaced by the new RR or has a conflicting TTL.
1312 * The necessary changes are appended to ctx->del_diff and ctx->add_diff;
1313 * we need to do all deletions before any additions so that we don't run
1314 * into transient states with conflicting TTLs.
1319 dns_dbversion_t
*ver
;
1322 dns_rdata_t
*update_rr
;
1323 dns_ttl_t update_rr_ttl
;
1324 isc_boolean_t ignore_add
;
1325 dns_diff_t del_diff
;
1326 dns_diff_t add_diff
;
1327 } add_rr_prepare_ctx_t
;
1330 add_rr_prepare_action(void *data
, rr_t
*rr
) {
1331 isc_result_t result
= ISC_R_SUCCESS
;
1332 add_rr_prepare_ctx_t
*ctx
= data
;
1333 dns_difftuple_t
*tuple
= NULL
;
1334 isc_boolean_t equal
;
1337 * If the update RR is a "duplicate" of the update RR,
1338 * the update should be silently ignored.
1340 equal
= ISC_TF(dns_rdata_casecompare(&rr
->rdata
, ctx
->update_rr
) == 0);
1341 if (equal
&& rr
->ttl
== ctx
->update_rr_ttl
) {
1342 ctx
->ignore_add
= ISC_TRUE
;
1343 return (ISC_R_SUCCESS
);
1347 * If this RR is "equal" to the update RR, it should
1348 * be deleted before the update RR is added.
1350 if (replaces_p(ctx
->update_rr
, &rr
->rdata
)) {
1351 CHECK(dns_difftuple_create(ctx
->del_diff
.mctx
, DNS_DIFFOP_DEL
,
1352 ctx
->name
, rr
->ttl
, &rr
->rdata
,
1354 dns_diff_append(&ctx
->del_diff
, &tuple
);
1355 return (ISC_R_SUCCESS
);
1359 * If this RR differs in TTL from the update RR,
1360 * its TTL must be adjusted.
1362 if (rr
->ttl
!= ctx
->update_rr_ttl
) {
1363 CHECK(dns_difftuple_create(ctx
->del_diff
.mctx
, DNS_DIFFOP_DEL
,
1364 ctx
->name
, rr
->ttl
, &rr
->rdata
,
1366 dns_diff_append(&ctx
->del_diff
, &tuple
);
1368 CHECK(dns_difftuple_create(ctx
->add_diff
.mctx
,
1369 DNS_DIFFOP_ADD
, ctx
->name
,
1371 &rr
->rdata
, &tuple
));
1372 dns_diff_append(&ctx
->add_diff
, &tuple
);
1379 /**************************************************************************/
1381 * Miscellaneous subroutines.
1385 * Extract a single update RR from 'section' of dynamic update message
1386 * 'msg', with consistency checking.
1388 * Stores the owner name, rdata, and TTL of the update RR at 'name',
1389 * 'rdata', and 'ttl', respectively.
1392 get_current_rr(dns_message_t
*msg
, dns_section_t section
,
1393 dns_rdataclass_t zoneclass
, dns_name_t
**name
,
1394 dns_rdata_t
*rdata
, dns_rdatatype_t
*covers
,
1395 dns_ttl_t
*ttl
, dns_rdataclass_t
*update_class
)
1397 dns_rdataset_t
*rdataset
;
1398 isc_result_t result
;
1399 dns_message_currentname(msg
, section
, name
);
1400 rdataset
= ISC_LIST_HEAD((*name
)->list
);
1401 INSIST(rdataset
!= NULL
);
1402 INSIST(ISC_LIST_NEXT(rdataset
, link
) == NULL
);
1403 *covers
= rdataset
->covers
;
1404 *ttl
= rdataset
->ttl
;
1405 result
= dns_rdataset_first(rdataset
);
1406 INSIST(result
== ISC_R_SUCCESS
);
1407 dns_rdataset_current(rdataset
, rdata
);
1408 INSIST(dns_rdataset_next(rdataset
) == ISC_R_NOMORE
);
1409 *update_class
= rdata
->rdclass
;
1410 rdata
->rdclass
= zoneclass
;
1414 * Increment the SOA serial number of database 'db', version 'ver'.
1415 * Replace the SOA record in the database, and log the
1420 * XXXRTH Failures in this routine will be worth logging, when
1421 * we have a logging system. Failure to find the zonename
1422 * or the SOA rdataset warrant at least an UNEXPECTED_ERROR().
1426 increment_soa_serial(dns_db_t
*db
, dns_dbversion_t
*ver
,
1427 dns_diff_t
*diff
, isc_mem_t
*mctx
)
1429 dns_difftuple_t
*deltuple
= NULL
;
1430 dns_difftuple_t
*addtuple
= NULL
;
1431 isc_uint32_t serial
;
1432 isc_result_t result
;
1434 CHECK(dns_db_createsoatuple(db
, ver
, mctx
, DNS_DIFFOP_DEL
, &deltuple
));
1435 CHECK(dns_difftuple_copy(deltuple
, &addtuple
));
1436 addtuple
->op
= DNS_DIFFOP_ADD
;
1438 serial
= dns_soa_getserial(&addtuple
->rdata
);
1441 serial
= (serial
+ 1) & 0xFFFFFFFF;
1445 dns_soa_setserial(serial
, &addtuple
->rdata
);
1446 CHECK(do_one_tuple(&deltuple
, db
, ver
, diff
));
1447 CHECK(do_one_tuple(&addtuple
, db
, ver
, diff
));
1448 result
= ISC_R_SUCCESS
;
1451 if (addtuple
!= NULL
)
1452 dns_difftuple_free(&addtuple
);
1453 if (deltuple
!= NULL
)
1454 dns_difftuple_free(&deltuple
);
1459 * Check that the new SOA record at 'update_rdata' does not
1460 * illegally cause the SOA serial number to decrease or stay
1461 * unchanged relative to the existing SOA in 'db'.
1463 * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not.
1465 * William King points out that RFC2136 is inconsistent about
1466 * the case where the serial number stays unchanged:
1468 * section 3.4.2.2 requires a server to ignore a SOA update request
1469 * if the serial number on the update SOA is less_than_or_equal to
1470 * the zone SOA serial.
1472 * section 3.6 requires a server to ignore a SOA update request if
1473 * the serial is less_than the zone SOA serial.
1475 * Paul says 3.4.2.2 is correct.
1479 check_soa_increment(dns_db_t
*db
, dns_dbversion_t
*ver
,
1480 dns_rdata_t
*update_rdata
, isc_boolean_t
*ok
)
1482 isc_uint32_t db_serial
;
1483 isc_uint32_t update_serial
;
1484 isc_result_t result
;
1486 update_serial
= dns_soa_getserial(update_rdata
);
1488 result
= dns_db_getsoaserial(db
, ver
, &db_serial
);
1489 if (result
!= ISC_R_SUCCESS
)
1492 if (DNS_SERIAL_GE(db_serial
, update_serial
)) {
1498 return (ISC_R_SUCCESS
);
1502 /**************************************************************************/
1504 * Incremental updating of NSECs and RRSIGs.
1507 #define MAXZONEKEYS 32 /*%< Maximum number of zone keys supported. */
1510 * We abuse the dns_diff_t type to represent a set of domain names
1511 * affected by the update.
1514 namelist_append_name(dns_diff_t
*list
, dns_name_t
*name
) {
1515 isc_result_t result
;
1516 dns_difftuple_t
*tuple
= NULL
;
1517 static dns_rdata_t dummy_rdata
= DNS_RDATA_INIT
;
1519 CHECK(dns_difftuple_create(list
->mctx
, DNS_DIFFOP_EXISTS
, name
, 0,
1520 &dummy_rdata
, &tuple
));
1521 dns_diff_append(list
, &tuple
);
1527 namelist_append_subdomain(dns_db_t
*db
, dns_name_t
*name
, dns_diff_t
*affected
)
1529 isc_result_t result
;
1530 dns_fixedname_t fixedname
;
1532 dns_dbiterator_t
*dbit
= NULL
;
1534 dns_fixedname_init(&fixedname
);
1535 child
= dns_fixedname_name(&fixedname
);
1537 CHECK(dns_db_createiterator(db
, DNS_DB_NONSEC3
, &dbit
));
1539 for (result
= dns_dbiterator_seek(dbit
, name
);
1540 result
== ISC_R_SUCCESS
;
1541 result
= dns_dbiterator_next(dbit
))
1543 dns_dbnode_t
*node
= NULL
;
1544 CHECK(dns_dbiterator_current(dbit
, &node
, child
));
1545 dns_db_detachnode(db
, &node
);
1546 if (! dns_name_issubdomain(child
, name
))
1548 CHECK(namelist_append_name(affected
, child
));
1550 if (result
== ISC_R_NOMORE
)
1551 result
= ISC_R_SUCCESS
;
1554 dns_dbiterator_destroy(&dbit
);
1561 * Helper function for non_nsec_rrset_exists().
1564 is_non_nsec_action(void *data
, dns_rdataset_t
*rrset
) {
1566 if (!(rrset
->type
== dns_rdatatype_nsec
||
1567 rrset
->type
== dns_rdatatype_nsec3
||
1568 (rrset
->type
== dns_rdatatype_rrsig
&&
1569 (rrset
->covers
== dns_rdatatype_nsec
||
1570 rrset
->covers
== dns_rdatatype_nsec3
))))
1571 return (ISC_R_EXISTS
);
1572 return (ISC_R_SUCCESS
);
1576 * Check whether there is an rrset other than a NSEC or RRSIG NSEC,
1577 * i.e., anything that justifies the continued existence of a name
1578 * after a secure update.
1580 * If such an rrset exists, set '*exists' to ISC_TRUE.
1581 * Otherwise, set it to ISC_FALSE.
1584 non_nsec_rrset_exists(dns_db_t
*db
, dns_dbversion_t
*ver
,
1585 dns_name_t
*name
, isc_boolean_t
*exists
)
1587 isc_result_t result
;
1588 result
= foreach_rrset(db
, ver
, name
, is_non_nsec_action
, NULL
);
1589 RETURN_EXISTENCE_FLAG
;
1593 * A comparison function for sorting dns_diff_t:s by name.
1596 name_order(const void *av
, const void *bv
) {
1597 dns_difftuple_t
const * const *ap
= av
;
1598 dns_difftuple_t
const * const *bp
= bv
;
1599 dns_difftuple_t
const *a
= *ap
;
1600 dns_difftuple_t
const *b
= *bp
;
1601 return (dns_name_compare(&a
->name
, &b
->name
));
1605 uniqify_name_list(dns_diff_t
*list
) {
1606 isc_result_t result
;
1607 dns_difftuple_t
*p
, *q
;
1609 CHECK(dns_diff_sort(list
, name_order
));
1611 p
= ISC_LIST_HEAD(list
->tuples
);
1614 q
= ISC_LIST_NEXT(p
, link
);
1615 if (q
== NULL
|| ! dns_name_equal(&p
->name
, &q
->name
))
1617 ISC_LIST_UNLINK(list
->tuples
, q
, link
);
1618 dns_difftuple_free(&q
);
1620 p
= ISC_LIST_NEXT(p
, link
);
1627 is_active(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
1628 isc_boolean_t
*flag
, isc_boolean_t
*cut
, isc_boolean_t
*unsecure
)
1630 isc_result_t result
;
1631 dns_fixedname_t foundname
;
1632 dns_fixedname_init(&foundname
);
1633 result
= dns_db_find(db
, name
, ver
, dns_rdatatype_any
,
1634 DNS_DBFIND_GLUEOK
| DNS_DBFIND_NOWILD
,
1635 (isc_stdtime_t
) 0, NULL
,
1636 dns_fixedname_name(&foundname
),
1638 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_EMPTYNAME
) {
1641 if (unsecure
!= NULL
)
1642 *unsecure
= ISC_FALSE
;
1643 return (ISC_R_SUCCESS
);
1644 } else if (result
== DNS_R_ZONECUT
) {
1647 if (unsecure
!= NULL
) {
1649 * We are at the zonecut. Check to see if there
1652 if (dns_db_find(db
, name
, ver
, dns_rdatatype_ds
, 0,
1653 (isc_stdtime_t
) 0, NULL
,
1654 dns_fixedname_name(&foundname
),
1655 NULL
, NULL
) == DNS_R_NXRRSET
)
1656 *unsecure
= ISC_TRUE
;
1658 *unsecure
= ISC_FALSE
;
1660 return (ISC_R_SUCCESS
);
1661 } else if (result
== DNS_R_GLUE
|| result
== DNS_R_DNAME
||
1662 result
== DNS_R_DELEGATION
|| result
== DNS_R_NXDOMAIN
) {
1665 if (unsecure
!= NULL
)
1666 *unsecure
= ISC_FALSE
;
1667 return (ISC_R_SUCCESS
);
1674 if (unsecure
!= NULL
)
1675 *unsecure
= ISC_FALSE
;
1681 * Find the next/previous name that has a NSEC record.
1682 * In other words, skip empty database nodes and names that
1683 * have had their NSECs removed because they are obscured by
1687 next_active(ns_client_t
*client
, dns_zone_t
*zone
, dns_db_t
*db
,
1688 dns_dbversion_t
*ver
, dns_name_t
*oldname
, dns_name_t
*newname
,
1689 isc_boolean_t forward
)
1691 isc_result_t result
;
1692 dns_dbiterator_t
*dbit
= NULL
;
1693 isc_boolean_t has_nsec
;
1694 unsigned int wraps
= 0;
1695 isc_boolean_t secure
= dns_db_issecure(db
);
1697 CHECK(dns_db_createiterator(db
, 0, &dbit
));
1699 CHECK(dns_dbiterator_seek(dbit
, oldname
));
1701 dns_dbnode_t
*node
= NULL
;
1704 result
= dns_dbiterator_next(dbit
);
1706 result
= dns_dbiterator_prev(dbit
);
1707 if (result
== ISC_R_NOMORE
) {
1712 CHECK(dns_dbiterator_first(dbit
));
1714 CHECK(dns_dbiterator_last(dbit
));
1717 update_log(client
, zone
, ISC_LOG_ERROR
,
1718 "secure zone with no NSECs");
1719 result
= DNS_R_BADZONE
;
1723 CHECK(dns_dbiterator_current(dbit
, &node
, newname
));
1724 dns_db_detachnode(db
, &node
);
1727 * The iterator may hold the tree lock, and
1728 * rrset_exists() calls dns_db_findnode() which
1729 * may try to reacquire it. To avoid deadlock
1730 * we must pause the iterator first.
1732 CHECK(dns_dbiterator_pause(dbit
));
1734 CHECK(rrset_exists(db
, ver
, newname
,
1735 dns_rdatatype_nsec
, 0, &has_nsec
));
1737 dns_fixedname_t ffound
;
1739 dns_fixedname_init(&ffound
);
1740 found
= dns_fixedname_name(&ffound
);
1741 result
= dns_db_find(db
, newname
, ver
,
1743 DNS_DBFIND_NOWILD
, 0, NULL
, found
,
1745 if (result
== ISC_R_SUCCESS
||
1746 result
== DNS_R_EMPTYNAME
||
1747 result
== DNS_R_NXRRSET
||
1748 result
== DNS_R_CNAME
||
1749 (result
== DNS_R_DELEGATION
&&
1750 dns_name_equal(newname
, found
))) {
1751 has_nsec
= ISC_TRUE
;
1752 result
= ISC_R_SUCCESS
;
1753 } else if (result
!= DNS_R_NXDOMAIN
)
1756 } while (! has_nsec
);
1759 dns_dbiterator_destroy(&dbit
);
1765 * Add a NSEC record for "name", recording the change in "diff".
1766 * The existing NSEC is removed.
1769 add_nsec(ns_client_t
*client
, dns_zone_t
*zone
, dns_db_t
*db
,
1770 dns_dbversion_t
*ver
, dns_name_t
*name
, dns_ttl_t nsecttl
,
1773 isc_result_t result
;
1774 dns_dbnode_t
*node
= NULL
;
1775 unsigned char buffer
[DNS_NSEC_BUFFERSIZE
];
1776 dns_rdata_t rdata
= DNS_RDATA_INIT
;
1777 dns_difftuple_t
*tuple
= NULL
;
1778 dns_fixedname_t fixedname
;
1781 dns_fixedname_init(&fixedname
);
1782 target
= dns_fixedname_name(&fixedname
);
1785 * Find the successor name, aka NSEC target.
1787 CHECK(next_active(client
, zone
, db
, ver
, name
, target
, ISC_TRUE
));
1790 * Create the NSEC RDATA.
1792 CHECK(dns_db_findnode(db
, name
, ISC_FALSE
, &node
));
1793 dns_rdata_init(&rdata
);
1794 CHECK(dns_nsec_buildrdata(db
, ver
, node
, target
, buffer
, &rdata
));
1795 dns_db_detachnode(db
, &node
);
1798 * Delete the old NSEC and record the change.
1800 CHECK(delete_if(true_p
, db
, ver
, name
, dns_rdatatype_nsec
, 0,
1803 * Add the new NSEC and record the change.
1805 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_ADD
, name
,
1806 nsecttl
, &rdata
, &tuple
));
1807 CHECK(do_one_tuple(&tuple
, db
, ver
, diff
));
1808 INSIST(tuple
== NULL
);
1812 dns_db_detachnode(db
, &node
);
1817 * Add a placeholder NSEC record for "name", recording the change in "diff".
1820 add_placeholder_nsec(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
1823 isc_result_t result
;
1824 dns_difftuple_t
*tuple
= NULL
;
1826 unsigned char data
[1] = { 0 }; /* The root domain, no bits. */
1827 dns_rdata_t rdata
= DNS_RDATA_INIT
;
1830 r
.length
= sizeof(data
);
1831 dns_rdata_fromregion(&rdata
, dns_db_class(db
), dns_rdatatype_nsec
, &r
);
1832 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_ADD
, name
, 0,
1834 CHECK(do_one_tuple(&tuple
, db
, ver
, diff
));
1840 find_zone_keys(dns_zone_t
*zone
, dns_db_t
*db
, dns_dbversion_t
*ver
,
1841 isc_mem_t
*mctx
, unsigned int maxkeys
,
1842 dst_key_t
**keys
, unsigned int *nkeys
)
1844 isc_result_t result
;
1845 dns_dbnode_t
*node
= NULL
;
1846 const char *directory
= dns_zone_getkeydirectory(zone
);
1847 CHECK(dns_db_findnode(db
, dns_db_origin(db
), ISC_FALSE
, &node
));
1848 CHECK(dns_dnssec_findzonekeys2(db
, ver
, node
, dns_db_origin(db
),
1849 directory
, mctx
, maxkeys
, keys
, nkeys
));
1852 dns_db_detachnode(db
, &node
);
1857 * Add RRSIG records for an RRset, recording the change in "diff".
1860 add_sigs(ns_client_t
*client
, dns_zone_t
*zone
, dns_db_t
*db
,
1861 dns_dbversion_t
*ver
, dns_name_t
*name
, dns_rdatatype_t type
,
1862 dns_diff_t
*diff
, dst_key_t
**keys
, unsigned int nkeys
,
1863 isc_stdtime_t inception
, isc_stdtime_t expire
,
1864 isc_boolean_t check_ksk
, isc_boolean_t keyset_kskonly
)
1866 isc_result_t result
;
1867 dns_dbnode_t
*node
= NULL
;
1868 dns_rdataset_t rdataset
;
1869 dns_rdata_t sig_rdata
= DNS_RDATA_INIT
;
1870 isc_buffer_t buffer
;
1871 unsigned char data
[1024]; /* XXX */
1873 isc_boolean_t added_sig
= ISC_FALSE
;
1874 isc_mem_t
*mctx
= client
->mctx
;
1876 dns_rdataset_init(&rdataset
);
1877 isc_buffer_init(&buffer
, data
, sizeof(data
));
1879 /* Get the rdataset to sign. */
1880 if (type
== dns_rdatatype_nsec3
)
1881 CHECK(dns_db_findnsec3node(db
, name
, ISC_FALSE
, &node
));
1883 CHECK(dns_db_findnode(db
, name
, ISC_FALSE
, &node
));
1884 CHECK(dns_db_findrdataset(db
, node
, ver
, type
, 0,
1885 (isc_stdtime_t
) 0, &rdataset
, NULL
));
1886 dns_db_detachnode(db
, &node
);
1888 #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
1889 #define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
1890 #define ALG(x) dst_key_alg(x)
1893 * If we are honoring KSK flags then we need to check that we
1894 * have both KSK and non-KSK keys that are not revoked per
1897 for (i
= 0; i
< nkeys
; i
++) {
1898 isc_boolean_t both
= ISC_FALSE
;
1900 if (!dst_key_isprivate(keys
[i
]))
1903 if (check_ksk
&& !REVOKE(keys
[i
])) {
1904 isc_boolean_t have_ksk
, have_nonksk
;
1906 have_ksk
= ISC_TRUE
;
1907 have_nonksk
= ISC_FALSE
;
1909 have_ksk
= ISC_FALSE
;
1910 have_nonksk
= ISC_TRUE
;
1912 for (j
= 0; j
< nkeys
; j
++) {
1913 if (j
== i
|| ALG(keys
[i
]) != ALG(keys
[j
]))
1915 if (REVOKE(keys
[j
]))
1918 have_ksk
= ISC_TRUE
;
1920 have_nonksk
= ISC_TRUE
;
1921 both
= have_ksk
&& have_nonksk
;
1928 if (type
== dns_rdatatype_dnskey
) {
1929 if (!KSK(keys
[i
]) && keyset_kskonly
)
1931 } else if (KSK(keys
[i
]))
1933 } else if (REVOKE(keys
[i
]) && type
!= dns_rdatatype_dnskey
)
1936 /* Calculate the signature, creating a RRSIG RDATA. */
1937 CHECK(dns_dnssec_sign(name
, &rdataset
, keys
[i
],
1938 &inception
, &expire
,
1939 mctx
, &buffer
, &sig_rdata
));
1941 /* Update the database and journal with the RRSIG. */
1942 /* XXX inefficient - will cause dataset merging */
1943 CHECK(update_one_rr(db
, ver
, diff
, DNS_DIFFOP_ADDRESIGN
, name
,
1944 rdataset
.ttl
, &sig_rdata
));
1945 dns_rdata_reset(&sig_rdata
);
1946 added_sig
= ISC_TRUE
;
1949 update_log(client
, zone
, ISC_LOG_ERROR
,
1950 "found no active private keys, "
1951 "unable to generate any signatures");
1952 result
= ISC_R_NOTFOUND
;
1956 if (dns_rdataset_isassociated(&rdataset
))
1957 dns_rdataset_disassociate(&rdataset
);
1959 dns_db_detachnode(db
, &node
);
1964 * Delete expired RRsigs and any RRsigs we are about to re-sign.
1965 * See also zone.c:del_sigs().
1968 del_keysigs(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
1969 dns_diff_t
*diff
, dst_key_t
**keys
, unsigned int nkeys
)
1971 isc_result_t result
;
1972 dns_dbnode_t
*node
= NULL
;
1973 dns_rdataset_t rdataset
;
1974 dns_rdata_t rdata
= DNS_RDATA_INIT
;
1976 dns_rdata_rrsig_t rrsig
;
1977 isc_boolean_t found
;
1979 dns_rdataset_init(&rdataset
);
1981 result
= dns_db_findnode(db
, name
, ISC_FALSE
, &node
);
1982 if (result
== ISC_R_NOTFOUND
)
1983 return (ISC_R_SUCCESS
);
1984 if (result
!= ISC_R_SUCCESS
)
1986 result
= dns_db_findrdataset(db
, node
, ver
, dns_rdatatype_rrsig
,
1987 dns_rdatatype_dnskey
, (isc_stdtime_t
) 0,
1989 dns_db_detachnode(db
, &node
);
1991 if (result
== ISC_R_NOTFOUND
)
1992 return (ISC_R_SUCCESS
);
1993 if (result
!= ISC_R_SUCCESS
)
1996 for (result
= dns_rdataset_first(&rdataset
);
1997 result
== ISC_R_SUCCESS
;
1998 result
= dns_rdataset_next(&rdataset
)) {
1999 dns_rdataset_current(&rdataset
, &rdata
);
2000 result
= dns_rdata_tostruct(&rdata
, &rrsig
, NULL
);
2001 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
2003 for (i
= 0; i
< nkeys
; i
++) {
2004 if (rrsig
.keyid
== dst_key_id(keys
[i
])) {
2006 if (!dst_key_isprivate(keys
[i
])) {
2008 * The re-signing code in zone.c
2009 * will mark this as offline.
2010 * Just skip the record for now.
2014 result
= update_one_rr(db
, ver
, diff
,
2015 DNS_DIFFOP_DEL
, name
,
2016 rdataset
.ttl
, &rdata
);
2021 * If there is not a matching DNSKEY then delete the RRSIG.
2024 result
= update_one_rr(db
, ver
, diff
, DNS_DIFFOP_DEL
,
2025 name
, rdataset
.ttl
, &rdata
);
2026 dns_rdata_reset(&rdata
);
2027 if (result
!= ISC_R_SUCCESS
)
2030 dns_rdataset_disassociate(&rdataset
);
2031 if (result
== ISC_R_NOMORE
)
2032 result
= ISC_R_SUCCESS
;
2035 dns_db_detachnode(db
, &node
);
2040 add_exposed_sigs(ns_client_t
*client
, dns_zone_t
*zone
, dns_db_t
*db
,
2041 dns_dbversion_t
*ver
, dns_name_t
*name
, isc_boolean_t cut
,
2042 dns_diff_t
*diff
, dst_key_t
**keys
, unsigned int nkeys
,
2043 isc_stdtime_t inception
, isc_stdtime_t expire
,
2044 isc_boolean_t check_ksk
, isc_boolean_t keyset_kskonly
)
2046 isc_result_t result
;
2048 dns_rdatasetiter_t
*iter
;
2051 result
= dns_db_findnode(db
, name
, ISC_FALSE
, &node
);
2052 if (result
== ISC_R_NOTFOUND
)
2053 return (ISC_R_SUCCESS
);
2054 if (result
!= ISC_R_SUCCESS
)
2058 result
= dns_db_allrdatasets(db
, node
, ver
,
2059 (isc_stdtime_t
) 0, &iter
);
2060 if (result
!= ISC_R_SUCCESS
)
2063 for (result
= dns_rdatasetiter_first(iter
);
2064 result
== ISC_R_SUCCESS
;
2065 result
= dns_rdatasetiter_next(iter
))
2067 dns_rdataset_t rdataset
;
2068 dns_rdatatype_t type
;
2071 dns_rdataset_init(&rdataset
);
2072 dns_rdatasetiter_current(iter
, &rdataset
);
2073 type
= rdataset
.type
;
2074 dns_rdataset_disassociate(&rdataset
);
2077 * We don't need to sign unsigned NSEC records at the cut
2078 * as they are handled elsewhere.
2080 if ((type
== dns_rdatatype_rrsig
) ||
2081 (cut
&& type
!= dns_rdatatype_ds
))
2083 result
= rrset_exists(db
, ver
, name
, dns_rdatatype_rrsig
,
2085 if (result
!= ISC_R_SUCCESS
)
2086 goto cleanup_iterator
;
2089 result
= add_sigs(client
, zone
, db
, ver
, name
, type
, diff
,
2090 keys
, nkeys
, inception
, expire
,
2091 check_ksk
, keyset_kskonly
);
2092 if (result
!= ISC_R_SUCCESS
)
2093 goto cleanup_iterator
;
2095 if (result
== ISC_R_NOMORE
)
2096 result
= ISC_R_SUCCESS
;
2099 dns_rdatasetiter_destroy(&iter
);
2102 dns_db_detachnode(db
, &node
);
2108 * Update RRSIG, NSEC and NSEC3 records affected by an update. The original
2109 * update, including the SOA serial update but excluding the RRSIG & NSEC
2110 * changes, is in "diff" and has already been applied to "newver" of "db".
2111 * The database version prior to the update is "oldver".
2113 * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
2114 * and added (as a minimal diff) to "diff".
2116 * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
2119 update_signatures(ns_client_t
*client
, dns_zone_t
*zone
, dns_db_t
*db
,
2120 dns_dbversion_t
*oldver
, dns_dbversion_t
*newver
,
2121 dns_diff_t
*diff
, isc_uint32_t sigvalidityinterval
)
2123 isc_result_t result
;
2125 dns_diff_t diffnames
;
2126 dns_diff_t affected
;
2127 dns_diff_t sig_diff
;
2128 dns_diff_t nsec_diff
;
2129 dns_diff_t nsec_mindiff
;
2130 isc_boolean_t flag
, build_nsec
, build_nsec3
;
2131 dst_key_t
*zone_keys
[MAXZONEKEYS
];
2132 unsigned int nkeys
= 0;
2134 isc_stdtime_t now
, inception
, expire
;
2136 dns_rdata_soa_t soa
;
2137 dns_rdata_t rdata
= DNS_RDATA_INIT
;
2138 dns_rdataset_t rdataset
;
2139 dns_dbnode_t
*node
= NULL
;
2140 isc_boolean_t check_ksk
, keyset_kskonly
;
2141 isc_boolean_t unsecure
;
2143 dns_rdatatype_t privatetype
= dns_zone_getprivatetype(zone
);
2145 dns_diff_init(client
->mctx
, &diffnames
);
2146 dns_diff_init(client
->mctx
, &affected
);
2148 dns_diff_init(client
->mctx
, &sig_diff
);
2149 sig_diff
.resign
= dns_zone_getsigresigninginterval(zone
);
2150 dns_diff_init(client
->mctx
, &nsec_diff
);
2151 dns_diff_init(client
->mctx
, &nsec_mindiff
);
2153 result
= find_zone_keys(zone
, db
, newver
, client
->mctx
,
2154 MAXZONEKEYS
, zone_keys
, &nkeys
);
2155 if (result
!= ISC_R_SUCCESS
) {
2156 update_log(client
, zone
, ISC_LOG_ERROR
,
2157 "could not get zone keys for secure dynamic update");
2161 isc_stdtime_get(&now
);
2162 inception
= now
- 3600; /* Allow for some clock skew. */
2163 expire
= now
+ sigvalidityinterval
;
2166 * Do we look at the KSK flag on the DNSKEY to determining which
2167 * keys sign which RRsets? First check the zone option then
2168 * check the keys flags to make sure at least one has a ksk set
2171 check_ksk
= ISC_TF((dns_zone_getoptions(zone
) &
2172 DNS_ZONEOPT_UPDATECHECKKSK
) != 0);
2173 keyset_kskonly
= ISC_TF((dns_zone_getoptions(zone
) &
2174 DNS_ZONEOPT_DNSKEYKSKONLY
) != 0);
2177 * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
2179 CHECK(dns_db_findnode(db
, dns_db_origin(db
), ISC_FALSE
, &node
));
2180 dns_rdataset_init(&rdataset
);
2181 CHECK(dns_db_findrdataset(db
, node
, newver
, dns_rdatatype_soa
, 0,
2182 (isc_stdtime_t
) 0, &rdataset
, NULL
));
2183 CHECK(dns_rdataset_first(&rdataset
));
2184 dns_rdataset_current(&rdataset
, &rdata
);
2185 CHECK(dns_rdata_tostruct(&rdata
, &soa
, NULL
));
2186 nsecttl
= soa
.minimum
;
2187 dns_rdataset_disassociate(&rdataset
);
2188 dns_db_detachnode(db
, &node
);
2191 * Find all RRsets directly affected by the update, and
2192 * update their RRSIGs. Also build a list of names affected
2193 * by the update in "diffnames".
2195 CHECK(dns_diff_sort(diff
, temp_order
));
2197 t
= ISC_LIST_HEAD(diff
->tuples
);
2199 dns_name_t
*name
= &t
->name
;
2200 /* Now "name" is a new, unique name affected by the update. */
2202 CHECK(namelist_append_name(&diffnames
, name
));
2204 while (t
!= NULL
&& dns_name_equal(&t
->name
, name
)) {
2205 dns_rdatatype_t type
;
2206 type
= t
->rdata
.type
;
2209 * Now "name" and "type" denote a new unique RRset
2210 * affected by the update.
2213 /* Don't sign RRSIGs. */
2214 if (type
== dns_rdatatype_rrsig
)
2218 * Delete all old RRSIGs covering this type, since they
2219 * are all invalid when the signed RRset has changed.
2220 * We may not be able to recreate all of them - tough.
2221 * Special case changes to the zone's DNSKEY records
2222 * to support offline KSKs.
2224 if (type
== dns_rdatatype_dnskey
)
2225 del_keysigs(db
, newver
, name
, &sig_diff
,
2228 CHECK(delete_if(true_p
, db
, newver
, name
,
2229 dns_rdatatype_rrsig
, type
,
2233 * If this RRset is still visible after the update,
2234 * add a new signature for it.
2236 CHECK(rrset_visible(db
, newver
, name
, type
, &flag
));
2238 CHECK(add_sigs(client
, zone
, db
, newver
, name
,
2239 type
, &sig_diff
, zone_keys
,
2240 nkeys
, inception
, expire
,
2241 check_ksk
, keyset_kskonly
));
2244 /* Skip any other updates to the same RRset. */
2246 dns_name_equal(&t
->name
, name
) &&
2247 t
->rdata
.type
== type
)
2249 t
= ISC_LIST_NEXT(t
, link
);
2253 update_log(client
, zone
, ISC_LOG_DEBUG(3), "updated data signatures");
2255 /* Remove orphaned NSECs and RRSIG NSECs. */
2256 for (t
= ISC_LIST_HEAD(diffnames
.tuples
);
2258 t
= ISC_LIST_NEXT(t
, link
))
2260 CHECK(non_nsec_rrset_exists(db
, newver
, &t
->name
, &flag
));
2262 CHECK(delete_if(true_p
, db
, newver
, &t
->name
,
2263 dns_rdatatype_any
, 0,
2267 update_log(client
, zone
, ISC_LOG_DEBUG(3),
2268 "removed any orphaned NSEC records");
2271 * See if we need to build NSEC or NSEC3 chains.
2273 CHECK(dns_private_chains(db
, newver
, privatetype
, &build_nsec
,
2278 update_log(client
, zone
, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
2281 * When a name is created or deleted, its predecessor needs to
2282 * have its NSEC updated.
2284 for (t
= ISC_LIST_HEAD(diffnames
.tuples
);
2286 t
= ISC_LIST_NEXT(t
, link
))
2288 isc_boolean_t existed
, exists
;
2289 dns_fixedname_t fixedname
;
2290 dns_name_t
*prevname
;
2292 dns_fixedname_init(&fixedname
);
2293 prevname
= dns_fixedname_name(&fixedname
);
2295 CHECK(name_exists(db
, oldver
, &t
->name
, &existed
));
2296 CHECK(name_exists(db
, newver
, &t
->name
, &exists
));
2297 if (exists
== existed
)
2301 * Find the predecessor.
2302 * When names become obscured or unobscured in this update
2303 * transaction, we may find the wrong predecessor because
2304 * the NSECs have not yet been updated to reflect the delegation
2305 * change. This should not matter because in this case,
2306 * the correct predecessor is either the delegation node or
2307 * a newly unobscured node, and those nodes are on the
2308 * "affected" list in any case.
2310 CHECK(next_active(client
, zone
, db
, newver
,
2311 &t
->name
, prevname
, ISC_FALSE
));
2312 CHECK(namelist_append_name(&affected
, prevname
));
2316 * Find names potentially affected by delegation changes
2317 * (obscured by adding an NS or DNAME, or unobscured by
2320 for (t
= ISC_LIST_HEAD(diffnames
.tuples
);
2322 t
= ISC_LIST_NEXT(t
, link
))
2324 isc_boolean_t ns_existed
, dname_existed
;
2325 isc_boolean_t ns_exists
, dname_exists
;
2327 CHECK(rrset_exists(db
, oldver
, &t
->name
, dns_rdatatype_ns
, 0,
2329 CHECK(rrset_exists(db
, oldver
, &t
->name
, dns_rdatatype_dname
, 0,
2331 CHECK(rrset_exists(db
, newver
, &t
->name
, dns_rdatatype_ns
, 0,
2333 CHECK(rrset_exists(db
, newver
, &t
->name
, dns_rdatatype_dname
, 0,
2335 if ((ns_exists
|| dname_exists
) == (ns_existed
|| dname_existed
))
2338 * There was a delegation change. Mark all subdomains
2339 * of t->name as potentially needing a NSEC update.
2341 CHECK(namelist_append_subdomain(db
, &t
->name
, &affected
));
2344 ISC_LIST_APPENDLIST(affected
.tuples
, diffnames
.tuples
, link
);
2345 INSIST(ISC_LIST_EMPTY(diffnames
.tuples
));
2347 CHECK(uniqify_name_list(&affected
));
2350 * Determine which names should have NSECs, and delete/create
2351 * NSECs to make it so. We don't know the final NSEC targets yet,
2352 * so we just create placeholder NSECs with arbitrary contents
2353 * to indicate that their respective owner names should be part of
2356 for (t
= ISC_LIST_HEAD(affected
.tuples
);
2358 t
= ISC_LIST_NEXT(t
, link
))
2360 isc_boolean_t exists
;
2361 dns_name_t
*name
= &t
->name
;
2363 CHECK(name_exists(db
, newver
, name
, &exists
));
2366 CHECK(is_active(db
, newver
, name
, &flag
, &cut
, NULL
));
2369 * This name is obscured. Delete any
2370 * existing NSEC record.
2372 CHECK(delete_if(true_p
, db
, newver
, name
,
2373 dns_rdatatype_nsec
, 0,
2375 CHECK(delete_if(rrsig_p
, db
, newver
, name
,
2376 dns_rdatatype_any
, 0, NULL
, diff
));
2379 * This name is not obscured. It needs to have a
2380 * NSEC unless it is the at the origin, in which
2381 * case it should already exist if there is a complete
2382 * NSEC chain and if there isn't a complete NSEC chain
2383 * we don't want to add one as that would signal that
2384 * there is a complete NSEC chain.
2386 if (!dns_name_equal(name
, dns_db_origin(db
))) {
2387 CHECK(rrset_exists(db
, newver
, name
,
2388 dns_rdatatype_nsec
, 0,
2391 CHECK(add_placeholder_nsec(db
, newver
,
2394 CHECK(add_exposed_sigs(client
, zone
, db
, newver
, name
,
2395 cut
, diff
, zone_keys
, nkeys
,
2396 inception
, expire
, check_ksk
,
2402 * Now we know which names are part of the NSEC chain.
2403 * Make them all point at their correct targets.
2405 for (t
= ISC_LIST_HEAD(affected
.tuples
);
2407 t
= ISC_LIST_NEXT(t
, link
))
2409 CHECK(rrset_exists(db
, newver
, &t
->name
,
2410 dns_rdatatype_nsec
, 0, &flag
));
2413 * There is a NSEC, but we don't know if it is correct.
2414 * Delete it and create a correct one to be sure.
2415 * If the update was unnecessary, the diff minimization
2416 * will take care of eliminating it from the journal,
2419 * The RRSIG bit should always be set in the NSECs
2420 * we generate, because they will all get RRSIG NSECs.
2421 * (XXX what if the zone keys are missing?).
2422 * Because the RRSIG NSECs have not necessarily been
2423 * created yet, the correctness of the bit mask relies
2424 * on the assumption that NSECs are only created if
2425 * there is other data, and if there is other data,
2426 * there are other RRSIGs.
2428 CHECK(add_nsec(client
, zone
, db
, newver
, &t
->name
,
2429 nsecttl
, &nsec_diff
));
2434 * Minimize the set of NSEC updates so that we don't
2435 * have to regenerate the RRSIG NSECs for NSECs that were
2436 * replaced with identical ones.
2438 while ((t
= ISC_LIST_HEAD(nsec_diff
.tuples
)) != NULL
) {
2439 ISC_LIST_UNLINK(nsec_diff
.tuples
, t
, link
);
2440 dns_diff_appendminimal(&nsec_mindiff
, &t
);
2443 update_log(client
, zone
, ISC_LOG_DEBUG(3),
2444 "signing rebuilt NSEC chain");
2446 /* Update RRSIG NSECs. */
2447 for (t
= ISC_LIST_HEAD(nsec_mindiff
.tuples
);
2449 t
= ISC_LIST_NEXT(t
, link
))
2451 if (t
->op
== DNS_DIFFOP_DEL
) {
2452 CHECK(delete_if(true_p
, db
, newver
, &t
->name
,
2453 dns_rdatatype_rrsig
, dns_rdatatype_nsec
,
2455 } else if (t
->op
== DNS_DIFFOP_ADD
) {
2456 CHECK(add_sigs(client
, zone
, db
, newver
, &t
->name
,
2457 dns_rdatatype_nsec
, &sig_diff
,
2458 zone_keys
, nkeys
, inception
, expire
,
2459 check_ksk
, keyset_kskonly
));
2467 /* Record our changes for the journal. */
2468 while ((t
= ISC_LIST_HEAD(sig_diff
.tuples
)) != NULL
) {
2469 ISC_LIST_UNLINK(sig_diff
.tuples
, t
, link
);
2470 dns_diff_appendminimal(diff
, &t
);
2472 while ((t
= ISC_LIST_HEAD(nsec_mindiff
.tuples
)) != NULL
) {
2473 ISC_LIST_UNLINK(nsec_mindiff
.tuples
, t
, link
);
2474 dns_diff_appendminimal(diff
, &t
);
2477 INSIST(ISC_LIST_EMPTY(sig_diff
.tuples
));
2478 INSIST(ISC_LIST_EMPTY(nsec_diff
.tuples
));
2479 INSIST(ISC_LIST_EMPTY(nsec_mindiff
.tuples
));
2482 update_log(client
, zone
, ISC_LOG_DEBUG(3),
2483 "no NSEC3 chains to rebuild");
2487 update_log(client
, zone
, ISC_LOG_DEBUG(3), "rebuilding NSEC3 chains");
2489 dns_diff_clear(&diffnames
);
2490 dns_diff_clear(&affected
);
2492 CHECK(dns_diff_sort(diff
, temp_order
));
2495 * Find names potentially affected by delegation changes
2496 * (obscured by adding an NS or DNAME, or unobscured by
2499 t
= ISC_LIST_HEAD(diff
->tuples
);
2501 dns_name_t
*name
= &t
->name
;
2503 isc_boolean_t ns_existed
, dname_existed
;
2504 isc_boolean_t ns_exists
, dname_exists
;
2505 isc_boolean_t exists
, existed
;
2507 if (t
->rdata
.type
== dns_rdatatype_nsec
||
2508 t
->rdata
.type
== dns_rdatatype_rrsig
) {
2509 t
= ISC_LIST_NEXT(t
, link
);
2513 CHECK(namelist_append_name(&affected
, name
));
2515 CHECK(rrset_exists(db
, oldver
, name
, dns_rdatatype_ns
, 0,
2517 CHECK(rrset_exists(db
, oldver
, name
, dns_rdatatype_dname
, 0,
2519 CHECK(rrset_exists(db
, newver
, name
, dns_rdatatype_ns
, 0,
2521 CHECK(rrset_exists(db
, newver
, name
, dns_rdatatype_dname
, 0,
2524 exists
= ns_exists
|| dname_exists
;
2525 existed
= ns_existed
|| dname_existed
;
2526 if (exists
== existed
)
2529 * There was a delegation change. Mark all subdomains
2530 * of t->name as potentially needing a NSEC3 update.
2532 CHECK(namelist_append_subdomain(db
, name
, &affected
));
2535 while (t
!= NULL
&& dns_name_equal(&t
->name
, name
))
2536 t
= ISC_LIST_NEXT(t
, link
);
2539 for (t
= ISC_LIST_HEAD(affected
.tuples
);
2541 t
= ISC_LIST_NEXT(t
, link
)) {
2542 dns_name_t
*name
= &t
->name
;
2544 unsecure
= ISC_FALSE
; /* Silence compiler warning. */
2545 CHECK(is_active(db
, newver
, name
, &flag
, &cut
, &unsecure
));
2548 CHECK(delete_if(rrsig_p
, db
, newver
, name
,
2549 dns_rdatatype_any
, 0, NULL
, diff
));
2550 CHECK(dns_nsec3_delnsec3sx(db
, newver
, name
,
2551 privatetype
, &nsec_diff
));
2553 CHECK(add_exposed_sigs(client
, zone
, db
, newver
, name
,
2554 cut
, diff
, zone_keys
, nkeys
,
2555 inception
, expire
, check_ksk
,
2557 CHECK(dns_nsec3_addnsec3sx(db
, newver
, name
, nsecttl
,
2558 unsecure
, privatetype
,
2564 * Minimize the set of NSEC3 updates so that we don't
2565 * have to regenerate the RRSIG NSEC3s for NSEC3s that were
2566 * replaced with identical ones.
2568 while ((t
= ISC_LIST_HEAD(nsec_diff
.tuples
)) != NULL
) {
2569 ISC_LIST_UNLINK(nsec_diff
.tuples
, t
, link
);
2570 dns_diff_appendminimal(&nsec_mindiff
, &t
);
2573 update_log(client
, zone
, ISC_LOG_DEBUG(3),
2574 "signing rebuilt NSEC3 chain");
2576 /* Update RRSIG NSEC3s. */
2577 for (t
= ISC_LIST_HEAD(nsec_mindiff
.tuples
);
2579 t
= ISC_LIST_NEXT(t
, link
))
2581 if (t
->op
== DNS_DIFFOP_DEL
) {
2582 CHECK(delete_if(true_p
, db
, newver
, &t
->name
,
2583 dns_rdatatype_rrsig
,
2584 dns_rdatatype_nsec3
,
2586 } else if (t
->op
== DNS_DIFFOP_ADD
) {
2587 CHECK(add_sigs(client
, zone
, db
, newver
, &t
->name
,
2588 dns_rdatatype_nsec3
,
2589 &sig_diff
, zone_keys
, nkeys
,
2590 inception
, expire
, check_ksk
,
2597 /* Record our changes for the journal. */
2598 while ((t
= ISC_LIST_HEAD(sig_diff
.tuples
)) != NULL
) {
2599 ISC_LIST_UNLINK(sig_diff
.tuples
, t
, link
);
2600 dns_diff_appendminimal(diff
, &t
);
2602 while ((t
= ISC_LIST_HEAD(nsec_mindiff
.tuples
)) != NULL
) {
2603 ISC_LIST_UNLINK(nsec_mindiff
.tuples
, t
, link
);
2604 dns_diff_appendminimal(diff
, &t
);
2607 INSIST(ISC_LIST_EMPTY(sig_diff
.tuples
));
2608 INSIST(ISC_LIST_EMPTY(nsec_diff
.tuples
));
2609 INSIST(ISC_LIST_EMPTY(nsec_mindiff
.tuples
));
2612 dns_diff_clear(&sig_diff
);
2613 dns_diff_clear(&nsec_diff
);
2614 dns_diff_clear(&nsec_mindiff
);
2616 dns_diff_clear(&affected
);
2617 dns_diff_clear(&diffnames
);
2619 for (i
= 0; i
< nkeys
; i
++)
2620 dst_key_free(&zone_keys
[i
]);
2626 /**************************************************************************/
2628 * The actual update code in all its glory. We try to follow
2629 * the RFC2136 pseudocode as closely as possible.
2633 send_update_event(ns_client_t
*client
, dns_zone_t
*zone
) {
2634 isc_result_t result
= ISC_R_SUCCESS
;
2635 update_event_t
*event
= NULL
;
2636 isc_task_t
*zonetask
= NULL
;
2637 ns_client_t
*evclient
;
2639 event
= (update_event_t
*)
2640 isc_event_allocate(client
->mctx
, client
, DNS_EVENT_UPDATE
,
2641 update_action
, NULL
, sizeof(*event
));
2643 FAIL(ISC_R_NOMEMORY
);
2645 event
->result
= ISC_R_SUCCESS
;
2648 ns_client_attach(client
, &evclient
);
2649 INSIST(client
->nupdates
== 0);
2651 event
->ev_arg
= evclient
;
2653 dns_zone_gettask(zone
, &zonetask
);
2654 isc_task_send(zonetask
, ISC_EVENT_PTR(&event
));
2658 isc_event_free(ISC_EVENT_PTR(&event
));
2663 respond(ns_client_t
*client
, isc_result_t result
) {
2664 isc_result_t msg_result
;
2666 msg_result
= dns_message_reply(client
->message
, ISC_TRUE
);
2667 if (msg_result
!= ISC_R_SUCCESS
)
2669 client
->message
->rcode
= dns_result_torcode(result
);
2671 ns_client_send(client
);
2675 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_UPDATE
, NS_LOGMODULE_UPDATE
,
2677 "could not create update response message: %s",
2678 isc_result_totext(msg_result
));
2679 ns_client_next(client
, msg_result
);
2683 ns_update_start(ns_client_t
*client
, isc_result_t sigresult
) {
2684 dns_message_t
*request
= client
->message
;
2685 isc_result_t result
;
2686 dns_name_t
*zonename
;
2687 dns_rdataset_t
*zone_rdataset
;
2688 dns_zone_t
*zone
= NULL
;
2691 * Interpret the zone section.
2693 result
= dns_message_firstname(request
, DNS_SECTION_ZONE
);
2694 if (result
!= ISC_R_SUCCESS
)
2695 FAILC(DNS_R_FORMERR
, "update zone section empty");
2698 * The zone section must contain exactly one "question", and
2699 * it must be of type SOA.
2702 dns_message_currentname(request
, DNS_SECTION_ZONE
, &zonename
);
2703 zone_rdataset
= ISC_LIST_HEAD(zonename
->list
);
2704 if (zone_rdataset
->type
!= dns_rdatatype_soa
)
2705 FAILC(DNS_R_FORMERR
,
2706 "update zone section contains non-SOA");
2707 if (ISC_LIST_NEXT(zone_rdataset
, link
) != NULL
)
2708 FAILC(DNS_R_FORMERR
,
2709 "update zone section contains multiple RRs");
2711 /* The zone section must have exactly one name. */
2712 result
= dns_message_nextname(request
, DNS_SECTION_ZONE
);
2713 if (result
!= ISC_R_NOMORE
)
2714 FAILC(DNS_R_FORMERR
,
2715 "update zone section contains multiple RRs");
2717 result
= dns_zt_find(client
->view
->zonetable
, zonename
, 0, NULL
,
2719 if (result
!= ISC_R_SUCCESS
)
2720 FAILC(DNS_R_NOTAUTH
, "not authoritative for update zone");
2722 switch(dns_zone_gettype(zone
)) {
2723 case dns_zone_master
:
2725 * We can now fail due to a bad signature as we now know
2726 * that we are the master.
2728 if (sigresult
!= ISC_R_SUCCESS
)
2730 CHECK(send_update_event(client
, zone
));
2732 case dns_zone_slave
:
2733 CHECK(checkupdateacl(client
, dns_zone_getforwardacl(zone
),
2734 "update forwarding", zonename
, ISC_TRUE
,
2736 CHECK(send_forward_event(client
, zone
));
2739 FAILC(DNS_R_NOTAUTH
, "not authoritative for update zone");
2744 if (result
== DNS_R_REFUSED
) {
2745 INSIST(dns_zone_gettype(zone
) == dns_zone_slave
);
2746 inc_stats(zone
, dns_nsstatscounter_updaterej
);
2749 * We failed without having sent an update event to the zone.
2750 * We are still in the client task context, so we can
2751 * simply give an error response without switching tasks.
2753 respond(client
, result
);
2755 dns_zone_detach(&zone
);
2759 * DS records are not allowed to exist without corresponding NS records,
2760 * RFC 3658, 2.2 Protocol Change,
2761 * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
2765 remove_orphaned_ds(dns_db_t
*db
, dns_dbversion_t
*newver
, dns_diff_t
*diff
) {
2766 isc_result_t result
;
2767 isc_boolean_t ns_exists
;
2768 dns_difftuple_t
*tupple
;
2769 dns_diff_t temp_diff
;
2771 dns_diff_init(diff
->mctx
, &temp_diff
);
2773 for (tupple
= ISC_LIST_HEAD(diff
->tuples
);
2775 tupple
= ISC_LIST_NEXT(tupple
, link
)) {
2776 if (!((tupple
->op
== DNS_DIFFOP_DEL
&&
2777 tupple
->rdata
.type
== dns_rdatatype_ns
) ||
2778 (tupple
->op
== DNS_DIFFOP_ADD
&&
2779 tupple
->rdata
.type
== dns_rdatatype_ds
)))
2781 CHECK(rrset_exists(db
, newver
, &tupple
->name
,
2782 dns_rdatatype_ns
, 0, &ns_exists
));
2784 !dns_name_equal(&tupple
->name
, dns_db_origin(db
)))
2786 CHECK(delete_if(true_p
, db
, newver
, &tupple
->name
,
2787 dns_rdatatype_ds
, 0, NULL
, &temp_diff
));
2789 result
= ISC_R_SUCCESS
;
2792 for (tupple
= ISC_LIST_HEAD(temp_diff
.tuples
);
2794 tupple
= ISC_LIST_HEAD(temp_diff
.tuples
)) {
2795 ISC_LIST_UNLINK(temp_diff
.tuples
, tupple
, link
);
2796 dns_diff_appendminimal(diff
, &tupple
);
2802 * This implements the post load integrity checks for mx records.
2805 check_mx(ns_client_t
*client
, dns_zone_t
*zone
,
2806 dns_db_t
*db
, dns_dbversion_t
*newver
, dns_diff_t
*diff
)
2808 char tmp
[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
2809 char ownerbuf
[DNS_NAME_FORMATSIZE
];
2810 char namebuf
[DNS_NAME_FORMATSIZE
];
2811 char altbuf
[DNS_NAME_FORMATSIZE
];
2813 dns_fixedname_t fixed
;
2814 dns_name_t
*foundname
;
2817 isc_boolean_t ok
= ISC_TRUE
;
2818 isc_boolean_t isaddress
;
2819 isc_result_t result
;
2820 struct in6_addr addr6
;
2821 struct in_addr addr
;
2822 unsigned int options
;
2824 dns_fixedname_init(&fixed
);
2825 foundname
= dns_fixedname_name(&fixed
);
2826 dns_rdata_init(&rdata
);
2827 options
= dns_zone_getoptions(zone
);
2829 for (t
= ISC_LIST_HEAD(diff
->tuples
);
2831 t
= ISC_LIST_NEXT(t
, link
)) {
2832 if (t
->op
!= DNS_DIFFOP_ADD
||
2833 t
->rdata
.type
!= dns_rdatatype_mx
)
2836 result
= dns_rdata_tostruct(&t
->rdata
, &mx
, NULL
);
2837 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
2839 * Check if we will error out if we attempt to reload the
2842 dns_name_format(&mx
.mx
, namebuf
, sizeof(namebuf
));
2843 dns_name_format(&t
->name
, ownerbuf
, sizeof(ownerbuf
));
2844 isaddress
= ISC_FALSE
;
2845 if ((options
& DNS_RDATA_CHECKMX
) != 0 &&
2846 strlcpy(tmp
, namebuf
, sizeof(tmp
)) < sizeof(tmp
)) {
2847 if (tmp
[strlen(tmp
) - 1] == '.')
2848 tmp
[strlen(tmp
) - 1] = '\0';
2849 if (inet_aton(tmp
, &addr
) == 1 ||
2850 inet_pton(AF_INET6
, tmp
, &addr6
) == 1)
2851 isaddress
= ISC_TRUE
;
2854 if (isaddress
&& (options
& DNS_RDATA_CHECKMXFAIL
) != 0) {
2855 update_log(client
, zone
, ISC_LOG_ERROR
,
2858 dns_result_totext(DNS_R_MXISADDRESS
));
2860 } else if (isaddress
) {
2861 update_log(client
, zone
, ISC_LOG_WARNING
,
2862 "%s/MX: warning: '%s': %s",
2864 dns_result_totext(DNS_R_MXISADDRESS
));
2868 * Check zone integrity checks.
2870 if ((options
& DNS_ZONEOPT_CHECKINTEGRITY
) == 0)
2872 result
= dns_db_find(db
, &mx
.mx
, newver
, dns_rdatatype_a
,
2873 0, 0, NULL
, foundname
, NULL
, NULL
);
2874 if (result
== ISC_R_SUCCESS
)
2877 if (result
== DNS_R_NXRRSET
) {
2878 result
= dns_db_find(db
, &mx
.mx
, newver
,
2880 0, 0, NULL
, foundname
,
2882 if (result
== ISC_R_SUCCESS
)
2886 if (result
== DNS_R_NXRRSET
|| result
== DNS_R_NXDOMAIN
) {
2887 update_log(client
, zone
, ISC_LOG_ERROR
,
2888 "%s/MX '%s' has no address records "
2889 "(A or AAAA)", ownerbuf
, namebuf
);
2891 } else if (result
== DNS_R_CNAME
) {
2892 update_log(client
, zone
, ISC_LOG_ERROR
,
2893 "%s/MX '%s' is a CNAME (illegal)",
2896 } else if (result
== DNS_R_DNAME
) {
2897 dns_name_format(foundname
, altbuf
, sizeof altbuf
);
2898 update_log(client
, zone
, ISC_LOG_ERROR
,
2899 "%s/MX '%s' is below a DNAME '%s' (illegal)",
2900 ownerbuf
, namebuf
, altbuf
);
2904 return (ok
? ISC_R_SUCCESS
: DNS_R_REFUSED
);
2908 rr_exists(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_name_t
*name
,
2909 const dns_rdata_t
*rdata
, isc_boolean_t
*flag
)
2911 dns_rdataset_t rdataset
;
2912 dns_dbnode_t
*node
= NULL
;
2913 isc_result_t result
;
2915 dns_rdataset_init(&rdataset
);
2916 if (rdata
->type
== dns_rdatatype_nsec3
)
2917 CHECK(dns_db_findnsec3node(db
, name
, ISC_FALSE
, &node
));
2919 CHECK(dns_db_findnode(db
, name
, ISC_FALSE
, &node
));
2920 result
= dns_db_findrdataset(db
, node
, ver
, rdata
->type
, 0,
2921 (isc_stdtime_t
) 0, &rdataset
, NULL
);
2922 if (result
== ISC_R_NOTFOUND
) {
2924 result
= ISC_R_SUCCESS
;
2928 for (result
= dns_rdataset_first(&rdataset
);
2929 result
== ISC_R_SUCCESS
;
2930 result
= dns_rdataset_next(&rdataset
)) {
2931 dns_rdata_t myrdata
= DNS_RDATA_INIT
;
2932 dns_rdataset_current(&rdataset
, &myrdata
);
2933 if (!dns_rdata_casecompare(&myrdata
, rdata
))
2936 dns_rdataset_disassociate(&rdataset
);
2937 if (result
== ISC_R_SUCCESS
) {
2939 } else if (result
== ISC_R_NOMORE
) {
2941 result
= ISC_R_SUCCESS
;
2946 dns_db_detachnode(db
, &node
);
2951 get_iterations(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_rdatatype_t privatetype
,
2952 unsigned int *iterationsp
)
2954 dns_dbnode_t
*node
= NULL
;
2955 dns_rdata_nsec3param_t nsec3param
;
2956 dns_rdataset_t rdataset
;
2957 isc_result_t result
;
2958 unsigned int iterations
= 0;
2960 dns_rdataset_init(&rdataset
);
2962 result
= dns_db_getoriginnode(db
, &node
);
2963 if (result
!= ISC_R_SUCCESS
)
2965 result
= dns_db_findrdataset(db
, node
, ver
, dns_rdatatype_nsec3param
,
2966 0, (isc_stdtime_t
) 0, &rdataset
, NULL
);
2967 if (result
== ISC_R_NOTFOUND
)
2969 if (result
!= ISC_R_SUCCESS
)
2972 for (result
= dns_rdataset_first(&rdataset
);
2973 result
== ISC_R_SUCCESS
;
2974 result
= dns_rdataset_next(&rdataset
)) {
2975 dns_rdata_t rdata
= DNS_RDATA_INIT
;
2976 dns_rdataset_current(&rdataset
, &rdata
);
2977 CHECK(dns_rdata_tostruct(&rdata
, &nsec3param
, NULL
));
2978 if ((nsec3param
.flags
& DNS_NSEC3FLAG_REMOVE
) != 0)
2980 if (nsec3param
.iterations
> iterations
)
2981 iterations
= nsec3param
.iterations
;
2983 if (result
!= ISC_R_NOMORE
)
2986 dns_rdataset_disassociate(&rdataset
);
2989 if (privatetype
== 0)
2992 result
= dns_db_findrdataset(db
, node
, ver
, privatetype
,
2993 0, (isc_stdtime_t
) 0, &rdataset
, NULL
);
2994 if (result
== ISC_R_NOTFOUND
)
2996 if (result
!= ISC_R_SUCCESS
)
2999 for (result
= dns_rdataset_first(&rdataset
);
3000 result
== ISC_R_SUCCESS
;
3001 result
= dns_rdataset_next(&rdataset
)) {
3002 unsigned char buf
[DNS_NSEC3PARAM_BUFFERSIZE
];
3003 dns_rdata_t
private = DNS_RDATA_INIT
;
3004 dns_rdata_t rdata
= DNS_RDATA_INIT
;
3006 dns_rdataset_current(&rdataset
, &rdata
);
3007 if (!dns_nsec3param_fromprivate(&private, &rdata
,
3010 CHECK(dns_rdata_tostruct(&rdata
, &nsec3param
, NULL
));
3011 if ((nsec3param
.flags
& DNS_NSEC3FLAG_REMOVE
) != 0)
3013 if (nsec3param
.iterations
> iterations
)
3014 iterations
= nsec3param
.iterations
;
3016 if (result
!= ISC_R_NOMORE
)
3020 *iterationsp
= iterations
;
3021 result
= ISC_R_SUCCESS
;
3025 dns_db_detachnode(db
, &node
);
3026 if (dns_rdataset_isassociated(&rdataset
))
3027 dns_rdataset_disassociate(&rdataset
);
3032 * Prevent the zone entering a inconsistent state where
3033 * NSEC only DNSKEYs are present with NSEC3 chains.
3036 check_dnssec(ns_client_t
*client
, dns_zone_t
*zone
, dns_db_t
*db
,
3037 dns_dbversion_t
*ver
, dns_diff_t
*diff
)
3039 dns_diff_t temp_diff
;
3041 dns_difftuple_t
*tuple
, *newtuple
= NULL
, *next
;
3043 isc_result_t result
;
3044 unsigned int iterations
= 0, max
;
3045 dns_rdatatype_t privatetype
= dns_zone_getprivatetype(zone
);
3047 dns_diff_init(diff
->mctx
, &temp_diff
);
3049 CHECK(dns_nsec_nseconly(db
, ver
, &flag
));
3052 CHECK(dns_nsec3_activex(db
, ver
, ISC_FALSE
,
3053 privatetype
, &flag
));
3055 update_log(client
, zone
, ISC_LOG_WARNING
,
3056 "NSEC only DNSKEYs and NSEC3 chains not allowed");
3058 CHECK(get_iterations(db
, ver
, privatetype
, &iterations
));
3059 CHECK(dns_nsec3_maxiterations(db
, ver
, client
->mctx
, &max
));
3060 if (max
!= 0 && iterations
> max
) {
3062 update_log(client
, zone
, ISC_LOG_WARNING
,
3063 "too many NSEC3 iterations (%u) for "
3064 "weakest DNSKEY (%u)", iterations
, max
);
3068 for (tuple
= ISC_LIST_HEAD(diff
->tuples
);
3071 next
= ISC_LIST_NEXT(tuple
, link
);
3072 if (tuple
->rdata
.type
!= dns_rdatatype_dnskey
&&
3073 tuple
->rdata
.type
!= dns_rdatatype_nsec3param
)
3075 op
= (tuple
->op
== DNS_DIFFOP_DEL
) ?
3076 DNS_DIFFOP_ADD
: DNS_DIFFOP_DEL
;
3077 CHECK(dns_difftuple_create(temp_diff
.mctx
, op
,
3078 &tuple
->name
, tuple
->ttl
,
3079 &tuple
->rdata
, &newtuple
));
3080 CHECK(do_one_tuple(&newtuple
, db
, ver
, &temp_diff
));
3081 INSIST(newtuple
== NULL
);
3083 for (tuple
= ISC_LIST_HEAD(temp_diff
.tuples
);
3085 tuple
= ISC_LIST_HEAD(temp_diff
.tuples
)) {
3086 ISC_LIST_UNLINK(temp_diff
.tuples
, tuple
, link
);
3087 dns_diff_appendminimal(diff
, &tuple
);
3093 dns_diff_clear(&temp_diff
);
3098 * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
3101 add_nsec3param_records(ns_client_t
*client
, dns_zone_t
*zone
, dns_db_t
*db
,
3102 dns_dbversion_t
*ver
, dns_diff_t
*diff
)
3104 isc_result_t result
= ISC_R_SUCCESS
;
3105 dns_difftuple_t
*tuple
, *newtuple
= NULL
, *next
;
3106 dns_rdata_t rdata
= DNS_RDATA_INIT
;
3107 unsigned char buf
[DNS_NSEC3PARAM_BUFFERSIZE
+ 1];
3108 dns_diff_t temp_diff
;
3111 dns_name_t
*name
= dns_zone_getorigin(zone
);
3112 dns_rdatatype_t privatetype
= dns_zone_getprivatetype(zone
);;
3114 update_log(client
, zone
, ISC_LOG_DEBUG(3),
3115 "checking for NSEC3PARAM changes");
3117 dns_diff_init(diff
->mctx
, &temp_diff
);
3120 * Extract NSEC3PARAM tuples from list.
3122 for (tuple
= ISC_LIST_HEAD(diff
->tuples
);
3126 next
= ISC_LIST_NEXT(tuple
, link
);
3128 if (tuple
->rdata
.type
!= dns_rdatatype_nsec3param
||
3129 !dns_name_equal(name
, &tuple
->name
))
3131 ISC_LIST_UNLINK(diff
->tuples
, tuple
, link
);
3132 ISC_LIST_APPEND(temp_diff
.tuples
, tuple
, link
);
3135 for (tuple
= ISC_LIST_HEAD(temp_diff
.tuples
);
3136 tuple
!= NULL
; tuple
= next
) {
3138 if (tuple
->op
== DNS_DIFFOP_ADD
) {
3139 next
= ISC_LIST_NEXT(tuple
, link
);
3140 while (next
!= NULL
) {
3141 unsigned char *next_data
= next
->rdata
.data
;
3142 unsigned char *tuple_data
= tuple
->rdata
.data
;
3143 if (next_data
[0] != tuple_data
[0] ||
3145 next_data
[2] != tuple_data
[2] ||
3146 next_data
[3] != tuple_data
[3] ||
3147 next_data
[4] != tuple_data
[4] ||
3148 !memcmp(&next_data
[5], &tuple_data
[5],
3150 next
= ISC_LIST_NEXT(next
, link
);
3153 op
= (next
->op
== DNS_DIFFOP_DEL
) ?
3154 DNS_DIFFOP_ADD
: DNS_DIFFOP_DEL
;
3155 CHECK(dns_difftuple_create(diff
->mctx
, op
,
3159 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3160 ISC_LIST_UNLINK(temp_diff
.tuples
, next
, link
);
3161 dns_diff_appendminimal(diff
, &next
);
3162 next
= ISC_LIST_NEXT(tuple
, link
);
3165 INSIST(tuple
->rdata
.data
[1] & DNS_NSEC3FLAG_UPDATE
);
3168 * See if we already have a CREATE request in progress.
3170 dns_nsec3param_toprivate(&tuple
->rdata
, &rdata
,
3171 privatetype
, buf
, sizeof(buf
));
3172 buf
[2] |= DNS_NSEC3FLAG_CREATE
;
3173 buf
[2] &= ~DNS_NSEC3FLAG_UPDATE
;
3175 CHECK(rr_exists(db
, ver
, name
, &rdata
, &flag
));
3178 CHECK(dns_difftuple_create(diff
->mctx
,
3183 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3187 * Remove the temporary add record.
3189 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_DEL
,
3191 &tuple
->rdata
, &newtuple
));
3192 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3193 next
= ISC_LIST_NEXT(tuple
, link
);
3194 ISC_LIST_UNLINK(temp_diff
.tuples
, tuple
, link
);
3195 dns_diff_appendminimal(diff
, &tuple
);
3196 dns_rdata_reset(&rdata
);
3198 next
= ISC_LIST_NEXT(tuple
, link
);
3202 * Reverse any pending changes.
3204 for (tuple
= ISC_LIST_HEAD(temp_diff
.tuples
);
3205 tuple
!= NULL
; tuple
= next
) {
3206 next
= ISC_LIST_NEXT(tuple
, link
);
3207 if ((tuple
->rdata
.data
[1] & ~DNS_NSEC3FLAG_OPTOUT
) != 0) {
3208 op
= (tuple
->op
== DNS_DIFFOP_DEL
) ?
3209 DNS_DIFFOP_ADD
: DNS_DIFFOP_DEL
;
3210 CHECK(dns_difftuple_create(diff
->mctx
, op
, name
,
3211 tuple
->ttl
, &tuple
->rdata
,
3213 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3214 ISC_LIST_UNLINK(temp_diff
.tuples
, tuple
, link
);
3215 dns_diff_appendminimal(diff
, &tuple
);
3220 * Convert deletions into delayed deletions.
3222 for (tuple
= ISC_LIST_HEAD(temp_diff
.tuples
);
3223 tuple
!= NULL
; tuple
= next
) {
3224 next
= ISC_LIST_NEXT(tuple
, link
);
3226 * See if we already have a REMOVE request in progress.
3228 dns_nsec3param_toprivate(&tuple
->rdata
, &rdata
,
3229 privatetype
, buf
, sizeof(buf
));
3230 buf
[2] |= DNS_NSEC3FLAG_REMOVE
;
3232 CHECK(rr_exists(db
, ver
, name
, &rdata
, &flag
));
3235 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_ADD
,
3236 name
, tuple
->ttl
, &rdata
,
3238 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3240 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_ADD
, name
,
3241 tuple
->ttl
, &tuple
->rdata
,
3243 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3244 ISC_LIST_UNLINK(temp_diff
.tuples
, tuple
, link
);
3245 dns_diff_appendminimal(diff
, &tuple
);
3246 dns_rdata_reset(&rdata
);
3249 result
= ISC_R_SUCCESS
;
3251 dns_diff_clear(&temp_diff
);
3256 rollback_private(dns_db_t
*db
, dns_rdatatype_t privatetype
,
3257 dns_dbversion_t
*ver
, dns_diff_t
*diff
)
3259 dns_diff_t temp_diff
;
3261 dns_difftuple_t
*tuple
, *newtuple
= NULL
, *next
;
3262 dns_name_t
*name
= dns_db_origin(db
);
3263 isc_mem_t
*mctx
= diff
->mctx
;
3264 isc_result_t result
;
3266 if (privatetype
== 0)
3267 return (ISC_R_SUCCESS
);
3269 dns_diff_init(mctx
, &temp_diff
);
3272 * Extract the changes to be rolled back.
3274 for (tuple
= ISC_LIST_HEAD(diff
->tuples
);
3278 next
= ISC_LIST_NEXT(tuple
, link
);
3280 if (tuple
->rdata
.type
!= privatetype
||
3281 !dns_name_equal(name
, &tuple
->name
))
3285 * Allow records which indicate that a zone has been
3286 * signed with a DNSKEY to be be removed.
3288 if (tuple
->op
== DNS_DIFFOP_DEL
&&
3289 tuple
->rdata
.length
== 5 &&
3290 tuple
->rdata
.data
[0] != 0 &&
3291 tuple
->rdata
.data
[4] != 0)
3294 ISC_LIST_UNLINK(diff
->tuples
, tuple
, link
);
3295 ISC_LIST_PREPEND(temp_diff
.tuples
, tuple
, link
);
3299 * Rollback the changes.
3301 while ((tuple
= ISC_LIST_HEAD(temp_diff
.tuples
)) != NULL
) {
3302 op
= (tuple
->op
== DNS_DIFFOP_DEL
) ?
3303 DNS_DIFFOP_ADD
: DNS_DIFFOP_DEL
;
3304 CHECK(dns_difftuple_create(mctx
, op
, name
, tuple
->ttl
,
3305 &tuple
->rdata
, &newtuple
));
3306 CHECK(do_one_tuple(&newtuple
, db
, ver
, &temp_diff
));
3308 result
= ISC_R_SUCCESS
;
3311 dns_diff_clear(&temp_diff
);
3316 * Add records to cause the delayed signing of the zone by added DNSKEY
3317 * to remove the RRSIG records generated by a deleted DNSKEY.
3320 add_signing_records(dns_db_t
*db
, dns_rdatatype_t privatetype
,
3321 dns_dbversion_t
*ver
, dns_diff_t
*diff
)
3323 dns_difftuple_t
*tuple
, *newtuple
= NULL
;
3324 dns_rdata_dnskey_t dnskey
;
3325 dns_rdata_t rdata
= DNS_RDATA_INIT
;
3328 isc_result_t result
= ISC_R_SUCCESS
;
3330 unsigned char buf
[5];
3331 dns_name_t
*name
= dns_db_origin(db
);
3333 for (tuple
= ISC_LIST_HEAD(diff
->tuples
);
3335 tuple
= ISC_LIST_NEXT(tuple
, link
)) {
3336 if (tuple
->rdata
.type
!= dns_rdatatype_dnskey
)
3339 dns_rdata_tostruct(&tuple
->rdata
, &dnskey
, NULL
);
3341 (DNS_KEYFLAG_OWNERMASK
|DNS_KEYTYPE_NOAUTH
))
3342 != DNS_KEYOWNER_ZONE
)
3345 dns_rdata_toregion(&tuple
->rdata
, &r
);
3347 keyid
= dst_region_computeid(&r
, dnskey
.algorithm
);
3349 buf
[0] = dnskey
.algorithm
;
3350 buf
[1] = (keyid
& 0xff00) >> 8;
3351 buf
[2] = (keyid
& 0xff);
3352 buf
[3] = (tuple
->op
== DNS_DIFFOP_ADD
) ? 0 : 1;
3355 rdata
.length
= sizeof(buf
);
3356 rdata
.type
= privatetype
;
3357 rdata
.rdclass
= tuple
->rdata
.rdclass
;
3359 CHECK(rr_exists(db
, ver
, name
, &rdata
, &flag
));
3362 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_ADD
,
3363 name
, 0, &rdata
, &newtuple
));
3364 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3365 INSIST(newtuple
== NULL
);
3367 * Remove any record which says this operation has already
3371 CHECK(rr_exists(db
, ver
, name
, &rdata
, &flag
));
3373 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_DEL
,
3374 name
, 0, &rdata
, &newtuple
));
3375 CHECK(do_one_tuple(&newtuple
, db
, ver
, diff
));
3376 INSIST(newtuple
== NULL
);
3384 * Mark all NSEC3 chains for deletion without creating a NSEC chain as
3385 * a side effect of deleting the last chain.
3388 delete_chains(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_zone_t
*zone
,
3391 dns_dbnode_t
*node
= NULL
;
3392 dns_difftuple_t
*tuple
= NULL
;
3394 dns_rdata_t rdata
= DNS_RDATA_INIT
;
3395 dns_rdataset_t rdataset
;
3397 isc_result_t result
= ISC_R_SUCCESS
;
3398 unsigned char buf
[DNS_NSEC3PARAM_BUFFERSIZE
+ 1];
3399 dns_name_t
*origin
= dns_zone_getorigin(zone
);
3400 dns_rdatatype_t privatetype
= dns_zone_getprivatetype(zone
);
3402 dns_name_init(&next
, NULL
);
3403 dns_rdataset_init(&rdataset
);
3405 result
= dns_db_getoriginnode(db
, &node
);
3406 if (result
!= ISC_R_SUCCESS
)
3410 * Cause all NSEC3 chains to be deleted.
3412 result
= dns_db_findrdataset(db
, node
, ver
, dns_rdatatype_nsec3param
,
3413 0, (isc_stdtime_t
) 0, &rdataset
, NULL
);
3414 if (result
== ISC_R_NOTFOUND
)
3416 if (result
!= ISC_R_SUCCESS
)
3419 for (result
= dns_rdataset_first(&rdataset
);
3420 result
== ISC_R_SUCCESS
;
3421 result
= dns_rdataset_next(&rdataset
)) {
3422 dns_rdata_t
private = DNS_RDATA_INIT
;
3424 dns_rdataset_current(&rdataset
, &rdata
);
3426 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_DEL
, origin
,
3427 rdataset
.ttl
, &rdata
, &tuple
));
3428 CHECK(do_one_tuple(&tuple
, db
, ver
, diff
));
3429 INSIST(tuple
== NULL
);
3431 dns_nsec3param_toprivate(&rdata
, &private, privatetype
,
3433 buf
[2] = DNS_NSEC3FLAG_REMOVE
| DNS_NSEC3FLAG_NONSEC
;
3435 CHECK(rr_exists(db
, ver
, origin
, &rdata
, &flag
));
3438 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_ADD
,
3439 origin
, 0, &rdata
, &tuple
));
3440 CHECK(do_one_tuple(&tuple
, db
, ver
, diff
));
3441 INSIST(tuple
== NULL
);
3443 dns_rdata_reset(&rdata
);
3445 if (result
!= ISC_R_NOMORE
)
3448 dns_rdataset_disassociate(&rdataset
);
3451 if (privatetype
== 0)
3453 result
= dns_db_findrdataset(db
, node
, ver
, privatetype
, 0,
3454 (isc_stdtime_t
) 0, &rdataset
, NULL
);
3455 if (result
== ISC_R_NOTFOUND
)
3457 if (result
!= ISC_R_SUCCESS
)
3460 for (result
= dns_rdataset_first(&rdataset
);
3461 result
== ISC_R_SUCCESS
;
3462 result
= dns_rdataset_next(&rdataset
)) {
3463 dns_rdataset_current(&rdataset
, &rdata
);
3464 INSIST(rdata
.length
<= sizeof(buf
));
3465 memcpy(buf
, rdata
.data
, rdata
.length
);
3468 buf
[2] == (DNS_NSEC3FLAG_REMOVE
| DNS_NSEC3FLAG_NONSEC
)) {
3469 dns_rdata_reset(&rdata
);
3473 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_DEL
, origin
,
3474 0, &rdata
, &tuple
));
3475 CHECK(do_one_tuple(&tuple
, db
, ver
, diff
));
3476 INSIST(tuple
== NULL
);
3478 buf
[2] = DNS_NSEC3FLAG_REMOVE
| DNS_NSEC3FLAG_NONSEC
;
3480 CHECK(rr_exists(db
, ver
, origin
, &rdata
, &flag
));
3483 CHECK(dns_difftuple_create(diff
->mctx
, DNS_DIFFOP_ADD
,
3484 origin
, 0, &rdata
, &tuple
));
3485 CHECK(do_one_tuple(&tuple
, db
, ver
, diff
));
3486 INSIST(tuple
== NULL
);
3488 dns_rdata_reset(&rdata
);
3490 if (result
!= ISC_R_NOMORE
)
3493 result
= ISC_R_SUCCESS
;
3496 if (dns_rdataset_isassociated(&rdataset
))
3497 dns_rdataset_disassociate(&rdataset
);
3498 dns_db_detachnode(db
, &node
);
3502 static isc_boolean_t
3503 isdnssec(dns_db_t
*db
, dns_dbversion_t
*ver
, dns_rdatatype_t privatetype
) {
3504 isc_result_t result
;
3505 isc_boolean_t build_nsec
, build_nsec3
;
3507 if (dns_db_issecure(db
))
3510 result
= dns_private_chains(db
, ver
, privatetype
,
3511 &build_nsec
, &build_nsec3
);
3512 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
3513 return (build_nsec
|| build_nsec3
);
3517 update_action(isc_task_t
*task
, isc_event_t
*event
) {
3518 update_event_t
*uev
= (update_event_t
*) event
;
3519 dns_zone_t
*zone
= uev
->zone
;
3520 ns_client_t
*client
= (ns_client_t
*)event
->ev_arg
;
3522 isc_result_t result
;
3523 dns_db_t
*db
= NULL
;
3524 dns_dbversion_t
*oldver
= NULL
;
3525 dns_dbversion_t
*ver
= NULL
;
3526 dns_diff_t diff
; /* Pending updates. */
3527 dns_diff_t temp
; /* Pending RR existence assertions. */
3528 isc_boolean_t soa_serial_changed
= ISC_FALSE
;
3529 isc_mem_t
*mctx
= client
->mctx
;
3530 dns_rdatatype_t covers
;
3531 dns_message_t
*request
= client
->message
;
3532 dns_rdataclass_t zoneclass
;
3533 dns_name_t
*zonename
;
3534 dns_ssutable_t
*ssutable
= NULL
;
3535 dns_fixedname_t tmpnamefixed
;
3536 dns_name_t
*tmpname
= NULL
;
3537 unsigned int options
;
3538 dns_difftuple_t
*tuple
;
3539 dns_rdata_dnskey_t dnskey
;
3540 unsigned char buf
[DNS_NSEC3PARAM_BUFFERSIZE
];
3541 isc_boolean_t had_dnskey
;
3542 dns_rdatatype_t privatetype
= dns_zone_getprivatetype(zone
);
3544 INSIST(event
->ev_type
== DNS_EVENT_UPDATE
);
3546 dns_diff_init(mctx
, &diff
);
3547 dns_diff_init(mctx
, &temp
);
3549 CHECK(dns_zone_getdb(zone
, &db
));
3550 zonename
= dns_db_origin(db
);
3551 zoneclass
= dns_db_class(db
);
3552 dns_zone_getssutable(zone
, &ssutable
);
3555 * Update message processing can leak record existance information
3556 * so check that we are allowed to query this zone. Additionally
3557 * if we would refuse all updates for this zone we bail out here.
3559 CHECK(checkqueryacl(client
, dns_zone_getqueryacl(zone
), zonename
,
3560 dns_zone_getupdateacl(zone
), ssutable
));
3563 * Get old and new versions now that queryacl has been checked.
3565 dns_db_currentversion(db
, &oldver
);
3566 CHECK(dns_db_newversion(db
, &ver
));
3569 * Check prerequisites.
3572 for (result
= dns_message_firstname(request
, DNS_SECTION_PREREQUISITE
);
3573 result
== ISC_R_SUCCESS
;
3574 result
= dns_message_nextname(request
, DNS_SECTION_PREREQUISITE
))
3576 dns_name_t
*name
= NULL
;
3577 dns_rdata_t rdata
= DNS_RDATA_INIT
;
3579 dns_rdataclass_t update_class
;
3582 get_current_rr(request
, DNS_SECTION_PREREQUISITE
, zoneclass
,
3583 &name
, &rdata
, &covers
, &ttl
, &update_class
);
3586 PREREQFAILC(DNS_R_FORMERR
,
3587 "prerequisite TTL is not zero");
3589 if (! dns_name_issubdomain(name
, zonename
))
3590 PREREQFAILN(DNS_R_NOTZONE
, name
,
3591 "prerequisite name is out of zone");
3593 if (update_class
== dns_rdataclass_any
) {
3594 if (rdata
.length
!= 0)
3595 PREREQFAILC(DNS_R_FORMERR
,
3596 "class ANY prerequisite "
3597 "RDATA is not empty");
3598 if (rdata
.type
== dns_rdatatype_any
) {
3599 CHECK(name_exists(db
, ver
, name
, &flag
));
3601 PREREQFAILN(DNS_R_NXDOMAIN
, name
,
3607 CHECK(rrset_exists(db
, ver
, name
,
3608 rdata
.type
, covers
, &flag
));
3610 /* RRset does not exist. */
3611 PREREQFAILNT(DNS_R_NXRRSET
, name
, rdata
.type
,
3612 "'rrset exists (value independent)' "
3613 "prerequisite not satisfied");
3616 } else if (update_class
== dns_rdataclass_none
) {
3617 if (rdata
.length
!= 0)
3618 PREREQFAILC(DNS_R_FORMERR
,
3619 "class NONE prerequisite "
3620 "RDATA is not empty");
3621 if (rdata
.type
== dns_rdatatype_any
) {
3622 CHECK(name_exists(db
, ver
, name
, &flag
));
3624 PREREQFAILN(DNS_R_YXDOMAIN
, name
,
3625 "'name not in use' "
3630 CHECK(rrset_exists(db
, ver
, name
,
3631 rdata
.type
, covers
, &flag
));
3634 PREREQFAILNT(DNS_R_YXRRSET
, name
,
3636 "'rrset does not exist' "
3641 } else if (update_class
== zoneclass
) {
3642 /* "temp<rr.name, rr.type> += rr;" */
3643 result
= temp_append(&temp
, name
, &rdata
);
3644 if (result
!= ISC_R_SUCCESS
) {
3645 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
3646 "temp entry creation failed: %s",
3647 dns_result_totext(result
));
3648 FAIL(ISC_R_UNEXPECTED
);
3651 PREREQFAILC(DNS_R_FORMERR
, "malformed prerequisite");
3654 if (result
!= ISC_R_NOMORE
)
3658 * Perform the final check of the "rrset exists (value dependent)"
3661 if (ISC_LIST_HEAD(temp
.tuples
) != NULL
) {
3662 dns_rdatatype_t type
;
3665 * Sort the prerequisite records by owner name,
3668 result
= dns_diff_sort(&temp
, temp_order
);
3669 if (result
!= ISC_R_SUCCESS
)
3670 FAILC(result
, "'RRset exists (value dependent)' "
3671 "prerequisite not satisfied");
3673 dns_fixedname_init(&tmpnamefixed
);
3674 tmpname
= dns_fixedname_name(&tmpnamefixed
);
3675 result
= temp_check(mctx
, &temp
, db
, ver
, tmpname
, &type
);
3676 if (result
!= ISC_R_SUCCESS
)
3677 FAILNT(result
, tmpname
, type
,
3678 "'RRset exists (value dependent)' "
3679 "prerequisite not satisfied");
3682 update_log(client
, zone
, LOGLEVEL_DEBUG
,
3683 "prerequisites are OK");
3686 * Check Requestor's Permissions. It seems a bit silly to do this
3687 * only after prerequisite testing, but that is what RFC2136 says.
3689 result
= ISC_R_SUCCESS
;
3690 if (ssutable
== NULL
)
3691 CHECK(checkupdateacl(client
, dns_zone_getupdateacl(zone
),
3692 "update", zonename
, ISC_FALSE
, ISC_FALSE
));
3693 else if (client
->signer
== NULL
&& !TCPCLIENT(client
))
3694 CHECK(checkupdateacl(client
, NULL
, "update", zonename
,
3695 ISC_FALSE
, ISC_TRUE
));
3697 if (dns_zone_getupdatedisabled(zone
))
3698 FAILC(DNS_R_REFUSED
, "dynamic update temporarily disabled "
3699 "because the zone is frozen. Use "
3700 "'rndc thaw' to re-enable updates.");
3703 * Perform the Update Section Prescan.
3706 for (result
= dns_message_firstname(request
, DNS_SECTION_UPDATE
);
3707 result
== ISC_R_SUCCESS
;
3708 result
= dns_message_nextname(request
, DNS_SECTION_UPDATE
))
3710 dns_name_t
*name
= NULL
;
3711 dns_rdata_t rdata
= DNS_RDATA_INIT
;
3713 dns_rdataclass_t update_class
;
3714 get_current_rr(request
, DNS_SECTION_UPDATE
, zoneclass
,
3715 &name
, &rdata
, &covers
, &ttl
, &update_class
);
3717 if (! dns_name_issubdomain(name
, zonename
))
3718 FAILC(DNS_R_NOTZONE
,
3719 "update RR is outside zone");
3720 if (update_class
== zoneclass
) {
3722 * Check for meta-RRs. The RFC2136 pseudocode says
3723 * check for ANY|AXFR|MAILA|MAILB, but the text adds
3724 * "or any other QUERY metatype"
3726 if (dns_rdatatype_ismeta(rdata
.type
)) {
3727 FAILC(DNS_R_FORMERR
,
3728 "meta-RR in update");
3730 result
= dns_zone_checknames(zone
, name
, &rdata
);
3731 if (result
!= ISC_R_SUCCESS
)
3732 FAIL(DNS_R_REFUSED
);
3733 } else if (update_class
== dns_rdataclass_any
) {
3734 if (ttl
!= 0 || rdata
.length
!= 0 ||
3735 (dns_rdatatype_ismeta(rdata
.type
) &&
3736 rdata
.type
!= dns_rdatatype_any
))
3737 FAILC(DNS_R_FORMERR
,
3738 "meta-RR in update");
3739 } else if (update_class
== dns_rdataclass_none
) {
3741 dns_rdatatype_ismeta(rdata
.type
))
3742 FAILC(DNS_R_FORMERR
,
3743 "meta-RR in update");
3745 update_log(client
, zone
, ISC_LOG_WARNING
,
3746 "update RR has incorrect class %d",
3748 FAIL(DNS_R_FORMERR
);
3752 * draft-ietf-dnsind-simple-secure-update-01 says
3753 * "Unlike traditional dynamic update, the client
3754 * is forbidden from updating NSEC records."
3756 if (rdata
.type
== dns_rdatatype_nsec3
) {
3757 FAILC(DNS_R_REFUSED
,
3758 "explicit NSEC3 updates are not allowed "
3760 } else if (rdata
.type
== dns_rdatatype_nsec
) {
3761 FAILC(DNS_R_REFUSED
,
3762 "explicit NSEC updates are not allowed "
3764 } else if (rdata
.type
== dns_rdatatype_rrsig
&&
3765 !dns_name_equal(name
, zonename
)) {
3766 FAILC(DNS_R_REFUSED
,
3767 "explicit RRSIG updates are currently "
3768 "not supported in secure zones except "
3772 if (ssutable
!= NULL
) {
3773 isc_netaddr_t
*tcpaddr
, netaddr
;
3775 * If this is a TCP connection then pass the
3776 * address of the client through for tcp-self
3777 * and 6to4-self otherwise pass NULL. This
3778 * provides weak address based authentication.
3780 if (TCPCLIENT(client
)) {
3781 isc_netaddr_fromsockaddr(&netaddr
,
3786 if (rdata
.type
!= dns_rdatatype_any
) {
3787 if (!dns_ssutable_checkrules(ssutable
,
3791 FAILC(DNS_R_REFUSED
,
3792 "rejected by secure update");
3794 if (!ssu_checkall(db
, ver
, name
, ssutable
,
3795 client
->signer
, tcpaddr
))
3796 FAILC(DNS_R_REFUSED
,
3797 "rejected by secure update");
3801 if (result
!= ISC_R_NOMORE
)
3804 update_log(client
, zone
, LOGLEVEL_DEBUG
,
3805 "update section prescan OK");
3808 * Process the Update Section.
3811 options
= dns_zone_getoptions(zone
);
3812 for (result
= dns_message_firstname(request
, DNS_SECTION_UPDATE
);
3813 result
== ISC_R_SUCCESS
;
3814 result
= dns_message_nextname(request
, DNS_SECTION_UPDATE
))
3816 dns_name_t
*name
= NULL
;
3817 dns_rdata_t rdata
= DNS_RDATA_INIT
;
3819 dns_rdataclass_t update_class
;
3822 get_current_rr(request
, DNS_SECTION_UPDATE
, zoneclass
,
3823 &name
, &rdata
, &covers
, &ttl
, &update_class
);
3825 if (update_class
== zoneclass
) {
3828 * RFC1123 doesn't allow MF and MD in master zones. */
3829 if (rdata
.type
== dns_rdatatype_md
||
3830 rdata
.type
== dns_rdatatype_mf
) {
3831 char typebuf
[DNS_RDATATYPE_FORMATSIZE
];
3833 dns_rdatatype_format(rdata
.type
, typebuf
,
3835 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
3836 "attempt to add %s ignored",
3840 if ((rdata
.type
== dns_rdatatype_ns
||
3841 rdata
.type
== dns_rdatatype_dname
) &&
3842 dns_name_iswildcard(name
)) {
3843 char typebuf
[DNS_RDATATYPE_FORMATSIZE
];
3845 dns_rdatatype_format(rdata
.type
, typebuf
,
3847 update_log(client
, zone
,
3849 "attempt to add wildcard %s record "
3850 "ignored", typebuf
);
3853 if (rdata
.type
== dns_rdatatype_cname
) {
3854 CHECK(cname_incompatible_rrset_exists(db
, ver
,
3858 update_log(client
, zone
,
3860 "attempt to add CNAME "
3861 "alongside non-CNAME "
3866 CHECK(rrset_exists(db
, ver
, name
,
3867 dns_rdatatype_cname
, 0,
3870 ! dns_rdatatype_isdnssec(rdata
.type
))
3872 update_log(client
, zone
,
3874 "attempt to add non-CNAME "
3875 "alongside CNAME ignored");
3879 if (rdata
.type
== dns_rdatatype_soa
) {
3881 CHECK(rrset_exists(db
, ver
, name
,
3882 dns_rdatatype_soa
, 0,
3885 update_log(client
, zone
,
3887 "attempt to create 2nd "
3891 CHECK(check_soa_increment(db
, ver
, &rdata
,
3894 update_log(client
, zone
,
3896 "SOA update failed to "
3897 "increment serial, "
3901 soa_serial_changed
= ISC_TRUE
;
3904 if (rdata
.type
== privatetype
) {
3905 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
3906 "attempt to add a private type "
3907 "(%u) record rejected internal "
3908 "use only", privatetype
);
3912 if (rdata
.type
== dns_rdatatype_nsec3param
) {
3914 * Ignore attempts to add NSEC3PARAM records
3915 * with any flags other than OPTOUT.
3917 if ((rdata
.data
[1] & ~DNS_NSEC3FLAG_OPTOUT
) != 0) {
3918 update_log(client
, zone
,
3920 "attempt to add NSEC3PARAM "
3921 "record with non OPTOUT "
3927 * NSEC3CHAIN creation flag.
3929 INSIST(rdata
.length
<= sizeof(buf
));
3930 memcpy(buf
, rdata
.data
, rdata
.length
);
3931 buf
[1] |= DNS_NSEC3FLAG_UPDATE
;
3935 * Force the TTL to zero for NSEC3PARAM records.
3940 if ((options
& DNS_ZONEOPT_CHECKWILDCARD
) != 0 &&
3941 dns_name_internalwildcard(name
)) {
3942 char namestr
[DNS_NAME_FORMATSIZE
];
3943 dns_name_format(name
, namestr
,
3945 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
3946 "warning: ownername '%s' contains "
3947 "a non-terminal wildcard", namestr
);
3950 if (isc_log_wouldlog(ns_g_lctx
, LOGLEVEL_PROTOCOL
)) {
3951 char namestr
[DNS_NAME_FORMATSIZE
];
3952 char typestr
[DNS_RDATATYPE_FORMATSIZE
];
3953 dns_name_format(name
, namestr
,
3955 dns_rdatatype_format(rdata
.type
, typestr
,
3957 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
3958 "adding an RR at '%s' %s",
3962 /* Prepare the affected RRset for the addition. */
3964 add_rr_prepare_ctx_t ctx
;
3969 ctx
.update_rr
= &rdata
;
3970 ctx
.update_rr_ttl
= ttl
;
3971 ctx
.ignore_add
= ISC_FALSE
;
3972 dns_diff_init(mctx
, &ctx
.del_diff
);
3973 dns_diff_init(mctx
, &ctx
.add_diff
);
3974 CHECK(foreach_rr(db
, ver
, name
, rdata
.type
,
3975 covers
, add_rr_prepare_action
,
3978 if (ctx
.ignore_add
) {
3979 dns_diff_clear(&ctx
.del_diff
);
3980 dns_diff_clear(&ctx
.add_diff
);
3982 CHECK(do_diff(&ctx
.del_diff
, db
, ver
,
3984 CHECK(do_diff(&ctx
.add_diff
, db
, ver
,
3986 CHECK(update_one_rr(db
, ver
, &diff
,
3988 name
, ttl
, &rdata
));
3991 } else if (update_class
== dns_rdataclass_any
) {
3992 if (rdata
.type
== dns_rdatatype_any
) {
3993 if (isc_log_wouldlog(ns_g_lctx
,
3996 char namestr
[DNS_NAME_FORMATSIZE
];
3997 dns_name_format(name
, namestr
,
3999 update_log(client
, zone
,
4001 "delete all rrsets from "
4002 "name '%s'", namestr
);
4004 if (dns_name_equal(name
, zonename
)) {
4005 CHECK(delete_if(type_not_soa_nor_ns_p
,
4007 dns_rdatatype_any
, 0,
4010 CHECK(delete_if(type_not_dnssec
,
4012 dns_rdatatype_any
, 0,
4015 } else if (dns_name_equal(name
, zonename
) &&
4016 (rdata
.type
== dns_rdatatype_soa
||
4017 rdata
.type
== dns_rdatatype_ns
)) {
4018 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
4019 "attempt to delete all SOA "
4020 "or NS records ignored");
4023 if (isc_log_wouldlog(ns_g_lctx
,
4026 char namestr
[DNS_NAME_FORMATSIZE
];
4027 char typestr
[DNS_RDATATYPE_FORMATSIZE
];
4028 dns_name_format(name
, namestr
,
4030 dns_rdatatype_format(rdata
.type
,
4033 update_log(client
, zone
,
4035 "deleting rrset at '%s' %s",
4038 CHECK(delete_if(true_p
, db
, ver
, name
,
4039 rdata
.type
, covers
, &rdata
,
4042 } else if (update_class
== dns_rdataclass_none
) {
4043 char namestr
[DNS_NAME_FORMATSIZE
];
4044 char typestr
[DNS_RDATATYPE_FORMATSIZE
];
4047 * The (name == zonename) condition appears in
4048 * RFC2136 3.4.2.4 but is missing from the pseudocode.
4050 if (dns_name_equal(name
, zonename
)) {
4051 if (rdata
.type
== dns_rdatatype_soa
) {
4052 update_log(client
, zone
,
4054 "attempt to delete SOA "
4058 if (rdata
.type
== dns_rdatatype_ns
) {
4060 CHECK(rr_count(db
, ver
, name
,
4064 update_log(client
, zone
,
4073 dns_name_format(name
, namestr
, sizeof(namestr
));
4074 dns_rdatatype_format(rdata
.type
, typestr
,
4076 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
4077 "deleting an RR at %s %s", namestr
, typestr
);
4078 CHECK(delete_if(rr_equal_p
, db
, ver
, name
, rdata
.type
,
4079 covers
, &rdata
, &diff
));
4082 if (result
!= ISC_R_NOMORE
)
4086 * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
4087 * If they don't then back out all changes to DNSKEY/NSEC3PARAM
4090 if (! ISC_LIST_EMPTY(diff
.tuples
))
4091 CHECK(check_dnssec(client
, zone
, db
, ver
, &diff
));
4093 if (! ISC_LIST_EMPTY(diff
.tuples
)) {
4094 unsigned int errors
= 0;
4095 CHECK(dns_zone_nscheck(zone
, db
, ver
, &errors
));
4097 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
4098 "update rejected: post update name server "
4099 "sanity check failed");
4100 result
= DNS_R_REFUSED
;
4106 * If any changes were made, increment the SOA serial number,
4107 * update RRSIGs and NSECs (if zone is secure), and write the update
4110 if (! ISC_LIST_EMPTY(diff
.tuples
)) {
4112 dns_journal_t
*journal
;
4113 isc_boolean_t has_dnskey
;
4116 * Increment the SOA serial, but only if it was not
4117 * changed as a result of an update operation.
4119 if (! soa_serial_changed
) {
4120 CHECK(increment_soa_serial(db
, ver
, &diff
, mctx
));
4123 CHECK(check_mx(client
, zone
, db
, ver
, &diff
));
4125 CHECK(remove_orphaned_ds(db
, ver
, &diff
));
4127 CHECK(rrset_exists(db
, ver
, zonename
, dns_rdatatype_dnskey
,
4130 #define ALLOW_SECURE_TO_INSECURE(zone) \
4131 ((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0)
4133 if (!ALLOW_SECURE_TO_INSECURE(zone
)) {
4134 CHECK(rrset_exists(db
, oldver
, zonename
,
4135 dns_rdatatype_dnskey
, 0,
4137 if (had_dnskey
&& !has_dnskey
) {
4138 update_log(client
, zone
, LOGLEVEL_PROTOCOL
,
4139 "update rejected: all DNSKEY "
4140 "records removed and "
4141 "'dnssec-secure-to-insecure' "
4143 result
= DNS_R_REFUSED
;
4148 CHECK(rollback_private(db
, privatetype
, ver
, &diff
));
4150 CHECK(add_signing_records(db
, privatetype
, ver
, &diff
));
4152 CHECK(add_nsec3param_records(client
, zone
, db
, ver
, &diff
));
4156 * We are transitioning from secure to insecure.
4157 * Cause all NSEC3 chains to be deleted. When the
4158 * the last signature for the DNSKEY records are
4159 * remove any NSEC chain present will also be removed.
4161 CHECK(delete_chains(db
, ver
, zone
, &diff
));
4162 } else if (has_dnskey
&& isdnssec(db
, ver
, privatetype
)) {
4163 isc_uint32_t interval
;
4164 interval
= dns_zone_getsigvalidityinterval(zone
);
4165 result
= update_signatures(client
, zone
, db
, oldver
,
4166 ver
, &diff
, interval
);
4167 if (result
!= ISC_R_SUCCESS
) {
4168 update_log(client
, zone
,
4170 "RRSIG/NSEC/NSEC3 update failed: %s",
4171 isc_result_totext(result
));
4176 journalfile
= dns_zone_getjournal(zone
);
4177 if (journalfile
!= NULL
) {
4178 update_log(client
, zone
, LOGLEVEL_DEBUG
,
4179 "writing journal %s", journalfile
);
4182 result
= dns_journal_open(mctx
, journalfile
,
4183 ISC_TRUE
, &journal
);
4184 if (result
!= ISC_R_SUCCESS
)
4185 FAILS(result
, "journal open failed");
4187 result
= dns_journal_write_transaction(journal
, &diff
);
4188 if (result
!= ISC_R_SUCCESS
) {
4189 dns_journal_destroy(&journal
);
4190 FAILS(result
, "journal write failed");
4193 dns_journal_destroy(&journal
);
4197 * XXXRTH Just a note that this committing code will have
4198 * to change to handle databases that need two-phase
4199 * commit, but this isn't a priority.
4201 update_log(client
, zone
, LOGLEVEL_DEBUG
,
4202 "committing update transaction");
4204 dns_db_closeversion(db
, &ver
, ISC_TRUE
);
4207 * Mark the zone as dirty so that it will be written to disk.
4209 dns_zone_markdirty(zone
);
4212 * Notify slaves of the change we just made.
4214 dns_zone_notify(zone
);
4217 * Cause the zone to be signed with the key that we
4218 * have just added or have the corresponding signatures
4221 * Note: we are already committed to this course of action.
4223 for (tuple
= ISC_LIST_HEAD(diff
.tuples
);
4225 tuple
= ISC_LIST_NEXT(tuple
, link
)) {
4227 dns_secalg_t algorithm
;
4230 if (tuple
->rdata
.type
!= dns_rdatatype_dnskey
)
4233 dns_rdata_tostruct(&tuple
->rdata
, &dnskey
, NULL
);
4235 (DNS_KEYFLAG_OWNERMASK
|DNS_KEYTYPE_NOAUTH
))
4236 != DNS_KEYOWNER_ZONE
)
4239 dns_rdata_toregion(&tuple
->rdata
, &r
);
4240 algorithm
= dnskey
.algorithm
;
4241 keyid
= dst_region_computeid(&r
, algorithm
);
4243 result
= dns_zone_signwithkey(zone
, algorithm
, keyid
,
4244 ISC_TF(tuple
->op
== DNS_DIFFOP_DEL
));
4245 if (result
!= ISC_R_SUCCESS
) {
4246 update_log(client
, zone
, ISC_LOG_ERROR
,
4247 "dns_zone_signwithkey failed: %s",
4248 dns_result_totext(result
));
4253 * Cause the zone to add/delete NSEC3 chains for the
4254 * deferred NSEC3PARAM changes.
4256 * Note: we are already committed to this course of action.
4258 for (tuple
= ISC_LIST_HEAD(diff
.tuples
);
4260 tuple
= ISC_LIST_NEXT(tuple
, link
)) {
4261 unsigned char buf
[DNS_NSEC3PARAM_BUFFERSIZE
];
4262 dns_rdata_t rdata
= DNS_RDATA_INIT
;
4263 dns_rdata_nsec3param_t nsec3param
;
4265 if (tuple
->rdata
.type
!= privatetype
||
4266 tuple
->op
!= DNS_DIFFOP_ADD
)
4269 if (!dns_nsec3param_fromprivate(&tuple
->rdata
, &rdata
,
4272 dns_rdata_tostruct(&rdata
, &nsec3param
, NULL
);
4273 if (nsec3param
.flags
== 0)
4276 result
= dns_zone_addnsec3chain(zone
, &nsec3param
);
4277 if (result
!= ISC_R_SUCCESS
) {
4278 update_log(client
, zone
, ISC_LOG_ERROR
,
4279 "dns_zone_addnsec3chain failed: %s",
4280 dns_result_totext(result
));
4284 update_log(client
, zone
, LOGLEVEL_DEBUG
, "redundant request");
4285 dns_db_closeversion(db
, &ver
, ISC_TRUE
);
4287 result
= ISC_R_SUCCESS
;
4292 * The reason for failure should have been logged at this point.
4295 update_log(client
, zone
, LOGLEVEL_DEBUG
,
4297 dns_db_closeversion(db
, &ver
, ISC_FALSE
);
4301 dns_diff_clear(&temp
);
4302 dns_diff_clear(&diff
);
4305 dns_db_closeversion(db
, &oldver
, ISC_FALSE
);
4310 if (ssutable
!= NULL
)
4311 dns_ssutable_detach(&ssutable
);
4313 isc_task_detach(&task
);
4314 uev
->result
= result
;
4316 INSIST(uev
->zone
== zone
); /* we use this later */
4317 uev
->ev_type
= DNS_EVENT_UPDATEDONE
;
4318 uev
->ev_action
= updatedone_action
;
4319 isc_task_send(client
->task
, &event
);
4320 INSIST(event
== NULL
);
4324 updatedone_action(isc_task_t
*task
, isc_event_t
*event
) {
4325 update_event_t
*uev
= (update_event_t
*) event
;
4326 ns_client_t
*client
= (ns_client_t
*) event
->ev_arg
;
4330 INSIST(event
->ev_type
== DNS_EVENT_UPDATEDONE
);
4331 INSIST(task
== client
->task
);
4333 INSIST(client
->nupdates
> 0);
4334 switch (uev
->result
) {
4336 inc_stats(uev
->zone
, dns_nsstatscounter_updatedone
);
4339 inc_stats(uev
->zone
, dns_nsstatscounter_updaterej
);
4342 inc_stats(uev
->zone
, dns_nsstatscounter_updatefail
);
4345 if (uev
->zone
!= NULL
)
4346 dns_zone_detach(&uev
->zone
);
4348 respond(client
, uev
->result
);
4349 isc_event_free(&event
);
4350 ns_client_detach(&client
);
4354 * Update forwarding support.
4358 forward_fail(isc_task_t
*task
, isc_event_t
*event
) {
4359 ns_client_t
*client
= (ns_client_t
*)event
->ev_arg
;
4363 INSIST(client
->nupdates
> 0);
4365 respond(client
, DNS_R_SERVFAIL
);
4366 isc_event_free(&event
);
4367 ns_client_detach(&client
);
4372 forward_callback(void *arg
, isc_result_t result
, dns_message_t
*answer
) {
4373 update_event_t
*uev
= arg
;
4374 ns_client_t
*client
= uev
->ev_arg
;
4375 dns_zone_t
*zone
= uev
->zone
;
4377 if (result
!= ISC_R_SUCCESS
) {
4378 INSIST(answer
== NULL
);
4379 uev
->ev_type
= DNS_EVENT_UPDATEDONE
;
4380 uev
->ev_action
= forward_fail
;
4381 inc_stats(zone
, dns_nsstatscounter_updatefwdfail
);
4383 uev
->ev_type
= DNS_EVENT_UPDATEDONE
;
4384 uev
->ev_action
= forward_done
;
4385 uev
->answer
= answer
;
4386 inc_stats(zone
, dns_nsstatscounter_updaterespfwd
);
4388 isc_task_send(client
->task
, ISC_EVENT_PTR(&uev
));
4389 dns_zone_detach(&zone
);
4393 forward_done(isc_task_t
*task
, isc_event_t
*event
) {
4394 update_event_t
*uev
= (update_event_t
*) event
;
4395 ns_client_t
*client
= (ns_client_t
*)event
->ev_arg
;
4399 INSIST(client
->nupdates
> 0);
4401 ns_client_sendraw(client
, uev
->answer
);
4402 dns_message_destroy(&uev
->answer
);
4403 isc_event_free(&event
);
4404 ns_client_detach(&client
);
4408 forward_action(isc_task_t
*task
, isc_event_t
*event
) {
4409 update_event_t
*uev
= (update_event_t
*) event
;
4410 dns_zone_t
*zone
= uev
->zone
;
4411 ns_client_t
*client
= (ns_client_t
*)event
->ev_arg
;
4412 isc_result_t result
;
4414 result
= dns_zone_forwardupdate(zone
, client
->message
,
4415 forward_callback
, event
);
4416 if (result
!= ISC_R_SUCCESS
) {
4417 uev
->ev_type
= DNS_EVENT_UPDATEDONE
;
4418 uev
->ev_action
= forward_fail
;
4419 isc_task_send(client
->task
, &event
);
4420 inc_stats(zone
, dns_nsstatscounter_updatefwdfail
);
4421 dns_zone_detach(&zone
);
4423 inc_stats(zone
, dns_nsstatscounter_updatereqfwd
);
4424 isc_task_detach(&task
);
4428 send_forward_event(ns_client_t
*client
, dns_zone_t
*zone
) {
4429 isc_result_t result
= ISC_R_SUCCESS
;
4430 update_event_t
*event
= NULL
;
4431 isc_task_t
*zonetask
= NULL
;
4432 ns_client_t
*evclient
;
4434 event
= (update_event_t
*)
4435 isc_event_allocate(client
->mctx
, client
, DNS_EVENT_UPDATE
,
4436 forward_action
, NULL
, sizeof(*event
));
4438 FAIL(ISC_R_NOMEMORY
);
4440 event
->result
= ISC_R_SUCCESS
;
4443 ns_client_attach(client
, &evclient
);
4444 INSIST(client
->nupdates
== 0);
4446 event
->ev_arg
= evclient
;
4448 dns_zone_gettask(zone
, &zonetask
);
4449 isc_task_send(zonetask
, ISC_EVENT_PTR(&event
));
4453 isc_event_free(ISC_EVENT_PTR(&event
));