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