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 * Zone.
29 *
30 */
31
32 #include "adapter/adapter.h"
33 #include "file.h"
34 #include "hsm.h"
35 #include "locks.h"
36 #include "log.h"
37 #include "status.h"
38 #include "util.h"
39 #include "signer/backup.h"
40 #include "signer/zone.h"
41 #include "wire/netio.h"
42 #include "compat.h"
43 #include "daemon/signertasks.h"
44
45 #include <ldns/ldns.h>
46
47 static const char* zone_str = "zone";
48
49
50 /**
51 * Create a new zone.
52 *
53 */
54 zone_type*
zone_create(char * name,ldns_rr_class klass)55 zone_create(char* name, ldns_rr_class klass)
56 {
57 zone_type* zone = NULL;
58 int err;
59
60 if (!name || !klass) {
61 return NULL;
62 }
63 CHECKALLOC(zone = (zone_type*) calloc(1, sizeof(zone_type)));
64 /* [start] PS 9218653: Drop trailing dot in domain name */
65 if (strlen(name) > 1 && name[strlen(name)-1] == '.') {
66 name[strlen(name)-1] = '\0';
67 }
68 /* [end] PS 9218653 */
69
70 if (pthread_mutex_init(&zone->zone_lock, NULL)) {
71 free(zone);
72 return NULL;
73 }
74 if (pthread_mutex_init(&zone->xfr_lock, NULL)) {
75 (void)pthread_mutex_destroy(&zone->zone_lock);
76 free(zone);
77 return NULL;
78 }
79
80 zone->name = strdup(name);
81 if (!zone->name) {
82 ods_log_error("[%s] unable to create zone %s: allocator_strdup() "
83 "failed", zone_str, name);
84 zone_cleanup(zone);
85 return NULL;
86 }
87 zone->klass = klass;
88 zone->default_ttl = 3600; /* TODO: configure --default-ttl option? */
89 zone->apex = ldns_dname_new_frm_str(name);
90 /* check zone->apex? */
91 zone->notify_command = NULL;
92 zone->notify_ns = NULL;
93 zone->notify_args = NULL;
94 zone->policy_name = NULL;
95 zone->signconf_filename = NULL;
96 zone->adinbound = NULL;
97 zone->adoutbound = NULL;
98 zone->zl_status = ZONE_ZL_OK;
99 zone->xfrd = NULL;
100 zone->notify = NULL;
101 zone->db = namedb_create((void*)zone);
102 if (!zone->db) {
103 ods_log_error("[%s] unable to create zone %s: namedb_create() "
104 "failed", zone_str, name);
105 zone_cleanup(zone);
106 return NULL;
107 }
108 zone->ixfr = ixfr_create();
109 if (!zone->ixfr) {
110 ods_log_error("[%s] unable to create zone %s: ixfr_create() "
111 "failed", zone_str, name);
112 zone_cleanup(zone);
113 return NULL;
114 }
115 zone->zoneconfigvalid = 0;
116 zone->signconf = signconf_create();
117 if (!zone->signconf) {
118 ods_log_error("[%s] unable to create zone %s: signconf_create() "
119 "failed", zone_str, name);
120 zone_cleanup(zone);
121 return NULL;
122 }
123 zone->stats = stats_create();
124 zone->rrstore = rrset_store_initialize();
125 return zone;
126 }
127
128 /**
129 * Load signer configuration for zone.
130 *
131 */
132 ods_status
zone_load_signconf(zone_type * zone,signconf_type ** new_signconf)133 zone_load_signconf(zone_type* zone, signconf_type** new_signconf)
134 {
135 ods_status status = ODS_STATUS_OK;
136 signconf_type* signconf = NULL;
137 char* datestamp = NULL;
138
139 if (!zone || !zone->name || !zone->signconf) {
140 return ODS_STATUS_ASSERT_ERR;
141 }
142 if (!zone->signconf_filename) {
143 ods_log_warning("[%s] zone %s has no signconf filename, treat as "
144 "insecure?", zone_str, zone->name);
145 return ODS_STATUS_INSECURE;
146 }
147 status = signconf_update(&signconf, zone->signconf_filename,
148 zone->signconf->last_modified);
149 if (status == ODS_STATUS_OK) {
150 if (!signconf) {
151 /* this is unexpected */
152 ods_log_alert("[%s] unable to load signconf for zone %s: signconf "
153 "status ok but no signconf stored", zone_str, zone->name);
154 return ODS_STATUS_ASSERT_ERR;
155 }
156 (void)time_datestamp(signconf->last_modified, "%Y-%m-%d %T",
157 &datestamp);
158 ods_log_debug("[%s] zone %s signconf file %s is modified since %s",
159 zone_str, zone->name, zone->signconf_filename,
160 datestamp?datestamp:"Unknown");
161 free((void*)datestamp);
162 *new_signconf = signconf;
163 } else if (status == ODS_STATUS_UNCHANGED) {
164 /* OPENDNSSEC-686: changes happening within one second will not be
165 * seen
166 */
167 (void)time_datestamp(zone->signconf->last_modified,
168 "%Y-%m-%d %T", &datestamp);
169 ods_log_verbose("[%s] zone %s signconf file %s is unchanged since "
170 "%s", zone_str, zone->name, zone->signconf_filename,
171 datestamp?datestamp:"Unknown");
172 free((void*)datestamp);
173 } else {
174 ods_log_error("[%s] unable to load signconf for zone %s: signconf %s "
175 "%s", zone_str, zone->name, zone->signconf_filename,
176 ods_status2str(status));
177 }
178 return status;
179 }
180
181 /**
182 * Publish the keys as indicated by the signer configuration.
183 *
184 */
185 ods_status
zone_publish_dnskeys(zone_type * zone,int skip_hsm_access)186 zone_publish_dnskeys(zone_type* zone, int skip_hsm_access)
187 {
188 hsm_ctx_t* ctx = NULL;
189 uint32_t ttl = 0;
190 unsigned int i;
191 ods_status status = ODS_STATUS_OK;
192 rrset_type* rrset = NULL;
193 rr_type* dnskey = NULL;
194
195 if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
196 return ODS_STATUS_ASSERT_ERR;
197 }
198 ods_log_assert(zone->name);
199
200 /* hsm access */
201 if (!skip_hsm_access) {
202 ctx = hsm_create_context();
203 if (ctx == NULL) {
204 ods_log_error("[%s] unable to publish keys for zone %s: "
205 "error creating libhsm context", zone_str, zone->name);
206 return ODS_STATUS_HSM_ERR;
207 }
208 }
209 ttl = zone->default_ttl;
210 /* dnskey ttl */
211 if (zone->signconf->dnskey_ttl) {
212 ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
213 }
214 /* publish keys */
215 for (i=0; i < zone->signconf->keys->count; i++) {
216 if (!zone->signconf->keys->keys[i].publish) {
217 continue;
218 }
219 if (!zone->signconf->keys->keys[i].dnskey) {
220 /* get dnskey */
221 if (zone->signconf->keys->keys[i].resourcerecord) {
222 if ((status = rrset_getliteralrr(&zone->signconf->keys->keys[i].dnskey, zone->signconf->keys->keys[i].resourcerecord, ttl, zone->apex)) != ODS_STATUS_OK) {
223 ods_log_error("[%s] unable to publish dnskeys for zone %s: "
224 "error decoding literal dnskey", zone_str, zone->name);
225 if (!skip_hsm_access) {
226 hsm_destroy_context(ctx);
227 }
228 return status;
229 }
230 } else {
231 status = lhsm_get_key(ctx, zone->apex,
232 &zone->signconf->keys->keys[i], skip_hsm_access);
233 if (status != ODS_STATUS_OK) {
234 ods_log_error("[%s] unable to publish dnskeys for zone %s: "
235 "error creating dnskey", zone_str, zone->name);
236 break;
237 }
238 }
239 }
240 ods_log_debug("[%s] publish %s DNSKEY locator %s", zone_str,
241 zone->name, zone->signconf->keys->keys[i].locator);
242 if (!skip_hsm_access) {
243 ods_log_assert(zone->signconf->keys->keys[i].dnskey);
244 ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl);
245 ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass);
246 status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0);
247 if (status == ODS_STATUS_UNCHANGED) {
248 /* rr already exists, adjust pointer */
249 rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
250 ods_log_assert(rrset);
251 dnskey = rrset_lookup_rr(rrset,
252 zone->signconf->keys->keys[i].dnskey);
253 ods_log_assert(dnskey);
254 if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) {
255 ldns_rr_free(zone->signconf->keys->keys[i].dnskey);
256 }
257 zone->signconf->keys->keys[i].dnskey = dnskey->rr;
258 status = ODS_STATUS_OK;
259 } else if (status != ODS_STATUS_OK) {
260 ods_log_error("[%s] unable to publish dnskeys for zone %s: "
261 "error adding dnskey", zone_str, zone->name);
262 break;
263 }
264 }
265 }
266 /* done */
267 if (!skip_hsm_access) {
268 hsm_destroy_context(ctx);
269 }
270 return status;
271 }
272
273
274 /**
275 * Unlink DNSKEY RRs.
276 *
277 */
278 void
zone_rollback_dnskeys(zone_type * zone)279 zone_rollback_dnskeys(zone_type* zone)
280 {
281 uint16_t i = 0;
282 rrset_type* rrset = NULL;
283 rr_type* dnskey = NULL;
284 if (!zone || !zone->signconf || !zone->signconf->keys) {
285 return;
286 }
287 rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
288 /* unlink dnskey rrs */
289 for (i=0; i < zone->signconf->keys->count; i++) {
290 if (rrset && zone->signconf->keys->keys[i].dnskey) {
291 dnskey = rrset_lookup_rr(rrset, zone->signconf->keys->keys[i].dnskey);
292 /* always remove the DNSKEY record when rollback is requested, as we don't know how to
293 * distinguish reading an empty file or reading a failed input set.
294 */
295 zone->signconf->keys->keys[i].dnskey = NULL;
296 }
297 }
298 }
299
300
301 /**
302 * Publish the NSEC3 parameters as indicated by the signer configuration.
303 *
304 */
305 ods_status
zone_publish_nsec3param(zone_type * zone)306 zone_publish_nsec3param(zone_type* zone)
307 {
308 rrset_type* rrset = NULL;
309 rr_type* n3prr = NULL;
310 ldns_rr* rr = NULL;
311 ods_status status = ODS_STATUS_OK;
312
313 if (!zone || !zone->name || !zone->db || !zone->signconf) {
314 return ODS_STATUS_ASSERT_ERR;
315 }
316 if (!zone->signconf->nsec3params) {
317 /* NSEC */
318 ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC);
319 return ODS_STATUS_OK;
320 }
321
322 if (!zone->signconf->nsec3params->rr) {
323 uint32_t paramttl =
324 (uint32_t) duration2time(zone->signconf->nsec3param_ttl);
325 rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
326 if (!rr) {
327 ods_log_error("[%s] unable to publish nsec3params for zone %s: "
328 "error creating rr (%s)", zone_str, zone->name,
329 ods_status2str(status));
330 return ODS_STATUS_MALLOC_ERR;
331 }
332 ldns_rr_set_class(rr, zone->klass);
333 ldns_rr_set_ttl(rr, paramttl);
334 ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex));
335 ldns_nsec3_add_param_rdfs(rr,
336 zone->signconf->nsec3params->algorithm, 0,
337 zone->signconf->nsec3params->iterations,
338 zone->signconf->nsec3params->salt_len,
339 zone->signconf->nsec3params->salt_data);
340 /**
341 * Always set bit 7 of the flags to zero,
342 * according to rfc5155 section 11
343 */
344 ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0);
345 zone->signconf->nsec3params->rr = rr;
346 }
347
348 /* Delete all nsec3param rrs. */
349 (void) zone_del_nsec3params(zone);
350
351 ods_log_assert(zone->signconf->nsec3params->rr);
352 status = zone_add_rr(zone, ldns_rr_clone(zone->signconf->nsec3params->rr), 0);
353 if (status == ODS_STATUS_UNCHANGED) {
354 status = ODS_STATUS_OK;
355 } else if (status != ODS_STATUS_OK) {
356 ods_log_error("[%s] unable to publish nsec3params for zone %s: "
357 "error adding nsec3params (%s)", zone_str,
358 zone->name, ods_status2str(status));
359 }
360 return status;
361 }
362
363
364 /**
365 * Unlink NSEC3PARAM RR.
366 *
367 */
368 void
zone_rollback_nsec3param(zone_type * zone)369 zone_rollback_nsec3param(zone_type* zone)
370 {
371 rrset_type* rrset = NULL;
372 rr_type* n3prr = NULL;
373
374 if (!zone || !zone->signconf || !zone->signconf->nsec3params) {
375 return;
376 }
377 rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS);
378 if (rrset && zone->signconf->nsec3params->rr) {
379 n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr);
380 if (n3prr && !n3prr->exists &&
381 n3prr->rr == zone->signconf->nsec3params->rr) {
382 zone->signconf->nsec3params->rr = NULL;
383 }
384 }
385 }
386
387
388 /**
389 * Prepare keys for signing.
390 *
391 */
392 ods_status
zone_prepare_keys(zone_type * zone)393 zone_prepare_keys(zone_type* zone)
394 {
395 hsm_ctx_t* ctx = NULL;
396 int skip_hsm_access;
397 uint16_t i = 0;
398 ods_status status = ODS_STATUS_OK;
399
400 if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
401 return ODS_STATUS_ASSERT_ERR;
402 }
403 ods_log_assert(zone->name);
404 /* hsm access */
405 ctx = hsm_create_context();
406 if (ctx == NULL) {
407 ods_log_error("[%s] unable to prepare signing keys for zone %s: error creating libhsm context", zone_str, zone->name);
408 return ODS_STATUS_HSM_ERR;
409 }
410 /* prepare keys */
411 for (i=0; i < zone->signconf->keys->count; i++) {
412 if(zone->signconf->dnskey_signature != NULL && zone->signconf->keys->keys[i].ksk)
413 continue;
414 /* get dnskey */
415 skip_hsm_access = (zone->signconf->keys->keys[i].publish || zone->signconf->keys->keys[i].zsk || zone->signconf->keys->keys[i].ksk ? 0 : 1);
416 status = lhsm_get_key(ctx, zone->apex, &zone->signconf->keys->keys[i], skip_hsm_access);
417 if (status != ODS_STATUS_OK) {
418 ods_log_error("[%s] unable to prepare signing keys for zone %s: error getting dnskey", zone_str, zone->name);
419 break;
420 }
421 ods_log_assert(zone->signconf->keys->keys[i].params);
422 }
423 /* done */
424 hsm_destroy_context(ctx);
425 return status;
426 }
427
428
429 /**
430 * Update serial.
431 *
432 */
433 ods_status
zone_update_serial(zone_type * zone)434 zone_update_serial(zone_type* zone)
435 {
436 ods_status status = ODS_STATUS_OK;
437 rrset_type* rrset = NULL;
438 rr_type* soa = NULL;
439 ldns_rr* rr = NULL;
440 ldns_rdf* soa_rdata = NULL;
441
442 ods_log_assert(zone);
443 ods_log_assert(zone->apex);
444 ods_log_assert(zone->name);
445 ods_log_assert(zone->db);
446 ods_log_assert(zone->signconf);
447
448 if (zone->db->serial_updated) {
449 /* already done, unmark and return ok */
450 ods_log_debug("[%s] zone %s soa serial already up to date",
451 zone_str, zone->name);
452 zone->db->serial_updated = 0;
453 return ODS_STATUS_OK;
454 }
455 rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
456 if (!rrset || !rrset->rrs || !rrset->rrs[0].rr) {
457 ods_log_error("[%s] unable to update zone %s soa serial: failed to "
458 "find soa rrset", zone_str, zone->name);
459 return ODS_STATUS_ERR;
460 }
461 ods_log_assert(rrset);
462 ods_log_assert(rrset->rrs);
463 ods_log_assert(rrset->rrs[0].rr);
464 rr = ldns_rr_clone(rrset->rrs[0].rr);
465 if (!rr) {
466 ods_log_error("[%s] unable to update zone %s soa serial: failed to "
467 "clone soa rr", zone_str, zone->name);
468 return ODS_STATUS_ERR;
469 }
470 status = namedb_update_serial(zone->db, zone->name,
471 zone->signconf->soa_serial, zone->db->inbserial);
472 if (status != ODS_STATUS_OK) {
473 ods_log_error("[%s] unable to update zone %s soa serial: %s",
474 zone_str, zone->name, ods_status2str(status));
475 if (status == ODS_STATUS_CONFLICT_ERR) {
476 ods_log_error("[%s] If this is the result of a key rollover, "
477 "please increment the serial in the unsigned zone %s",
478 zone_str, zone->name);
479 }
480 ldns_rr_free(rr);
481 return status;
482 }
483 ods_log_verbose("[%s] zone %s set soa serial to %u", zone_str,
484 zone->name, zone->db->intserial);
485 soa_rdata = ldns_rr_set_rdf(rr,
486 ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
487 zone->db->intserial), SE_SOA_RDATA_SERIAL);
488 if (soa_rdata) {
489 ldns_rdf_deep_free(soa_rdata);
490 soa_rdata = NULL;
491 } else {
492 ods_log_error("[%s] unable to update zone %s soa serial: failed to "
493 "replace soa serial rdata", zone_str, zone->name);
494 ldns_rr_free(rr);
495 return ODS_STATUS_ERR;
496 }
497 soa = rrset_add_rr(rrset, rr);
498 ods_log_assert(soa);
499 rrset_diff(rrset, 0, 0);
500 zone->db->serial_updated = 0;
501 return ODS_STATUS_OK;
502 }
503
504
505 /**
506 * Lookup RRset.
507 *
508 */
509 rrset_type*
zone_lookup_rrset(zone_type * zone,ldns_rdf * owner,ldns_rr_type type)510 zone_lookup_rrset(zone_type* zone, ldns_rdf* owner, ldns_rr_type type)
511 {
512 domain_type* domain = NULL;
513 if (!zone || !owner || !type) {
514 return NULL;
515 }
516 domain = namedb_lookup_domain(zone->db, owner);
517 if (!domain) {
518 return NULL;
519 }
520 return domain_lookup_rrset(domain, type);
521 }
522
523
524 /**
525 * Add RR.
526 *
527 */
528 ods_status
zone_add_rr(zone_type * zone,ldns_rr * rr,int do_stats)529 zone_add_rr(zone_type* zone, ldns_rr* rr, int do_stats)
530 {
531 domain_type* domain = NULL;
532 rrset_type* rrset = NULL;
533 rr_type* record = NULL;
534 ods_status status = ODS_STATUS_OK;
535
536 ods_log_assert(rr);
537 ods_log_assert(zone);
538 ods_log_assert(zone->name);
539 ods_log_assert(zone->db);
540 ods_log_assert(zone->signconf);
541 /* If we already have this RR, return ODS_STATUS_UNCHANGED */
542 domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
543 if (!domain) {
544 domain = namedb_add_domain(zone->db, ldns_rr_owner(rr));
545 if (!domain) {
546 ods_log_error("[%s] unable to add RR to zone %s: "
547 "failed to add domain", zone_str, zone->name);
548 return ODS_STATUS_ERR;
549 }
550 if (ldns_dname_compare(domain->dname, zone->apex) == 0) {
551 domain->is_apex = 1;
552 } else {
553 status = namedb_domain_entize(zone->db, domain, zone->apex);
554 if (status != ODS_STATUS_OK) {
555 ods_log_error("[%s] unable to add RR to zone %s: "
556 "failed to entize domain", zone_str, zone->name);
557 return ODS_STATUS_ERR;
558 }
559 }
560 }
561 rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
562 if (!rrset) {
563 rrset = rrset_create(domain->zone, ldns_rr_get_type(rr));
564 if (!rrset) {
565 ods_log_error("[%s] unable to add RR to zone %s: "
566 "failed to add RRset", zone_str, zone->name);
567 return ODS_STATUS_ERR;
568 }
569 domain_add_rrset(domain, rrset);
570 }
571 record = rrset_lookup_rr(rrset, rr);
572
573 uint32_t ttl_rr = ldns_rr_ttl(rr);
574 uint32_t ttl_rrset = rrset_lookup_ttl(rrset, ttl_rr);
575
576 if (record && ttl_rr == ttl_rrset && ttl_rr == ldns_rr_ttl(record->rr)) {
577 record->is_added = 1; /* already exists, just mark added */
578 record->is_removed = 0; /* unset is_removed */
579 return ODS_STATUS_UNCHANGED;
580 } else {
581 record = rrset_add_rr(rrset, rr);
582 ods_log_assert(record);
583 ods_log_assert(record->rr);
584 ods_log_assert(record->is_added);
585 if (ttl_rr != ttl_rrset) {
586 char *str = ldns_rr2str(rr);
587 str[(strlen(str)) - 1] = '\0';
588 for (int i = 0; i < strlen(str); i++) {
589 if (str[i] == '\t') {
590 str[i] = ' ';
591 }
592 }
593 ods_log_error("In zone file %s: TTL for the record '%s' (%d) not"
594 " equal to recordset TTL (%d)", zone->name, str, ttl_rr, ttl_rrset);
595 LDNS_FREE(str);
596 }
597 }
598 /* update stats */
599 if (do_stats && zone->stats) {
600 zone->stats->sort_count += 1;
601 }
602 return ODS_STATUS_OK;
603 }
604
605
606 /**
607 * Delete RR.
608 *
609 */
610 ods_status
zone_del_rr(zone_type * zone,ldns_rr * rr,int do_stats)611 zone_del_rr(zone_type* zone, ldns_rr* rr, int do_stats)
612 {
613 domain_type* domain = NULL;
614 rrset_type* rrset = NULL;
615 rr_type* record = NULL;
616 ods_log_assert(rr);
617 ods_log_assert(zone);
618 ods_log_assert(zone->name);
619 ods_log_assert(zone->db);
620 ods_log_assert(zone->signconf);
621 domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
622 if (!domain) {
623 ods_log_warning("[%s] unable to delete RR from zone %s: "
624 "domain not found", zone_str, zone->name);
625 return ODS_STATUS_UNCHANGED;
626 }
627 rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
628 if (!rrset) {
629 ods_log_warning("[%s] unable to delete RR from zone %s: "
630 "RRset not found", zone_str, zone->name);
631 return ODS_STATUS_UNCHANGED;
632 }
633 record = rrset_lookup_rr(rrset, rr);
634 if (!record) {
635 ods_log_error("[%s] unable to delete RR from zone %s: "
636 "RR not found", zone_str, zone->name);
637 return ODS_STATUS_UNCHANGED;
638 }
639
640 record->is_removed = 1;
641 record->is_added = 0; /* unset is_added */
642 /* update stats */
643 if (do_stats && zone->stats) {
644 zone->stats->sort_count -= 1;
645 }
646 return ODS_STATUS_OK;
647 }
648
649 /**
650 * Delete NSEC3PARAM RRs.
651 *
652 * Marks all NSEC3PARAM records as removed.
653 */
654 ods_status
zone_del_nsec3params(zone_type * zone)655 zone_del_nsec3params(zone_type* zone)
656 {
657 domain_type* domain = NULL;
658 rrset_type* rrset = NULL;
659 int i;
660
661 ods_log_assert(zone);
662 ods_log_assert(zone->name);
663 ods_log_assert(zone->db);
664
665 domain = namedb_lookup_domain(zone->db, zone->apex);
666 if (!domain) {
667 ods_log_verbose("[%s] unable to delete RR from zone %s: "
668 "domain not found", zone_str, zone->name);
669 return ODS_STATUS_UNCHANGED;
670 }
671
672 rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_NSEC3PARAMS);
673 if (!rrset) {
674 ods_log_verbose("[%s] NSEC3PARAM in zone %s not found: "
675 "skipping delete", zone_str, zone->name);
676 return ODS_STATUS_UNCHANGED;
677 }
678
679 /* We don't actually delete the record as we still need the
680 * information in the IXFR. Just set it as removed. The code
681 * inserting the new record may flip this flag when the record
682 * hasn't changed. */
683 for (i=0; i < rrset->rr_count; i++) {
684 rrset->rrs[i].is_removed = 1;
685 }
686 return ODS_STATUS_OK;
687 }
688
689 /**
690 * Merge zones.
691 *
692 */
693 void
zone_merge(zone_type * z1,zone_type * z2)694 zone_merge(zone_type* z1, zone_type* z2)
695 {
696 const char* str;
697 adapter_type* adtmp = NULL;
698
699 if (!z1 || !z2) {
700 return;
701 }
702 /* policy name */
703 if (ods_strcmp(z2->policy_name, z1->policy_name) != 0) {
704 if (z2->policy_name) {
705 str = strdup(z2->policy_name);
706 if (!str) {
707 ods_log_error("[%s] failed to merge policy %s name to zone "
708 "%s", zone_str, z2->policy_name, z1->name);
709 } else {
710 free((void*)z1->policy_name);
711 z1->policy_name = str;
712 z1->zl_status = ZONE_ZL_UPDATED;
713 }
714 } else {
715 free((void*)z1->policy_name);
716 z1->policy_name = NULL;
717 z1->zl_status = ZONE_ZL_UPDATED;
718 }
719 }
720 /* signconf filename */
721 if (ods_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) {
722 if (z2->signconf_filename) {
723 str = strdup(z2->signconf_filename);
724 if (!str) {
725 ods_log_error("[%s] failed to merge signconf filename %s to "
726 "zone %s", zone_str, z2->policy_name, z1->name);
727 } else {
728 free((void*)z1->signconf_filename);
729 z1->signconf_filename = str;
730 z1->zl_status = ZONE_ZL_UPDATED;
731 }
732 } else {
733 free((void*)z1->signconf_filename);
734 z1->signconf_filename = NULL;
735 z1->zl_status = ZONE_ZL_UPDATED;
736 }
737 }
738 /* adapters */
739 if (adapter_compare(z2->adinbound, z1->adinbound) != 0) {
740 adtmp = z2->adinbound;
741 z2->adinbound = z1->adinbound;
742 z1->adinbound = adtmp;
743 adtmp = NULL;
744 }
745 if (adapter_compare(z2->adoutbound, z1->adoutbound) != 0) {
746 adtmp = z2->adoutbound;
747 z2->adoutbound = z1->adoutbound;
748 z1->adoutbound = adtmp;
749 adtmp = NULL;
750 }
751 }
752
753
754 /**
755 * Clean up zone.
756 *
757 */
758 void
zone_cleanup(zone_type * zone)759 zone_cleanup(zone_type* zone)
760 {
761 if (!zone) {
762 return;
763 }
764 pthread_mutex_lock(&zone->zone_lock);
765 ldns_rdf_deep_free(zone->apex);
766 adapter_cleanup(zone->adinbound);
767 adapter_cleanup(zone->adoutbound);
768 namedb_cleanup(zone->db);
769 ixfr_cleanup(zone->ixfr);
770 xfrd_cleanup(zone->xfrd, 1);
771 notify_cleanup(zone->notify);
772 signconf_cleanup(zone->signconf);
773 pthread_mutex_unlock(&zone->zone_lock);
774 stats_cleanup(zone->stats);
775 free(zone->notify_command);
776 free(zone->notify_args);
777 free((void*)zone->policy_name);
778 free((void*)zone->signconf_filename);
779 free((void*)zone->name);
780 collection_class_destroy(&zone->rrstore);
781 pthread_mutex_destroy(&zone->xfr_lock);
782 pthread_mutex_destroy(&zone->zone_lock);
783 free(zone);
784 }
785
786
787 /**
788 * Recover zone from backup.
789 *
790 */
791 ods_status
zone_recover2(engine_type * engine,zone_type * zone)792 zone_recover2(engine_type* engine, zone_type* zone)
793 {
794 char* filename = NULL;
795 FILE* fd = NULL;
796 const char* token = NULL;
797 time_t when = 0;
798 ods_status status = ODS_STATUS_OK;
799 /* zone part */
800 int klass = 0;
801 uint32_t inbound = 0, internal = 0, outbound = 0;
802 /* signconf part */
803 time_t lastmod = 0;
804 /* nsec3params part */
805 const char* salt = NULL;
806
807 ods_log_assert(zone);
808 ods_log_assert(zone->name);
809 ods_log_assert(zone->signconf);
810 ods_log_assert(zone->db);
811
812 filename = ods_build_path(zone->name, ".backup2", 0, 1);
813 if (!filename) {
814 return ODS_STATUS_MALLOC_ERR;
815 }
816 fd = ods_fopen(filename, NULL, "r");
817 if (fd) {
818 /* start recovery */
819 if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V3)) {
820 ods_log_error("[%s] corrupted backup file zone %s: read magic "
821 "error", zone_str, zone->name);
822 goto recover_error2;
823 }
824 if (!backup_read_check_str(fd, ";;Time:") |
825 !backup_read_time_t(fd, &when)) {
826 ods_log_error("[%s] corrupted backup file zone %s: read time "
827 "error", zone_str, zone->name);
828 goto recover_error2;
829 }
830 /* zone stuff */
831 if (!backup_read_check_str(fd, ";;Zone:") |
832 !backup_read_check_str(fd, "name") |
833 !backup_read_check_str(fd, zone->name)) {
834 ods_log_error("[%s] corrupted backup file zone %s: read name "
835 "error", zone_str, zone->name);
836 goto recover_error2;
837 }
838 if (!backup_read_check_str(fd, "class") |
839 !backup_read_int(fd, &klass)) {
840 ods_log_error("[%s] corrupted backup file zone %s: read class "
841 "error", zone_str, zone->name);
842 goto recover_error2;
843 }
844 if (!backup_read_check_str(fd, "inbound") |
845 !backup_read_uint32_t(fd, &inbound) |
846 !backup_read_check_str(fd, "internal") |
847 !backup_read_uint32_t(fd, &internal) |
848 !backup_read_check_str(fd, "outbound") |
849 !backup_read_uint32_t(fd, &outbound)) {
850 ods_log_error("[%s] corrupted backup file zone %s: read serial "
851 "error", zone_str, zone->name);
852 goto recover_error2;
853 }
854 zone->klass = (ldns_rr_class) klass;
855 zone->db->inbserial = inbound;
856 zone->db->intserial = internal;
857 zone->db->outserial = outbound;
858 /* signconf part */
859 if (!backup_read_check_str(fd, ";;Signconf:") |
860 !backup_read_check_str(fd, "lastmod") |
861 !backup_read_time_t(fd, &lastmod) |
862 !backup_read_check_str(fd, "maxzonettl") |
863 !backup_read_check_str(fd, "0") |
864 !backup_read_check_str(fd, "resign") |
865 !backup_read_duration(fd, &zone->signconf->sig_resign_interval) |
866 !backup_read_check_str(fd, "refresh") |
867 !backup_read_duration(fd, &zone->signconf->sig_refresh_interval) |
868 !backup_read_check_str(fd, "valid") |
869 !backup_read_duration(fd, &zone->signconf->sig_validity_default) |
870 !backup_read_check_str(fd, "denial") |
871 !backup_read_duration(fd,&zone->signconf->sig_validity_denial) |
872 !backup_read_check_str(fd, "keyset") |
873 !backup_read_duration(fd,&zone->signconf->sig_validity_keyset) |
874 !backup_read_check_str(fd, "jitter") |
875 !backup_read_duration(fd, &zone->signconf->sig_jitter) |
876 !backup_read_check_str(fd, "offset") |
877 !backup_read_duration(fd, &zone->signconf->sig_inception_offset) |
878 !backup_read_check_str(fd, "nsec") |
879 !backup_read_rr_type(fd, &zone->signconf->nsec_type) |
880 !backup_read_check_str(fd, "dnskeyttl") |
881 !backup_read_duration(fd, &zone->signconf->dnskey_ttl) |
882 !backup_read_check_str(fd, "soattl") |
883 !backup_read_duration(fd, &zone->signconf->soa_ttl) |
884 !backup_read_check_str(fd, "soamin") |
885 !backup_read_duration(fd, &zone->signconf->soa_min) |
886 !backup_read_check_str(fd, "serial") |
887 !backup_read_str(fd, &zone->signconf->soa_serial)) {
888 ods_log_error("[%s] corrupted backup file zone %s: read signconf "
889 "error", zone_str, zone->name);
890 goto recover_error2;
891 }
892 /* nsec3params part */
893 if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
894 if (!backup_read_check_str(fd, ";;Nsec3parameters:") |
895 !backup_read_check_str(fd, "salt") |
896 !backup_read_str(fd, &salt) |
897 !backup_read_check_str(fd, "algorithm") |
898 !backup_read_uint32_t(fd, &zone->signconf->nsec3_algo) |
899 !backup_read_check_str(fd, "optout") |
900 !backup_read_int(fd, &zone->signconf->nsec3_optout) |
901 !backup_read_check_str(fd, "iterations") |
902 !backup_read_uint32_t(fd, &zone->signconf->nsec3_iterations)) {
903 ods_log_error("[%s] corrupted backup file zone %s: read "
904 "nsec3parameters error", zone_str, zone->name);
905 goto recover_error2;
906 }
907 zone->signconf->nsec3_salt = strdup(salt);
908 free((void*) salt);
909 salt = NULL;
910 zone->signconf->nsec3params = nsec3params_create(
911 zone->signconf,
912 (uint8_t) zone->signconf->nsec3_algo,
913 (uint8_t) zone->signconf->nsec3_optout,
914 (uint16_t) zone->signconf->nsec3_iterations,
915 zone->signconf->nsec3_salt);
916 if (!zone->signconf->nsec3params) {
917 ods_log_error("[%s] corrupted backup file zone %s: unable to "
918 "create nsec3param", zone_str, zone->name);
919 goto recover_error2;
920 }
921 }
922 zone->signconf->last_modified = lastmod;
923 zone->zoneconfigvalid = 1;
924 zone->default_ttl = (uint32_t) duration2time(zone->signconf->soa_min);
925 /* keys part */
926 zone->signconf->keys = keylist_create((void*) zone->signconf);
927 while (backup_read_str(fd, &token)) {
928 if (ods_strcmp(token, ";;Key:") == 0) {
929 if (!key_recover2(fd, zone->signconf->keys)) {
930 ods_log_error("[%s] corrupted backup file zone %s: read "
931 "key error", zone_str, zone->name);
932 goto recover_error2;
933 }
934 } else if (ods_strcmp(token, ";;") == 0) {
935 /* keylist done */
936 free((void*) token);
937 token = NULL;
938 break;
939 } else {
940 /* keylist corrupted */
941 goto recover_error2;
942 }
943 free((void*) token);
944 token = NULL;
945 }
946 /* publish dnskeys */
947 status = zone_publish_dnskeys(zone, 1);
948 if (status != ODS_STATUS_OK) {
949 ods_log_error("[%s] corrupted backup file zone %s: unable to "
950 "publish dnskeys (%s)", zone_str, zone->name,
951 ods_status2str(status));
952 goto recover_error2;
953 }
954 /* publish nsec3param */
955 if (!zone->signconf->passthrough)
956 status = zone_publish_nsec3param(zone);
957 if (status != ODS_STATUS_OK) {
958 ods_log_error("[%s] corrupted backup file zone %s: unable to "
959 "publish nsec3param (%s)", zone_str, zone->name,
960 ods_status2str(status));
961 goto recover_error2;
962 }
963 /* publish other records */
964 status = backup_read_namedb(fd, zone);
965 if (status != ODS_STATUS_OK) {
966 ods_log_error("[%s] corrupted backup file zone %s: unable to "
967 "read resource records (%s)", zone_str, zone->name,
968 ods_status2str(status));
969 goto recover_error2;
970 }
971 /* task */
972 schedule_scheduletask(engine->taskq, TASK_SIGN, zone->name, zone, &zone->zone_lock, schedule_PROMPTLY);
973 free((void*)filename);
974 ods_fclose(fd);
975 zone->db->is_initialized = 1;
976 zone->db->have_serial = 1;
977 /* journal */
978 filename = ods_build_path(zone->name, ".ixfr", 0, 1);
979 if (filename) {
980 fd = ods_fopen(filename, NULL, "r");
981 }
982 if (fd) {
983 status = backup_read_ixfr(fd, zone);
984 if (status != ODS_STATUS_OK) {
985 ods_log_warning("[%s] corrupted journal file zone %s, "
986 "skipping (%s)", zone_str, zone->name,
987 ods_status2str(status));
988 (void)unlink(filename);
989 ixfr_cleanup(zone->ixfr);
990 zone->ixfr = ixfr_create();
991 }
992 }
993 pthread_mutex_lock(&zone->ixfr->ixfr_lock);
994 ixfr_purge(zone->ixfr, zone->name);
995 pthread_mutex_unlock(&zone->ixfr->ixfr_lock);
996
997 /* all ok */
998 free((void*)filename);
999 if (fd) {
1000 ods_fclose(fd);
1001 }
1002 if (zone->stats) {
1003 pthread_mutex_lock(&zone->stats->stats_lock);
1004 stats_clear(zone->stats);
1005 pthread_mutex_unlock(&zone->stats->stats_lock);
1006 }
1007 return ODS_STATUS_OK;
1008 }
1009 free(filename);
1010 return ODS_STATUS_UNCHANGED;
1011
1012 recover_error2:
1013 free((void*)filename);
1014 ods_fclose(fd);
1015 /* signconf cleanup */
1016 free((void*)salt);
1017 salt = NULL;
1018 signconf_cleanup(zone->signconf);
1019 zone->signconf = signconf_create();
1020 ods_log_assert(zone->signconf);
1021 /* namedb cleanup */
1022 namedb_cleanup(zone->db);
1023 zone->db = namedb_create((void*)zone);
1024 ods_log_assert(zone->db);
1025 /* stats reset */
1026 if (zone->stats) {
1027 pthread_mutex_lock(&zone->stats->stats_lock);
1028 stats_clear(zone->stats);
1029 pthread_mutex_unlock(&zone->stats->stats_lock);
1030 }
1031 return ODS_STATUS_ERR;
1032 }
1033
1034
1035 /**
1036 * Backup zone.
1037 *
1038 */
1039 ods_status
zone_backup2(zone_type * zone,time_t nextResign)1040 zone_backup2(zone_type* zone, time_t nextResign)
1041 {
1042 char* filename = NULL;
1043 char* tmpfile = NULL;
1044 FILE* fd = NULL;
1045 int ret = 0;
1046 ods_status status = ODS_STATUS_OK;
1047
1048 ods_log_assert(zone);
1049 ods_log_assert(zone->name);
1050 ods_log_assert(zone->db);
1051 ods_log_assert(zone->signconf);
1052
1053 tmpfile = ods_build_path(zone->name, ".backup2.tmp", 0, 1);
1054 filename = ods_build_path(zone->name, ".backup2", 0, 1);
1055 if (!tmpfile || !filename) {
1056 free(tmpfile);
1057 free(filename);
1058 return ODS_STATUS_MALLOC_ERR;
1059 }
1060 fd = ods_fopen(tmpfile, NULL, "w");
1061 if (fd) {
1062 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
1063 fprintf(fd, ";;Time: %u\n", (unsigned) nextResign);
1064 /** Backup zone */
1065 fprintf(fd, ";;Zone: name %s class %i inbound %u internal %u "
1066 "outbound %u\n", zone->name, (int) zone->klass,
1067 (unsigned) zone->db->inbserial,
1068 (unsigned) zone->db->intserial,
1069 (unsigned) zone->db->outserial);
1070 /** Backup signconf */
1071 signconf_backup(fd, zone->signconf, ODS_SE_FILE_MAGIC_V3);
1072 /** Backup NSEC3 parameters */
1073 if (zone->signconf->nsec3params) {
1074 nsec3params_backup(fd,
1075 zone->signconf->nsec3_algo,
1076 zone->signconf->nsec3_optout,
1077 zone->signconf->nsec3_iterations,
1078 zone->signconf->nsec3_salt,
1079 zone->signconf->nsec3params->rr,
1080 ODS_SE_FILE_MAGIC_V3);
1081 }
1082 /** Backup keylist */
1083 keylist_backup(fd, zone->signconf->keys, ODS_SE_FILE_MAGIC_V3);
1084 fprintf(fd, ";;\n");
1085 /** Backup domains and stuff */
1086 namedb_backup2(fd, zone->db);
1087 /** Done */
1088 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
1089 ods_fclose(fd);
1090 ret = rename(tmpfile, filename);
1091 if (ret != 0) {
1092 ods_log_error("[%s] unable to rename zone %s backup %s to %s: %s",
1093 zone_str, zone->name, tmpfile, filename, strerror(errno));
1094 status = ODS_STATUS_RENAME_ERR;
1095 }
1096 } else {
1097 status = ODS_STATUS_FOPEN_ERR;
1098 }
1099
1100 free((void*) tmpfile);
1101 free((void*) filename);
1102 return status;
1103 }
1104