xref: /minix3/external/bsd/bind/dist/lib/dns/update.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: update.c,v 1.4 2014/12/10 04:37:58 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2011-2013  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  *
6*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek  *
10*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek  */
18*00b67f09SDavid van Moolenbroek 
19*00b67f09SDavid van Moolenbroek /* Id */
20*00b67f09SDavid van Moolenbroek 
21*00b67f09SDavid van Moolenbroek #include <config.h>
22*00b67f09SDavid van Moolenbroek 
23*00b67f09SDavid van Moolenbroek #include <isc/log.h>
24*00b67f09SDavid van Moolenbroek #include <isc/netaddr.h>
25*00b67f09SDavid van Moolenbroek #include <isc/print.h>
26*00b67f09SDavid van Moolenbroek #include <isc/serial.h>
27*00b67f09SDavid van Moolenbroek #include <isc/stats.h>
28*00b67f09SDavid van Moolenbroek #include <isc/stdtime.h>
29*00b67f09SDavid van Moolenbroek #include <isc/string.h>
30*00b67f09SDavid van Moolenbroek #include <isc/taskpool.h>
31*00b67f09SDavid van Moolenbroek #include <isc/util.h>
32*00b67f09SDavid van Moolenbroek 
33*00b67f09SDavid van Moolenbroek #include <dns/db.h>
34*00b67f09SDavid van Moolenbroek #include <dns/dbiterator.h>
35*00b67f09SDavid van Moolenbroek #include <dns/diff.h>
36*00b67f09SDavid van Moolenbroek #include <dns/dnssec.h>
37*00b67f09SDavid van Moolenbroek #include <dns/events.h>
38*00b67f09SDavid van Moolenbroek #include <dns/fixedname.h>
39*00b67f09SDavid van Moolenbroek #include <dns/journal.h>
40*00b67f09SDavid van Moolenbroek #include <dns/keyvalues.h>
41*00b67f09SDavid van Moolenbroek #include <dns/log.h>
42*00b67f09SDavid van Moolenbroek #include <dns/message.h>
43*00b67f09SDavid van Moolenbroek #include <dns/nsec.h>
44*00b67f09SDavid van Moolenbroek #include <dns/nsec3.h>
45*00b67f09SDavid van Moolenbroek #include <dns/private.h>
46*00b67f09SDavid van Moolenbroek #include <dns/rdataclass.h>
47*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
48*00b67f09SDavid van Moolenbroek #include <dns/rdatasetiter.h>
49*00b67f09SDavid van Moolenbroek #include <dns/rdatastruct.h>
50*00b67f09SDavid van Moolenbroek #include <dns/rdatatype.h>
51*00b67f09SDavid van Moolenbroek #include <dns/result.h>
52*00b67f09SDavid van Moolenbroek #include <dns/soa.h>
53*00b67f09SDavid van Moolenbroek #include <dns/ssu.h>
54*00b67f09SDavid van Moolenbroek #include <dns/tsig.h>
55*00b67f09SDavid van Moolenbroek #include <dns/update.h>
56*00b67f09SDavid van Moolenbroek #include <dns/view.h>
57*00b67f09SDavid van Moolenbroek #include <dns/zone.h>
58*00b67f09SDavid van Moolenbroek #include <dns/zt.h>
59*00b67f09SDavid van Moolenbroek 
60*00b67f09SDavid van Moolenbroek 
61*00b67f09SDavid van Moolenbroek /**************************************************************************/
62*00b67f09SDavid van Moolenbroek 
63*00b67f09SDavid van Moolenbroek /*%
64*00b67f09SDavid van Moolenbroek  * Log level for tracing dynamic update protocol requests.
65*00b67f09SDavid van Moolenbroek  */
66*00b67f09SDavid van Moolenbroek #define LOGLEVEL_PROTOCOL	ISC_LOG_INFO
67*00b67f09SDavid van Moolenbroek 
68*00b67f09SDavid van Moolenbroek /*%
69*00b67f09SDavid van Moolenbroek  * Log level for low-level debug tracing.
70*00b67f09SDavid van Moolenbroek  */
71*00b67f09SDavid van Moolenbroek #define LOGLEVEL_DEBUG		ISC_LOG_DEBUG(8)
72*00b67f09SDavid van Moolenbroek 
73*00b67f09SDavid van Moolenbroek /*%
74*00b67f09SDavid van Moolenbroek  * Check an operation for failure.  These macros all assume that
75*00b67f09SDavid van Moolenbroek  * the function using them has a 'result' variable and a 'failure'
76*00b67f09SDavid van Moolenbroek  * label.
77*00b67f09SDavid van Moolenbroek  */
78*00b67f09SDavid van Moolenbroek #define CHECK(op) \
79*00b67f09SDavid van Moolenbroek 	do { result = (op); \
80*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) goto failure; \
81*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
82*00b67f09SDavid van Moolenbroek 
83*00b67f09SDavid van Moolenbroek /*%
84*00b67f09SDavid van Moolenbroek  * Fail unconditionally with result 'code', which must not
85*00b67f09SDavid van Moolenbroek  * be ISC_R_SUCCESS.  The reason for failure presumably has
86*00b67f09SDavid van Moolenbroek  * been logged already.
87*00b67f09SDavid van Moolenbroek  *
88*00b67f09SDavid van Moolenbroek  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
89*00b67f09SDavid van Moolenbroek  * from complaining about "end-of-loop code not reached".
90*00b67f09SDavid van Moolenbroek  */
91*00b67f09SDavid van Moolenbroek 
92*00b67f09SDavid van Moolenbroek #define FAIL(code) \
93*00b67f09SDavid van Moolenbroek 	do {							\
94*00b67f09SDavid van Moolenbroek 		result = (code);				\
95*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) goto failure;	\
96*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
97*00b67f09SDavid van Moolenbroek 
98*00b67f09SDavid van Moolenbroek /*%
99*00b67f09SDavid van Moolenbroek  * Fail unconditionally and log as a client error.
100*00b67f09SDavid van Moolenbroek  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
101*00b67f09SDavid van Moolenbroek  * from complaining about "end-of-loop code not reached".
102*00b67f09SDavid van Moolenbroek  */
103*00b67f09SDavid van Moolenbroek #define FAILC(code, msg) \
104*00b67f09SDavid van Moolenbroek 	do {							\
105*00b67f09SDavid van Moolenbroek 		const char *_what = "failed";			\
106*00b67f09SDavid van Moolenbroek 		result = (code);				\
107*00b67f09SDavid van Moolenbroek 		switch (result) {				\
108*00b67f09SDavid van Moolenbroek 		case DNS_R_NXDOMAIN:				\
109*00b67f09SDavid van Moolenbroek 		case DNS_R_YXDOMAIN:				\
110*00b67f09SDavid van Moolenbroek 		case DNS_R_YXRRSET:				\
111*00b67f09SDavid van Moolenbroek 		case DNS_R_NXRRSET:				\
112*00b67f09SDavid van Moolenbroek 			_what = "unsuccessful";			\
113*00b67f09SDavid van Moolenbroek 		}						\
114*00b67f09SDavid van Moolenbroek 		update_log(log, zone, LOGLEVEL_PROTOCOL,	\
115*00b67f09SDavid van Moolenbroek 			   "update %s: %s (%s)", _what,		\
116*00b67f09SDavid van Moolenbroek 			   msg, isc_result_totext(result));	\
117*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) goto failure;	\
118*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
119*00b67f09SDavid van Moolenbroek 
120*00b67f09SDavid van Moolenbroek #define FAILN(code, name, msg) \
121*00b67f09SDavid van Moolenbroek 	do {								\
122*00b67f09SDavid van Moolenbroek 		const char *_what = "failed";				\
123*00b67f09SDavid van Moolenbroek 		result = (code);					\
124*00b67f09SDavid van Moolenbroek 		switch (result) {					\
125*00b67f09SDavid van Moolenbroek 		case DNS_R_NXDOMAIN:					\
126*00b67f09SDavid van Moolenbroek 		case DNS_R_YXDOMAIN:					\
127*00b67f09SDavid van Moolenbroek 		case DNS_R_YXRRSET:					\
128*00b67f09SDavid van Moolenbroek 		case DNS_R_NXRRSET:					\
129*00b67f09SDavid van Moolenbroek 			_what = "unsuccessful";				\
130*00b67f09SDavid van Moolenbroek 		}							\
131*00b67f09SDavid van Moolenbroek 		if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) {	\
132*00b67f09SDavid van Moolenbroek 			char _nbuf[DNS_NAME_FORMATSIZE];		\
133*00b67f09SDavid van Moolenbroek 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
134*00b67f09SDavid van Moolenbroek 			update_log(log, zone, LOGLEVEL_PROTOCOL,	\
135*00b67f09SDavid van Moolenbroek 				   "update %s: %s: %s (%s)", _what, _nbuf, \
136*00b67f09SDavid van Moolenbroek 				   msg, isc_result_totext(result));	\
137*00b67f09SDavid van Moolenbroek 		}							\
138*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) goto failure;		\
139*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
140*00b67f09SDavid van Moolenbroek 
141*00b67f09SDavid van Moolenbroek #define FAILNT(code, name, type, msg) \
142*00b67f09SDavid van Moolenbroek 	do {								\
143*00b67f09SDavid van Moolenbroek 		const char *_what = "failed";				\
144*00b67f09SDavid van Moolenbroek 		result = (code);					\
145*00b67f09SDavid van Moolenbroek 		switch (result) {					\
146*00b67f09SDavid van Moolenbroek 		case DNS_R_NXDOMAIN:					\
147*00b67f09SDavid van Moolenbroek 		case DNS_R_YXDOMAIN:					\
148*00b67f09SDavid van Moolenbroek 		case DNS_R_YXRRSET:					\
149*00b67f09SDavid van Moolenbroek 		case DNS_R_NXRRSET:					\
150*00b67f09SDavid van Moolenbroek 			_what = "unsuccessful";				\
151*00b67f09SDavid van Moolenbroek 		}							\
152*00b67f09SDavid van Moolenbroek 		if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) {	\
153*00b67f09SDavid van Moolenbroek 			char _nbuf[DNS_NAME_FORMATSIZE];		\
154*00b67f09SDavid van Moolenbroek 			char _tbuf[DNS_RDATATYPE_FORMATSIZE];		\
155*00b67f09SDavid van Moolenbroek 			dns_name_format(name, _nbuf, sizeof(_nbuf));	\
156*00b67f09SDavid van Moolenbroek 			dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
157*00b67f09SDavid van Moolenbroek 			update_log(log, zone, LOGLEVEL_PROTOCOL,	\
158*00b67f09SDavid van Moolenbroek 				   "update %s: %s/%s: %s (%s)",		\
159*00b67f09SDavid van Moolenbroek 				   _what, _nbuf, _tbuf, msg,		\
160*00b67f09SDavid van Moolenbroek 				   isc_result_totext(result));		\
161*00b67f09SDavid van Moolenbroek 		}							\
162*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) goto failure;		\
163*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
164*00b67f09SDavid van Moolenbroek 
165*00b67f09SDavid van Moolenbroek /*%
166*00b67f09SDavid van Moolenbroek  * Fail unconditionally and log as a server error.
167*00b67f09SDavid van Moolenbroek  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
168*00b67f09SDavid van Moolenbroek  * from complaining about "end-of-loop code not reached".
169*00b67f09SDavid van Moolenbroek  */
170*00b67f09SDavid van Moolenbroek #define FAILS(code, msg) \
171*00b67f09SDavid van Moolenbroek 	do {							\
172*00b67f09SDavid van Moolenbroek 		result = (code);				\
173*00b67f09SDavid van Moolenbroek 		update_log(log, zone, LOGLEVEL_PROTOCOL,	\
174*00b67f09SDavid van Moolenbroek 			   "error: %s: %s",			\
175*00b67f09SDavid van Moolenbroek 			   msg, isc_result_totext(result));	\
176*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) goto failure;	\
177*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
178*00b67f09SDavid van Moolenbroek 
179*00b67f09SDavid van Moolenbroek /**************************************************************************/
180*00b67f09SDavid van Moolenbroek 
181*00b67f09SDavid van Moolenbroek typedef struct rr rr_t;
182*00b67f09SDavid van Moolenbroek 
183*00b67f09SDavid van Moolenbroek struct rr {
184*00b67f09SDavid van Moolenbroek 	/* dns_name_t name; */
185*00b67f09SDavid van Moolenbroek 	isc_uint32_t		ttl;
186*00b67f09SDavid van Moolenbroek 	dns_rdata_t		rdata;
187*00b67f09SDavid van Moolenbroek };
188*00b67f09SDavid van Moolenbroek 
189*00b67f09SDavid van Moolenbroek typedef struct update_event update_event_t;
190*00b67f09SDavid van Moolenbroek 
191*00b67f09SDavid van Moolenbroek /**************************************************************************/
192*00b67f09SDavid van Moolenbroek 
193*00b67f09SDavid van Moolenbroek static void
194*00b67f09SDavid van Moolenbroek update_log(dns_update_log_t *callback, dns_zone_t *zone,
195*00b67f09SDavid van Moolenbroek 	   int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
196*00b67f09SDavid van Moolenbroek 
197*00b67f09SDavid van Moolenbroek static void
update_log(dns_update_log_t * callback,dns_zone_t * zone,int level,const char * fmt,...)198*00b67f09SDavid van Moolenbroek update_log(dns_update_log_t *callback, dns_zone_t *zone,
199*00b67f09SDavid van Moolenbroek 	   int level, const char *fmt, ...)
200*00b67f09SDavid van Moolenbroek {
201*00b67f09SDavid van Moolenbroek 	va_list ap;
202*00b67f09SDavid van Moolenbroek 	char message[4096];
203*00b67f09SDavid van Moolenbroek 
204*00b67f09SDavid van Moolenbroek 	if (callback == NULL)
205*00b67f09SDavid van Moolenbroek 		return;
206*00b67f09SDavid van Moolenbroek 
207*00b67f09SDavid van Moolenbroek 	if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
208*00b67f09SDavid van Moolenbroek 		return;
209*00b67f09SDavid van Moolenbroek 
210*00b67f09SDavid van Moolenbroek 
211*00b67f09SDavid van Moolenbroek 	va_start(ap, fmt);
212*00b67f09SDavid van Moolenbroek 	vsnprintf(message, sizeof(message), fmt, ap);
213*00b67f09SDavid van Moolenbroek 	va_end(ap);
214*00b67f09SDavid van Moolenbroek 
215*00b67f09SDavid van Moolenbroek 	(callback->func)(callback->arg, zone, level, message);
216*00b67f09SDavid van Moolenbroek }
217*00b67f09SDavid van Moolenbroek 
218*00b67f09SDavid van Moolenbroek /*%
219*00b67f09SDavid van Moolenbroek  * Update a single RR in version 'ver' of 'db' and log the
220*00b67f09SDavid van Moolenbroek  * update in 'diff'.
221*00b67f09SDavid van Moolenbroek  *
222*00b67f09SDavid van Moolenbroek  * Ensures:
223*00b67f09SDavid van Moolenbroek  * \li	'*tuple' == NULL.  Either the tuple is freed, or its
224*00b67f09SDavid van Moolenbroek  *	ownership has been transferred to the diff.
225*00b67f09SDavid van Moolenbroek  */
226*00b67f09SDavid van Moolenbroek static isc_result_t
do_one_tuple(dns_difftuple_t ** tuple,dns_db_t * db,dns_dbversion_t * ver,dns_diff_t * diff)227*00b67f09SDavid van Moolenbroek do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
228*00b67f09SDavid van Moolenbroek 	     dns_diff_t *diff)
229*00b67f09SDavid van Moolenbroek {
230*00b67f09SDavid van Moolenbroek 	dns_diff_t temp_diff;
231*00b67f09SDavid van Moolenbroek 	isc_result_t result;
232*00b67f09SDavid van Moolenbroek 
233*00b67f09SDavid van Moolenbroek 	/*
234*00b67f09SDavid van Moolenbroek 	 * Create a singleton diff.
235*00b67f09SDavid van Moolenbroek 	 */
236*00b67f09SDavid van Moolenbroek 	dns_diff_init(diff->mctx, &temp_diff);
237*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
238*00b67f09SDavid van Moolenbroek 
239*00b67f09SDavid van Moolenbroek 	/*
240*00b67f09SDavid van Moolenbroek 	 * Apply it to the database.
241*00b67f09SDavid van Moolenbroek 	 */
242*00b67f09SDavid van Moolenbroek 	result = dns_diff_apply(&temp_diff, db, ver);
243*00b67f09SDavid van Moolenbroek 	ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
244*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
245*00b67f09SDavid van Moolenbroek 		dns_difftuple_free(tuple);
246*00b67f09SDavid van Moolenbroek 		return (result);
247*00b67f09SDavid van Moolenbroek 	}
248*00b67f09SDavid van Moolenbroek 
249*00b67f09SDavid van Moolenbroek 	/*
250*00b67f09SDavid van Moolenbroek 	 * Merge it into the current pending journal entry.
251*00b67f09SDavid van Moolenbroek 	 */
252*00b67f09SDavid van Moolenbroek 	dns_diff_appendminimal(diff, tuple);
253*00b67f09SDavid van Moolenbroek 
254*00b67f09SDavid van Moolenbroek 	/*
255*00b67f09SDavid van Moolenbroek 	 * Do not clear temp_diff.
256*00b67f09SDavid van Moolenbroek 	 */
257*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
258*00b67f09SDavid van Moolenbroek }
259*00b67f09SDavid van Moolenbroek 
260*00b67f09SDavid van Moolenbroek static isc_result_t
update_one_rr(dns_db_t * db,dns_dbversion_t * ver,dns_diff_t * diff,dns_diffop_t op,dns_name_t * name,dns_ttl_t ttl,dns_rdata_t * rdata)261*00b67f09SDavid van Moolenbroek update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
262*00b67f09SDavid van Moolenbroek 	      dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
263*00b67f09SDavid van Moolenbroek 	      dns_rdata_t *rdata)
264*00b67f09SDavid van Moolenbroek {
265*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
266*00b67f09SDavid van Moolenbroek 	isc_result_t result;
267*00b67f09SDavid van Moolenbroek 	result = dns_difftuple_create(diff->mctx, op,
268*00b67f09SDavid van Moolenbroek 				      name, ttl, rdata, &tuple);
269*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
270*00b67f09SDavid van Moolenbroek 		return (result);
271*00b67f09SDavid van Moolenbroek 	return (do_one_tuple(&tuple, db, ver, diff));
272*00b67f09SDavid van Moolenbroek }
273*00b67f09SDavid van Moolenbroek 
274*00b67f09SDavid van Moolenbroek /**************************************************************************/
275*00b67f09SDavid van Moolenbroek /*
276*00b67f09SDavid van Moolenbroek  * Callback-style iteration over rdatasets and rdatas.
277*00b67f09SDavid van Moolenbroek  *
278*00b67f09SDavid van Moolenbroek  * foreach_rrset() can be used to iterate over the RRsets
279*00b67f09SDavid van Moolenbroek  * of a name and call a callback function with each
280*00b67f09SDavid van Moolenbroek  * one.  Similarly, foreach_rr() can be used to iterate
281*00b67f09SDavid van Moolenbroek  * over the individual RRs at name, optionally restricted
282*00b67f09SDavid van Moolenbroek  * to RRs of a given type.
283*00b67f09SDavid van Moolenbroek  *
284*00b67f09SDavid van Moolenbroek  * The callback functions are called "actions" and take
285*00b67f09SDavid van Moolenbroek  * two arguments: a void pointer for passing arbitrary
286*00b67f09SDavid van Moolenbroek  * context information, and a pointer to the current RRset
287*00b67f09SDavid van Moolenbroek  * or RR.  By convention, their names end in "_action".
288*00b67f09SDavid van Moolenbroek  */
289*00b67f09SDavid van Moolenbroek 
290*00b67f09SDavid van Moolenbroek /*
291*00b67f09SDavid van Moolenbroek  * XXXRTH  We might want to make this public somewhere in libdns.
292*00b67f09SDavid van Moolenbroek  */
293*00b67f09SDavid van Moolenbroek 
294*00b67f09SDavid van Moolenbroek /*%
295*00b67f09SDavid van Moolenbroek  * Function type for foreach_rrset() iterator actions.
296*00b67f09SDavid van Moolenbroek  */
297*00b67f09SDavid van Moolenbroek typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
298*00b67f09SDavid van Moolenbroek 
299*00b67f09SDavid van Moolenbroek /*%
300*00b67f09SDavid van Moolenbroek  * Function type for foreach_rr() iterator actions.
301*00b67f09SDavid van Moolenbroek  */
302*00b67f09SDavid van Moolenbroek typedef isc_result_t rr_func(void *data, rr_t *rr);
303*00b67f09SDavid van Moolenbroek 
304*00b67f09SDavid van Moolenbroek /*%
305*00b67f09SDavid van Moolenbroek  * Internal context struct for foreach_node_rr().
306*00b67f09SDavid van Moolenbroek  */
307*00b67f09SDavid van Moolenbroek typedef struct {
308*00b67f09SDavid van Moolenbroek 	rr_func *	rr_action;
309*00b67f09SDavid van Moolenbroek 	void *		rr_action_data;
310*00b67f09SDavid van Moolenbroek } foreach_node_rr_ctx_t;
311*00b67f09SDavid van Moolenbroek 
312*00b67f09SDavid van Moolenbroek /*%
313*00b67f09SDavid van Moolenbroek  * Internal helper function for foreach_node_rr().
314*00b67f09SDavid van Moolenbroek  */
315*00b67f09SDavid van Moolenbroek static isc_result_t
foreach_node_rr_action(void * data,dns_rdataset_t * rdataset)316*00b67f09SDavid van Moolenbroek foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
317*00b67f09SDavid van Moolenbroek 	isc_result_t result;
318*00b67f09SDavid van Moolenbroek 	foreach_node_rr_ctx_t *ctx = data;
319*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(rdataset);
320*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
321*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(rdataset))
322*00b67f09SDavid van Moolenbroek 	{
323*00b67f09SDavid van Moolenbroek 		rr_t rr = { 0, DNS_RDATA_INIT };
324*00b67f09SDavid van Moolenbroek 
325*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(rdataset, &rr.rdata);
326*00b67f09SDavid van Moolenbroek 		rr.ttl = rdataset->ttl;
327*00b67f09SDavid van Moolenbroek 		result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
328*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
329*00b67f09SDavid van Moolenbroek 			return (result);
330*00b67f09SDavid van Moolenbroek 	}
331*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
332*00b67f09SDavid van Moolenbroek 		return (result);
333*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
334*00b67f09SDavid van Moolenbroek }
335*00b67f09SDavid van Moolenbroek 
336*00b67f09SDavid van Moolenbroek /*%
337*00b67f09SDavid van Moolenbroek  * For each rdataset of 'name' in 'ver' of 'db', call 'action'
338*00b67f09SDavid van Moolenbroek  * with the rdataset and 'action_data' as arguments.  If the name
339*00b67f09SDavid van Moolenbroek  * does not exist, do nothing.
340*00b67f09SDavid van Moolenbroek  *
341*00b67f09SDavid van Moolenbroek  * If 'action' returns an error, abort iteration and return the error.
342*00b67f09SDavid van Moolenbroek  */
343*00b67f09SDavid van Moolenbroek static isc_result_t
foreach_rrset(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,rrset_func * action,void * action_data)344*00b67f09SDavid van Moolenbroek foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
345*00b67f09SDavid van Moolenbroek 	      rrset_func *action, void *action_data)
346*00b67f09SDavid van Moolenbroek {
347*00b67f09SDavid van Moolenbroek 	isc_result_t result;
348*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node;
349*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_t *iter;
350*00b67f09SDavid van Moolenbroek 
351*00b67f09SDavid van Moolenbroek 	node = NULL;
352*00b67f09SDavid van Moolenbroek 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
353*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
354*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
355*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
356*00b67f09SDavid van Moolenbroek 		return (result);
357*00b67f09SDavid van Moolenbroek 
358*00b67f09SDavid van Moolenbroek 	iter = NULL;
359*00b67f09SDavid van Moolenbroek 	result = dns_db_allrdatasets(db, node, ver,
360*00b67f09SDavid van Moolenbroek 				     (isc_stdtime_t) 0, &iter);
361*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
362*00b67f09SDavid van Moolenbroek 		goto cleanup_node;
363*00b67f09SDavid van Moolenbroek 
364*00b67f09SDavid van Moolenbroek 	for (result = dns_rdatasetiter_first(iter);
365*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
366*00b67f09SDavid van Moolenbroek 	     result = dns_rdatasetiter_next(iter))
367*00b67f09SDavid van Moolenbroek 	{
368*00b67f09SDavid van Moolenbroek 		dns_rdataset_t rdataset;
369*00b67f09SDavid van Moolenbroek 
370*00b67f09SDavid van Moolenbroek 		dns_rdataset_init(&rdataset);
371*00b67f09SDavid van Moolenbroek 		dns_rdatasetiter_current(iter, &rdataset);
372*00b67f09SDavid van Moolenbroek 
373*00b67f09SDavid van Moolenbroek 		result = (*action)(action_data, &rdataset);
374*00b67f09SDavid van Moolenbroek 
375*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
376*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
377*00b67f09SDavid van Moolenbroek 			goto cleanup_iterator;
378*00b67f09SDavid van Moolenbroek 	}
379*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
380*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
381*00b67f09SDavid van Moolenbroek 
382*00b67f09SDavid van Moolenbroek  cleanup_iterator:
383*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_destroy(&iter);
384*00b67f09SDavid van Moolenbroek 
385*00b67f09SDavid van Moolenbroek  cleanup_node:
386*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
387*00b67f09SDavid van Moolenbroek 
388*00b67f09SDavid van Moolenbroek 	return (result);
389*00b67f09SDavid van Moolenbroek }
390*00b67f09SDavid van Moolenbroek 
391*00b67f09SDavid van Moolenbroek /*%
392*00b67f09SDavid van Moolenbroek  * For each RR of 'name' in 'ver' of 'db', call 'action'
393*00b67f09SDavid van Moolenbroek  * with the RR and 'action_data' as arguments.  If the name
394*00b67f09SDavid van Moolenbroek  * does not exist, do nothing.
395*00b67f09SDavid van Moolenbroek  *
396*00b67f09SDavid van Moolenbroek  * If 'action' returns an error, abort iteration
397*00b67f09SDavid van Moolenbroek  * and return the error.
398*00b67f09SDavid van Moolenbroek  */
399*00b67f09SDavid van Moolenbroek static isc_result_t
foreach_node_rr(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,rr_func * rr_action,void * rr_action_data)400*00b67f09SDavid van Moolenbroek foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
401*00b67f09SDavid van Moolenbroek 		rr_func *rr_action, void *rr_action_data)
402*00b67f09SDavid van Moolenbroek {
403*00b67f09SDavid van Moolenbroek 	foreach_node_rr_ctx_t ctx;
404*00b67f09SDavid van Moolenbroek 	ctx.rr_action = rr_action;
405*00b67f09SDavid van Moolenbroek 	ctx.rr_action_data = rr_action_data;
406*00b67f09SDavid van Moolenbroek 	return (foreach_rrset(db, ver, name,
407*00b67f09SDavid van Moolenbroek 			      foreach_node_rr_action, &ctx));
408*00b67f09SDavid van Moolenbroek }
409*00b67f09SDavid van Moolenbroek 
410*00b67f09SDavid van Moolenbroek 
411*00b67f09SDavid van Moolenbroek /*%
412*00b67f09SDavid van Moolenbroek  * For each of the RRs specified by 'db', 'ver', 'name', 'type',
413*00b67f09SDavid van Moolenbroek  * (which can be dns_rdatatype_any to match any type), and 'covers', call
414*00b67f09SDavid van Moolenbroek  * 'action' with the RR and 'action_data' as arguments. If the name
415*00b67f09SDavid van Moolenbroek  * does not exist, or if no RRset of the given type exists at the name,
416*00b67f09SDavid van Moolenbroek  * do nothing.
417*00b67f09SDavid van Moolenbroek  *
418*00b67f09SDavid van Moolenbroek  * If 'action' returns an error, abort iteration and return the error.
419*00b67f09SDavid van Moolenbroek  */
420*00b67f09SDavid van Moolenbroek static isc_result_t
foreach_rr(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_rdatatype_t type,dns_rdatatype_t covers,rr_func * rr_action,void * rr_action_data)421*00b67f09SDavid van Moolenbroek foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
422*00b67f09SDavid van Moolenbroek 	   dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
423*00b67f09SDavid van Moolenbroek 	   void *rr_action_data)
424*00b67f09SDavid van Moolenbroek {
425*00b67f09SDavid van Moolenbroek 
426*00b67f09SDavid van Moolenbroek 	isc_result_t result;
427*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node;
428*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
429*00b67f09SDavid van Moolenbroek 
430*00b67f09SDavid van Moolenbroek 	if (type == dns_rdatatype_any)
431*00b67f09SDavid van Moolenbroek 		return (foreach_node_rr(db, ver, name,
432*00b67f09SDavid van Moolenbroek 					rr_action, rr_action_data));
433*00b67f09SDavid van Moolenbroek 
434*00b67f09SDavid van Moolenbroek 	node = NULL;
435*00b67f09SDavid van Moolenbroek 	if (type == dns_rdatatype_nsec3 ||
436*00b67f09SDavid van Moolenbroek 	    (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
437*00b67f09SDavid van Moolenbroek 		result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
438*00b67f09SDavid van Moolenbroek 	else
439*00b67f09SDavid van Moolenbroek 		result = dns_db_findnode(db, name, ISC_FALSE, &node);
440*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
441*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
442*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
443*00b67f09SDavid van Moolenbroek 		return (result);
444*00b67f09SDavid van Moolenbroek 
445*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
446*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, ver, type, covers,
447*00b67f09SDavid van Moolenbroek 				     (isc_stdtime_t) 0, &rdataset, NULL);
448*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
449*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
450*00b67f09SDavid van Moolenbroek 		goto cleanup_node;
451*00b67f09SDavid van Moolenbroek 	}
452*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
453*00b67f09SDavid van Moolenbroek 		goto cleanup_node;
454*00b67f09SDavid van Moolenbroek 
455*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
456*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
457*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset))
458*00b67f09SDavid van Moolenbroek 	{
459*00b67f09SDavid van Moolenbroek 		rr_t rr = { 0, DNS_RDATA_INIT };
460*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rr.rdata);
461*00b67f09SDavid van Moolenbroek 		rr.ttl = rdataset.ttl;
462*00b67f09SDavid van Moolenbroek 		result = (*rr_action)(rr_action_data, &rr);
463*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
464*00b67f09SDavid van Moolenbroek 			goto cleanup_rdataset;
465*00b67f09SDavid van Moolenbroek 	}
466*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
467*00b67f09SDavid van Moolenbroek 		goto cleanup_rdataset;
468*00b67f09SDavid van Moolenbroek 	result = ISC_R_SUCCESS;
469*00b67f09SDavid van Moolenbroek 
470*00b67f09SDavid van Moolenbroek  cleanup_rdataset:
471*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
472*00b67f09SDavid van Moolenbroek  cleanup_node:
473*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
474*00b67f09SDavid van Moolenbroek 
475*00b67f09SDavid van Moolenbroek 	return (result);
476*00b67f09SDavid van Moolenbroek }
477*00b67f09SDavid van Moolenbroek 
478*00b67f09SDavid van Moolenbroek /**************************************************************************/
479*00b67f09SDavid van Moolenbroek /*
480*00b67f09SDavid van Moolenbroek  * Various tests on the database contents (for prerequisites, etc).
481*00b67f09SDavid van Moolenbroek  */
482*00b67f09SDavid van Moolenbroek 
483*00b67f09SDavid van Moolenbroek /*%
484*00b67f09SDavid van Moolenbroek  * Function type for predicate functions that compare a database RR 'db_rr'
485*00b67f09SDavid van Moolenbroek  * against an update RR 'update_rr'.
486*00b67f09SDavid van Moolenbroek  */
487*00b67f09SDavid van Moolenbroek typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
488*00b67f09SDavid van Moolenbroek 
489*00b67f09SDavid van Moolenbroek /*%
490*00b67f09SDavid van Moolenbroek  * Helper function for rrset_exists().
491*00b67f09SDavid van Moolenbroek  */
492*00b67f09SDavid van Moolenbroek static isc_result_t
rrset_exists_action(void * data,rr_t * rr)493*00b67f09SDavid van Moolenbroek rrset_exists_action(void *data, rr_t *rr) {
494*00b67f09SDavid van Moolenbroek 	UNUSED(data);
495*00b67f09SDavid van Moolenbroek 	UNUSED(rr);
496*00b67f09SDavid van Moolenbroek 	return (ISC_R_EXISTS);
497*00b67f09SDavid van Moolenbroek }
498*00b67f09SDavid van Moolenbroek 
499*00b67f09SDavid van Moolenbroek /*%
500*00b67f09SDavid van Moolenbroek  * Utility macro for RR existence checking functions.
501*00b67f09SDavid van Moolenbroek  *
502*00b67f09SDavid van Moolenbroek  * If the variable 'result' has the value ISC_R_EXISTS or
503*00b67f09SDavid van Moolenbroek  * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
504*00b67f09SDavid van Moolenbroek  * respectively, and return success.
505*00b67f09SDavid van Moolenbroek  *
506*00b67f09SDavid van Moolenbroek  * If 'result' has any other value, there was a failure.
507*00b67f09SDavid van Moolenbroek  * Return the failure result code and do not set *exists.
508*00b67f09SDavid van Moolenbroek  *
509*00b67f09SDavid van Moolenbroek  * This would be more readable as "do { if ... } while(0)",
510*00b67f09SDavid van Moolenbroek  * but that form generates tons of warnings on Solaris 2.6.
511*00b67f09SDavid van Moolenbroek  */
512*00b67f09SDavid van Moolenbroek #define RETURN_EXISTENCE_FLAG				\
513*00b67f09SDavid van Moolenbroek 	return ((result == ISC_R_EXISTS) ?		\
514*00b67f09SDavid van Moolenbroek 		(*exists = ISC_TRUE, ISC_R_SUCCESS) :	\
515*00b67f09SDavid van Moolenbroek 		((result == ISC_R_SUCCESS) ?		\
516*00b67f09SDavid van Moolenbroek 		 (*exists = ISC_FALSE, ISC_R_SUCCESS) :	\
517*00b67f09SDavid van Moolenbroek 		 result))
518*00b67f09SDavid van Moolenbroek 
519*00b67f09SDavid van Moolenbroek /*%
520*00b67f09SDavid van Moolenbroek  * Set '*exists' to true iff an rrset of the given type exists,
521*00b67f09SDavid van Moolenbroek  * to false otherwise.
522*00b67f09SDavid van Moolenbroek  */
523*00b67f09SDavid van Moolenbroek static isc_result_t
rrset_exists(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_rdatatype_t type,dns_rdatatype_t covers,isc_boolean_t * exists)524*00b67f09SDavid van Moolenbroek rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
525*00b67f09SDavid van Moolenbroek 	     dns_rdatatype_t type, dns_rdatatype_t covers,
526*00b67f09SDavid van Moolenbroek 	     isc_boolean_t *exists)
527*00b67f09SDavid van Moolenbroek {
528*00b67f09SDavid van Moolenbroek 	isc_result_t result;
529*00b67f09SDavid van Moolenbroek 	result = foreach_rr(db, ver, name, type, covers,
530*00b67f09SDavid van Moolenbroek 			    rrset_exists_action, NULL);
531*00b67f09SDavid van Moolenbroek 	RETURN_EXISTENCE_FLAG;
532*00b67f09SDavid van Moolenbroek }
533*00b67f09SDavid van Moolenbroek 
534*00b67f09SDavid van Moolenbroek /*%
535*00b67f09SDavid van Moolenbroek  * Set '*visible' to true if the RRset exists and is part of the
536*00b67f09SDavid van Moolenbroek  * visible zone.  Otherwise '*visible' is set to false unless a
537*00b67f09SDavid van Moolenbroek  * error occurs.
538*00b67f09SDavid van Moolenbroek  */
539*00b67f09SDavid van Moolenbroek static isc_result_t
rrset_visible(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_rdatatype_t type,isc_boolean_t * visible)540*00b67f09SDavid van Moolenbroek rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
541*00b67f09SDavid van Moolenbroek 	      dns_rdatatype_t type, isc_boolean_t *visible)
542*00b67f09SDavid van Moolenbroek {
543*00b67f09SDavid van Moolenbroek 	isc_result_t result;
544*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixed;
545*00b67f09SDavid van Moolenbroek 
546*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixed);
547*00b67f09SDavid van Moolenbroek 	result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD,
548*00b67f09SDavid van Moolenbroek 			     (isc_stdtime_t) 0, NULL,
549*00b67f09SDavid van Moolenbroek 			     dns_fixedname_name(&fixed), NULL, NULL);
550*00b67f09SDavid van Moolenbroek 	switch (result) {
551*00b67f09SDavid van Moolenbroek 	case ISC_R_SUCCESS:
552*00b67f09SDavid van Moolenbroek 		*visible = ISC_TRUE;
553*00b67f09SDavid van Moolenbroek 		break;
554*00b67f09SDavid van Moolenbroek 	/*
555*00b67f09SDavid van Moolenbroek 	 * Glue, obscured, deleted or replaced records.
556*00b67f09SDavid van Moolenbroek 	 */
557*00b67f09SDavid van Moolenbroek 	case DNS_R_DELEGATION:
558*00b67f09SDavid van Moolenbroek 	case DNS_R_DNAME:
559*00b67f09SDavid van Moolenbroek 	case DNS_R_CNAME:
560*00b67f09SDavid van Moolenbroek 	case DNS_R_NXDOMAIN:
561*00b67f09SDavid van Moolenbroek 	case DNS_R_NXRRSET:
562*00b67f09SDavid van Moolenbroek 	case DNS_R_EMPTYNAME:
563*00b67f09SDavid van Moolenbroek 	case DNS_R_COVERINGNSEC:
564*00b67f09SDavid van Moolenbroek 		*visible = ISC_FALSE;
565*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
566*00b67f09SDavid van Moolenbroek 		break;
567*00b67f09SDavid van Moolenbroek 	default:
568*00b67f09SDavid van Moolenbroek 		break;
569*00b67f09SDavid van Moolenbroek 	}
570*00b67f09SDavid van Moolenbroek 	return (result);
571*00b67f09SDavid van Moolenbroek }
572*00b67f09SDavid van Moolenbroek 
573*00b67f09SDavid van Moolenbroek /*%
574*00b67f09SDavid van Moolenbroek  * Context struct and helper function for name_exists().
575*00b67f09SDavid van Moolenbroek  */
576*00b67f09SDavid van Moolenbroek 
577*00b67f09SDavid van Moolenbroek static isc_result_t
name_exists_action(void * data,dns_rdataset_t * rrset)578*00b67f09SDavid van Moolenbroek name_exists_action(void *data, dns_rdataset_t *rrset) {
579*00b67f09SDavid van Moolenbroek 	UNUSED(data);
580*00b67f09SDavid van Moolenbroek 	UNUSED(rrset);
581*00b67f09SDavid van Moolenbroek 	return (ISC_R_EXISTS);
582*00b67f09SDavid van Moolenbroek }
583*00b67f09SDavid van Moolenbroek 
584*00b67f09SDavid van Moolenbroek /*%
585*00b67f09SDavid van Moolenbroek  * Set '*exists' to true iff the given name exists, to false otherwise.
586*00b67f09SDavid van Moolenbroek  */
587*00b67f09SDavid van Moolenbroek static isc_result_t
name_exists(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,isc_boolean_t * exists)588*00b67f09SDavid van Moolenbroek name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
589*00b67f09SDavid van Moolenbroek 	    isc_boolean_t *exists)
590*00b67f09SDavid van Moolenbroek {
591*00b67f09SDavid van Moolenbroek 	isc_result_t result;
592*00b67f09SDavid van Moolenbroek 	result = foreach_rrset(db, ver, name,
593*00b67f09SDavid van Moolenbroek 			       name_exists_action, NULL);
594*00b67f09SDavid van Moolenbroek 	RETURN_EXISTENCE_FLAG;
595*00b67f09SDavid van Moolenbroek }
596*00b67f09SDavid van Moolenbroek 
597*00b67f09SDavid van Moolenbroek /**************************************************************************/
598*00b67f09SDavid van Moolenbroek /*
599*00b67f09SDavid van Moolenbroek  * Checking of "RRset exists (value dependent)" prerequisites.
600*00b67f09SDavid van Moolenbroek  *
601*00b67f09SDavid van Moolenbroek  * In the RFC2136 section 3.2.5, this is the pseudocode involving
602*00b67f09SDavid van Moolenbroek  * a variable called "temp", a mapping of <name, type> tuples to rrsets.
603*00b67f09SDavid van Moolenbroek  *
604*00b67f09SDavid van Moolenbroek  * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
605*00b67f09SDavid van Moolenbroek  * where each tuple has op==DNS_DIFFOP_EXISTS.
606*00b67f09SDavid van Moolenbroek  */
607*00b67f09SDavid van Moolenbroek 
608*00b67f09SDavid van Moolenbroek /*%
609*00b67f09SDavid van Moolenbroek  * A comparison function defining the sorting order for the entries
610*00b67f09SDavid van Moolenbroek  * in the "temp" data structure.  The major sort key is the owner name,
611*00b67f09SDavid van Moolenbroek  * followed by the type and rdata.
612*00b67f09SDavid van Moolenbroek  */
613*00b67f09SDavid van Moolenbroek static int
temp_order(const void * av,const void * bv)614*00b67f09SDavid van Moolenbroek temp_order(const void *av, const void *bv) {
615*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const * const *ap = av;
616*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const * const *bp = bv;
617*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const *a = *ap;
618*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const *b = *bp;
619*00b67f09SDavid van Moolenbroek 	int r;
620*00b67f09SDavid van Moolenbroek 	r = dns_name_compare(&a->name, &b->name);
621*00b67f09SDavid van Moolenbroek 	if (r != 0)
622*00b67f09SDavid van Moolenbroek 		return (r);
623*00b67f09SDavid van Moolenbroek 	r = (b->rdata.type - a->rdata.type);
624*00b67f09SDavid van Moolenbroek 	if (r != 0)
625*00b67f09SDavid van Moolenbroek 		return (r);
626*00b67f09SDavid van Moolenbroek 	r = dns_rdata_casecompare(&a->rdata, &b->rdata);
627*00b67f09SDavid van Moolenbroek 	return (r);
628*00b67f09SDavid van Moolenbroek }
629*00b67f09SDavid van Moolenbroek 
630*00b67f09SDavid van Moolenbroek /**************************************************************************/
631*00b67f09SDavid van Moolenbroek /*
632*00b67f09SDavid van Moolenbroek  * Conditional deletion of RRs.
633*00b67f09SDavid van Moolenbroek  */
634*00b67f09SDavid van Moolenbroek 
635*00b67f09SDavid van Moolenbroek /*%
636*00b67f09SDavid van Moolenbroek  * Context structure for delete_if().
637*00b67f09SDavid van Moolenbroek  */
638*00b67f09SDavid van Moolenbroek 
639*00b67f09SDavid van Moolenbroek typedef struct {
640*00b67f09SDavid van Moolenbroek 	rr_predicate *predicate;
641*00b67f09SDavid van Moolenbroek 	dns_db_t *db;
642*00b67f09SDavid van Moolenbroek 	dns_dbversion_t *ver;
643*00b67f09SDavid van Moolenbroek 	dns_diff_t *diff;
644*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
645*00b67f09SDavid van Moolenbroek 	dns_rdata_t *update_rr;
646*00b67f09SDavid van Moolenbroek } conditional_delete_ctx_t;
647*00b67f09SDavid van Moolenbroek 
648*00b67f09SDavid van Moolenbroek /*%
649*00b67f09SDavid van Moolenbroek  * Predicate functions for delete_if().
650*00b67f09SDavid van Moolenbroek  */
651*00b67f09SDavid van Moolenbroek 
652*00b67f09SDavid van Moolenbroek /*%
653*00b67f09SDavid van Moolenbroek  * Return true always.
654*00b67f09SDavid van Moolenbroek  */
655*00b67f09SDavid van Moolenbroek static isc_boolean_t
true_p(dns_rdata_t * update_rr,dns_rdata_t * db_rr)656*00b67f09SDavid van Moolenbroek true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
657*00b67f09SDavid van Moolenbroek 	UNUSED(update_rr);
658*00b67f09SDavid van Moolenbroek 	UNUSED(db_rr);
659*00b67f09SDavid van Moolenbroek 	return (ISC_TRUE);
660*00b67f09SDavid van Moolenbroek }
661*00b67f09SDavid van Moolenbroek 
662*00b67f09SDavid van Moolenbroek /*%
663*00b67f09SDavid van Moolenbroek  * Return true if the record is a RRSIG.
664*00b67f09SDavid van Moolenbroek  */
665*00b67f09SDavid van Moolenbroek static isc_boolean_t
rrsig_p(dns_rdata_t * update_rr,dns_rdata_t * db_rr)666*00b67f09SDavid van Moolenbroek rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
667*00b67f09SDavid van Moolenbroek 	UNUSED(update_rr);
668*00b67f09SDavid van Moolenbroek 	return ((db_rr->type == dns_rdatatype_rrsig) ?
669*00b67f09SDavid van Moolenbroek 		ISC_TRUE : ISC_FALSE);
670*00b67f09SDavid van Moolenbroek }
671*00b67f09SDavid van Moolenbroek 
672*00b67f09SDavid van Moolenbroek /*%
673*00b67f09SDavid van Moolenbroek  * Internal helper function for delete_if().
674*00b67f09SDavid van Moolenbroek  */
675*00b67f09SDavid van Moolenbroek static isc_result_t
delete_if_action(void * data,rr_t * rr)676*00b67f09SDavid van Moolenbroek delete_if_action(void *data, rr_t *rr) {
677*00b67f09SDavid van Moolenbroek 	conditional_delete_ctx_t *ctx = data;
678*00b67f09SDavid van Moolenbroek 	if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
679*00b67f09SDavid van Moolenbroek 		isc_result_t result;
680*00b67f09SDavid van Moolenbroek 		result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
681*00b67f09SDavid van Moolenbroek 				       DNS_DIFFOP_DEL, ctx->name,
682*00b67f09SDavid van Moolenbroek 				       rr->ttl, &rr->rdata);
683*00b67f09SDavid van Moolenbroek 		return (result);
684*00b67f09SDavid van Moolenbroek 	} else {
685*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
686*00b67f09SDavid van Moolenbroek 	}
687*00b67f09SDavid van Moolenbroek }
688*00b67f09SDavid van Moolenbroek 
689*00b67f09SDavid van Moolenbroek /*%
690*00b67f09SDavid van Moolenbroek  * Conditionally delete RRs.  Apply 'predicate' to the RRs
691*00b67f09SDavid van Moolenbroek  * specified by 'db', 'ver', 'name', and 'type' (which can
692*00b67f09SDavid van Moolenbroek  * be dns_rdatatype_any to match any type).  Delete those
693*00b67f09SDavid van Moolenbroek  * RRs for which the predicate returns true, and log the
694*00b67f09SDavid van Moolenbroek  * deletions in 'diff'.
695*00b67f09SDavid van Moolenbroek  */
696*00b67f09SDavid van Moolenbroek static isc_result_t
delete_if(rr_predicate * predicate,dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_rdatatype_t type,dns_rdatatype_t covers,dns_rdata_t * update_rr,dns_diff_t * diff)697*00b67f09SDavid van Moolenbroek delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
698*00b67f09SDavid van Moolenbroek 	  dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
699*00b67f09SDavid van Moolenbroek 	  dns_rdata_t *update_rr, dns_diff_t *diff)
700*00b67f09SDavid van Moolenbroek {
701*00b67f09SDavid van Moolenbroek 	conditional_delete_ctx_t ctx;
702*00b67f09SDavid van Moolenbroek 	ctx.predicate = predicate;
703*00b67f09SDavid van Moolenbroek 	ctx.db = db;
704*00b67f09SDavid van Moolenbroek 	ctx.ver = ver;
705*00b67f09SDavid van Moolenbroek 	ctx.diff = diff;
706*00b67f09SDavid van Moolenbroek 	ctx.name = name;
707*00b67f09SDavid van Moolenbroek 	ctx.update_rr = update_rr;
708*00b67f09SDavid van Moolenbroek 	return (foreach_rr(db, ver, name, type, covers,
709*00b67f09SDavid van Moolenbroek 			   delete_if_action, &ctx));
710*00b67f09SDavid van Moolenbroek }
711*00b67f09SDavid van Moolenbroek 
712*00b67f09SDavid van Moolenbroek /**************************************************************************/
713*00b67f09SDavid van Moolenbroek /*
714*00b67f09SDavid van Moolenbroek  * Incremental updating of NSECs and RRSIGs.
715*00b67f09SDavid van Moolenbroek  */
716*00b67f09SDavid van Moolenbroek 
717*00b67f09SDavid van Moolenbroek /*%
718*00b67f09SDavid van Moolenbroek  * We abuse the dns_diff_t type to represent a set of domain names
719*00b67f09SDavid van Moolenbroek  * affected by the update.
720*00b67f09SDavid van Moolenbroek  */
721*00b67f09SDavid van Moolenbroek static isc_result_t
namelist_append_name(dns_diff_t * list,dns_name_t * name)722*00b67f09SDavid van Moolenbroek namelist_append_name(dns_diff_t *list, dns_name_t *name) {
723*00b67f09SDavid van Moolenbroek 	isc_result_t result;
724*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
725*00b67f09SDavid van Moolenbroek 	static dns_rdata_t dummy_rdata = DNS_RDATA_INIT;
726*00b67f09SDavid van Moolenbroek 
727*00b67f09SDavid van Moolenbroek 	CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0,
728*00b67f09SDavid van Moolenbroek 				   &dummy_rdata, &tuple));
729*00b67f09SDavid van Moolenbroek 	dns_diff_append(list, &tuple);
730*00b67f09SDavid van Moolenbroek  failure:
731*00b67f09SDavid van Moolenbroek 	return (result);
732*00b67f09SDavid van Moolenbroek }
733*00b67f09SDavid van Moolenbroek 
734*00b67f09SDavid van Moolenbroek static isc_result_t
namelist_append_subdomain(dns_db_t * db,dns_name_t * name,dns_diff_t * affected)735*00b67f09SDavid van Moolenbroek namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
736*00b67f09SDavid van Moolenbroek {
737*00b67f09SDavid van Moolenbroek 	isc_result_t result;
738*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixedname;
739*00b67f09SDavid van Moolenbroek 	dns_name_t *child;
740*00b67f09SDavid van Moolenbroek 	dns_dbiterator_t *dbit = NULL;
741*00b67f09SDavid van Moolenbroek 
742*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixedname);
743*00b67f09SDavid van Moolenbroek 	child = dns_fixedname_name(&fixedname);
744*00b67f09SDavid van Moolenbroek 
745*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
746*00b67f09SDavid van Moolenbroek 
747*00b67f09SDavid van Moolenbroek 	for (result = dns_dbiterator_seek(dbit, name);
748*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
749*00b67f09SDavid van Moolenbroek 	     result = dns_dbiterator_next(dbit))
750*00b67f09SDavid van Moolenbroek 	{
751*00b67f09SDavid van Moolenbroek 		dns_dbnode_t *node = NULL;
752*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_current(dbit, &node, child));
753*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
754*00b67f09SDavid van Moolenbroek 		if (! dns_name_issubdomain(child, name))
755*00b67f09SDavid van Moolenbroek 			break;
756*00b67f09SDavid van Moolenbroek 		CHECK(namelist_append_name(affected, child));
757*00b67f09SDavid van Moolenbroek 	}
758*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
759*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
760*00b67f09SDavid van Moolenbroek  failure:
761*00b67f09SDavid van Moolenbroek 	if (dbit != NULL)
762*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&dbit);
763*00b67f09SDavid van Moolenbroek 	return (result);
764*00b67f09SDavid van Moolenbroek }
765*00b67f09SDavid van Moolenbroek 
766*00b67f09SDavid van Moolenbroek 
767*00b67f09SDavid van Moolenbroek 
768*00b67f09SDavid van Moolenbroek /*%
769*00b67f09SDavid van Moolenbroek  * Helper function for non_nsec_rrset_exists().
770*00b67f09SDavid van Moolenbroek  */
771*00b67f09SDavid van Moolenbroek static isc_result_t
is_non_nsec_action(void * data,dns_rdataset_t * rrset)772*00b67f09SDavid van Moolenbroek is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
773*00b67f09SDavid van Moolenbroek 	UNUSED(data);
774*00b67f09SDavid van Moolenbroek 	if (!(rrset->type == dns_rdatatype_nsec ||
775*00b67f09SDavid van Moolenbroek 	      rrset->type == dns_rdatatype_nsec3 ||
776*00b67f09SDavid van Moolenbroek 	      (rrset->type == dns_rdatatype_rrsig &&
777*00b67f09SDavid van Moolenbroek 	       (rrset->covers == dns_rdatatype_nsec ||
778*00b67f09SDavid van Moolenbroek 		rrset->covers == dns_rdatatype_nsec3))))
779*00b67f09SDavid van Moolenbroek 		return (ISC_R_EXISTS);
780*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
781*00b67f09SDavid van Moolenbroek }
782*00b67f09SDavid van Moolenbroek 
783*00b67f09SDavid van Moolenbroek /*%
784*00b67f09SDavid van Moolenbroek  * Check whether there is an rrset other than a NSEC or RRSIG NSEC,
785*00b67f09SDavid van Moolenbroek  * i.e., anything that justifies the continued existence of a name
786*00b67f09SDavid van Moolenbroek  * after a secure update.
787*00b67f09SDavid van Moolenbroek  *
788*00b67f09SDavid van Moolenbroek  * If such an rrset exists, set '*exists' to ISC_TRUE.
789*00b67f09SDavid van Moolenbroek  * Otherwise, set it to ISC_FALSE.
790*00b67f09SDavid van Moolenbroek  */
791*00b67f09SDavid van Moolenbroek static isc_result_t
non_nsec_rrset_exists(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,isc_boolean_t * exists)792*00b67f09SDavid van Moolenbroek non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
793*00b67f09SDavid van Moolenbroek 		     dns_name_t *name, isc_boolean_t *exists)
794*00b67f09SDavid van Moolenbroek {
795*00b67f09SDavid van Moolenbroek 	isc_result_t result;
796*00b67f09SDavid van Moolenbroek 	result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
797*00b67f09SDavid van Moolenbroek 	RETURN_EXISTENCE_FLAG;
798*00b67f09SDavid van Moolenbroek }
799*00b67f09SDavid van Moolenbroek 
800*00b67f09SDavid van Moolenbroek /*%
801*00b67f09SDavid van Moolenbroek  * A comparison function for sorting dns_diff_t:s by name.
802*00b67f09SDavid van Moolenbroek  */
803*00b67f09SDavid van Moolenbroek static int
name_order(const void * av,const void * bv)804*00b67f09SDavid van Moolenbroek name_order(const void *av, const void *bv) {
805*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const * const *ap = av;
806*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const * const *bp = bv;
807*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const *a = *ap;
808*00b67f09SDavid van Moolenbroek 	dns_difftuple_t const *b = *bp;
809*00b67f09SDavid van Moolenbroek 	return (dns_name_compare(&a->name, &b->name));
810*00b67f09SDavid van Moolenbroek }
811*00b67f09SDavid van Moolenbroek 
812*00b67f09SDavid van Moolenbroek static isc_result_t
uniqify_name_list(dns_diff_t * list)813*00b67f09SDavid van Moolenbroek uniqify_name_list(dns_diff_t *list) {
814*00b67f09SDavid van Moolenbroek 	isc_result_t result;
815*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *p, *q;
816*00b67f09SDavid van Moolenbroek 
817*00b67f09SDavid van Moolenbroek 	CHECK(dns_diff_sort(list, name_order));
818*00b67f09SDavid van Moolenbroek 
819*00b67f09SDavid van Moolenbroek 	p = ISC_LIST_HEAD(list->tuples);
820*00b67f09SDavid van Moolenbroek 	while (p != NULL) {
821*00b67f09SDavid van Moolenbroek 		do {
822*00b67f09SDavid van Moolenbroek 			q = ISC_LIST_NEXT(p, link);
823*00b67f09SDavid van Moolenbroek 			if (q == NULL || ! dns_name_equal(&p->name, &q->name))
824*00b67f09SDavid van Moolenbroek 				break;
825*00b67f09SDavid van Moolenbroek 			ISC_LIST_UNLINK(list->tuples, q, link);
826*00b67f09SDavid van Moolenbroek 			dns_difftuple_free(&q);
827*00b67f09SDavid van Moolenbroek 		} while (1);
828*00b67f09SDavid van Moolenbroek 		p = ISC_LIST_NEXT(p, link);
829*00b67f09SDavid van Moolenbroek 	}
830*00b67f09SDavid van Moolenbroek  failure:
831*00b67f09SDavid van Moolenbroek 	return (result);
832*00b67f09SDavid van Moolenbroek }
833*00b67f09SDavid van Moolenbroek 
834*00b67f09SDavid van Moolenbroek static isc_result_t
is_active(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,isc_boolean_t * flag,isc_boolean_t * cut,isc_boolean_t * unsecure)835*00b67f09SDavid van Moolenbroek is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
836*00b67f09SDavid van Moolenbroek 	  isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure)
837*00b67f09SDavid van Moolenbroek {
838*00b67f09SDavid van Moolenbroek 	isc_result_t result;
839*00b67f09SDavid van Moolenbroek 	dns_fixedname_t foundname;
840*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&foundname);
841*00b67f09SDavid van Moolenbroek 	result = dns_db_find(db, name, ver, dns_rdatatype_any,
842*00b67f09SDavid van Moolenbroek 			     DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
843*00b67f09SDavid van Moolenbroek 			     (isc_stdtime_t) 0, NULL,
844*00b67f09SDavid van Moolenbroek 			     dns_fixedname_name(&foundname),
845*00b67f09SDavid van Moolenbroek 			     NULL, NULL);
846*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
847*00b67f09SDavid van Moolenbroek 		*flag = ISC_TRUE;
848*00b67f09SDavid van Moolenbroek 		*cut = ISC_FALSE;
849*00b67f09SDavid van Moolenbroek 		if (unsecure != NULL)
850*00b67f09SDavid van Moolenbroek 			*unsecure = ISC_FALSE;
851*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
852*00b67f09SDavid van Moolenbroek 	} else if (result == DNS_R_ZONECUT) {
853*00b67f09SDavid van Moolenbroek 		*flag = ISC_TRUE;
854*00b67f09SDavid van Moolenbroek 		*cut = ISC_TRUE;
855*00b67f09SDavid van Moolenbroek 		if (unsecure != NULL) {
856*00b67f09SDavid van Moolenbroek 			/*
857*00b67f09SDavid van Moolenbroek 			 * We are at the zonecut.  Check to see if there
858*00b67f09SDavid van Moolenbroek 			 * is a DS RRset.
859*00b67f09SDavid van Moolenbroek 			 */
860*00b67f09SDavid van Moolenbroek 			if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
861*00b67f09SDavid van Moolenbroek 					(isc_stdtime_t) 0, NULL,
862*00b67f09SDavid van Moolenbroek 					dns_fixedname_name(&foundname),
863*00b67f09SDavid van Moolenbroek 					NULL, NULL) == DNS_R_NXRRSET)
864*00b67f09SDavid van Moolenbroek 				*unsecure = ISC_TRUE;
865*00b67f09SDavid van Moolenbroek 			else
866*00b67f09SDavid van Moolenbroek 				*unsecure = ISC_FALSE;
867*00b67f09SDavid van Moolenbroek 		}
868*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
869*00b67f09SDavid van Moolenbroek 	} else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
870*00b67f09SDavid van Moolenbroek 		   result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
871*00b67f09SDavid van Moolenbroek 		*flag = ISC_FALSE;
872*00b67f09SDavid van Moolenbroek 		*cut = ISC_FALSE;
873*00b67f09SDavid van Moolenbroek 		if (unsecure != NULL)
874*00b67f09SDavid van Moolenbroek 			*unsecure = ISC_FALSE;
875*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
876*00b67f09SDavid van Moolenbroek 	} else {
877*00b67f09SDavid van Moolenbroek 		/*
878*00b67f09SDavid van Moolenbroek 		 * Silence compiler.
879*00b67f09SDavid van Moolenbroek 		 */
880*00b67f09SDavid van Moolenbroek 		*flag = ISC_FALSE;
881*00b67f09SDavid van Moolenbroek 		*cut = ISC_FALSE;
882*00b67f09SDavid van Moolenbroek 		if (unsecure != NULL)
883*00b67f09SDavid van Moolenbroek 			*unsecure = ISC_FALSE;
884*00b67f09SDavid van Moolenbroek 		return (result);
885*00b67f09SDavid van Moolenbroek 	}
886*00b67f09SDavid van Moolenbroek }
887*00b67f09SDavid van Moolenbroek 
888*00b67f09SDavid van Moolenbroek /*%
889*00b67f09SDavid van Moolenbroek  * Find the next/previous name that has a NSEC record.
890*00b67f09SDavid van Moolenbroek  * In other words, skip empty database nodes and names that
891*00b67f09SDavid van Moolenbroek  * have had their NSECs removed because they are obscured by
892*00b67f09SDavid van Moolenbroek  * a zone cut.
893*00b67f09SDavid van Moolenbroek  */
894*00b67f09SDavid van Moolenbroek static isc_result_t
next_active(dns_update_log_t * log,dns_zone_t * zone,dns_db_t * db,dns_dbversion_t * ver,dns_name_t * oldname,dns_name_t * newname,isc_boolean_t forward)895*00b67f09SDavid van Moolenbroek next_active(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
896*00b67f09SDavid van Moolenbroek 	    dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname,
897*00b67f09SDavid van Moolenbroek 	    isc_boolean_t forward)
898*00b67f09SDavid van Moolenbroek {
899*00b67f09SDavid van Moolenbroek 	isc_result_t result;
900*00b67f09SDavid van Moolenbroek 	dns_dbiterator_t *dbit = NULL;
901*00b67f09SDavid van Moolenbroek 	isc_boolean_t has_nsec = ISC_FALSE;
902*00b67f09SDavid van Moolenbroek 	unsigned int wraps = 0;
903*00b67f09SDavid van Moolenbroek 	isc_boolean_t secure = dns_db_issecure(db);
904*00b67f09SDavid van Moolenbroek 
905*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_createiterator(db, 0, &dbit));
906*00b67f09SDavid van Moolenbroek 
907*00b67f09SDavid van Moolenbroek 	CHECK(dns_dbiterator_seek(dbit, oldname));
908*00b67f09SDavid van Moolenbroek 	do {
909*00b67f09SDavid van Moolenbroek 		dns_dbnode_t *node = NULL;
910*00b67f09SDavid van Moolenbroek 
911*00b67f09SDavid van Moolenbroek 		if (forward)
912*00b67f09SDavid van Moolenbroek 			result = dns_dbiterator_next(dbit);
913*00b67f09SDavid van Moolenbroek 		else
914*00b67f09SDavid van Moolenbroek 			result = dns_dbiterator_prev(dbit);
915*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE) {
916*00b67f09SDavid van Moolenbroek 			/*
917*00b67f09SDavid van Moolenbroek 			 * Wrap around.
918*00b67f09SDavid van Moolenbroek 			 */
919*00b67f09SDavid van Moolenbroek 			if (forward)
920*00b67f09SDavid van Moolenbroek 				CHECK(dns_dbiterator_first(dbit));
921*00b67f09SDavid van Moolenbroek 			else
922*00b67f09SDavid van Moolenbroek 				CHECK(dns_dbiterator_last(dbit));
923*00b67f09SDavid van Moolenbroek 			wraps++;
924*00b67f09SDavid van Moolenbroek 			if (wraps == 2) {
925*00b67f09SDavid van Moolenbroek 				update_log(log, zone, ISC_LOG_ERROR,
926*00b67f09SDavid van Moolenbroek 					   "secure zone with no NSECs");
927*00b67f09SDavid van Moolenbroek 				result = DNS_R_BADZONE;
928*00b67f09SDavid van Moolenbroek 				goto failure;
929*00b67f09SDavid van Moolenbroek 			}
930*00b67f09SDavid van Moolenbroek 		}
931*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_current(dbit, &node, newname));
932*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
933*00b67f09SDavid van Moolenbroek 
934*00b67f09SDavid van Moolenbroek 		/*
935*00b67f09SDavid van Moolenbroek 		 * The iterator may hold the tree lock, and
936*00b67f09SDavid van Moolenbroek 		 * rrset_exists() calls dns_db_findnode() which
937*00b67f09SDavid van Moolenbroek 		 * may try to reacquire it.  To avoid deadlock
938*00b67f09SDavid van Moolenbroek 		 * we must pause the iterator first.
939*00b67f09SDavid van Moolenbroek 		 */
940*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_pause(dbit));
941*00b67f09SDavid van Moolenbroek 		if (secure) {
942*00b67f09SDavid van Moolenbroek 			CHECK(rrset_exists(db, ver, newname,
943*00b67f09SDavid van Moolenbroek 					   dns_rdatatype_nsec, 0, &has_nsec));
944*00b67f09SDavid van Moolenbroek 		} else {
945*00b67f09SDavid van Moolenbroek 			dns_fixedname_t ffound;
946*00b67f09SDavid van Moolenbroek 			dns_name_t *found;
947*00b67f09SDavid van Moolenbroek 			dns_fixedname_init(&ffound);
948*00b67f09SDavid van Moolenbroek 			found = dns_fixedname_name(&ffound);
949*00b67f09SDavid van Moolenbroek 			result = dns_db_find(db, newname, ver,
950*00b67f09SDavid van Moolenbroek 					     dns_rdatatype_soa,
951*00b67f09SDavid van Moolenbroek 					     DNS_DBFIND_NOWILD, 0, NULL, found,
952*00b67f09SDavid van Moolenbroek 					     NULL, NULL);
953*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS ||
954*00b67f09SDavid van Moolenbroek 			    result == DNS_R_EMPTYNAME ||
955*00b67f09SDavid van Moolenbroek 			    result == DNS_R_NXRRSET ||
956*00b67f09SDavid van Moolenbroek 			    result == DNS_R_CNAME ||
957*00b67f09SDavid van Moolenbroek 			    (result == DNS_R_DELEGATION &&
958*00b67f09SDavid van Moolenbroek 			     dns_name_equal(newname, found))) {
959*00b67f09SDavid van Moolenbroek 				has_nsec = ISC_TRUE;
960*00b67f09SDavid van Moolenbroek 				result = ISC_R_SUCCESS;
961*00b67f09SDavid van Moolenbroek 			} else if (result != DNS_R_NXDOMAIN)
962*00b67f09SDavid van Moolenbroek 				break;
963*00b67f09SDavid van Moolenbroek 		}
964*00b67f09SDavid van Moolenbroek 	} while (! has_nsec);
965*00b67f09SDavid van Moolenbroek  failure:
966*00b67f09SDavid van Moolenbroek 	if (dbit != NULL)
967*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&dbit);
968*00b67f09SDavid van Moolenbroek 
969*00b67f09SDavid van Moolenbroek 	return (result);
970*00b67f09SDavid van Moolenbroek }
971*00b67f09SDavid van Moolenbroek 
972*00b67f09SDavid van Moolenbroek /*%
973*00b67f09SDavid van Moolenbroek  * Add a NSEC record for "name", recording the change in "diff".
974*00b67f09SDavid van Moolenbroek  * The existing NSEC is removed.
975*00b67f09SDavid van Moolenbroek  */
976*00b67f09SDavid van Moolenbroek static isc_result_t
add_nsec(dns_update_log_t * log,dns_zone_t * zone,dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_ttl_t nsecttl,dns_diff_t * diff)977*00b67f09SDavid van Moolenbroek add_nsec(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
978*00b67f09SDavid van Moolenbroek 	 dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl,
979*00b67f09SDavid van Moolenbroek 	 dns_diff_t *diff)
980*00b67f09SDavid van Moolenbroek {
981*00b67f09SDavid van Moolenbroek 	isc_result_t result;
982*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
983*00b67f09SDavid van Moolenbroek 	unsigned char buffer[DNS_NSEC_BUFFERSIZE];
984*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
985*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
986*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixedname;
987*00b67f09SDavid van Moolenbroek 	dns_name_t *target;
988*00b67f09SDavid van Moolenbroek 
989*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixedname);
990*00b67f09SDavid van Moolenbroek 	target = dns_fixedname_name(&fixedname);
991*00b67f09SDavid van Moolenbroek 
992*00b67f09SDavid van Moolenbroek 	/*
993*00b67f09SDavid van Moolenbroek 	 * Find the successor name, aka NSEC target.
994*00b67f09SDavid van Moolenbroek 	 */
995*00b67f09SDavid van Moolenbroek 	CHECK(next_active(log, zone, db, ver, name, target, ISC_TRUE));
996*00b67f09SDavid van Moolenbroek 
997*00b67f09SDavid van Moolenbroek 	/*
998*00b67f09SDavid van Moolenbroek 	 * Create the NSEC RDATA.
999*00b67f09SDavid van Moolenbroek 	 */
1000*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1001*00b67f09SDavid van Moolenbroek 	dns_rdata_init(&rdata);
1002*00b67f09SDavid van Moolenbroek 	CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
1003*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1004*00b67f09SDavid van Moolenbroek 
1005*00b67f09SDavid van Moolenbroek 	/*
1006*00b67f09SDavid van Moolenbroek 	 * Delete the old NSEC and record the change.
1007*00b67f09SDavid van Moolenbroek 	 */
1008*00b67f09SDavid van Moolenbroek 	CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0,
1009*00b67f09SDavid van Moolenbroek 			NULL, diff));
1010*00b67f09SDavid van Moolenbroek 	/*
1011*00b67f09SDavid van Moolenbroek 	 * Add the new NSEC and record the change.
1012*00b67f09SDavid van Moolenbroek 	 */
1013*00b67f09SDavid van Moolenbroek 	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
1014*00b67f09SDavid van Moolenbroek 				   nsecttl, &rdata, &tuple));
1015*00b67f09SDavid van Moolenbroek 	CHECK(do_one_tuple(&tuple, db, ver, diff));
1016*00b67f09SDavid van Moolenbroek 	INSIST(tuple == NULL);
1017*00b67f09SDavid van Moolenbroek 
1018*00b67f09SDavid van Moolenbroek  failure:
1019*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1020*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1021*00b67f09SDavid van Moolenbroek 	return (result);
1022*00b67f09SDavid van Moolenbroek }
1023*00b67f09SDavid van Moolenbroek 
1024*00b67f09SDavid van Moolenbroek /*%
1025*00b67f09SDavid van Moolenbroek  * Add a placeholder NSEC record for "name", recording the change in "diff".
1026*00b67f09SDavid van Moolenbroek  */
1027*00b67f09SDavid van Moolenbroek static isc_result_t
add_placeholder_nsec(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_diff_t * diff)1028*00b67f09SDavid van Moolenbroek add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1029*00b67f09SDavid van Moolenbroek 		     dns_diff_t *diff)
1030*00b67f09SDavid van Moolenbroek {
1031*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1032*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
1033*00b67f09SDavid van Moolenbroek 	isc_region_t r;
1034*00b67f09SDavid van Moolenbroek 	unsigned char data[1] = { 0 }; /* The root domain, no bits. */
1035*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
1036*00b67f09SDavid van Moolenbroek 
1037*00b67f09SDavid van Moolenbroek 	r.base = data;
1038*00b67f09SDavid van Moolenbroek 	r.length = sizeof(data);
1039*00b67f09SDavid van Moolenbroek 	dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
1040*00b67f09SDavid van Moolenbroek 	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
1041*00b67f09SDavid van Moolenbroek 				   &rdata, &tuple));
1042*00b67f09SDavid van Moolenbroek 	CHECK(do_one_tuple(&tuple, db, ver, diff));
1043*00b67f09SDavid van Moolenbroek  failure:
1044*00b67f09SDavid van Moolenbroek 	return (result);
1045*00b67f09SDavid van Moolenbroek }
1046*00b67f09SDavid van Moolenbroek 
1047*00b67f09SDavid van Moolenbroek static isc_result_t
find_zone_keys(dns_zone_t * zone,dns_db_t * db,dns_dbversion_t * ver,isc_mem_t * mctx,unsigned int maxkeys,dst_key_t ** keys,unsigned int * nkeys)1048*00b67f09SDavid van Moolenbroek find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
1049*00b67f09SDavid van Moolenbroek 	       isc_mem_t *mctx, unsigned int maxkeys,
1050*00b67f09SDavid van Moolenbroek 	       dst_key_t **keys, unsigned int *nkeys)
1051*00b67f09SDavid van Moolenbroek {
1052*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1053*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1054*00b67f09SDavid van Moolenbroek 	const char *directory = dns_zone_getkeydirectory(zone);
1055*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1056*00b67f09SDavid van Moolenbroek 	CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
1057*00b67f09SDavid van Moolenbroek 				       directory, mctx, maxkeys, keys, nkeys));
1058*00b67f09SDavid van Moolenbroek  failure:
1059*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1060*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1061*00b67f09SDavid van Moolenbroek 	return (result);
1062*00b67f09SDavid van Moolenbroek }
1063*00b67f09SDavid van Moolenbroek 
1064*00b67f09SDavid van Moolenbroek /*%
1065*00b67f09SDavid van Moolenbroek  * Add RRSIG records for an RRset, recording the change in "diff".
1066*00b67f09SDavid van Moolenbroek  */
1067*00b67f09SDavid van Moolenbroek static isc_result_t
add_sigs(dns_update_log_t * log,dns_zone_t * zone,dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_rdatatype_t type,dns_diff_t * diff,dst_key_t ** keys,unsigned int nkeys,isc_stdtime_t inception,isc_stdtime_t expire,isc_boolean_t check_ksk,isc_boolean_t keyset_kskonly)1068*00b67f09SDavid van Moolenbroek add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1069*00b67f09SDavid van Moolenbroek 	 dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type,
1070*00b67f09SDavid van Moolenbroek 	 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1071*00b67f09SDavid van Moolenbroek 	 isc_stdtime_t inception, isc_stdtime_t expire,
1072*00b67f09SDavid van Moolenbroek 	 isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
1073*00b67f09SDavid van Moolenbroek {
1074*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1075*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1076*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1077*00b67f09SDavid van Moolenbroek 	dns_rdata_t sig_rdata = DNS_RDATA_INIT;
1078*00b67f09SDavid van Moolenbroek 	isc_buffer_t buffer;
1079*00b67f09SDavid van Moolenbroek 	unsigned char data[1024]; /* XXX */
1080*00b67f09SDavid van Moolenbroek 	unsigned int i, j;
1081*00b67f09SDavid van Moolenbroek 	isc_boolean_t added_sig = ISC_FALSE;
1082*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx = diff->mctx;
1083*00b67f09SDavid van Moolenbroek 
1084*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1085*00b67f09SDavid van Moolenbroek 	isc_buffer_init(&buffer, data, sizeof(data));
1086*00b67f09SDavid van Moolenbroek 
1087*00b67f09SDavid van Moolenbroek 	/* Get the rdataset to sign. */
1088*00b67f09SDavid van Moolenbroek 	if (type == dns_rdatatype_nsec3)
1089*00b67f09SDavid van Moolenbroek 		CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
1090*00b67f09SDavid van Moolenbroek 	else
1091*00b67f09SDavid van Moolenbroek 		CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
1092*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_findrdataset(db, node, ver, type, 0,
1093*00b67f09SDavid van Moolenbroek 				  (isc_stdtime_t) 0, &rdataset, NULL));
1094*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1095*00b67f09SDavid van Moolenbroek 
1096*00b67f09SDavid van Moolenbroek #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
1097*00b67f09SDavid van Moolenbroek #define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
1098*00b67f09SDavid van Moolenbroek #define ALG(x) dst_key_alg(x)
1099*00b67f09SDavid van Moolenbroek 
1100*00b67f09SDavid van Moolenbroek 	/*
1101*00b67f09SDavid van Moolenbroek 	 * If we are honoring KSK flags then we need to check that we
1102*00b67f09SDavid van Moolenbroek 	 * have both KSK and non-KSK keys that are not revoked per
1103*00b67f09SDavid van Moolenbroek 	 * algorithm.
1104*00b67f09SDavid van Moolenbroek 	 */
1105*00b67f09SDavid van Moolenbroek 	for (i = 0; i < nkeys; i++) {
1106*00b67f09SDavid van Moolenbroek 		isc_boolean_t both = ISC_FALSE;
1107*00b67f09SDavid van Moolenbroek 
1108*00b67f09SDavid van Moolenbroek 		if (!dst_key_isprivate(keys[i]))
1109*00b67f09SDavid van Moolenbroek 			continue;
1110*00b67f09SDavid van Moolenbroek 
1111*00b67f09SDavid van Moolenbroek 		if (check_ksk && !REVOKE(keys[i])) {
1112*00b67f09SDavid van Moolenbroek 			isc_boolean_t have_ksk, have_nonksk;
1113*00b67f09SDavid van Moolenbroek 			if (KSK(keys[i])) {
1114*00b67f09SDavid van Moolenbroek 				have_ksk = ISC_TRUE;
1115*00b67f09SDavid van Moolenbroek 				have_nonksk = ISC_FALSE;
1116*00b67f09SDavid van Moolenbroek 			} else {
1117*00b67f09SDavid van Moolenbroek 				have_ksk = ISC_FALSE;
1118*00b67f09SDavid van Moolenbroek 				have_nonksk = ISC_TRUE;
1119*00b67f09SDavid van Moolenbroek 			}
1120*00b67f09SDavid van Moolenbroek 			for (j = 0; j < nkeys; j++) {
1121*00b67f09SDavid van Moolenbroek 				if (j == i || ALG(keys[i]) != ALG(keys[j]))
1122*00b67f09SDavid van Moolenbroek 					continue;
1123*00b67f09SDavid van Moolenbroek 				if (REVOKE(keys[j]))
1124*00b67f09SDavid van Moolenbroek 					continue;
1125*00b67f09SDavid van Moolenbroek 				if (KSK(keys[j]))
1126*00b67f09SDavid van Moolenbroek 					have_ksk = ISC_TRUE;
1127*00b67f09SDavid van Moolenbroek 				else
1128*00b67f09SDavid van Moolenbroek 					have_nonksk = ISC_TRUE;
1129*00b67f09SDavid van Moolenbroek 				both = have_ksk && have_nonksk;
1130*00b67f09SDavid van Moolenbroek 				if (both)
1131*00b67f09SDavid van Moolenbroek 					break;
1132*00b67f09SDavid van Moolenbroek 			}
1133*00b67f09SDavid van Moolenbroek 		}
1134*00b67f09SDavid van Moolenbroek 
1135*00b67f09SDavid van Moolenbroek 		if (both) {
1136*00b67f09SDavid van Moolenbroek 			if (type == dns_rdatatype_dnskey) {
1137*00b67f09SDavid van Moolenbroek 				if (!KSK(keys[i]) && keyset_kskonly)
1138*00b67f09SDavid van Moolenbroek 					continue;
1139*00b67f09SDavid van Moolenbroek 			} else if (KSK(keys[i]))
1140*00b67f09SDavid van Moolenbroek 				continue;
1141*00b67f09SDavid van Moolenbroek 		} else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey)
1142*00b67f09SDavid van Moolenbroek 			continue;
1143*00b67f09SDavid van Moolenbroek 
1144*00b67f09SDavid van Moolenbroek 		/* Calculate the signature, creating a RRSIG RDATA. */
1145*00b67f09SDavid van Moolenbroek 		CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
1146*00b67f09SDavid van Moolenbroek 				      &inception, &expire,
1147*00b67f09SDavid van Moolenbroek 				      mctx, &buffer, &sig_rdata));
1148*00b67f09SDavid van Moolenbroek 
1149*00b67f09SDavid van Moolenbroek 		/* Update the database and journal with the RRSIG. */
1150*00b67f09SDavid van Moolenbroek 		/* XXX inefficient - will cause dataset merging */
1151*00b67f09SDavid van Moolenbroek 		CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, name,
1152*00b67f09SDavid van Moolenbroek 				    rdataset.ttl, &sig_rdata));
1153*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&sig_rdata);
1154*00b67f09SDavid van Moolenbroek 		isc_buffer_init(&buffer, data, sizeof(data));
1155*00b67f09SDavid van Moolenbroek 		added_sig = ISC_TRUE;
1156*00b67f09SDavid van Moolenbroek 	}
1157*00b67f09SDavid van Moolenbroek 	if (!added_sig) {
1158*00b67f09SDavid van Moolenbroek 		update_log(log, zone, ISC_LOG_ERROR,
1159*00b67f09SDavid van Moolenbroek 			   "found no active private keys, "
1160*00b67f09SDavid van Moolenbroek 			   "unable to generate any signatures");
1161*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOTFOUND;
1162*00b67f09SDavid van Moolenbroek 	}
1163*00b67f09SDavid van Moolenbroek 
1164*00b67f09SDavid van Moolenbroek  failure:
1165*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
1166*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1167*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1168*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1169*00b67f09SDavid van Moolenbroek 	return (result);
1170*00b67f09SDavid van Moolenbroek }
1171*00b67f09SDavid van Moolenbroek 
1172*00b67f09SDavid van Moolenbroek /*
1173*00b67f09SDavid van Moolenbroek  * Delete expired RRsigs and any RRsigs we are about to re-sign.
1174*00b67f09SDavid van Moolenbroek  * See also zone.c:del_sigs().
1175*00b67f09SDavid van Moolenbroek  */
1176*00b67f09SDavid van Moolenbroek static isc_result_t
del_keysigs(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,dns_diff_t * diff,dst_key_t ** keys,unsigned int nkeys)1177*00b67f09SDavid van Moolenbroek del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1178*00b67f09SDavid van Moolenbroek 	    dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys)
1179*00b67f09SDavid van Moolenbroek {
1180*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1181*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1182*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1183*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
1184*00b67f09SDavid van Moolenbroek 	unsigned int i;
1185*00b67f09SDavid van Moolenbroek 	dns_rdata_rrsig_t rrsig;
1186*00b67f09SDavid van Moolenbroek 	isc_boolean_t found;
1187*00b67f09SDavid van Moolenbroek 
1188*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1189*00b67f09SDavid van Moolenbroek 
1190*00b67f09SDavid van Moolenbroek 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
1191*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1192*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1193*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1194*00b67f09SDavid van Moolenbroek 		goto failure;
1195*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
1196*00b67f09SDavid van Moolenbroek 				     dns_rdatatype_dnskey, (isc_stdtime_t) 0,
1197*00b67f09SDavid van Moolenbroek 				     &rdataset, NULL);
1198*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1199*00b67f09SDavid van Moolenbroek 
1200*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1201*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1202*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1203*00b67f09SDavid van Moolenbroek 		goto failure;
1204*00b67f09SDavid van Moolenbroek 
1205*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1206*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1207*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1208*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
1209*00b67f09SDavid van Moolenbroek 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
1210*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1211*00b67f09SDavid van Moolenbroek 		found = ISC_FALSE;
1212*00b67f09SDavid van Moolenbroek 		for (i = 0; i < nkeys; i++) {
1213*00b67f09SDavid van Moolenbroek 			if (rrsig.keyid == dst_key_id(keys[i])) {
1214*00b67f09SDavid van Moolenbroek 				found = ISC_TRUE;
1215*00b67f09SDavid van Moolenbroek 				if (!dst_key_isprivate(keys[i]) &&
1216*00b67f09SDavid van Moolenbroek 				    !dst_key_inactive(keys[i]))
1217*00b67f09SDavid van Moolenbroek 				{
1218*00b67f09SDavid van Moolenbroek 					/*
1219*00b67f09SDavid van Moolenbroek 					 * The re-signing code in zone.c
1220*00b67f09SDavid van Moolenbroek 					 * will mark this as offline.
1221*00b67f09SDavid van Moolenbroek 					 * Just skip the record for now.
1222*00b67f09SDavid van Moolenbroek 					 */
1223*00b67f09SDavid van Moolenbroek 					break;
1224*00b67f09SDavid van Moolenbroek 				}
1225*00b67f09SDavid van Moolenbroek 				result = update_one_rr(db, ver, diff,
1226*00b67f09SDavid van Moolenbroek 						       DNS_DIFFOP_DEL, name,
1227*00b67f09SDavid van Moolenbroek 						       rdataset.ttl, &rdata);
1228*00b67f09SDavid van Moolenbroek 				break;
1229*00b67f09SDavid van Moolenbroek 			}
1230*00b67f09SDavid van Moolenbroek 		}
1231*00b67f09SDavid van Moolenbroek 		/*
1232*00b67f09SDavid van Moolenbroek 		 * If there is not a matching DNSKEY then delete the RRSIG.
1233*00b67f09SDavid van Moolenbroek 		 */
1234*00b67f09SDavid van Moolenbroek 		if (!found)
1235*00b67f09SDavid van Moolenbroek 			result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
1236*00b67f09SDavid van Moolenbroek 					       name, rdataset.ttl, &rdata);
1237*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&rdata);
1238*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1239*00b67f09SDavid van Moolenbroek 			break;
1240*00b67f09SDavid van Moolenbroek 	}
1241*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1242*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1243*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1244*00b67f09SDavid van Moolenbroek failure:
1245*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1246*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1247*00b67f09SDavid van Moolenbroek 	return (result);
1248*00b67f09SDavid van Moolenbroek }
1249*00b67f09SDavid van Moolenbroek 
1250*00b67f09SDavid van Moolenbroek static isc_result_t
add_exposed_sigs(dns_update_log_t * log,dns_zone_t * zone,dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,isc_boolean_t cut,dns_diff_t * diff,dst_key_t ** keys,unsigned int nkeys,isc_stdtime_t inception,isc_stdtime_t expire,isc_boolean_t check_ksk,isc_boolean_t keyset_kskonly)1251*00b67f09SDavid van Moolenbroek add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1252*00b67f09SDavid van Moolenbroek 		 dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut,
1253*00b67f09SDavid van Moolenbroek 		 dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
1254*00b67f09SDavid van Moolenbroek 		 isc_stdtime_t inception, isc_stdtime_t expire,
1255*00b67f09SDavid van Moolenbroek 		 isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
1256*00b67f09SDavid van Moolenbroek {
1257*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1258*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node;
1259*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_t *iter;
1260*00b67f09SDavid van Moolenbroek 
1261*00b67f09SDavid van Moolenbroek 	node = NULL;
1262*00b67f09SDavid van Moolenbroek 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
1263*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1264*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1265*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1266*00b67f09SDavid van Moolenbroek 		return (result);
1267*00b67f09SDavid van Moolenbroek 
1268*00b67f09SDavid van Moolenbroek 	iter = NULL;
1269*00b67f09SDavid van Moolenbroek 	result = dns_db_allrdatasets(db, node, ver,
1270*00b67f09SDavid van Moolenbroek 				     (isc_stdtime_t) 0, &iter);
1271*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1272*00b67f09SDavid van Moolenbroek 		goto cleanup_node;
1273*00b67f09SDavid van Moolenbroek 
1274*00b67f09SDavid van Moolenbroek 	for (result = dns_rdatasetiter_first(iter);
1275*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1276*00b67f09SDavid van Moolenbroek 	     result = dns_rdatasetiter_next(iter))
1277*00b67f09SDavid van Moolenbroek 	{
1278*00b67f09SDavid van Moolenbroek 		dns_rdataset_t rdataset;
1279*00b67f09SDavid van Moolenbroek 		dns_rdatatype_t type;
1280*00b67f09SDavid van Moolenbroek 		isc_boolean_t flag;
1281*00b67f09SDavid van Moolenbroek 
1282*00b67f09SDavid van Moolenbroek 		dns_rdataset_init(&rdataset);
1283*00b67f09SDavid van Moolenbroek 		dns_rdatasetiter_current(iter, &rdataset);
1284*00b67f09SDavid van Moolenbroek 		type = rdataset.type;
1285*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1286*00b67f09SDavid van Moolenbroek 
1287*00b67f09SDavid van Moolenbroek 		/*
1288*00b67f09SDavid van Moolenbroek 		 * We don't need to sign unsigned NSEC records at the cut
1289*00b67f09SDavid van Moolenbroek 		 * as they are handled elsewhere.
1290*00b67f09SDavid van Moolenbroek 		 */
1291*00b67f09SDavid van Moolenbroek 		if ((type == dns_rdatatype_rrsig) ||
1292*00b67f09SDavid van Moolenbroek 		    (cut && type != dns_rdatatype_ds))
1293*00b67f09SDavid van Moolenbroek 			continue;
1294*00b67f09SDavid van Moolenbroek 		result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
1295*00b67f09SDavid van Moolenbroek 				      type, &flag);
1296*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1297*00b67f09SDavid van Moolenbroek 			goto cleanup_iterator;
1298*00b67f09SDavid van Moolenbroek 		if (flag)
1299*00b67f09SDavid van Moolenbroek 			continue;;
1300*00b67f09SDavid van Moolenbroek 		result = add_sigs(log, zone, db, ver, name, type, diff,
1301*00b67f09SDavid van Moolenbroek 					  keys, nkeys, inception, expire,
1302*00b67f09SDavid van Moolenbroek 					  check_ksk, keyset_kskonly);
1303*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1304*00b67f09SDavid van Moolenbroek 			goto cleanup_iterator;
1305*00b67f09SDavid van Moolenbroek 	}
1306*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1307*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1308*00b67f09SDavid van Moolenbroek 
1309*00b67f09SDavid van Moolenbroek  cleanup_iterator:
1310*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_destroy(&iter);
1311*00b67f09SDavid van Moolenbroek 
1312*00b67f09SDavid van Moolenbroek  cleanup_node:
1313*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1314*00b67f09SDavid van Moolenbroek 
1315*00b67f09SDavid van Moolenbroek 	return (result);
1316*00b67f09SDavid van Moolenbroek }
1317*00b67f09SDavid van Moolenbroek 
1318*00b67f09SDavid van Moolenbroek /*%
1319*00b67f09SDavid van Moolenbroek  * Update RRSIG, NSEC and NSEC3 records affected by an update.  The original
1320*00b67f09SDavid van Moolenbroek  * update, including the SOA serial update but excluding the RRSIG & NSEC
1321*00b67f09SDavid van Moolenbroek  * changes, is in "diff" and has already been applied to "newver" of "db".
1322*00b67f09SDavid van Moolenbroek  * The database version prior to the update is "oldver".
1323*00b67f09SDavid van Moolenbroek  *
1324*00b67f09SDavid van Moolenbroek  * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
1325*00b67f09SDavid van Moolenbroek  * and added (as a minimal diff) to "diff".
1326*00b67f09SDavid van Moolenbroek  *
1327*00b67f09SDavid van Moolenbroek  * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
1328*00b67f09SDavid van Moolenbroek  */
1329*00b67f09SDavid van Moolenbroek isc_result_t
dns_update_signatures(dns_update_log_t * log,dns_zone_t * zone,dns_db_t * db,dns_dbversion_t * oldver,dns_dbversion_t * newver,dns_diff_t * diff,isc_uint32_t sigvalidityinterval)1330*00b67f09SDavid van Moolenbroek dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
1331*00b67f09SDavid van Moolenbroek 		      dns_dbversion_t *oldver, dns_dbversion_t *newver,
1332*00b67f09SDavid van Moolenbroek 		      dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
1333*00b67f09SDavid van Moolenbroek {
1334*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1335*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *t;
1336*00b67f09SDavid van Moolenbroek 	dns_diff_t diffnames;
1337*00b67f09SDavid van Moolenbroek 	dns_diff_t affected;
1338*00b67f09SDavid van Moolenbroek 	dns_diff_t sig_diff;
1339*00b67f09SDavid van Moolenbroek 	dns_diff_t nsec_diff;
1340*00b67f09SDavid van Moolenbroek 	dns_diff_t nsec_mindiff;
1341*00b67f09SDavid van Moolenbroek 	isc_boolean_t flag, build_nsec, build_nsec3;
1342*00b67f09SDavid van Moolenbroek 	dst_key_t *zone_keys[DNS_MAXZONEKEYS];
1343*00b67f09SDavid van Moolenbroek 	unsigned int nkeys = 0;
1344*00b67f09SDavid van Moolenbroek 	unsigned int i;
1345*00b67f09SDavid van Moolenbroek 	isc_stdtime_t now, inception, expire;
1346*00b67f09SDavid van Moolenbroek 	dns_ttl_t nsecttl;
1347*00b67f09SDavid van Moolenbroek 	dns_rdata_soa_t soa;
1348*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
1349*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1350*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1351*00b67f09SDavid van Moolenbroek 	isc_boolean_t check_ksk, keyset_kskonly;
1352*00b67f09SDavid van Moolenbroek 	isc_boolean_t unsecure;
1353*00b67f09SDavid van Moolenbroek 	isc_boolean_t cut;
1354*00b67f09SDavid van Moolenbroek 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
1355*00b67f09SDavid van Moolenbroek 
1356*00b67f09SDavid van Moolenbroek 	dns_diff_init(diff->mctx, &diffnames);
1357*00b67f09SDavid van Moolenbroek 	dns_diff_init(diff->mctx, &affected);
1358*00b67f09SDavid van Moolenbroek 
1359*00b67f09SDavid van Moolenbroek 	dns_diff_init(diff->mctx, &sig_diff);
1360*00b67f09SDavid van Moolenbroek 	dns_diff_init(diff->mctx, &nsec_diff);
1361*00b67f09SDavid van Moolenbroek 	dns_diff_init(diff->mctx, &nsec_mindiff);
1362*00b67f09SDavid van Moolenbroek 
1363*00b67f09SDavid van Moolenbroek 	result = find_zone_keys(zone, db, newver, diff->mctx,
1364*00b67f09SDavid van Moolenbroek 				DNS_MAXZONEKEYS, zone_keys, &nkeys);
1365*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1366*00b67f09SDavid van Moolenbroek 		update_log(log, zone, ISC_LOG_ERROR,
1367*00b67f09SDavid van Moolenbroek 			   "could not get zone keys for secure dynamic update");
1368*00b67f09SDavid van Moolenbroek 		goto failure;
1369*00b67f09SDavid van Moolenbroek 	}
1370*00b67f09SDavid van Moolenbroek 
1371*00b67f09SDavid van Moolenbroek 	isc_stdtime_get(&now);
1372*00b67f09SDavid van Moolenbroek 	inception = now - 3600; /* Allow for some clock skew. */
1373*00b67f09SDavid van Moolenbroek 	expire = now + sigvalidityinterval;
1374*00b67f09SDavid van Moolenbroek 
1375*00b67f09SDavid van Moolenbroek 	/*
1376*00b67f09SDavid van Moolenbroek 	 * Do we look at the KSK flag on the DNSKEY to determining which
1377*00b67f09SDavid van Moolenbroek 	 * keys sign which RRsets?  First check the zone option then
1378*00b67f09SDavid van Moolenbroek 	 * check the keys flags to make sure at least one has a ksk set
1379*00b67f09SDavid van Moolenbroek 	 * and one doesn't.
1380*00b67f09SDavid van Moolenbroek 	 */
1381*00b67f09SDavid van Moolenbroek 	check_ksk = ISC_TF((dns_zone_getoptions(zone) &
1382*00b67f09SDavid van Moolenbroek 			    DNS_ZONEOPT_UPDATECHECKKSK) != 0);
1383*00b67f09SDavid van Moolenbroek 	keyset_kskonly = ISC_TF((dns_zone_getoptions(zone) &
1384*00b67f09SDavid van Moolenbroek 				DNS_ZONEOPT_DNSKEYKSKONLY) != 0);
1385*00b67f09SDavid van Moolenbroek 
1386*00b67f09SDavid van Moolenbroek 	/*
1387*00b67f09SDavid van Moolenbroek 	 * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
1388*00b67f09SDavid van Moolenbroek 	 */
1389*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
1390*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1391*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0,
1392*00b67f09SDavid van Moolenbroek 				  (isc_stdtime_t) 0, &rdataset, NULL));
1393*00b67f09SDavid van Moolenbroek 	CHECK(dns_rdataset_first(&rdataset));
1394*00b67f09SDavid van Moolenbroek 	dns_rdataset_current(&rdataset, &rdata);
1395*00b67f09SDavid van Moolenbroek 	CHECK(dns_rdata_tostruct(&rdata, &soa, NULL));
1396*00b67f09SDavid van Moolenbroek 	nsecttl = soa.minimum;
1397*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1398*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1399*00b67f09SDavid van Moolenbroek 
1400*00b67f09SDavid van Moolenbroek 	/*
1401*00b67f09SDavid van Moolenbroek 	 * Find all RRsets directly affected by the update, and
1402*00b67f09SDavid van Moolenbroek 	 * update their RRSIGs.  Also build a list of names affected
1403*00b67f09SDavid van Moolenbroek 	 * by the update in "diffnames".
1404*00b67f09SDavid van Moolenbroek 	 */
1405*00b67f09SDavid van Moolenbroek 	CHECK(dns_diff_sort(diff, temp_order));
1406*00b67f09SDavid van Moolenbroek 
1407*00b67f09SDavid van Moolenbroek 	t = ISC_LIST_HEAD(diff->tuples);
1408*00b67f09SDavid van Moolenbroek 	while (t != NULL) {
1409*00b67f09SDavid van Moolenbroek 		dns_name_t *name = &t->name;
1410*00b67f09SDavid van Moolenbroek 		/* Now "name" is a new, unique name affected by the update. */
1411*00b67f09SDavid van Moolenbroek 
1412*00b67f09SDavid van Moolenbroek 		CHECK(namelist_append_name(&diffnames, name));
1413*00b67f09SDavid van Moolenbroek 
1414*00b67f09SDavid van Moolenbroek 		while (t != NULL && dns_name_equal(&t->name, name)) {
1415*00b67f09SDavid van Moolenbroek 			dns_rdatatype_t type;
1416*00b67f09SDavid van Moolenbroek 			type = t->rdata.type;
1417*00b67f09SDavid van Moolenbroek 
1418*00b67f09SDavid van Moolenbroek 			/*
1419*00b67f09SDavid van Moolenbroek 			 * Now "name" and "type" denote a new unique RRset
1420*00b67f09SDavid van Moolenbroek 			 * affected by the update.
1421*00b67f09SDavid van Moolenbroek 			 */
1422*00b67f09SDavid van Moolenbroek 
1423*00b67f09SDavid van Moolenbroek 			/* Don't sign RRSIGs. */
1424*00b67f09SDavid van Moolenbroek 			if (type == dns_rdatatype_rrsig)
1425*00b67f09SDavid van Moolenbroek 				goto skip;
1426*00b67f09SDavid van Moolenbroek 
1427*00b67f09SDavid van Moolenbroek 			/*
1428*00b67f09SDavid van Moolenbroek 			 * Delete all old RRSIGs covering this type, since they
1429*00b67f09SDavid van Moolenbroek 			 * are all invalid when the signed RRset has changed.
1430*00b67f09SDavid van Moolenbroek 			 * We may not be able to recreate all of them - tough.
1431*00b67f09SDavid van Moolenbroek 			 * Special case changes to the zone's DNSKEY records
1432*00b67f09SDavid van Moolenbroek 			 * to support offline KSKs.
1433*00b67f09SDavid van Moolenbroek 			 */
1434*00b67f09SDavid van Moolenbroek 			if (type == dns_rdatatype_dnskey)
1435*00b67f09SDavid van Moolenbroek 				del_keysigs(db, newver, name, &sig_diff,
1436*00b67f09SDavid van Moolenbroek 					    zone_keys, nkeys);
1437*00b67f09SDavid van Moolenbroek 			else
1438*00b67f09SDavid van Moolenbroek 				CHECK(delete_if(true_p, db, newver, name,
1439*00b67f09SDavid van Moolenbroek 						dns_rdatatype_rrsig, type,
1440*00b67f09SDavid van Moolenbroek 						NULL, &sig_diff));
1441*00b67f09SDavid van Moolenbroek 
1442*00b67f09SDavid van Moolenbroek 			/*
1443*00b67f09SDavid van Moolenbroek 			 * If this RRset is still visible after the update,
1444*00b67f09SDavid van Moolenbroek 			 * add a new signature for it.
1445*00b67f09SDavid van Moolenbroek 			 */
1446*00b67f09SDavid van Moolenbroek 			CHECK(rrset_visible(db, newver, name, type, &flag));
1447*00b67f09SDavid van Moolenbroek 			if (flag) {
1448*00b67f09SDavid van Moolenbroek 				CHECK(add_sigs(log, zone, db, newver, name,
1449*00b67f09SDavid van Moolenbroek 					       type, &sig_diff, zone_keys,
1450*00b67f09SDavid van Moolenbroek 					       nkeys, inception, expire,
1451*00b67f09SDavid van Moolenbroek 					       check_ksk, keyset_kskonly));
1452*00b67f09SDavid van Moolenbroek 			}
1453*00b67f09SDavid van Moolenbroek 		skip:
1454*00b67f09SDavid van Moolenbroek 			/* Skip any other updates to the same RRset. */
1455*00b67f09SDavid van Moolenbroek 			while (t != NULL &&
1456*00b67f09SDavid van Moolenbroek 			       dns_name_equal(&t->name, name) &&
1457*00b67f09SDavid van Moolenbroek 			       t->rdata.type == type)
1458*00b67f09SDavid van Moolenbroek 			{
1459*00b67f09SDavid van Moolenbroek 				t = ISC_LIST_NEXT(t, link);
1460*00b67f09SDavid van Moolenbroek 			}
1461*00b67f09SDavid van Moolenbroek 		}
1462*00b67f09SDavid van Moolenbroek 	}
1463*00b67f09SDavid van Moolenbroek 	update_log(log, zone, ISC_LOG_DEBUG(3), "updated data signatures");
1464*00b67f09SDavid van Moolenbroek 
1465*00b67f09SDavid van Moolenbroek 	/* Remove orphaned NSECs and RRSIG NSECs. */
1466*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(diffnames.tuples);
1467*00b67f09SDavid van Moolenbroek 	     t != NULL;
1468*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link))
1469*00b67f09SDavid van Moolenbroek 	{
1470*00b67f09SDavid van Moolenbroek 		CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag));
1471*00b67f09SDavid van Moolenbroek 		if (! flag) {
1472*00b67f09SDavid van Moolenbroek 			CHECK(delete_if(true_p, db, newver, &t->name,
1473*00b67f09SDavid van Moolenbroek 					dns_rdatatype_any, 0,
1474*00b67f09SDavid van Moolenbroek 					NULL, &sig_diff));
1475*00b67f09SDavid van Moolenbroek 		}
1476*00b67f09SDavid van Moolenbroek 	}
1477*00b67f09SDavid van Moolenbroek 	update_log(log, zone, ISC_LOG_DEBUG(3),
1478*00b67f09SDavid van Moolenbroek 		   "removed any orphaned NSEC records");
1479*00b67f09SDavid van Moolenbroek 
1480*00b67f09SDavid van Moolenbroek 	/*
1481*00b67f09SDavid van Moolenbroek 	 * See if we need to build NSEC or NSEC3 chains.
1482*00b67f09SDavid van Moolenbroek 	 */
1483*00b67f09SDavid van Moolenbroek 	CHECK(dns_private_chains(db, newver, privatetype, &build_nsec,
1484*00b67f09SDavid van Moolenbroek 				 &build_nsec3));
1485*00b67f09SDavid van Moolenbroek 	if (!build_nsec)
1486*00b67f09SDavid van Moolenbroek 		goto update_nsec3;
1487*00b67f09SDavid van Moolenbroek 
1488*00b67f09SDavid van Moolenbroek 	update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
1489*00b67f09SDavid van Moolenbroek 
1490*00b67f09SDavid van Moolenbroek 	/*
1491*00b67f09SDavid van Moolenbroek 	 * When a name is created or deleted, its predecessor needs to
1492*00b67f09SDavid van Moolenbroek 	 * have its NSEC updated.
1493*00b67f09SDavid van Moolenbroek 	 */
1494*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(diffnames.tuples);
1495*00b67f09SDavid van Moolenbroek 	     t != NULL;
1496*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link))
1497*00b67f09SDavid van Moolenbroek 	{
1498*00b67f09SDavid van Moolenbroek 		isc_boolean_t existed, exists;
1499*00b67f09SDavid van Moolenbroek 		dns_fixedname_t fixedname;
1500*00b67f09SDavid van Moolenbroek 		dns_name_t *prevname;
1501*00b67f09SDavid van Moolenbroek 
1502*00b67f09SDavid van Moolenbroek 		dns_fixedname_init(&fixedname);
1503*00b67f09SDavid van Moolenbroek 		prevname = dns_fixedname_name(&fixedname);
1504*00b67f09SDavid van Moolenbroek 
1505*00b67f09SDavid van Moolenbroek 		if (oldver != NULL)
1506*00b67f09SDavid van Moolenbroek 			CHECK(name_exists(db, oldver, &t->name, &existed));
1507*00b67f09SDavid van Moolenbroek 		else
1508*00b67f09SDavid van Moolenbroek 			existed = ISC_FALSE;
1509*00b67f09SDavid van Moolenbroek 		CHECK(name_exists(db, newver, &t->name, &exists));
1510*00b67f09SDavid van Moolenbroek 		if (exists == existed)
1511*00b67f09SDavid van Moolenbroek 			continue;
1512*00b67f09SDavid van Moolenbroek 
1513*00b67f09SDavid van Moolenbroek 		/*
1514*00b67f09SDavid van Moolenbroek 		 * Find the predecessor.
1515*00b67f09SDavid van Moolenbroek 		 * When names become obscured or unobscured in this update
1516*00b67f09SDavid van Moolenbroek 		 * transaction, we may find the wrong predecessor because
1517*00b67f09SDavid van Moolenbroek 		 * the NSECs have not yet been updated to reflect the delegation
1518*00b67f09SDavid van Moolenbroek 		 * change.  This should not matter because in this case,
1519*00b67f09SDavid van Moolenbroek 		 * the correct predecessor is either the delegation node or
1520*00b67f09SDavid van Moolenbroek 		 * a newly unobscured node, and those nodes are on the
1521*00b67f09SDavid van Moolenbroek 		 * "affected" list in any case.
1522*00b67f09SDavid van Moolenbroek 		 */
1523*00b67f09SDavid van Moolenbroek 		CHECK(next_active(log, zone, db, newver,
1524*00b67f09SDavid van Moolenbroek 				  &t->name, prevname, ISC_FALSE));
1525*00b67f09SDavid van Moolenbroek 		CHECK(namelist_append_name(&affected, prevname));
1526*00b67f09SDavid van Moolenbroek 	}
1527*00b67f09SDavid van Moolenbroek 
1528*00b67f09SDavid van Moolenbroek 	/*
1529*00b67f09SDavid van Moolenbroek 	 * Find names potentially affected by delegation changes
1530*00b67f09SDavid van Moolenbroek 	 * (obscured by adding an NS or DNAME, or unobscured by
1531*00b67f09SDavid van Moolenbroek 	 * removing one).
1532*00b67f09SDavid van Moolenbroek 	 */
1533*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(diffnames.tuples);
1534*00b67f09SDavid van Moolenbroek 	     t != NULL;
1535*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link))
1536*00b67f09SDavid van Moolenbroek 	{
1537*00b67f09SDavid van Moolenbroek 		isc_boolean_t ns_existed, dname_existed;
1538*00b67f09SDavid van Moolenbroek 		isc_boolean_t ns_exists, dname_exists;
1539*00b67f09SDavid van Moolenbroek 
1540*00b67f09SDavid van Moolenbroek 		if (oldver != NULL)
1541*00b67f09SDavid van Moolenbroek 			CHECK(rrset_exists(db, oldver, &t->name,
1542*00b67f09SDavid van Moolenbroek 					  dns_rdatatype_ns, 0, &ns_existed));
1543*00b67f09SDavid van Moolenbroek 		else
1544*00b67f09SDavid van Moolenbroek 			ns_existed = ISC_FALSE;
1545*00b67f09SDavid van Moolenbroek 		if (oldver != NULL)
1546*00b67f09SDavid van Moolenbroek 			CHECK(rrset_exists(db, oldver, &t->name,
1547*00b67f09SDavid van Moolenbroek 					   dns_rdatatype_dname, 0,
1548*00b67f09SDavid van Moolenbroek 					   &dname_existed));
1549*00b67f09SDavid van Moolenbroek 		else
1550*00b67f09SDavid van Moolenbroek 			dname_existed = ISC_FALSE;
1551*00b67f09SDavid van Moolenbroek 		CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0,
1552*00b67f09SDavid van Moolenbroek 				   &ns_exists));
1553*00b67f09SDavid van Moolenbroek 		CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0,
1554*00b67f09SDavid van Moolenbroek 				   &dname_exists));
1555*00b67f09SDavid van Moolenbroek 		if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
1556*00b67f09SDavid van Moolenbroek 			continue;
1557*00b67f09SDavid van Moolenbroek 		/*
1558*00b67f09SDavid van Moolenbroek 		 * There was a delegation change.  Mark all subdomains
1559*00b67f09SDavid van Moolenbroek 		 * of t->name as potentially needing a NSEC update.
1560*00b67f09SDavid van Moolenbroek 		 */
1561*00b67f09SDavid van Moolenbroek 		CHECK(namelist_append_subdomain(db, &t->name, &affected));
1562*00b67f09SDavid van Moolenbroek 	}
1563*00b67f09SDavid van Moolenbroek 
1564*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link);
1565*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(diffnames.tuples));
1566*00b67f09SDavid van Moolenbroek 
1567*00b67f09SDavid van Moolenbroek 	CHECK(uniqify_name_list(&affected));
1568*00b67f09SDavid van Moolenbroek 
1569*00b67f09SDavid van Moolenbroek 	/*
1570*00b67f09SDavid van Moolenbroek 	 * Determine which names should have NSECs, and delete/create
1571*00b67f09SDavid van Moolenbroek 	 * NSECs to make it so.  We don't know the final NSEC targets yet,
1572*00b67f09SDavid van Moolenbroek 	 * so we just create placeholder NSECs with arbitrary contents
1573*00b67f09SDavid van Moolenbroek 	 * to indicate that their respective owner names should be part of
1574*00b67f09SDavid van Moolenbroek 	 * the NSEC chain.
1575*00b67f09SDavid van Moolenbroek 	 */
1576*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(affected.tuples);
1577*00b67f09SDavid van Moolenbroek 	     t != NULL;
1578*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link))
1579*00b67f09SDavid van Moolenbroek 	{
1580*00b67f09SDavid van Moolenbroek 		isc_boolean_t exists;
1581*00b67f09SDavid van Moolenbroek 		dns_name_t *name = &t->name;
1582*00b67f09SDavid van Moolenbroek 
1583*00b67f09SDavid van Moolenbroek 		CHECK(name_exists(db, newver, name, &exists));
1584*00b67f09SDavid van Moolenbroek 		if (! exists)
1585*00b67f09SDavid van Moolenbroek 			continue;
1586*00b67f09SDavid van Moolenbroek 		CHECK(is_active(db, newver, name, &flag, &cut, NULL));
1587*00b67f09SDavid van Moolenbroek 		if (!flag) {
1588*00b67f09SDavid van Moolenbroek 			/*
1589*00b67f09SDavid van Moolenbroek 			 * This name is obscured.  Delete any
1590*00b67f09SDavid van Moolenbroek 			 * existing NSEC record.
1591*00b67f09SDavid van Moolenbroek 			 */
1592*00b67f09SDavid van Moolenbroek 			CHECK(delete_if(true_p, db, newver, name,
1593*00b67f09SDavid van Moolenbroek 					dns_rdatatype_nsec, 0,
1594*00b67f09SDavid van Moolenbroek 					NULL, &nsec_diff));
1595*00b67f09SDavid van Moolenbroek 			CHECK(delete_if(rrsig_p, db, newver, name,
1596*00b67f09SDavid van Moolenbroek 					dns_rdatatype_any, 0, NULL, diff));
1597*00b67f09SDavid van Moolenbroek 		} else {
1598*00b67f09SDavid van Moolenbroek 			/*
1599*00b67f09SDavid van Moolenbroek 			 * This name is not obscured.  It needs to have a
1600*00b67f09SDavid van Moolenbroek 			 * NSEC unless it is the at the origin, in which
1601*00b67f09SDavid van Moolenbroek 			 * case it should already exist if there is a complete
1602*00b67f09SDavid van Moolenbroek 			 * NSEC chain and if there isn't a complete NSEC chain
1603*00b67f09SDavid van Moolenbroek 			 * we don't want to add one as that would signal that
1604*00b67f09SDavid van Moolenbroek 			 * there is a complete NSEC chain.
1605*00b67f09SDavid van Moolenbroek 			 */
1606*00b67f09SDavid van Moolenbroek 			if (!dns_name_equal(name, dns_db_origin(db))) {
1607*00b67f09SDavid van Moolenbroek 				CHECK(rrset_exists(db, newver, name,
1608*00b67f09SDavid van Moolenbroek 						   dns_rdatatype_nsec, 0,
1609*00b67f09SDavid van Moolenbroek 						   &flag));
1610*00b67f09SDavid van Moolenbroek 				if (!flag)
1611*00b67f09SDavid van Moolenbroek 					CHECK(add_placeholder_nsec(db, newver,
1612*00b67f09SDavid van Moolenbroek 								   name, diff));
1613*00b67f09SDavid van Moolenbroek 			}
1614*00b67f09SDavid van Moolenbroek 			CHECK(add_exposed_sigs(log, zone, db, newver, name,
1615*00b67f09SDavid van Moolenbroek 					       cut, &sig_diff, zone_keys, nkeys,
1616*00b67f09SDavid van Moolenbroek 					       inception, expire, check_ksk,
1617*00b67f09SDavid van Moolenbroek 					       keyset_kskonly));
1618*00b67f09SDavid van Moolenbroek 		}
1619*00b67f09SDavid van Moolenbroek 	}
1620*00b67f09SDavid van Moolenbroek 
1621*00b67f09SDavid van Moolenbroek 	/*
1622*00b67f09SDavid van Moolenbroek 	 * Now we know which names are part of the NSEC chain.
1623*00b67f09SDavid van Moolenbroek 	 * Make them all point at their correct targets.
1624*00b67f09SDavid van Moolenbroek 	 */
1625*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(affected.tuples);
1626*00b67f09SDavid van Moolenbroek 	     t != NULL;
1627*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link))
1628*00b67f09SDavid van Moolenbroek 	{
1629*00b67f09SDavid van Moolenbroek 		CHECK(rrset_exists(db, newver, &t->name,
1630*00b67f09SDavid van Moolenbroek 				   dns_rdatatype_nsec, 0, &flag));
1631*00b67f09SDavid van Moolenbroek 		if (flag) {
1632*00b67f09SDavid van Moolenbroek 			/*
1633*00b67f09SDavid van Moolenbroek 			 * There is a NSEC, but we don't know if it is correct.
1634*00b67f09SDavid van Moolenbroek 			 * Delete it and create a correct one to be sure.
1635*00b67f09SDavid van Moolenbroek 			 * If the update was unnecessary, the diff minimization
1636*00b67f09SDavid van Moolenbroek 			 * will take care of eliminating it from the journal,
1637*00b67f09SDavid van Moolenbroek 			 * IXFRs, etc.
1638*00b67f09SDavid van Moolenbroek 			 *
1639*00b67f09SDavid van Moolenbroek 			 * The RRSIG bit should always be set in the NSECs
1640*00b67f09SDavid van Moolenbroek 			 * we generate, because they will all get RRSIG NSECs.
1641*00b67f09SDavid van Moolenbroek 			 * (XXX what if the zone keys are missing?).
1642*00b67f09SDavid van Moolenbroek 			 * Because the RRSIG NSECs have not necessarily been
1643*00b67f09SDavid van Moolenbroek 			 * created yet, the correctness of the bit mask relies
1644*00b67f09SDavid van Moolenbroek 			 * on the assumption that NSECs are only created if
1645*00b67f09SDavid van Moolenbroek 			 * there is other data, and if there is other data,
1646*00b67f09SDavid van Moolenbroek 			 * there are other RRSIGs.
1647*00b67f09SDavid van Moolenbroek 			 */
1648*00b67f09SDavid van Moolenbroek 			CHECK(add_nsec(log, zone, db, newver, &t->name,
1649*00b67f09SDavid van Moolenbroek 				       nsecttl, &nsec_diff));
1650*00b67f09SDavid van Moolenbroek 		}
1651*00b67f09SDavid van Moolenbroek 	}
1652*00b67f09SDavid van Moolenbroek 
1653*00b67f09SDavid van Moolenbroek 	/*
1654*00b67f09SDavid van Moolenbroek 	 * Minimize the set of NSEC updates so that we don't
1655*00b67f09SDavid van Moolenbroek 	 * have to regenerate the RRSIG NSECs for NSECs that were
1656*00b67f09SDavid van Moolenbroek 	 * replaced with identical ones.
1657*00b67f09SDavid van Moolenbroek 	 */
1658*00b67f09SDavid van Moolenbroek 	while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
1659*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
1660*00b67f09SDavid van Moolenbroek 		dns_diff_appendminimal(&nsec_mindiff, &t);
1661*00b67f09SDavid van Moolenbroek 	}
1662*00b67f09SDavid van Moolenbroek 
1663*00b67f09SDavid van Moolenbroek 	update_log(log, zone, ISC_LOG_DEBUG(3), "signing rebuilt NSEC chain");
1664*00b67f09SDavid van Moolenbroek 
1665*00b67f09SDavid van Moolenbroek 	/* Update RRSIG NSECs. */
1666*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
1667*00b67f09SDavid van Moolenbroek 	     t != NULL;
1668*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link))
1669*00b67f09SDavid van Moolenbroek 	{
1670*00b67f09SDavid van Moolenbroek 		if (t->op == DNS_DIFFOP_DEL) {
1671*00b67f09SDavid van Moolenbroek 			CHECK(delete_if(true_p, db, newver, &t->name,
1672*00b67f09SDavid van Moolenbroek 					dns_rdatatype_rrsig, dns_rdatatype_nsec,
1673*00b67f09SDavid van Moolenbroek 					NULL, &sig_diff));
1674*00b67f09SDavid van Moolenbroek 		} else if (t->op == DNS_DIFFOP_ADD) {
1675*00b67f09SDavid van Moolenbroek 			CHECK(add_sigs(log, zone, db, newver, &t->name,
1676*00b67f09SDavid van Moolenbroek 				       dns_rdatatype_nsec, &sig_diff,
1677*00b67f09SDavid van Moolenbroek 				       zone_keys, nkeys, inception, expire,
1678*00b67f09SDavid van Moolenbroek 				       check_ksk, keyset_kskonly));
1679*00b67f09SDavid van Moolenbroek 		} else {
1680*00b67f09SDavid van Moolenbroek 			INSIST(0);
1681*00b67f09SDavid van Moolenbroek 		}
1682*00b67f09SDavid van Moolenbroek 	}
1683*00b67f09SDavid van Moolenbroek 
1684*00b67f09SDavid van Moolenbroek  update_nsec3:
1685*00b67f09SDavid van Moolenbroek 
1686*00b67f09SDavid van Moolenbroek 	/* Record our changes for the journal. */
1687*00b67f09SDavid van Moolenbroek 	while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
1688*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(sig_diff.tuples, t, link);
1689*00b67f09SDavid van Moolenbroek 		dns_diff_appendminimal(diff, &t);
1690*00b67f09SDavid van Moolenbroek 	}
1691*00b67f09SDavid van Moolenbroek 	while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
1692*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
1693*00b67f09SDavid van Moolenbroek 		dns_diff_appendminimal(diff, &t);
1694*00b67f09SDavid van Moolenbroek 	}
1695*00b67f09SDavid van Moolenbroek 
1696*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
1697*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
1698*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
1699*00b67f09SDavid van Moolenbroek 
1700*00b67f09SDavid van Moolenbroek 	if (!build_nsec3) {
1701*00b67f09SDavid van Moolenbroek 		update_log(log, zone, ISC_LOG_DEBUG(3),
1702*00b67f09SDavid van Moolenbroek 			   "no NSEC3 chains to rebuild");
1703*00b67f09SDavid van Moolenbroek 		goto failure;
1704*00b67f09SDavid van Moolenbroek 	}
1705*00b67f09SDavid van Moolenbroek 
1706*00b67f09SDavid van Moolenbroek 	update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC3 chains");
1707*00b67f09SDavid van Moolenbroek 
1708*00b67f09SDavid van Moolenbroek 	dns_diff_clear(&diffnames);
1709*00b67f09SDavid van Moolenbroek 	dns_diff_clear(&affected);
1710*00b67f09SDavid van Moolenbroek 
1711*00b67f09SDavid van Moolenbroek 	CHECK(dns_diff_sort(diff, temp_order));
1712*00b67f09SDavid van Moolenbroek 
1713*00b67f09SDavid van Moolenbroek 	/*
1714*00b67f09SDavid van Moolenbroek 	 * Find names potentially affected by delegation changes
1715*00b67f09SDavid van Moolenbroek 	 * (obscured by adding an NS or DNAME, or unobscured by
1716*00b67f09SDavid van Moolenbroek 	 * removing one).
1717*00b67f09SDavid van Moolenbroek 	 */
1718*00b67f09SDavid van Moolenbroek 	t = ISC_LIST_HEAD(diff->tuples);
1719*00b67f09SDavid van Moolenbroek 	while (t != NULL) {
1720*00b67f09SDavid van Moolenbroek 		dns_name_t *name = &t->name;
1721*00b67f09SDavid van Moolenbroek 
1722*00b67f09SDavid van Moolenbroek 		isc_boolean_t ns_existed, dname_existed;
1723*00b67f09SDavid van Moolenbroek 		isc_boolean_t ns_exists, dname_exists;
1724*00b67f09SDavid van Moolenbroek 		isc_boolean_t exists, existed;
1725*00b67f09SDavid van Moolenbroek 
1726*00b67f09SDavid van Moolenbroek 		if (t->rdata.type == dns_rdatatype_nsec ||
1727*00b67f09SDavid van Moolenbroek 		    t->rdata.type == dns_rdatatype_rrsig) {
1728*00b67f09SDavid van Moolenbroek 			t = ISC_LIST_NEXT(t, link);
1729*00b67f09SDavid van Moolenbroek 			continue;
1730*00b67f09SDavid van Moolenbroek 		}
1731*00b67f09SDavid van Moolenbroek 
1732*00b67f09SDavid van Moolenbroek 		CHECK(namelist_append_name(&affected, name));
1733*00b67f09SDavid van Moolenbroek 
1734*00b67f09SDavid van Moolenbroek 		if (oldver != NULL)
1735*00b67f09SDavid van Moolenbroek 			CHECK(rrset_exists(db, oldver, name, dns_rdatatype_ns,
1736*00b67f09SDavid van Moolenbroek 					   0, &ns_existed));
1737*00b67f09SDavid van Moolenbroek 		else
1738*00b67f09SDavid van Moolenbroek 			ns_existed = ISC_FALSE;
1739*00b67f09SDavid van Moolenbroek 		if (oldver != NULL)
1740*00b67f09SDavid van Moolenbroek 			CHECK(rrset_exists(db, oldver, name,
1741*00b67f09SDavid van Moolenbroek 					   dns_rdatatype_dname, 0,
1742*00b67f09SDavid van Moolenbroek 					   &dname_existed));
1743*00b67f09SDavid van Moolenbroek 		else
1744*00b67f09SDavid van Moolenbroek 			dname_existed = ISC_FALSE;
1745*00b67f09SDavid van Moolenbroek 		CHECK(rrset_exists(db, newver, name, dns_rdatatype_ns, 0,
1746*00b67f09SDavid van Moolenbroek 				   &ns_exists));
1747*00b67f09SDavid van Moolenbroek 		CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0,
1748*00b67f09SDavid van Moolenbroek 				   &dname_exists));
1749*00b67f09SDavid van Moolenbroek 
1750*00b67f09SDavid van Moolenbroek 		exists = ns_exists || dname_exists;
1751*00b67f09SDavid van Moolenbroek 		existed = ns_existed || dname_existed;
1752*00b67f09SDavid van Moolenbroek 		if (exists == existed)
1753*00b67f09SDavid van Moolenbroek 			goto nextname;
1754*00b67f09SDavid van Moolenbroek 		/*
1755*00b67f09SDavid van Moolenbroek 		 * There was a delegation change.  Mark all subdomains
1756*00b67f09SDavid van Moolenbroek 		 * of t->name as potentially needing a NSEC3 update.
1757*00b67f09SDavid van Moolenbroek 		 */
1758*00b67f09SDavid van Moolenbroek 		CHECK(namelist_append_subdomain(db, name, &affected));
1759*00b67f09SDavid van Moolenbroek 
1760*00b67f09SDavid van Moolenbroek 	nextname:
1761*00b67f09SDavid van Moolenbroek 		while (t != NULL && dns_name_equal(&t->name, name))
1762*00b67f09SDavid van Moolenbroek 			t = ISC_LIST_NEXT(t, link);
1763*00b67f09SDavid van Moolenbroek 	}
1764*00b67f09SDavid van Moolenbroek 
1765*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(affected.tuples);
1766*00b67f09SDavid van Moolenbroek 	     t != NULL;
1767*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link)) {
1768*00b67f09SDavid van Moolenbroek 		dns_name_t *name = &t->name;
1769*00b67f09SDavid van Moolenbroek 
1770*00b67f09SDavid van Moolenbroek 		unsecure = ISC_FALSE;	/* Silence compiler warning. */
1771*00b67f09SDavid van Moolenbroek 		CHECK(is_active(db, newver, name, &flag, &cut, &unsecure));
1772*00b67f09SDavid van Moolenbroek 
1773*00b67f09SDavid van Moolenbroek 		if (!flag) {
1774*00b67f09SDavid van Moolenbroek 			CHECK(delete_if(rrsig_p, db, newver, name,
1775*00b67f09SDavid van Moolenbroek 					dns_rdatatype_any, 0, NULL, diff));
1776*00b67f09SDavid van Moolenbroek 			CHECK(dns_nsec3_delnsec3sx(db, newver, name,
1777*00b67f09SDavid van Moolenbroek 						   privatetype, &nsec_diff));
1778*00b67f09SDavid van Moolenbroek 		} else {
1779*00b67f09SDavid van Moolenbroek 			CHECK(add_exposed_sigs(log, zone, db, newver, name,
1780*00b67f09SDavid van Moolenbroek 					       cut, &sig_diff, zone_keys, nkeys,
1781*00b67f09SDavid van Moolenbroek 					       inception, expire, check_ksk,
1782*00b67f09SDavid van Moolenbroek 					       keyset_kskonly));
1783*00b67f09SDavid van Moolenbroek 			CHECK(dns_nsec3_addnsec3sx(db, newver, name, nsecttl,
1784*00b67f09SDavid van Moolenbroek 						   unsecure, privatetype,
1785*00b67f09SDavid van Moolenbroek 						   &nsec_diff));
1786*00b67f09SDavid van Moolenbroek 		}
1787*00b67f09SDavid van Moolenbroek 	}
1788*00b67f09SDavid van Moolenbroek 
1789*00b67f09SDavid van Moolenbroek 	/*
1790*00b67f09SDavid van Moolenbroek 	 * Minimize the set of NSEC3 updates so that we don't
1791*00b67f09SDavid van Moolenbroek 	 * have to regenerate the RRSIG NSEC3s for NSEC3s that were
1792*00b67f09SDavid van Moolenbroek 	 * replaced with identical ones.
1793*00b67f09SDavid van Moolenbroek 	 */
1794*00b67f09SDavid van Moolenbroek 	while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
1795*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
1796*00b67f09SDavid van Moolenbroek 		dns_diff_appendminimal(&nsec_mindiff, &t);
1797*00b67f09SDavid van Moolenbroek 	}
1798*00b67f09SDavid van Moolenbroek 
1799*00b67f09SDavid van Moolenbroek 	update_log(log, zone, ISC_LOG_DEBUG(3),
1800*00b67f09SDavid van Moolenbroek 		   "signing rebuilt NSEC3 chain");
1801*00b67f09SDavid van Moolenbroek 
1802*00b67f09SDavid van Moolenbroek 	/* Update RRSIG NSEC3s. */
1803*00b67f09SDavid van Moolenbroek 	for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
1804*00b67f09SDavid van Moolenbroek 	     t != NULL;
1805*00b67f09SDavid van Moolenbroek 	     t = ISC_LIST_NEXT(t, link))
1806*00b67f09SDavid van Moolenbroek 	{
1807*00b67f09SDavid van Moolenbroek 		if (t->op == DNS_DIFFOP_DEL) {
1808*00b67f09SDavid van Moolenbroek 			CHECK(delete_if(true_p, db, newver, &t->name,
1809*00b67f09SDavid van Moolenbroek 					dns_rdatatype_rrsig,
1810*00b67f09SDavid van Moolenbroek 					dns_rdatatype_nsec3,
1811*00b67f09SDavid van Moolenbroek 					NULL, &sig_diff));
1812*00b67f09SDavid van Moolenbroek 		} else if (t->op == DNS_DIFFOP_ADD) {
1813*00b67f09SDavid van Moolenbroek 			CHECK(add_sigs(log, zone, db, newver, &t->name,
1814*00b67f09SDavid van Moolenbroek 				       dns_rdatatype_nsec3,
1815*00b67f09SDavid van Moolenbroek 				       &sig_diff, zone_keys, nkeys,
1816*00b67f09SDavid van Moolenbroek 				       inception, expire, check_ksk,
1817*00b67f09SDavid van Moolenbroek 				       keyset_kskonly));
1818*00b67f09SDavid van Moolenbroek 		} else {
1819*00b67f09SDavid van Moolenbroek 			INSIST(0);
1820*00b67f09SDavid van Moolenbroek 		}
1821*00b67f09SDavid van Moolenbroek 	}
1822*00b67f09SDavid van Moolenbroek 
1823*00b67f09SDavid van Moolenbroek 	/* Record our changes for the journal. */
1824*00b67f09SDavid van Moolenbroek 	while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
1825*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(sig_diff.tuples, t, link);
1826*00b67f09SDavid van Moolenbroek 		dns_diff_appendminimal(diff, &t);
1827*00b67f09SDavid van Moolenbroek 	}
1828*00b67f09SDavid van Moolenbroek 	while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
1829*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
1830*00b67f09SDavid van Moolenbroek 		dns_diff_appendminimal(diff, &t);
1831*00b67f09SDavid van Moolenbroek 	}
1832*00b67f09SDavid van Moolenbroek 
1833*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
1834*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
1835*00b67f09SDavid van Moolenbroek 	INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
1836*00b67f09SDavid van Moolenbroek 
1837*00b67f09SDavid van Moolenbroek  failure:
1838*00b67f09SDavid van Moolenbroek 	dns_diff_clear(&sig_diff);
1839*00b67f09SDavid van Moolenbroek 	dns_diff_clear(&nsec_diff);
1840*00b67f09SDavid van Moolenbroek 	dns_diff_clear(&nsec_mindiff);
1841*00b67f09SDavid van Moolenbroek 
1842*00b67f09SDavid van Moolenbroek 	dns_diff_clear(&affected);
1843*00b67f09SDavid van Moolenbroek 	dns_diff_clear(&diffnames);
1844*00b67f09SDavid van Moolenbroek 
1845*00b67f09SDavid van Moolenbroek 	for (i = 0; i < nkeys; i++)
1846*00b67f09SDavid van Moolenbroek 		dst_key_free(&zone_keys[i]);
1847*00b67f09SDavid van Moolenbroek 
1848*00b67f09SDavid van Moolenbroek 	return (result);
1849*00b67f09SDavid van Moolenbroek }
1850*00b67f09SDavid van Moolenbroek 
1851*00b67f09SDavid van Moolenbroek isc_uint32_t
dns_update_soaserial(isc_uint32_t serial,dns_updatemethod_t method)1852*00b67f09SDavid van Moolenbroek dns_update_soaserial(isc_uint32_t serial, dns_updatemethod_t method) {
1853*00b67f09SDavid van Moolenbroek 	isc_stdtime_t now;
1854*00b67f09SDavid van Moolenbroek 
1855*00b67f09SDavid van Moolenbroek 	if (method == dns_updatemethod_unixtime) {
1856*00b67f09SDavid van Moolenbroek 		isc_stdtime_get(&now);
1857*00b67f09SDavid van Moolenbroek 		if (now != 0 && isc_serial_gt(now, serial))
1858*00b67f09SDavid van Moolenbroek 			return (now);
1859*00b67f09SDavid van Moolenbroek 	}
1860*00b67f09SDavid van Moolenbroek 
1861*00b67f09SDavid van Moolenbroek 	/* RFC1982 */
1862*00b67f09SDavid van Moolenbroek 	serial = (serial + 1) & 0xFFFFFFFF;
1863*00b67f09SDavid van Moolenbroek 	if (serial == 0)
1864*00b67f09SDavid van Moolenbroek 		serial = 1;
1865*00b67f09SDavid van Moolenbroek 
1866*00b67f09SDavid van Moolenbroek 	return (serial);
1867*00b67f09SDavid van Moolenbroek }
1868