xref: /minix3/external/bsd/bind/dist/lib/dns/nsec.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: nsec.c,v 1.9 2014/12/10 04:37:58 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004, 2005, 2007-2009, 2011-2014  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek 
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek 
26*00b67f09SDavid van Moolenbroek #include <isc/log.h>
27*00b67f09SDavid van Moolenbroek #include <isc/string.h>
28*00b67f09SDavid van Moolenbroek #include <isc/util.h>
29*00b67f09SDavid van Moolenbroek 
30*00b67f09SDavid van Moolenbroek #include <dns/db.h>
31*00b67f09SDavid van Moolenbroek #include <dns/nsec.h>
32*00b67f09SDavid van Moolenbroek #include <dns/rdata.h>
33*00b67f09SDavid van Moolenbroek #include <dns/rdatalist.h>
34*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
35*00b67f09SDavid van Moolenbroek #include <dns/rdatasetiter.h>
36*00b67f09SDavid van Moolenbroek #include <dns/rdatastruct.h>
37*00b67f09SDavid van Moolenbroek #include <dns/result.h>
38*00b67f09SDavid van Moolenbroek 
39*00b67f09SDavid van Moolenbroek #include <dst/dst.h>
40*00b67f09SDavid van Moolenbroek 
41*00b67f09SDavid van Moolenbroek #define RETERR(x) do { \
42*00b67f09SDavid van Moolenbroek 	result = (x); \
43*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) \
44*00b67f09SDavid van Moolenbroek 		goto failure; \
45*00b67f09SDavid van Moolenbroek 	} while (/*CONSTCOND*/0)
46*00b67f09SDavid van Moolenbroek 
47*00b67f09SDavid van Moolenbroek void
dns_nsec_setbit(unsigned char * array,unsigned int type,unsigned int bit)48*00b67f09SDavid van Moolenbroek dns_nsec_setbit(unsigned char *array, unsigned int type, unsigned int bit) {
49*00b67f09SDavid van Moolenbroek 	unsigned int shift, mask;
50*00b67f09SDavid van Moolenbroek 
51*00b67f09SDavid van Moolenbroek 	shift = 7 - (type % 8);
52*00b67f09SDavid van Moolenbroek 	mask = 1 << shift;
53*00b67f09SDavid van Moolenbroek 
54*00b67f09SDavid van Moolenbroek 	if (bit != 0)
55*00b67f09SDavid van Moolenbroek 		array[type / 8] |= mask;
56*00b67f09SDavid van Moolenbroek 	else
57*00b67f09SDavid van Moolenbroek 		array[type / 8] &= (~mask & 0xFF);
58*00b67f09SDavid van Moolenbroek }
59*00b67f09SDavid van Moolenbroek 
60*00b67f09SDavid van Moolenbroek isc_boolean_t
dns_nsec_isset(const unsigned char * array,unsigned int type)61*00b67f09SDavid van Moolenbroek dns_nsec_isset(const unsigned char *array, unsigned int type) {
62*00b67f09SDavid van Moolenbroek 	unsigned int byte, shift, mask;
63*00b67f09SDavid van Moolenbroek 
64*00b67f09SDavid van Moolenbroek 	byte = array[type / 8];
65*00b67f09SDavid van Moolenbroek 	shift = 7 - (type % 8);
66*00b67f09SDavid van Moolenbroek 	mask = 1 << shift;
67*00b67f09SDavid van Moolenbroek 
68*00b67f09SDavid van Moolenbroek 	return (ISC_TF(byte & mask));
69*00b67f09SDavid van Moolenbroek }
70*00b67f09SDavid van Moolenbroek 
71*00b67f09SDavid van Moolenbroek unsigned int
dns_nsec_compressbitmap(unsigned char * map,const unsigned char * raw,unsigned int max_type)72*00b67f09SDavid van Moolenbroek dns_nsec_compressbitmap(unsigned char *map, const unsigned char *raw,
73*00b67f09SDavid van Moolenbroek 			unsigned int max_type)
74*00b67f09SDavid van Moolenbroek {
75*00b67f09SDavid van Moolenbroek 	unsigned char *start = map;
76*00b67f09SDavid van Moolenbroek 	unsigned int window;
77*00b67f09SDavid van Moolenbroek 	int octet;
78*00b67f09SDavid van Moolenbroek 
79*00b67f09SDavid van Moolenbroek 	if (raw == NULL)
80*00b67f09SDavid van Moolenbroek 		return (0);
81*00b67f09SDavid van Moolenbroek 
82*00b67f09SDavid van Moolenbroek 	for (window = 0; window < 256; window++) {
83*00b67f09SDavid van Moolenbroek 		if (window * 256 > max_type)
84*00b67f09SDavid van Moolenbroek 			break;
85*00b67f09SDavid van Moolenbroek 		for (octet = 31; octet >= 0; octet--)
86*00b67f09SDavid van Moolenbroek 			if (*(raw + octet) != 0)
87*00b67f09SDavid van Moolenbroek 				break;
88*00b67f09SDavid van Moolenbroek 		if (octet < 0) {
89*00b67f09SDavid van Moolenbroek 			raw += 32;
90*00b67f09SDavid van Moolenbroek 			continue;
91*00b67f09SDavid van Moolenbroek 		}
92*00b67f09SDavid van Moolenbroek 		*map++ = window;
93*00b67f09SDavid van Moolenbroek 		*map++ = octet + 1;
94*00b67f09SDavid van Moolenbroek 		/*
95*00b67f09SDavid van Moolenbroek 		 * Note: potential overlapping move.
96*00b67f09SDavid van Moolenbroek 		 */
97*00b67f09SDavid van Moolenbroek 		memmove(map, raw, octet + 1);
98*00b67f09SDavid van Moolenbroek 		map += octet + 1;
99*00b67f09SDavid van Moolenbroek 		raw += 32;
100*00b67f09SDavid van Moolenbroek 	}
101*00b67f09SDavid van Moolenbroek 	return (unsigned int)(map - start);
102*00b67f09SDavid van Moolenbroek }
103*00b67f09SDavid van Moolenbroek 
104*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec_buildrdata(dns_db_t * db,dns_dbversion_t * version,dns_dbnode_t * node,dns_name_t * target,unsigned char * buffer,dns_rdata_t * rdata)105*00b67f09SDavid van Moolenbroek dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version,
106*00b67f09SDavid van Moolenbroek 		    dns_dbnode_t *node, dns_name_t *target,
107*00b67f09SDavid van Moolenbroek 		    unsigned char *buffer, dns_rdata_t *rdata)
108*00b67f09SDavid van Moolenbroek {
109*00b67f09SDavid van Moolenbroek 	isc_result_t result;
110*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
111*00b67f09SDavid van Moolenbroek 	isc_region_t r;
112*00b67f09SDavid van Moolenbroek 	unsigned int i;
113*00b67f09SDavid van Moolenbroek 
114*00b67f09SDavid van Moolenbroek 	unsigned char *nsec_bits, *bm;
115*00b67f09SDavid van Moolenbroek 	unsigned int max_type;
116*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_t *rdsiter;
117*00b67f09SDavid van Moolenbroek 
118*00b67f09SDavid van Moolenbroek 	memset(buffer, 0, DNS_NSEC_BUFFERSIZE);
119*00b67f09SDavid van Moolenbroek 	dns_name_toregion(target, &r);
120*00b67f09SDavid van Moolenbroek 	memmove(buffer, r.base, r.length);
121*00b67f09SDavid van Moolenbroek 	r.base = buffer;
122*00b67f09SDavid van Moolenbroek 	/*
123*00b67f09SDavid van Moolenbroek 	 * Use the end of the space for a raw bitmap leaving enough
124*00b67f09SDavid van Moolenbroek 	 * space for the window identifiers and length octets.
125*00b67f09SDavid van Moolenbroek 	 */
126*00b67f09SDavid van Moolenbroek 	bm = r.base + r.length + 512;
127*00b67f09SDavid van Moolenbroek 	nsec_bits = r.base + r.length;
128*00b67f09SDavid van Moolenbroek 	dns_nsec_setbit(bm, dns_rdatatype_rrsig, 1);
129*00b67f09SDavid van Moolenbroek 	dns_nsec_setbit(bm, dns_rdatatype_nsec, 1);
130*00b67f09SDavid van Moolenbroek 	max_type = dns_rdatatype_nsec;
131*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
132*00b67f09SDavid van Moolenbroek 	rdsiter = NULL;
133*00b67f09SDavid van Moolenbroek 	result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
134*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
135*00b67f09SDavid van Moolenbroek 		return (result);
136*00b67f09SDavid van Moolenbroek 	for (result = dns_rdatasetiter_first(rdsiter);
137*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
138*00b67f09SDavid van Moolenbroek 	     result = dns_rdatasetiter_next(rdsiter))
139*00b67f09SDavid van Moolenbroek 	{
140*00b67f09SDavid van Moolenbroek 		dns_rdatasetiter_current(rdsiter, &rdataset);
141*00b67f09SDavid van Moolenbroek 		if (rdataset.type != dns_rdatatype_nsec &&
142*00b67f09SDavid van Moolenbroek 		    rdataset.type != dns_rdatatype_nsec3 &&
143*00b67f09SDavid van Moolenbroek 		    rdataset.type != dns_rdatatype_rrsig) {
144*00b67f09SDavid van Moolenbroek 			if (rdataset.type > max_type)
145*00b67f09SDavid van Moolenbroek 				max_type = rdataset.type;
146*00b67f09SDavid van Moolenbroek 			dns_nsec_setbit(bm, rdataset.type, 1);
147*00b67f09SDavid van Moolenbroek 		}
148*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
149*00b67f09SDavid van Moolenbroek 	}
150*00b67f09SDavid van Moolenbroek 
151*00b67f09SDavid van Moolenbroek 	/*
152*00b67f09SDavid van Moolenbroek 	 * At zone cuts, deny the existence of glue in the parent zone.
153*00b67f09SDavid van Moolenbroek 	 */
154*00b67f09SDavid van Moolenbroek 	if (dns_nsec_isset(bm, dns_rdatatype_ns) &&
155*00b67f09SDavid van Moolenbroek 	    ! dns_nsec_isset(bm, dns_rdatatype_soa)) {
156*00b67f09SDavid van Moolenbroek 		for (i = 0; i <= max_type; i++) {
157*00b67f09SDavid van Moolenbroek 			if (dns_nsec_isset(bm, i) &&
158*00b67f09SDavid van Moolenbroek 			    ! dns_rdatatype_iszonecutauth((dns_rdatatype_t)i))
159*00b67f09SDavid van Moolenbroek 				dns_nsec_setbit(bm, i, 0);
160*00b67f09SDavid van Moolenbroek 		}
161*00b67f09SDavid van Moolenbroek 	}
162*00b67f09SDavid van Moolenbroek 
163*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_destroy(&rdsiter);
164*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
165*00b67f09SDavid van Moolenbroek 		return (result);
166*00b67f09SDavid van Moolenbroek 
167*00b67f09SDavid van Moolenbroek 	nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type);
168*00b67f09SDavid van Moolenbroek 
169*00b67f09SDavid van Moolenbroek 	r.length = (unsigned int)(nsec_bits - r.base);
170*00b67f09SDavid van Moolenbroek 	INSIST(r.length <= DNS_NSEC_BUFFERSIZE);
171*00b67f09SDavid van Moolenbroek 	dns_rdata_fromregion(rdata,
172*00b67f09SDavid van Moolenbroek 			     dns_db_class(db),
173*00b67f09SDavid van Moolenbroek 			     dns_rdatatype_nsec,
174*00b67f09SDavid van Moolenbroek 			     &r);
175*00b67f09SDavid van Moolenbroek 
176*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
177*00b67f09SDavid van Moolenbroek }
178*00b67f09SDavid van Moolenbroek 
179*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec_build(dns_db_t * db,dns_dbversion_t * version,dns_dbnode_t * node,dns_name_t * target,dns_ttl_t ttl)180*00b67f09SDavid van Moolenbroek dns_nsec_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
181*00b67f09SDavid van Moolenbroek 	       dns_name_t *target, dns_ttl_t ttl)
182*00b67f09SDavid van Moolenbroek {
183*00b67f09SDavid van Moolenbroek 	isc_result_t result;
184*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
185*00b67f09SDavid van Moolenbroek 	unsigned char data[DNS_NSEC_BUFFERSIZE];
186*00b67f09SDavid van Moolenbroek 	dns_rdatalist_t rdatalist;
187*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
188*00b67f09SDavid van Moolenbroek 
189*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
190*00b67f09SDavid van Moolenbroek 	dns_rdata_init(&rdata);
191*00b67f09SDavid van Moolenbroek 
192*00b67f09SDavid van Moolenbroek 	RETERR(dns_nsec_buildrdata(db, version, node, target, data, &rdata));
193*00b67f09SDavid van Moolenbroek 
194*00b67f09SDavid van Moolenbroek 	rdatalist.rdclass = dns_db_class(db);
195*00b67f09SDavid van Moolenbroek 	rdatalist.type = dns_rdatatype_nsec;
196*00b67f09SDavid van Moolenbroek 	rdatalist.covers = 0;
197*00b67f09SDavid van Moolenbroek 	rdatalist.ttl = ttl;
198*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(rdatalist.rdata);
199*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
200*00b67f09SDavid van Moolenbroek 	RETERR(dns_rdatalist_tordataset(&rdatalist, &rdataset));
201*00b67f09SDavid van Moolenbroek 	result = dns_db_addrdataset(db, node, version, 0, &rdataset,
202*00b67f09SDavid van Moolenbroek 				    0, NULL);
203*00b67f09SDavid van Moolenbroek 	if (result == DNS_R_UNCHANGED)
204*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
205*00b67f09SDavid van Moolenbroek 
206*00b67f09SDavid van Moolenbroek  failure:
207*00b67f09SDavid van Moolenbroek 	if (dns_rdataset_isassociated(&rdataset))
208*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
209*00b67f09SDavid van Moolenbroek 	return (result);
210*00b67f09SDavid van Moolenbroek }
211*00b67f09SDavid van Moolenbroek 
212*00b67f09SDavid van Moolenbroek isc_boolean_t
dns_nsec_typepresent(dns_rdata_t * nsec,dns_rdatatype_t type)213*00b67f09SDavid van Moolenbroek dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) {
214*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec_t nsecstruct;
215*00b67f09SDavid van Moolenbroek 	isc_result_t result;
216*00b67f09SDavid van Moolenbroek 	isc_boolean_t present;
217*00b67f09SDavid van Moolenbroek 	unsigned int i, len, window;
218*00b67f09SDavid van Moolenbroek 
219*00b67f09SDavid van Moolenbroek 	REQUIRE(nsec != NULL);
220*00b67f09SDavid van Moolenbroek 	REQUIRE(nsec->type == dns_rdatatype_nsec);
221*00b67f09SDavid van Moolenbroek 
222*00b67f09SDavid van Moolenbroek 	/* This should never fail */
223*00b67f09SDavid van Moolenbroek 	result = dns_rdata_tostruct(nsec, &nsecstruct, NULL);
224*00b67f09SDavid van Moolenbroek 	INSIST(result == ISC_R_SUCCESS);
225*00b67f09SDavid van Moolenbroek 
226*00b67f09SDavid van Moolenbroek 	present = ISC_FALSE;
227*00b67f09SDavid van Moolenbroek 	for (i = 0; i < nsecstruct.len; i += len) {
228*00b67f09SDavid van Moolenbroek 		INSIST(i + 2 <= nsecstruct.len);
229*00b67f09SDavid van Moolenbroek 		window = nsecstruct.typebits[i];
230*00b67f09SDavid van Moolenbroek 		len = nsecstruct.typebits[i + 1];
231*00b67f09SDavid van Moolenbroek 		INSIST(len > 0 && len <= 32);
232*00b67f09SDavid van Moolenbroek 		i += 2;
233*00b67f09SDavid van Moolenbroek 		INSIST(i + len <= nsecstruct.len);
234*00b67f09SDavid van Moolenbroek 		if (window * 256 > type)
235*00b67f09SDavid van Moolenbroek 			break;
236*00b67f09SDavid van Moolenbroek 		if ((window + 1) * 256 <= type)
237*00b67f09SDavid van Moolenbroek 			continue;
238*00b67f09SDavid van Moolenbroek 		if (type < (window * 256) + len * 8)
239*00b67f09SDavid van Moolenbroek 			present = ISC_TF(dns_nsec_isset(&nsecstruct.typebits[i],
240*00b67f09SDavid van Moolenbroek 						   type % 256));
241*00b67f09SDavid van Moolenbroek 		break;
242*00b67f09SDavid van Moolenbroek 	}
243*00b67f09SDavid van Moolenbroek 	dns_rdata_freestruct(&nsecstruct);
244*00b67f09SDavid van Moolenbroek 	return (present);
245*00b67f09SDavid van Moolenbroek }
246*00b67f09SDavid van Moolenbroek 
247*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec_nseconly(dns_db_t * db,dns_dbversion_t * version,isc_boolean_t * answer)248*00b67f09SDavid van Moolenbroek dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version,
249*00b67f09SDavid van Moolenbroek 		  isc_boolean_t *answer)
250*00b67f09SDavid van Moolenbroek {
251*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
252*00b67f09SDavid van Moolenbroek 	dns_rdataset_t rdataset;
253*00b67f09SDavid van Moolenbroek 	dns_rdata_dnskey_t dnskey;
254*00b67f09SDavid van Moolenbroek 	isc_result_t result;
255*00b67f09SDavid van Moolenbroek 
256*00b67f09SDavid van Moolenbroek 	REQUIRE(answer != NULL);
257*00b67f09SDavid van Moolenbroek 
258*00b67f09SDavid van Moolenbroek 	dns_rdataset_init(&rdataset);
259*00b67f09SDavid van Moolenbroek 
260*00b67f09SDavid van Moolenbroek 	result = dns_db_getoriginnode(db, &node);
261*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
262*00b67f09SDavid van Moolenbroek 		return (result);
263*00b67f09SDavid van Moolenbroek 
264*00b67f09SDavid van Moolenbroek 	result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
265*00b67f09SDavid van Moolenbroek 				     0, 0, &rdataset, NULL);
266*00b67f09SDavid van Moolenbroek 	dns_db_detachnode(db, &node);
267*00b67f09SDavid van Moolenbroek 
268*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND)
269*00b67f09SDavid van Moolenbroek 		*answer = ISC_FALSE;
270*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
271*00b67f09SDavid van Moolenbroek 		return (result);
272*00b67f09SDavid van Moolenbroek 	for (result = dns_rdataset_first(&rdataset);
273*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
274*00b67f09SDavid van Moolenbroek 	     result = dns_rdataset_next(&rdataset)) {
275*00b67f09SDavid van Moolenbroek 		dns_rdata_t rdata = DNS_RDATA_INIT;
276*00b67f09SDavid van Moolenbroek 
277*00b67f09SDavid van Moolenbroek 		dns_rdataset_current(&rdataset, &rdata);
278*00b67f09SDavid van Moolenbroek 		result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
279*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
280*00b67f09SDavid van Moolenbroek 
281*00b67f09SDavid van Moolenbroek 		if (dnskey.algorithm == DST_ALG_RSAMD5 ||
282*00b67f09SDavid van Moolenbroek 		    dnskey.algorithm == DST_ALG_RSASHA1 ||
283*00b67f09SDavid van Moolenbroek 		    dnskey.algorithm == DST_ALG_DSA ||
284*00b67f09SDavid van Moolenbroek 		    dnskey.algorithm == DST_ALG_ECC)
285*00b67f09SDavid van Moolenbroek 			break;
286*00b67f09SDavid van Moolenbroek 	}
287*00b67f09SDavid van Moolenbroek 	dns_rdataset_disassociate(&rdataset);
288*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS)
289*00b67f09SDavid van Moolenbroek 		*answer = ISC_TRUE;
290*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE) {
291*00b67f09SDavid van Moolenbroek 		*answer = ISC_FALSE;
292*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
293*00b67f09SDavid van Moolenbroek 	}
294*00b67f09SDavid van Moolenbroek 	return (result);
295*00b67f09SDavid van Moolenbroek }
296*00b67f09SDavid van Moolenbroek 
297*00b67f09SDavid van Moolenbroek /*%
298*00b67f09SDavid van Moolenbroek  * Return ISC_R_SUCCESS if we can determine that the name doesn't exist
299*00b67f09SDavid van Moolenbroek  * or we can determine whether there is data or not at the name.
300*00b67f09SDavid van Moolenbroek  * If the name does not exist return the wildcard name.
301*00b67f09SDavid van Moolenbroek  *
302*00b67f09SDavid van Moolenbroek  * Return ISC_R_IGNORE when the NSEC is not the appropriate one.
303*00b67f09SDavid van Moolenbroek  */
304*00b67f09SDavid van Moolenbroek isc_result_t
dns_nsec_noexistnodata(dns_rdatatype_t type,dns_name_t * name,dns_name_t * nsecname,dns_rdataset_t * nsecset,isc_boolean_t * exists,isc_boolean_t * data,dns_name_t * wild,dns_nseclog_t logit,void * arg)305*00b67f09SDavid van Moolenbroek dns_nsec_noexistnodata(dns_rdatatype_t type, dns_name_t *name,
306*00b67f09SDavid van Moolenbroek 		       dns_name_t *nsecname, dns_rdataset_t *nsecset,
307*00b67f09SDavid van Moolenbroek 		       isc_boolean_t *exists, isc_boolean_t *data,
308*00b67f09SDavid van Moolenbroek 		       dns_name_t *wild, dns_nseclog_t logit, void *arg)
309*00b67f09SDavid van Moolenbroek {
310*00b67f09SDavid van Moolenbroek 	int order;
311*00b67f09SDavid van Moolenbroek 	dns_rdata_t rdata = DNS_RDATA_INIT;
312*00b67f09SDavid van Moolenbroek 	isc_result_t result;
313*00b67f09SDavid van Moolenbroek 	dns_namereln_t relation;
314*00b67f09SDavid van Moolenbroek 	unsigned int olabels, nlabels, labels;
315*00b67f09SDavid van Moolenbroek 	dns_rdata_nsec_t nsec;
316*00b67f09SDavid van Moolenbroek 	isc_boolean_t atparent;
317*00b67f09SDavid van Moolenbroek 	isc_boolean_t ns;
318*00b67f09SDavid van Moolenbroek 	isc_boolean_t soa;
319*00b67f09SDavid van Moolenbroek 
320*00b67f09SDavid van Moolenbroek 	REQUIRE(exists != NULL);
321*00b67f09SDavid van Moolenbroek 	REQUIRE(data != NULL);
322*00b67f09SDavid van Moolenbroek 	REQUIRE(nsecset != NULL &&
323*00b67f09SDavid van Moolenbroek 		nsecset->type == dns_rdatatype_nsec);
324*00b67f09SDavid van Moolenbroek 
325*00b67f09SDavid van Moolenbroek 	result = dns_rdataset_first(nsecset);
326*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
327*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3), "failure processing NSEC set");
328*00b67f09SDavid van Moolenbroek 		return (result);
329*00b67f09SDavid van Moolenbroek 	}
330*00b67f09SDavid van Moolenbroek 	dns_rdataset_current(nsecset, &rdata);
331*00b67f09SDavid van Moolenbroek 
332*00b67f09SDavid van Moolenbroek 	(*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC");
333*00b67f09SDavid van Moolenbroek 	relation = dns_name_fullcompare(name, nsecname, &order, &olabels);
334*00b67f09SDavid van Moolenbroek 
335*00b67f09SDavid van Moolenbroek 	if (order < 0) {
336*00b67f09SDavid van Moolenbroek 		/*
337*00b67f09SDavid van Moolenbroek 		 * The name is not within the NSEC range.
338*00b67f09SDavid van Moolenbroek 		 */
339*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3),
340*00b67f09SDavid van Moolenbroek 			      "NSEC does not cover name, before NSEC");
341*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
342*00b67f09SDavid van Moolenbroek 	}
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek 	if (order == 0) {
345*00b67f09SDavid van Moolenbroek 		/*
346*00b67f09SDavid van Moolenbroek 		 * The names are the same.   If we are validating "."
347*00b67f09SDavid van Moolenbroek 		 * then atparent should not be set as there is no parent.
348*00b67f09SDavid van Moolenbroek 		 */
349*00b67f09SDavid van Moolenbroek 		atparent = (olabels != 1) && dns_rdatatype_atparent(type);
350*00b67f09SDavid van Moolenbroek 		ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
351*00b67f09SDavid van Moolenbroek 		soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa);
352*00b67f09SDavid van Moolenbroek 		if (ns && !soa) {
353*00b67f09SDavid van Moolenbroek 			if (!atparent) {
354*00b67f09SDavid van Moolenbroek 				/*
355*00b67f09SDavid van Moolenbroek 				 * This NSEC record is from somewhere higher in
356*00b67f09SDavid van Moolenbroek 				 * the DNS, and at the parent of a delegation.
357*00b67f09SDavid van Moolenbroek 				 * It can not be legitimately used here.
358*00b67f09SDavid van Moolenbroek 				 */
359*00b67f09SDavid van Moolenbroek 				(*logit)(arg, ISC_LOG_DEBUG(3),
360*00b67f09SDavid van Moolenbroek 					      "ignoring parent nsec");
361*00b67f09SDavid van Moolenbroek 				return (ISC_R_IGNORE);
362*00b67f09SDavid van Moolenbroek 			}
363*00b67f09SDavid van Moolenbroek 		} else if (atparent && ns && soa) {
364*00b67f09SDavid van Moolenbroek 			/*
365*00b67f09SDavid van Moolenbroek 			 * This NSEC record is from the child.
366*00b67f09SDavid van Moolenbroek 			 * It can not be legitimately used here.
367*00b67f09SDavid van Moolenbroek 			 */
368*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3),
369*00b67f09SDavid van Moolenbroek 				      "ignoring child nsec");
370*00b67f09SDavid van Moolenbroek 			return (ISC_R_IGNORE);
371*00b67f09SDavid van Moolenbroek 		}
372*00b67f09SDavid van Moolenbroek 		if (type == dns_rdatatype_cname || type == dns_rdatatype_nxt ||
373*00b67f09SDavid van Moolenbroek 		    type == dns_rdatatype_nsec || type == dns_rdatatype_key ||
374*00b67f09SDavid van Moolenbroek 		    !dns_nsec_typepresent(&rdata, dns_rdatatype_cname)) {
375*00b67f09SDavid van Moolenbroek 			*exists = ISC_TRUE;
376*00b67f09SDavid van Moolenbroek 			*data = dns_nsec_typepresent(&rdata, type);
377*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3),
378*00b67f09SDavid van Moolenbroek 				      "nsec proves name exists (owner) data=%d",
379*00b67f09SDavid van Moolenbroek 				      *data);
380*00b67f09SDavid van Moolenbroek 			return (ISC_R_SUCCESS);
381*00b67f09SDavid van Moolenbroek 		}
382*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists");
383*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
384*00b67f09SDavid van Moolenbroek 	}
385*00b67f09SDavid van Moolenbroek 
386*00b67f09SDavid van Moolenbroek 	if (relation == dns_namereln_subdomain &&
387*00b67f09SDavid van Moolenbroek 	    dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
388*00b67f09SDavid van Moolenbroek 	    !dns_nsec_typepresent(&rdata, dns_rdatatype_soa))
389*00b67f09SDavid van Moolenbroek 	{
390*00b67f09SDavid van Moolenbroek 		/*
391*00b67f09SDavid van Moolenbroek 		 * This NSEC record is from somewhere higher in
392*00b67f09SDavid van Moolenbroek 		 * the DNS, and at the parent of a delegation.
393*00b67f09SDavid van Moolenbroek 		 * It can not be legitimately used here.
394*00b67f09SDavid van Moolenbroek 		 */
395*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3), "ignoring parent nsec");
396*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
397*00b67f09SDavid van Moolenbroek 	}
398*00b67f09SDavid van Moolenbroek 
399*00b67f09SDavid van Moolenbroek 	result = dns_rdata_tostruct(&rdata, &nsec, NULL);
400*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
401*00b67f09SDavid van Moolenbroek 		return (result);
402*00b67f09SDavid van Moolenbroek 	relation = dns_name_fullcompare(&nsec.next, name, &order, &nlabels);
403*00b67f09SDavid van Moolenbroek 	if (order == 0) {
404*00b67f09SDavid van Moolenbroek 		dns_rdata_freestruct(&nsec);
405*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3),
406*00b67f09SDavid van Moolenbroek 			      "ignoring nsec matches next name");
407*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
408*00b67f09SDavid van Moolenbroek 	}
409*00b67f09SDavid van Moolenbroek 
410*00b67f09SDavid van Moolenbroek 	if (order < 0 && !dns_name_issubdomain(nsecname, &nsec.next)) {
411*00b67f09SDavid van Moolenbroek 		/*
412*00b67f09SDavid van Moolenbroek 		 * The name is not within the NSEC range.
413*00b67f09SDavid van Moolenbroek 		 */
414*00b67f09SDavid van Moolenbroek 		dns_rdata_freestruct(&nsec);
415*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3),
416*00b67f09SDavid van Moolenbroek 			    "ignoring nsec because name is past end of range");
417*00b67f09SDavid van Moolenbroek 		return (ISC_R_IGNORE);
418*00b67f09SDavid van Moolenbroek 	}
419*00b67f09SDavid van Moolenbroek 
420*00b67f09SDavid van Moolenbroek 	if (order > 0 && relation == dns_namereln_subdomain) {
421*00b67f09SDavid van Moolenbroek 		(*logit)(arg, ISC_LOG_DEBUG(3),
422*00b67f09SDavid van Moolenbroek 			      "nsec proves name exist (empty)");
423*00b67f09SDavid van Moolenbroek 		dns_rdata_freestruct(&nsec);
424*00b67f09SDavid van Moolenbroek 		*exists = ISC_TRUE;
425*00b67f09SDavid van Moolenbroek 		*data = ISC_FALSE;
426*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
427*00b67f09SDavid van Moolenbroek 	}
428*00b67f09SDavid van Moolenbroek 	if (wild != NULL) {
429*00b67f09SDavid van Moolenbroek 		dns_name_t common;
430*00b67f09SDavid van Moolenbroek 		dns_name_init(&common, NULL);
431*00b67f09SDavid van Moolenbroek 		if (olabels > nlabels) {
432*00b67f09SDavid van Moolenbroek 			labels = dns_name_countlabels(nsecname);
433*00b67f09SDavid van Moolenbroek 			dns_name_getlabelsequence(nsecname, labels - olabels,
434*00b67f09SDavid van Moolenbroek 						  olabels, &common);
435*00b67f09SDavid van Moolenbroek 		} else {
436*00b67f09SDavid van Moolenbroek 			labels = dns_name_countlabels(&nsec.next);
437*00b67f09SDavid van Moolenbroek 			dns_name_getlabelsequence(&nsec.next, labels - nlabels,
438*00b67f09SDavid van Moolenbroek 						  nlabels, &common);
439*00b67f09SDavid van Moolenbroek 		}
440*00b67f09SDavid van Moolenbroek 		result = dns_name_concatenate(dns_wildcardname, &common,
441*00b67f09SDavid van Moolenbroek 					      wild, NULL);
442*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
443*00b67f09SDavid van Moolenbroek 			dns_rdata_freestruct(&nsec);
444*00b67f09SDavid van Moolenbroek 			(*logit)(arg, ISC_LOG_DEBUG(3),
445*00b67f09SDavid van Moolenbroek 				    "failure generating wildcard name");
446*00b67f09SDavid van Moolenbroek 			return (result);
447*00b67f09SDavid van Moolenbroek 		}
448*00b67f09SDavid van Moolenbroek 	}
449*00b67f09SDavid van Moolenbroek 	dns_rdata_freestruct(&nsec);
450*00b67f09SDavid van Moolenbroek 	(*logit)(arg, ISC_LOG_DEBUG(3), "nsec range ok");
451*00b67f09SDavid van Moolenbroek 	*exists = ISC_FALSE;
452*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
453*00b67f09SDavid van Moolenbroek }
454