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