OpenDNSSEC-signer 2.1.13
zone.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 "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
47static const char* zone_str = "zone";
48
49
55zone_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();
125 return zone;
126}
127
132ods_status
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
185ods_status
186zone_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
278void
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
305ods_status
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,
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
368void
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
392ods_status
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
433ods_status
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
510zone_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
528ods_status
529zone_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
610ods_status
611zone_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
654ods_status
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
693void
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;
713 }
714 } else {
715 free((void*)z1->policy_name);
716 z1->policy_name = NULL;
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;
731 }
732 } else {
733 free((void*)z1->signconf_filename);
734 z1->signconf_filename = NULL;
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
758void
760{
761 if (!zone) {
762 return;
763 }
764pthread_mutex_lock(&zone->zone_lock);
765 ldns_rdf_deep_free(zone->apex);
768 namedb_cleanup(zone->db);
769 ixfr_cleanup(zone->ixfr);
770 xfrd_cleanup(zone->xfrd, 1);
771 notify_cleanup(zone->notify);
773pthread_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
791ods_status
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") |
866 !backup_read_check_str(fd, "refresh") |
868 !backup_read_check_str(fd, "valid") |
870 !backup_read_check_str(fd, "denial") |
872 !backup_read_check_str(fd, "keyset") |
874 !backup_read_check_str(fd, "jitter") |
876 !backup_read_check_str(fd, "offset") |
878 !backup_read_check_str(fd, "nsec") |
880 !backup_read_check_str(fd, "dnskeyttl") |
882 !backup_read_check_str(fd, "soattl") |
884 !backup_read_check_str(fd, "soamin") |
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") |
899 !backup_read_check_str(fd, "optout") |
901 !backup_read_check_str(fd, "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;
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
1012recover_error2:
1013 free((void*)filename);
1014 ods_fclose(fd);
1015 /* signconf cleanup */
1016 free((void*)salt);
1017 salt = NULL;
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
1039ods_status
1040zone_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);
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);
1071 signconf_backup(fd, zone->signconf, ODS_SE_FILE_MAGIC_V3);
1073 if (zone->signconf->nsec3params) {
1075 zone->signconf->nsec3_algo,
1076 zone->signconf->nsec3_optout,
1078 zone->signconf->nsec3_salt,
1079 zone->signconf->nsec3params->rr,
1080 ODS_SE_FILE_MAGIC_V3);
1081 }
1083 keylist_backup(fd, zone->signconf->keys, ODS_SE_FILE_MAGIC_V3);
1084 fprintf(fd, ";;\n");
1086 namedb_backup2(fd, zone->db);
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}
int adapter_compare(adapter_type *a1, adapter_type *a2)
Definition: adapter.c:212
void adapter_cleanup(adapter_type *adapter)
Definition: adapter.c:234
ods_status backup_read_namedb(FILE *in, void *zone)
Definition: backup.c:304
int backup_read_uint32_t(FILE *in, uint32_t *v)
Definition: backup.c:209
int backup_read_int(FILE *in, int *v)
Definition: backup.c:175
ods_status backup_read_ixfr(FILE *in, void *zone)
Definition: backup.c:499
int backup_read_rr_type(FILE *in, ldns_rr_type *v)
Definition: backup.c:158
int backup_read_time_t(FILE *in, time_t *v)
Definition: backup.c:121
int backup_read_check_str(FILE *in, const char *str)
Definition: backup.c:77
int backup_read_duration(FILE *in, duration_type **v)
Definition: backup.c:138
int backup_read_str(FILE *in, const char **str)
Definition: backup.c:104
rrset_type * domain_lookup_rrset(domain_type *domain, ldns_rr_type rrtype)
Definition: domain.c:141
void domain_add_rrset(domain_type *domain, rrset_type *rrset)
Definition: domain.c:160
ods_status lhsm_get_key(hsm_ctx_t *ctx, ldns_rdf *owner, key_type *key_id, int skip_hsm_access)
Definition: hsm.c:81
void ixfr_purge(ixfr_type *ixfr, char const *zonename)
Definition: ixfr.c:237
void ixfr_cleanup(ixfr_type *ixfr)
Definition: ixfr.c:277
ixfr_type * ixfr_create()
Definition: ixfr.c:91
key_type * key_recover2(FILE *fd, keylist_type *kl)
Definition: keys.c:223
keylist_type * keylist_create(signconf_type *signconf)
Definition: keys.c:48
void keylist_backup(FILE *fd, keylist_type *kl, const char *version)
Definition: keys.c:268
namedb_type * namedb_create(void *zone)
Definition: namedb.c:121
void namedb_cleanup(namedb_type *db)
Definition: namedb.c:1131
void namedb_backup2(FILE *fd, namedb_type *db)
Definition: namedb.c:1152
ods_status namedb_domain_entize(namedb_type *db, domain_type *domain, ldns_rdf *apex)
Definition: namedb.c:281
domain_type * namedb_lookup_domain(namedb_type *db, ldns_rdf *dname)
Definition: namedb.c:338
ods_status namedb_update_serial(namedb_type *db, const char *zone_name, const char *format, uint32_t inbound_serial)
Definition: namedb.c:193
domain_type * namedb_add_domain(namedb_type *db, ldns_rdf *dname)
Definition: namedb.c:352
void notify_cleanup(notify_type *notify)
Definition: notify.c:600
nsec3params_type * nsec3params_create(void *sc, uint8_t algo, uint8_t flags, uint16_t iter, const char *salt)
Definition: nsec3params.c:103
void nsec3params_backup(FILE *fd, uint8_t algo, uint8_t flags, uint16_t iter, const char *salt, ldns_rr *rr, const char *version)
Definition: nsec3params.c:141
rr_type * rrset_lookup_rr(rrset_type *rrset, ldns_rr *rr)
Definition: rrset.c:236
rr_type * rrset_add_rr(rrset_type *rrset, ldns_rr *rr)
Definition: rrset.c:299
collection_class rrset_store_initialize()
Definition: rrset.c:223
ods_status rrset_getliteralrr(ldns_rr **dnskey, const char *resourcerecord, uint32_t ttl, ldns_rdf *apex)
Definition: rrset.c:851
void rrset_diff(rrset_type *rrset, unsigned is_ixfr, unsigned more_coming)
Definition: rrset.c:366
rrset_type * rrset_create(zone_type *zone, ldns_rr_type type)
Definition: rrset.c:199
uint32_t rrset_lookup_ttl(rrset_type *rrset, uint32_t default_ttl)
Definition: rrset.c:263
void signconf_backup(FILE *fd, signconf_type *sc, const char *version)
Definition: signconf.c:214
ods_status signconf_update(signconf_type **signconf, const char *scfile, time_t last_modified)
Definition: signconf.c:154
void signconf_cleanup(signconf_type *sc)
Definition: signconf.c:470
signconf_type * signconf_create(void)
Definition: signconf.c:47
stats_type * stats_create(void)
Definition: stats.c:40
void stats_clear(stats_type *stats)
Definition: stats.c:54
void stats_cleanup(stats_type *stats)
Definition: stats.c:106
ldns_rdf * dname
Definition: domain.h:56
zone_type * zone
Definition: domain.h:54
unsigned is_apex
Definition: domain.h:60
schedule_type * taskq
Definition: engine.h:54
pthread_mutex_t ixfr_lock
Definition: ixfr.h:64
ldns_rr * dnskey
Definition: keys.h:51
const char * resourcerecord
Definition: keys.h:54
int ksk
Definition: keys.h:58
const char * locator
Definition: keys.h:53
hsm_sign_params_t * params
Definition: keys.h:52
int publish
Definition: keys.h:57
int zsk
Definition: keys.h:59
size_t count
Definition: keys.h:69
key_type * keys
Definition: keys.h:68
unsigned have_serial
Definition: namedb.h:60
unsigned is_initialized
Definition: namedb.h:57
uint32_t intserial
Definition: namedb.h:54
uint32_t inbserial
Definition: namedb.h:53
unsigned serial_updated
Definition: namedb.h:58
uint32_t outserial
Definition: namedb.h:55
uint8_t * salt_data
Definition: nsec3params.h:53
uint16_t iterations
Definition: nsec3params.h:51
ldns_rr * rr
Definition: rrset.h:52
unsigned is_removed
Definition: rrset.h:56
unsigned exists
Definition: rrset.h:54
unsigned is_added
Definition: rrset.h:55
size_t rr_count
Definition: rrset.h:65
rr_type * rrs
Definition: rrset.h:64
duration_type * soa_ttl
Definition: signconf.h:66
keylist_type * keys
Definition: signconf.h:64
duration_type * sig_jitter
Definition: signconf.h:51
duration_type * sig_refresh_interval
Definition: signconf.h:47
uint32_t nsec3_iterations
Definition: signconf.h:58
int nsec3_optout
Definition: signconf.h:56
duration_type * soa_min
Definition: signconf.h:67
const char * soa_serial
Definition: signconf.h:68
duration_type * nsec3param_ttl
Definition: signconf.h:54
duration_type * sig_resign_interval
Definition: signconf.h:46
time_t last_modified
Definition: signconf.h:72
nsec3params_type * nsec3params
Definition: signconf.h:60
ldns_rr_type nsec_type
Definition: signconf.h:55
duration_type * sig_inception_offset
Definition: signconf.h:52
const char ** dnskey_signature
Definition: signconf.h:63
const char * nsec3_salt
Definition: signconf.h:59
duration_type * sig_validity_keyset
Definition: signconf.h:50
duration_type * sig_validity_denial
Definition: signconf.h:49
duration_type * dnskey_ttl
Definition: signconf.h:62
uint32_t nsec3_algo
Definition: signconf.h:57
duration_type * sig_validity_default
Definition: signconf.h:48
pthread_mutex_t stats_lock
Definition: stats.h:63
uint32_t sort_count
Definition: stats.h:51
char * notify_command
Definition: zone.h:65
collection_class rrstore
Definition: zone.h:89
signconf_type * signconf
Definition: zone.h:77
notify_type * notify
Definition: zone.h:83
char ** notify_args
Definition: zone.h:67
uint32_t default_ttl
Definition: zone.h:63
const char * notify_ns
Definition: zone.h:66
const char * policy_name
Definition: zone.h:70
stats_type * stats
Definition: zone.h:85
namedb_type * db
Definition: zone.h:79
pthread_mutex_t xfr_lock
Definition: zone.h:87
ldns_rr_class klass
Definition: zone.h:62
adapter_type * adinbound
Definition: zone.h:74
ldns_rdf * apex
Definition: zone.h:61
ixfr_type * ixfr
Definition: zone.h:80
const char * signconf_filename
Definition: zone.h:71
zone_zl_status zl_status
Definition: zone.h:72
int zoneconfigvalid
Definition: zone.h:90
xfrd_type * xfrd
Definition: zone.h:82
const char * name
Definition: zone.h:69
pthread_mutex_t zone_lock
Definition: zone.h:86
adapter_type * adoutbound
Definition: zone.h:75
void xfrd_cleanup(xfrd_type *xfrd, int backup)
Definition: xfrd.c:2179
ods_status zone_backup2(zone_type *zone, time_t nextResign)
Definition: zone.c:1040
void zone_rollback_nsec3param(zone_type *zone)
Definition: zone.c:369
ods_status zone_update_serial(zone_type *zone)
Definition: zone.c:434
ods_status zone_publish_dnskeys(zone_type *zone, int skip_hsm_access)
Definition: zone.c:186
ods_status zone_add_rr(zone_type *zone, ldns_rr *rr, int do_stats)
Definition: zone.c:529
void zone_rollback_dnskeys(zone_type *zone)
Definition: zone.c:279
ods_status zone_del_nsec3params(zone_type *zone)
Definition: zone.c:655
void zone_merge(zone_type *z1, zone_type *z2)
Definition: zone.c:694
ods_status zone_load_signconf(zone_type *zone, signconf_type **new_signconf)
Definition: zone.c:133
ods_status zone_del_rr(zone_type *zone, ldns_rr *rr, int do_stats)
Definition: zone.c:611
void zone_cleanup(zone_type *zone)
Definition: zone.c:759
ods_status zone_prepare_keys(zone_type *zone)
Definition: zone.c:393
ods_status zone_publish_nsec3param(zone_type *zone)
Definition: zone.c:306
zone_type * zone_create(char *name, ldns_rr_class klass)
Definition: zone.c:55
ods_status zone_recover2(engine_type *engine, zone_type *zone)
Definition: zone.c:792
rrset_type * zone_lookup_rrset(zone_type *zone, ldns_rdf *owner, ldns_rr_type type)
Definition: zone.c:510
@ ZONE_ZL_OK
Definition: zone.h:34
@ ZONE_ZL_UPDATED
Definition: zone.h:36