OpenDNSSEC-signer  1.4.5
domain.c
Go to the documentation of this file.
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 
32 #include "config.h"
33 #include "shared/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 
47 void
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  return;
81 }
82 
83 
89 domain_create(void* zoneptr, ldns_rdf* dname)
90 {
91  domain_type* domain = NULL;
92  zone_type* zone = (zone_type*) zoneptr;
93  if (!dname || !zoneptr) {
94  return NULL;
95  }
96  domain = (domain_type*) allocator_alloc(
97  zone->allocator, sizeof(domain_type));
98  if (!domain) {
99  ods_log_error("[%s] unable to create domain: allocator_alloc() "
100  "failed", dname_str);
101  return NULL;
102  }
103  domain->dname = ldns_rdf_clone(dname);
104  if (!domain->dname) {
105  ods_log_error("[%s] unable to create domain: ldns_rdf_clone() "
106  "failed", dname_str);
107  allocator_deallocate(zone->allocator, domain);
108  return NULL;
109  }
110  domain->zone = zoneptr;
111  domain->denial = NULL; /* no reference yet */
112  domain->node = NULL; /* not in db yet */
113  domain->rrsets = NULL;
114  domain->parent = NULL;
115  domain->is_apex = 0;
116  domain->is_new = 0;
117  return domain;
118 }
119 
120 
125 size_t
127 {
128  rrset_type* rrset = NULL;
129  size_t count = 0;
130  if (!domain) {
131  return 0;
132  }
133  rrset = domain->rrsets;
134  while (rrset) {
135  count++; /* rr_count may be zero */
136  rrset = rrset->next;
137  }
138  return count;
139 }
140 
141 
146 size_t
148 {
149  rrset_type* rrset = NULL;
150  size_t count = 0;
151  if (!domain) {
152  return 0;
153  }
154  rrset = domain->rrsets;
155  while (rrset) {
156  if (rrset_count_rr_is_added(rrset)) {
157  count++;
158  }
159  rrset = rrset->next;
160  }
161  return count;
162 }
163 
164 
169 rrset_type*
170 domain_lookup_rrset(domain_type* domain, ldns_rr_type rrtype)
171 {
172  rrset_type* rrset = NULL;
173  if (!domain || !domain->rrsets || !rrtype) {
174  return NULL;
175  }
176  rrset = domain->rrsets;
177  while (rrset && rrset->rrtype != rrtype) {
178  rrset = rrset->next;
179  }
180  return rrset;
181 }
182 
183 
188 void
190 {
191  rrset_type** p = NULL;
192  denial_type* denial = NULL;
193  ods_log_assert(domain);
194  ods_log_assert(rrset);
195  if (!domain->rrsets) {
196  domain->rrsets = rrset;
197  } else {
198  p = &domain->rrsets;
199  while(*p) {
200  p = &((*p)->next);
201  }
202  *p = rrset;
203  rrset->next = NULL;
204  }
205  log_rrset(domain->dname, rrset->rrtype, "+RRSET", LOG_DEEEBUG);
206  rrset->domain = (void*) domain;
207  if (domain->denial) {
208  denial = (denial_type*) domain->denial;
209  denial->bitmap_changed = 1;
210  }
211  return;
212 }
213 
214 
219 rrset_type*
220 domain_del_rrset(domain_type* domain, ldns_rr_type rrtype)
221 {
222  rrset_type* cur = NULL;
223  denial_type* denial = NULL;
224  if (!domain || !rrtype) {
225  return NULL;
226  }
227  if (!domain->rrsets) {
228  ods_log_error("[%s] unable to delete RRset: RRset with RRtype %s "
229  "does not exist", dname_str, rrset_type2str(rrtype));
230  return NULL;
231  }
232  if (domain->rrsets->rrtype == rrtype) {
233  cur = domain->rrsets;
234  domain->rrsets = cur->next;
235  cur->domain = NULL;
236  cur->next = NULL;
237  log_rrset(domain->dname, rrtype, "-RRSET", LOG_DEEEBUG);
238  if (domain->denial) {
239  denial = (denial_type*) domain->denial;
240  denial->bitmap_changed = 1;
241  }
242  return cur;
243  }
244  cur = domain->rrsets;
245  while (cur) {
246  if (!cur->next) {
247  ods_log_error("[%s] unable to delete RRset: RRset with RRtype %s "
248  "does not exist", dname_str, rrset_type2str(rrtype));
249  return NULL;
250  }
251  ods_log_assert(cur->next);
252  if (cur->next->rrtype != rrtype) {
253  cur = cur->next;
254  } else {
255  ods_log_assert(cur->next->rrtype == rrtype);
256  cur->next = cur->next->next;
257  cur = cur->next;
258  cur->domain = NULL;
259  cur->next = NULL;
260  log_rrset(domain->dname, rrtype, "-RRSET", LOG_DEEEBUG);
261  if (domain->denial) {
262  denial = (denial_type*) domain->denial;
263  denial->bitmap_changed = 1;
264  }
265  return cur;
266  }
267  }
268  ods_log_error("[%s] unable to delete RRset: RRset with RRtype %s "
269  "does not exist", dname_str, rrset_type2str(rrtype));
270  return NULL;
271 }
272 
273 
278 void
279 domain_diff(domain_type* domain, unsigned is_ixfr, unsigned more_coming)
280 {
281  denial_type* denial = NULL;
282  rrset_type* rrset = NULL;
283  rrset_type* prev_rrset = NULL;
284 
285  if (!domain) {
286  return;
287  }
288  rrset = domain->rrsets;
289  while (rrset) {
290  if (rrset->rrtype == LDNS_RR_TYPE_NSEC3PARAMS ||
291  rrset->rrtype == LDNS_RR_TYPE_DNSKEY) {
292  /* always do full diff on NSEC3PARAMS | DNSKEY RRset */
293  rrset_diff(rrset, 0, more_coming);
294  } else {
295  rrset_diff(rrset, is_ixfr, more_coming);
296  }
297  if (rrset->rr_count <= 0) {
298  /* delete entire rrset */
299  if (!prev_rrset) {
300  domain->rrsets = rrset->next;
301  } else {
302  prev_rrset->next = rrset->next;
303  }
304  rrset->next = NULL;
305  log_rrset(domain->dname, rrset->rrtype, "-RRSET", LOG_DEEEBUG);
306  rrset_cleanup(rrset);
307  if (!prev_rrset) {
308  rrset = domain->rrsets;
309  } else {
310  rrset = prev_rrset->next;
311  }
312  if (domain->denial) {
313  denial = (denial_type*) domain->denial;
314  denial->bitmap_changed = 1;
315  }
316  } else {
317  /* just go to next rrset */
318  prev_rrset = rrset;
319  rrset = rrset->next;
320  }
321  }
322  return;
323 }
324 
325 
330 void
331 domain_rollback(domain_type* domain, int keepsc)
332 {
333  denial_type* denial = NULL;
334  rrset_type* rrset = NULL;
335  rrset_type* prev_rrset = NULL;
336  ldns_rr* del_rr = NULL;
337  int del_rrset = 0;
338  uint16_t i = 0;
339  if (!domain) {
340  return;
341  }
342  rrset = domain->rrsets;
343  while (rrset) {
344  if (keepsc) {
345  /* skip rollback for NSEC3PARAM and DNSKEY RRset */
346  if (rrset->rrtype == LDNS_RR_TYPE_NSEC3PARAMS ||
347  rrset->rrtype == LDNS_RR_TYPE_DNSKEY) {
348  prev_rrset = rrset;
349  rrset = rrset->next;
350  continue;
351  }
352  }
353  /* walk rrs */
354  for (i=0; i < rrset->rr_count; i++) {
355  rrset->rrs[i].is_added = 0;
356  rrset->rrs[i].is_removed = 0;
357  if (!rrset->rrs[i].exists) {
358  /* can we delete the RRset? */
359  if(rrset->rr_count == 1) {
360  del_rrset = 1;
361  }
362  del_rr = rrset->rrs[i].rr;
363  rrset_del_rr(rrset, i);
364  ldns_rr_free(del_rr);
365  del_rr = NULL;
366  i--;
367  }
368  }
369  /* next rrset */
370  if (del_rrset) {
371  /* delete entire rrset */
372  if (!prev_rrset) {
373  domain->rrsets = rrset->next;
374  } else {
375  prev_rrset->next = rrset->next;
376  }
377  rrset->next = NULL;
378  log_rrset(domain->dname, rrset->rrtype, "-RRSET", LOG_DEEEBUG);
379  rrset_cleanup(rrset);
380  if (!prev_rrset) {
381  rrset = domain->rrsets;
382  } else {
383  rrset = prev_rrset->next;
384  }
385  if (domain->denial) {
386  denial = (denial_type*) domain->denial;
387  denial->bitmap_changed = 0;
388  }
389  del_rrset = 0;
390  } else {
391  /* just go to next rrset */
392  prev_rrset = rrset;
393  rrset = rrset->next;
394  }
395  }
396  return;
397 }
398 
399 
404 int
406 {
407  ldns_rbnode_t* n = LDNS_RBTREE_NULL;
408  domain_type* d = NULL;
409 
410  ods_log_assert(domain);
411  if (domain->rrsets) {
412  return 0; /* not an empty non-terminal */
413  }
414  n = ldns_rbtree_next(domain->node);
415  while (n && n != LDNS_RBTREE_NULL) {
416  d = (domain_type*) n->data;
417  if (!ldns_dname_is_subdomain(d->dname, domain->dname)) {
418  break;
419  }
420  if (d->rrsets) {
421  if (domain_is_delegpt(d) != LDNS_RR_TYPE_NS &&
422  domain_is_occluded(d) == LDNS_RR_TYPE_SOA) {
423  /* domain has signed delegation/auth */
424  return 0;
425  }
426  }
427  /* maybe there is data at the next domain */
428  n = ldns_rbtree_next(n);
429  }
430  return 1;
431 }
432 
433 
438 ldns_rr_type
440 {
441  ods_log_assert(domain);
442  if (domain->is_apex) {
443  return LDNS_RR_TYPE_SOA;
444  }
445  if (domain_lookup_rrset(domain, LDNS_RR_TYPE_NS)) {
446  if (domain_lookup_rrset(domain, LDNS_RR_TYPE_DS)) {
447  /* Signed delegation */
448  return LDNS_RR_TYPE_DS;
449  } else {
450  /* Unsigned delegation */
451  return LDNS_RR_TYPE_NS;
452  }
453  }
454  /* Authoritative */
455  return LDNS_RR_TYPE_SOA;
456 }
457 
458 
463 ldns_rr_type
465 {
466  domain_type* parent = NULL;
467  ods_log_assert(domain);
468  if (domain->is_apex) {
469  return LDNS_RR_TYPE_SOA;
470  }
471  parent = domain->parent;
472  while (parent && !parent->is_apex) {
473  if (domain_lookup_rrset(parent, LDNS_RR_TYPE_NS)) {
474  /* Glue / Empty non-terminal to Glue */
475  return LDNS_RR_TYPE_A;
476  }
477  if (domain_lookup_rrset(parent, LDNS_RR_TYPE_DNAME)) {
478  /* Occluded data / Empty non-terminal to Occluded data */
479  return LDNS_RR_TYPE_DNAME;
480  }
481  parent = parent->parent;
482  }
483  /* Authoritative or delegation */
484  return LDNS_RR_TYPE_SOA;
485 }
486 
487 
492 void
493 domain_print(FILE* fd, domain_type* domain, ods_status* status)
494 {
495  char* str = NULL;
496  rrset_type* rrset = NULL;
497  rrset_type* soa_rrset = NULL;
498  rrset_type* cname_rrset = NULL;
499  if (!domain || !fd) {
500  if (status) {
501  ods_log_crit("[%s] unable to print domain: domain or fd missing",
502  dname_str);
503  *status = ODS_STATUS_ASSERT_ERR;
504  }
505  return;
506  }
507  /* empty non-terminal? */
508  if (!domain->rrsets) {
509  str = ldns_rdf2str(domain->dname);
510  fprintf(fd, ";;Empty non-terminal %s\n", str);
511  free((void*)str);
512  /* Denial of Existence */
513  if (domain->denial) {
514  denial_print(fd, (denial_type*) domain->denial, status);
515  }
516  return;
517  }
518  /* no other data may accompany a CNAME */
519  cname_rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_CNAME);
520  if (cname_rrset) {
521  rrset_print(fd, cname_rrset, 0, status);
522  } else {
523  /* if SOA, print soa first */
524  if (domain->is_apex) {
525  soa_rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_SOA);
526  if (soa_rrset) {
527  rrset_print(fd, soa_rrset, 0, status);
528  if (status && *status != ODS_STATUS_OK) {
529  return;
530  }
531  }
532  }
533  /* print other RRsets */
534  rrset = domain->rrsets;
535  while (rrset) {
536  /* skip SOA RRset */
537  if (rrset->rrtype != LDNS_RR_TYPE_SOA) {
538  rrset_print(fd, rrset, 0, status);
539  }
540  if (status && *status != ODS_STATUS_OK) {
541  ods_log_crit("[%s] failed to print one or more RRsets: %s",
542  dname_str, ods_status2str(*status));
543  return;
544  }
545  rrset = rrset->next;
546  }
547  }
548  /* Denial of Existence */
549  if (domain->denial) {
550  denial_print(fd, (denial_type*) domain->denial, status);
551  }
552  return;
553 }
554 
555 
560 void
562 {
563  zone_type* zone = NULL;
564  if (!domain) {
565  return;
566  }
567  zone = (zone_type*) domain->zone;
568  ldns_rdf_deep_free(domain->dname);
569  rrset_cleanup(domain->rrsets);
570  allocator_deallocate(zone->allocator, (void*)domain);
571  return;
572 }
573 
574 
579 void
580 domain_backup2(FILE* fd, domain_type* domain, int sigs)
581 {
582  rrset_type* rrset = NULL;
583  if (!domain || !fd) {
584  return;
585  }
586  /* if SOA, print soa first */
587  if (domain->is_apex) {
588  rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_SOA);
589  if (rrset) {
590  if (sigs) {
591  rrset_backup2(fd, rrset);
592  } else {
593  rrset_print(fd, rrset, 1, NULL);
594  }
595  }
596  }
597  rrset = domain->rrsets;
598  while (rrset) {
599  /* skip SOA RRset */
600  if (rrset->rrtype != LDNS_RR_TYPE_SOA) {
601  if (sigs) {
602  rrset_backup2(fd, rrset);
603  } else {
604  rrset_print(fd, rrset, 1, NULL);
605  }
606  }
607  rrset = rrset->next;
608  }
609  return;
610 }