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