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