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