1 /*
2 * special zone file structures and functions for better dnssec handling
3 */
4
5 #include <ldns/config.h>
6
7 #include <ldns/ldns.h>
8
9 ldns_dnssec_rrs *
ldns_dnssec_rrs_new(void)10 ldns_dnssec_rrs_new(void)
11 {
12 ldns_dnssec_rrs *new_rrs;
13 new_rrs = LDNS_MALLOC(ldns_dnssec_rrs);
14 if(!new_rrs) return NULL;
15 new_rrs->rr = NULL;
16 new_rrs->next = NULL;
17 return new_rrs;
18 }
19
20 INLINE void
ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs * rrs,int deep)21 ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep)
22 {
23 ldns_dnssec_rrs *next;
24 while (rrs) {
25 next = rrs->next;
26 if (deep) {
27 ldns_rr_free(rrs->rr);
28 }
29 LDNS_FREE(rrs);
30 rrs = next;
31 }
32 }
33
34 void
ldns_dnssec_rrs_free(ldns_dnssec_rrs * rrs)35 ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs)
36 {
37 ldns_dnssec_rrs_free_internal(rrs, 0);
38 }
39
40 void
ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs * rrs)41 ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs)
42 {
43 ldns_dnssec_rrs_free_internal(rrs, 1);
44 }
45
46 ldns_status
ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs * rrs,ldns_rr * rr)47 ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr)
48 {
49 int cmp;
50 ldns_dnssec_rrs *new_rrs;
51 if (!rrs || !rr) {
52 return LDNS_STATUS_ERR;
53 }
54
55 /* this could be done more efficiently; name and type should already
56 be equal */
57 cmp = ldns_rr_compare(rrs->rr, rr);
58 if (cmp < 0) {
59 if (rrs->next) {
60 return ldns_dnssec_rrs_add_rr(rrs->next, rr);
61 } else {
62 new_rrs = ldns_dnssec_rrs_new();
63 new_rrs->rr = rr;
64 rrs->next = new_rrs;
65 }
66 } else if (cmp > 0) {
67 /* put the current old rr in the new next, put the new
68 rr in the current container */
69 new_rrs = ldns_dnssec_rrs_new();
70 new_rrs->rr = rrs->rr;
71 new_rrs->next = rrs->next;
72 rrs->rr = rr;
73 rrs->next = new_rrs;
74 }
75 /* Silently ignore equal rr's */
76 return LDNS_STATUS_OK;
77 }
78
79 void
ldns_dnssec_rrs_print_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_rrs * rrs)80 ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt,
81 const ldns_dnssec_rrs *rrs)
82 {
83 if (!rrs) {
84 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
85 fprintf(out, "; <void>");
86 } else {
87 if (rrs->rr) {
88 ldns_rr_print_fmt(out, fmt, rrs->rr);
89 }
90 if (rrs->next) {
91 ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next);
92 }
93 }
94 }
95
96 void
ldns_dnssec_rrs_print(FILE * out,const ldns_dnssec_rrs * rrs)97 ldns_dnssec_rrs_print(FILE *out, const ldns_dnssec_rrs *rrs)
98 {
99 ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs);
100 }
101
102
103 ldns_dnssec_rrsets *
ldns_dnssec_rrsets_new(void)104 ldns_dnssec_rrsets_new(void)
105 {
106 ldns_dnssec_rrsets *new_rrsets;
107 new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets);
108 if(!new_rrsets) return NULL;
109 new_rrsets->rrs = NULL;
110 new_rrsets->type = 0;
111 new_rrsets->signatures = NULL;
112 new_rrsets->next = NULL;
113 return new_rrsets;
114 }
115
116 INLINE void
ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets * rrsets,int deep)117 ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep)
118 {
119 if (rrsets) {
120 if (rrsets->rrs) {
121 ldns_dnssec_rrs_free_internal(rrsets->rrs, deep);
122 }
123 if (rrsets->next) {
124 ldns_dnssec_rrsets_free_internal(rrsets->next, deep);
125 }
126 if (rrsets->signatures) {
127 ldns_dnssec_rrs_free_internal(rrsets->signatures, deep);
128 }
129 LDNS_FREE(rrsets);
130 }
131 }
132
133 void
ldns_dnssec_rrsets_free(ldns_dnssec_rrsets * rrsets)134 ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets)
135 {
136 ldns_dnssec_rrsets_free_internal(rrsets, 0);
137 }
138
139 void
ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets * rrsets)140 ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets)
141 {
142 ldns_dnssec_rrsets_free_internal(rrsets, 1);
143 }
144
145 ldns_rr_type
ldns_dnssec_rrsets_type(const ldns_dnssec_rrsets * rrsets)146 ldns_dnssec_rrsets_type(const ldns_dnssec_rrsets *rrsets)
147 {
148 if (rrsets) {
149 return rrsets->type;
150 } else {
151 return 0;
152 }
153 }
154
155 ldns_status
ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets * rrsets,ldns_rr_type type)156 ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
157 ldns_rr_type type)
158 {
159 if (rrsets) {
160 rrsets->type = type;
161 return LDNS_STATUS_OK;
162 }
163 return LDNS_STATUS_ERR;
164 }
165
166 static ldns_dnssec_rrsets *
ldns_dnssec_rrsets_new_frm_rr(ldns_rr * rr)167 ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr)
168 {
169 ldns_dnssec_rrsets *new_rrsets;
170 ldns_rr_type rr_type;
171 bool rrsig;
172
173 new_rrsets = ldns_dnssec_rrsets_new();
174 rr_type = ldns_rr_get_type(rr);
175 if (rr_type == LDNS_RR_TYPE_RRSIG) {
176 rrsig = true;
177 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
178 } else {
179 rrsig = false;
180 }
181 if (!rrsig) {
182 new_rrsets->rrs = ldns_dnssec_rrs_new();
183 new_rrsets->rrs->rr = rr;
184 } else {
185 new_rrsets->signatures = ldns_dnssec_rrs_new();
186 new_rrsets->signatures->rr = rr;
187 }
188 new_rrsets->type = rr_type;
189 return new_rrsets;
190 }
191
192 ldns_status
ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets * rrsets,ldns_rr * rr)193 ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr)
194 {
195 ldns_dnssec_rrsets *new_rrsets;
196 ldns_rr_type rr_type;
197 bool rrsig = false;
198 ldns_status result = LDNS_STATUS_OK;
199
200 if (!rrsets || !rr) {
201 return LDNS_STATUS_ERR;
202 }
203
204 rr_type = ldns_rr_get_type(rr);
205
206 if (rr_type == LDNS_RR_TYPE_RRSIG) {
207 rrsig = true;
208 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
209 }
210
211 if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) {
212 if (!rrsig) {
213 rrsets->rrs = ldns_dnssec_rrs_new();
214 rrsets->rrs->rr = rr;
215 rrsets->type = rr_type;
216 } else {
217 rrsets->signatures = ldns_dnssec_rrs_new();
218 rrsets->signatures->rr = rr;
219 rrsets->type = rr_type;
220 }
221 return LDNS_STATUS_OK;
222 }
223
224 if (rr_type > ldns_dnssec_rrsets_type(rrsets)) {
225 if (rrsets->next) {
226 result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr);
227 } else {
228 new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr);
229 rrsets->next = new_rrsets;
230 }
231 } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) {
232 /* move the current one into the new next,
233 replace field of current with data from new rr */
234 new_rrsets = ldns_dnssec_rrsets_new();
235 new_rrsets->rrs = rrsets->rrs;
236 new_rrsets->type = rrsets->type;
237 new_rrsets->signatures = rrsets->signatures;
238 new_rrsets->next = rrsets->next;
239 if (!rrsig) {
240 rrsets->rrs = ldns_dnssec_rrs_new();
241 rrsets->rrs->rr = rr;
242 rrsets->signatures = NULL;
243 } else {
244 rrsets->rrs = NULL;
245 rrsets->signatures = ldns_dnssec_rrs_new();
246 rrsets->signatures->rr = rr;
247 }
248 rrsets->type = rr_type;
249 rrsets->next = new_rrsets;
250 } else {
251 /* equal, add to current rrsets */
252 if (rrsig) {
253 if (rrsets->signatures) {
254 result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr);
255 } else {
256 rrsets->signatures = ldns_dnssec_rrs_new();
257 rrsets->signatures->rr = rr;
258 }
259 } else {
260 if (rrsets->rrs) {
261 result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr);
262 } else {
263 rrsets->rrs = ldns_dnssec_rrs_new();
264 rrsets->rrs->rr = rr;
265 }
266 }
267 }
268
269 return result;
270 }
271
272 static void
ldns_dnssec_rrsets_print_soa_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_rrsets * rrsets,bool follow,bool show_soa)273 ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
274 const ldns_dnssec_rrsets *rrsets,
275 bool follow,
276 bool show_soa)
277 {
278 if (!rrsets) {
279 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
280 fprintf(out, "; <void>\n");
281 } else {
282 if (rrsets->rrs &&
283 (show_soa ||
284 ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA
285 )
286 ) {
287 ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs);
288 if (rrsets->signatures) {
289 ldns_dnssec_rrs_print_fmt(out, fmt,
290 rrsets->signatures);
291 }
292 }
293 if (follow && rrsets->next) {
294 ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
295 rrsets->next, follow, show_soa);
296 }
297 }
298 }
299
300
301 void
ldns_dnssec_rrsets_print_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_rrsets * rrsets,bool follow)302 ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
303 const ldns_dnssec_rrsets *rrsets,
304 bool follow)
305 {
306 ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
307 }
308
309 void
ldns_dnssec_rrsets_print(FILE * out,const ldns_dnssec_rrsets * rrsets,bool follow)310 ldns_dnssec_rrsets_print(FILE *out, const ldns_dnssec_rrsets *rrsets, bool follow)
311 {
312 ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default,
313 rrsets, follow);
314 }
315
316 ldns_dnssec_name *
ldns_dnssec_name_new(void)317 ldns_dnssec_name_new(void)
318 {
319 ldns_dnssec_name *new_name;
320
321 new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
322 if (!new_name) {
323 return NULL;
324 }
325 /*
326 * not needed anymore because CALLOC initalizes everything to zero.
327
328 new_name->name = NULL;
329 new_name->rrsets = NULL;
330 new_name->name_alloced = false;
331 new_name->nsec = NULL;
332 new_name->nsec_signatures = NULL;
333
334 new_name->is_glue = false;
335 new_name->hashed_name = NULL;
336
337 */
338 return new_name;
339 }
340
341 ldns_dnssec_name *
ldns_dnssec_name_new_frm_rr(ldns_rr * rr)342 ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
343 {
344 ldns_dnssec_name *new_name = ldns_dnssec_name_new();
345
346 new_name->name = ldns_rr_owner(rr);
347 if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
348 ldns_dnssec_name_free(new_name);
349 return NULL;
350 }
351
352 return new_name;
353 }
354
355 INLINE void
ldns_dnssec_name_free_internal(ldns_dnssec_name * name,int deep)356 ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
357 int deep)
358 {
359 if (name) {
360 if (name->name_alloced) {
361 ldns_rdf_deep_free(name->name);
362 }
363 if (name->rrsets) {
364 ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
365 }
366 if (name->nsec && deep) {
367 ldns_rr_free(name->nsec);
368 }
369 if (name->nsec_signatures) {
370 ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
371 }
372 if (name->hashed_name) {
373 if (deep) {
374 ldns_rdf_deep_free(name->hashed_name);
375 }
376 }
377 LDNS_FREE(name);
378 }
379 }
380
381 void
ldns_dnssec_name_free(ldns_dnssec_name * name)382 ldns_dnssec_name_free(ldns_dnssec_name *name)
383 {
384 ldns_dnssec_name_free_internal(name, 0);
385 }
386
387 void
ldns_dnssec_name_deep_free(ldns_dnssec_name * name)388 ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
389 {
390 ldns_dnssec_name_free_internal(name, 1);
391 }
392
393 ldns_rdf *
ldns_dnssec_name_name(const ldns_dnssec_name * name)394 ldns_dnssec_name_name(const ldns_dnssec_name *name)
395 {
396 if (name) {
397 return name->name;
398 }
399 return NULL;
400 }
401
402 bool
ldns_dnssec_name_is_glue(const ldns_dnssec_name * name)403 ldns_dnssec_name_is_glue(const ldns_dnssec_name *name)
404 {
405 if (name) {
406 return name->is_glue;
407 }
408 return false;
409 }
410
411 void
ldns_dnssec_name_set_name(ldns_dnssec_name * rrset,ldns_rdf * dname)412 ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
413 ldns_rdf *dname)
414 {
415 if (rrset && dname) {
416 rrset->name = dname;
417 }
418 }
419
420
421 void
ldns_dnssec_name_set_nsec(ldns_dnssec_name * rrset,ldns_rr * nsec)422 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
423 {
424 if (rrset && nsec) {
425 rrset->nsec = nsec;
426 }
427 }
428
429 int
ldns_dnssec_name_cmp(const void * a,const void * b)430 ldns_dnssec_name_cmp(const void *a, const void *b)
431 {
432 ldns_dnssec_name *na = (ldns_dnssec_name *) a;
433 ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
434
435 if (na && nb) {
436 return ldns_dname_compare(ldns_dnssec_name_name(na),
437 ldns_dnssec_name_name(nb));
438 } else if (na) {
439 return 1;
440 } else if (nb) {
441 return -1;
442 } else {
443 return 0;
444 }
445 }
446
447 ldns_status
ldns_dnssec_name_add_rr(ldns_dnssec_name * name,ldns_rr * rr)448 ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
449 ldns_rr *rr)
450 {
451 ldns_status result = LDNS_STATUS_OK;
452 ldns_rr_type rr_type;
453 ldns_rr_type typecovered = 0;
454
455 /* special handling for NSEC3 and NSECX covering RRSIGS */
456
457 if (!name || !rr) {
458 return LDNS_STATUS_ERR;
459 }
460
461 rr_type = ldns_rr_get_type(rr);
462
463 if (rr_type == LDNS_RR_TYPE_RRSIG) {
464 typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
465 }
466
467 if (rr_type == LDNS_RR_TYPE_NSEC ||
468 rr_type == LDNS_RR_TYPE_NSEC3) {
469 /* XX check if is already set (and error?) */
470 name->nsec = rr;
471 } else if (typecovered == LDNS_RR_TYPE_NSEC ||
472 typecovered == LDNS_RR_TYPE_NSEC3) {
473 if (name->nsec_signatures) {
474 result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
475 } else {
476 name->nsec_signatures = ldns_dnssec_rrs_new();
477 name->nsec_signatures->rr = rr;
478 }
479 } else {
480 /* it's a 'normal' RR, add it to the right rrset */
481 if (name->rrsets) {
482 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
483 } else {
484 name->rrsets = ldns_dnssec_rrsets_new();
485 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
486 }
487 }
488 return result;
489 }
490
491 ldns_dnssec_rrsets *
ldns_dnssec_name_find_rrset(const ldns_dnssec_name * name,ldns_rr_type type)492 ldns_dnssec_name_find_rrset(const ldns_dnssec_name *name,
493 ldns_rr_type type) {
494 ldns_dnssec_rrsets *result;
495
496 result = name->rrsets;
497 while (result) {
498 if (result->type == type) {
499 return result;
500 } else {
501 result = result->next;
502 }
503 }
504 return NULL;
505 }
506
507 ldns_dnssec_rrsets *
ldns_dnssec_zone_find_rrset(const ldns_dnssec_zone * zone,const ldns_rdf * dname,ldns_rr_type type)508 ldns_dnssec_zone_find_rrset(const ldns_dnssec_zone *zone,
509 const ldns_rdf *dname,
510 ldns_rr_type type)
511 {
512 ldns_rbnode_t *node;
513
514 if (!zone || !dname || !zone->names) {
515 return NULL;
516 }
517
518 node = ldns_rbtree_search(zone->names, dname);
519 if (node) {
520 return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
521 type);
522 } else {
523 return NULL;
524 }
525 }
526
527 static void
ldns_dnssec_name_print_soa_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_name * name,bool show_soa)528 ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
529 const ldns_dnssec_name *name,
530 bool show_soa)
531 {
532 if (name) {
533 if(name->rrsets) {
534 ldns_dnssec_rrsets_print_soa_fmt(out, fmt,
535 name->rrsets, true, show_soa);
536 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
537 fprintf(out, ";; Empty nonterminal: ");
538 ldns_rdf_print(out, name->name);
539 fprintf(out, "\n");
540 }
541 if(name->nsec) {
542 ldns_rr_print_fmt(out, fmt, name->nsec);
543 }
544 if (name->nsec_signatures) {
545 ldns_dnssec_rrs_print_fmt(out, fmt,
546 name->nsec_signatures);
547 }
548 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
549 fprintf(out, "; <void>\n");
550 }
551 }
552
553
554 void
ldns_dnssec_name_print_fmt(FILE * out,const ldns_output_format * fmt,const ldns_dnssec_name * name)555 ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
556 const ldns_dnssec_name *name)
557 {
558 ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
559 }
560
561 void
ldns_dnssec_name_print(FILE * out,const ldns_dnssec_name * name)562 ldns_dnssec_name_print(FILE *out, const ldns_dnssec_name *name)
563 {
564 ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
565 }
566
567
568 ldns_dnssec_zone *
ldns_dnssec_zone_new(void)569 ldns_dnssec_zone_new(void)
570 {
571 ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
572 if(!zone) return NULL;
573 zone->soa = NULL;
574 zone->names = NULL;
575 zone->hashed_names = NULL;
576 zone->_nsec3params = NULL;
577
578 return zone;
579 }
580
581 static bool
rr_is_rrsig_covering(ldns_rr * rr,ldns_rr_type t)582 rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
583 {
584 return ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
585 && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
586 }
587
588 /* When the zone is first read into an list and then inserted into an
589 * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
590 * to each other. Because ldns-verify-zone (the only program that uses this
591 * function) uses the rbtree mostly for sequentual walking, this results
592 * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
593 */
594 #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
595
596 static ldns_status
597 ldns_dnssec_zone_add_empty_nonterminals_nsec3(
598 ldns_dnssec_zone *zone, ldns_rbtree_t *nsec3s);
599
600 static void
ldns_todo_nsec3_ents_node_free(ldns_rbnode_t * node,void * arg)601 ldns_todo_nsec3_ents_node_free(ldns_rbnode_t *node, void *arg) {
602 (void) arg;
603 ldns_rdf_deep_free((ldns_rdf *)node->key);
604 LDNS_FREE(node);
605 }
606
607 ldns_status
ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone ** z,FILE * fp,const ldns_rdf * origin,uint32_t ttl,ldns_rr_class ATTR_UNUSED (c),int * line_nr)608 ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* origin,
609 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
610 {
611 ldns_rr* cur_rr;
612 size_t i;
613
614 ldns_rdf *my_origin = NULL;
615 ldns_rdf *my_prev = NULL;
616
617 ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
618 /* NSEC3s may occur before the names they refer to. We must remember
619 them and add them to the name later on, after the name is read.
620 We track not yet matching NSEC3s*n the todo_nsec3s list */
621 ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
622 /* when reading NSEC3s, there is a chance that we encounter nsecs
623 for empty nonterminals, whose nonterminals we cannot derive yet
624 because the needed information is to be read later.
625
626 nsec3_ents (where ent is e.n.t.; i.e. empty non terminal) will
627 hold the NSEC3s that still didn't have a matching name in the
628 zone tree, even after all names were read. They can only match
629 after the zone is equiped with all the empty non terminals. */
630 ldns_rbtree_t todo_nsec3_ents;
631 ldns_rbnode_t *new_node;
632 ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
633
634 ldns_status status;
635
636 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
637 ldns_zone* zone = NULL;
638 #else
639 uint32_t my_ttl = ttl;
640 #endif
641
642 ldns_rbtree_init(&todo_nsec3_ents, ldns_dname_compare_v);
643
644 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
645 status = ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr);
646 if (status != LDNS_STATUS_OK)
647 goto error;
648 #endif
649 if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) {
650 status = LDNS_STATUS_MEM_ERR;
651 goto error;
652 }
653 if (origin) {
654 if (!(my_origin = ldns_rdf_clone(origin))) {
655 status = LDNS_STATUS_MEM_ERR;
656 goto error;
657 }
658 if (!(my_prev = ldns_rdf_clone(origin))) {
659 status = LDNS_STATUS_MEM_ERR;
660 goto error;
661 }
662 }
663
664 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
665 if (ldns_zone_soa(zone)) {
666 status = ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone));
667 if (status != LDNS_STATUS_OK)
668 goto error;
669 }
670 for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
671 cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
672 status = LDNS_STATUS_OK;
673 #else
674 while (!feof(fp)) {
675 status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
676 &my_prev, line_nr);
677
678 #endif
679 switch (status) {
680 case LDNS_STATUS_OK:
681
682 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
683 if (status ==
684 LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
685
686 if (rr_is_rrsig_covering(cur_rr,
687 LDNS_RR_TYPE_NSEC3)){
688 ldns_rr_list_push_rr(todo_nsec3_rrsigs,
689 cur_rr);
690 } else {
691 ldns_rr_list_push_rr(todo_nsec3s,
692 cur_rr);
693 }
694 status = LDNS_STATUS_OK;
695
696 } else if (status != LDNS_STATUS_OK)
697 goto error;
698
699 break;
700
701
702 case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */
703 case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/
704 case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/
705 status = LDNS_STATUS_OK;
706 break;
707
708 case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
709 status = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
710 break;
711
712 default:
713 goto error;
714 }
715 }
716
717 for (i = 0; status == LDNS_STATUS_OK &&
718 i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
719 cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
720 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
721 if (status == LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
722 if (!(new_node = LDNS_MALLOC(ldns_rbnode_t))) {
723 status = LDNS_STATUS_MEM_ERR;
724 break;
725 }
726 new_node->key = ldns_dname_label(ldns_rr_owner(cur_rr), 0);
727 new_node->data = cur_rr;
728 if (!ldns_rbtree_insert(&todo_nsec3_ents, new_node)) {
729 LDNS_FREE(new_node);
730 status = LDNS_STATUS_MEM_ERR;
731 break;
732 }
733 status = LDNS_STATUS_OK;
734 }
735 }
736 if (todo_nsec3_ents.count > 0)
737 (void) ldns_dnssec_zone_add_empty_nonterminals_nsec3(
738 newzone, &todo_nsec3_ents);
739 for (i = 0; status == LDNS_STATUS_OK &&
740 i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); i++) {
741 cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
742 status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
743 }
744 if (z) {
745 *z = newzone;
746 newzone = NULL;
747 } else {
748 ldns_dnssec_zone_free(newzone);
749 }
750
751 error:
752 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
753 if (zone) {
754 ldns_zone_free(zone);
755 }
756 #endif
757 ldns_rr_list_free(todo_nsec3_rrsigs);
758 ldns_traverse_postorder(&todo_nsec3_ents,
759 ldns_todo_nsec3_ents_node_free, NULL);
760 ldns_rr_list_free(todo_nsec3s);
761
762 if (my_origin) {
763 ldns_rdf_deep_free(my_origin);
764 }
765 if (my_prev) {
766 ldns_rdf_deep_free(my_prev);
767 }
768 if (newzone) {
769 ldns_dnssec_zone_free(newzone);
770 }
771 return status;
772 }
773
774 ldns_status
775 ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, const ldns_rdf* origin,
776 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
777 {
778 return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
779 }
780
781 static void
782 ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
783 (void) arg;
784 ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
785 LDNS_FREE(node);
786 }
787
788 static void
789 ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
790 (void) arg;
791 ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
792 LDNS_FREE(node);
793 }
794
795 void
796 ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
797 {
798 if (zone) {
799 if (zone->names) {
800 /* destroy all name structures within the tree */
801 ldns_traverse_postorder(zone->names,
802 ldns_dnssec_name_node_free,
803 NULL);
804 LDNS_FREE(zone->names);
805 }
806 LDNS_FREE(zone);
807 }
808 }
809
810 void
811 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
812 {
813 if (zone) {
814 if (zone->names) {
815 /* destroy all name structures within the tree */
816 ldns_traverse_postorder(zone->names,
817 ldns_dnssec_name_node_deep_free,
818 NULL);
819 LDNS_FREE(zone->names);
820 }
821 LDNS_FREE(zone);
822 }
823 }
824
825 /* use for dname comparison in tree */
826 int
827 ldns_dname_compare_v(const void *a, const void *b) {
828 return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
829 }
830
831 static void
832 ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
833 ldns_dnssec_name* name, ldns_rr* nsec3rr);
834
835 static void
836 ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) {
837 (void) arg;
838 LDNS_FREE(node);
839 }
840
841 static void
842 ldns_dnssec_zone_hashed_names_from_nsec3(
843 ldns_dnssec_zone* zone, ldns_rr* nsec3rr)
844 {
845 ldns_rbnode_t* current_node;
846 ldns_dnssec_name* current_name;
847
848 assert(zone != NULL);
849 assert(nsec3rr != NULL);
850
851 if (zone->hashed_names) {
852 ldns_traverse_postorder(zone->hashed_names,
853 ldns_hashed_names_node_free, NULL);
854 LDNS_FREE(zone->hashed_names);
855 }
856 zone->_nsec3params = nsec3rr;
857
858 /* So this is a NSEC3 zone.
859 * Calculate hashes for all names already in the zone
860 */
861 zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v);
862 if (zone->hashed_names == NULL) {
863 return;
864 }
865 for ( current_node = ldns_rbtree_first(zone->names)
866 ; current_node != LDNS_RBTREE_NULL
867 ; current_node = ldns_rbtree_next(current_node)
868 ) {
869 current_name = (ldns_dnssec_name *) current_node->data;
870 ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr);
871
872 }
873 }
874
875 static void
876 ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone,
877 ldns_dnssec_name* name, ldns_rr* nsec3rr)
878 {
879 ldns_rbnode_t* new_node;
880
881 assert(name != NULL);
882 if (! zone->_nsec3params) {
883 if (! nsec3rr) {
884 return;
885 }
886 ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr);
887
888 } else if (! nsec3rr) {
889 nsec3rr = zone->_nsec3params;
890 }
891 name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name);
892
893 /* Also store in zone->hashed_names */
894 if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) {
895
896 new_node->key = name->hashed_name;
897 new_node->data = name;
898
899 if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) {
900
901 LDNS_FREE(new_node);
902 }
903 }
904 }
905
906
907 static ldns_rbnode_t *
908 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) {
909 ldns_rdf *hashed_name;
910
911 hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
912 if (hashed_name == NULL) {
913 return NULL;
914 }
915 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){
916
917 ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr);
918 }
919 if (zone->hashed_names == NULL) {
920 ldns_rdf_deep_free(hashed_name);
921 return NULL;
922 }
923 return ldns_rbtree_search(zone->hashed_names, hashed_name);
924 }
925
926 ldns_status
927 ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
928 {
929 ldns_status result = LDNS_STATUS_OK;
930 ldns_dnssec_name *cur_name;
931 ldns_rbnode_t *cur_node;
932 ldns_rr_type type_covered = 0;
933
934 if (!zone || !rr) {
935 return LDNS_STATUS_ERR;
936 }
937
938 if (!zone->names) {
939 zone->names = ldns_rbtree_create(ldns_dname_compare_v);
940 if(!zone->names) return LDNS_STATUS_MEM_ERR;
941 }
942
943 /* we need the original of the hashed name if this is
944 an NSEC3, or an RRSIG that covers an NSEC3 */
945 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
946 type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
947 }
948 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
949 type_covered == LDNS_RR_TYPE_NSEC3) {
950 cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr);
951 if (!cur_node) {
952 return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
953 }
954 } else {
955 cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
956 }
957 if (!cur_node) {
958 /* add */
959 cur_name = ldns_dnssec_name_new_frm_rr(rr);
960 if(!cur_name) return LDNS_STATUS_MEM_ERR;
961 cur_node = LDNS_MALLOC(ldns_rbnode_t);
962 if(!cur_node) {
963 ldns_dnssec_name_free(cur_name);
964 return LDNS_STATUS_MEM_ERR;
965 }
966 cur_node->key = ldns_rr_owner(rr);
967 cur_node->data = cur_name;
968 (void)ldns_rbtree_insert(zone->names, cur_node);
969 ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL);
970 } else {
971 cur_name = (ldns_dnssec_name *) cur_node->data;
972 result = ldns_dnssec_name_add_rr(cur_name, rr);
973 }
974 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
975 zone->soa = cur_name;
976 }
977 return result;
978 }
979
980 void
981 ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
982 const ldns_rbtree_t *tree,
983 bool print_soa)
984 {
985 ldns_rbnode_t *node;
986 ldns_dnssec_name *name;
987
988 node = ldns_rbtree_first(tree);
989 while (node != LDNS_RBTREE_NULL) {
990 name = (ldns_dnssec_name *) node->data;
991 ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
992 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
993 fprintf(out, ";\n");
994 node = ldns_rbtree_next(node);
995 }
996 }
997
998 void
999 ldns_dnssec_zone_names_print(FILE *out, const ldns_rbtree_t *tree, bool print_soa)
1000 {
1001 ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
1002 tree, print_soa);
1003 }
1004
1005 void
1006 ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
1007 const ldns_dnssec_zone *zone)
1008 {
1009 if (zone) {
1010 if (zone->soa) {
1011 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
1012 fprintf(out, ";; Zone: ");
1013 ldns_rdf_print(out, ldns_dnssec_name_name(
1014 zone->soa));
1015 fprintf(out, "\n;\n");
1016 }
1017 ldns_dnssec_rrsets_print_fmt(out, fmt,
1018 ldns_dnssec_name_find_rrset(
1019 zone->soa,
1020 LDNS_RR_TYPE_SOA),
1021 false);
1022 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
1023 fprintf(out, ";\n");
1024 }
1025
1026 if (zone->names) {
1027 ldns_dnssec_zone_names_print_fmt(out, fmt,
1028 zone->names, false);
1029 }
1030 }
1031 }
1032
1033 void
1034 ldns_dnssec_zone_print(FILE *out, const ldns_dnssec_zone *zone)
1035 {
1036 ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
1037 }
1038
1039 static ldns_status
1040 ldns_dnssec_zone_add_empty_nonterminals_nsec3(
1041 ldns_dnssec_zone *zone, ldns_rbtree_t *nsec3s)
1042 {
1043 ldns_dnssec_name *new_name;
1044 ldns_rdf *cur_name;
1045 ldns_rdf *next_name;
1046 ldns_rbnode_t *cur_node, *next_node, *new_node;
1047
1048 /* for the detection */
1049 uint16_t i, cur_label_count, next_label_count;
1050 uint16_t soa_label_count = 0;
1051 ldns_rdf *l1, *l2;
1052 int lpos;
1053
1054 if (!zone) {
1055 return LDNS_STATUS_ERR;
1056 }
1057 if (zone->soa && zone->soa->name) {
1058 soa_label_count = ldns_dname_label_count(zone->soa->name);
1059 }
1060
1061 cur_node = ldns_rbtree_first(zone->names);
1062 while (cur_node != LDNS_RBTREE_NULL) {
1063 next_node = ldns_rbtree_next(cur_node);
1064
1065 /* skip glue */
1066 while (next_node != LDNS_RBTREE_NULL &&
1067 next_node->data &&
1068 ((ldns_dnssec_name *)next_node->data)->is_glue
1069 ) {
1070 next_node = ldns_rbtree_next(next_node);
1071 }
1072
1073 if (next_node == LDNS_RBTREE_NULL) {
1074 next_node = ldns_rbtree_first(zone->names);
1075 }
1076 if (! cur_node->data || ! next_node->data) {
1077 return LDNS_STATUS_ERR;
1078 }
1079 cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
1080 next_name = ((ldns_dnssec_name *)next_node->data)->name;
1081 cur_label_count = ldns_dname_label_count(cur_name);
1082 next_label_count = ldns_dname_label_count(next_name);
1083
1084 /* Since the names are in canonical order, we can
1085 * recognize empty non-terminals by their labels;
1086 * every label after the first one on the next owner
1087 * name is a non-terminal if it either does not exist
1088 * in the current name or is different from the same
1089 * label in the current name (counting from the end)
1090 */
1091 for (i = 1; i < next_label_count - soa_label_count; i++) {
1092 lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1093 if (lpos >= 0) {
1094 l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1095 } else {
1096 l1 = NULL;
1097 }
1098 l2 = ldns_dname_clone_from(next_name, i);
1099
1100 if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1101 /* We have an empty nonterminal, add it to the
1102 * tree
1103 */
1104 ldns_rbnode_t *node = NULL;
1105 ldns_rdf *ent_name;
1106
1107 if (!(ent_name = ldns_dname_clone_from(
1108 next_name, i)))
1109 return LDNS_STATUS_MEM_ERR;
1110
1111 if (nsec3s && zone->_nsec3params) {
1112 ldns_rdf *ent_hashed_name;
1113
1114 if (!(ent_hashed_name =
1115 ldns_nsec3_hash_name_frm_nsec3(
1116 zone->_nsec3params,
1117 ent_name)))
1118 return LDNS_STATUS_MEM_ERR;
1119 node = ldns_rbtree_search(nsec3s,
1120 ent_hashed_name);
1121 if (!node) {
1122 ldns_rdf_deep_free(l1);
1123 ldns_rdf_deep_free(l2);
1124 continue;
1125 }
1126 }
1127 new_name = ldns_dnssec_name_new();
1128 if (!new_name) {
1129 return LDNS_STATUS_MEM_ERR;
1130 }
1131 new_name->name = ent_name;
1132 if (!new_name->name) {
1133 ldns_dnssec_name_free(new_name);
1134 return LDNS_STATUS_MEM_ERR;
1135 }
1136 new_name->name_alloced = true;
1137 new_node = LDNS_MALLOC(ldns_rbnode_t);
1138 if (!new_node) {
1139 ldns_dnssec_name_free(new_name);
1140 return LDNS_STATUS_MEM_ERR;
1141 }
1142 new_node->key = new_name->name;
1143 new_node->data = new_name;
1144 (void)ldns_rbtree_insert(zone->names, new_node);
1145 ldns_dnssec_name_make_hashed_name(
1146 zone, new_name, NULL);
1147 if (node)
1148 (void) ldns_dnssec_zone_add_rr(zone,
1149 (ldns_rr *)node->data);
1150 }
1151 ldns_rdf_deep_free(l1);
1152 ldns_rdf_deep_free(l2);
1153 }
1154
1155 /* we might have inserted a new node after
1156 * the current one so we can't just use next()
1157 */
1158 if (next_node != ldns_rbtree_first(zone->names)) {
1159 cur_node = next_node;
1160 } else {
1161 cur_node = LDNS_RBTREE_NULL;
1162 }
1163 }
1164 return LDNS_STATUS_OK;
1165 }
1166
1167 ldns_status
1168 ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
1169 {
1170 return ldns_dnssec_zone_add_empty_nonterminals_nsec3(zone, NULL);
1171 }
1172
1173 bool
1174 ldns_dnssec_zone_is_nsec3_optout(const ldns_dnssec_zone* zone)
1175 {
1176 ldns_rr* nsec3;
1177 ldns_rbnode_t* node;
1178
1179 if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1180 node = ldns_rbtree_first(zone->names);
1181 while (node != LDNS_RBTREE_NULL) {
1182 nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1183 if (nsec3 &&ldns_rr_get_type(nsec3)
1184 == LDNS_RR_TYPE_NSEC3 &&
1185 ldns_nsec3_optout(nsec3)) {
1186 return true;
1187 }
1188 node = ldns_rbtree_next(node);
1189 }
1190 }
1191 return false;
1192 }
1193