OpenDNSSEC-signer  1.3.9
zone.c
Go to the documentation of this file.
1 /*
2  * $Id: zone.c 6244 2012-04-03 13:56:27Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "adapter/adapi.h"
35 #include "adapter/adapter.h"
36 #include "scheduler/schedule.h"
37 #include "scheduler/task.h"
38 #include "shared/allocator.h"
39 #include "shared/file.h"
40 #include "shared/hsm.h"
41 #include "shared/locks.h"
42 #include "shared/log.h"
43 #include "shared/status.h"
44 #include "shared/util.h"
45 #include "signer/backup.h"
46 #include "signer/nsec3params.h"
47 #include "signer/signconf.h"
48 #include "signer/zone.h"
49 #include "signer/zonedata.h"
50 
51 #include <ldns/ldns.h>
52 
53 static const char* zone_str = "zone";
54 
55 
60 zone_type*
61 zone_create(char* name, ldns_rr_class klass)
62 {
63  allocator_type* allocator = NULL;
64  zone_type* zone = NULL;
65 
66  if (!name || !klass) {
67  ods_log_error("[%s] unable to create zone: no name or class",
68  zone_str);
69  return NULL;
70  }
71 
72  allocator = allocator_create(malloc, free);
73  if (!allocator) {
74  ods_log_error("[%s] unable to create zone %s: create allocator "
75  "failed", zone_str, name);
76  return NULL;
77  }
78  ods_log_assert(allocator);
79 
80  zone = (zone_type*) allocator_alloc(allocator, sizeof(zone_type));
81  if (!zone) {
82  ods_log_error("[%s] unable to create zone %s: allocator failed",
83  zone_str, name);
84  allocator_cleanup(allocator);
85  return NULL;
86  }
87  ods_log_assert(zone);
88 
89  zone->allocator = allocator;
90  /* [start] PS 9218653: Drop trailing dot in domain name */
91  if (strlen(name) > 1 && name[strlen(name)-1] == '.') {
92  name[strlen(name)-1] = '\0';
93  }
94  /* [end] PS 9218653 */
95  zone->name = allocator_strdup(allocator, name);
96  zone->klass = klass;
97 
98  zone->dname = ldns_dname_new_frm_str(name);
99  ldns_dname2canonical(zone->dname);
100  zone->notify_ns = NULL;
101  zone->policy_name = NULL;
102  zone->signconf_filename = NULL;
103 
104  zone->adinbound = NULL;
105  zone->adoutbound = NULL;
106  zone->nsec3params = NULL;
107 
108  zone->just_added = 0;
109  zone->just_updated = 0;
110  zone->tobe_removed = 0;
111  zone->processed = 0;
112  zone->prepared = 0;
113  zone->fetch = 0;
114 
115  zone->zonedata = zonedata_create(zone->allocator);
116  if (!zone->zonedata) {
117  ods_log_error("[%s] unable to create zone %s: create zonedata "
118  "failed", zone_str, name);
119  zone_cleanup(zone);
120  return NULL;
121  }
122 
123  zone->signconf = signconf_create();
124  if (!zone->signconf) {
125  ods_log_error("[%s] unable to create zone %s: create signconf "
126  "failed", zone_str, name);
127  zone_cleanup(zone);
128  return NULL;
129  }
130 
131  zone->stats = stats_create();
132  zone->task = NULL;
133  lock_basic_init(&zone->zone_lock);
134  return zone;
135 }
136 
137 
143 zone_add_rr(zone_type* zone, ldns_rr* rr, int do_stats)
144 {
145  domain_type* domain = NULL;
146  rrset_type* rrset = NULL;
147  ldns_rdf* soa_min = NULL;
148  ldns_rr_type type = LDNS_RR_TYPE_FIRST;
149  uint32_t tmp = 0;
150 
151  if (!rr) {
152  ods_log_error("[%s] unable to add RR: no RR", zone_str);
153  return ODS_STATUS_ASSERT_ERR;
154  }
155  ods_log_assert(rr);
156 
157  if (!zone || !zone->zonedata) {
158  ods_log_error("[%s] unable to add RR: no storage", zone_str);
159  return ODS_STATUS_ASSERT_ERR;
160  }
161  ods_log_assert(zone);
162  ods_log_assert(zone->zonedata);
163 
164  if (!zone->signconf) {
165  ods_log_error("[%s] unable to add RR: no signconf", zone_str);
166  return ODS_STATUS_ASSERT_ERR;
167  }
168  ods_log_assert(zone->signconf);
169 
170  /* in-zone? */
171  if (ldns_dname_compare(zone->dname, ldns_rr_owner(rr)) != 0 &&
172  !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->dname)) {
173  ods_log_warning("[%s] zone %s contains out-of-zone data, skipping",
174  zone_str, zone->name?zone->name:"(null)");
175  /* ok, just filter */
176  ldns_rr_free(rr);
177  return ODS_STATUS_OK;
178  }
179 
180  /* type specific configuration */
181  type = ldns_rr_get_type(rr);
182  if (type == LDNS_RR_TYPE_DNSKEY && zone->signconf->dnskey_ttl) {
183  tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
184  ods_log_verbose("[%s] zone %s set DNSKEY TTL to %u",
185  zone_str, zone->name?zone->name:"(null)", tmp);
186  ldns_rr_set_ttl(rr, tmp);
187  }
188  if (type == LDNS_RR_TYPE_SOA) {
189  if (zone->signconf->soa_ttl) {
190  tmp = (uint32_t) duration2time(zone->signconf->soa_ttl);
191  ods_log_verbose("[%s] zone %s set SOA TTL to %u",
192  zone_str, zone->name?zone->name:"(null)", tmp);
193  ldns_rr_set_ttl(rr, tmp);
194  }
195  if (zone->signconf->soa_min) {
196  tmp = (uint32_t) duration2time(zone->signconf->soa_min);
197  ods_log_verbose("[%s] zone %s set SOA MINIMUM to %u",
198  zone_str, zone->name?zone->name:"(null)", tmp);
199  soa_min = ldns_rr_set_rdf(rr,
200  ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp),
202  if (soa_min) {
203  ldns_rdf_deep_free(soa_min);
204  } else {
205  ods_log_error("[%s] zone %s failed to replace SOA MINIMUM "
206  "rdata", zone_str, zone->name?zone->name:"(null)");
207  return ODS_STATUS_ASSERT_ERR;
208  }
209  }
210  }
211 
212  /* lookup domain */
213  domain = zonedata_lookup_domain(zone->zonedata, ldns_rr_owner(rr));
214  if (!domain) {
215  /* add domain */
216  domain = domain_create(ldns_rr_owner(rr));
217  if (!domain) {
218  ods_log_error("[%s] unable to add RR: create domain failed",
219  zone_str);
220  return ODS_STATUS_ERR;
221  }
222  if (zonedata_add_domain(zone->zonedata, domain) == NULL) {
223  ods_log_error("[%s] unable to add RR: add domain failed",
224  zone_str);
225  return ODS_STATUS_ERR;
226  }
227  if (ldns_dname_compare(domain->dname, zone->dname) == 0) {
228  domain->dstatus = DOMAIN_STATUS_APEX;
229  }
230  }
231  ods_log_assert(domain);
232 
233  /* lookup RRset */
234  rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
235  if (!rrset) {
236  /* add RRset */
237  rrset = rrset_create(ldns_rr_get_type(rr));
238  if (!rrset) {
239  ods_log_error("[%s] unable to add RR: create RRset failed",
240  zone_str);
241  return ODS_STATUS_ERR;
242  }
243  if (domain_add_rrset(domain, rrset) == NULL) {
244  ods_log_error("[%s] unable to add RR: add RRset failed",
245  zone_str);
246  return ODS_STATUS_ERR;
247  }
248  }
249  ods_log_assert(rrset);
250 
251  /* add RR */
252  if (rrset_add_rr(rrset, rr) == NULL) {
253  ods_log_error("[%s] unable to add RR: pend RR failed", zone_str);
254  return ODS_STATUS_ERR;
255  }
256 
257  /* update stats */
258  if (zone->stats && do_stats) {
259  zone->stats->sort_count += 1;
260  }
261  return ODS_STATUS_OK;
262 }
263 
264 
270 zone_del_rr(zone_type* zone, ldns_rr* rr, int do_stats)
271 {
272  domain_type* domain = NULL;
273  rrset_type* rrset = NULL;
274 
275  if (!rr) {
276  ods_log_error("[%s] unable to del RR: no RR", zone_str);
277  return ODS_STATUS_ASSERT_ERR;
278  }
279  ods_log_assert(rr);
280 
281  if (!zone || !zone->zonedata) {
282  ods_log_error("[%s] unable to del RR: no storage", zone_str);
283  return ODS_STATUS_ASSERT_ERR;
284  }
285  ods_log_assert(zone);
286  ods_log_assert(zone->zonedata);
287 
288  /* lookup domain */
289  domain = zonedata_lookup_domain(zone->zonedata, ldns_rr_owner(rr));
290  if (!domain) {
291  /* no domain, no del */
292  ods_log_warning("[%s] unable to del RR: no such domain", zone_str);
293  return ODS_STATUS_UNCHANGED;
294  }
295  ods_log_assert(domain);
296 
297  /* lookup RRset */
298  rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
299  if (!rrset) {
300  /* no RRset, no del */
301  ods_log_warning("[%s] unable to del RR: no such RRset", zone_str);
302  return ODS_STATUS_UNCHANGED;
303  }
304  ods_log_assert(rrset);
305 
306  /* del RR */
307  if (rrset_del_rr(rrset, rr, (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY))
308  == NULL) {
309  ods_log_error("[%s] unable to del RR: pend RR failed", zone_str);
310  return ODS_STATUS_ERR;
311  }
312 
313  /* update stats */
314  if (do_stats && zone->stats) {
315  zone->stats->sort_count -= 1;
316  }
317  return ODS_STATUS_OK;
318 }
319 
320 
325 static ods_status
326 dnskey_withdraw(zone_type* zone, ldns_rr_list* del)
327 {
328  ldns_rr* clone = NULL;
329  ods_status status = ODS_STATUS_OK;
330  size_t i = 0;
331 
332  for (i=0; i < ldns_rr_list_rr_count(del); i++) {
333  clone = ldns_rr_clone(ldns_rr_list_rr(del, i));
334  status = zone_del_rr(zone, clone, 0);
335  if (status != ODS_STATUS_OK) {
336  return status;
337  }
338  }
339  return status;
340 }
341 
342 
347 static ods_status
348 nsec3param_withdraw(zone_type* zone, ldns_rr* rr)
349 {
350  ldns_rr* clone = NULL;
351  ods_status status = ODS_STATUS_OK;
352 
353  if (!rr) { /* no nsec3param, nothing to withdraw */
354  return status;
355  }
356  clone = ldns_rr_clone(rr);
357  status = zone_del_rr(zone, clone, 0);
358  if (status != ODS_STATUS_OK) {
359  return status;
360  }
361  return status;
362 }
363 
364 
371 {
372  ods_status status = ODS_STATUS_OK;
373  signconf_type* signconf = NULL;
374  ldns_rr_list* del = NULL;
375  char* datestamp = NULL;
376  uint32_t ustamp;
377  task_id denial_what;
378  task_id keys_what;
379  task_id what;
380 
381  if (!zone) {
382  ods_log_error("[%s] unable to load signconf: no zone", zone_str);
383  return ODS_STATUS_ASSERT_ERR;
384  }
385  ods_log_assert(zone);
386  if (!zone->signconf_filename) {
387  ods_log_warning("[%s] zone %s has no signconf filename, treat as "
388  "insecure?", zone_str, zone->name);
389  return ODS_STATUS_INSECURE;
390  }
392 
393  status = signconf_update(&signconf, zone->signconf_filename,
394  zone->signconf->last_modified);
395  if (status == ODS_STATUS_OK) {
396  if (!signconf) {
397  /* this is unexpected */
398  ods_log_error("[%s] unable to load signconf: zone %s signconf "
399  "%s: storage empty", zone_str, zone->name,
400  zone->signconf_filename);
401  return ODS_STATUS_ASSERT_ERR;
402  }
403  ustamp = time_datestamp(signconf->last_modified, "%Y-%m-%d %T",
404  &datestamp);
405  ods_log_debug("[%s] zone %s signconf file %s is modified since %s",
406  zone_str, zone->name, zone->signconf_filename,
407  datestamp?datestamp:"Unknown");
408  free((void*)datestamp);
409 
410  /* do stuff */
411  del = ldns_rr_list_new();
412  if (!del) {
413  ods_log_error("[%s] unable to load signconf: zone %s "
414  "signconf %s: ldns_rr_list_new() failed",
415  zone_str, zone->name, zone->signconf_filename);
416  return ODS_STATUS_MALLOC_ERR;
417  }
418  denial_what = signconf_compare_denial(zone->signconf, signconf);
419  keys_what = signconf_compare_keys(zone->signconf, signconf, del);
420 
421  /* Key Rollover? */
422  if (keys_what == TASK_READ) {
423  status = dnskey_withdraw(zone, del);
424  }
425  ldns_rr_list_free(del);
426  if (status != ODS_STATUS_OK) {
427  ods_log_error("[%s] unable to load signconf: zone %s "
428  "signconf %s: failed to delete DNSKEY from RRset",
429  zone_str, zone->name, zone->signconf_filename);
431  return status;
432  }
433 
434  /* Denial of Existence Rollover? */
435  if (denial_what == TASK_NSECIFY) {
436  status = ODS_STATUS_OK;
437  if (denial_what == TASK_NSECIFY && zone->nsec3params) {
438  status = nsec3param_withdraw(zone, zone->nsec3params->rr);
439  }
440  if (status != ODS_STATUS_OK) {
441  ods_log_error("[%s] unable to load signconf: zone %s "
442  "signconf %s: failed to delete NSEC3PARAM RRset",
443  zone_str, zone->name, zone->signconf_filename);
445  return status;
446  }
447  /* or NSEC -> NSEC3, or NSEC3 -> NSEC, or NSEC3PARAM changed */
449  zone->nsec3params = NULL;
450  /* all NSEC(3)s become invalid */
454  }
455 
456  /* all ok, switch to new signconf */
457  if (keys_what != TASK_NONE) {
458  what = keys_what;
459  } else {
460  what = denial_what;
461  }
462  if (what == TASK_NONE) { /* no major changes, continue signing */
463  what = TASK_SIGN;
464  }
465  *tbs = what;
466  ods_log_debug("[%s] tbs for zone %s set to: %s", zone_str,
467  zone->name, task_what2str(*tbs));
468  signconf_cleanup(zone->signconf);
469  ods_log_debug("[%s] zone %s switch to new signconf", zone_str,
470  zone->name);
471  zone->signconf = signconf;
472  signconf_log(zone->signconf, zone->name);
473  zone->zonedata->default_ttl =
474  (uint32_t) duration2time(zone->signconf->soa_min);
475  } else if (status == ODS_STATUS_UNCHANGED) {
476  *tbs = TASK_READ;
477  ods_log_debug("[%s] tbs for zone %s set to: %s", zone_str,
478  zone->name, task_what2str(*tbs));
479  ustamp = time_datestamp(zone->signconf->last_modified,
480  "%Y-%m-%d %T", &datestamp);
481  ods_log_verbose("[%s] zone %s signconf file %s is unchanged since "
482  "%s", zone_str, zone->name, zone->signconf_filename,
483  datestamp?datestamp:"Unknown");
484  free((void*)datestamp);
485  } else {
486  ods_log_error("[%s] unable to load signconf: zone %s signconf %s: "
487  "%s", zone_str, zone->name, zone->signconf_filename,
488  ods_status2str(status));
489  }
490  return status;
491 }
492 
493 
499 zone_publish_dnskeys(zone_type* zone, int recover)
500 {
501  hsm_ctx_t* ctx = NULL;
502  key_type* key = NULL;
503  uint32_t ttl = 0;
504  size_t count = 0;
505  ods_status status = ODS_STATUS_OK;
506  ldns_rr* dnskey = NULL;
507  int do_publish = 0;
508 
509  if (!zone) {
510  ods_log_error("[%s] unable to publish dnskeys: no zone", zone_str);
511  return ODS_STATUS_ASSERT_ERR;
512  }
513  ods_log_assert(zone);
514 
515  if (!zone->signconf) {
516  ods_log_error("[%s] unable to publish dnskeys zone %s: no signconf",
517  zone_str, zone->name);
518  return ODS_STATUS_ASSERT_ERR;
519  }
520  ods_log_assert(zone->signconf);
521 
522  if (!zone->signconf->keys) {
523  ods_log_error("[%s] unable to publish dnskeys zone %s: no keys",
524  zone_str, zone->name);
525  return ODS_STATUS_ASSERT_ERR;
526  }
527  ods_log_assert(zone->signconf->keys);
528 
529  if (!zone->zonedata) {
530  ods_log_error("[%s] unable to publish dnskeys zone %s: no zonedata",
531  zone_str, zone->name);
532  return ODS_STATUS_ASSERT_ERR;
533  }
534  ods_log_assert(zone->zonedata);
535 
536  ttl = zone->zonedata->default_ttl;
537  if (zone->signconf->dnskey_ttl) {
538  ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
539  }
540 
541  /* check connection here? */
542  ctx = hsm_create_context();
543  if (ctx == NULL) {
544  ods_log_error("[%s] unable to publish dnskeys for zone %s: error "
545  "creating libhsm context", zone_str, zone->name);
546  return ODS_STATUS_HSM_ERR;
547  }
548 
549  key = zone->signconf->keys->first_key;
550  for (count=0; count < zone->signconf->keys->count; count++) {
551  if (key->publish) {
552  do_publish = 0;
553  if (!key->dnskey) {
554  do_publish = 1;
555  }
556 
557  status = lhsm_get_key(ctx, zone->dname, key);
558  if (status != ODS_STATUS_OK) {
559  ods_log_error("[%s] unable to publish dnskeys zone %s: "
560  "error creating DNSKEY for key %s", zone_str,
561  zone->name, key->locator?key->locator:"(null)");
562  break;
563  }
564  ods_log_assert(key->dnskey);
565 
566  if (recover) {
567  dnskey = ldns_rr_clone(key->dnskey);
568  status = zone_add_rr(zone, dnskey, 0);
569  } else if (do_publish) {
570  ldns_rr_set_ttl(key->dnskey, ttl);
571  ldns_rr_set_class(key->dnskey, zone->klass);
572  ldns_rr2canonical(key->dnskey);
573  dnskey = ldns_rr_clone(key->dnskey);
574  status = zone_add_rr(zone, dnskey, 0);
575  } else {
576  status = ODS_STATUS_OK;
577  }
578 
579  if (status != ODS_STATUS_OK) {
580  ods_log_error("[%s] unable to publish dnskeys zone %s: "
581  "error adding DNSKEY[%u] for key %s", zone_str,
582  zone->name, ldns_calc_keytag(dnskey),
583  key->locator?key->locator:"(null)");
584  break;
585  }
586  }
587  key = key->next;
588  }
589 
590  if (status != ODS_STATUS_OK) {
592  }
593 
594  hsm_destroy_context(ctx);
595  ctx = NULL;
596  return status;
597 }
598 
599 
605 zone_prepare_nsec3(zone_type* zone, int recover)
606 {
607  ldns_rr* nsec3params_rr = NULL;
608  ods_status status = ODS_STATUS_OK;
609  int doe_rollover = 0;
610 
611  if (!zone) {
612  ods_log_error("[%s] unable to prepare NSEC3: no zone", zone_str);
613  return ODS_STATUS_ASSERT_ERR;
614  }
615  ods_log_assert(zone);
616 
617  if (!zone->signconf) {
618  ods_log_error("[%s] unable to prepare NSEC3: no signconf", zone_str);
619  return ODS_STATUS_ASSERT_ERR;
620  }
621  ods_log_assert(zone->signconf);
622 
623  if (zone->signconf->nsec_type != LDNS_RR_TYPE_NSEC3) {
624  /* no preparations needed */
625  return ODS_STATUS_OK;
626  }
627 
628  if (!zone->nsec3params) {
629  ods_log_debug("[%s] prepare NSEC3 for zone %s", zone_str, zone->name);
630 
632  (uint8_t) zone->signconf->nsec3_algo,
633  (uint8_t) zone->signconf->nsec3_optout,
634  (uint16_t) zone->signconf->nsec3_iterations,
635  zone->signconf->nsec3_salt);
636  doe_rollover = 1;
637  }
638  if (!zone->nsec3params) {
639  ods_log_error("[%s] unable to prepare zone %s for NSEC3: failed "
640  "to create NSEC3 parameters", zone_str, zone->name);
641  return ODS_STATUS_MALLOC_ERR;
642  }
644 
645  if (recover) {
646  nsec3params_rr = ldns_rr_clone(zone->nsec3params->rr);
647  status = zone_add_rr(zone, nsec3params_rr, 0);
648  } else if (doe_rollover) {
649  nsec3params_rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
650  if (!nsec3params_rr) {
651  ods_log_error("[%s] unable to prepare zone %s for NSEC3: failed "
652  "to create NSEC3PARAM RR", zone_str, zone->name);
654  zone->nsec3params = NULL;
655  return ODS_STATUS_MALLOC_ERR;
656  }
657  ods_log_assert(nsec3params_rr);
658 
659  ldns_rr_set_class(nsec3params_rr, zone->klass);
660  ldns_rr_set_ttl(nsec3params_rr, zone->zonedata->default_ttl);
661  ldns_rr_set_owner(nsec3params_rr, ldns_rdf_clone(zone->dname));
662  ldns_nsec3_add_param_rdfs(nsec3params_rr,
663  zone->nsec3params->algorithm, 0,
664  zone->nsec3params->iterations,
665  zone->nsec3params->salt_len,
666  zone->nsec3params->salt_data);
671  ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(nsec3params_rr, 1)), 7, 0);
672 
673  ldns_rr2canonical(nsec3params_rr);
674  zone->nsec3params->rr = ldns_rr_clone(nsec3params_rr);
675  status = zone_add_rr(zone, nsec3params_rr, 0);
676  }
677 
678  if (status != ODS_STATUS_OK) {
679  ods_log_error("[%s] unable to add NSEC3PARAM RR to zone %s",
680  zone_str, zone->name);
682  zone->nsec3params = NULL;
683  ldns_rr_free(nsec3params_rr);
684  }
685  /* previous nsec3params is already withdrawn during load signconf */
686 
687  return status;
688 }
689 
690 
697 {
698  char* filename = NULL;
699  FILE* fd = NULL;
700 
701  ods_log_assert(zone);
702  ods_log_assert(zone->zonedata);
703  ods_log_assert(zone->signconf);
704 
705  filename = ods_build_path(zone->name, ".backup", 0, 1);
706  fd = ods_fopen(filename, NULL, "w");
707  free((void*)filename);
708 
709  if (fd) {
710  fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
712  fprintf(fd, ";;Zone: name %s class %i ttl %u inbound %u internal "
713  "%u outbound %u\n",
714  zone->name?zone->name:"(null)",
715  (int) zone->klass,
716  (unsigned) zone->zonedata->default_ttl,
717  (unsigned) zone->zonedata->inbound_serial,
718  (unsigned) zone->zonedata->internal_serial,
719  (unsigned) zone->zonedata->outbound_serial);
721  if (zone->task) {
722  task_backup(fd, (task_type*) zone->task);
723  }
725  signconf_backup(fd, zone->signconf);
726  fprintf(fd, ";;\n");
728  if (zone->nsec3params) {
730  zone->signconf->nsec3_algo,
731  zone->signconf->nsec3_optout,
732  zone->signconf->nsec3_iterations,
733  zone->signconf->nsec3_salt,
734  zone->nsec3params->rr);
735  }
737  keylist_backup(fd, zone->signconf->keys);
739  zonedata_backup(fd, zone->zonedata);
741  fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
742  ods_fclose(fd);
743  } else {
744  return ODS_STATUS_FOPEN_ERR;
745  }
746  return ODS_STATUS_OK;
747 }
748 
749 
756 {
757  char* filename = NULL;
758  FILE* fd = NULL;
759  const char* token = NULL;
760  ods_status status = ODS_STATUS_OK;
761  /* zone part */
762  int klass = 0;
763  uint32_t ttl = 0;
764  uint32_t inbound = 0;
765  uint32_t internal = 0;
766  uint32_t outbound = 0;
767  /* task part */
768  task_type* task = NULL;
769  time_t when = 0;
770  time_t backoff = 0;
771  int what = 0;
772  int interrupt = 0;
773  int halted = 0;
774  int flush = 0;
775  /* signconf part */
776  time_t lastmod = 0;
777  /* nsec3params part */
778  const char* salt = NULL;
779  ldns_rr* nsec3params_rr = NULL;
780  nsec3params_type* nsec3params = NULL;
781  /* keys part */
782  key_type* key = NULL;
783  /* zonedata part */
784  int fetch = 0;
785 
786  ods_log_assert(zone);
787  ods_log_assert(zone->signconf);
788  ods_log_assert(zone->zonedata);
789 
790  filename = ods_build_path(zone->name, ".backup", 0, 1);
791  fd = ods_fopen(filename, NULL, "r");
792  free((void*)filename);
793  if (fd) {
794  /* start recovery */
795  if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC) ||
796  /* zone part */
797  !backup_read_check_str(fd, ";;Zone:") ||
798  !backup_read_check_str(fd, "name") ||
799  !backup_read_check_str(fd, zone->name) ||
800  !backup_read_check_str(fd, "class") ||
801  !backup_read_int(fd, &klass) ||
802  !backup_read_check_str(fd, "ttl") ||
803  !backup_read_uint32_t(fd, &ttl) ||
804  !backup_read_check_str(fd, "inbound") ||
805  !backup_read_uint32_t(fd, &inbound) ||
806  !backup_read_check_str(fd, "internal") ||
807  !backup_read_uint32_t(fd, &internal) ||
808  !backup_read_check_str(fd, "outbound") ||
809  !backup_read_uint32_t(fd, &outbound) ||
810  /* task part */
811  !backup_read_check_str(fd, ";;Task:") ||
812  !backup_read_check_str(fd, "when") ||
813  !backup_read_time_t(fd, &when) ||
814  !backup_read_check_str(fd, "what") ||
815  !backup_read_int(fd, &what) ||
816  !backup_read_check_str(fd, "interrupt") ||
817  !backup_read_int(fd, &interrupt) ||
818  !backup_read_check_str(fd, "halted") ||
819  !backup_read_int(fd, &halted) ||
820  !backup_read_check_str(fd, "backoff") ||
821  !backup_read_time_t(fd, &backoff) ||
822  !backup_read_check_str(fd, "flush") ||
823  !backup_read_int(fd, &flush) ||
824  /* signconf part */
825  !backup_read_check_str(fd, ";;Signconf:") ||
826  !backup_read_check_str(fd, "lastmod") ||
827  !backup_read_time_t(fd, &lastmod) ||
828  !backup_read_check_str(fd, "resign") ||
830  &zone->signconf->sig_resign_interval) ||
831  !backup_read_check_str(fd, "refresh") ||
833  &zone->signconf->sig_refresh_interval) ||
834  !backup_read_check_str(fd, "valid") ||
836  &zone->signconf->sig_validity_default) ||
837  !backup_read_check_str(fd, "denial") ||
839  &zone->signconf->sig_validity_denial) ||
840  !backup_read_check_str(fd, "jitter") ||
841  !backup_read_duration(fd, &zone->signconf->sig_jitter) ||
842  !backup_read_check_str(fd, "offset") ||
844  &zone->signconf->sig_inception_offset) ||
845  !backup_read_check_str(fd, "nsec") ||
846  !backup_read_rr_type(fd, &zone->signconf->nsec_type) ||
847  !backup_read_check_str(fd, "dnskeyttl") ||
848  !backup_read_duration(fd, &zone->signconf->dnskey_ttl) ||
849  !backup_read_check_str(fd, "soattl") ||
850  !backup_read_duration(fd, &zone->signconf->soa_ttl) ||
851  !backup_read_check_str(fd, "soamin") ||
852  !backup_read_duration(fd, &zone->signconf->soa_min) ||
853  !backup_read_check_str(fd, "serial") ||
854  !backup_read_str(fd, &zone->signconf->soa_serial) ||
855  !backup_read_check_str(fd, "audit") ||
856  !backup_read_int(fd, &zone->signconf->audit) ||
857  !backup_read_check_str(fd, ";;")) {
858  goto recover_error;
859  }
860  /* nsec3params part */
861  if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
862  if (!backup_read_check_str(fd, ";;Nsec3parameters:") ||
863  !backup_read_check_str(fd, "salt") ||
864  !backup_read_str(fd, &salt) ||
865  !backup_read_check_str(fd, "algorithm") ||
866  !backup_read_uint32_t(fd, &zone->signconf->nsec3_algo) ||
867  !backup_read_check_str(fd, "optout") ||
868  !backup_read_int(fd, &zone->signconf->nsec3_optout) ||
869  !backup_read_check_str(fd, "iterations") ||
871  &zone->signconf->nsec3_iterations) ||
872  ldns_rr_new_frm_fp(&nsec3params_rr, fd, NULL, NULL, NULL) ||
873  !backup_read_check_str(fd, ";;Nsec3done") ||
874  !backup_read_check_str(fd, ";;")) {
875  goto recover_error;
876  }
877  }
878  /* keys part */
879  zone->signconf->keys = keylist_create(zone->signconf->allocator);
880  while (backup_read_str(fd, &token)) {
881  if (ods_strcmp(token, ";;Key:") == 0) {
882  key = key_recover(fd, zone->signconf->allocator);
883  if (!key || keylist_push(zone->signconf->keys, key) !=
884  ODS_STATUS_OK) {
885  goto recover_error;
886  }
887  key = NULL;
888  } else if (ods_strcmp(token, ";;") == 0) {
889  /* keylist done */
890  free((void*) token);
891  token = NULL;
892  break;
893  } else {
894  /* keylist corrupted */
895  goto recover_error;
896  }
897  free((void*) token);
898  token = NULL;
899  }
900  /* zonedata part */
901  filename = ods_build_path(zone->name, ".inbound", 0, 1);
902  status = adbackup_read(zone, filename);
903  free((void*)filename);
904  if (status != ODS_STATUS_OK) {
905  goto recover_error;
906  }
907 
908  zone->klass = (ldns_rr_class) klass;
909  zone->zonedata->default_ttl = ttl;
910  zone->zonedata->inbound_serial = inbound;
911  zone->zonedata->internal_serial = internal;
912  zone->zonedata->outbound_serial = outbound;
914  zone->signconf->allocator, salt);
915  free((void*) salt);
916  salt = NULL;
917  task = task_create((task_id) what, when, zone->name, (void*) zone);
918  if (!task) {
919  goto recover_error;
920  }
921  if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
922  nsec3params = nsec3params_create(zone->signconf->nsec3_algo,
923  zone->signconf->nsec3_optout,
924  zone->signconf->nsec3_iterations,
925  zone->signconf->nsec3_salt);
926  if (!nsec3params) {
927  goto recover_error;
928  }
929  nsec3params->rr = nsec3params_rr;
930  zone->nsec3params = nsec3params;
931  }
932  zone->task = (void*) task;
933  zone->signconf->last_modified = lastmod;
934 
940  status = zone_publish_dnskeys(zone, 1);
941  if (status != ODS_STATUS_OK) {
942  zone->task = NULL;
943  zone->nsec3params = NULL;
944  goto recover_error;
945  }
946  status = zone_prepare_nsec3(zone, 1);
947  if (status != ODS_STATUS_OK) {
948  zone->task = NULL;
949  zone->nsec3params = NULL;
950  goto recover_error;
951  }
952  status = zonedata_commit(zone->zonedata);
953  if (status != ODS_STATUS_OK) {
954  zone->task = NULL;
955  zone->nsec3params = NULL;
956  goto recover_error;
957  }
958  status = zonedata_entize(zone->zonedata, zone->dname);
959  if (status != ODS_STATUS_OK) {
960  zone->task = NULL;
961  zone->nsec3params = NULL;
962  goto recover_error;
963  }
964  status = zonedata_recover(zone->zonedata, fd);
965  if (status != ODS_STATUS_OK) {
966  zone->task = NULL;
967  zone->nsec3params = NULL;
968  goto recover_error;
969  }
970  ods_fclose(fd);
971 
972  /* all ok */
973  zone->zonedata->initialized = 1;
974  zone->prepared = 1;
975  if (zone->stats) {
977  stats_clear(zone->stats);
979  }
980  return ODS_STATUS_OK;
981  } else {
982  /* backwards compatible backup recovery (serial) */
983  filename = ods_build_path(zone->name, ".state", 0, 1);
984  fd = ods_fopen(filename, NULL, "r");
985  free((void*)filename);
986  if (fd) {
987  if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V1) ||
988  !backup_read_check_str(fd, ";name:") ||
989  !backup_read_check_str(fd, zone->name) ||
990  !backup_read_check_str(fd, ";class:") ||
991  !backup_read_int(fd, &klass) ||
992  !backup_read_check_str(fd, ";fetch:") ||
993  !backup_read_int(fd, &fetch) ||
994  !backup_read_check_str(fd, ";default_ttl:") ||
995  !backup_read_uint32_t(fd, &ttl) ||
996  !backup_read_check_str(fd, ";inbound_serial:") ||
997  !backup_read_uint32_t(fd, &inbound) ||
998  !backup_read_check_str(fd, ";internal_serial:") ||
999  !backup_read_uint32_t(fd, &internal) ||
1000  !backup_read_check_str(fd, ";outbound_serial:") ||
1001  !backup_read_uint32_t(fd, &outbound) ||
1002  !backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V1))
1003  {
1004  goto recover_error;
1005  }
1006  zone->klass = (ldns_rr_class) klass;
1007  zone->zonedata->default_ttl = ttl;
1008  zone->zonedata->inbound_serial = inbound;
1009  zone->zonedata->internal_serial = internal;
1010  zone->zonedata->outbound_serial = outbound;
1011  /* all ok */
1012  zone->zonedata->initialized = 1;
1013  zone->prepared = 1;
1014  if (zone->stats) {
1015  lock_basic_lock(&zone->stats->stats_lock);
1016  stats_clear(zone->stats);
1018  }
1019  return ODS_STATUS_UNCHANGED;
1020  }
1021  ods_fclose(fd);
1022  }
1023 
1024  return ODS_STATUS_UNCHANGED;
1025 
1026 recover_error:
1027  ods_log_error("[%s] unable to recover zone %s: corrupted file",
1028  zone_str, zone->name);
1029  ods_fclose(fd);
1030 
1031  /* signconf cleanup */
1032  signconf_cleanup(zone->signconf);
1033  zone->signconf = signconf_create();
1034  ods_log_assert(zone->signconf);
1035 
1036  /* task cleanup */
1037  task_cleanup(task);
1038  task = NULL;
1039 
1040  /* nsec3params cleanup */
1041  free((void*)salt);
1042  salt = NULL;
1043 
1044  ldns_rr_free(nsec3params_rr);
1045  nsec3params_rr = NULL;
1046  if (nsec3params) {
1047  nsec3params->rr = NULL;
1048  }
1049  nsec3params_cleanup(nsec3params);
1050  nsec3params = NULL;
1051 
1052  /* zonedata cleanup */
1053  zonedata_cleanup(zone->zonedata);
1054  zone->zonedata = zonedata_create(zone->allocator);
1055  ods_log_assert(zone->zonedata);
1056  /* do keep serial information */
1057  zone->zonedata->inbound_serial = inbound;
1058  zone->zonedata->internal_serial = internal;
1059  zone->zonedata->outbound_serial = outbound;
1060  zone->zonedata->initialized = 1;
1061 
1062  if (zone->stats) {
1063  lock_basic_lock(&zone->stats->stats_lock);
1064  stats_clear(zone->stats);
1066  }
1067  return ODS_STATUS_ERR;
1068 }
1069 
1070 
1075 void
1077 {
1078  const char* str;
1079  adapter_type* adtmp = NULL;
1080 
1081  if (!z1 || !z2) {
1082  return;
1083  }
1084 
1085  /* policy name */
1086  if (ods_strcmp(z2->policy_name, z1->policy_name) != 0) {
1087  if (z2->policy_name) {
1088  str = strdup(z2->policy_name);
1089  if (!str) {
1090  ods_log_error("[%s] failed to merge policy %s name to zone "
1091  "%s", zone_str, z2->policy_name, z1->name);
1092  } else {
1093  free((void*)z1->policy_name);
1094  z1->policy_name = str;
1095  z1->just_updated = 1;
1096  }
1097  } else {
1098  free((void*)z1->policy_name);
1099  z1->policy_name = NULL;
1100  z1->just_updated = 1;
1101  }
1102  }
1103 
1104  /* signconf filename */
1105  if (ods_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) {
1106  if (z2->signconf_filename) {
1107  str = strdup(z2->signconf_filename);
1108  if (!str) {
1109  ods_log_error("[%s] failed to merge signconf filename %s to "
1110  "zone %s", zone_str, z2->policy_name, z1->name);
1111  } else {
1112  free((void*)z1->signconf_filename);
1113  z1->signconf_filename = str;
1114  z1->just_updated = 1;
1115  }
1116  } else {
1117  free((void*)z1->signconf_filename);
1118  z1->signconf_filename = NULL;
1119  z1->just_updated = 1;
1120  }
1121  }
1122 
1123  /* adapters */
1124  if (adapter_compare(z2->adinbound, z1->adinbound) != 0) {
1125  adtmp = z2->adinbound;
1126  z2->adinbound = z1->adinbound;
1127  z1->adinbound = adtmp;
1128  adtmp = NULL;
1129  }
1130  if (adapter_compare(z2->adoutbound, z1->adoutbound) != 0) {
1131  adtmp = z2->adoutbound;
1132  z2->adoutbound = z1->adoutbound;
1133  z1->adoutbound = adtmp;
1134  adtmp = NULL;
1135  }
1136  return;
1137 }
1138 
1139 
1144 ods_status
1146 {
1147  ods_status status = ODS_STATUS_OK;
1148  domain_type* domain = NULL;
1149  rrset_type* rrset = NULL;
1150  ldns_rdf* serial = NULL;
1151 
1152  if (!zone) {
1153  ods_log_error("[%s] unable to update serial: no zone",
1154  zone_str);
1155  return ODS_STATUS_ASSERT_ERR;
1156  }
1157  ods_log_assert(zone);
1158 
1159  if (!zone->signconf) {
1160  ods_log_error("[%s] unable to update serial: no signconf",
1161  zone_str);
1162  return ODS_STATUS_ASSERT_ERR;
1163  }
1164  ods_log_assert(zone->signconf);
1165 
1166  if (!zone->zonedata) {
1167  ods_log_error("[%s] unable to update serial: no zonedata",
1168  zone_str);
1169  return ODS_STATUS_ASSERT_ERR;
1170  }
1171  ods_log_assert(zone->zonedata);
1172 
1173  status = zonedata_update_serial(zone->zonedata, zone->signconf);
1174  if (status != ODS_STATUS_OK) {
1175  ods_log_error("[%s] unable to update serial: failed to increment",
1176  zone_str);
1177  return status;
1178  }
1179 
1180  /* lookup domain */
1181  domain = zonedata_lookup_domain(zone->zonedata, zone->dname);
1182  if (!domain) {
1183  ods_log_error("[%s] unable to update serial: apex not found",
1184  zone_str);
1185  return ODS_STATUS_ERR;
1186  }
1187  ods_log_assert(domain);
1188 
1189  /* lookup RRset */
1190  rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_SOA);
1191  if (!rrset) {
1192  ods_log_error("[%s] unable to update serial: SOA RRset not found",
1193  zone_str);
1194  return ODS_STATUS_ERR;
1195  }
1196  ods_log_assert(rrset);
1197  ods_log_assert(rrset->rr_type == LDNS_RR_TYPE_SOA);
1198 
1199  if (rrset->rrs && rrset->rrs->rr) {
1200  serial = ldns_rr_set_rdf(rrset->rrs->rr,
1201  ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
1203  if (serial) {
1204  if (ldns_rdf2native_int32(serial) !=
1205  zone->zonedata->internal_serial) {
1206  rrset->needs_signing = 1;
1207  }
1208  ldns_rdf_deep_free(serial);
1209  } else {
1210  ods_log_error("[%s] unable to update serial: failed to replace "
1211  "SOA SERIAL rdata", zone_str);
1212  return ODS_STATUS_ERR;
1213  }
1214  }
1215  return ODS_STATUS_OK;
1216 }
1217 
1218 
1223 ods_status
1224 zone_print(FILE* fd, zone_type* zone)
1225 {
1226  if (fd && zone && zone->zonedata) {
1227  return zonedata_print(fd, zone->zonedata);
1228  }
1229  return ODS_STATUS_ASSERT_ERR;
1230 }
1231 
1232 
1237 ods_status
1239 {
1240  if (zone && zone->zonedata && zone->adinbound) {
1241  return zonedata_examine(zone->zonedata, zone->dname,
1242  zone->adinbound->type);
1243  }
1244  return ODS_STATUS_ASSERT_ERR;
1245 }
1246 
1247 
1252 void
1254 {
1255  allocator_type* allocator;
1256  lock_basic_type zone_lock;
1257 
1258  if (!zone) {
1259  return;
1260  }
1261 
1262  allocator = zone->allocator;
1263  zone_lock = zone->zone_lock;
1264 
1265  ldns_rdf_deep_free(zone->dname);
1266  adapter_cleanup(zone->adinbound);
1267  adapter_cleanup(zone->adoutbound);
1268  zonedata_cleanup(zone->zonedata);
1269  signconf_cleanup(zone->signconf);
1271  stats_cleanup(zone->stats);
1272  allocator_deallocate(allocator, (void*) zone->notify_ns);
1273  allocator_deallocate(allocator, (void*) zone->policy_name);
1274  allocator_deallocate(allocator, (void*) zone->signconf_filename);
1275  allocator_deallocate(allocator, (void*) zone->name);
1276  allocator_deallocate(allocator, (void*) zone);
1277  allocator_cleanup(allocator);
1278  lock_basic_destroy(&zone_lock);
1279  return;
1280 }