xref: /minix/external/bsd/bind/dist/lib/dns/nsec3.c (revision 00b67f09)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: nsec3.c,v 1.11 2015/07/08 17:28:58 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2006, 2008-2015  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/base32.h>
24*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
25*00b67f09SDavid van Moolenbroek #include <isc/hex.h>
26*00b67f09SDavid van Moolenbroek #include <isc/iterated_hash.h>
27*00b67f09SDavid van Moolenbroek #include <isc/log.h>
28*00b67f09SDavid van Moolenbroek #include <isc/string.h>
29*00b67f09SDavid van Moolenbroek #include <isc/util.h>
30*00b67f09SDavid van Moolenbroek 
31*00b67f09SDavid van Moolenbroek #include <dst/dst.h>
32*00b67f09SDavid van Moolenbroek 
33*00b67f09SDavid van Moolenbroek #include <dns/db.h>
34*00b67f09SDavid van Moolenbroek #include <dns/zone.h>
35*00b67f09SDavid van Moolenbroek #include <dns/compress.h>
36*00b67f09SDavid van Moolenbroek #include <dns/dbiterator.h>
37*00b67f09SDavid van Moolenbroek #include <dns/diff.h>
38*00b67f09SDavid van Moolenbroek #include <dns/fixedname.h>
39*00b67f09SDavid van Moolenbroek #include <dns/nsec.h>
40*00b67f09SDavid van Moolenbroek #include <dns/nsec3.h>
41*00b67f09SDavid van Moolenbroek #include <dns/rdata.h>
42*00b67f09SDavid van Moolenbroek #include <dns/rdatalist.h>
43*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
44*00b67f09SDavid van Moolenbroek #include <dns/rdatasetiter.h>
45*00b67f09SDavid van Moolenbroek #include <dns/rdatastruct.h>
46*00b67f09SDavid van Moolenbroek #include <dns/result.h>
47*00b67f09SDavid van Moolenbroek 
48*00b67f09SDavid van Moolenbroek #define CHECK(x) do { \
49*00b67f09SDavid van Moolenbroek 	result = (x); \
50*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) \
51*00b67f09SDavid van Moolenbroek 		goto failure; \
52*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
53*00b67f09SDavid van Moolenbroek 
54*00b67f09SDavid van Moolenbroek #define OPTOUT(x) (((x) & DNS_NSEC3FLAG_OPTOUT) != 0)
55*00b67f09SDavid van Moolenbroek #define CREATE(x) (((x) & DNS_NSEC3FLAG_CREATE) != 0)
56*00b67f09SDavid van Moolenbroek #define INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0)
57*00b67f09SDavid van Moolenbroek #define REMOVE(x) (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
58*00b67f09SDavid van Moolenbroek 
59*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_buildrdata(dns_db_t * db,dns_dbversion_t * version,dns_dbnode_t * node,unsigned int hashalg,unsigned int flags,unsigned int iterations,const unsigned char * salt,size_t salt_length,const unsigned char * nexthash,size_t hash_length,unsigned char * buffer,dns_rdata_t * rdata)60*00b67f09SDavid van Moolenbroek dns_nsec3_buildrdata(dns_db_t *db, dns_dbversion_t *version,
61*00b67f09SDavid van Moolenbroek 		     dns_dbnode_t *node, unsigned int hashalg,
62*00b67f09SDavid van Moolenbroek 		     unsigned int flags, unsigned int iterations,
63*00b67f09SDavid van Moolenbroek 		     const unsigned char *salt, size_t salt_length,
64*00b67f09SDavid van Moolenbroek 		     const unsigned char *nexthash, size_t hash_length,
65*00b67f09SDavid van Moolenbroek 		     unsigned char *buffer, dns_rdata_t *rdata)
66*00b67f09SDavid van Moolenbroek {
67*00b67f09SDavid van Moolenbroek 	isc_result_t result;
68*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
69*00b67f09SDavid van Moolenbroek 	isc_region_t r;
70*00b67f09SDavid van Moolenbroek 	unsigned int i;
71*00b67f09SDavid van Moolenbroek 	isc_boolean_t found;
72*00b67f09SDavid van Moolenbroek 	isc_boolean_t found_ns;
73*00b67f09SDavid van Moolenbroek 	isc_boolean_t need_rrsig;
74*00b67f09SDavid van Moolenbroek 
75*00b67f09SDavid van Moolenbroek 	unsigned char *nsec_bits, *bm;
76*00b67f09SDavid van Moolenbroek 	unsigned int max_type;
77*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_t *rdsiter;
78*00b67f09SDavid van Moolenbroek 	unsigned char *p;
79*00b67f09SDavid van Moolenbroek 
80*00b67f09SDavid van Moolenbroek 	REQUIRE(salt_length < 256U);
81*00b67f09SDavid van Moolenbroek 	REQUIRE(hash_length < 256U);
82*00b67f09SDavid van Moolenbroek 	REQUIRE(flags <= 0xffU);
83*00b67f09SDavid van Moolenbroek 	REQUIRE(hashalg <= 0xffU);
84*00b67f09SDavid van Moolenbroek 	REQUIRE(iterations <= 0xffffU);
85*00b67f09SDavid van Moolenbroek 
86*00b67f09SDavid van Moolenbroek 	switch (hashalg) {
87*00b67f09SDavid van Moolenbroek 	case dns_hash_sha1:
88*00b67f09SDavid van Moolenbroek 		REQUIRE(hash_length == ISC_SHA1_DIGESTLENGTH);
89*00b67f09SDavid van Moolenbroek 		break;
90*00b67f09SDavid van Moolenbroek 	}
91*00b67f09SDavid van Moolenbroek 
92*00b67f09SDavid van Moolenbroek 	memset(buffer, 0, DNS_NSEC3_BUFFERSIZE);
93*00b67f09SDavid van Moolenbroek 
94*00b67f09SDavid van Moolenbroek 	p = buffer;
95*00b67f09SDavid van Moolenbroek 
96*00b67f09SDavid van Moolenbroek 	*p++ = hashalg;
97*00b67f09SDavid van Moolenbroek 	*p++ = flags;
98*00b67f09SDavid van Moolenbroek 
99*00b67f09SDavid van Moolenbroek 	*p++ = iterations >> 8;
100*00b67f09SDavid van Moolenbroek 	*p++ = iterations;
101*00b67f09SDavid van Moolenbroek 
102*00b67f09SDavid van Moolenbroek 	*p++ = (unsigned char)salt_length;
103*00b67f09SDavid van Moolenbroek 	memmove(p, salt, salt_length);
104*00b67f09SDavid van Moolenbroek 	p += salt_length;
105*00b67f09SDavid van Moolenbroek 
106*00b67f09SDavid van Moolenbroek 	*p++ = (unsigned char)hash_length;
107*00b67f09SDavid van Moolenbroek 	memmove(p, nexthash, hash_length);
108*00b67f09SDavid van Moolenbroek 	p += hash_length;
109*00b67f09SDavid van Moolenbroek 
110*00b67f09SDavid van Moolenbroek 	r.length = (unsigned int)(p - buffer);
111*00b67f09SDavid van Moolenbroek 	r.base = buffer;
112*00b67f09SDavid van Moolenbroek 
113*00b67f09SDavid van Moolenbroek 	/*
114*00b67f09SDavid van Moolenbroek 	 * Use the end of the space for a raw bitmap leaving enough
115*00b67f09SDavid van Moolenbroek 	 * space for the window identifiers and length octets.
116*00b67f09SDavid van Moolenbroek 	 */
117*00b67f09SDavid van Moolenbroek 	bm = r.base + r.length + 512;
118*00b67f09SDavid van Moolenbroek 	nsec_bits = r.base + r.length;
119*00b67f09SDavid van Moolenbroek 	max_type = 0;
120*00b67f09SDavid van Moolenbroek 	if (node == NULL)
121*00b67f09SDavid van Moolenbroek 		goto collapse_bitmap;
122*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
123*00b67f09SDavid van Moolenbroek 	rdsiter = NULL;
124*00b67f09SDavid van Moolenbroek 	result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
125*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
126*00b67f09SDavid van Moolenbroek 		return (result);
127*00b67f09SDavid van Moolenbroek 	found = found_ns = need_rrsig = ISC_FALSE;
128*00b67f09SDavid van Moolenbroek 	for (result = dns_rdatasetiter_first(rdsiter);
129*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
130*00b67f09SDavid van Moolenbroek 	     result = dns_rdatasetiter_next(rdsiter))
131*00b67f09SDavid van Moolenbroek 	{
132*00b67f09SDavid van Moolenbroek 		dns_rdatasetiter_current(rdsiter, &rdataset);
133*00b67f09SDavid van Moolenbroek 		if (rdataset.type != dns_rdatatype_nsec &&
134*00b67f09SDavid van Moolenbroek 		    rdataset.type != dns_rdatatype_nsec3 &&
135*00b67f09SDavid van Moolenbroek 		    rdataset.type != dns_rdatatype_rrsig) {
136*00b67f09SDavid van Moolenbroek 			if (rdataset.type > max_type)
137*00b67f09SDavid van Moolenbroek 				max_type = rdataset.type;
138*00b67f09SDavid van Moolenbroek 			dns_nsec_setbit(bm, rdataset.type, 1);
139*00b67f09SDavid van Moolenbroek 			/*
140*00b67f09SDavid van Moolenbroek 			 * Work out if we need to set the RRSIG bit for
141*00b67f09SDavid van Moolenbroek 			 * this node.  We set the RRSIG bit if either of
142*00b67f09SDavid van Moolenbroek 			 * the following conditions are met:
143*00b67f09SDavid van Moolenbroek 			 * 1) We have a SOA or DS then we need to set
144*00b67f09SDavid van Moolenbroek 			 *    the RRSIG bit as both always will be signed.
145*00b67f09SDavid van Moolenbroek 			 * 2) We set the RRSIG bit if we don't have
146*00b67f09SDavid van Moolenbroek 			 *    a NS record but do have other data.
147*00b67f09SDavid van Moolenbroek 			 */
148*00b67f09SDavid van Moolenbroek 			if (rdataset.type == dns_rdatatype_soa ||
149*00b67f09SDavid van Moolenbroek 			    rdataset.type == dns_rdatatype_ds)
150*00b67f09SDavid van Moolenbroek 				need_rrsig = ISC_TRUE;
151*00b67f09SDavid van Moolenbroek 			else if (rdataset.type == dns_rdatatype_ns)
152*00b67f09SDavid van Moolenbroek 				found_ns = ISC_TRUE;
153*00b67f09SDavid van Moolenbroek 			else
154*00b67f09SDavid van Moolenbroek 				found = ISC_TRUE;
155*00b67f09SDavid van Moolenbroek 		}
156*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
157*00b67f09SDavid van Moolenbroek 	}
158*00b67f09SDavid van Moolenbroek 	if ((found && !found_ns) || need_rrsig) {
159*00b67f09SDavid van Moolenbroek 		if (dns_rdatatype_rrsig > max_type)
160*00b67f09SDavid van Moolenbroek 			max_type = dns_rdatatype_rrsig;
161*00b67f09SDavid van Moolenbroek 		dns_nsec_setbit(bm, dns_rdatatype_rrsig, 1);
162*00b67f09SDavid van Moolenbroek 	}
163*00b67f09SDavid van Moolenbroek 
164*00b67f09SDavid van Moolenbroek 	/*
165*00b67f09SDavid van Moolenbroek 	 * At zone cuts, deny the existence of glue in the parent zone.
166*00b67f09SDavid van Moolenbroek 	 */
167*00b67f09SDavid van Moolenbroek 	if (dns_nsec_isset(bm, dns_rdatatype_ns) &&
168*00b67f09SDavid van Moolenbroek 	    ! dns_nsec_isset(bm, dns_rdatatype_soa)) {
169*00b67f09SDavid van Moolenbroek 		for (i = 0; i <= max_type; i++) {
170*00b67f09SDavid van Moolenbroek 			if (dns_nsec_isset(bm, i) &&
171*00b67f09SDavid van Moolenbroek 			    ! dns_rdatatype_iszonecutauth((dns_rdatatype_t)i))
172*00b67f09SDavid van Moolenbroek 				dns_nsec_setbit(bm, i, 0);
173*00b67f09SDavid van Moolenbroek 		}
174*00b67f09SDavid van Moolenbroek 	}
175*00b67f09SDavid van Moolenbroek 
176*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_destroy(&rdsiter);
177*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
178*00b67f09SDavid van Moolenbroek 		return (result);
179*00b67f09SDavid van Moolenbroek 
180*00b67f09SDavid van Moolenbroek  collapse_bitmap:
181*00b67f09SDavid van Moolenbroek 	nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type);
182*00b67f09SDavid van Moolenbroek 	r.length = (unsigned int)(nsec_bits - r.base);
183*00b67f09SDavid van Moolenbroek 	INSIST(r.length <= DNS_NSEC3_BUFFERSIZE);
184*00b67f09SDavid van Moolenbroek 	dns_rdata_fromregion(rdata, dns_db_class(db), dns_rdatatype_nsec3, &r);
185*00b67f09SDavid van Moolenbroek 
186*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
187*00b67f09SDavid van Moolenbroek }
188*00b67f09SDavid van Moolenbroek 
189*00b67f09SDavid van Moolenbroek isc_boolean_t
dns_nsec3_typepresent(dns_rdata_t * rdata,dns_rdatatype_t type)190*00b67f09SDavid van Moolenbroek dns_nsec3_typepresent(dns_rdata_t *rdata, dns_rdatatype_t type) {
191*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3_t nsec3;
192*00b67f09SDavid van Moolenbroek 	isc_result_t result;
193*00b67f09SDavid van Moolenbroek 	isc_boolean_t present;
194*00b67f09SDavid van Moolenbroek 	unsigned int i, len, window;
195*00b67f09SDavid van Moolenbroek 
196*00b67f09SDavid van Moolenbroek 	REQUIRE(rdata != NULL);
197*00b67f09SDavid van Moolenbroek 	REQUIRE(rdata->type == dns_rdatatype_nsec3);
198*00b67f09SDavid van Moolenbroek 
199*00b67f09SDavid van Moolenbroek 	/* This should never fail */
200*00b67f09SDavid van Moolenbroek 	result = dns_rdata_tostruct(rdata, &nsec3, NULL);
201*00b67f09SDavid van Moolenbroek 	INSIST(result == ISC_R_SUCCESS);
202*00b67f09SDavid van Moolenbroek 
203*00b67f09SDavid van Moolenbroek 	present = ISC_FALSE;
204*00b67f09SDavid van Moolenbroek 	for (i = 0; i < nsec3.len; i += len) {
205*00b67f09SDavid van Moolenbroek 		INSIST(i + 2 <= nsec3.len);
206*00b67f09SDavid van Moolenbroek 		window = nsec3.typebits[i];
207*00b67f09SDavid van Moolenbroek 		len = nsec3.typebits[i + 1];
208*00b67f09SDavid van Moolenbroek 		INSIST(len > 0 && len <= 32);
209*00b67f09SDavid van Moolenbroek 		i += 2;
210*00b67f09SDavid van Moolenbroek 		INSIST(i + len <= nsec3.len);
211*00b67f09SDavid van Moolenbroek 		if (window * 256 > type)
212*00b67f09SDavid van Moolenbroek 			break;
213*00b67f09SDavid van Moolenbroek 		if ((window + 1) * 256 <= type)
214*00b67f09SDavid van Moolenbroek 			continue;
215*00b67f09SDavid van Moolenbroek 		if (type < (window * 256) + len * 8)
216*00b67f09SDavid van Moolenbroek 			present = ISC_TF(dns_nsec_isset(&nsec3.typebits[i],
217*00b67f09SDavid van Moolenbroek 						   type % 256));
218*00b67f09SDavid van Moolenbroek 		break;
219*00b67f09SDavid van Moolenbroek 	}
220*00b67f09SDavid van Moolenbroek 	dns_rdata_freestruct(&nsec3);
221*00b67f09SDavid van Moolenbroek 	return (present);
222*00b67f09SDavid van Moolenbroek }
223*00b67f09SDavid van Moolenbroek 
224*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_hashname(dns_fixedname_t * result,unsigned char rethash[NSEC3_MAX_HASH_LENGTH],size_t * hash_length,dns_name_t * name,dns_name_t * origin,dns_hash_t hashalg,unsigned int iterations,const unsigned char * salt,size_t saltlength)225*00b67f09SDavid van Moolenbroek dns_nsec3_hashname(dns_fixedname_t *result,
226*00b67f09SDavid van Moolenbroek 		   unsigned char rethash[NSEC3_MAX_HASH_LENGTH],
227*00b67f09SDavid van Moolenbroek 		   size_t *hash_length, dns_name_t *name, dns_name_t *origin,
228*00b67f09SDavid van Moolenbroek 		   dns_hash_t hashalg, unsigned int iterations,
229*00b67f09SDavid van Moolenbroek 		   const unsigned char *salt, size_t saltlength)
230*00b67f09SDavid van Moolenbroek {
231*00b67f09SDavid van Moolenbroek 	unsigned char hash[NSEC3_MAX_HASH_LENGTH];
232*00b67f09SDavid van Moolenbroek 	unsigned char nametext[DNS_NAME_FORMATSIZE];
233*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixed;
234*00b67f09SDavid van Moolenbroek 	dns_name_t *downcased;
235*00b67f09SDavid van Moolenbroek 	isc_buffer_t namebuffer;
236*00b67f09SDavid van Moolenbroek 	isc_region_t region;
237*00b67f09SDavid van Moolenbroek 	size_t len;
238*00b67f09SDavid van Moolenbroek 
239*00b67f09SDavid van Moolenbroek 	if (rethash == NULL)
240*00b67f09SDavid van Moolenbroek 		rethash = hash;
241*00b67f09SDavid van Moolenbroek 
242*00b67f09SDavid van Moolenbroek 	memset(rethash, 0, NSEC3_MAX_HASH_LENGTH);
243*00b67f09SDavid van Moolenbroek 
244*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixed);
245*00b67f09SDavid van Moolenbroek 	downcased = dns_fixedname_name(&fixed);
246*00b67f09SDavid van Moolenbroek 	dns_name_downcase(name, downcased, NULL);
247*00b67f09SDavid van Moolenbroek 
248*00b67f09SDavid van Moolenbroek 	/* hash the node name */
249*00b67f09SDavid van Moolenbroek 	len = isc_iterated_hash(rethash, hashalg, iterations,
250*00b67f09SDavid van Moolenbroek 				salt, (int)saltlength,
251*00b67f09SDavid van Moolenbroek 				downcased->ndata, downcased->length);
252*00b67f09SDavid van Moolenbroek 	if (len == 0U)
253*00b67f09SDavid van Moolenbroek 		return (DNS_R_BADALG);
254*00b67f09SDavid van Moolenbroek 
255*00b67f09SDavid van Moolenbroek 	if (hash_length != NULL)
256*00b67f09SDavid van Moolenbroek 		*hash_length = len;
257*00b67f09SDavid van Moolenbroek 
258*00b67f09SDavid van Moolenbroek 	/* convert the hash to base32hex non-padded */
259*00b67f09SDavid van Moolenbroek 	region.base = rethash;
260*00b67f09SDavid van Moolenbroek 	region.length = (unsigned int)len;
261*00b67f09SDavid van Moolenbroek 	isc_buffer_init(&namebuffer, nametext, sizeof nametext);
262*00b67f09SDavid van Moolenbroek 	isc_base32hexnp_totext(&region, 1, "", &namebuffer);
263*00b67f09SDavid van Moolenbroek 
264*00b67f09SDavid van Moolenbroek 	/* convert the hex to a domain name */
265*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(result);
266*00b67f09SDavid van Moolenbroek 	return (dns_name_fromtext(dns_fixedname_name(result), &namebuffer,
267*00b67f09SDavid van Moolenbroek 				  origin, 0, NULL));
268*00b67f09SDavid van Moolenbroek }
269*00b67f09SDavid van Moolenbroek 
270*00b67f09SDavid van Moolenbroek unsigned int
dns_nsec3_hashlength(dns_hash_t hash)271*00b67f09SDavid van Moolenbroek dns_nsec3_hashlength(dns_hash_t hash) {
272*00b67f09SDavid van Moolenbroek 
273*00b67f09SDavid van Moolenbroek 	switch (hash) {
274*00b67f09SDavid van Moolenbroek 	case dns_hash_sha1:
275*00b67f09SDavid van Moolenbroek 		return(ISC_SHA1_DIGESTLENGTH);
276*00b67f09SDavid van Moolenbroek 	}
277*00b67f09SDavid van Moolenbroek 	return (0);
278*00b67f09SDavid van Moolenbroek }
279*00b67f09SDavid van Moolenbroek 
280*00b67f09SDavid van Moolenbroek isc_boolean_t
dns_nsec3_supportedhash(dns_hash_t hash)281*00b67f09SDavid van Moolenbroek dns_nsec3_supportedhash(dns_hash_t hash) {
282*00b67f09SDavid van Moolenbroek 	switch (hash) {
283*00b67f09SDavid van Moolenbroek 	case dns_hash_sha1:
284*00b67f09SDavid van Moolenbroek 		return (ISC_TRUE);
285*00b67f09SDavid van Moolenbroek 	}
286*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
287*00b67f09SDavid van Moolenbroek }
288*00b67f09SDavid van Moolenbroek 
289*00b67f09SDavid van Moolenbroek /*%
290*00b67f09SDavid van Moolenbroek  * Update a single RR in version 'ver' of 'db' and log the
291*00b67f09SDavid van Moolenbroek  * update in 'diff'.
292*00b67f09SDavid van Moolenbroek  *
293*00b67f09SDavid van Moolenbroek  * Ensures:
294*00b67f09SDavid van Moolenbroek  * \li  '*tuple' == NULL.  Either the tuple is freed, or its
295*00b67f09SDavid van Moolenbroek  *      ownership has been transferred to the diff.
296*00b67f09SDavid van Moolenbroek  */
297*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)298*00b67f09SDavid van Moolenbroek do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
299*00b67f09SDavid van Moolenbroek 	     dns_diff_t *diff)
300*00b67f09SDavid van Moolenbroek {
301*00b67f09SDavid van Moolenbroek 	dns_diff_t temp_diff;
302*00b67f09SDavid van Moolenbroek 	isc_result_t result;
303*00b67f09SDavid van Moolenbroek 
304*00b67f09SDavid van Moolenbroek 	/*
305*00b67f09SDavid van Moolenbroek 	 * Create a singleton diff.
306*00b67f09SDavid van Moolenbroek 	 */
307*00b67f09SDavid van Moolenbroek 	dns_diff_init(diff->mctx, &temp_diff);
308*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
309*00b67f09SDavid van Moolenbroek 
310*00b67f09SDavid van Moolenbroek 	/*
311*00b67f09SDavid van Moolenbroek 	 * Apply it to the database.
312*00b67f09SDavid van Moolenbroek 	 */
313*00b67f09SDavid van Moolenbroek 	result = dns_diff_apply(&temp_diff, db, ver);
314*00b67f09SDavid van Moolenbroek 	ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
315*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
316*00b67f09SDavid van Moolenbroek 		dns_difftuple_free(tuple);
317*00b67f09SDavid van Moolenbroek 		return (result);
318*00b67f09SDavid van Moolenbroek 	}
319*00b67f09SDavid van Moolenbroek 
320*00b67f09SDavid van Moolenbroek 	/*
321*00b67f09SDavid van Moolenbroek 	 * Merge it into the current pending journal entry.
322*00b67f09SDavid van Moolenbroek 	 */
323*00b67f09SDavid van Moolenbroek 	dns_diff_appendminimal(diff, tuple);
324*00b67f09SDavid van Moolenbroek 
325*00b67f09SDavid van Moolenbroek 	/*
326*00b67f09SDavid van Moolenbroek 	 * Do not clear temp_diff.
327*00b67f09SDavid van Moolenbroek 	 */
328*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
329*00b67f09SDavid van Moolenbroek }
330*00b67f09SDavid van Moolenbroek 
331*00b67f09SDavid van Moolenbroek /*%
332*00b67f09SDavid van Moolenbroek  * Set '*exists' to true iff the given name exists, to false otherwise.
333*00b67f09SDavid van Moolenbroek  */
334*00b67f09SDavid van Moolenbroek static isc_result_t
name_exists(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,isc_boolean_t * exists)335*00b67f09SDavid van Moolenbroek name_exists(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
336*00b67f09SDavid van Moolenbroek 	    isc_boolean_t *exists)
337*00b67f09SDavid van Moolenbroek {
338*00b67f09SDavid van Moolenbroek 	isc_result_t result;
339*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
340*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_t *iter = NULL;
341*00b67f09SDavid van Moolenbroek 
342*00b67f09SDavid van Moolenbroek 	result = dns_db_findnode(db, name, ISC_FALSE, &node);
343*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
344*00b67f09SDavid van Moolenbroek 		*exists = ISC_FALSE;
345*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
346*00b67f09SDavid van Moolenbroek 	}
347*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
348*00b67f09SDavid van Moolenbroek 		return (result);
349*00b67f09SDavid van Moolenbroek 
350*00b67f09SDavid van Moolenbroek 	result = dns_db_allrdatasets(db, node, version,
351*00b67f09SDavid van Moolenbroek 				     (isc_stdtime_t) 0, &iter);
352*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
353*00b67f09SDavid van Moolenbroek 		goto cleanup_node;
354*00b67f09SDavid van Moolenbroek 
355*00b67f09SDavid van Moolenbroek 	result = dns_rdatasetiter_first(iter);
356*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
357*00b67f09SDavid van Moolenbroek 		*exists = ISC_TRUE;
358*00b67f09SDavid van Moolenbroek 	} else if (result == ISC_R_NOMORE) {
359*00b67f09SDavid van Moolenbroek 		*exists = ISC_FALSE;
360*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
361*00b67f09SDavid van Moolenbroek 	} else
362*00b67f09SDavid van Moolenbroek 		*exists = ISC_FALSE;
363*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_destroy(&iter);
364*00b67f09SDavid van Moolenbroek 
365*00b67f09SDavid van Moolenbroek  cleanup_node:
366*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
367*00b67f09SDavid van Moolenbroek 	return (result);
368*00b67f09SDavid van Moolenbroek }
369*00b67f09SDavid van Moolenbroek 
370*00b67f09SDavid van Moolenbroek static isc_boolean_t
match_nsec3param(const dns_rdata_nsec3_t * nsec3,const dns_rdata_nsec3param_t * nsec3param)371*00b67f09SDavid van Moolenbroek match_nsec3param(const dns_rdata_nsec3_t *nsec3,
372*00b67f09SDavid van Moolenbroek 		 const dns_rdata_nsec3param_t *nsec3param)
373*00b67f09SDavid van Moolenbroek {
374*00b67f09SDavid van Moolenbroek 	if (nsec3->hash == nsec3param->hash &&
375*00b67f09SDavid van Moolenbroek 	    nsec3->iterations == nsec3param->iterations &&
376*00b67f09SDavid van Moolenbroek 	    nsec3->salt_length == nsec3param->salt_length &&
377*00b67f09SDavid van Moolenbroek 	    !memcmp(nsec3->salt, nsec3param->salt, nsec3->salt_length))
378*00b67f09SDavid van Moolenbroek 		return (ISC_TRUE);
379*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
380*00b67f09SDavid van Moolenbroek }
381*00b67f09SDavid van Moolenbroek 
382*00b67f09SDavid van Moolenbroek /*%
383*00b67f09SDavid van Moolenbroek  * Delete NSEC3 records at "name" which match "param", recording the
384*00b67f09SDavid van Moolenbroek  * change in "diff".
385*00b67f09SDavid van Moolenbroek  */
386*00b67f09SDavid van Moolenbroek static isc_result_t
delete(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,const dns_rdata_nsec3param_t * nsec3param,dns_diff_t * diff)387*00b67f09SDavid van Moolenbroek delete(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
388*00b67f09SDavid van Moolenbroek        const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff)
389*00b67f09SDavid van Moolenbroek {
390*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL ;
391*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
392*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3_t nsec3;
393*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
394*00b67f09SDavid van Moolenbroek 	isc_result_t result;
395*00b67f09SDavid van Moolenbroek 
396*00b67f09SDavid van Moolenbroek 	result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
397*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
398*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
399*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
400*00b67f09SDavid van Moolenbroek 		return (result);
401*00b67f09SDavid van Moolenbroek 
402*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
403*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3, 0,
404*00b67f09SDavid van Moolenbroek 				     (isc_stdtime_t) 0, &rdataset, NULL);
405*00b67f09SDavid van Moolenbroek 
406*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
407*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
408*00b67f09SDavid van Moolenbroek 		goto cleanup_node;
409*00b67f09SDavid van Moolenbroek 	}
410*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
411*00b67f09SDavid van Moolenbroek 		goto cleanup_node;
412*00b67f09SDavid van Moolenbroek 
413*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
414*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
415*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset))
416*00b67f09SDavid van Moolenbroek 	{
417*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
418*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
419*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_tostruct(&rdata, &nsec3, NULL));
420*00b67f09SDavid van Moolenbroek 
421*00b67f09SDavid van Moolenbroek 		if (!match_nsec3param(&nsec3, nsec3param))
422*00b67f09SDavid van Moolenbroek 			continue;
423*00b67f09SDavid van Moolenbroek 
424*00b67f09SDavid van Moolenbroek 		result = dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, name,
425*00b67f09SDavid van Moolenbroek 					      rdataset.ttl, &rdata, &tuple);
426*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
427*00b67f09SDavid van Moolenbroek 			goto failure;
428*00b67f09SDavid van Moolenbroek 		result = do_one_tuple(&tuple, db, version, diff);
429*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
430*00b67f09SDavid van Moolenbroek 			goto failure;
431*00b67f09SDavid van Moolenbroek 	}
432*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
433*00b67f09SDavid van Moolenbroek 		goto failure;
434*00b67f09SDavid van Moolenbroek 	result = ISC_R_SUCCESS;
435*00b67f09SDavid van Moolenbroek 
436*00b67f09SDavid van Moolenbroek  failure:
437*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
438*00b67f09SDavid van Moolenbroek  cleanup_node:
439*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
440*00b67f09SDavid van Moolenbroek 
441*00b67f09SDavid van Moolenbroek 	return (result);
442*00b67f09SDavid van Moolenbroek }
443*00b67f09SDavid van Moolenbroek 
444*00b67f09SDavid van Moolenbroek static isc_boolean_t
better_param(dns_rdataset_t * nsec3paramset,dns_rdata_t * param)445*00b67f09SDavid van Moolenbroek better_param(dns_rdataset_t *nsec3paramset, dns_rdata_t *param) {
446*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
447*00b67f09SDavid van Moolenbroek 	isc_result_t result;
448*00b67f09SDavid van Moolenbroek 
449*00b67f09SDavid van Moolenbroek 	if (REMOVE(param->data[1]))
450*00b67f09SDavid van Moolenbroek 		return (ISC_TRUE);
451*00b67f09SDavid van Moolenbroek 
452*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
453*00b67f09SDavid van Moolenbroek 	dns_rdataset_clone(nsec3paramset, &rdataset);
454*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
455*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
456*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
457*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata =  DNS_RDATA_INIT;
458*00b67f09SDavid van Moolenbroek 		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
459*00b67f09SDavid van Moolenbroek 
460*00b67f09SDavid van Moolenbroek 		if (rdataset.type != dns_rdatatype_nsec3param) {
461*00b67f09SDavid van Moolenbroek 			dns_rdata_t tmprdata =  DNS_RDATA_INIT;
462*00b67f09SDavid van Moolenbroek 			dns_rdataset_current(&rdataset, &tmprdata);
463*00b67f09SDavid van Moolenbroek 			if (!dns_nsec3param_fromprivate(&tmprdata, &rdata,
464*00b67f09SDavid van Moolenbroek 							buf, sizeof(buf)))
465*00b67f09SDavid van Moolenbroek 				continue;
466*00b67f09SDavid van Moolenbroek 		} else
467*00b67f09SDavid van Moolenbroek 			dns_rdataset_current(&rdataset, &rdata);
468*00b67f09SDavid van Moolenbroek 
469*00b67f09SDavid van Moolenbroek 		if (rdata.length != param->length)
470*00b67f09SDavid van Moolenbroek 			continue;
471*00b67f09SDavid van Moolenbroek 		if (rdata.data[0] != param->data[0] ||
472*00b67f09SDavid van Moolenbroek 		    REMOVE(rdata.data[1]) ||
473*00b67f09SDavid van Moolenbroek 		    rdata.data[2] != param->data[2] ||
474*00b67f09SDavid van Moolenbroek 		    rdata.data[3] != param->data[3] ||
475*00b67f09SDavid van Moolenbroek 		    rdata.data[4] != param->data[4] ||
476*00b67f09SDavid van Moolenbroek 		    memcmp(&rdata.data[5], &param->data[5], param->data[4]))
477*00b67f09SDavid van Moolenbroek 			continue;
478*00b67f09SDavid van Moolenbroek 		if (CREATE(rdata.data[1]) && !CREATE(param->data[1])) {
479*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
480*00b67f09SDavid van Moolenbroek 			return (ISC_TRUE);
481*00b67f09SDavid van Moolenbroek 		}
482*00b67f09SDavid van Moolenbroek 	}
483*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
484*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
485*00b67f09SDavid van Moolenbroek }
486*00b67f09SDavid van Moolenbroek 
487*00b67f09SDavid van Moolenbroek static isc_result_t
find_nsec3(dns_rdata_nsec3_t * nsec3,dns_rdataset_t * rdataset,const dns_rdata_nsec3param_t * nsec3param)488*00b67f09SDavid van Moolenbroek find_nsec3(dns_rdata_nsec3_t *nsec3, dns_rdataset_t *rdataset,
489*00b67f09SDavid van Moolenbroek 	   const dns_rdata_nsec3param_t *nsec3param)
490*00b67f09SDavid van Moolenbroek {
491*00b67f09SDavid van Moolenbroek 	isc_result_t result;
492*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(rdataset);
493*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
494*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(rdataset)) {
495*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
496*00b67f09SDavid van Moolenbroek 
497*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(rdataset, &rdata);
498*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_tostruct(&rdata, nsec3, NULL));
499*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&rdata);
500*00b67f09SDavid van Moolenbroek 		if (match_nsec3param(nsec3, nsec3param))
501*00b67f09SDavid van Moolenbroek 			break;
502*00b67f09SDavid van Moolenbroek 	}
503*00b67f09SDavid van Moolenbroek  failure:
504*00b67f09SDavid van Moolenbroek 	return (result);
505*00b67f09SDavid van Moolenbroek }
506*00b67f09SDavid van Moolenbroek 
507*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_addnsec3(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,const dns_rdata_nsec3param_t * nsec3param,dns_ttl_t nsecttl,isc_boolean_t unsecure,dns_diff_t * diff)508*00b67f09SDavid van Moolenbroek dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version,
509*00b67f09SDavid van Moolenbroek 		   dns_name_t *name, const dns_rdata_nsec3param_t *nsec3param,
510*00b67f09SDavid van Moolenbroek 		   dns_ttl_t nsecttl, isc_boolean_t unsecure, dns_diff_t *diff)
511*00b67f09SDavid van Moolenbroek {
512*00b67f09SDavid van Moolenbroek 	dns_dbiterator_t *dbit = NULL;
513*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
514*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *newnode = NULL;
515*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
516*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixed;
517*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fprev;
518*00b67f09SDavid van Moolenbroek 	dns_hash_t hash;
519*00b67f09SDavid van Moolenbroek 	dns_name_t *hashname;
520*00b67f09SDavid van Moolenbroek 	dns_name_t *origin;
521*00b67f09SDavid van Moolenbroek 	dns_name_t *prev;
522*00b67f09SDavid van Moolenbroek 	dns_name_t empty;
523*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3_t nsec3;
524*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
525*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
526*00b67f09SDavid van Moolenbroek 	int pass;
527*00b67f09SDavid van Moolenbroek 	isc_boolean_t exists = ISC_FALSE;
528*00b67f09SDavid van Moolenbroek 	isc_boolean_t maybe_remove_unsecure = ISC_FALSE;
529*00b67f09SDavid van Moolenbroek 	isc_uint8_t flags;
530*00b67f09SDavid van Moolenbroek 	isc_buffer_t buffer;
531*00b67f09SDavid van Moolenbroek 	isc_result_t result;
532*00b67f09SDavid van Moolenbroek 	unsigned char *old_next;
533*00b67f09SDavid van Moolenbroek 	unsigned char *salt;
534*00b67f09SDavid van Moolenbroek 	unsigned char nexthash[NSEC3_MAX_HASH_LENGTH];
535*00b67f09SDavid van Moolenbroek 	unsigned char nsec3buf[DNS_NSEC3_BUFFERSIZE];
536*00b67f09SDavid van Moolenbroek 	unsigned int iterations;
537*00b67f09SDavid van Moolenbroek 	unsigned int labels;
538*00b67f09SDavid van Moolenbroek 	size_t next_length;
539*00b67f09SDavid van Moolenbroek 	unsigned int old_length;
540*00b67f09SDavid van Moolenbroek 	unsigned int salt_length;
541*00b67f09SDavid van Moolenbroek 
542*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixed);
543*00b67f09SDavid van Moolenbroek 	hashname = dns_fixedname_name(&fixed);
544*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fprev);
545*00b67f09SDavid van Moolenbroek 	prev = dns_fixedname_name(&fprev);
546*00b67f09SDavid van Moolenbroek 
547*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
548*00b67f09SDavid van Moolenbroek 
549*00b67f09SDavid van Moolenbroek 	origin = dns_db_origin(db);
550*00b67f09SDavid van Moolenbroek 
551*00b67f09SDavid van Moolenbroek 	/*
552*00b67f09SDavid van Moolenbroek 	 * Chain parameters.
553*00b67f09SDavid van Moolenbroek 	 */
554*00b67f09SDavid van Moolenbroek 	hash = nsec3param->hash;
555*00b67f09SDavid van Moolenbroek 	iterations = nsec3param->iterations;
556*00b67f09SDavid van Moolenbroek 	salt_length = nsec3param->salt_length;
557*00b67f09SDavid van Moolenbroek 	salt = nsec3param->salt;
558*00b67f09SDavid van Moolenbroek 
559*00b67f09SDavid van Moolenbroek 	/*
560*00b67f09SDavid van Moolenbroek 	 * Default flags for a new chain.
561*00b67f09SDavid van Moolenbroek 	 */
562*00b67f09SDavid van Moolenbroek 	flags = nsec3param->flags & DNS_NSEC3FLAG_OPTOUT;
563*00b67f09SDavid van Moolenbroek 
564*00b67f09SDavid van Moolenbroek 	/*
565*00b67f09SDavid van Moolenbroek 	 * If this is the first NSEC3 in the chain nexthash will
566*00b67f09SDavid van Moolenbroek 	 * remain pointing to itself.
567*00b67f09SDavid van Moolenbroek 	 */
568*00b67f09SDavid van Moolenbroek 	next_length = sizeof(nexthash);
569*00b67f09SDavid van Moolenbroek 	CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
570*00b67f09SDavid van Moolenbroek 				 name, origin, hash, iterations,
571*00b67f09SDavid van Moolenbroek 				 salt, salt_length));
572*00b67f09SDavid van Moolenbroek 	INSIST(next_length <= sizeof(nexthash));
573*00b67f09SDavid van Moolenbroek 
574*00b67f09SDavid van Moolenbroek 	/*
575*00b67f09SDavid van Moolenbroek 	 * Create the node if it doesn't exist and hold
576*00b67f09SDavid van Moolenbroek 	 * a reference to it until we have added the NSEC3.
577*00b67f09SDavid van Moolenbroek 	 */
578*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_findnsec3node(db, hashname, ISC_TRUE, &newnode));
579*00b67f09SDavid van Moolenbroek 
580*00b67f09SDavid van Moolenbroek 	/*
581*00b67f09SDavid van Moolenbroek 	 * Seek the iterator to the 'newnode'.
582*00b67f09SDavid van Moolenbroek 	 */
583*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbit));
584*00b67f09SDavid van Moolenbroek 	CHECK(dns_dbiterator_seek(dbit, hashname));
585*00b67f09SDavid van Moolenbroek 	CHECK(dns_dbiterator_pause(dbit));
586*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, newnode, version, dns_rdatatype_nsec3,
587*00b67f09SDavid van Moolenbroek 				     0, (isc_stdtime_t) 0, &rdataset, NULL);
588*00b67f09SDavid van Moolenbroek 	/*
589*00b67f09SDavid van Moolenbroek 	 * If we updating a existing NSEC3 then find its
590*00b67f09SDavid van Moolenbroek 	 * next field.
591*00b67f09SDavid van Moolenbroek 	 */
592*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
593*00b67f09SDavid van Moolenbroek 		result = find_nsec3(&nsec3, &rdataset, nsec3param);
594*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
595*00b67f09SDavid van Moolenbroek 			if (!CREATE(nsec3param->flags))
596*00b67f09SDavid van Moolenbroek 				flags = nsec3.flags;
597*00b67f09SDavid van Moolenbroek 			next_length = nsec3.next_length;
598*00b67f09SDavid van Moolenbroek 			INSIST(next_length <= sizeof(nexthash));
599*00b67f09SDavid van Moolenbroek 			memmove(nexthash, nsec3.next, next_length);
600*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
601*00b67f09SDavid van Moolenbroek 			/*
602*00b67f09SDavid van Moolenbroek 			 * If the NSEC3 is not for a unsecure delegation then
603*00b67f09SDavid van Moolenbroek 			 * we are just updating it.  If it is for a unsecure
604*00b67f09SDavid van Moolenbroek 			 * delegation then we need find out if we need to
605*00b67f09SDavid van Moolenbroek 			 * remove the NSEC3 record or not by examining the
606*00b67f09SDavid van Moolenbroek 			 * previous NSEC3 record.
607*00b67f09SDavid van Moolenbroek 			 */
608*00b67f09SDavid van Moolenbroek 			if (!unsecure)
609*00b67f09SDavid van Moolenbroek 				goto addnsec3;
610*00b67f09SDavid van Moolenbroek 			else if (CREATE(nsec3param->flags) && OPTOUT(flags)) {
611*00b67f09SDavid van Moolenbroek 				result = dns_nsec3_delnsec3(db, version, name,
612*00b67f09SDavid van Moolenbroek 							    nsec3param, diff);
613*00b67f09SDavid van Moolenbroek 				goto failure;
614*00b67f09SDavid van Moolenbroek 			} else
615*00b67f09SDavid van Moolenbroek 				maybe_remove_unsecure = ISC_TRUE;
616*00b67f09SDavid van Moolenbroek 		} else {
617*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
618*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_NOMORE)
619*00b67f09SDavid van Moolenbroek 				goto failure;
620*00b67f09SDavid van Moolenbroek 		}
621*00b67f09SDavid van Moolenbroek 	}
622*00b67f09SDavid van Moolenbroek 
623*00b67f09SDavid van Moolenbroek 	/*
624*00b67f09SDavid van Moolenbroek 	 * Find the previous NSEC3 (if any) and update it if required.
625*00b67f09SDavid van Moolenbroek 	 */
626*00b67f09SDavid van Moolenbroek 	pass = 0;
627*00b67f09SDavid van Moolenbroek 	do {
628*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_prev(dbit);
629*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE) {
630*00b67f09SDavid van Moolenbroek 			pass++;
631*00b67f09SDavid van Moolenbroek 			CHECK(dns_dbiterator_last(dbit));
632*00b67f09SDavid van Moolenbroek 		}
633*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_current(dbit, &node, prev));
634*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_pause(dbit));
635*00b67f09SDavid van Moolenbroek 		result = dns_db_findrdataset(db, node, version,
636*00b67f09SDavid van Moolenbroek 					     dns_rdatatype_nsec3, 0,
637*00b67f09SDavid van Moolenbroek 					     (isc_stdtime_t) 0, &rdataset,
638*00b67f09SDavid van Moolenbroek 					     NULL);
639*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
640*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
641*00b67f09SDavid van Moolenbroek 			continue;
642*00b67f09SDavid van Moolenbroek 
643*00b67f09SDavid van Moolenbroek 		result = find_nsec3(&nsec3, &rdataset, nsec3param);
644*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE) {
645*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
646*00b67f09SDavid van Moolenbroek 			continue;
647*00b67f09SDavid van Moolenbroek 		}
648*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
649*00b67f09SDavid van Moolenbroek 			goto failure;
650*00b67f09SDavid van Moolenbroek 
651*00b67f09SDavid van Moolenbroek 		if (maybe_remove_unsecure) {
652*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
653*00b67f09SDavid van Moolenbroek 			/*
654*00b67f09SDavid van Moolenbroek 			 * If we have OPTOUT set in the previous NSEC3 record
655*00b67f09SDavid van Moolenbroek 			 * we actually need to delete the NSEC3 record.
656*00b67f09SDavid van Moolenbroek 			 * Otherwise we just need to replace the NSEC3 record.
657*00b67f09SDavid van Moolenbroek 			 */
658*00b67f09SDavid van Moolenbroek 			if (OPTOUT(nsec3.flags)) {
659*00b67f09SDavid van Moolenbroek 				result = dns_nsec3_delnsec3(db, version, name,
660*00b67f09SDavid van Moolenbroek 							    nsec3param, diff);
661*00b67f09SDavid van Moolenbroek 				goto failure;
662*00b67f09SDavid van Moolenbroek 			}
663*00b67f09SDavid van Moolenbroek 			goto addnsec3;
664*00b67f09SDavid van Moolenbroek 		} else {
665*00b67f09SDavid van Moolenbroek 			/*
666*00b67f09SDavid van Moolenbroek 			 * Is this is a unsecure delegation we are adding?
667*00b67f09SDavid van Moolenbroek 			 * If so no change is required.
668*00b67f09SDavid van Moolenbroek 			 */
669*00b67f09SDavid van Moolenbroek 			if (OPTOUT(nsec3.flags) && unsecure) {
670*00b67f09SDavid van Moolenbroek 				dns_rdataset_disassociate(&rdataset);
671*00b67f09SDavid van Moolenbroek 				goto failure;
672*00b67f09SDavid van Moolenbroek 			}
673*00b67f09SDavid van Moolenbroek 		}
674*00b67f09SDavid van Moolenbroek 
675*00b67f09SDavid van Moolenbroek 		old_next = nsec3.next;
676*00b67f09SDavid van Moolenbroek 		old_length = nsec3.next_length;
677*00b67f09SDavid van Moolenbroek 
678*00b67f09SDavid van Moolenbroek 		/*
679*00b67f09SDavid van Moolenbroek 		 * Delete the old previous NSEC3.
680*00b67f09SDavid van Moolenbroek 		 */
681*00b67f09SDavid van Moolenbroek 		CHECK(delete(db, version, prev, nsec3param, diff));
682*00b67f09SDavid van Moolenbroek 
683*00b67f09SDavid van Moolenbroek 		/*
684*00b67f09SDavid van Moolenbroek 		 * Fixup the previous NSEC3.
685*00b67f09SDavid van Moolenbroek 		 */
686*00b67f09SDavid van Moolenbroek 		nsec3.next = nexthash;
687*00b67f09SDavid van Moolenbroek 		nsec3.next_length = (unsigned char)next_length;
688*00b67f09SDavid van Moolenbroek 		isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf));
689*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
690*00b67f09SDavid van Moolenbroek 					   dns_rdatatype_nsec3, &nsec3,
691*00b67f09SDavid van Moolenbroek 					   &buffer));
692*00b67f09SDavid van Moolenbroek 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, prev,
693*00b67f09SDavid van Moolenbroek 					   rdataset.ttl, &rdata, &tuple));
694*00b67f09SDavid van Moolenbroek 		CHECK(do_one_tuple(&tuple, db, version, diff));
695*00b67f09SDavid van Moolenbroek 		INSIST(old_length <= sizeof(nexthash));
696*00b67f09SDavid van Moolenbroek 		memmove(nexthash, old_next, old_length);
697*00b67f09SDavid van Moolenbroek 		if (!CREATE(nsec3param->flags))
698*00b67f09SDavid van Moolenbroek 			flags = nsec3.flags;
699*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&rdata);
700*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
701*00b67f09SDavid van Moolenbroek 		break;
702*00b67f09SDavid van Moolenbroek 	} while (pass < 2);
703*00b67f09SDavid van Moolenbroek 
704*00b67f09SDavid van Moolenbroek  addnsec3:
705*00b67f09SDavid van Moolenbroek 	/*
706*00b67f09SDavid van Moolenbroek 	 * Create the NSEC3 RDATA.
707*00b67f09SDavid van Moolenbroek 	 */
708*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
709*00b67f09SDavid van Moolenbroek 	CHECK(dns_nsec3_buildrdata(db, version, node, hash, flags, iterations,
710*00b67f09SDavid van Moolenbroek 				   salt, salt_length, nexthash, next_length,
711*00b67f09SDavid van Moolenbroek 				   nsec3buf, &rdata));
712*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
713*00b67f09SDavid van Moolenbroek 
714*00b67f09SDavid van Moolenbroek 	/*
715*00b67f09SDavid van Moolenbroek 	 * Delete the old NSEC3 and record the change.
716*00b67f09SDavid van Moolenbroek 	 */
717*00b67f09SDavid van Moolenbroek 	CHECK(delete(db, version, hashname, nsec3param, diff));
718*00b67f09SDavid van Moolenbroek 	/*
719*00b67f09SDavid van Moolenbroek 	 * Add the new NSEC3 and record the change.
720*00b67f09SDavid van Moolenbroek 	 */
721*00b67f09SDavid van Moolenbroek 	CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
722*00b67f09SDavid van Moolenbroek 				   hashname, nsecttl, &rdata, &tuple));
723*00b67f09SDavid van Moolenbroek 	CHECK(do_one_tuple(&tuple, db, version, diff));
724*00b67f09SDavid van Moolenbroek 	INSIST(tuple == NULL);
725*00b67f09SDavid van Moolenbroek 	dns_rdata_reset(&rdata);
726*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &newnode);
727*00b67f09SDavid van Moolenbroek 
728*00b67f09SDavid van Moolenbroek 	/*
729*00b67f09SDavid van Moolenbroek 	 * Add missing NSEC3 records for empty nodes
730*00b67f09SDavid van Moolenbroek 	 */
731*00b67f09SDavid van Moolenbroek 	dns_name_init(&empty, NULL);
732*00b67f09SDavid van Moolenbroek 	dns_name_clone(name, &empty);
733*00b67f09SDavid van Moolenbroek 	do {
734*00b67f09SDavid van Moolenbroek 		labels = dns_name_countlabels(&empty) - 1;
735*00b67f09SDavid van Moolenbroek 		if (labels <= dns_name_countlabels(origin))
736*00b67f09SDavid van Moolenbroek 			break;
737*00b67f09SDavid van Moolenbroek 		dns_name_getlabelsequence(&empty, 1, labels, &empty);
738*00b67f09SDavid van Moolenbroek 		CHECK(name_exists(db, version, &empty, &exists));
739*00b67f09SDavid van Moolenbroek 		if (exists)
740*00b67f09SDavid van Moolenbroek 			break;
741*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
742*00b67f09SDavid van Moolenbroek 					 &empty, origin, hash, iterations,
743*00b67f09SDavid van Moolenbroek 					 salt, salt_length));
744*00b67f09SDavid van Moolenbroek 
745*00b67f09SDavid van Moolenbroek 		/*
746*00b67f09SDavid van Moolenbroek 		 * Create the node if it doesn't exist and hold
747*00b67f09SDavid van Moolenbroek 		 * a reference to it until we have added the NSEC3
748*00b67f09SDavid van Moolenbroek 		 * or we discover we don't need to add make a change.
749*00b67f09SDavid van Moolenbroek 		 */
750*00b67f09SDavid van Moolenbroek 		CHECK(dns_db_findnsec3node(db, hashname, ISC_TRUE, &newnode));
751*00b67f09SDavid van Moolenbroek 		result = dns_db_findrdataset(db, newnode, version,
752*00b67f09SDavid van Moolenbroek 					     dns_rdatatype_nsec3, 0,
753*00b67f09SDavid van Moolenbroek 					     (isc_stdtime_t) 0, &rdataset,
754*00b67f09SDavid van Moolenbroek 					     NULL);
755*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
756*00b67f09SDavid van Moolenbroek 			result = find_nsec3(&nsec3, &rdataset, nsec3param);
757*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
758*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_SUCCESS) {
759*00b67f09SDavid van Moolenbroek 				dns_db_detachnode(db, &newnode);
760*00b67f09SDavid van Moolenbroek 				break;
761*00b67f09SDavid van Moolenbroek 			}
762*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_NOMORE)
763*00b67f09SDavid van Moolenbroek 				goto failure;
764*00b67f09SDavid van Moolenbroek 		}
765*00b67f09SDavid van Moolenbroek 
766*00b67f09SDavid van Moolenbroek 		/*
767*00b67f09SDavid van Moolenbroek 		 * Find the previous NSEC3 and update it.
768*00b67f09SDavid van Moolenbroek 		 */
769*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_seek(dbit, hashname));
770*00b67f09SDavid van Moolenbroek 		pass = 0;
771*00b67f09SDavid van Moolenbroek 		do {
772*00b67f09SDavid van Moolenbroek 			result = dns_dbiterator_prev(dbit);
773*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOMORE) {
774*00b67f09SDavid van Moolenbroek 				pass++;
775*00b67f09SDavid van Moolenbroek 				CHECK(dns_dbiterator_last(dbit));
776*00b67f09SDavid van Moolenbroek 			}
777*00b67f09SDavid van Moolenbroek 			CHECK(dns_dbiterator_current(dbit, &node, prev));
778*00b67f09SDavid van Moolenbroek 			CHECK(dns_dbiterator_pause(dbit));
779*00b67f09SDavid van Moolenbroek 			result = dns_db_findrdataset(db, node, version,
780*00b67f09SDavid van Moolenbroek 						     dns_rdatatype_nsec3, 0,
781*00b67f09SDavid van Moolenbroek 						     (isc_stdtime_t) 0,
782*00b67f09SDavid van Moolenbroek 						     &rdataset, NULL);
783*00b67f09SDavid van Moolenbroek 			dns_db_detachnode(db, &node);
784*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
785*00b67f09SDavid van Moolenbroek 				continue;
786*00b67f09SDavid van Moolenbroek 			result = find_nsec3(&nsec3, &rdataset, nsec3param);
787*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOMORE) {
788*00b67f09SDavid van Moolenbroek 				dns_rdataset_disassociate(&rdataset);
789*00b67f09SDavid van Moolenbroek 				continue;
790*00b67f09SDavid van Moolenbroek 			}
791*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
792*00b67f09SDavid van Moolenbroek 				goto failure;
793*00b67f09SDavid van Moolenbroek 
794*00b67f09SDavid van Moolenbroek 			old_next = nsec3.next;
795*00b67f09SDavid van Moolenbroek 			old_length = nsec3.next_length;
796*00b67f09SDavid van Moolenbroek 
797*00b67f09SDavid van Moolenbroek 			/*
798*00b67f09SDavid van Moolenbroek 			 * Delete the old previous NSEC3.
799*00b67f09SDavid van Moolenbroek 			 */
800*00b67f09SDavid van Moolenbroek 			CHECK(delete(db, version, prev, nsec3param, diff));
801*00b67f09SDavid van Moolenbroek 
802*00b67f09SDavid van Moolenbroek 			/*
803*00b67f09SDavid van Moolenbroek 			 * Fixup the previous NSEC3.
804*00b67f09SDavid van Moolenbroek 			 */
805*00b67f09SDavid van Moolenbroek 			nsec3.next = nexthash;
806*00b67f09SDavid van Moolenbroek 			nsec3.next_length = (unsigned char)next_length;
807*00b67f09SDavid van Moolenbroek 			isc_buffer_init(&buffer, nsec3buf,
808*00b67f09SDavid van Moolenbroek 					sizeof(nsec3buf));
809*00b67f09SDavid van Moolenbroek 			CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
810*00b67f09SDavid van Moolenbroek 						   dns_rdatatype_nsec3, &nsec3,
811*00b67f09SDavid van Moolenbroek 						   &buffer));
812*00b67f09SDavid van Moolenbroek 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
813*00b67f09SDavid van Moolenbroek 						   prev, rdataset.ttl, &rdata,
814*00b67f09SDavid van Moolenbroek 						   &tuple));
815*00b67f09SDavid van Moolenbroek 			CHECK(do_one_tuple(&tuple, db, version, diff));
816*00b67f09SDavid van Moolenbroek 			INSIST(old_length <= sizeof(nexthash));
817*00b67f09SDavid van Moolenbroek 			memmove(nexthash, old_next, old_length);
818*00b67f09SDavid van Moolenbroek 			if (!CREATE(nsec3param->flags))
819*00b67f09SDavid van Moolenbroek 				flags = nsec3.flags;
820*00b67f09SDavid van Moolenbroek 			dns_rdata_reset(&rdata);
821*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
822*00b67f09SDavid van Moolenbroek 			break;
823*00b67f09SDavid van Moolenbroek 		} while (pass < 2);
824*00b67f09SDavid van Moolenbroek 
825*00b67f09SDavid van Moolenbroek 		INSIST(pass < 2);
826*00b67f09SDavid van Moolenbroek 
827*00b67f09SDavid van Moolenbroek 		/*
828*00b67f09SDavid van Moolenbroek 		 * Create the NSEC3 RDATA for the empty node.
829*00b67f09SDavid van Moolenbroek 		 */
830*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_buildrdata(db, version, NULL, hash, flags,
831*00b67f09SDavid van Moolenbroek 					   iterations, salt, salt_length,
832*00b67f09SDavid van Moolenbroek 					   nexthash, next_length, nsec3buf,
833*00b67f09SDavid van Moolenbroek 					   &rdata));
834*00b67f09SDavid van Moolenbroek 		/*
835*00b67f09SDavid van Moolenbroek 		 * Delete the old NSEC3 and record the change.
836*00b67f09SDavid van Moolenbroek 		 */
837*00b67f09SDavid van Moolenbroek 		CHECK(delete(db, version, hashname, nsec3param, diff));
838*00b67f09SDavid van Moolenbroek 
839*00b67f09SDavid van Moolenbroek 		/*
840*00b67f09SDavid van Moolenbroek 		 * Add the new NSEC3 and record the change.
841*00b67f09SDavid van Moolenbroek 		 */
842*00b67f09SDavid van Moolenbroek 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
843*00b67f09SDavid van Moolenbroek 					   hashname, nsecttl, &rdata, &tuple));
844*00b67f09SDavid van Moolenbroek 		CHECK(do_one_tuple(&tuple, db, version, diff));
845*00b67f09SDavid van Moolenbroek 		INSIST(tuple == NULL);
846*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&rdata);
847*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &newnode);
848*00b67f09SDavid van Moolenbroek 	} while (1);
849*00b67f09SDavid van Moolenbroek 
850*00b67f09SDavid van Moolenbroek 	/* result cannot be ISC_R_NOMORE here */
851*00b67f09SDavid van Moolenbroek 	INSIST(result != ISC_R_NOMORE);
852*00b67f09SDavid van Moolenbroek 
853*00b67f09SDavid van Moolenbroek  failure:
854*00b67f09SDavid van Moolenbroek 	if (dbit != NULL)
855*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&dbit);
856*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
857*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
858*00b67f09SDavid van Moolenbroek 	if (node != NULL)
859*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
860*00b67f09SDavid van Moolenbroek 	if (newnode != NULL)
861*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &newnode);
862*00b67f09SDavid van Moolenbroek 	return (result);
863*00b67f09SDavid van Moolenbroek }
864*00b67f09SDavid van Moolenbroek 
865*00b67f09SDavid van Moolenbroek /*%
866*00b67f09SDavid van Moolenbroek  * Add NSEC3 records for "name", recording the change in "diff".
867*00b67f09SDavid van Moolenbroek  * The existing NSEC3 records are removed.
868*00b67f09SDavid van Moolenbroek  */
869*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_addnsec3s(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,dns_ttl_t nsecttl,isc_boolean_t unsecure,dns_diff_t * diff)870*00b67f09SDavid van Moolenbroek dns_nsec3_addnsec3s(dns_db_t *db, dns_dbversion_t *version,
871*00b67f09SDavid van Moolenbroek 		    dns_name_t *name, dns_ttl_t nsecttl,
872*00b67f09SDavid van Moolenbroek 		    isc_boolean_t unsecure, dns_diff_t *diff)
873*00b67f09SDavid van Moolenbroek {
874*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
875*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3param_t nsec3param;
876*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
877*00b67f09SDavid van Moolenbroek 	isc_result_t result;
878*00b67f09SDavid van Moolenbroek 
879*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
880*00b67f09SDavid van Moolenbroek 
881*00b67f09SDavid van Moolenbroek 	/*
882*00b67f09SDavid van Moolenbroek 	 * Find the NSEC3 parameters for this zone.
883*00b67f09SDavid van Moolenbroek 	 */
884*00b67f09SDavid van Moolenbroek 	result = dns_db_getoriginnode(db, &node);
885*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
886*00b67f09SDavid van Moolenbroek 		return (result);
887*00b67f09SDavid van Moolenbroek 
888*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version,
889*00b67f09SDavid van Moolenbroek 				     dns_rdatatype_nsec3param, 0, 0,
890*00b67f09SDavid van Moolenbroek 				     &rdataset, NULL);
891*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
892*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
893*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
894*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
895*00b67f09SDavid van Moolenbroek 		return (result);
896*00b67f09SDavid van Moolenbroek 
897*00b67f09SDavid van Moolenbroek 	/*
898*00b67f09SDavid van Moolenbroek 	 * Update each active NSEC3 chain.
899*00b67f09SDavid van Moolenbroek 	 */
900*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
901*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
902*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
903*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
904*00b67f09SDavid van Moolenbroek 
905*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
906*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
907*00b67f09SDavid van Moolenbroek 
908*00b67f09SDavid van Moolenbroek 		if (nsec3param.flags != 0)
909*00b67f09SDavid van Moolenbroek 			continue;
910*00b67f09SDavid van Moolenbroek 		/*
911*00b67f09SDavid van Moolenbroek 		 * We have a active chain.  Update it.
912*00b67f09SDavid van Moolenbroek 		 */
913*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param,
914*00b67f09SDavid van Moolenbroek 					 nsecttl, unsecure, diff));
915*00b67f09SDavid van Moolenbroek 	}
916*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
917*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
918*00b67f09SDavid van Moolenbroek 
919*00b67f09SDavid van Moolenbroek  failure:
920*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
921*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
922*00b67f09SDavid van Moolenbroek 	if (node != NULL)
923*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
924*00b67f09SDavid van Moolenbroek 
925*00b67f09SDavid van Moolenbroek 	return (result);
926*00b67f09SDavid van Moolenbroek }
927*00b67f09SDavid van Moolenbroek 
928*00b67f09SDavid van Moolenbroek isc_boolean_t
dns_nsec3param_fromprivate(dns_rdata_t * src,dns_rdata_t * target,unsigned char * buf,size_t buflen)929*00b67f09SDavid van Moolenbroek dns_nsec3param_fromprivate(dns_rdata_t *src, dns_rdata_t *target,
930*00b67f09SDavid van Moolenbroek 			   unsigned char *buf, size_t buflen)
931*00b67f09SDavid van Moolenbroek {
932*00b67f09SDavid van Moolenbroek 	dns_decompress_t dctx;
933*00b67f09SDavid van Moolenbroek 	isc_result_t result;
934*00b67f09SDavid van Moolenbroek 	isc_buffer_t buf1;
935*00b67f09SDavid van Moolenbroek 	isc_buffer_t buf2;
936*00b67f09SDavid van Moolenbroek 
937*00b67f09SDavid van Moolenbroek 	/*
938*00b67f09SDavid van Moolenbroek 	 * Algorithm 0 (reserved by RFC 4034) is used to identify
939*00b67f09SDavid van Moolenbroek 	 * NSEC3PARAM records from DNSKEY pointers.
940*00b67f09SDavid van Moolenbroek 	 */
941*00b67f09SDavid van Moolenbroek 	if (src->length < 1 || src->data[0] != 0)
942*00b67f09SDavid van Moolenbroek 		return (ISC_FALSE);
943*00b67f09SDavid van Moolenbroek 
944*00b67f09SDavid van Moolenbroek 	isc_buffer_init(&buf1, src->data + 1, src->length - 1);
945*00b67f09SDavid van Moolenbroek 	isc_buffer_add(&buf1, src->length - 1);
946*00b67f09SDavid van Moolenbroek 	isc_buffer_setactive(&buf1, src->length - 1);
947*00b67f09SDavid van Moolenbroek 	isc_buffer_init(&buf2, buf, (unsigned int)buflen);
948*00b67f09SDavid van Moolenbroek 	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
949*00b67f09SDavid van Moolenbroek 	result = dns_rdata_fromwire(target, src->rdclass,
950*00b67f09SDavid van Moolenbroek 				    dns_rdatatype_nsec3param,
951*00b67f09SDavid van Moolenbroek 				    &buf1, &dctx, 0, &buf2);
952*00b67f09SDavid van Moolenbroek 	dns_decompress_invalidate(&dctx);
953*00b67f09SDavid van Moolenbroek 
954*00b67f09SDavid van Moolenbroek 	return (ISC_TF(result == ISC_R_SUCCESS));
955*00b67f09SDavid van Moolenbroek }
956*00b67f09SDavid van Moolenbroek 
957*00b67f09SDavid van Moolenbroek void
dns_nsec3param_toprivate(dns_rdata_t * src,dns_rdata_t * target,dns_rdatatype_t privatetype,unsigned char * buf,size_t buflen)958*00b67f09SDavid van Moolenbroek dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target,
959*00b67f09SDavid van Moolenbroek 			 dns_rdatatype_t privatetype,
960*00b67f09SDavid van Moolenbroek 			 unsigned char *buf, size_t buflen)
961*00b67f09SDavid van Moolenbroek {
962*00b67f09SDavid van Moolenbroek 	REQUIRE(buflen >= src->length + 1);
963*00b67f09SDavid van Moolenbroek 
964*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_RDATA_INITIALIZED(target));
965*00b67f09SDavid van Moolenbroek 
966*00b67f09SDavid van Moolenbroek 	memmove(buf + 1, src->data, src->length);
967*00b67f09SDavid van Moolenbroek 	buf[0] = 0;
968*00b67f09SDavid van Moolenbroek 	target->data = buf;
969*00b67f09SDavid van Moolenbroek 	target->length = src->length + 1;
970*00b67f09SDavid van Moolenbroek 	target->type = privatetype;
971*00b67f09SDavid van Moolenbroek 	target->rdclass = src->rdclass;
972*00b67f09SDavid van Moolenbroek 	target->flags = 0;
973*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(target, link);
974*00b67f09SDavid van Moolenbroek }
975*00b67f09SDavid van Moolenbroek 
976*00b67f09SDavid van Moolenbroek static isc_result_t
rr_exists(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,const dns_rdata_t * rdata,isc_boolean_t * flag)977*00b67f09SDavid van Moolenbroek rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
978*00b67f09SDavid van Moolenbroek 	  const dns_rdata_t *rdata, isc_boolean_t *flag)
979*00b67f09SDavid van Moolenbroek {
980*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
981*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
982*00b67f09SDavid van Moolenbroek 	isc_result_t result;
983*00b67f09SDavid van Moolenbroek 
984*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
985*00b67f09SDavid van Moolenbroek 	if (rdata->type == dns_rdatatype_nsec3)
986*00b67f09SDavid van Moolenbroek 		CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
987*00b67f09SDavid van Moolenbroek 	else
988*00b67f09SDavid van Moolenbroek 		CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
989*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, ver, rdata->type, 0,
990*00b67f09SDavid van Moolenbroek 				     (isc_stdtime_t) 0, &rdataset, NULL);
991*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
992*00b67f09SDavid van Moolenbroek 		*flag = ISC_FALSE;
993*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
994*00b67f09SDavid van Moolenbroek 		goto failure;
995*00b67f09SDavid van Moolenbroek 	}
996*00b67f09SDavid van Moolenbroek 
997*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
998*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
999*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1000*00b67f09SDavid van Moolenbroek 		dns_rdata_t myrdata = DNS_RDATA_INIT;
1001*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &myrdata);
1002*00b67f09SDavid van Moolenbroek 		if (!dns_rdata_casecompare(&myrdata, rdata))
1003*00b67f09SDavid van Moolenbroek 			break;
1004*00b67f09SDavid van Moolenbroek 	}
1005*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1006*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
1007*00b67f09SDavid van Moolenbroek 		*flag = ISC_TRUE;
1008*00b67f09SDavid van Moolenbroek 	} else if (result == ISC_R_NOMORE) {
1009*00b67f09SDavid van Moolenbroek 		*flag = ISC_FALSE;
1010*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1011*00b67f09SDavid van Moolenbroek 	}
1012*00b67f09SDavid van Moolenbroek 
1013*00b67f09SDavid van Moolenbroek  failure:
1014*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1015*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1016*00b67f09SDavid van Moolenbroek 	return (result);
1017*00b67f09SDavid van Moolenbroek }
1018*00b67f09SDavid van Moolenbroek 
1019*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3param_deletechains(dns_db_t * db,dns_dbversion_t * ver,dns_zone_t * zone,isc_boolean_t nonsec,dns_diff_t * diff)1020*00b67f09SDavid van Moolenbroek dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver,
1021*00b67f09SDavid van Moolenbroek 			    dns_zone_t *zone, isc_boolean_t nonsec,
1022*00b67f09SDavid van Moolenbroek 			    dns_diff_t *diff)
1023*00b67f09SDavid van Moolenbroek {
1024*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1025*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
1026*00b67f09SDavid van Moolenbroek 	dns_name_t next;
1027*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
1028*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1029*00b67f09SDavid van Moolenbroek 	isc_boolean_t flag;
1030*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
1031*00b67f09SDavid van Moolenbroek 	unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1];
1032*00b67f09SDavid van Moolenbroek 	dns_name_t *origin = dns_zone_getorigin(zone);
1033*00b67f09SDavid van Moolenbroek 	dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
1034*00b67f09SDavid van Moolenbroek 
1035*00b67f09SDavid van Moolenbroek 	dns_name_init(&next, NULL);
1036*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1037*00b67f09SDavid van Moolenbroek 
1038*00b67f09SDavid van Moolenbroek 	result = dns_db_getoriginnode(db, &node);
1039*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1040*00b67f09SDavid van Moolenbroek 		return (result);
1041*00b67f09SDavid van Moolenbroek 
1042*00b67f09SDavid van Moolenbroek 	/*
1043*00b67f09SDavid van Moolenbroek 	 * Cause all NSEC3 chains to be deleted.
1044*00b67f09SDavid van Moolenbroek 	 */
1045*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
1046*00b67f09SDavid van Moolenbroek 				     0, (isc_stdtime_t) 0, &rdataset, NULL);
1047*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1048*00b67f09SDavid van Moolenbroek 		goto try_private;
1049*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1050*00b67f09SDavid van Moolenbroek 		goto failure;
1051*00b67f09SDavid van Moolenbroek 
1052*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1053*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1054*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1055*00b67f09SDavid van Moolenbroek 		dns_rdata_t private = DNS_RDATA_INIT;
1056*00b67f09SDavid van Moolenbroek 
1057*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
1058*00b67f09SDavid van Moolenbroek 
1059*00b67f09SDavid van Moolenbroek 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin,
1060*00b67f09SDavid van Moolenbroek 					   rdataset.ttl, &rdata, &tuple));
1061*00b67f09SDavid van Moolenbroek 		CHECK(do_one_tuple(&tuple, db, ver, diff));
1062*00b67f09SDavid van Moolenbroek 		INSIST(tuple == NULL);
1063*00b67f09SDavid van Moolenbroek 
1064*00b67f09SDavid van Moolenbroek 		dns_nsec3param_toprivate(&rdata, &private, privatetype,
1065*00b67f09SDavid van Moolenbroek 					 buf, sizeof(buf));
1066*00b67f09SDavid van Moolenbroek 		buf[2] = DNS_NSEC3FLAG_REMOVE;
1067*00b67f09SDavid van Moolenbroek 		if (nonsec)
1068*00b67f09SDavid van Moolenbroek 			buf[2] |= DNS_NSEC3FLAG_NONSEC;
1069*00b67f09SDavid van Moolenbroek 
1070*00b67f09SDavid van Moolenbroek 		CHECK(rr_exists(db, ver, origin, &private, &flag));
1071*00b67f09SDavid van Moolenbroek 
1072*00b67f09SDavid van Moolenbroek 		if (!flag) {
1073*00b67f09SDavid van Moolenbroek 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
1074*00b67f09SDavid van Moolenbroek 						   origin, 0, &private,
1075*00b67f09SDavid van Moolenbroek 						   &tuple));
1076*00b67f09SDavid van Moolenbroek 			CHECK(do_one_tuple(&tuple, db, ver, diff));
1077*00b67f09SDavid van Moolenbroek 			INSIST(tuple == NULL);
1078*00b67f09SDavid van Moolenbroek 		}
1079*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&rdata);
1080*00b67f09SDavid van Moolenbroek 	}
1081*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
1082*00b67f09SDavid van Moolenbroek 		goto failure;
1083*00b67f09SDavid van Moolenbroek 
1084*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1085*00b67f09SDavid van Moolenbroek 
1086*00b67f09SDavid van Moolenbroek  try_private:
1087*00b67f09SDavid van Moolenbroek 	if (privatetype == 0)
1088*00b67f09SDavid van Moolenbroek 		goto success;
1089*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, ver, privatetype, 0,
1090*00b67f09SDavid van Moolenbroek 				     (isc_stdtime_t) 0, &rdataset, NULL);
1091*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1092*00b67f09SDavid van Moolenbroek 		goto success;
1093*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1094*00b67f09SDavid van Moolenbroek 		goto failure;
1095*00b67f09SDavid van Moolenbroek 
1096*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1097*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1098*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1099*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&rdata);
1100*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
1101*00b67f09SDavid van Moolenbroek 		INSIST(rdata.length <= sizeof(buf));
1102*00b67f09SDavid van Moolenbroek 		memmove(buf, rdata.data, rdata.length);
1103*00b67f09SDavid van Moolenbroek 
1104*00b67f09SDavid van Moolenbroek 		/*
1105*00b67f09SDavid van Moolenbroek 		 * Private NSEC3 record length >= 6.
1106*00b67f09SDavid van Moolenbroek 		 * <0(1), hash(1), flags(1), iterations(2), saltlen(1)>
1107*00b67f09SDavid van Moolenbroek 		 */
1108*00b67f09SDavid van Moolenbroek 		if (rdata.length < 6 || buf[0] != 0 ||
1109*00b67f09SDavid van Moolenbroek 		    (buf[2] & DNS_NSEC3FLAG_REMOVE) != 0 ||
1110*00b67f09SDavid van Moolenbroek 		    (nonsec && (buf[2] & DNS_NSEC3FLAG_NONSEC) != 0))
1111*00b67f09SDavid van Moolenbroek 			continue;
1112*00b67f09SDavid van Moolenbroek 
1113*00b67f09SDavid van Moolenbroek 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin,
1114*00b67f09SDavid van Moolenbroek 					   0, &rdata, &tuple));
1115*00b67f09SDavid van Moolenbroek 		CHECK(do_one_tuple(&tuple, db, ver, diff));
1116*00b67f09SDavid van Moolenbroek 		INSIST(tuple == NULL);
1117*00b67f09SDavid van Moolenbroek 
1118*00b67f09SDavid van Moolenbroek 		rdata.data = buf;
1119*00b67f09SDavid van Moolenbroek 		buf[2] = DNS_NSEC3FLAG_REMOVE;
1120*00b67f09SDavid van Moolenbroek 		if (nonsec)
1121*00b67f09SDavid van Moolenbroek 			buf[2] |= DNS_NSEC3FLAG_NONSEC;
1122*00b67f09SDavid van Moolenbroek 
1123*00b67f09SDavid van Moolenbroek 		CHECK(rr_exists(db, ver, origin, &rdata, &flag));
1124*00b67f09SDavid van Moolenbroek 
1125*00b67f09SDavid van Moolenbroek 		if (!flag) {
1126*00b67f09SDavid van Moolenbroek 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
1127*00b67f09SDavid van Moolenbroek 						   origin, 0, &rdata, &tuple));
1128*00b67f09SDavid van Moolenbroek 			CHECK(do_one_tuple(&tuple, db, ver, diff));
1129*00b67f09SDavid van Moolenbroek 			INSIST(tuple == NULL);
1130*00b67f09SDavid van Moolenbroek 		}
1131*00b67f09SDavid van Moolenbroek 	}
1132*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
1133*00b67f09SDavid van Moolenbroek 		goto failure;
1134*00b67f09SDavid van Moolenbroek  success:
1135*00b67f09SDavid van Moolenbroek 	result = ISC_R_SUCCESS;
1136*00b67f09SDavid van Moolenbroek 
1137*00b67f09SDavid van Moolenbroek  failure:
1138*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
1139*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1140*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1141*00b67f09SDavid van Moolenbroek 	return (result);
1142*00b67f09SDavid van Moolenbroek }
1143*00b67f09SDavid van Moolenbroek 
1144*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_addnsec3sx(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,dns_ttl_t nsecttl,isc_boolean_t unsecure,dns_rdatatype_t type,dns_diff_t * diff)1145*00b67f09SDavid van Moolenbroek dns_nsec3_addnsec3sx(dns_db_t *db, dns_dbversion_t *version,
1146*00b67f09SDavid van Moolenbroek 		     dns_name_t *name, dns_ttl_t nsecttl,
1147*00b67f09SDavid van Moolenbroek 		     isc_boolean_t unsecure, dns_rdatatype_t type,
1148*00b67f09SDavid van Moolenbroek 		     dns_diff_t *diff)
1149*00b67f09SDavid van Moolenbroek {
1150*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1151*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3param_t nsec3param;
1152*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1153*00b67f09SDavid van Moolenbroek 	dns_rdataset_t prdataset;
1154*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1155*00b67f09SDavid van Moolenbroek 
1156*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1157*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&prdataset);
1158*00b67f09SDavid van Moolenbroek 
1159*00b67f09SDavid van Moolenbroek 	/*
1160*00b67f09SDavid van Moolenbroek 	 * Find the NSEC3 parameters for this zone.
1161*00b67f09SDavid van Moolenbroek 	 */
1162*00b67f09SDavid van Moolenbroek 	result = dns_db_getoriginnode(db, &node);
1163*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1164*00b67f09SDavid van Moolenbroek 		return (result);
1165*00b67f09SDavid van Moolenbroek 
1166*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version, type, 0, 0,
1167*00b67f09SDavid van Moolenbroek 				     &prdataset, NULL);
1168*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
1169*00b67f09SDavid van Moolenbroek 		goto failure;
1170*00b67f09SDavid van Moolenbroek 
1171*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version,
1172*00b67f09SDavid van Moolenbroek 				     dns_rdatatype_nsec3param, 0, 0,
1173*00b67f09SDavid van Moolenbroek 				     &rdataset, NULL);
1174*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1175*00b67f09SDavid van Moolenbroek 		goto try_private;
1176*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1177*00b67f09SDavid van Moolenbroek 		goto failure;
1178*00b67f09SDavid van Moolenbroek 
1179*00b67f09SDavid van Moolenbroek 	/*
1180*00b67f09SDavid van Moolenbroek 	 * Update each active NSEC3 chain.
1181*00b67f09SDavid van Moolenbroek 	 */
1182*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1183*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1184*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1185*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
1186*00b67f09SDavid van Moolenbroek 
1187*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
1188*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
1189*00b67f09SDavid van Moolenbroek 
1190*00b67f09SDavid van Moolenbroek 		if (nsec3param.flags != 0)
1191*00b67f09SDavid van Moolenbroek 			continue;
1192*00b67f09SDavid van Moolenbroek 
1193*00b67f09SDavid van Moolenbroek 		/*
1194*00b67f09SDavid van Moolenbroek 		 * We have a active chain.  Update it.
1195*00b67f09SDavid van Moolenbroek 		 */
1196*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param,
1197*00b67f09SDavid van Moolenbroek 					 nsecttl, unsecure, diff));
1198*00b67f09SDavid van Moolenbroek 	}
1199*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
1200*00b67f09SDavid van Moolenbroek 		goto failure;
1201*00b67f09SDavid van Moolenbroek 
1202*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1203*00b67f09SDavid van Moolenbroek 
1204*00b67f09SDavid van Moolenbroek  try_private:
1205*00b67f09SDavid van Moolenbroek 	if (!dns_rdataset_isassociated(&prdataset))
1206*00b67f09SDavid van Moolenbroek 		goto success;
1207*00b67f09SDavid van Moolenbroek 	/*
1208*00b67f09SDavid van Moolenbroek 	 * Update each active NSEC3 chain.
1209*00b67f09SDavid van Moolenbroek 	 */
1210*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&prdataset);
1211*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1212*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&prdataset)) {
1213*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata1 = DNS_RDATA_INIT;
1214*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata2 = DNS_RDATA_INIT;
1215*00b67f09SDavid van Moolenbroek 		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
1216*00b67f09SDavid van Moolenbroek 
1217*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&prdataset, &rdata1);
1218*00b67f09SDavid van Moolenbroek 		if (!dns_nsec3param_fromprivate(&rdata1, &rdata2,
1219*00b67f09SDavid van Moolenbroek 						buf, sizeof(buf)))
1220*00b67f09SDavid van Moolenbroek 			continue;
1221*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL));
1222*00b67f09SDavid van Moolenbroek 
1223*00b67f09SDavid van Moolenbroek 		if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
1224*00b67f09SDavid van Moolenbroek 			continue;
1225*00b67f09SDavid van Moolenbroek 		if (better_param(&prdataset, &rdata2))
1226*00b67f09SDavid van Moolenbroek 			continue;
1227*00b67f09SDavid van Moolenbroek 
1228*00b67f09SDavid van Moolenbroek 		/*
1229*00b67f09SDavid van Moolenbroek 		 * We have a active chain.  Update it.
1230*00b67f09SDavid van Moolenbroek 		 */
1231*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_addnsec3(db, version, name, &nsec3param,
1232*00b67f09SDavid van Moolenbroek 					 nsecttl, unsecure, diff));
1233*00b67f09SDavid van Moolenbroek 	}
1234*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1235*00b67f09SDavid van Moolenbroek  success:
1236*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1237*00b67f09SDavid van Moolenbroek  failure:
1238*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
1239*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1240*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&prdataset))
1241*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&prdataset);
1242*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1243*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1244*00b67f09SDavid van Moolenbroek 
1245*00b67f09SDavid van Moolenbroek 	return (result);
1246*00b67f09SDavid van Moolenbroek }
1247*00b67f09SDavid van Moolenbroek 
1248*00b67f09SDavid van Moolenbroek /*%
1249*00b67f09SDavid van Moolenbroek  * Determine whether any NSEC3 records that were associated with
1250*00b67f09SDavid van Moolenbroek  * 'name' should be deleted or if they should continue to exist.
1251*00b67f09SDavid van Moolenbroek  * ISC_TRUE indicates they should be deleted.
1252*00b67f09SDavid van Moolenbroek  * ISC_FALSE indicates they should be retained.
1253*00b67f09SDavid van Moolenbroek  */
1254*00b67f09SDavid van Moolenbroek static isc_result_t
deleteit(dns_db_t * db,dns_dbversion_t * ver,dns_name_t * name,isc_boolean_t * yesno)1255*00b67f09SDavid van Moolenbroek deleteit(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
1256*00b67f09SDavid van Moolenbroek 	 isc_boolean_t *yesno)
1257*00b67f09SDavid van Moolenbroek {
1258*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1259*00b67f09SDavid van Moolenbroek 	dns_fixedname_t foundname;
1260*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&foundname);
1261*00b67f09SDavid van Moolenbroek 
1262*00b67f09SDavid van Moolenbroek 	result = dns_db_find(db, name, ver, dns_rdatatype_any,
1263*00b67f09SDavid van Moolenbroek 			     DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
1264*00b67f09SDavid van Moolenbroek 			     (isc_stdtime_t) 0, NULL,
1265*00b67f09SDavid van Moolenbroek 			     dns_fixedname_name(&foundname),
1266*00b67f09SDavid van Moolenbroek 			     NULL, NULL);
1267*00b67f09SDavid van Moolenbroek 	if (result == DNS_R_EMPTYNAME || result == ISC_R_SUCCESS ||
1268*00b67f09SDavid van Moolenbroek 	    result ==  DNS_R_ZONECUT) {
1269*00b67f09SDavid van Moolenbroek 		*yesno = ISC_FALSE;
1270*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1271*00b67f09SDavid van Moolenbroek 	}
1272*00b67f09SDavid van Moolenbroek 	if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
1273*00b67f09SDavid van Moolenbroek 	    result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
1274*00b67f09SDavid van Moolenbroek 		*yesno = ISC_TRUE;
1275*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1276*00b67f09SDavid van Moolenbroek 	}
1277*00b67f09SDavid van Moolenbroek 	/*
1278*00b67f09SDavid van Moolenbroek 	 * Silence compiler.
1279*00b67f09SDavid van Moolenbroek 	 */
1280*00b67f09SDavid van Moolenbroek 	*yesno = ISC_TRUE;
1281*00b67f09SDavid van Moolenbroek 	return (result);
1282*00b67f09SDavid van Moolenbroek }
1283*00b67f09SDavid van Moolenbroek 
1284*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_delnsec3(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,const dns_rdata_nsec3param_t * nsec3param,dns_diff_t * diff)1285*00b67f09SDavid van Moolenbroek dns_nsec3_delnsec3(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
1286*00b67f09SDavid van Moolenbroek 		   const dns_rdata_nsec3param_t *nsec3param, dns_diff_t *diff)
1287*00b67f09SDavid van Moolenbroek {
1288*00b67f09SDavid van Moolenbroek 	dns_dbiterator_t *dbit = NULL;
1289*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1290*00b67f09SDavid van Moolenbroek 	dns_difftuple_t *tuple = NULL;
1291*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fixed;
1292*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fprev;
1293*00b67f09SDavid van Moolenbroek 	dns_hash_t hash;
1294*00b67f09SDavid van Moolenbroek 	dns_name_t *hashname;
1295*00b67f09SDavid van Moolenbroek 	dns_name_t *origin;
1296*00b67f09SDavid van Moolenbroek 	dns_name_t *prev;
1297*00b67f09SDavid van Moolenbroek 	dns_name_t empty;
1298*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3_t nsec3;
1299*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
1300*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1301*00b67f09SDavid van Moolenbroek 	int pass;
1302*00b67f09SDavid van Moolenbroek 	isc_boolean_t yesno;
1303*00b67f09SDavid van Moolenbroek 	isc_buffer_t buffer;
1304*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1305*00b67f09SDavid van Moolenbroek 	unsigned char *salt;
1306*00b67f09SDavid van Moolenbroek 	unsigned char nexthash[NSEC3_MAX_HASH_LENGTH];
1307*00b67f09SDavid van Moolenbroek 	unsigned char nsec3buf[DNS_NSEC3_BUFFERSIZE];
1308*00b67f09SDavid van Moolenbroek 	unsigned int iterations;
1309*00b67f09SDavid van Moolenbroek 	unsigned int labels;
1310*00b67f09SDavid van Moolenbroek 	size_t next_length;
1311*00b67f09SDavid van Moolenbroek 	unsigned int salt_length;
1312*00b67f09SDavid van Moolenbroek 
1313*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fixed);
1314*00b67f09SDavid van Moolenbroek 	hashname = dns_fixedname_name(&fixed);
1315*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fprev);
1316*00b67f09SDavid van Moolenbroek 	prev = dns_fixedname_name(&fprev);
1317*00b67f09SDavid van Moolenbroek 
1318*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1319*00b67f09SDavid van Moolenbroek 
1320*00b67f09SDavid van Moolenbroek 	origin = dns_db_origin(db);
1321*00b67f09SDavid van Moolenbroek 
1322*00b67f09SDavid van Moolenbroek 	/*
1323*00b67f09SDavid van Moolenbroek 	 * Chain parameters.
1324*00b67f09SDavid van Moolenbroek 	 */
1325*00b67f09SDavid van Moolenbroek 	hash = nsec3param->hash;
1326*00b67f09SDavid van Moolenbroek 	iterations = nsec3param->iterations;
1327*00b67f09SDavid van Moolenbroek 	salt_length = nsec3param->salt_length;
1328*00b67f09SDavid van Moolenbroek 	salt = nsec3param->salt;
1329*00b67f09SDavid van Moolenbroek 
1330*00b67f09SDavid van Moolenbroek 	/*
1331*00b67f09SDavid van Moolenbroek 	 * If this is the first NSEC3 in the chain nexthash will
1332*00b67f09SDavid van Moolenbroek 	 * remain pointing to itself.
1333*00b67f09SDavid van Moolenbroek 	 */
1334*00b67f09SDavid van Moolenbroek 	next_length = sizeof(nexthash);
1335*00b67f09SDavid van Moolenbroek 	CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
1336*00b67f09SDavid van Moolenbroek 				 name, origin, hash, iterations,
1337*00b67f09SDavid van Moolenbroek 				 salt, salt_length));
1338*00b67f09SDavid van Moolenbroek 
1339*00b67f09SDavid van Moolenbroek 	CHECK(dns_db_createiterator(db, DNS_DB_NSEC3ONLY, &dbit));
1340*00b67f09SDavid van Moolenbroek 
1341*00b67f09SDavid van Moolenbroek 	result = dns_dbiterator_seek(dbit, hashname);
1342*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1343*00b67f09SDavid van Moolenbroek 		goto success;
1344*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1345*00b67f09SDavid van Moolenbroek 		goto failure;
1346*00b67f09SDavid van Moolenbroek 
1347*00b67f09SDavid van Moolenbroek 	CHECK(dns_dbiterator_current(dbit, &node, NULL));
1348*00b67f09SDavid van Moolenbroek 	CHECK(dns_dbiterator_pause(dbit));
1349*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version, dns_rdatatype_nsec3,
1350*00b67f09SDavid van Moolenbroek 				     0, (isc_stdtime_t) 0, &rdataset, NULL);
1351*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1352*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1353*00b67f09SDavid van Moolenbroek 		goto success;
1354*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1355*00b67f09SDavid van Moolenbroek 		goto failure;
1356*00b67f09SDavid van Moolenbroek 
1357*00b67f09SDavid van Moolenbroek 	/*
1358*00b67f09SDavid van Moolenbroek 	 * If we find a existing NSEC3 for this chain then save the
1359*00b67f09SDavid van Moolenbroek 	 * next field.
1360*00b67f09SDavid van Moolenbroek 	 */
1361*00b67f09SDavid van Moolenbroek 	result = find_nsec3(&nsec3, &rdataset, nsec3param);
1362*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
1363*00b67f09SDavid van Moolenbroek 		next_length = nsec3.next_length;
1364*00b67f09SDavid van Moolenbroek 		INSIST(next_length <= sizeof(nexthash));
1365*00b67f09SDavid van Moolenbroek 		memmove(nexthash, nsec3.next, next_length);
1366*00b67f09SDavid van Moolenbroek 	}
1367*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1368*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1369*00b67f09SDavid van Moolenbroek 		goto success;
1370*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1371*00b67f09SDavid van Moolenbroek 		goto failure;
1372*00b67f09SDavid van Moolenbroek 
1373*00b67f09SDavid van Moolenbroek 	/*
1374*00b67f09SDavid van Moolenbroek 	 * Find the previous NSEC3 and update it.
1375*00b67f09SDavid van Moolenbroek 	 */
1376*00b67f09SDavid van Moolenbroek 	pass = 0;
1377*00b67f09SDavid van Moolenbroek 	do {
1378*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_prev(dbit);
1379*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE) {
1380*00b67f09SDavid van Moolenbroek 			pass++;
1381*00b67f09SDavid van Moolenbroek 			CHECK(dns_dbiterator_last(dbit));
1382*00b67f09SDavid van Moolenbroek 		}
1383*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_current(dbit, &node, prev));
1384*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_pause(dbit));
1385*00b67f09SDavid van Moolenbroek 		result = dns_db_findrdataset(db, node, version,
1386*00b67f09SDavid van Moolenbroek 					     dns_rdatatype_nsec3, 0,
1387*00b67f09SDavid van Moolenbroek 					     (isc_stdtime_t) 0, &rdataset,
1388*00b67f09SDavid van Moolenbroek 					     NULL);
1389*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1390*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1391*00b67f09SDavid van Moolenbroek 			continue;
1392*00b67f09SDavid van Moolenbroek 		result = find_nsec3(&nsec3, &rdataset, nsec3param);
1393*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE) {
1394*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
1395*00b67f09SDavid van Moolenbroek 			continue;
1396*00b67f09SDavid van Moolenbroek 		}
1397*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1398*00b67f09SDavid van Moolenbroek 			goto failure;
1399*00b67f09SDavid van Moolenbroek 
1400*00b67f09SDavid van Moolenbroek 		/*
1401*00b67f09SDavid van Moolenbroek 		 * Delete the old previous NSEC3.
1402*00b67f09SDavid van Moolenbroek 		 */
1403*00b67f09SDavid van Moolenbroek 		CHECK(delete(db, version, prev, nsec3param, diff));
1404*00b67f09SDavid van Moolenbroek 
1405*00b67f09SDavid van Moolenbroek 		/*
1406*00b67f09SDavid van Moolenbroek 		 * Fixup the previous NSEC3.
1407*00b67f09SDavid van Moolenbroek 		 */
1408*00b67f09SDavid van Moolenbroek 		nsec3.next = nexthash;
1409*00b67f09SDavid van Moolenbroek 		nsec3.next_length = (unsigned char)next_length;
1410*00b67f09SDavid van Moolenbroek 		if (CREATE(nsec3param->flags))
1411*00b67f09SDavid van Moolenbroek 			nsec3.flags = nsec3param->flags & DNS_NSEC3FLAG_OPTOUT;
1412*00b67f09SDavid van Moolenbroek 		isc_buffer_init(&buffer, nsec3buf, sizeof(nsec3buf));
1413*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
1414*00b67f09SDavid van Moolenbroek 					   dns_rdatatype_nsec3, &nsec3,
1415*00b67f09SDavid van Moolenbroek 					   &buffer));
1416*00b67f09SDavid van Moolenbroek 		CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, prev,
1417*00b67f09SDavid van Moolenbroek 					   rdataset.ttl, &rdata, &tuple));
1418*00b67f09SDavid van Moolenbroek 		CHECK(do_one_tuple(&tuple, db, version, diff));
1419*00b67f09SDavid van Moolenbroek 		dns_rdata_reset(&rdata);
1420*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1421*00b67f09SDavid van Moolenbroek 		break;
1422*00b67f09SDavid van Moolenbroek 	} while (pass < 2);
1423*00b67f09SDavid van Moolenbroek 
1424*00b67f09SDavid van Moolenbroek 	/*
1425*00b67f09SDavid van Moolenbroek 	 * Delete the old NSEC3 and record the change.
1426*00b67f09SDavid van Moolenbroek 	 */
1427*00b67f09SDavid van Moolenbroek 	CHECK(delete(db, version, hashname, nsec3param, diff));
1428*00b67f09SDavid van Moolenbroek 
1429*00b67f09SDavid van Moolenbroek 	/*
1430*00b67f09SDavid van Moolenbroek 	 *  Delete NSEC3 records for now non active nodes.
1431*00b67f09SDavid van Moolenbroek 	 */
1432*00b67f09SDavid van Moolenbroek 	dns_name_init(&empty, NULL);
1433*00b67f09SDavid van Moolenbroek 	dns_name_clone(name, &empty);
1434*00b67f09SDavid van Moolenbroek 	do {
1435*00b67f09SDavid van Moolenbroek 		labels = dns_name_countlabels(&empty) - 1;
1436*00b67f09SDavid van Moolenbroek 		if (labels <= dns_name_countlabels(origin))
1437*00b67f09SDavid van Moolenbroek 			break;
1438*00b67f09SDavid van Moolenbroek 		dns_name_getlabelsequence(&empty, 1, labels, &empty);
1439*00b67f09SDavid van Moolenbroek 		CHECK(deleteit(db, version, &empty, &yesno));
1440*00b67f09SDavid van Moolenbroek 		if (!yesno)
1441*00b67f09SDavid van Moolenbroek 			break;
1442*00b67f09SDavid van Moolenbroek 
1443*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_hashname(&fixed, nexthash, &next_length,
1444*00b67f09SDavid van Moolenbroek 					 &empty, origin, hash, iterations,
1445*00b67f09SDavid van Moolenbroek 					 salt, salt_length));
1446*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_seek(dbit, hashname);
1447*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOTFOUND)
1448*00b67f09SDavid van Moolenbroek 			goto success;
1449*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1450*00b67f09SDavid van Moolenbroek 			goto failure;
1451*00b67f09SDavid van Moolenbroek 
1452*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_current(dbit, &node, NULL));
1453*00b67f09SDavid van Moolenbroek 		CHECK(dns_dbiterator_pause(dbit));
1454*00b67f09SDavid van Moolenbroek 		result = dns_db_findrdataset(db, node, version,
1455*00b67f09SDavid van Moolenbroek 					     dns_rdatatype_nsec3, 0,
1456*00b67f09SDavid van Moolenbroek 					     (isc_stdtime_t) 0, &rdataset,
1457*00b67f09SDavid van Moolenbroek 					     NULL);
1458*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1459*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOTFOUND)
1460*00b67f09SDavid van Moolenbroek 			goto success;
1461*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1462*00b67f09SDavid van Moolenbroek 			goto failure;
1463*00b67f09SDavid van Moolenbroek 
1464*00b67f09SDavid van Moolenbroek 		result = find_nsec3(&nsec3, &rdataset, nsec3param);
1465*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
1466*00b67f09SDavid van Moolenbroek 			next_length = nsec3.next_length;
1467*00b67f09SDavid van Moolenbroek 			INSIST(next_length <= sizeof(nexthash));
1468*00b67f09SDavid van Moolenbroek 			memmove(nexthash, nsec3.next, next_length);
1469*00b67f09SDavid van Moolenbroek 		}
1470*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1471*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE)
1472*00b67f09SDavid van Moolenbroek 			goto success;
1473*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1474*00b67f09SDavid van Moolenbroek 			goto failure;
1475*00b67f09SDavid van Moolenbroek 
1476*00b67f09SDavid van Moolenbroek 		pass = 0;
1477*00b67f09SDavid van Moolenbroek 		do {
1478*00b67f09SDavid van Moolenbroek 			result = dns_dbiterator_prev(dbit);
1479*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOMORE) {
1480*00b67f09SDavid van Moolenbroek 				pass++;
1481*00b67f09SDavid van Moolenbroek 				CHECK(dns_dbiterator_last(dbit));
1482*00b67f09SDavid van Moolenbroek 			}
1483*00b67f09SDavid van Moolenbroek 			CHECK(dns_dbiterator_current(dbit, &node, prev));
1484*00b67f09SDavid van Moolenbroek 			CHECK(dns_dbiterator_pause(dbit));
1485*00b67f09SDavid van Moolenbroek 			result = dns_db_findrdataset(db, node, version,
1486*00b67f09SDavid van Moolenbroek 						     dns_rdatatype_nsec3, 0,
1487*00b67f09SDavid van Moolenbroek 						     (isc_stdtime_t) 0,
1488*00b67f09SDavid van Moolenbroek 						     &rdataset, NULL);
1489*00b67f09SDavid van Moolenbroek 			dns_db_detachnode(db, &node);
1490*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
1491*00b67f09SDavid van Moolenbroek 				continue;
1492*00b67f09SDavid van Moolenbroek 			result = find_nsec3(&nsec3, &rdataset, nsec3param);
1493*00b67f09SDavid van Moolenbroek 			if (result == ISC_R_NOMORE) {
1494*00b67f09SDavid van Moolenbroek 				dns_rdataset_disassociate(&rdataset);
1495*00b67f09SDavid van Moolenbroek 				continue;
1496*00b67f09SDavid van Moolenbroek 			}
1497*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
1498*00b67f09SDavid van Moolenbroek 				goto failure;
1499*00b67f09SDavid van Moolenbroek 
1500*00b67f09SDavid van Moolenbroek 			/*
1501*00b67f09SDavid van Moolenbroek 			 * Delete the old previous NSEC3.
1502*00b67f09SDavid van Moolenbroek 			 */
1503*00b67f09SDavid van Moolenbroek 			CHECK(delete(db, version, prev, nsec3param, diff));
1504*00b67f09SDavid van Moolenbroek 
1505*00b67f09SDavid van Moolenbroek 			/*
1506*00b67f09SDavid van Moolenbroek 			 * Fixup the previous NSEC3.
1507*00b67f09SDavid van Moolenbroek 			 */
1508*00b67f09SDavid van Moolenbroek 			nsec3.next = nexthash;
1509*00b67f09SDavid van Moolenbroek 			nsec3.next_length = (unsigned char)next_length;
1510*00b67f09SDavid van Moolenbroek 			isc_buffer_init(&buffer, nsec3buf,
1511*00b67f09SDavid van Moolenbroek 					sizeof(nsec3buf));
1512*00b67f09SDavid van Moolenbroek 			CHECK(dns_rdata_fromstruct(&rdata, rdataset.rdclass,
1513*00b67f09SDavid van Moolenbroek 						   dns_rdatatype_nsec3, &nsec3,
1514*00b67f09SDavid van Moolenbroek 						   &buffer));
1515*00b67f09SDavid van Moolenbroek 			CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
1516*00b67f09SDavid van Moolenbroek 						   prev, rdataset.ttl, &rdata,
1517*00b67f09SDavid van Moolenbroek 						   &tuple));
1518*00b67f09SDavid van Moolenbroek 			CHECK(do_one_tuple(&tuple, db, version, diff));
1519*00b67f09SDavid van Moolenbroek 			dns_rdata_reset(&rdata);
1520*00b67f09SDavid van Moolenbroek 			dns_rdataset_disassociate(&rdataset);
1521*00b67f09SDavid van Moolenbroek 			break;
1522*00b67f09SDavid van Moolenbroek 		} while (pass < 2);
1523*00b67f09SDavid van Moolenbroek 
1524*00b67f09SDavid van Moolenbroek 		INSIST(pass < 2);
1525*00b67f09SDavid van Moolenbroek 
1526*00b67f09SDavid van Moolenbroek 		/*
1527*00b67f09SDavid van Moolenbroek 		 * Delete the old NSEC3 and record the change.
1528*00b67f09SDavid van Moolenbroek 		 */
1529*00b67f09SDavid van Moolenbroek 		CHECK(delete(db, version, hashname, nsec3param, diff));
1530*00b67f09SDavid van Moolenbroek 	} while (1);
1531*00b67f09SDavid van Moolenbroek 
1532*00b67f09SDavid van Moolenbroek  success:
1533*00b67f09SDavid van Moolenbroek 	result = ISC_R_SUCCESS;
1534*00b67f09SDavid van Moolenbroek 
1535*00b67f09SDavid van Moolenbroek  failure:
1536*00b67f09SDavid van Moolenbroek 	if (dbit != NULL)
1537*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&dbit);
1538*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
1539*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1540*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1541*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1542*00b67f09SDavid van Moolenbroek 	return (result);
1543*00b67f09SDavid van Moolenbroek }
1544*00b67f09SDavid van Moolenbroek 
1545*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_delnsec3s(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,dns_diff_t * diff)1546*00b67f09SDavid van Moolenbroek dns_nsec3_delnsec3s(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
1547*00b67f09SDavid van Moolenbroek 		    dns_diff_t *diff)
1548*00b67f09SDavid van Moolenbroek {
1549*00b67f09SDavid van Moolenbroek 	return (dns_nsec3_delnsec3sx(db, version, name, 0, diff));
1550*00b67f09SDavid van Moolenbroek }
1551*00b67f09SDavid van Moolenbroek 
1552*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_delnsec3sx(dns_db_t * db,dns_dbversion_t * version,dns_name_t * name,dns_rdatatype_t privatetype,dns_diff_t * diff)1553*00b67f09SDavid van Moolenbroek dns_nsec3_delnsec3sx(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
1554*00b67f09SDavid van Moolenbroek 		     dns_rdatatype_t privatetype, dns_diff_t *diff)
1555*00b67f09SDavid van Moolenbroek {
1556*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1557*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3param_t nsec3param;
1558*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1559*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1560*00b67f09SDavid van Moolenbroek 
1561*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1562*00b67f09SDavid van Moolenbroek 
1563*00b67f09SDavid van Moolenbroek 	/*
1564*00b67f09SDavid van Moolenbroek 	 * Find the NSEC3 parameters for this zone.
1565*00b67f09SDavid van Moolenbroek 	 */
1566*00b67f09SDavid van Moolenbroek 	result = dns_db_getoriginnode(db, &node);
1567*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1568*00b67f09SDavid van Moolenbroek 		return (result);
1569*00b67f09SDavid van Moolenbroek 
1570*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version,
1571*00b67f09SDavid van Moolenbroek 				     dns_rdatatype_nsec3param, 0, 0,
1572*00b67f09SDavid van Moolenbroek 				     &rdataset, NULL);
1573*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1574*00b67f09SDavid van Moolenbroek 		goto try_private;
1575*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1576*00b67f09SDavid van Moolenbroek 		goto failure;
1577*00b67f09SDavid van Moolenbroek 
1578*00b67f09SDavid van Moolenbroek 	/*
1579*00b67f09SDavid van Moolenbroek 	 * Update each active NSEC3 chain.
1580*00b67f09SDavid van Moolenbroek 	 */
1581*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1582*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1583*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1584*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
1585*00b67f09SDavid van Moolenbroek 
1586*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
1587*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
1588*00b67f09SDavid van Moolenbroek 
1589*00b67f09SDavid van Moolenbroek 		if (nsec3param.flags != 0)
1590*00b67f09SDavid van Moolenbroek 			continue;
1591*00b67f09SDavid van Moolenbroek 		/*
1592*00b67f09SDavid van Moolenbroek 		 * We have a active chain.  Update it.
1593*00b67f09SDavid van Moolenbroek 		 */
1594*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff));
1595*00b67f09SDavid van Moolenbroek 	}
1596*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1597*00b67f09SDavid van Moolenbroek 
1598*00b67f09SDavid van Moolenbroek  try_private:
1599*00b67f09SDavid van Moolenbroek 	if (privatetype == 0)
1600*00b67f09SDavid van Moolenbroek 		goto success;
1601*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version, privatetype, 0, 0,
1602*00b67f09SDavid van Moolenbroek 				     &rdataset, NULL);
1603*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1604*00b67f09SDavid van Moolenbroek 		goto success;
1605*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1606*00b67f09SDavid van Moolenbroek 		goto failure;
1607*00b67f09SDavid van Moolenbroek 
1608*00b67f09SDavid van Moolenbroek 	/*
1609*00b67f09SDavid van Moolenbroek 	 * Update each NSEC3 chain being built.
1610*00b67f09SDavid van Moolenbroek 	 */
1611*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1612*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1613*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1614*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata1 = DNS_RDATA_INIT;
1615*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata2 = DNS_RDATA_INIT;
1616*00b67f09SDavid van Moolenbroek 		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
1617*00b67f09SDavid van Moolenbroek 
1618*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata1);
1619*00b67f09SDavid van Moolenbroek 		if (!dns_nsec3param_fromprivate(&rdata1,  &rdata2,
1620*00b67f09SDavid van Moolenbroek 						buf, sizeof(buf)))
1621*00b67f09SDavid van Moolenbroek 			continue;
1622*00b67f09SDavid van Moolenbroek 		CHECK(dns_rdata_tostruct(&rdata2, &nsec3param, NULL));
1623*00b67f09SDavid van Moolenbroek 
1624*00b67f09SDavid van Moolenbroek 		if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
1625*00b67f09SDavid van Moolenbroek 			continue;
1626*00b67f09SDavid van Moolenbroek 		if (better_param(&rdataset, &rdata2))
1627*00b67f09SDavid van Moolenbroek 			continue;
1628*00b67f09SDavid van Moolenbroek 
1629*00b67f09SDavid van Moolenbroek 		/*
1630*00b67f09SDavid van Moolenbroek 		 * We have a active chain.  Update it.
1631*00b67f09SDavid van Moolenbroek 		 */
1632*00b67f09SDavid van Moolenbroek 		CHECK(dns_nsec3_delnsec3(db, version, name, &nsec3param, diff));
1633*00b67f09SDavid van Moolenbroek 	}
1634*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1635*00b67f09SDavid van Moolenbroek  success:
1636*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1637*00b67f09SDavid van Moolenbroek 
1638*00b67f09SDavid van Moolenbroek  failure:
1639*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
1640*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1641*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1642*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1643*00b67f09SDavid van Moolenbroek 
1644*00b67f09SDavid van Moolenbroek 	return (result);
1645*00b67f09SDavid van Moolenbroek }
1646*00b67f09SDavid van Moolenbroek 
1647*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_active(dns_db_t * db,dns_dbversion_t * version,isc_boolean_t complete,isc_boolean_t * answer)1648*00b67f09SDavid van Moolenbroek dns_nsec3_active(dns_db_t *db, dns_dbversion_t *version,
1649*00b67f09SDavid van Moolenbroek 		 isc_boolean_t complete, isc_boolean_t *answer)
1650*00b67f09SDavid van Moolenbroek {
1651*00b67f09SDavid van Moolenbroek 	return (dns_nsec3_activex(db, version, complete, 0, answer));
1652*00b67f09SDavid van Moolenbroek }
1653*00b67f09SDavid van Moolenbroek 
1654*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_activex(dns_db_t * db,dns_dbversion_t * version,isc_boolean_t complete,dns_rdatatype_t privatetype,isc_boolean_t * answer)1655*00b67f09SDavid van Moolenbroek dns_nsec3_activex(dns_db_t *db, dns_dbversion_t *version,
1656*00b67f09SDavid van Moolenbroek 		  isc_boolean_t complete, dns_rdatatype_t privatetype,
1657*00b67f09SDavid van Moolenbroek 		  isc_boolean_t *answer)
1658*00b67f09SDavid van Moolenbroek {
1659*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1660*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1661*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3param_t nsec3param;
1662*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1663*00b67f09SDavid van Moolenbroek 
1664*00b67f09SDavid van Moolenbroek 	REQUIRE(answer != NULL);
1665*00b67f09SDavid van Moolenbroek 
1666*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1667*00b67f09SDavid van Moolenbroek 
1668*00b67f09SDavid van Moolenbroek 	result = dns_db_getoriginnode(db, &node);
1669*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1670*00b67f09SDavid van Moolenbroek 		return (result);
1671*00b67f09SDavid van Moolenbroek 
1672*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version,
1673*00b67f09SDavid van Moolenbroek 				     dns_rdatatype_nsec3param, 0, 0,
1674*00b67f09SDavid van Moolenbroek 				     &rdataset, NULL);
1675*00b67f09SDavid van Moolenbroek 
1676*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
1677*00b67f09SDavid van Moolenbroek 		goto try_private;
1678*00b67f09SDavid van Moolenbroek 
1679*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1680*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1681*00b67f09SDavid van Moolenbroek 		return (result);
1682*00b67f09SDavid van Moolenbroek 	}
1683*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1684*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1685*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1686*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
1687*00b67f09SDavid van Moolenbroek 
1688*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
1689*00b67f09SDavid van Moolenbroek 		result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
1690*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1691*00b67f09SDavid van Moolenbroek 
1692*00b67f09SDavid van Moolenbroek 		if (nsec3param.flags == 0)
1693*00b67f09SDavid van Moolenbroek 			break;
1694*00b67f09SDavid van Moolenbroek 	}
1695*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1696*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
1697*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1698*00b67f09SDavid van Moolenbroek 		*answer = ISC_TRUE;
1699*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1700*00b67f09SDavid van Moolenbroek 	}
1701*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1702*00b67f09SDavid van Moolenbroek 		*answer = ISC_FALSE;
1703*00b67f09SDavid van Moolenbroek 
1704*00b67f09SDavid van Moolenbroek  try_private:
1705*00b67f09SDavid van Moolenbroek 	if (privatetype == 0 || complete) {
1706*00b67f09SDavid van Moolenbroek 		*answer = ISC_FALSE;
1707*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1708*00b67f09SDavid van Moolenbroek 	}
1709*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version, privatetype, 0, 0,
1710*00b67f09SDavid van Moolenbroek 				     &rdataset, NULL);
1711*00b67f09SDavid van Moolenbroek 
1712*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1713*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
1714*00b67f09SDavid van Moolenbroek 		*answer = ISC_FALSE;
1715*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1716*00b67f09SDavid van Moolenbroek 	}
1717*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1718*00b67f09SDavid van Moolenbroek 		return (result);
1719*00b67f09SDavid van Moolenbroek 
1720*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1721*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1722*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1723*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata1 = DNS_RDATA_INIT;
1724*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata2 = DNS_RDATA_INIT;
1725*00b67f09SDavid van Moolenbroek 		unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
1726*00b67f09SDavid van Moolenbroek 
1727*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata1);
1728*00b67f09SDavid van Moolenbroek 		if (!dns_nsec3param_fromprivate(&rdata1, &rdata2,
1729*00b67f09SDavid van Moolenbroek 						buf, sizeof(buf)))
1730*00b67f09SDavid van Moolenbroek 			continue;
1731*00b67f09SDavid van Moolenbroek 		result = dns_rdata_tostruct(&rdata2, &nsec3param, NULL);
1732*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1733*00b67f09SDavid van Moolenbroek 
1734*00b67f09SDavid van Moolenbroek 		if (!complete && CREATE(nsec3param.flags))
1735*00b67f09SDavid van Moolenbroek 			break;
1736*00b67f09SDavid van Moolenbroek 	}
1737*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
1738*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS) {
1739*00b67f09SDavid van Moolenbroek 		*answer = ISC_TRUE;
1740*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1741*00b67f09SDavid van Moolenbroek 	}
1742*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE) {
1743*00b67f09SDavid van Moolenbroek 		*answer = ISC_FALSE;
1744*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1745*00b67f09SDavid van Moolenbroek 	}
1746*00b67f09SDavid van Moolenbroek 
1747*00b67f09SDavid van Moolenbroek 	return (result);
1748*00b67f09SDavid van Moolenbroek }
1749*00b67f09SDavid van Moolenbroek 
1750*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_maxiterations(dns_db_t * db,dns_dbversion_t * version,isc_mem_t * mctx,unsigned int * iterationsp)1751*00b67f09SDavid van Moolenbroek dns_nsec3_maxiterations(dns_db_t *db, dns_dbversion_t *version,
1752*00b67f09SDavid van Moolenbroek 			isc_mem_t *mctx, unsigned int *iterationsp)
1753*00b67f09SDavid van Moolenbroek {
1754*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1755*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
1756*00b67f09SDavid van Moolenbroek 	dst_key_t *key = NULL;
1757*00b67f09SDavid van Moolenbroek 	isc_buffer_t buffer;
1758*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1759*00b67f09SDavid van Moolenbroek 	unsigned int bits, minbits = 4096;
1760*00b67f09SDavid van Moolenbroek 
1761*00b67f09SDavid van Moolenbroek 	result = dns_db_getoriginnode(db, &node);
1762*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1763*00b67f09SDavid van Moolenbroek 		return (result);
1764*00b67f09SDavid van Moolenbroek 
1765*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
1766*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
1767*00b67f09SDavid van Moolenbroek 				     0, 0, &rdataset, NULL);
1768*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
1769*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
1770*00b67f09SDavid van Moolenbroek 		*iterationsp = 0;
1771*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1772*00b67f09SDavid van Moolenbroek 	}
1773*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1774*00b67f09SDavid van Moolenbroek 		goto failure;
1775*00b67f09SDavid van Moolenbroek 
1776*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
1777*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1778*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
1779*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
1780*00b67f09SDavid van Moolenbroek 
1781*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
1782*00b67f09SDavid van Moolenbroek 		isc_buffer_init(&buffer, rdata.data, rdata.length);
1783*00b67f09SDavid van Moolenbroek 		isc_buffer_add(&buffer, rdata.length);
1784*00b67f09SDavid van Moolenbroek 		CHECK(dst_key_fromdns(dns_db_origin(db), rdataset.rdclass,
1785*00b67f09SDavid van Moolenbroek 				      &buffer, mctx, &key));
1786*00b67f09SDavid van Moolenbroek 		bits = dst_key_size(key);
1787*00b67f09SDavid van Moolenbroek 		dst_key_free(&key);
1788*00b67f09SDavid van Moolenbroek 		if (minbits > bits)
1789*00b67f09SDavid van Moolenbroek 			minbits = bits;
1790*00b67f09SDavid van Moolenbroek 	}
1791*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
1792*00b67f09SDavid van Moolenbroek 		goto failure;
1793*00b67f09SDavid van Moolenbroek 
1794*00b67f09SDavid van Moolenbroek 	if (minbits <= 1024)
1795*00b67f09SDavid van Moolenbroek 		*iterationsp = 150;
1796*00b67f09SDavid van Moolenbroek 	else if (minbits <= 2048)
1797*00b67f09SDavid van Moolenbroek 		*iterationsp = 500;
1798*00b67f09SDavid van Moolenbroek 	else
1799*00b67f09SDavid van Moolenbroek 		*iterationsp = 2500;
1800*00b67f09SDavid van Moolenbroek 	result = ISC_R_SUCCESS;
1801*00b67f09SDavid van Moolenbroek 
1802*00b67f09SDavid van Moolenbroek  failure:
1803*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
1804*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1805*00b67f09SDavid van Moolenbroek 	return (result);
1806*00b67f09SDavid van Moolenbroek }
1807*00b67f09SDavid van Moolenbroek 
1808*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec3_noexistnodata(dns_rdatatype_t type,dns_name_t * name,dns_name_t * nsec3name,dns_rdataset_t * nsec3set,dns_name_t * zonename,isc_boolean_t * exists,isc_boolean_t * data,isc_boolean_t * optout,isc_boolean_t * unknown,isc_boolean_t * setclosest,isc_boolean_t * setnearest,dns_name_t * closest,dns_name_t * nearest,dns_nseclog_t logit,void * arg)1809*00b67f09SDavid van Moolenbroek dns_nsec3_noexistnodata(dns_rdatatype_t type, dns_name_t* name,
1810*00b67f09SDavid van Moolenbroek 			dns_name_t *nsec3name, dns_rdataset_t *nsec3set,
1811*00b67f09SDavid van Moolenbroek 			dns_name_t *zonename, isc_boolean_t *exists,
1812*00b67f09SDavid van Moolenbroek 			isc_boolean_t *data, isc_boolean_t *optout,
1813*00b67f09SDavid van Moolenbroek 			isc_boolean_t *unknown, isc_boolean_t *setclosest,
1814*00b67f09SDavid van Moolenbroek 			isc_boolean_t *setnearest, dns_name_t *closest,
1815*00b67f09SDavid van Moolenbroek 			dns_name_t *nearest, dns_nseclog_t logit, void *arg)
1816*00b67f09SDavid van Moolenbroek {
1817*00b67f09SDavid van Moolenbroek 	char namebuf[DNS_NAME_FORMATSIZE];
1818*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fzone;
1819*00b67f09SDavid van Moolenbroek 	dns_fixedname_t qfixed;
1820*00b67f09SDavid van Moolenbroek 	dns_label_t hashlabel;
1821*00b67f09SDavid van Moolenbroek 	dns_name_t *qname;
1822*00b67f09SDavid van Moolenbroek 	dns_name_t *zone;
1823*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec3_t nsec3;
1824*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
1825*00b67f09SDavid van Moolenbroek 	int order;
1826*00b67f09SDavid van Moolenbroek 	int scope;
1827*00b67f09SDavid van Moolenbroek 	isc_boolean_t atparent;
1828*00b67f09SDavid van Moolenbroek 	isc_boolean_t first;
1829*00b67f09SDavid van Moolenbroek 	isc_boolean_t ns;
1830*00b67f09SDavid van Moolenbroek 	isc_boolean_t soa;
1831*00b67f09SDavid van Moolenbroek 	isc_buffer_t buffer;
1832*00b67f09SDavid van Moolenbroek 	isc_result_t answer = ISC_R_IGNORE;
1833*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1834*00b67f09SDavid van Moolenbroek 	unsigned char hash[NSEC3_MAX_HASH_LENGTH];
1835*00b67f09SDavid van Moolenbroek 	unsigned char owner[NSEC3_MAX_HASH_LENGTH];
1836*00b67f09SDavid van Moolenbroek 	unsigned int length;
1837*00b67f09SDavid van Moolenbroek 	unsigned int qlabels;
1838*00b67f09SDavid van Moolenbroek 	unsigned int zlabels;
1839*00b67f09SDavid van Moolenbroek 
1840*00b67f09SDavid van Moolenbroek 	REQUIRE((exists == NULL && data == NULL) ||
1841*00b67f09SDavid van Moolenbroek 		(exists != NULL && data != NULL));
1842*00b67f09SDavid van Moolenbroek 	REQUIRE(nsec3set != NULL && nsec3set->type == dns_rdatatype_nsec3);
1843*00b67f09SDavid van Moolenbroek 	REQUIRE((setclosest == NULL && closest == NULL) ||
1844*00b67f09SDavid van Moolenbroek 		(setclosest != NULL && closest != NULL));
1845*00b67f09SDavid van Moolenbroek 	REQUIRE((setnearest == NULL && nearest == NULL) ||
1846*00b67f09SDavid van Moolenbroek 		(setnearest != NULL && nearest != NULL));
1847*00b67f09SDavid van Moolenbroek 
1848*00b67f09SDavid van Moolenbroek 	result = dns_rdataset_first(nsec3set);
1849*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
1850*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3), "failure processing NSEC3 set");
1851*00b67f09SDavid van Moolenbroek 		return (result);
1852*00b67f09SDavid van Moolenbroek 	}
1853*00b67f09SDavid van Moolenbroek 
1854*00b67f09SDavid van Moolenbroek 	dns_rdataset_current(nsec3set, &rdata);
1855*00b67f09SDavid van Moolenbroek 
1856*00b67f09SDavid van Moolenbroek 	result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
1857*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1858*00b67f09SDavid van Moolenbroek 		return (result);
1859*00b67f09SDavid van Moolenbroek 
1860*00b67f09SDavid van Moolenbroek 	(*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC3");
1861*00b67f09SDavid van Moolenbroek 
1862*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fzone);
1863*00b67f09SDavid van Moolenbroek 	zone = dns_fixedname_name(&fzone);
1864*00b67f09SDavid van Moolenbroek 	zlabels = dns_name_countlabels(nsec3name);
1865*00b67f09SDavid van Moolenbroek 
1866*00b67f09SDavid van Moolenbroek 	/*
1867*00b67f09SDavid van Moolenbroek 	 * NSEC3 records must have two or more labels to be valid.
1868*00b67f09SDavid van Moolenbroek 	 */
1869*00b67f09SDavid van Moolenbroek 	if (zlabels < 2)
1870*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
1871*00b67f09SDavid van Moolenbroek 
1872*00b67f09SDavid van Moolenbroek 	/*
1873*00b67f09SDavid van Moolenbroek 	 * Strip off the NSEC3 hash to get the zone.
1874*00b67f09SDavid van Moolenbroek 	 */
1875*00b67f09SDavid van Moolenbroek 	zlabels--;
1876*00b67f09SDavid van Moolenbroek 	dns_name_split(nsec3name, zlabels, NULL, zone);
1877*00b67f09SDavid van Moolenbroek 
1878*00b67f09SDavid van Moolenbroek 	/*
1879*00b67f09SDavid van Moolenbroek 	 * If not below the zone name we can ignore this record.
1880*00b67f09SDavid van Moolenbroek 	 */
1881*00b67f09SDavid van Moolenbroek 	if (!dns_name_issubdomain(name, zone))
1882*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
1883*00b67f09SDavid van Moolenbroek 
1884*00b67f09SDavid van Moolenbroek 	/*
1885*00b67f09SDavid van Moolenbroek 	 * Is this zone the same or deeper than the current zone?
1886*00b67f09SDavid van Moolenbroek 	 */
1887*00b67f09SDavid van Moolenbroek 	if (dns_name_countlabels(zonename) == 0 ||
1888*00b67f09SDavid van Moolenbroek 	    dns_name_issubdomain(zone, zonename))
1889*00b67f09SDavid van Moolenbroek 		dns_name_copy(zone, zonename, NULL);
1890*00b67f09SDavid van Moolenbroek 
1891*00b67f09SDavid van Moolenbroek 	if (!dns_name_equal(zone, zonename))
1892*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
1893*00b67f09SDavid van Moolenbroek 
1894*00b67f09SDavid van Moolenbroek 	/*
1895*00b67f09SDavid van Moolenbroek 	 * Are we only looking for the most enclosing zone?
1896*00b67f09SDavid van Moolenbroek 	 */
1897*00b67f09SDavid van Moolenbroek 	if (exists == NULL || data == NULL)
1898*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1899*00b67f09SDavid van Moolenbroek 
1900*00b67f09SDavid van Moolenbroek 	/*
1901*00b67f09SDavid van Moolenbroek 	 * Only set unknown once we are sure that this NSEC3 is from
1902*00b67f09SDavid van Moolenbroek 	 * the deepest covering zone.
1903*00b67f09SDavid van Moolenbroek 	 */
1904*00b67f09SDavid van Moolenbroek 	if (!dns_nsec3_supportedhash(nsec3.hash)) {
1905*00b67f09SDavid van Moolenbroek 		if (unknown != NULL)
1906*00b67f09SDavid van Moolenbroek 			*unknown = ISC_TRUE;
1907*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
1908*00b67f09SDavid van Moolenbroek 	}
1909*00b67f09SDavid van Moolenbroek 
1910*00b67f09SDavid van Moolenbroek 	/*
1911*00b67f09SDavid van Moolenbroek 	 * Recover the hash from the first label.
1912*00b67f09SDavid van Moolenbroek 	 */
1913*00b67f09SDavid van Moolenbroek 	dns_name_getlabel(nsec3name, 0, &hashlabel);
1914*00b67f09SDavid van Moolenbroek 	isc_region_consume(&hashlabel, 1);
1915*00b67f09SDavid van Moolenbroek 	isc_buffer_init(&buffer, owner, sizeof(owner));
1916*00b67f09SDavid van Moolenbroek 	result = isc_base32hex_decoderegion(&hashlabel, &buffer);
1917*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1918*00b67f09SDavid van Moolenbroek 		return (result);
1919*00b67f09SDavid van Moolenbroek 
1920*00b67f09SDavid van Moolenbroek 	/*
1921*00b67f09SDavid van Moolenbroek 	 * The hash lengths should match.  If not ignore the record.
1922*00b67f09SDavid van Moolenbroek 	 */
1923*00b67f09SDavid van Moolenbroek 	if (isc_buffer_usedlength(&buffer) != nsec3.next_length)
1924*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
1925*00b67f09SDavid van Moolenbroek 
1926*00b67f09SDavid van Moolenbroek 	/*
1927*00b67f09SDavid van Moolenbroek 	 * Work out what this NSEC3 covers.
1928*00b67f09SDavid van Moolenbroek 	 * Inside (<0) or outside (>=0).
1929*00b67f09SDavid van Moolenbroek 	 */
1930*00b67f09SDavid van Moolenbroek 	scope = memcmp(owner, nsec3.next, nsec3.next_length);
1931*00b67f09SDavid van Moolenbroek 
1932*00b67f09SDavid van Moolenbroek 	/*
1933*00b67f09SDavid van Moolenbroek 	 * Prepare to compute all the hashes.
1934*00b67f09SDavid van Moolenbroek 	 */
1935*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&qfixed);
1936*00b67f09SDavid van Moolenbroek 	qname = dns_fixedname_name(&qfixed);
1937*00b67f09SDavid van Moolenbroek 	dns_name_downcase(name, qname, NULL);
1938*00b67f09SDavid van Moolenbroek 	qlabels = dns_name_countlabels(qname);
1939*00b67f09SDavid van Moolenbroek 	first = ISC_TRUE;
1940*00b67f09SDavid van Moolenbroek 
1941*00b67f09SDavid van Moolenbroek 	while (qlabels >= zlabels) {
1942*00b67f09SDavid van Moolenbroek 		length = isc_iterated_hash(hash, nsec3.hash, nsec3.iterations,
1943*00b67f09SDavid van Moolenbroek 					   nsec3.salt, nsec3.salt_length,
1944*00b67f09SDavid van Moolenbroek 					   qname->ndata, qname->length);
1945*00b67f09SDavid van Moolenbroek 		/*
1946*00b67f09SDavid van Moolenbroek 		 * The computed hash length should match.
1947*00b67f09SDavid van Moolenbroek 		 */
1948*00b67f09SDavid van Moolenbroek 		if (length != nsec3.next_length) {
1949*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3),
1950*00b67f09SDavid van Moolenbroek 				 "ignoring NSEC bad length %u vs %u",
1951*00b67f09SDavid van Moolenbroek 				 length, nsec3.next_length);
1952*00b67f09SDavid van Moolenbroek 			return (ISC_R_IGNORE);
1953*00b67f09SDavid van Moolenbroek 		}
1954*00b67f09SDavid van Moolenbroek 
1955*00b67f09SDavid van Moolenbroek 		order = memcmp(hash, owner, length);
1956*00b67f09SDavid van Moolenbroek 		if (first && order == 0) {
1957*00b67f09SDavid van Moolenbroek 			/*
1958*00b67f09SDavid van Moolenbroek 			 * The hashes are the same.
1959*00b67f09SDavid van Moolenbroek 			 */
1960*00b67f09SDavid van Moolenbroek 			atparent = dns_rdatatype_atparent(type);
1961*00b67f09SDavid van Moolenbroek 			ns = dns_nsec3_typepresent(&rdata, dns_rdatatype_ns);
1962*00b67f09SDavid van Moolenbroek 			soa = dns_nsec3_typepresent(&rdata, dns_rdatatype_soa);
1963*00b67f09SDavid van Moolenbroek 			if (ns && !soa) {
1964*00b67f09SDavid van Moolenbroek 				if (!atparent) {
1965*00b67f09SDavid van Moolenbroek 					/*
1966*00b67f09SDavid van Moolenbroek 					 * This NSEC3 record is from somewhere
1967*00b67f09SDavid van Moolenbroek 					 * higher in the DNS, and at the
1968*00b67f09SDavid van Moolenbroek 					 * parent of a delegation. It can not
1969*00b67f09SDavid van Moolenbroek 					 * be legitimately used here.
1970*00b67f09SDavid van Moolenbroek 					 */
1971*00b67f09SDavid van Moolenbroek 					(*logit)(arg, ISC_LOG_DEBUG(3),
1972*00b67f09SDavid van Moolenbroek 						 "ignoring parent NSEC3");
1973*00b67f09SDavid van Moolenbroek 					return (ISC_R_IGNORE);
1974*00b67f09SDavid van Moolenbroek 				}
1975*00b67f09SDavid van Moolenbroek 			} else if (atparent && ns && soa) {
1976*00b67f09SDavid van Moolenbroek 				/*
1977*00b67f09SDavid van Moolenbroek 				 * This NSEC3 record is from the child.
1978*00b67f09SDavid van Moolenbroek 				 * It can not be legitimately used here.
1979*00b67f09SDavid van Moolenbroek 				 */
1980*00b67f09SDavid van Moolenbroek 				(*logit)(arg, ISC_LOG_DEBUG(3),
1981*00b67f09SDavid van Moolenbroek 					 "ignoring child NSEC3");
1982*00b67f09SDavid van Moolenbroek 				return (ISC_R_IGNORE);
1983*00b67f09SDavid van Moolenbroek 			}
1984*00b67f09SDavid van Moolenbroek 			if (type == dns_rdatatype_cname ||
1985*00b67f09SDavid van Moolenbroek 			    type == dns_rdatatype_nxt ||
1986*00b67f09SDavid van Moolenbroek 			    type == dns_rdatatype_nsec ||
1987*00b67f09SDavid van Moolenbroek 			    type == dns_rdatatype_key ||
1988*00b67f09SDavid van Moolenbroek 			    !dns_nsec3_typepresent(&rdata, dns_rdatatype_cname)) {
1989*00b67f09SDavid van Moolenbroek 				*exists = ISC_TRUE;
1990*00b67f09SDavid van Moolenbroek 				*data = dns_nsec3_typepresent(&rdata, type);
1991*00b67f09SDavid van Moolenbroek 				(*logit)(arg, ISC_LOG_DEBUG(3),
1992*00b67f09SDavid van Moolenbroek 					 "NSEC3 proves name exists (owner) "
1993*00b67f09SDavid van Moolenbroek 					 "data=%d", *data);
1994*00b67f09SDavid van Moolenbroek 				return (ISC_R_SUCCESS);
1995*00b67f09SDavid van Moolenbroek 			}
1996*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3),
1997*00b67f09SDavid van Moolenbroek 				 "NSEC3 proves CNAME exists");
1998*00b67f09SDavid van Moolenbroek 			return (ISC_R_IGNORE);
1999*00b67f09SDavid van Moolenbroek 		}
2000*00b67f09SDavid van Moolenbroek 
2001*00b67f09SDavid van Moolenbroek 		if (order == 0 &&
2002*00b67f09SDavid van Moolenbroek 		    dns_nsec3_typepresent(&rdata, dns_rdatatype_ns) &&
2003*00b67f09SDavid van Moolenbroek 		    !dns_nsec3_typepresent(&rdata, dns_rdatatype_soa))
2004*00b67f09SDavid van Moolenbroek 		{
2005*00b67f09SDavid van Moolenbroek 			/*
2006*00b67f09SDavid van Moolenbroek 			 * This NSEC3 record is from somewhere higher in
2007*00b67f09SDavid van Moolenbroek 			 * the DNS, and at the parent of a delegation.
2008*00b67f09SDavid van Moolenbroek 			 * It can not be legitimately used here.
2009*00b67f09SDavid van Moolenbroek 			 */
2010*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3),
2011*00b67f09SDavid van Moolenbroek 				 "ignoring parent NSEC3");
2012*00b67f09SDavid van Moolenbroek 			return (ISC_R_IGNORE);
2013*00b67f09SDavid van Moolenbroek 		}
2014*00b67f09SDavid van Moolenbroek 
2015*00b67f09SDavid van Moolenbroek 		/*
2016*00b67f09SDavid van Moolenbroek 		 * Potential closest encloser.
2017*00b67f09SDavid van Moolenbroek 		 */
2018*00b67f09SDavid van Moolenbroek 		if (order == 0) {
2019*00b67f09SDavid van Moolenbroek 			if (closest != NULL &&
2020*00b67f09SDavid van Moolenbroek 			    (dns_name_countlabels(closest) == 0 ||
2021*00b67f09SDavid van Moolenbroek 			     dns_name_issubdomain(qname, closest)) &&
2022*00b67f09SDavid van Moolenbroek 			    !dns_nsec3_typepresent(&rdata, dns_rdatatype_ds) &&
2023*00b67f09SDavid van Moolenbroek 			    !dns_nsec3_typepresent(&rdata, dns_rdatatype_dname) &&
2024*00b67f09SDavid van Moolenbroek 			    (dns_nsec3_typepresent(&rdata, dns_rdatatype_soa) ||
2025*00b67f09SDavid van Moolenbroek 			     !dns_nsec3_typepresent(&rdata, dns_rdatatype_ns)))
2026*00b67f09SDavid van Moolenbroek 			{
2027*00b67f09SDavid van Moolenbroek 
2028*00b67f09SDavid van Moolenbroek 				dns_name_format(qname, namebuf,
2029*00b67f09SDavid van Moolenbroek 						sizeof(namebuf));
2030*00b67f09SDavid van Moolenbroek 				(*logit)(arg, ISC_LOG_DEBUG(3),
2031*00b67f09SDavid van Moolenbroek 					 "NSEC3 indicates potential closest "
2032*00b67f09SDavid van Moolenbroek 					 "encloser: '%s'", namebuf);
2033*00b67f09SDavid van Moolenbroek 				dns_name_copy(qname, closest, NULL);
2034*00b67f09SDavid van Moolenbroek 				*setclosest = ISC_TRUE;
2035*00b67f09SDavid van Moolenbroek 			}
2036*00b67f09SDavid van Moolenbroek 			dns_name_format(qname, namebuf, sizeof(namebuf));
2037*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3),
2038*00b67f09SDavid van Moolenbroek 				 "NSEC3 at super-domain %s", namebuf);
2039*00b67f09SDavid van Moolenbroek 			return (answer);
2040*00b67f09SDavid van Moolenbroek 		}
2041*00b67f09SDavid van Moolenbroek 
2042*00b67f09SDavid van Moolenbroek 		/*
2043*00b67f09SDavid van Moolenbroek 		 * Find if the name does not exist.
2044*00b67f09SDavid van Moolenbroek 		 *
2045*00b67f09SDavid van Moolenbroek 		 * We continue as we need to find the name closest to the
2046*00b67f09SDavid van Moolenbroek 		 * closest encloser that doesn't exist.
2047*00b67f09SDavid van Moolenbroek 		 *
2048*00b67f09SDavid van Moolenbroek 		 * We also need to continue to ensure that we are not
2049*00b67f09SDavid van Moolenbroek 		 * proving the non-existence of a record in a sub-zone.
2050*00b67f09SDavid van Moolenbroek 		 * If that would be the case we will return ISC_R_IGNORE
2051*00b67f09SDavid van Moolenbroek 		 * above.
2052*00b67f09SDavid van Moolenbroek 		 */
2053*00b67f09SDavid van Moolenbroek 		if ((scope < 0 && order > 0 &&
2054*00b67f09SDavid van Moolenbroek 		     memcmp(hash, nsec3.next, length) < 0) ||
2055*00b67f09SDavid van Moolenbroek 		    (scope >= 0 && (order > 0 ||
2056*00b67f09SDavid van Moolenbroek 				    memcmp(hash, nsec3.next, length) < 0)))
2057*00b67f09SDavid van Moolenbroek 		{
2058*00b67f09SDavid van Moolenbroek 			dns_name_format(qname, namebuf, sizeof(namebuf));
2059*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3), "NSEC3 proves "
2060*00b67f09SDavid van Moolenbroek 				 "name does not exist: '%s'", namebuf);
2061*00b67f09SDavid van Moolenbroek 			if (nearest != NULL &&
2062*00b67f09SDavid van Moolenbroek 			    (dns_name_countlabels(nearest) == 0 ||
2063*00b67f09SDavid van Moolenbroek 			     dns_name_issubdomain(nearest, qname))) {
2064*00b67f09SDavid van Moolenbroek 				dns_name_copy(qname, nearest, NULL);
2065*00b67f09SDavid van Moolenbroek 				*setnearest = ISC_TRUE;
2066*00b67f09SDavid van Moolenbroek 			}
2067*00b67f09SDavid van Moolenbroek 
2068*00b67f09SDavid van Moolenbroek 			*exists = ISC_FALSE;
2069*00b67f09SDavid van Moolenbroek 			*data = ISC_FALSE;
2070*00b67f09SDavid van Moolenbroek 			if (optout != NULL) {
2071*00b67f09SDavid van Moolenbroek 				if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0)
2072*00b67f09SDavid van Moolenbroek 					(*logit)(arg, ISC_LOG_DEBUG(3),
2073*00b67f09SDavid van Moolenbroek 						 "NSEC3 indicates optout");
2074*00b67f09SDavid van Moolenbroek 				else
2075*00b67f09SDavid van Moolenbroek 					(*logit)(arg, ISC_LOG_DEBUG(3),
2076*00b67f09SDavid van Moolenbroek 						 "NSEC3 indicates secure range");
2077*00b67f09SDavid van Moolenbroek 				*optout =
2078*00b67f09SDavid van Moolenbroek 				    ISC_TF(nsec3.flags & DNS_NSEC3FLAG_OPTOUT);
2079*00b67f09SDavid van Moolenbroek 			}
2080*00b67f09SDavid van Moolenbroek 			answer = ISC_R_SUCCESS;
2081*00b67f09SDavid van Moolenbroek 		}
2082*00b67f09SDavid van Moolenbroek 
2083*00b67f09SDavid van Moolenbroek 		qlabels--;
2084*00b67f09SDavid van Moolenbroek 		if (qlabels > 0)
2085*00b67f09SDavid van Moolenbroek 			dns_name_split(qname, qlabels, NULL, qname);
2086*00b67f09SDavid van Moolenbroek 		first = ISC_FALSE;
2087*00b67f09SDavid van Moolenbroek 	}
2088*00b67f09SDavid van Moolenbroek 	return (answer);
2089*00b67f09SDavid van Moolenbroek }
2090