1 /*
2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /**
28  * Domain.
29  *
30  */
31 
32 #include "config.h"
33 #include "log.h"
34 #include "signer/backup.h"
35 #include "signer/denial.h"
36 #include "signer/domain.h"
37 #include "signer/ixfr.h"
38 #include "signer/zone.h"
39 
40 static const char* dname_str = "domain";
41 
42 
43 /**
44  * Log domain name.
45  *
46  */
47 void
log_dname(ldns_rdf * rdf,const char * pre,int level)48 log_dname(ldns_rdf *rdf, const char* pre, int level)
49 {
50     char* str = NULL;
51     if (ods_log_get_level() < level) {
52         return;
53     }
54     str = ldns_rdf2str(rdf);
55     if (!str) {
56         return;
57     }
58     if (level == LOG_EMERG) {
59         ods_fatal_exit("[%s] %s: %s", dname_str, pre?pre:"", str);
60     } else if (level == LOG_ALERT) {
61         ods_log_alert("[%s] %s: %s", dname_str, pre?pre:"", str);
62     } else if (level == LOG_CRIT) {
63         ods_log_crit("[%s] %s: %s", dname_str, pre?pre:"", str);
64     } else if (level == LOG_ERR) {
65         ods_log_error("[%s] %s: %s", dname_str, pre?pre:"", str);
66     } else if (level == LOG_WARNING) {
67         ods_log_warning("[%s] %s: %s", dname_str, pre?pre:"", str);
68     } else if (level == LOG_NOTICE) {
69         ods_log_info("[%s] %s: %s", dname_str, pre?pre:"", str);
70     } else if (level == LOG_INFO) {
71         ods_log_verbose("[%s] %s: %s", dname_str, pre?pre:"", str);
72     } else if (level == LOG_DEBUG) {
73         ods_log_debug("[%s] %s: %s", dname_str, pre?pre:"", str);
74     } else if (level == LOG_DEEEBUG) {
75         ods_log_deeebug("[%s] %s: %s", dname_str, pre?pre:"", str);
76     } else {
77         ods_log_deeebug("[%s] %s: %s", dname_str, pre?pre:"", str);
78     }
79     free((void*)str);
80 }
81 
82 
83 /**
84  * Create domain.
85  *
86  */
87 domain_type*
domain_create(zone_type * zone,ldns_rdf * dname)88 domain_create(zone_type* zone, ldns_rdf* dname)
89 {
90     domain_type* domain = NULL;
91     if (!dname || !zone) {
92         return NULL;
93     }
94     CHECKALLOC(domain = (domain_type*) malloc(sizeof(domain_type)));
95     domain->dname = ldns_rdf_clone(dname);
96     if (!domain->dname) {
97         ods_log_error("[%s] unable to create domain: ldns_rdf_clone() "
98             "failed", dname_str);
99         free(domain);
100         return NULL;
101     }
102     domain->zone = zone;
103     domain->denial = NULL; /* no reference yet */
104     domain->node = NULL; /* not in db yet */
105     domain->rrsets = NULL;
106     domain->parent = NULL;
107     domain->is_apex = 0;
108     domain->is_new = 0;
109     return domain;
110 }
111 
112 
113 /**
114  * Count the number of RRsets at this domain with RRs that have is_added.
115  *
116  */
117 size_t
domain_count_rrset_is_added(domain_type * domain)118 domain_count_rrset_is_added(domain_type* domain)
119 {
120     rrset_type* rrset = NULL;
121     size_t count = 0;
122     if (!domain) {
123         return 0;
124     }
125     rrset = domain->rrsets;
126     while (rrset) {
127         if (rrset_count_rr_is_added(rrset)) {
128             count++;
129         }
130         rrset = rrset->next;
131     }
132     return count;
133 }
134 
135 
136 /**
137  * Look up RRset at this domain.
138  *
139  */
140 rrset_type*
domain_lookup_rrset(domain_type * domain,ldns_rr_type rrtype)141 domain_lookup_rrset(domain_type* domain, ldns_rr_type rrtype)
142 {
143     rrset_type* rrset = NULL;
144     if (!domain || !domain->rrsets || !rrtype) {
145         return NULL;
146     }
147     rrset = domain->rrsets;
148     while (rrset && rrset->rrtype != rrtype) {
149         rrset = rrset->next;
150     }
151     return rrset;
152 }
153 
154 
155 /**
156  * Add RRset to domain.
157  *
158  */
159 void
domain_add_rrset(domain_type * domain,rrset_type * rrset)160 domain_add_rrset(domain_type* domain, rrset_type* rrset)
161 {
162     rrset_type** p = NULL;
163     denial_type* denial = NULL;
164     ods_log_assert(domain);
165     ods_log_assert(rrset);
166     if (!domain->rrsets) {
167         domain->rrsets = rrset;
168     } else {
169         p = &domain->rrsets;
170         while(*p) {
171             p = &((*p)->next);
172         }
173         *p = rrset;
174         rrset->next = NULL;
175     }
176     log_rrset(domain->dname, rrset->rrtype, "+RRSET", LOG_DEEEBUG);
177     rrset->domain = (void*) domain;
178     if (domain->denial) {
179         denial = (denial_type*) domain->denial;
180         denial->bitmap_changed = 1;
181     }
182 }
183 
184 
185 /**
186  * Apply differences at domain.
187  *
188  */
189 void
domain_diff(domain_type * domain,unsigned is_ixfr,unsigned more_coming)190 domain_diff(domain_type* domain, unsigned is_ixfr, unsigned more_coming)
191 {
192     denial_type* denial = NULL;
193     rrset_type* rrset = NULL;
194     rrset_type* prev_rrset = NULL;
195 
196     if (!domain) {
197         return;
198     }
199     rrset = domain->rrsets;
200     while (rrset) {
201         if (rrset->rrtype == LDNS_RR_TYPE_NSEC3PARAMS ||
202             rrset->rrtype == LDNS_RR_TYPE_DNSKEY) {
203             /* always do full diff on NSEC3PARAMS | DNSKEY RRset */
204             rrset_diff(rrset, 0, more_coming);
205         } else {
206             rrset_diff(rrset, is_ixfr, more_coming);
207         }
208         if (rrset->rr_count <= 0) {
209             /* delete entire rrset */
210             if (!prev_rrset) {
211                 domain->rrsets = rrset->next;
212             } else {
213                 prev_rrset->next = rrset->next;
214             }
215             rrset->next = NULL;
216             log_rrset(domain->dname, rrset->rrtype, "-RRSET", LOG_DEEEBUG);
217             rrset_cleanup(rrset);
218             if (!prev_rrset) {
219                 rrset = domain->rrsets;
220             } else {
221                 rrset = prev_rrset->next;
222             }
223             if (domain->denial) {
224                 denial = (denial_type*) domain->denial;
225                 denial->bitmap_changed = 1;
226             }
227         } else {
228             /* just go to next rrset */
229             prev_rrset = rrset;
230             rrset = rrset->next;
231         }
232     }
233 }
234 
235 
236 /**
237  * Rollback differences at domain.
238  *
239  */
240 void
domain_rollback(domain_type * domain,int keepsc)241 domain_rollback(domain_type* domain, int keepsc)
242 {
243     denial_type* denial = NULL;
244     rrset_type* rrset = NULL;
245     rrset_type* prev_rrset = NULL;
246     int del_rrset = 0;
247     uint16_t i = 0;
248     if (!domain) {
249         return;
250     }
251     rrset = domain->rrsets;
252     while (rrset) {
253         if (keepsc) {
254             /* skip rollback for NSEC3PARAM and DNSKEY RRset */
255             if (rrset->rrtype == LDNS_RR_TYPE_NSEC3PARAMS ||
256                 rrset->rrtype == LDNS_RR_TYPE_DNSKEY) {
257                 prev_rrset = rrset;
258                 rrset = rrset->next;
259                 continue;
260             }
261         }
262         /* walk rrs */
263         for (i=0; i < rrset->rr_count; i++) {
264             rrset->rrs[i].is_added = 0;
265             rrset->rrs[i].is_removed = 0;
266             if (!rrset->rrs[i].exists) {
267                 /* can we delete the RRset? */
268                 if(rrset->rr_count == 1) {
269                     del_rrset = 1;
270                 }
271                 rrset_del_rr(rrset, i);
272                 i--;
273             }
274         }
275         /* next rrset */
276         if (del_rrset) {
277             /* delete entire rrset */
278             if (!prev_rrset) {
279                 domain->rrsets = rrset->next;
280             } else {
281                 prev_rrset->next = rrset->next;
282             }
283             rrset->next = NULL;
284             log_rrset(domain->dname, rrset->rrtype, "-RRSET", LOG_DEEEBUG);
285             rrset_cleanup(rrset);
286             if (!prev_rrset) {
287                 rrset = domain->rrsets;
288             } else {
289                 rrset = prev_rrset->next;
290             }
291             if (domain->denial) {
292                 denial = (denial_type*) domain->denial;
293                 denial->bitmap_changed = 0;
294             }
295             del_rrset = 0;
296         } else {
297             /* just go to next rrset */
298             prev_rrset = rrset;
299             rrset = rrset->next;
300         }
301     }
302 }
303 
304 
305 /**
306  * Check whether a domain is an empty non-terminal to unsigned delegation.
307  *
308  */
309 int
domain_ent2unsignedns(domain_type * domain)310 domain_ent2unsignedns(domain_type* domain)
311 {
312     ldns_rbnode_t* n = LDNS_RBTREE_NULL;
313     domain_type* d = NULL;
314 
315     ods_log_assert(domain);
316     if (domain->rrsets) {
317         return 0; /* not an empty non-terminal */
318     }
319     n = ldns_rbtree_next(domain->node);
320     while (n && n != LDNS_RBTREE_NULL) {
321         d = (domain_type*) n->data;
322         if (!ldns_dname_is_subdomain(d->dname, domain->dname)) {
323             break;
324         }
325         if (d->rrsets) {
326             if (domain_is_delegpt(d) != LDNS_RR_TYPE_NS &&
327                 domain_is_occluded(d) == LDNS_RR_TYPE_SOA) {
328                 /* domain has signed delegation/auth */
329                 return 0;
330             }
331         }
332         /* maybe there is data at the next domain */
333         n = ldns_rbtree_next(n);
334     }
335     return 1;
336 }
337 
338 
339 /**
340  * Check whether the domain is a delegation point.
341  *
342  */
343 ldns_rr_type
domain_is_delegpt(domain_type * domain)344 domain_is_delegpt(domain_type* domain)
345 {
346     ods_log_assert(domain);
347     if (domain->is_apex) {
348         return LDNS_RR_TYPE_SOA;
349     }
350     if (domain_lookup_rrset(domain, LDNS_RR_TYPE_NS)) {
351         if (domain_lookup_rrset(domain, LDNS_RR_TYPE_DS)) {
352             /* Signed delegation */
353             return LDNS_RR_TYPE_DS;
354         } else {
355             /* Unsigned delegation */
356             return LDNS_RR_TYPE_NS;
357         }
358     }
359     /* Authoritative */
360     return LDNS_RR_TYPE_SOA;
361 }
362 
363 
364 /**
365  * Check whether the domain is occluded.
366  *
367  */
368 ldns_rr_type
domain_is_occluded(domain_type * domain)369 domain_is_occluded(domain_type* domain)
370 {
371     domain_type* parent = NULL;
372     ods_log_assert(domain);
373     if (domain->is_apex) {
374         return LDNS_RR_TYPE_SOA;
375     }
376     parent = domain->parent;
377     while (parent && !parent->is_apex) {
378         if (domain_lookup_rrset(parent, LDNS_RR_TYPE_NS)) {
379             /* Glue / Empty non-terminal to Glue */
380             return LDNS_RR_TYPE_A;
381         }
382         if (domain_lookup_rrset(parent, LDNS_RR_TYPE_DNAME)) {
383             /* Occluded data / Empty non-terminal to Occluded data */
384             return LDNS_RR_TYPE_DNAME;
385         }
386         parent = parent->parent;
387     }
388     /* Authoritative or delegation */
389     return LDNS_RR_TYPE_SOA;
390 }
391 
392 
393 /**
394  * Print domain.
395  *
396  */
397 void
domain_print(FILE * fd,domain_type * domain,ods_status * status)398 domain_print(FILE* fd, domain_type* domain, ods_status* status)
399 {
400     char* str = NULL;
401     rrset_type* rrset = NULL;
402     rrset_type* soa_rrset = NULL;
403     rrset_type* cname_rrset = NULL;
404     if (!domain || !fd) {
405         if (status) {
406             ods_log_crit("[%s] unable to print domain: domain or fd missing",
407                 dname_str);
408             *status = ODS_STATUS_ASSERT_ERR;
409         }
410         return;
411     }
412     /* empty non-terminal? */
413     if (!domain->rrsets) {
414         str = ldns_rdf2str(domain->dname);
415         fprintf(fd, ";;Empty non-terminal %s\n", str);
416         free((void*)str);
417         /* Denial of Existence */
418         if (domain->denial) {
419             denial_print(fd, (denial_type*) domain->denial, status);
420         }
421         return;
422     }
423     /* no other data may accompany a CNAME */
424     cname_rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_CNAME);
425     if (cname_rrset) {
426         rrset_print(fd, cname_rrset, 0, status);
427     } else {
428         /* if SOA, print soa first */
429         if (domain->is_apex) {
430             soa_rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_SOA);
431             if (soa_rrset) {
432                 rrset_print(fd, soa_rrset, 0, status);
433                 if (status && *status != ODS_STATUS_OK) {
434                     return;
435                 }
436             }
437         }
438         /* print other RRsets */
439         rrset = domain->rrsets;
440         while (rrset) {
441             /* skip SOA RRset */
442             if (rrset->rrtype != LDNS_RR_TYPE_SOA) {
443                 rrset_print(fd, rrset, 0, status);
444             }
445             if (status && *status != ODS_STATUS_OK) {
446                 ods_log_crit("[%s] failed to print one or more RRsets: %s",
447                     dname_str, ods_status2str(*status));
448                 return;
449             }
450             rrset = rrset->next;
451         }
452     }
453     /* Denial of Existence */
454     if (domain->denial) {
455         denial_print(fd, (denial_type*) domain->denial, status);
456     }
457 }
458 
459 
460 /**
461  * Clean up domain.
462  *
463  */
464 void
domain_cleanup(domain_type * domain)465 domain_cleanup(domain_type* domain)
466 {
467     if (!domain) {
468         return;
469     }
470     ldns_rdf_deep_free(domain->dname);
471     rrset_cleanup(domain->rrsets);
472     free(domain);
473 }
474 
475 
476 /**
477  * Backup domain.
478  *
479  */
480 void
domain_backup2(FILE * fd,domain_type * domain,int sigs)481 domain_backup2(FILE* fd, domain_type* domain, int sigs)
482 {
483     rrset_type* rrset = NULL;
484     if (!domain || !fd) {
485         return;
486     }
487     /* if SOA, print soa first */
488     if (domain->is_apex) {
489         rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_SOA);
490         if (rrset) {
491             if (sigs) {
492                 rrset_backup2(fd, rrset);
493             } else {
494                 rrset_print(fd, rrset, 1, NULL);
495             }
496         }
497     }
498     rrset = domain->rrsets;
499     while (rrset) {
500         /* skip SOA RRset */
501         if (rrset->rrtype != LDNS_RR_TYPE_SOA) {
502             if (sigs) {
503                 rrset_backup2(fd, rrset);
504             } else {
505                 rrset_print(fd, rrset, 1, NULL);
506             }
507         }
508         rrset = rrset->next;
509     }
510 }
511