No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / bin / named / update.c
blob945158f7ba7b6682248bca793a77a1585b5095f6
1 /* $NetBSD$ */
3 /*
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 */
22 #include <config.h>
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>
30 #include <isc/util.h>
32 #include <dns/db.h>
33 #include <dns/dbiterator.h>
34 #include <dns/diff.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>
41 #include <dns/nsec.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>
49 #include <dns/soa.h>
50 #include <dns/ssu.h>
51 #include <dns/view.h>
52 #include <dns/zone.h>
53 #include <dns/zt.h>
55 #include <named/client.h>
56 #include <named/log.h>
57 #include <named/server.h>
58 #include <named/update.h>
60 /*! \file
61 * \brief
62 * This module implements dynamic update as in RFC2136.
66 * XXX TODO:
67 * - document strict minimality
70 /**************************************************************************/
72 /*%
73 * Log level for tracing dynamic update protocol requests.
75 #define LOGLEVEL_PROTOCOL ISC_LOG_INFO
77 /*%
78 * Log level for low-level debug tracing.
80 #define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8)
82 /*%
83 * Check an operation for failure. These macros all assume that
84 * the function using them has a 'result' variable and a 'failure'
85 * label.
87 #define CHECK(op) \
88 do { result = (op); \
89 if (result != ISC_R_SUCCESS) goto failure; \
90 } while (0)
92 /*%
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".
101 #define FAIL(code) \
102 do { \
103 result = (code); \
104 if (result != ISC_R_SUCCESS) goto failure; \
105 } while (0)
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) \
113 do { \
114 const char *_what = "failed"; \
115 result = (code); \
116 switch (result) { \
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; \
127 } while (0)
128 #define PREREQFAILC(code, msg) \
129 do { \
130 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
131 FAILC(code, msg); \
132 } while (0)
134 #define FAILN(code, name, msg) \
135 do { \
136 const char *_what = "failed"; \
137 result = (code); \
138 switch (result) { \
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; \
153 } while (0)
154 #define PREREQFAILN(code, name, msg) \
155 do { \
156 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
157 FAILN(code, name, msg); \
158 } while (0)
160 #define FAILNT(code, name, type, msg) \
161 do { \
162 const char *_what = "failed"; \
163 result = (code); \
164 switch (result) { \
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; \
182 } while (0)
183 #define PREREQFAILNT(code, name, type, msg) \
184 do { \
185 inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
186 FAILNT(code, name, type, msg); \
187 } while (0)
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) \
195 do { \
196 result = (code); \
197 update_log(client, zone, LOGLEVEL_PROTOCOL, \
198 "error: %s: %s", \
199 msg, isc_result_totext(result)); \
200 if (result != ISC_R_SUCCESS) goto failure; \
201 } while (0)
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;
212 struct rr {
213 /* dns_name_t name; */
214 isc_uint32_t ttl;
215 dns_rdata_t rdata;
218 typedef struct update_event update_event_t;
220 struct update_event {
221 ISC_EVENT_COMMON(update_event_t);
222 dns_zone_t *zone;
223 isc_result_t result;
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 /**************************************************************************/
239 static void
240 update_log(ns_client_t *client, dns_zone_t *zone,
241 int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
243 static void
244 update_log(ns_client_t *client, dns_zone_t *zone,
245 int level, const char *fmt, ...)
247 va_list ap;
248 char message[4096];
249 char namebuf[DNS_NAME_FORMATSIZE];
250 char classbuf[DNS_RDATACLASS_FORMATSIZE];
252 if (client == NULL || zone == NULL)
253 return;
255 if (isc_log_wouldlog(ns_g_lctx, level) == ISC_FALSE)
256 return;
258 dns_name_format(dns_zone_getorigin(zone), namebuf,
259 sizeof(namebuf));
260 dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
261 sizeof(classbuf));
263 va_start(ap, fmt);
264 vsnprintf(message, sizeof(message), fmt, ap);
265 va_end(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.
275 static inline void
276 inc_stats(dns_zone_t *zone, isc_statscounter_t counter) {
277 isc_stats_increment(ns_g_server->nsstats, counter);
279 if (zone != NULL) {
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.
292 static isc_result_t
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];
298 int level;
299 isc_result_t result;
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,
305 sizeof(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",
313 namebuf, classbuf);
314 } else if (updateacl == NULL && ssutable == NULL) {
315 dns_name_format(zonename, namebuf, sizeof(namebuf));
316 dns_rdataclass_format(client->view->rdclass, classbuf,
317 sizeof(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);
324 return (result);
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
334 * log at debug=3.
335 * If the zone has no access controls configured ('acl' == NULL &&
336 * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise
337 * at error.
339 * If the request was signed log that we received it.
341 static isc_result_t
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";
350 isc_result_t result;
352 if (slave && acl == NULL) {
353 result = DNS_R_NOTIMP;
354 level = ISC_LOG_DEBUG(3);
355 msg = "disabled";
356 } else {
357 result = ns_client_checkaclsilent(client, NULL, acl, ISC_FALSE);
358 if (result == ISC_R_SUCCESS) {
359 level = ISC_LOG_DEBUG(3);
360 msg = "approved";
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,
375 sizeof(classbuf));
377 ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
378 NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s",
379 message, namebuf, classbuf, msg);
380 return (result);
384 * Update a single RR in version 'ver' of 'db' and log the
385 * update in 'diff'.
387 * Ensures:
388 * \li '*tuple' == NULL. Either the tuple is freed, or its
389 * ownership has been transferred to the diff.
391 static isc_result_t
392 do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
393 dns_diff_t *diff)
395 dns_diff_t temp_diff;
396 isc_result_t result;
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);
412 return (result);
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
428 * update in 'diff'.
430 * Ensures:
431 * \li 'updates' is empty.
433 static isc_result_t
434 do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver,
435 dns_diff_t *diff)
437 isc_result_t result;
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);
445 failure:
446 dns_diff_clear(diff);
447 return (result);
450 static isc_result_t
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,
453 dns_rdata_t *rdata)
455 dns_difftuple_t *tuple = NULL;
456 isc_result_t result;
457 result = dns_difftuple_create(diff->mctx, op,
458 name, ttl, rdata, &tuple);
459 if (result != ISC_R_SUCCESS)
460 return (result);
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().
497 typedef struct {
498 rr_func * rr_action;
499 void * rr_action_data;
500 } foreach_node_rr_ctx_t;
503 * Internal helper function for foreach_node_rr().
505 static isc_result_t
506 foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
507 isc_result_t result;
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)
519 return (result);
521 if (result != ISC_R_NOMORE)
522 return (result);
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.
533 static isc_result_t
534 foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
535 rrset_func *action, void *action_data)
537 isc_result_t result;
538 dns_dbnode_t *node;
539 dns_rdatasetiter_t *iter;
541 node = NULL;
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)
546 return (result);
548 iter = NULL;
549 result = dns_db_allrdatasets(db, node, ver,
550 (isc_stdtime_t) 0, &iter);
551 if (result != ISC_R_SUCCESS)
552 goto cleanup_node;
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;
572 cleanup_iterator:
573 dns_rdatasetiter_destroy(&iter);
575 cleanup_node:
576 dns_db_detachnode(db, &node);
578 return (result);
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.
589 static isc_result_t
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,
606 * do nothing.
608 * If 'action' returns an error, abort iteration and return the error.
610 static isc_result_t
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)
616 isc_result_t result;
617 dns_dbnode_t *node;
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));
624 node = NULL;
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);
628 else
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)
633 return (result);
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;
640 goto cleanup_node;
642 if (result != ISC_R_SUCCESS)
643 goto cleanup_node;
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;
660 cleanup_rdataset:
661 dns_rdataset_disassociate(&rdataset);
662 cleanup_node:
663 dns_db_detachnode(db, &node);
665 return (result);
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().
682 static isc_result_t
683 rrset_exists_action(void *data, rr_t *rr) {
684 UNUSED(data);
685 UNUSED(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) : \
707 result))
710 * Set '*exists' to true iff an rrset of the given type exists,
711 * to false otherwise.
713 static isc_result_t
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)
718 isc_result_t result;
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
727 * error occurs.
729 static isc_result_t
730 rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
731 dns_rdatatype_t type, isc_boolean_t *visible)
733 isc_result_t result;
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);
740 switch (result) {
741 case ISC_R_SUCCESS:
742 *visible = ISC_TRUE;
743 break;
745 * Glue, obscured, deleted or replaced records.
747 case DNS_R_DELEGATION:
748 case DNS_R_DNAME:
749 case DNS_R_CNAME:
750 case DNS_R_NXDOMAIN:
751 case DNS_R_NXRRSET:
752 case DNS_R_EMPTYNAME:
753 case DNS_R_COVERINGNSEC:
754 *visible = ISC_FALSE;
755 result = ISC_R_SUCCESS;
756 break;
757 default:
758 break;
760 return (result);
764 * Helper function for cname_incompatible_rrset_exists.
766 static isc_result_t
767 cname_compatibility_action(void *data, dns_rdataset_t *rrset) {
768 UNUSED(data);
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.
783 static isc_result_t
784 cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
785 dns_name_t *name, isc_boolean_t *exists) {
786 isc_result_t result;
787 result = foreach_rrset(db, ver, name,
788 cname_compatibility_action, NULL);
789 RETURN_EXISTENCE_FLAG;
793 * Helper function for rr_count().
795 static isc_result_t
796 count_rr_action(void *data, rr_t *rr) {
797 int *countp = data;
798 UNUSED(rr);
799 (*countp)++;
800 return (ISC_R_SUCCESS);
804 * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'.
806 static isc_result_t
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)
810 *countp = 0;
811 return (foreach_rr(db, ver, name, type, covers,
812 count_rr_action, countp));
816 * Context struct and helper function for name_exists().
819 static isc_result_t
820 name_exists_action(void *data, dns_rdataset_t *rrset) {
821 UNUSED(data);
822 UNUSED(rrset);
823 return (ISC_R_EXISTS);
827 * Set '*exists' to true iff the given name exists, to false otherwise.
829 static isc_result_t
830 name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
831 isc_boolean_t *exists)
833 isc_result_t result;
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
842 * ssu_checkrule().
844 typedef struct {
845 /* The ownername of the record to be updated. */
846 dns_name_t *name;
848 /* The signature's name if the request was signed. */
849 dns_name_t *signer;
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;
856 } ssu_check_t;
858 static isc_result_t
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,
872 rrset->type);
873 return (result == ISC_TRUE ? ISC_R_SUCCESS : ISC_R_FAILURE);
876 static isc_boolean_t
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)
881 isc_result_t result;
882 ssu_check_t ssuinfo;
884 ssuinfo.name = name;
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'.
908 static isc_result_t
909 temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) {
910 isc_result_t result;
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);
917 failure:
918 return (result);
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)
925 * if not.
927 static isc_result_t
928 temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) {
929 for (;;) {
930 if (a == NULL || b == NULL)
931 break;
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.
951 static int
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;
957 int r;
958 r = dns_name_compare(&a->name, &b->name);
959 if (r != 0)
960 return (r);
961 r = (b->rdata.type - a->rdata.type);
962 if (r != 0)
963 return (r);
964 r = dns_rdata_casecompare(&a->rdata, &b->rdata);
965 return (r);
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.
978 static isc_result_t
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)
982 isc_result_t result;
983 dns_name_t *name;
984 dns_dbnode_t *node;
985 dns_difftuple_t *t;
986 dns_diff_t trash;
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);
996 while (t != NULL) {
997 name = &t->name;
998 (void)dns_name_copy(name, tmpname, NULL);
999 *typep = t->rdata.type;
1001 /* A new unique name begins here. */
1002 node = NULL;
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);
1010 return (result);
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);
1030 } else
1031 covers = 0;
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,
1040 &rdataset, NULL);
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)
1058 goto failure;
1060 if (result != ISC_R_NOMORE)
1061 goto failure;
1062 result = dns_diff_sort(&d_rrs, temp_order);
1063 if (result != ISC_R_SUCCESS)
1064 goto failure;
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.
1071 while (t != NULL &&
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);
1079 t = next;
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)
1086 goto failure;
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);
1097 continue;
1099 failure:
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);
1105 return (result);
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().
1124 typedef struct {
1125 rr_predicate *predicate;
1126 dns_db_t *db;
1127 dns_dbversion_t *ver;
1128 dns_diff_t *diff;
1129 dns_name_t *name;
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) {
1143 UNUSED(update_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) {
1157 UNUSED(update_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) {
1168 UNUSED(update_rr);
1169 UNUSED(db_rr);
1170 return (ISC_TRUE);
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) {
1178 UNUSED(update_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)
1215 return (ISC_FALSE);
1216 if (db_rr->type == dns_rdatatype_cname)
1217 return (ISC_TRUE);
1218 if (db_rr->type == dns_rdatatype_dname)
1219 return (ISC_TRUE);
1220 if (db_rr->type == dns_rdatatype_soa)
1221 return (ISC_TRUE);
1222 if (db_rr->type == dns_rdatatype_nsec)
1223 return (ISC_TRUE);
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)
1236 return (ISC_TRUE);
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)
1252 return (ISC_FALSE);
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)
1262 return (ISC_TRUE);
1264 return (ISC_FALSE);
1268 * Internal helper function for delete_if().
1270 static isc_result_t
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);
1278 return (result);
1279 } else {
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'.
1291 static isc_result_t
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;
1298 ctx.db = db;
1299 ctx.ver = ver;
1300 ctx.diff = diff;
1301 ctx.name = name;
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.
1317 typedef struct {
1318 dns_db_t *db;
1319 dns_dbversion_t *ver;
1320 dns_diff_t *diff;
1321 dns_name_t *name;
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;
1329 static isc_result_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,
1353 &tuple));
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,
1365 &tuple));
1366 dns_diff_append(&ctx->del_diff, &tuple);
1367 if (!equal) {
1368 CHECK(dns_difftuple_create(ctx->add_diff.mctx,
1369 DNS_DIFFOP_ADD, ctx->name,
1370 ctx->update_rr_ttl,
1371 &rr->rdata, &tuple));
1372 dns_diff_append(&ctx->add_diff, &tuple);
1375 failure:
1376 return (result);
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.
1391 static void
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
1416 * change in 'diff'.
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().
1425 static isc_result_t
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);
1440 /* RFC1982 */
1441 serial = (serial + 1) & 0xFFFFFFFF;
1442 if (serial == 0)
1443 serial = 1;
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;
1450 failure:
1451 if (addtuple != NULL)
1452 dns_difftuple_free(&addtuple);
1453 if (deltuple != NULL)
1454 dns_difftuple_free(&deltuple);
1455 return (result);
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.
1478 static isc_result_t
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)
1490 return (result);
1492 if (DNS_SERIAL_GE(db_serial, update_serial)) {
1493 *ok = ISC_FALSE;
1494 } else {
1495 *ok = ISC_TRUE;
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.
1513 static isc_result_t
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);
1522 failure:
1523 return (result);
1526 static isc_result_t
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;
1531 dns_name_t *child;
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))
1547 break;
1548 CHECK(namelist_append_name(affected, child));
1550 if (result == ISC_R_NOMORE)
1551 result = ISC_R_SUCCESS;
1552 failure:
1553 if (dbit != NULL)
1554 dns_dbiterator_destroy(&dbit);
1555 return (result);
1561 * Helper function for non_nsec_rrset_exists().
1563 static isc_result_t
1564 is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
1565 UNUSED(data);
1566 if (!(rrset->type == dns_rdatatype_nsec ||
1567 rrset->type == dns_rdatatype_nsec3 ||
1568 (rrset->type == dns_rdatatype_rrsig &&
1569 (rrset->covers == dns_rdatatype_nsec ||
1570 rrset->covers == dns_rdatatype_nsec3))))
1571 return (ISC_R_EXISTS);
1572 return (ISC_R_SUCCESS);
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.
1583 static isc_result_t
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.
1595 static int
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));
1604 static isc_result_t
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);
1612 while (p != NULL) {
1613 do {
1614 q = ISC_LIST_NEXT(p, link);
1615 if (q == NULL || ! dns_name_equal(&p->name, &q->name))
1616 break;
1617 ISC_LIST_UNLINK(list->tuples, q, link);
1618 dns_difftuple_free(&q);
1619 } while (1);
1620 p = ISC_LIST_NEXT(p, link);
1622 failure:
1623 return (result);
1626 static isc_result_t
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),
1637 NULL, NULL);
1638 if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
1639 *flag = ISC_TRUE;
1640 *cut = ISC_FALSE;
1641 if (unsecure != NULL)
1642 *unsecure = ISC_FALSE;
1643 return (ISC_R_SUCCESS);
1644 } else if (result == DNS_R_ZONECUT) {
1645 *flag = ISC_TRUE;
1646 *cut = ISC_TRUE;
1647 if (unsecure != NULL) {
1649 * We are at the zonecut. Check to see if there
1650 * is a DS RRset.
1652 if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
1653 (isc_stdtime_t) 0, NULL,
1654 dns_fixedname_name(&foundname),
1655 NULL, NULL) == DNS_R_NXRRSET)
1656 *unsecure = ISC_TRUE;
1657 else
1658 *unsecure = ISC_FALSE;
1660 return (ISC_R_SUCCESS);
1661 } else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
1662 result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
1663 *flag = ISC_FALSE;
1664 *cut = ISC_FALSE;
1665 if (unsecure != NULL)
1666 *unsecure = ISC_FALSE;
1667 return (ISC_R_SUCCESS);
1668 } else {
1670 * Silence compiler.
1672 *flag = ISC_FALSE;
1673 *cut = ISC_FALSE;
1674 if (unsecure != NULL)
1675 *unsecure = ISC_FALSE;
1676 return (result);
1681 * Find the next/previous name that has a NSEC record.
1682 * In other words, skip empty database nodes and names that
1683 * have had their NSECs removed because they are obscured by
1684 * a zone cut.
1686 static isc_result_t
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));
1700 do {
1701 dns_dbnode_t *node = NULL;
1703 if (forward)
1704 result = dns_dbiterator_next(dbit);
1705 else
1706 result = dns_dbiterator_prev(dbit);
1707 if (result == ISC_R_NOMORE) {
1709 * Wrap around.
1711 if (forward)
1712 CHECK(dns_dbiterator_first(dbit));
1713 else
1714 CHECK(dns_dbiterator_last(dbit));
1715 wraps++;
1716 if (wraps == 2) {
1717 update_log(client, zone, ISC_LOG_ERROR,
1718 "secure zone with no NSECs");
1719 result = DNS_R_BADZONE;
1720 goto failure;
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));
1733 if (secure) {
1734 CHECK(rrset_exists(db, ver, newname,
1735 dns_rdatatype_nsec, 0, &has_nsec));
1736 } else {
1737 dns_fixedname_t ffound;
1738 dns_name_t *found;
1739 dns_fixedname_init(&ffound);
1740 found = dns_fixedname_name(&ffound);
1741 result = dns_db_find(db, newname, ver,
1742 dns_rdatatype_soa,
1743 DNS_DBFIND_NOWILD, 0, NULL, found,
1744 NULL, NULL);
1745 if (result == ISC_R_SUCCESS ||
1746 result == DNS_R_EMPTYNAME ||
1747 result == DNS_R_NXRRSET ||
1748 result == DNS_R_CNAME ||
1749 (result == DNS_R_DELEGATION &&
1750 dns_name_equal(newname, found))) {
1751 has_nsec = ISC_TRUE;
1752 result = ISC_R_SUCCESS;
1753 } else if (result != DNS_R_NXDOMAIN)
1754 break;
1756 } while (! has_nsec);
1757 failure:
1758 if (dbit != NULL)
1759 dns_dbiterator_destroy(&dbit);
1761 return (result);
1765 * Add a NSEC record for "name", recording the change in "diff".
1766 * The existing NSEC is removed.
1768 static isc_result_t
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,
1771 dns_diff_t *diff)
1773 isc_result_t result;
1774 dns_dbnode_t *node = NULL;
1775 unsigned char buffer[DNS_NSEC_BUFFERSIZE];
1776 dns_rdata_t rdata = DNS_RDATA_INIT;
1777 dns_difftuple_t *tuple = NULL;
1778 dns_fixedname_t fixedname;
1779 dns_name_t *target;
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,
1801 NULL, diff));
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);
1810 failure:
1811 if (node != NULL)
1812 dns_db_detachnode(db, &node);
1813 return (result);
1817 * Add a placeholder NSEC record for "name", recording the change in "diff".
1819 static isc_result_t
1820 add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1821 dns_diff_t *diff)
1823 isc_result_t result;
1824 dns_difftuple_t *tuple = NULL;
1825 isc_region_t r;
1826 unsigned char data[1] = { 0 }; /* The root domain, no bits. */
1827 dns_rdata_t rdata = DNS_RDATA_INIT;
1829 r.base = data;
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,
1833 &rdata, &tuple));
1834 CHECK(do_one_tuple(&tuple, db, ver, diff));
1835 failure:
1836 return (result);
1839 static isc_result_t
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));
1850 failure:
1851 if (node != NULL)
1852 dns_db_detachnode(db, &node);
1853 return (result);
1857 * Add RRSIG records for an RRset, recording the change in "diff".
1859 static isc_result_t
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 */
1872 unsigned int i, j;
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));
1882 else
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
1895 * algorithm.
1897 for (i = 0; i < nkeys; i++) {
1898 isc_boolean_t both = ISC_FALSE;
1900 if (!dst_key_isprivate(keys[i]))
1901 continue;
1903 if (check_ksk && !REVOKE(keys[i])) {
1904 isc_boolean_t have_ksk, have_nonksk;
1905 if (KSK(keys[i])) {
1906 have_ksk = ISC_TRUE;
1907 have_nonksk = ISC_FALSE;
1908 } else {
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]))
1914 continue;
1915 if (REVOKE(keys[j]))
1916 continue;
1917 if (KSK(keys[j]))
1918 have_ksk = ISC_TRUE;
1919 else
1920 have_nonksk = ISC_TRUE;
1921 both = have_ksk && have_nonksk;
1922 if (both)
1923 break;
1927 if (both) {
1928 if (type == dns_rdatatype_dnskey) {
1929 if (!KSK(keys[i]) && keyset_kskonly)
1930 continue;
1931 } else if (KSK(keys[i]))
1932 continue;
1933 } else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey)
1934 continue;
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;
1948 if (!added_sig) {
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;
1955 failure:
1956 if (dns_rdataset_isassociated(&rdataset))
1957 dns_rdataset_disassociate(&rdataset);
1958 if (node != NULL)
1959 dns_db_detachnode(db, &node);
1960 return (result);
1964 * Delete expired RRsigs and any RRsigs we are about to re-sign.
1965 * See also zone.c:del_sigs().
1967 static isc_result_t
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;
1975 unsigned int i;
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)
1985 goto failure;
1986 result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
1987 dns_rdatatype_dnskey, (isc_stdtime_t) 0,
1988 &rdataset, NULL);
1989 dns_db_detachnode(db, &node);
1991 if (result == ISC_R_NOTFOUND)
1992 return (ISC_R_SUCCESS);
1993 if (result != ISC_R_SUCCESS)
1994 goto failure;
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);
2002 found = ISC_FALSE;
2003 for (i = 0; i < nkeys; i++) {
2004 if (rrsig.keyid == dst_key_id(keys[i])) {
2005 found = ISC_TRUE;
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.
2012 break;
2014 result = update_one_rr(db, ver, diff,
2015 DNS_DIFFOP_DEL, name,
2016 rdataset.ttl, &rdata);
2017 break;
2021 * If there is not a matching DNSKEY then delete the RRSIG.
2023 if (!found)
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)
2028 break;
2030 dns_rdataset_disassociate(&rdataset);
2031 if (result == ISC_R_NOMORE)
2032 result = ISC_R_SUCCESS;
2033 failure:
2034 if (node != NULL)
2035 dns_db_detachnode(db, &node);
2036 return (result);
2039 static isc_result_t
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;
2047 dns_dbnode_t *node;
2048 dns_rdatasetiter_t *iter;
2050 node = NULL;
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)
2055 return (result);
2057 iter = NULL;
2058 result = dns_db_allrdatasets(db, node, ver,
2059 (isc_stdtime_t) 0, &iter);
2060 if (result != ISC_R_SUCCESS)
2061 goto cleanup_node;
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;
2069 isc_boolean_t flag;
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))
2082 continue;
2083 result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
2084 type, &flag);
2085 if (result != ISC_R_SUCCESS)
2086 goto cleanup_iterator;
2087 if (flag)
2088 continue;;
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;
2098 cleanup_iterator:
2099 dns_rdatasetiter_destroy(&iter);
2101 cleanup_node:
2102 dns_db_detachnode(db, &node);
2104 return (result);
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.
2118 static isc_result_t
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;
2124 dns_difftuple_t *t;
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;
2133 unsigned int i;
2134 isc_stdtime_t now, inception, expire;
2135 dns_ttl_t nsecttl;
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;
2142 isc_boolean_t cut;
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");
2158 goto failure;
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
2169 * and one doesn't.
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);
2198 while (t != NULL) {
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)
2215 goto skip;
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,
2226 zone_keys, nkeys);
2227 else
2228 CHECK(delete_if(true_p, db, newver, name,
2229 dns_rdatatype_rrsig, type,
2230 NULL, &sig_diff));
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));
2237 if (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));
2243 skip:
2244 /* Skip any other updates to the same RRset. */
2245 while (t != NULL &&
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);
2257 t != NULL;
2258 t = ISC_LIST_NEXT(t, link))
2260 CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag));
2261 if (! flag) {
2262 CHECK(delete_if(true_p, db, newver, &t->name,
2263 dns_rdatatype_any, 0,
2264 NULL, &sig_diff));
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,
2274 &build_nsec3));
2275 if (!build_nsec)
2276 goto update_nsec3;
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);
2285 t != NULL;
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)
2298 continue;
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
2318 * removing one).
2320 for (t = ISC_LIST_HEAD(diffnames.tuples);
2321 t != NULL;
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,
2328 &ns_existed));
2329 CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_dname, 0,
2330 &dname_existed));
2331 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0,
2332 &ns_exists));
2333 CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0,
2334 &dname_exists));
2335 if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
2336 continue;
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
2354 * the NSEC chain.
2356 for (t = ISC_LIST_HEAD(affected.tuples);
2357 t != NULL;
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));
2364 if (! exists)
2365 continue;
2366 CHECK(is_active(db, newver, name, &flag, &cut, NULL));
2367 if (!flag) {
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,
2374 NULL, &nsec_diff));
2375 CHECK(delete_if(rrsig_p, db, newver, name,
2376 dns_rdatatype_any, 0, NULL, diff));
2377 } else {
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,
2389 &flag));
2390 if (!flag)
2391 CHECK(add_placeholder_nsec(db, newver,
2392 name, diff));
2394 CHECK(add_exposed_sigs(client, zone, db, newver, name,
2395 cut, diff, zone_keys, nkeys,
2396 inception, expire, check_ksk,
2397 keyset_kskonly));
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);
2406 t != NULL;
2407 t = ISC_LIST_NEXT(t, link))
2409 CHECK(rrset_exists(db, newver, &t->name,
2410 dns_rdatatype_nsec, 0, &flag));
2411 if (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,
2417 * IXFRs, etc.
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);
2448 t != NULL;
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,
2454 NULL, &sig_diff));
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));
2460 } else {
2461 INSIST(0);
2465 update_nsec3:
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));
2481 if (!build_nsec3) {
2482 update_log(client, zone, ISC_LOG_DEBUG(3),
2483 "no NSEC3 chains to rebuild");
2484 goto failure;
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
2497 * removing one).
2499 t = ISC_LIST_HEAD(diff->tuples);
2500 while (t != NULL) {
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);
2510 continue;
2513 CHECK(namelist_append_name(&affected, name));
2515 CHECK(rrset_exists(db, oldver, name, dns_rdatatype_ns, 0,
2516 &ns_existed));
2517 CHECK(rrset_exists(db, oldver, name, dns_rdatatype_dname, 0,
2518 &dname_existed));
2519 CHECK(rrset_exists(db, newver, name, dns_rdatatype_ns, 0,
2520 &ns_exists));
2521 CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0,
2522 &dname_exists));
2524 exists = ns_exists || dname_exists;
2525 existed = ns_existed || dname_existed;
2526 if (exists == existed)
2527 goto nextname;
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));
2534 nextname:
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);
2540 t != NULL;
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));
2547 if (!flag) {
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));
2552 } else {
2553 CHECK(add_exposed_sigs(client, zone, db, newver, name,
2554 cut, diff, zone_keys, nkeys,
2555 inception, expire, check_ksk,
2556 keyset_kskonly));
2557 CHECK(dns_nsec3_addnsec3sx(db, newver, name, nsecttl,
2558 unsecure, privatetype,
2559 &nsec_diff));
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);
2578 t != NULL;
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,
2585 NULL, &sig_diff));
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,
2591 keyset_kskonly));
2592 } else {
2593 INSIST(0);
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));
2611 failure:
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]);
2622 return (result);
2626 /**************************************************************************/
2628 * The actual update code in all its glory. We try to follow
2629 * the RFC2136 pseudocode as closely as possible.
2632 static isc_result_t
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));
2642 if (event == NULL)
2643 FAIL(ISC_R_NOMEMORY);
2644 event->zone = zone;
2645 event->result = ISC_R_SUCCESS;
2647 evclient = NULL;
2648 ns_client_attach(client, &evclient);
2649 INSIST(client->nupdates == 0);
2650 client->nupdates++;
2651 event->ev_arg = evclient;
2653 dns_zone_gettask(zone, &zonetask);
2654 isc_task_send(zonetask, ISC_EVENT_PTR(&event));
2656 failure:
2657 if (event != NULL)
2658 isc_event_free(ISC_EVENT_PTR(&event));
2659 return (result);
2662 static void
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)
2668 goto msg_failure;
2669 client->message->rcode = dns_result_torcode(result);
2671 ns_client_send(client);
2672 return;
2674 msg_failure:
2675 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
2676 ISC_LOG_ERROR,
2677 "could not create update response message: %s",
2678 isc_result_totext(msg_result));
2679 ns_client_next(client, msg_result);
2682 void
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.
2701 zonename = NULL;
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,
2718 &zone);
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)
2729 FAIL(sigresult);
2730 CHECK(send_update_event(client, zone));
2731 break;
2732 case dns_zone_slave:
2733 CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
2734 "update forwarding", zonename, ISC_TRUE,
2735 ISC_FALSE));
2736 CHECK(send_forward_event(client, zone));
2737 break;
2738 default:
2739 FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
2741 return;
2743 failure:
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);
2754 if (zone != NULL)
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".
2764 static isc_result_t
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);
2774 tupple != NULL;
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)))
2780 continue;
2781 CHECK(rrset_exists(db, newver, &tupple->name,
2782 dns_rdatatype_ns, 0, &ns_exists));
2783 if (ns_exists &&
2784 !dns_name_equal(&tupple->name, dns_db_origin(db)))
2785 continue;
2786 CHECK(delete_if(true_p, db, newver, &tupple->name,
2787 dns_rdatatype_ds, 0, NULL, &temp_diff));
2789 result = ISC_R_SUCCESS;
2791 failure:
2792 for (tupple = ISC_LIST_HEAD(temp_diff.tuples);
2793 tupple != NULL;
2794 tupple = ISC_LIST_HEAD(temp_diff.tuples)) {
2795 ISC_LIST_UNLINK(temp_diff.tuples, tupple, link);
2796 dns_diff_appendminimal(diff, &tupple);
2798 return (result);
2802 * This implements the post load integrity checks for mx records.
2804 static isc_result_t
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];
2812 dns_difftuple_t *t;
2813 dns_fixedname_t fixed;
2814 dns_name_t *foundname;
2815 dns_rdata_mx_t mx;
2816 dns_rdata_t rdata;
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);
2830 t != NULL;
2831 t = ISC_LIST_NEXT(t, link)) {
2832 if (t->op != DNS_DIFFOP_ADD ||
2833 t->rdata.type != dns_rdatatype_mx)
2834 continue;
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
2840 * zone.
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,
2856 "%s/MX: '%s': %s",
2857 ownerbuf, namebuf,
2858 dns_result_totext(DNS_R_MXISADDRESS));
2859 ok = ISC_FALSE;
2860 } else if (isaddress) {
2861 update_log(client, zone, ISC_LOG_WARNING,
2862 "%s/MX: warning: '%s': %s",
2863 ownerbuf, namebuf,
2864 dns_result_totext(DNS_R_MXISADDRESS));
2868 * Check zone integrity checks.
2870 if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0)
2871 continue;
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)
2875 continue;
2877 if (result == DNS_R_NXRRSET) {
2878 result = dns_db_find(db, &mx.mx, newver,
2879 dns_rdatatype_aaaa,
2880 0, 0, NULL, foundname,
2881 NULL, NULL);
2882 if (result == ISC_R_SUCCESS)
2883 continue;
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);
2890 ok = ISC_FALSE;
2891 } else if (result == DNS_R_CNAME) {
2892 update_log(client, zone, ISC_LOG_ERROR,
2893 "%s/MX '%s' is a CNAME (illegal)",
2894 ownerbuf, namebuf);
2895 ok = ISC_FALSE;
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);
2901 ok = ISC_FALSE;
2904 return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
2907 static isc_result_t
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));
2918 else
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) {
2923 *flag = ISC_FALSE;
2924 result = ISC_R_SUCCESS;
2925 goto failure;
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))
2934 break;
2936 dns_rdataset_disassociate(&rdataset);
2937 if (result == ISC_R_SUCCESS) {
2938 *flag = ISC_TRUE;
2939 } else if (result == ISC_R_NOMORE) {
2940 *flag = ISC_FALSE;
2941 result = ISC_R_SUCCESS;
2944 failure:
2945 if (node != NULL)
2946 dns_db_detachnode(db, &node);
2947 return (result);
2950 static isc_result_t
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)
2964 return (result);
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)
2968 goto try_private;
2969 if (result != ISC_R_SUCCESS)
2970 goto failure;
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)
2979 continue;
2980 if (nsec3param.iterations > iterations)
2981 iterations = nsec3param.iterations;
2983 if (result != ISC_R_NOMORE)
2984 goto failure;
2986 dns_rdataset_disassociate(&rdataset);
2988 try_private:
2989 if (privatetype == 0)
2990 goto success;
2992 result = dns_db_findrdataset(db, node, ver, privatetype,
2993 0, (isc_stdtime_t) 0, &rdataset, NULL);
2994 if (result == ISC_R_NOTFOUND)
2995 goto success;
2996 if (result != ISC_R_SUCCESS)
2997 goto failure;
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,
3008 buf, sizeof(buf)))
3009 continue;
3010 CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
3011 if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
3012 continue;
3013 if (nsec3param.iterations > iterations)
3014 iterations = nsec3param.iterations;
3016 if (result != ISC_R_NOMORE)
3017 goto failure;
3019 success:
3020 *iterationsp = iterations;
3021 result = ISC_R_SUCCESS;
3023 failure:
3024 if (node != NULL)
3025 dns_db_detachnode(db, &node);
3026 if (dns_rdataset_isassociated(&rdataset))
3027 dns_rdataset_disassociate(&rdataset);
3028 return (result);
3032 * Prevent the zone entering a inconsistent state where
3033 * NSEC only DNSKEYs are present with NSEC3 chains.
3035 static isc_result_t
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;
3040 dns_diffop_t op;
3041 dns_difftuple_t *tuple, *newtuple = NULL, *next;
3042 isc_boolean_t flag;
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));
3051 if (flag)
3052 CHECK(dns_nsec3_activex(db, ver, ISC_FALSE,
3053 privatetype, &flag));
3054 if (flag) {
3055 update_log(client, zone, ISC_LOG_WARNING,
3056 "NSEC only DNSKEYs and NSEC3 chains not allowed");
3057 } else {
3058 CHECK(get_iterations(db, ver, privatetype, &iterations));
3059 CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
3060 if (max != 0 && iterations > max) {
3061 flag = ISC_TRUE;
3062 update_log(client, zone, ISC_LOG_WARNING,
3063 "too many NSEC3 iterations (%u) for "
3064 "weakest DNSKEY (%u)", iterations, max);
3067 if (flag) {
3068 for (tuple = ISC_LIST_HEAD(diff->tuples);
3069 tuple != NULL;
3070 tuple = next) {
3071 next = ISC_LIST_NEXT(tuple, link);
3072 if (tuple->rdata.type != dns_rdatatype_dnskey &&
3073 tuple->rdata.type != dns_rdatatype_nsec3param)
3074 continue;
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);
3084 tuple != NULL;
3085 tuple = ISC_LIST_HEAD(temp_diff.tuples)) {
3086 ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
3087 dns_diff_appendminimal(diff, &tuple);
3092 failure:
3093 dns_diff_clear(&temp_diff);
3094 return (result);
3098 * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
3100 static isc_result_t
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;
3109 dns_diffop_t op;
3110 isc_boolean_t flag;
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);
3123 tuple != NULL;
3124 tuple = next) {
3126 next = ISC_LIST_NEXT(tuple, link);
3128 if (tuple->rdata.type != dns_rdatatype_nsec3param ||
3129 !dns_name_equal(name, &tuple->name))
3130 continue;
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] ||
3144 /* Ignore flags. */
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],
3149 tuple_data[4])) {
3150 next = ISC_LIST_NEXT(next, link);
3151 continue;
3153 op = (next->op == DNS_DIFFOP_DEL) ?
3154 DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
3155 CHECK(dns_difftuple_create(diff->mctx, op,
3156 name, next->ttl,
3157 &next->rdata,
3158 &newtuple));
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));
3177 if (!flag) {
3178 CHECK(dns_difftuple_create(diff->mctx,
3179 DNS_DIFFOP_ADD,
3180 name, tuple->ttl,
3181 &rdata,
3182 &newtuple));
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,
3190 name, tuple->ttl,
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);
3197 } else
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,
3212 &newtuple));
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));
3234 if (!flag) {
3235 CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
3236 name, tuple->ttl, &rdata,
3237 &newtuple));
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,
3242 &newtuple));
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;
3250 failure:
3251 dns_diff_clear(&temp_diff);
3252 return (result);
3255 static isc_result_t
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;
3260 dns_diffop_t op;
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);
3275 tuple != NULL;
3276 tuple = next) {
3278 next = ISC_LIST_NEXT(tuple, link);
3280 if (tuple->rdata.type != privatetype ||
3281 !dns_name_equal(name, &tuple->name))
3282 continue;
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)
3292 continue;
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;
3310 failure:
3311 dns_diff_clear(&temp_diff);
3312 return (result);
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.
3319 static isc_result_t
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;
3326 isc_boolean_t flag;
3327 isc_region_t r;
3328 isc_result_t result = ISC_R_SUCCESS;
3329 isc_uint16_t keyid;
3330 unsigned char buf[5];
3331 dns_name_t *name = dns_db_origin(db);
3333 for (tuple = ISC_LIST_HEAD(diff->tuples);
3334 tuple != NULL;
3335 tuple = ISC_LIST_NEXT(tuple, link)) {
3336 if (tuple->rdata.type != dns_rdatatype_dnskey)
3337 continue;
3339 dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
3340 if ((dnskey.flags &
3341 (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
3342 != DNS_KEYOWNER_ZONE)
3343 continue;
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;
3353 buf[4] = 0;
3354 rdata.data = buf;
3355 rdata.length = sizeof(buf);
3356 rdata.type = privatetype;
3357 rdata.rdclass = tuple->rdata.rdclass;
3359 CHECK(rr_exists(db, ver, name, &rdata, &flag));
3360 if (flag)
3361 continue;
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
3368 * completed.
3370 buf[4] = 1;
3371 CHECK(rr_exists(db, ver, name, &rdata, &flag));
3372 if (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);
3379 failure:
3380 return (result);
3384 * Mark all NSEC3 chains for deletion without creating a NSEC chain as
3385 * a side effect of deleting the last chain.
3387 static isc_result_t
3388 delete_chains(dns_db_t *db, dns_dbversion_t *ver, dns_zone_t *zone,
3389 dns_diff_t *diff)
3391 dns_dbnode_t *node = NULL;
3392 dns_difftuple_t *tuple = NULL;
3393 dns_name_t next;
3394 dns_rdata_t rdata = DNS_RDATA_INIT;
3395 dns_rdataset_t rdataset;
3396 isc_boolean_t flag;
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)
3407 return (result);
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)
3415 goto try_private;
3416 if (result != ISC_R_SUCCESS)
3417 goto failure;
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,
3432 buf, sizeof(buf));
3433 buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
3435 CHECK(rr_exists(db, ver, origin, &rdata, &flag));
3437 if (!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)
3446 goto failure;
3448 dns_rdataset_disassociate(&rdataset);
3450 try_private:
3451 if (privatetype == 0)
3452 goto success;
3453 result = dns_db_findrdataset(db, node, ver, privatetype, 0,
3454 (isc_stdtime_t) 0, &rdataset, NULL);
3455 if (result == ISC_R_NOTFOUND)
3456 goto success;
3457 if (result != ISC_R_SUCCESS)
3458 goto failure;
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);
3467 if (buf[0] != 0 ||
3468 buf[2] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) {
3469 dns_rdata_reset(&rdata);
3470 continue;
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));
3482 if (!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)
3491 goto failure;
3492 success:
3493 result = ISC_R_SUCCESS;
3495 failure:
3496 if (dns_rdataset_isassociated(&rdataset))
3497 dns_rdataset_disassociate(&rdataset);
3498 dns_db_detachnode(db, &node);
3499 return (result);
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))
3508 return (ISC_TRUE);
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);
3516 static void
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;
3578 dns_ttl_t ttl;
3579 dns_rdataclass_t update_class;
3580 isc_boolean_t flag;
3582 get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
3583 &name, &rdata, &covers, &ttl, &update_class);
3585 if (ttl != 0)
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));
3600 if (! flag) {
3601 PREREQFAILN(DNS_R_NXDOMAIN, name,
3602 "'name in use' "
3603 "prerequisite not "
3604 "satisfied");
3606 } else {
3607 CHECK(rrset_exists(db, ver, name,
3608 rdata.type, covers, &flag));
3609 if (! 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));
3623 if (flag) {
3624 PREREQFAILN(DNS_R_YXDOMAIN, name,
3625 "'name not in use' "
3626 "prerequisite not "
3627 "satisfied");
3629 } else {
3630 CHECK(rrset_exists(db, ver, name,
3631 rdata.type, covers, &flag));
3632 if (flag) {
3633 /* RRset exists. */
3634 PREREQFAILNT(DNS_R_YXRRSET, name,
3635 rdata.type,
3636 "'rrset does not exist' "
3637 "prerequisite not "
3638 "satisfied");
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);
3650 } else {
3651 PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite");
3654 if (result != ISC_R_NOMORE)
3655 FAIL(result);
3658 * Perform the final check of the "rrset exists (value dependent)"
3659 * prerequisites.
3661 if (ISC_LIST_HEAD(temp.tuples) != NULL) {
3662 dns_rdatatype_t type;
3665 * Sort the prerequisite records by owner name,
3666 * type, and rdata.
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;
3712 dns_ttl_t ttl;
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) {
3740 if (ttl != 0 ||
3741 dns_rdatatype_ismeta(rdata.type))
3742 FAILC(DNS_R_FORMERR,
3743 "meta-RR in update");
3744 } else {
3745 update_log(client, zone, ISC_LOG_WARNING,
3746 "update RR has incorrect class %d",
3747 update_class);
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 "
3759 "in secure zones");
3760 } else if (rdata.type == dns_rdatatype_nsec) {
3761 FAILC(DNS_R_REFUSED,
3762 "explicit NSEC updates are not allowed "
3763 "in secure zones");
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 "
3769 "at the apex");
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,
3782 &client->peeraddr);
3783 tcpaddr = &netaddr;
3784 } else
3785 tcpaddr = NULL;
3786 if (rdata.type != dns_rdatatype_any) {
3787 if (!dns_ssutable_checkrules(ssutable,
3788 client->signer,
3789 name, tcpaddr,
3790 rdata.type))
3791 FAILC(DNS_R_REFUSED,
3792 "rejected by secure update");
3793 } else {
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)
3802 FAIL(result);
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;
3818 dns_ttl_t ttl;
3819 dns_rdataclass_t update_class;
3820 isc_boolean_t flag;
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,
3834 sizeof(typebuf));
3835 update_log(client, zone, LOGLEVEL_PROTOCOL,
3836 "attempt to add %s ignored",
3837 typebuf);
3838 continue;
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,
3846 sizeof(typebuf));
3847 update_log(client, zone,
3848 LOGLEVEL_PROTOCOL,
3849 "attempt to add wildcard %s record "
3850 "ignored", typebuf);
3851 continue;
3853 if (rdata.type == dns_rdatatype_cname) {
3854 CHECK(cname_incompatible_rrset_exists(db, ver,
3855 name,
3856 &flag));
3857 if (flag) {
3858 update_log(client, zone,
3859 LOGLEVEL_PROTOCOL,
3860 "attempt to add CNAME "
3861 "alongside non-CNAME "
3862 "ignored");
3863 continue;
3865 } else {
3866 CHECK(rrset_exists(db, ver, name,
3867 dns_rdatatype_cname, 0,
3868 &flag));
3869 if (flag &&
3870 ! dns_rdatatype_isdnssec(rdata.type))
3872 update_log(client, zone,
3873 LOGLEVEL_PROTOCOL,
3874 "attempt to add non-CNAME "
3875 "alongside CNAME ignored");
3876 continue;
3879 if (rdata.type == dns_rdatatype_soa) {
3880 isc_boolean_t ok;
3881 CHECK(rrset_exists(db, ver, name,
3882 dns_rdatatype_soa, 0,
3883 &flag));
3884 if (! flag) {
3885 update_log(client, zone,
3886 LOGLEVEL_PROTOCOL,
3887 "attempt to create 2nd "
3888 "SOA ignored");
3889 continue;
3891 CHECK(check_soa_increment(db, ver, &rdata,
3892 &ok));
3893 if (! ok) {
3894 update_log(client, zone,
3895 LOGLEVEL_PROTOCOL,
3896 "SOA update failed to "
3897 "increment serial, "
3898 "ignoring it");
3899 continue;
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);
3909 continue;
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,
3919 LOGLEVEL_PROTOCOL,
3920 "attempt to add NSEC3PARAM "
3921 "record with non OPTOUT "
3922 "flag");
3923 continue;
3927 * NSEC3CHAIN creation flag.
3929 INSIST(rdata.length <= sizeof(buf));
3930 memcpy(buf, rdata.data, rdata.length);
3931 buf[1] |= DNS_NSEC3FLAG_UPDATE;
3932 rdata.data = buf;
3935 * Force the TTL to zero for NSEC3PARAM records.
3937 ttl = 0;
3940 if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
3941 dns_name_internalwildcard(name)) {
3942 char namestr[DNS_NAME_FORMATSIZE];
3943 dns_name_format(name, namestr,
3944 sizeof(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,
3954 sizeof(namestr));
3955 dns_rdatatype_format(rdata.type, typestr,
3956 sizeof(typestr));
3957 update_log(client, zone, LOGLEVEL_PROTOCOL,
3958 "adding an RR at '%s' %s",
3959 namestr, typestr);
3962 /* Prepare the affected RRset for the addition. */
3964 add_rr_prepare_ctx_t ctx;
3965 ctx.db = db;
3966 ctx.ver = ver;
3967 ctx.diff = &diff;
3968 ctx.name = name;
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,
3976 &ctx));
3978 if (ctx.ignore_add) {
3979 dns_diff_clear(&ctx.del_diff);
3980 dns_diff_clear(&ctx.add_diff);
3981 } else {
3982 CHECK(do_diff(&ctx.del_diff, db, ver,
3983 &diff));
3984 CHECK(do_diff(&ctx.add_diff, db, ver,
3985 &diff));
3986 CHECK(update_one_rr(db, ver, &diff,
3987 DNS_DIFFOP_ADD,
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,
3994 LOGLEVEL_PROTOCOL))
3996 char namestr[DNS_NAME_FORMATSIZE];
3997 dns_name_format(name, namestr,
3998 sizeof(namestr));
3999 update_log(client, zone,
4000 LOGLEVEL_PROTOCOL,
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,
4006 db, ver, name,
4007 dns_rdatatype_any, 0,
4008 &rdata, &diff));
4009 } else {
4010 CHECK(delete_if(type_not_dnssec,
4011 db, ver, name,
4012 dns_rdatatype_any, 0,
4013 &rdata, &diff));
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");
4021 continue;
4022 } else {
4023 if (isc_log_wouldlog(ns_g_lctx,
4024 LOGLEVEL_PROTOCOL))
4026 char namestr[DNS_NAME_FORMATSIZE];
4027 char typestr[DNS_RDATATYPE_FORMATSIZE];
4028 dns_name_format(name, namestr,
4029 sizeof(namestr));
4030 dns_rdatatype_format(rdata.type,
4031 typestr,
4032 sizeof(typestr));
4033 update_log(client, zone,
4034 LOGLEVEL_PROTOCOL,
4035 "deleting rrset at '%s' %s",
4036 namestr, typestr);
4038 CHECK(delete_if(true_p, db, ver, name,
4039 rdata.type, covers, &rdata,
4040 &diff));
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,
4053 LOGLEVEL_PROTOCOL,
4054 "attempt to delete SOA "
4055 "ignored");
4056 continue;
4058 if (rdata.type == dns_rdatatype_ns) {
4059 int count;
4060 CHECK(rr_count(db, ver, name,
4061 dns_rdatatype_ns,
4062 0, &count));
4063 if (count == 1) {
4064 update_log(client, zone,
4065 LOGLEVEL_PROTOCOL,
4066 "attempt to "
4067 "delete last "
4068 "NS ignored");
4069 continue;
4073 dns_name_format(name, namestr, sizeof(namestr));
4074 dns_rdatatype_format(rdata.type, typestr,
4075 sizeof(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)
4083 FAIL(result);
4086 * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
4087 * If they don't then back out all changes to DNSKEY/NSEC3PARAM
4088 * records.
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));
4096 if (errors != 0) {
4097 update_log(client, zone, LOGLEVEL_PROTOCOL,
4098 "update rejected: post update name server "
4099 "sanity check failed");
4100 result = DNS_R_REFUSED;
4101 goto failure;
4106 * If any changes were made, increment the SOA serial number,
4107 * update RRSIGs and NSECs (if zone is secure), and write the update
4108 * to the journal.
4110 if (! ISC_LIST_EMPTY(diff.tuples)) {
4111 char *journalfile;
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,
4128 0, &has_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,
4136 &had_dnskey));
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' "
4142 "not set");
4143 result = DNS_R_REFUSED;
4144 goto failure;
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));
4154 if (!has_dnskey) {
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,
4169 ISC_LOG_ERROR,
4170 "RRSIG/NSEC/NSEC3 update failed: %s",
4171 isc_result_totext(result));
4172 goto failure;
4176 journalfile = dns_zone_getjournal(zone);
4177 if (journalfile != NULL) {
4178 update_log(client, zone, LOGLEVEL_DEBUG,
4179 "writing journal %s", journalfile);
4181 journal = NULL;
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
4219 * deleted.
4221 * Note: we are already committed to this course of action.
4223 for (tuple = ISC_LIST_HEAD(diff.tuples);
4224 tuple != NULL;
4225 tuple = ISC_LIST_NEXT(tuple, link)) {
4226 isc_region_t r;
4227 dns_secalg_t algorithm;
4228 isc_uint16_t keyid;
4230 if (tuple->rdata.type != dns_rdatatype_dnskey)
4231 continue;
4233 dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
4234 if ((dnskey.flags &
4235 (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
4236 != DNS_KEYOWNER_ZONE)
4237 continue;
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);
4259 tuple != NULL;
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)
4267 continue;
4269 if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
4270 buf, sizeof(buf)))
4271 continue;
4272 dns_rdata_tostruct(&rdata, &nsec3param, NULL);
4273 if (nsec3param.flags == 0)
4274 continue;
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));
4283 } else {
4284 update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
4285 dns_db_closeversion(db, &ver, ISC_TRUE);
4287 result = ISC_R_SUCCESS;
4288 goto common;
4290 failure:
4292 * The reason for failure should have been logged at this point.
4294 if (ver != NULL) {
4295 update_log(client, zone, LOGLEVEL_DEBUG,
4296 "rolling back");
4297 dns_db_closeversion(db, &ver, ISC_FALSE);
4300 common:
4301 dns_diff_clear(&temp);
4302 dns_diff_clear(&diff);
4304 if (oldver != NULL)
4305 dns_db_closeversion(db, &oldver, ISC_FALSE);
4307 if (db != NULL)
4308 dns_db_detach(&db);
4310 if (ssutable != NULL)
4311 dns_ssutable_detach(&ssutable);
4313 isc_task_detach(&task);
4314 uev->result = result;
4315 if (zone != NULL)
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);
4323 static void
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;
4328 UNUSED(task);
4330 INSIST(event->ev_type == DNS_EVENT_UPDATEDONE);
4331 INSIST(task == client->task);
4333 INSIST(client->nupdates > 0);
4334 switch (uev->result) {
4335 case ISC_R_SUCCESS:
4336 inc_stats(uev->zone, dns_nsstatscounter_updatedone);
4337 break;
4338 case DNS_R_REFUSED:
4339 inc_stats(uev->zone, dns_nsstatscounter_updaterej);
4340 break;
4341 default:
4342 inc_stats(uev->zone, dns_nsstatscounter_updatefail);
4343 break;
4345 if (uev->zone != NULL)
4346 dns_zone_detach(&uev->zone);
4347 client->nupdates--;
4348 respond(client, uev->result);
4349 isc_event_free(&event);
4350 ns_client_detach(&client);
4354 * Update forwarding support.
4357 static void
4358 forward_fail(isc_task_t *task, isc_event_t *event) {
4359 ns_client_t *client = (ns_client_t *)event->ev_arg;
4361 UNUSED(task);
4363 INSIST(client->nupdates > 0);
4364 client->nupdates--;
4365 respond(client, DNS_R_SERVFAIL);
4366 isc_event_free(&event);
4367 ns_client_detach(&client);
4371 static void
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);
4382 } else {
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);
4392 static void
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;
4397 UNUSED(task);
4399 INSIST(client->nupdates > 0);
4400 client->nupdates--;
4401 ns_client_sendraw(client, uev->answer);
4402 dns_message_destroy(&uev->answer);
4403 isc_event_free(&event);
4404 ns_client_detach(&client);
4407 static void
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);
4422 } else
4423 inc_stats(zone, dns_nsstatscounter_updatereqfwd);
4424 isc_task_detach(&task);
4427 static isc_result_t
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));
4437 if (event == NULL)
4438 FAIL(ISC_R_NOMEMORY);
4439 event->zone = zone;
4440 event->result = ISC_R_SUCCESS;
4442 evclient = NULL;
4443 ns_client_attach(client, &evclient);
4444 INSIST(client->nupdates == 0);
4445 client->nupdates++;
4446 event->ev_arg = evclient;
4448 dns_zone_gettask(zone, &zonetask);
4449 isc_task_send(zonetask, ISC_EVENT_PTR(&event));
4451 failure:
4452 if (event != NULL)
4453 isc_event_free(ISC_EVENT_PTR(&event));
4454 return (result);