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(®ion, 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], ¶m->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