]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ldns/dnssec_zone.c
MFV r248590,248594:
[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 #if 0
302 static void
303 ldns_dnssec_rrsets_print_soa(FILE *out,
304                 ldns_dnssec_rrsets *rrsets,
305                 bool follow,
306                 bool show_soa)
307 {
308         ldns_dnssec_rrsets_print_soa_fmt(out, ldns_output_format_default,
309                         rrsets, follow, show_soa);
310 }
311 #endif
312
313 void
314 ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt,
315                 ldns_dnssec_rrsets *rrsets, 
316                 bool follow)
317 {
318         ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true);
319 }
320
321 void
322 ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow)
323 {
324         ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default, 
325                         rrsets, follow);
326 }
327
328 ldns_dnssec_name *
329 ldns_dnssec_name_new(void)
330 {
331         ldns_dnssec_name *new_name;
332
333         new_name = LDNS_CALLOC(ldns_dnssec_name, 1);
334         if (!new_name) {
335                 return NULL;
336         }
337         /*
338          * not needed anymore because CALLOC initalizes everything to zero.
339
340         new_name->name = NULL;
341         new_name->rrsets = NULL;
342         new_name->name_alloced = false;
343         new_name->nsec = NULL;
344         new_name->nsec_signatures = NULL;
345
346         new_name->is_glue = false;
347         new_name->hashed_name = NULL;
348
349          */
350         return new_name;
351 }
352
353 ldns_dnssec_name *
354 ldns_dnssec_name_new_frm_rr(ldns_rr *rr)
355 {
356         ldns_dnssec_name *new_name = ldns_dnssec_name_new();
357
358         new_name->name = ldns_rr_owner(rr);
359         if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) {
360                 ldns_dnssec_name_free(new_name);
361                 return NULL;
362         }
363
364         return new_name;
365 }
366
367 INLINE void
368 ldns_dnssec_name_free_internal(ldns_dnssec_name *name,
369                                int deep)
370 {
371         if (name) {
372                 if (name->name_alloced) {
373                         ldns_rdf_deep_free(name->name);
374                 }
375                 if (name->rrsets) {
376                         ldns_dnssec_rrsets_free_internal(name->rrsets, deep);
377                 }
378                 if (name->nsec && deep) {
379                         ldns_rr_free(name->nsec);
380                 }
381                 if (name->nsec_signatures) {
382                         ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep);
383                 }
384                 if (name->hashed_name) {
385                         if (deep) {
386                                 ldns_rdf_deep_free(name->hashed_name);
387                         }
388                 }
389                 LDNS_FREE(name);
390         }
391 }
392
393 void
394 ldns_dnssec_name_free(ldns_dnssec_name *name)
395 {
396   ldns_dnssec_name_free_internal(name, 0);
397 }
398
399 void
400 ldns_dnssec_name_deep_free(ldns_dnssec_name *name)
401 {
402   ldns_dnssec_name_free_internal(name, 1);
403 }
404
405 ldns_rdf *
406 ldns_dnssec_name_name(ldns_dnssec_name *name)
407 {
408         if (name) {
409                 return name->name;
410         }
411         return NULL;
412 }
413
414 bool
415 ldns_dnssec_name_is_glue(ldns_dnssec_name *name)
416 {
417         if (name) {
418                 return name->is_glue;
419         }
420         return false;
421 }
422
423 void
424 ldns_dnssec_name_set_name(ldns_dnssec_name *rrset,
425                                          ldns_rdf *dname)
426 {
427         if (rrset && dname) {
428                 rrset->name = dname;
429         }
430 }
431
432 #if 0
433 static ldns_rr *
434 ldns_dnssec_name_nsec(ldns_dnssec_name *rrset)
435 {
436         if (rrset) {
437                 return rrset->nsec;
438         }
439         return NULL;
440 }
441 #endif
442
443 void
444 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec)
445 {
446         if (rrset && nsec) {
447                 rrset->nsec = nsec;
448         }
449 }
450
451 int
452 ldns_dnssec_name_cmp(const void *a, const void *b)
453 {
454         ldns_dnssec_name *na = (ldns_dnssec_name *) a;
455         ldns_dnssec_name *nb = (ldns_dnssec_name *) b;
456
457         if (na && nb) {
458                 return ldns_dname_compare(ldns_dnssec_name_name(na),
459                                                          ldns_dnssec_name_name(nb));
460         } else if (na) {
461                 return 1;
462         } else if (nb) {
463                 return -1;
464         } else {
465                 return 0;
466         }
467 }
468
469 ldns_status
470 ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
471                                     ldns_rr *rr)
472 {
473         ldns_status result = LDNS_STATUS_OK;
474         ldns_rdf *name_name;
475         bool hashed_name = false;
476         ldns_rr_type rr_type;
477         ldns_rr_type typecovered = 0;
478
479         /* special handling for NSEC3 and NSECX covering RRSIGS */
480
481         if (!name || !rr) {
482                 return LDNS_STATUS_ERR;
483         }
484
485         rr_type = ldns_rr_get_type(rr);
486
487         if (rr_type == LDNS_RR_TYPE_RRSIG) {
488                 typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
489         }
490
491 #ifdef HAVE_SSL
492         if (rr_type == LDNS_RR_TYPE_NSEC3 ||
493             typecovered == LDNS_RR_TYPE_NSEC3) {
494                 name_name = ldns_nsec3_hash_name_frm_nsec3(rr,
495                                                                                    ldns_dnssec_name_name(name));
496                 hashed_name = true;
497         } else {
498                 name_name = ldns_dnssec_name_name(name);
499         }
500 #else
501         name_name = ldns_dnssec_name_name(name);
502 #endif /* HAVE_SSL */
503
504         if (rr_type == LDNS_RR_TYPE_NSEC ||
505             rr_type == LDNS_RR_TYPE_NSEC3) {
506                 /* XX check if is already set (and error?) */
507                 name->nsec = rr;
508         } else if (typecovered == LDNS_RR_TYPE_NSEC ||
509                          typecovered == LDNS_RR_TYPE_NSEC3) {
510                 if (name->nsec_signatures) {
511                         result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr);
512                 } else {
513                         name->nsec_signatures = ldns_dnssec_rrs_new();
514                         name->nsec_signatures->rr = rr;
515                 }
516         } else {
517                 /* it's a 'normal' RR, add it to the right rrset */
518                 if (name->rrsets) {
519                         result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
520                 } else {
521                         name->rrsets = ldns_dnssec_rrsets_new();
522                         result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr);
523                 }
524         }
525
526         if (hashed_name) {
527                 ldns_rdf_deep_free(name_name);
528         }
529
530         return result;
531 }
532
533 ldns_dnssec_rrsets *
534 ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
535                                            ldns_rr_type type) {
536         ldns_dnssec_rrsets *result;
537
538         result = name->rrsets;
539         while (result) {
540                 if (result->type == type) {
541                         return result;
542                 } else {
543                         result = result->next;
544                 }
545         }
546         return NULL;
547 }
548
549 ldns_dnssec_rrsets *
550 ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
551                                            ldns_rdf *dname,
552                                            ldns_rr_type type)
553 {
554         ldns_rbnode_t *node;
555
556         if (!zone || !dname) {
557                 return NULL;
558         }
559
560         node = ldns_rbtree_search(zone->names, dname);
561         if (node) {
562                 return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data,
563                                                                         type);
564         } else {
565                 return NULL;
566         }
567 }
568
569 static void
570 ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt,
571                 ldns_dnssec_name *name, 
572                 bool show_soa)
573 {
574         if (name) {
575                 if(name->rrsets) {
576                         ldns_dnssec_rrsets_print_soa_fmt(out, fmt, 
577                                         name->rrsets, true, show_soa);
578                 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
579                         fprintf(out, ";; Empty nonterminal: ");
580                         ldns_rdf_print(out, name->name);
581                         fprintf(out, "\n");
582                 }
583                 if(name->nsec) {
584                         ldns_rr_print_fmt(out, fmt, name->nsec);
585                 }
586                 if (name->nsec_signatures) {
587                         ldns_dnssec_rrs_print_fmt(out, fmt, 
588                                         name->nsec_signatures);
589                 }
590         } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
591                 fprintf(out, "; <void>\n");
592         }
593 }
594
595 #if 0
596 static void
597 ldns_dnssec_name_print_soa(FILE *out, ldns_dnssec_name *name, bool show_soa)
598 {
599         ldns_dnssec_name_print_soa_fmt(out, ldns_output_format_default,
600                        name, show_soa);
601 }
602 #endif
603
604 void
605 ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt,
606                 ldns_dnssec_name *name)
607 {
608         ldns_dnssec_name_print_soa_fmt(out, fmt, name, true);
609 }
610
611 void
612 ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name)
613 {
614         ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name);
615 }
616
617
618 ldns_dnssec_zone *
619 ldns_dnssec_zone_new(void)
620 {
621         ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone);
622         if(!zone) return NULL;
623         zone->soa = NULL;
624         zone->names = NULL;
625
626         return zone;
627 }
628
629 static bool
630 rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t)
631 {
632         return     ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG
633                 && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t;
634 }
635
636 /* When the zone is first read into an list and then inserted into an
637  * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next)
638  * to each other. Because ldns-verify-zone (the only program that uses this
639  * function) uses the rbtree mostly for sequentual walking, this results
640  * in a speed increase (of 15% on linux) because we have less CPU-cache misses.
641  */
642 #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */
643
644 ldns_status
645 ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
646                 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr)
647 {
648         ldns_rr* cur_rr;
649         size_t i;
650
651         ldns_rdf *my_origin = NULL;
652         ldns_rdf *my_prev = NULL;
653
654         ldns_dnssec_zone *newzone = ldns_dnssec_zone_new();
655         /* when reading NSEC3s, there is a chance that we encounter nsecs
656            for empty nonterminals, whose nonterminals we cannot derive yet
657            because the needed information is to be read later. in that case
658            we keep a list of those nsec3's and retry to add them later */
659         ldns_rr_list* todo_nsec3s = ldns_rr_list_new();
660         ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new();
661
662         ldns_status status = LDNS_STATUS_MEM_ERR;
663
664 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
665         ldns_zone* zone = NULL;
666         if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr)
667                         != LDNS_STATUS_OK) goto error;
668 #else
669         uint32_t  my_ttl = ttl;
670 #endif
671
672         if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error;
673
674         if (origin) {
675                 if (!(my_origin = ldns_rdf_clone(origin))) goto error;
676                 if (!(my_prev   = ldns_rdf_clone(origin))) goto error;
677         }
678
679 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
680         if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone))
681                         != LDNS_STATUS_OK) goto error;
682
683         for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
684                 cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i);
685                 status = LDNS_STATUS_OK;
686 #else
687         while (!feof(fp)) {
688                 status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin,
689                                 &my_prev, line_nr);
690
691 #endif
692                 switch (status) {
693                 case LDNS_STATUS_OK:
694
695                         status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
696                         if (status ==
697                                 LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) {
698
699                                 if (rr_is_rrsig_covering(cur_rr,
700                                                         LDNS_RR_TYPE_NSEC3)){
701                                         ldns_rr_list_push_rr(todo_nsec3_rrsigs,
702                                                         cur_rr);
703                                 } else {
704                                         ldns_rr_list_push_rr(todo_nsec3s,
705                                                         cur_rr);
706                                 }
707                         } else if (status != LDNS_STATUS_OK)
708                                 goto error;
709
710                         break;
711
712
713                 case LDNS_STATUS_SYNTAX_EMPTY:  /* empty line was seen */
714                 case LDNS_STATUS_SYNTAX_TTL:    /* the ttl was set*/
715                 case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/
716                         status = LDNS_STATUS_OK;
717                         break;
718
719                 case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */
720                         status =  LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL;
721                         break;
722
723                 default:
724                         goto error;
725                 }
726         }
727
728         if (ldns_rr_list_rr_count(todo_nsec3s) > 0) {
729                 (void) ldns_dnssec_zone_add_empty_nonterminals(newzone);
730                 for (i = 0; status == LDNS_STATUS_OK && 
731                                 i < ldns_rr_list_rr_count(todo_nsec3s); i++) {
732                         cur_rr = ldns_rr_list_rr(todo_nsec3s, i);
733                         status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
734                 }
735                 for (i = 0; status == LDNS_STATUS_OK &&
736                                 i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
737                                 i++){
738                         cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
739                         status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
740                 }
741         } else if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) {
742                 for (i = 0; status == LDNS_STATUS_OK &&
743                                 i < ldns_rr_list_rr_count(todo_nsec3_rrsigs);
744                                 i++){
745                         cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i);
746                         status = ldns_dnssec_zone_add_rr(newzone, cur_rr);
747                 }
748         }
749
750         if (z) {
751                 *z = newzone;
752                 newzone = NULL;
753         } else {
754                 ldns_dnssec_zone_free(newzone);
755         }
756
757 error:
758 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP
759         if (zone) {
760                 ldns_zone_free(zone);
761         }
762 #endif
763         ldns_rr_list_free(todo_nsec3_rrsigs);
764         ldns_rr_list_free(todo_nsec3s);
765
766         if (my_origin) {
767                 ldns_rdf_deep_free(my_origin);
768         }
769         if (my_prev) {
770                 ldns_rdf_deep_free(my_prev);
771         }
772         if (newzone) {
773                 ldns_dnssec_zone_free(newzone);
774         }
775         return status;
776 }
777
778 ldns_status
779 ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin,
780                 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c))
781 {
782         return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL);
783 }
784
785 static void
786 ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) {
787         (void) arg;
788         ldns_dnssec_name_free((ldns_dnssec_name *)node->data);
789         LDNS_FREE(node);
790 }
791
792 static void
793 ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) {
794         (void) arg;
795         ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data);
796         LDNS_FREE(node);
797 }
798
799 void
800 ldns_dnssec_zone_free(ldns_dnssec_zone *zone)
801 {
802         if (zone) {
803                 if (zone->names) {
804                         /* destroy all name structures within the tree */
805                         ldns_traverse_postorder(zone->names,
806                                                     ldns_dnssec_name_node_free,
807                                                     NULL);
808                         LDNS_FREE(zone->names);
809                 }
810                 LDNS_FREE(zone);
811         }
812 }
813
814 void
815 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone)
816 {
817         if (zone) {
818                 if (zone->names) {
819                         /* destroy all name structures within the tree */
820                         ldns_traverse_postorder(zone->names,
821                                                     ldns_dnssec_name_node_deep_free,
822                                                     NULL);
823                         LDNS_FREE(zone->names);
824                 }
825                 LDNS_FREE(zone);
826         }
827 }
828
829 /* use for dname comparison in tree */
830 static int
831 ldns_dname_compare_v(const void *a, const void *b) {
832         return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b);
833 }
834
835 static ldns_rbnode_t *
836 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone,
837                                      ldns_rr *rr) {
838         ldns_rbnode_t *current_node = ldns_rbtree_first(zone->names);
839         ldns_dnssec_name *current_name;
840         ldns_rdf *hashed_name;
841
842         hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0);
843
844         while (current_node != LDNS_RBTREE_NULL) {
845                 current_name = (ldns_dnssec_name *) current_node->data;
846                 if (!current_name->hashed_name) {
847                         current_name->hashed_name =
848                                 ldns_nsec3_hash_name_frm_nsec3(rr, current_name->name);
849                 }
850                 if (ldns_dname_compare(hashed_name,
851                                                    current_name->hashed_name)
852                     == 0) {
853                         ldns_rdf_deep_free(hashed_name);
854                         return current_node;
855                 }
856                 current_node = ldns_rbtree_next(current_node);
857         }
858         ldns_rdf_deep_free(hashed_name);
859         return NULL;
860 }
861
862 ldns_status
863 ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr)
864 {
865         ldns_status result = LDNS_STATUS_OK;
866         ldns_dnssec_name *cur_name;
867         ldns_rbnode_t *cur_node;
868         ldns_rr_type type_covered = 0;
869
870         if (!zone || !rr) {
871                 return LDNS_STATUS_ERR;
872         }
873
874         if (!zone->names) {
875                 zone->names = ldns_rbtree_create(ldns_dname_compare_v);
876                 if(!zone->names) return LDNS_STATUS_MEM_ERR;
877         }
878
879         /* we need the original of the hashed name if this is
880            an NSEC3, or an RRSIG that covers an NSEC3 */
881         if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) {
882                 type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr));
883         }
884         if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 ||
885             type_covered == LDNS_RR_TYPE_NSEC3) {
886                 cur_node = ldns_dnssec_zone_find_nsec3_original(zone,
887                                                                                            rr);
888                 if (!cur_node) {
889                         return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND;
890                 }
891         } else {
892                 cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr));
893         }
894
895         if (!cur_node) {
896                 /* add */
897                 cur_name = ldns_dnssec_name_new_frm_rr(rr);
898                 if(!cur_name) return LDNS_STATUS_MEM_ERR;
899                 cur_node = LDNS_MALLOC(ldns_rbnode_t);
900                 if(!cur_node) {
901                         ldns_dnssec_name_free(cur_name);
902                         return LDNS_STATUS_MEM_ERR;
903                 }
904                 cur_node->key = ldns_rr_owner(rr);
905                 cur_node->data = cur_name;
906                 (void)ldns_rbtree_insert(zone->names, cur_node);
907         } else {
908                 cur_name = (ldns_dnssec_name *) cur_node->data;
909                 result = ldns_dnssec_name_add_rr(cur_name, rr);
910         }
911
912         if (result != LDNS_STATUS_OK) {
913                 fprintf(stderr, "error adding rr: ");
914                 ldns_rr_print(stderr, rr);
915         }
916
917         /*TODO ldns_dnssec_name_print_names(stdout, zone->names, 0);*/
918         if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) {
919                 zone->soa = cur_name;
920         }
921
922         return result;
923 }
924
925 void
926 ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
927                 ldns_rbtree_t *tree, 
928                 bool print_soa)
929 {
930         ldns_rbnode_t *node;
931         ldns_dnssec_name *name;
932
933         node = ldns_rbtree_first(tree);
934         while (node != LDNS_RBTREE_NULL) {
935                 name = (ldns_dnssec_name *) node->data;
936                 ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa);
937                 if ((fmt->flags & LDNS_COMMENT_LAYOUT))
938                         fprintf(out, ";\n");
939                 node = ldns_rbtree_next(node);
940         }
941 }
942
943 void
944 ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa)
945 {
946         ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default,
947                        tree, print_soa);
948 }
949
950 void
951 ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt,
952                ldns_dnssec_zone *zone)
953 {
954         if (zone) {
955                 if (zone->soa) {
956                         if ((fmt->flags & LDNS_COMMENT_LAYOUT)) {
957                                 fprintf(out, ";; Zone: ");
958                                 ldns_rdf_print(out, ldns_dnssec_name_name(
959                                                         zone->soa));
960                                 fprintf(out, "\n;\n");
961                         }
962                         ldns_dnssec_rrsets_print_fmt(out, fmt,
963                                         ldns_dnssec_name_find_rrset(
964                                                 zone->soa, 
965                                                 LDNS_RR_TYPE_SOA), 
966                                         false);
967                         if ((fmt->flags & LDNS_COMMENT_LAYOUT))
968                                 fprintf(out, ";\n");
969                 }
970
971                 if (zone->names) {
972                         ldns_dnssec_zone_names_print_fmt(out, fmt, 
973                                         zone->names, false);
974                 }
975         }
976 }
977
978 void
979 ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone)
980 {
981         ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone);
982 }
983
984 ldns_status
985 ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone)
986 {
987         ldns_dnssec_name *new_name;
988         ldns_rdf *cur_name;
989         ldns_rdf *next_name;
990         ldns_rbnode_t *cur_node, *next_node, *new_node;
991
992         /* for the detection */
993         uint16_t i, cur_label_count, next_label_count;
994         uint16_t soa_label_count = 0;
995         ldns_rdf *l1, *l2;
996         int lpos;
997
998         if (!zone) {
999                 return LDNS_STATUS_ERR;
1000         }
1001         if (zone->soa && zone->soa->name) {
1002                 soa_label_count = ldns_dname_label_count(zone->soa->name);
1003         }
1004         
1005         cur_node = ldns_rbtree_first(zone->names);
1006         while (cur_node != LDNS_RBTREE_NULL) {
1007                 next_node = ldns_rbtree_next(cur_node);
1008                 
1009                 /* skip glue */
1010                 while (next_node != LDNS_RBTREE_NULL && 
1011                        next_node->data &&
1012                        ((ldns_dnssec_name *)next_node->data)->is_glue
1013                 ) {
1014                         next_node = ldns_rbtree_next(next_node);
1015                 }
1016
1017                 if (next_node == LDNS_RBTREE_NULL) {
1018                         next_node = ldns_rbtree_first(zone->names);
1019                 }
1020                 if (! cur_node->data || ! next_node->data) {
1021                         return LDNS_STATUS_ERR;
1022                 }
1023                 cur_name = ((ldns_dnssec_name *)cur_node->data)->name;
1024                 next_name = ((ldns_dnssec_name *)next_node->data)->name;
1025                 cur_label_count = ldns_dname_label_count(cur_name);
1026                 next_label_count = ldns_dname_label_count(next_name);
1027
1028                 /* Since the names are in canonical order, we can
1029                  * recognize empty non-terminals by their labels;
1030                  * every label after the first one on the next owner
1031                  * name is a non-terminal if it either does not exist
1032                  * in the current name or is different from the same
1033                  * label in the current name (counting from the end)
1034                  */
1035                 for (i = 1; i < next_label_count - soa_label_count; i++) {
1036                         lpos = (int)cur_label_count - (int)next_label_count + (int)i;
1037                         if (lpos >= 0) {
1038                                 l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos);
1039                         } else {
1040                                 l1 = NULL;
1041                         }
1042                         l2 = ldns_dname_clone_from(next_name, i);
1043
1044                         if (!l1 || ldns_dname_compare(l1, l2) != 0) {
1045                                 /* We have an empty nonterminal, add it to the
1046                                  * tree
1047                                  */
1048                                 new_name = ldns_dnssec_name_new();
1049                                 if (!new_name) {
1050                                         return LDNS_STATUS_MEM_ERR;
1051                                 }
1052                                 new_name->name = ldns_dname_clone_from(next_name,
1053                                                                        i);
1054                                 if (!new_name->name) {
1055                                         ldns_dnssec_name_free(new_name);
1056                                         return LDNS_STATUS_MEM_ERR;
1057                                 }
1058                                 new_name->name_alloced = true;
1059                                 new_node = LDNS_MALLOC(ldns_rbnode_t);
1060                                 if (!new_node) {
1061                                         ldns_dnssec_name_free(new_name);
1062                                         return LDNS_STATUS_MEM_ERR;
1063                                 }
1064                                 new_node->key = new_name->name;
1065                                 new_node->data = new_name;
1066                                 (void)ldns_rbtree_insert(zone->names, new_node);
1067                         }
1068                         ldns_rdf_deep_free(l1);
1069                         ldns_rdf_deep_free(l2);
1070                 }
1071                 
1072                 /* we might have inserted a new node after
1073                  * the current one so we can't just use next()
1074                  */
1075                 if (next_node != ldns_rbtree_first(zone->names)) {
1076                         cur_node = next_node;
1077                 } else {
1078                         cur_node = LDNS_RBTREE_NULL;
1079                 }
1080         }
1081         return LDNS_STATUS_OK;
1082 }
1083
1084 bool
1085 ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone)
1086 {
1087         ldns_rr* nsec3;
1088         ldns_rbnode_t* node;
1089
1090         if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) {
1091                 node = ldns_rbtree_first(zone->names);
1092                 while (node != LDNS_RBTREE_NULL) {
1093                         nsec3 = ((ldns_dnssec_name*)node->data)->nsec;
1094                         if (nsec3 &&ldns_rr_get_type(nsec3) 
1095                                         == LDNS_RR_TYPE_NSEC3 &&
1096                                         ldns_nsec3_optout(nsec3)) {
1097                                 return true;
1098                         }
1099                         node = ldns_rbtree_next(node);
1100                 }
1101         }
1102         return false;
1103 }