2 * Copyright (C) 2004, 2005, 2007-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001, 2003 Internet Software Consortium.
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.
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.
25 #include <isc/string.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>
39 #define RETERR(x) do { \
41 if (result != ISC_R_SUCCESS) \
46 dns_nsec_setbit(unsigned char *array, unsigned int type, unsigned int bit) {
47 unsigned int shift, mask;
49 shift = 7 - (type % 8);
53 array[type / 8] |= mask;
55 array[type / 8] &= (~mask & 0xFF);
59 dns_nsec_isset(const unsigned char *array, unsigned int type) {
60 unsigned int byte, shift, mask;
62 byte = array[type / 8];
63 shift = 7 - (type % 8);
66 return (ISC_TF(byte & mask));
70 dns_nsec_compressbitmap(unsigned char *map, const unsigned char *raw,
71 unsigned int max_type)
73 unsigned char *start = map;
80 for (window = 0; window < 256; window++) {
81 if (window * 256 > max_type)
83 for (octet = 31; octet >= 0; octet--)
84 if (*(raw + octet) != 0)
93 * Note: potential overlapping move.
95 memmove(map, raw, octet + 1);
99 return (unsigned int)(map - start);
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)
108 dns_rdataset_t rdataset;
112 unsigned char *nsec_bits, *bm;
113 unsigned int max_type;
114 dns_rdatasetiter_t *rdsiter;
116 memset(buffer, 0, DNS_NSEC_BUFFERSIZE);
117 dns_name_toregion(target, &r);
118 memmove(buffer, r.base, r.length);
121 * Use the end of the space for a raw bitmap leaving enough
122 * space for the window identifiers and length octets.
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);
131 result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
132 if (result != ISC_R_SUCCESS)
134 for (result = dns_rdatasetiter_first(rdsiter);
135 result == ISC_R_SUCCESS;
136 result = dns_rdatasetiter_next(rdsiter))
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);
146 dns_rdataset_disassociate(&rdataset);
150 * At zone cuts, deny the existence of glue in the parent zone.
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);
161 dns_rdatasetiter_destroy(&rdsiter);
162 if (result != ISC_R_NOMORE)
165 nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type);
167 r.length = (unsigned int)(nsec_bits - r.base);
168 INSIST(r.length <= DNS_NSEC_BUFFERSIZE);
169 dns_rdata_fromregion(rdata,
174 return (ISC_R_SUCCESS);
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)
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;
187 dns_rdataset_init(&rdataset);
188 dns_rdata_init(&rdata);
190 RETERR(dns_nsec_buildrdata(db, version, node, target, data, &rdata));
192 rdatalist.rdclass = dns_db_class(db);
193 rdatalist.type = dns_rdatatype_nsec;
194 rdatalist.covers = 0;
196 ISC_LIST_INIT(rdatalist.rdata);
197 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
198 RETERR(dns_rdatalist_tordataset(&rdatalist, &rdataset));
199 result = dns_db_addrdataset(db, node, version, 0, &rdataset,
201 if (result == DNS_R_UNCHANGED)
202 result = ISC_R_SUCCESS;
205 if (dns_rdataset_isassociated(&rdataset))
206 dns_rdataset_disassociate(&rdataset);
211 dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) {
212 dns_rdata_nsec_t nsecstruct;
214 isc_boolean_t present;
215 unsigned int i, len, window;
217 REQUIRE(nsec != NULL);
218 REQUIRE(nsec->type == dns_rdatatype_nsec);
220 /* This should never fail */
221 result = dns_rdata_tostruct(nsec, &nsecstruct, NULL);
222 INSIST(result == ISC_R_SUCCESS);
225 for (i = 0; i < nsecstruct.len; i += len) {
226 INSIST(i + 2 <= nsecstruct.len);
227 window = nsecstruct.typebits[i];
228 len = nsecstruct.typebits[i + 1];
229 INSIST(len > 0 && len <= 32);
231 INSIST(i + len <= nsecstruct.len);
232 if (window * 256 > type)
234 if ((window + 1) * 256 <= type)
236 if (type < (window * 256) + len * 8)
237 present = ISC_TF(dns_nsec_isset(&nsecstruct.typebits[i],
241 dns_rdata_freestruct(&nsecstruct);
246 dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version,
247 isc_boolean_t *answer)
249 dns_dbnode_t *node = NULL;
250 dns_rdataset_t rdataset;
251 dns_rdata_dnskey_t dnskey;
254 REQUIRE(answer != NULL);
256 dns_rdataset_init(&rdataset);
258 result = dns_db_getoriginnode(db, &node);
259 if (result != ISC_R_SUCCESS)
262 result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
263 0, 0, &rdataset, NULL);
264 dns_db_detachnode(db, &node);
266 if (result == ISC_R_NOTFOUND)
268 if (result != ISC_R_SUCCESS)
270 for (result = dns_rdataset_first(&rdataset);
271 result == ISC_R_SUCCESS;
272 result = dns_rdataset_next(&rdataset)) {
273 dns_rdata_t rdata = DNS_RDATA_INIT;
275 dns_rdataset_current(&rdataset, &rdata);
276 result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
277 RUNTIME_CHECK(result == ISC_R_SUCCESS);
279 if (dnskey.algorithm == DST_ALG_RSAMD5 ||
280 dnskey.algorithm == DST_ALG_RSASHA1 ||
281 dnskey.algorithm == DST_ALG_DSA ||
282 dnskey.algorithm == DST_ALG_ECC)
285 dns_rdataset_disassociate(&rdataset);
286 if (result == ISC_R_SUCCESS)
288 if (result == ISC_R_NOMORE) {
290 result = ISC_R_SUCCESS;
296 * Return ISC_R_SUCCESS if we can determine that the name doesn't exist
297 * or we can determine whether there is data or not at the name.
298 * If the name does not exist return the wildcard name.
300 * Return ISC_R_IGNORE when the NSEC is not the appropriate one.
303 dns_nsec_noexistnodata(dns_rdatatype_t type, dns_name_t *name,
304 dns_name_t *nsecname, dns_rdataset_t *nsecset,
305 isc_boolean_t *exists, isc_boolean_t *data,
306 dns_name_t *wild, dns_nseclog_t logit, void *arg)
309 dns_rdata_t rdata = DNS_RDATA_INIT;
311 dns_namereln_t relation;
312 unsigned int olabels, nlabels, labels;
313 dns_rdata_nsec_t nsec;
314 isc_boolean_t atparent;
318 REQUIRE(exists != NULL);
319 REQUIRE(data != NULL);
320 REQUIRE(nsecset != NULL &&
321 nsecset->type == dns_rdatatype_nsec);
323 result = dns_rdataset_first(nsecset);
324 if (result != ISC_R_SUCCESS) {
325 (*logit)(arg, ISC_LOG_DEBUG(3), "failure processing NSEC set");
328 dns_rdataset_current(nsecset, &rdata);
330 (*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC");
331 relation = dns_name_fullcompare(name, nsecname, &order, &olabels);
335 * The name is not within the NSEC range.
337 (*logit)(arg, ISC_LOG_DEBUG(3),
338 "NSEC does not cover name, before NSEC");
339 return (ISC_R_IGNORE);
344 * The names are the same. If we are validating "."
345 * then atparent should not be set as there is no parent.
347 atparent = (olabels != 1) && dns_rdatatype_atparent(type);
348 ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
349 soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa);
353 * This NSEC record is from somewhere higher in
354 * the DNS, and at the parent of a delegation.
355 * It can not be legitimately used here.
357 (*logit)(arg, ISC_LOG_DEBUG(3),
358 "ignoring parent nsec");
359 return (ISC_R_IGNORE);
361 } else if (atparent && ns && soa) {
363 * This NSEC record is from the child.
364 * It can not be legitimately used here.
366 (*logit)(arg, ISC_LOG_DEBUG(3),
367 "ignoring child nsec");
368 return (ISC_R_IGNORE);
370 if (type == dns_rdatatype_cname || type == dns_rdatatype_nxt ||
371 type == dns_rdatatype_nsec || type == dns_rdatatype_key ||
372 !dns_nsec_typepresent(&rdata, dns_rdatatype_cname)) {
374 *data = dns_nsec_typepresent(&rdata, type);
375 (*logit)(arg, ISC_LOG_DEBUG(3),
376 "nsec proves name exists (owner) data=%d",
378 return (ISC_R_SUCCESS);
380 (*logit)(arg, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists");
381 return (ISC_R_IGNORE);
384 if (relation == dns_namereln_subdomain &&
385 dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
386 !dns_nsec_typepresent(&rdata, dns_rdatatype_soa))
389 * This NSEC record is from somewhere higher in
390 * the DNS, and at the parent of a delegation.
391 * It can not be legitimately used here.
393 (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring parent nsec");
394 return (ISC_R_IGNORE);
397 result = dns_rdata_tostruct(&rdata, &nsec, NULL);
398 if (result != ISC_R_SUCCESS)
400 relation = dns_name_fullcompare(&nsec.next, name, &order, &nlabels);
402 dns_rdata_freestruct(&nsec);
403 (*logit)(arg, ISC_LOG_DEBUG(3),
404 "ignoring nsec matches next name");
405 return (ISC_R_IGNORE);
408 if (order < 0 && !dns_name_issubdomain(nsecname, &nsec.next)) {
410 * The name is not within the NSEC range.
412 dns_rdata_freestruct(&nsec);
413 (*logit)(arg, ISC_LOG_DEBUG(3),
414 "ignoring nsec because name is past end of range");
415 return (ISC_R_IGNORE);
418 if (order > 0 && relation == dns_namereln_subdomain) {
419 (*logit)(arg, ISC_LOG_DEBUG(3),
420 "nsec proves name exist (empty)");
421 dns_rdata_freestruct(&nsec);
424 return (ISC_R_SUCCESS);
428 dns_name_init(&common, NULL);
429 if (olabels > nlabels) {
430 labels = dns_name_countlabels(nsecname);
431 dns_name_getlabelsequence(nsecname, labels - olabels,
434 labels = dns_name_countlabels(&nsec.next);
435 dns_name_getlabelsequence(&nsec.next, labels - nlabels,
438 result = dns_name_concatenate(dns_wildcardname, &common,
440 if (result != ISC_R_SUCCESS) {
441 dns_rdata_freestruct(&nsec);
442 (*logit)(arg, ISC_LOG_DEBUG(3),
443 "failure generating wildcard name");
447 dns_rdata_freestruct(&nsec);
448 (*logit)(arg, ISC_LOG_DEBUG(3), "nsec range ok");
450 return (ISC_R_SUCCESS);