OpenDNSSEC-signer 1.2.1
|
00001 /* 00002 * $Id: zone.c 4521 2011-03-01 14:56:15Z matthijs $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "adapter/adapter.h" 00035 #include "scheduler/locks.h" 00036 #include "scheduler/task.h" 00037 #include "signer/backup.h" 00038 #include "signer/hsm.h" 00039 #include "signer/nsec3params.h" 00040 #include "signer/signconf.h" 00041 #include "signer/zone.h" 00042 #include "signer/zonedata.h" 00043 #include "util/duration.h" 00044 #include "util/file.h" 00045 #include "util/log.h" 00046 #include "util/se_malloc.h" 00047 #include "util/util.h" 00048 00049 #include <ldns/ldns.h> /* ldns_*() */ 00050 #include <libhsm.h> /* hsm_create_context(), hsm_get_key(), hsm_destroy_context() */ 00051 #include <libhsmdns.h> /* hsm_create_context(), hsm_get_key(), hsm_destroy_context() */ 00052 00053 00058 zone_type* 00059 zone_create(const char* name, ldns_rr_class klass) 00060 { 00061 zone_type* zone = (zone_type*) se_calloc(1, sizeof(zone_type)); 00062 se_log_assert(name); 00063 se_log_debug("create zone %s", name?name:"(null)"); 00064 zone->name = se_strdup(name); 00065 zone->dname = ldns_dname_new_frm_str(name); 00066 ldns_dname2canonical(zone->dname); 00067 zone->klass = klass; 00068 zone->notify_ns = NULL; 00069 zone->policy_name = NULL; 00070 zone->signconf_filename = NULL; 00071 zone->signconf = NULL; 00072 zone->nsec3params = NULL; 00073 zone->inbound_adapter = NULL; 00074 zone->outbound_adapter = NULL; 00075 zone->task = NULL; 00076 zone->backoff = 0; 00077 zone->just_added = 0; 00078 zone->just_updated = 0; 00079 zone->tobe_removed = 0; 00080 zone->in_progress = 0; 00081 zone->processed = 0; 00082 zone->fetch = 0; 00083 zone->zonedata = zonedata_create(); 00084 zone->stats = stats_create(); 00085 lock_basic_init(&zone->zone_lock); 00086 return zone; 00087 } 00088 00089 00094 void 00095 zone_update_zonelist(zone_type* z1, zone_type* z2) 00096 { 00097 se_log_assert(z1); 00098 se_log_assert(z2); 00099 00100 if (se_strcmp(z2->policy_name, z1->policy_name) != 0) { 00101 se_free((void*)z1->policy_name); 00102 if (z2->policy_name) { 00103 z1->policy_name = se_strdup(z2->policy_name); 00104 } else { 00105 z1->policy_name = NULL; 00106 } 00107 z1->just_updated = 1; 00108 } 00109 00110 if (se_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) { 00111 se_free((void*)z1->signconf_filename); 00112 if (z2->signconf_filename) { 00113 z1->signconf_filename = se_strdup(z2->signconf_filename); 00114 } else { 00115 z1->signconf_filename = NULL; 00116 } 00117 z1->just_updated = 1; 00118 } 00119 00120 if (adapter_compare(z1->inbound_adapter, z2->inbound_adapter) != 0) { 00121 adapter_cleanup(z1->inbound_adapter); 00122 if (z2->inbound_adapter) { 00123 z1->inbound_adapter = adapter_create( 00124 z2->inbound_adapter->filename, 00125 z2->inbound_adapter->type, 00126 z2->inbound_adapter->inbound); 00127 } else { 00128 z1->inbound_adapter = NULL; 00129 } 00130 z1->just_updated = 1; 00131 } 00132 00133 if (adapter_compare(z1->outbound_adapter, z2->outbound_adapter) != 0) { 00134 adapter_cleanup(z1->outbound_adapter); 00135 if (z2->outbound_adapter) { 00136 z1->outbound_adapter = adapter_create( 00137 z2->outbound_adapter->filename, 00138 z2->outbound_adapter->type, 00139 z2->outbound_adapter->inbound); 00140 } else { 00141 z1->outbound_adapter = NULL; 00142 } 00143 z1->just_updated = 1; 00144 } 00145 00146 zone_cleanup(z2); 00147 return; 00148 } 00149 00150 00155 int 00156 zone_update_signconf(zone_type* zone, struct tasklist_struct* tl, char* buf) 00157 { 00158 task_type* task = NULL; 00159 signconf_type* signconf = NULL; 00160 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00161 domain_type* domain = NULL; 00162 time_t last_modified = 0; 00163 time_t now = 0; 00164 int update = 0; 00165 00166 se_log_assert(zone); 00167 se_log_debug("load zone %s signconf %s", 00168 zone->name?zone->name:"(null)", 00169 zone->signconf_filename?zone->signconf_filename:"(null)"); 00170 00171 if (zone->signconf) { 00172 last_modified = zone->signconf->last_modified; 00173 } 00174 00175 signconf = signconf_read(zone->signconf_filename, last_modified); 00176 if (!signconf) { 00177 if (!zone->policy_name) { 00178 se_log_warning("zone %s has no policy", 00179 zone->name?zone->name:"(null)"); 00180 } else { 00181 signconf = signconf_read(zone->signconf_filename, 0); 00182 if (!signconf) { 00183 se_log_warning("zone %s has policy %s configured, " 00184 "but has no (valid) signconf file", 00185 zone->name?zone->name:"(null)", zone->policy_name); 00186 if (buf) { 00187 (void)snprintf(buf, ODS_SE_MAXLINE, 00188 "Zone %s config has errors.\n", 00189 zone->name?zone->name:"(null)"); 00190 } 00191 return -1; 00192 } else { 00193 se_log_debug("zone %s has not changed", 00194 zone->name?zone->name:"(null)"); 00195 signconf_cleanup(signconf); 00196 } 00197 } 00198 if (buf) { 00199 (void)snprintf(buf, ODS_SE_MAXLINE, 00200 "Zone %s config has not changed.\n", 00201 zone->name?zone->name:"(null)"); 00202 } 00203 return 0; 00204 } else if (signconf_check(signconf) != 0) { 00205 se_log_warning("zone %s signconf has errors", 00206 zone->name?zone->name:"(null)"); 00207 if (buf) { 00208 (void)snprintf(buf, ODS_SE_MAXLINE, 00209 "Zone %s config has errors.\n", zone->name?zone->name:"(null)"); 00210 } 00211 return -1; 00212 } else if (!zone->signconf) { 00213 zone->signconf = signconf; 00214 /* we don't check if foo in <Zone name="foo"> matches zone->name */ 00215 zone->signconf->name = zone->name; 00216 se_log_debug("zone %s now has signconf", 00217 zone->name?zone->name:"(null)"); 00218 signconf_backup(zone->signconf); 00219 00220 /* zone state? */ 00221 /* create task for new zone */ 00222 now = time_now(); 00223 zone->task = task_create(TASK_READ, now, zone->name, zone); 00224 task = tasklist_schedule_task(tl, zone->task, 0); 00225 if (!task) { 00226 if (buf) { 00227 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s now has config, " 00228 "but could not be scheduled.\n", 00229 zone->name?zone->name:"(null)"); 00230 } 00231 } else { 00232 if (buf) { 00233 (void)snprintf(buf, ODS_SE_MAXLINE, 00234 "Zone %s now has config.\n", 00235 zone->name?zone->name:"(null)"); 00236 } 00237 } 00238 return 1; 00239 } else { 00240 /* update task for new zone */ 00241 task = tasklist_delete_task(tl, zone->task); 00242 if (!task) { 00243 se_log_error("cannot update zone %s: delete old task failed", 00244 zone->name); 00245 if (buf) { 00246 (void)snprintf(buf, ODS_SE_MAXLINE, "Update zone %s failed.\n", 00247 zone->name?zone->name:"(null)"); 00248 } 00249 return -1; 00250 } 00251 00252 zone->task->what = signconf_compare(zone->signconf, signconf, &update); 00253 zone->task->when = time_now(); 00254 if (update) { 00255 /* destroy NSEC(3) storage */ 00256 se_log_debug("destroy old NSEC(3) records for zone %s", zone->name); 00257 if (zone->zonedata && zone->zonedata->denial_chain) { 00258 zonedata_cleanup_denials(zone->zonedata->denial_chain); 00259 zone->zonedata->denial_chain = NULL; 00260 node = ldns_rbtree_first(zone->zonedata->domains); 00261 while (node && node != LDNS_RBTREE_NULL) { 00262 domain = (domain_type*) node->data; 00263 domain->denial = NULL; 00264 node = ldns_rbtree_next(node); 00265 } 00266 } 00267 if (zone->nsec3params) { 00268 nsec3params_cleanup(zone->nsec3params); 00269 zone->nsec3params = NULL; 00270 } 00271 } 00272 00273 task = tasklist_schedule_task(tl, zone->task, 0); 00274 if (!task) { 00275 if (buf) { 00276 (void)snprintf(buf, ODS_SE_MAXLINE, 00277 "Zone %s config updated, but could not be schedulted.\n", 00278 zone->name?zone->name:"(null)"); 00279 } 00280 } else { 00281 if (buf) { 00282 (void)snprintf(buf, ODS_SE_MAXLINE, 00283 "Zone %s config updated.\n", zone->name?zone->name: 00284 "(null)"); 00285 } 00286 } 00287 00288 signconf_cleanup(zone->signconf); 00289 zone->signconf = signconf; 00290 zone->signconf->name = zone->name; 00291 se_log_debug("zone %s signconf updated", 00292 zone->name?zone->name:"(null)"); 00293 signconf_backup(zone->signconf); 00294 return 1; 00295 } 00296 /* not reached */ 00297 return 0; 00298 } 00299 00300 00305 static int 00306 zone_publish_dnskeys(zone_type* zone, FILE* fd) 00307 { 00308 key_type* key = NULL; 00309 uint32_t ttl = 0; 00310 size_t count = 0; 00311 int error = 0; 00312 hsm_ctx_t* ctx = NULL; 00313 ldns_rr* dnskey = NULL; 00314 00315 se_log_assert(zone); 00316 se_log_assert(zone->signconf); 00317 se_log_assert(zone->signconf->keys); 00318 se_log_assert(zone->zonedata); 00319 00320 ctx = hsm_create_context(); 00321 if (ctx == NULL) { 00322 se_log_error("error creating libhsm context"); 00323 return 2; 00324 } 00325 00326 ttl = zone->zonedata->default_ttl; 00327 if (zone->signconf->dnskey_ttl) { 00328 ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl); 00329 } 00330 00331 key = zone->signconf->keys->first_key; 00332 for (count=0; count < zone->signconf->keys->count; count++) { 00333 if (key->publish) { 00334 if (!key->dnskey) { 00335 error = hsm_get_key(ctx, zone->dname, key); 00336 if (error) { 00337 se_log_error("error creating DNSKEY for key %s", 00338 key->locator?key->locator:"(null)"); 00339 error = 1; 00340 break; 00341 } 00342 } 00343 ldns_rr_set_ttl(key->dnskey, ttl); 00344 ldns_rr_set_class(key->dnskey, zone->klass); 00345 ldns_rr2canonical(key->dnskey); 00346 dnskey = ldns_rr_clone(key->dnskey); 00347 error = zone_add_rr(zone, dnskey, 0); 00348 if (error) { 00349 se_log_error("error adding DNSKEY[%u] for key %s", 00350 ldns_calc_keytag(dnskey), 00351 key->locator?key->locator:"(null)"); 00352 break; 00353 } else if (fd) { 00354 fprintf(fd, ";DNSKEY %s %u %u %i %i %i\n", 00355 key->locator?key->locator:"(null)", key->algorithm, 00356 key->flags, key->publish, key->ksk, key->zsk); 00357 ldns_rr_print(fd, dnskey); 00358 fprintf(fd, ";END\n"); 00359 } 00360 } 00361 key = key->next; 00362 } 00363 hsm_destroy_context(ctx); 00364 return error; 00365 } 00366 00367 00372 static int 00373 zone_publish_nsec3params(zone_type* zone, FILE* fd) 00374 { 00375 ldns_rr* nsec3params_rr = NULL; 00376 int error = 0; 00377 00378 if (!zone->nsec3params) { 00379 zone->nsec3params = nsec3params_create( 00380 (uint8_t) zone->signconf->nsec3_algo, 00381 (uint8_t) zone->signconf->nsec3_optout, 00382 (uint16_t) zone->signconf->nsec3_iterations, 00383 zone->signconf->nsec3_salt); 00384 if (!zone->nsec3params) { 00385 se_log_error("error creating NSEC3 parameters for zone %s", 00386 zone->name?zone->name:"(null)"); 00387 return 1; 00388 } 00389 } 00390 00391 nsec3params_rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS); 00392 ldns_rr_set_class(nsec3params_rr, zone->klass); 00393 ldns_rr_set_ttl(nsec3params_rr, zone->zonedata->default_ttl); 00394 ldns_rr_set_owner(nsec3params_rr, ldns_rdf_clone(zone->dname)); 00395 ldns_nsec3_add_param_rdfs(nsec3params_rr, 00396 zone->nsec3params->algorithm, 0, 00397 zone->nsec3params->iterations, 00398 zone->nsec3params->salt_len, 00399 zone->nsec3params->salt_data); 00404 ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(nsec3params_rr, 1)), 7, 0); 00405 00406 ldns_rr2canonical(nsec3params_rr); 00407 error = zone_add_rr(zone, nsec3params_rr, 0); 00408 if (error) { 00409 se_log_error("error adding NSEC3PARAMS record to zone %s", 00410 zone->name?zone->name:"(null)"); 00411 } else if (fd) { 00412 fprintf(fd, ";NSEC3PARAMS %s %u %u %u\n", 00413 zone->signconf->nsec3_salt, zone->nsec3params->algorithm, 00414 zone->nsec3params->flags, zone->nsec3params->iterations); 00415 ldns_rr_print(fd, nsec3params_rr); 00416 fprintf(fd, ";END\n"); 00417 } 00418 return error; 00419 } 00420 00421 00426 int 00427 zone_update_zonedata(zone_type* zone) 00428 { 00429 int error = 0; 00430 00431 se_log_assert(zone); 00432 se_log_assert(zone->signconf); 00433 se_log_assert(zone->inbound_adapter); 00434 se_log_assert(zone->zonedata); 00435 00436 /* examine zone data */ 00437 se_log_debug("examine zone %s update", zone->name); 00438 error = zonedata_examine(zone->zonedata, zone->dname, 00439 zone->inbound_adapter->type==ADAPTER_FILE); 00440 if (error) { 00441 se_log_error("update zone %s failed: zone data contains errors", 00442 zone->name); 00443 zonedata_cancel_update(zone->zonedata); 00444 return error; 00445 } 00446 return zonedata_update(zone->zonedata, zone->signconf); 00447 } 00448 00449 00454 int 00455 zone_add_dnskeys(zone_type* zone) 00456 { 00457 int error = 0; 00458 char* filename = NULL; 00459 FILE* fd = NULL; 00460 00461 se_log_assert(zone); 00462 se_log_assert(zone->signconf); 00463 se_log_assert(zone->zonedata); 00464 00465 filename = se_build_path(zone->name, ".dnskeys", 0); 00466 fd = se_fopen(filename, NULL, "w"); 00467 if (fd) { 00468 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00469 } 00470 00471 error = zone_publish_dnskeys(zone, fd); 00472 if (error) { 00473 se_log_error("error adding DNSKEYs to zone %s", 00474 zone->name?zone->name:"(null)"); 00475 return error; 00476 } 00477 if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) { 00478 error = zone_publish_nsec3params(zone, fd); 00479 if (error) { 00480 se_log_error("error adding NSEC3PARAMS RR to zone %s", 00481 zone->name?zone->name:"(null)"); 00482 return error; 00483 } 00484 } 00485 00486 if (fd) { 00487 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00488 se_fclose(fd); 00489 } else { 00490 se_log_warning("cannot backup DNSKEY / NSEC3PARAMS records: " 00491 "cannot open file %s for writing", filename?filename:"(null)"); 00492 } 00493 se_free((void*)filename); 00494 00495 return error; 00496 } 00497 00498 00503 int 00504 zone_add_rr(zone_type* zone, ldns_rr* rr, int recover) 00505 { 00506 ldns_rr_type type = 0; 00507 int error = 0; 00508 int at_apex = 0; 00509 uint32_t tmp = 0; 00510 ldns_rdf* soa_min = NULL; 00511 00512 se_log_assert(zone); 00513 se_log_assert(zone->zonedata); 00514 se_log_assert(zone->signconf); 00515 se_log_assert(rr); 00516 00517 /* in-zone? */ 00518 if (ldns_dname_compare(zone->dname, ldns_rr_owner(rr)) != 0 && 00519 !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->dname)) { 00520 se_log_warning("zone %s contains out-of-zone data, skipping", 00521 zone->name?zone->name:"(null)"); 00522 return 0; 00523 } else if (ldns_dname_compare(zone->dname, ldns_rr_owner(rr)) == 0) { 00524 at_apex = 1; 00525 } 00526 00527 /* type specific configuration */ 00528 type = ldns_rr_get_type(rr); 00529 if (type == LDNS_RR_TYPE_DNSKEY && zone->signconf->dnskey_ttl) { 00530 tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl); 00531 se_log_verbose("zone %s set DNSKEY TTL to %u", 00532 zone->name?zone->name:"(null)", tmp); 00533 ldns_rr_set_ttl(rr, tmp); 00534 } 00535 if (type == LDNS_RR_TYPE_SOA) { 00536 if (zone->signconf->soa_ttl) { 00537 tmp = (uint32_t) duration2time(zone->signconf->soa_ttl); 00538 se_log_verbose("zone %s set SOA TTL to %u", 00539 zone->name?zone->name:"(null)", tmp); 00540 ldns_rr_set_ttl(rr, tmp); 00541 } 00542 if (zone->signconf->soa_min) { 00543 tmp = (uint32_t) duration2time(zone->signconf->soa_min); 00544 se_log_verbose("zone %s set SOA MINIMUM to %u", 00545 zone->name?zone->name:"(null)", tmp); 00546 soa_min = ldns_rr_set_rdf(rr, 00547 ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp), 00548 SE_SOA_RDATA_MINIMUM); 00549 if (soa_min) { 00550 ldns_rdf_deep_free(soa_min); 00551 } else { 00552 se_log_error("zone %s failed to replace SOA MINIMUM " 00553 "rdata", zone->name?zone->name:"(null)"); 00554 } 00555 } 00556 } 00557 if (recover) { 00558 error = zonedata_recover_rr_from_backup(zone->zonedata, rr); 00559 } else { 00560 error = zonedata_add_rr(zone->zonedata, rr, at_apex); 00561 } 00562 return error; 00563 } 00564 00565 00570 int 00571 zone_del_rr(zone_type* zone, ldns_rr* rr) 00572 { 00573 se_log_assert(zone); 00574 se_log_assert(zone->zonedata); 00575 se_log_assert(rr); 00576 return zonedata_del_rr(zone->zonedata, rr); 00577 } 00578 00579 00584 int 00585 zone_nsecify(zone_type* zone) 00586 { 00587 int error = 0; 00588 FILE* fd = NULL; 00589 char* filename = NULL; 00590 time_t start = 0; 00591 time_t end = 0; 00592 00593 se_log_assert(zone); 00594 se_log_assert(zone->signconf); 00595 se_log_assert(zone->zonedata); 00596 se_log_assert(zone->stats); 00597 00598 zone->stats->nsec_count = 0; 00599 zone->stats->nsec_time = 0; 00600 start = time(NULL); 00601 00602 /* add empty non-terminals */ 00603 error = zonedata_entize(zone->zonedata, zone->dname); 00604 if (error) { 00605 se_log_error("failed to add empty non-terminals to zone %s", 00606 zone->name?zone->name:"(null)"); 00607 return error; 00608 } 00609 00610 if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC) { 00611 error = zonedata_nsecify(zone->zonedata, zone->klass, zone->stats); 00612 } else if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) { 00613 if (zone->signconf->nsec3_optout) { 00614 se_log_debug("OptOut is being used for zone %s", 00615 zone->name?zone->name:"(null)"); 00616 } 00617 error = zonedata_nsecify3(zone->zonedata, zone->klass, 00618 zone->nsec3params, zone->stats); 00619 } else { 00620 se_log_error("unknown RR type for denial of existence, %i", 00621 zone->signconf->nsec_type); 00622 error = 1; 00623 } 00624 if (!error) { 00625 end = time(NULL); 00626 zone->stats->nsec_time = (end-start); 00627 00628 filename = se_build_path(zone->name, ".denial", 0); 00629 fd = se_fopen(filename, NULL, "w"); 00630 if (fd) { 00631 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00632 zonedata_print_nsec(fd, zone->zonedata); 00633 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00634 se_fclose(fd); 00635 } else { 00636 se_log_warning("cannot backup NSEC(3) records: cannot open file " 00637 "%s for writing", filename?filename:"(null)"); 00638 } 00639 se_free((void*)filename); 00640 } 00641 return error; 00642 } 00643 00644 00649 int 00650 zone_sign(zone_type* zone) 00651 { 00652 int error = 0; 00653 FILE* fd = NULL; 00654 char* filename = NULL; 00655 time_t start = 0; 00656 time_t end = 0; 00657 00658 se_log_assert(zone); 00659 se_log_assert(zone->signconf); 00660 se_log_assert(zone->zonedata); 00661 se_log_assert(zone->stats); 00662 00663 zone->stats->sig_count = 0; 00664 zone->stats->sig_reuse = 0; 00665 zone->stats->sig_time = 0; 00666 start = time(NULL); 00667 00668 error = zonedata_sign(zone->zonedata, zone->dname, zone->signconf, 00669 zone->stats); 00670 if (!error) { 00671 end = time(NULL); 00672 zone->stats->sig_time = (end-start); 00673 00674 filename = se_build_path(zone->name, ".rrsigs", 0); 00675 fd = se_fopen(filename, NULL, "w"); 00676 if (fd) { 00677 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00678 zonedata_print_rrsig(fd, zone->zonedata); 00679 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00680 se_fclose(fd); 00681 } else { 00682 se_log_warning("cannot backup RRSIG records: cannot open file " 00683 "%s for writing", filename?filename:"(null)"); 00684 } 00685 se_free((void*)filename); 00686 } 00687 return error; 00688 } 00689 00690 00697 int zone_backup_state(zone_type* zone) 00698 { 00699 int error = 0; 00700 char* filename = NULL; 00701 FILE* fd = NULL; 00702 00703 se_log_assert(zone); 00704 se_log_assert(zone->zonedata); 00705 se_log_assert(zone->signconf); 00706 00707 filename = se_build_path(zone->name, ".state", 0); 00708 fd = se_fopen(filename, NULL, "w"); 00709 if (fd) { 00710 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00711 fprintf(fd, ";name: %s\n", zone->name?zone->name:"(null)"); 00712 fprintf(fd, ";class: %i\n", (int) zone->klass); 00713 fprintf(fd, ";fetch: %i\n", (int) zone->fetch); 00714 fprintf(fd, ";default_ttl: %u\n", zone->zonedata->default_ttl); 00715 fprintf(fd, ";inbound_serial: %u\n", zone->zonedata->inbound_serial); 00716 fprintf(fd, ";internal_serial: %u\n", zone->zonedata->internal_serial); 00717 fprintf(fd, ";outbound_serial: %u\n", zone->zonedata->outbound_serial); 00718 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00719 se_fclose(fd); 00720 } else { 00721 se_log_error("cannot backup zone: cannot open file " 00722 "%s for writing", filename?filename:"(null)"); 00723 return 1; 00724 } 00725 se_free((void*)filename); 00726 00727 return error; 00728 } 00729 00730 00735 static int 00736 zone_recover_dnskeys_from_backup(zone_type* zone, FILE* fd) 00737 { 00738 int corrupted = 0; 00739 const char* token = NULL; 00740 key_type* key = NULL; 00741 ldns_rr* rr = NULL; 00742 00743 if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC)) { 00744 corrupted = 1; 00745 } 00746 00747 while (!corrupted) { 00748 if (backup_read_str(fd, &token)) { 00749 if (se_strcmp(token, ";DNSKEY") == 0) { 00750 key = key_recover_from_backup(fd); 00751 if (!key || keylist_add(zone->signconf->keys, key)) { 00752 se_log_error("error adding key from backup file " 00753 "%s.dnskeys to key list", zone->name); 00754 corrupted = 1; 00755 } else { 00756 rr = ldns_rr_clone(key->dnskey); 00757 corrupted = zone_add_rr(zone, rr, 1); 00758 if (corrupted) { 00759 se_log_error("error recovering DNSKEY[%u] rr", 00760 ldns_calc_keytag(rr)); 00761 } 00762 rr = NULL; 00763 } 00764 key = NULL; 00765 } else if (se_strcmp(token, ";NSEC3PARAMS") == 0) { 00766 zone->nsec3params = nsec3params_recover_from_backup(fd, 00767 &rr); 00768 if (!zone->nsec3params) { 00769 se_log_error("error recovering nsec3 parameters from file " 00770 "%s.dnskeys", zone->name); 00771 corrupted = 1; 00772 } else { 00773 corrupted = zone_add_rr(zone, rr, 1); 00774 if (corrupted) { 00775 se_log_error("error recovering NSEC3PARAMS rr"); 00776 } else { 00777 zone->signconf->nsec3_optout = 00778 (int) zone->nsec3params->flags; 00779 zone->signconf->nsec3_algo = 00780 (uint32_t) zone->nsec3params->algorithm; 00781 zone->signconf->nsec3_iterations = 00782 (uint32_t) zone->nsec3params->iterations; 00783 zone->signconf->nsec3_salt = 00784 nsec3params_salt2str(zone->nsec3params); 00785 } 00786 } 00787 rr = NULL; 00788 } else if (se_strcmp(token, ODS_SE_FILE_MAGIC) == 0) { 00789 se_free((void*) token); 00790 token = NULL; 00791 break; 00792 } else { 00793 corrupted = 1; 00794 } 00795 se_free((void*) token); 00796 token = NULL; 00797 } else { 00798 corrupted = 1; 00799 } 00800 } 00801 return corrupted; 00802 } 00803 00804 00809 static int 00810 zone_recover_rrsigs_from_backup(zone_type* zone, FILE* fd) 00811 { 00812 int corrupted = 0; 00813 const char* token = NULL; 00814 const char* locator = NULL; 00815 uint32_t flags = 0; 00816 ldns_rr* rr = NULL; 00817 ldns_status status = LDNS_STATUS_OK; 00818 00819 if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC)) { 00820 corrupted = 1; 00821 } 00822 00823 while (!corrupted) { 00824 if (backup_read_str(fd, &token)) { 00825 if (se_strcmp(token, ";RRSIG") == 0) { 00826 if (!backup_read_str(fd, &locator) || 00827 !backup_read_uint32_t(fd, &flags)) { 00828 00829 se_log_error("error reading key credentials from backup"); 00830 corrupted = 1; 00831 } else { 00832 status = ldns_rr_new_frm_fp(&rr, fd, NULL, NULL, NULL); 00833 if (status != LDNS_STATUS_OK) { 00834 se_log_error("error reading RRSIG from backup"); 00835 corrupted = 1; 00836 } else if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { 00837 se_log_error("expecting RRtype RRSIG from backup"); 00838 corrupted = 1; 00839 ldns_rr_free(rr); 00840 rr = NULL; 00841 } else { 00842 corrupted = zonedata_recover_rrsig_from_backup( 00843 zone->zonedata, rr, locator, flags); 00844 } 00845 } 00846 } else if (se_strcmp(token, ODS_SE_FILE_MAGIC) == 0) { 00847 se_free((void*) token); 00848 token = NULL; 00849 break; 00850 } else { 00851 corrupted = 1; 00852 } 00853 se_free((void*) token); 00854 token = NULL; 00855 } else { 00856 corrupted = 1; 00857 } 00858 00859 /* reset */ 00860 if (locator) { 00861 se_free((void*) locator); 00862 locator = NULL; 00863 } 00864 rr = NULL; 00865 flags = 0; 00866 status = LDNS_STATUS_OK; 00867 } 00868 return corrupted; 00869 } 00870 00871 00876 void 00877 zone_recover_from_backup(zone_type* zone, struct tasklist_struct* tl) 00878 { 00879 int klass = 0; 00880 int fetch = 0; 00881 int error = 0; 00882 char* filename = NULL; 00883 task_type* task = NULL; 00884 time_t now = 0; 00885 FILE* fd = NULL; 00886 00887 se_log_assert(zone); 00888 se_log_assert(zone->zonedata); 00889 00890 filename = se_build_path(zone->name, ".state", 0); 00891 fd = se_fopen(filename, NULL, "r"); 00892 se_free((void*)filename); 00893 if (fd) { 00894 if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC) || 00895 !backup_read_check_str(fd, ";name:") || 00896 !backup_read_check_str(fd, zone->name) || 00897 !backup_read_check_str(fd, ";class:") || 00898 !backup_read_int(fd, &klass) || 00899 !backup_read_check_str(fd, ";fetch:") || 00900 !backup_read_int(fd, &fetch) || 00901 !backup_read_check_str(fd, ";default_ttl:") || 00902 !backup_read_uint32_t(fd, &zone->zonedata->default_ttl) || 00903 !backup_read_check_str(fd, ";inbound_serial:") || 00904 !backup_read_uint32_t(fd, &zone->zonedata->inbound_serial) || 00905 !backup_read_check_str(fd, ";internal_serial:") || 00906 !backup_read_uint32_t(fd, &zone->zonedata->internal_serial) || 00907 !backup_read_check_str(fd, ";outbound_serial:") || 00908 !backup_read_uint32_t(fd, &zone->zonedata->outbound_serial) || 00909 !backup_read_check_str(fd, ODS_SE_FILE_MAGIC)) 00910 { 00911 se_log_error("unable to recover zone state from file %s.state: " 00912 "file corrupted", zone->name); 00913 se_fclose(fd); 00914 return; 00915 } 00916 zone->klass = (ldns_rr_class) klass; 00917 zone->fetch = fetch; 00918 00919 se_fclose(fd); 00920 } else { 00921 se_log_deeebug("unable to recover zone state from file %s.state: ", 00922 "no such file or directory", zone->name); 00923 return; 00924 } 00925 00926 /* let's see if we can recover the signconf now */ 00927 filename = se_build_path(zone->name, ".sc", 0); 00928 zone->signconf = signconf_recover_from_backup((const char*) filename); 00929 se_free((void*)filename); 00930 if (!zone->signconf) { 00931 /* no, stop recovering process */ 00932 return; 00933 } 00934 zone->signconf->name = zone->name; 00935 zone->signconf->keys = keylist_create(); 00936 00937 /* recover denial of existence */ 00938 filename = se_build_path(zone->name, ".denial", 0); 00939 fd = se_fopen(filename, NULL, "r"); 00940 se_free((void*)filename); 00941 if (fd) { 00942 error = zonedata_recover_from_backup(zone->zonedata, fd); 00943 se_fclose(fd); 00944 if (error) { 00945 se_log_error("unable to recover denial of existence from file " 00946 "%s.denial: file corrupted", zone->name); 00947 if (zone->zonedata) { 00948 zonedata_cleanup(zone->zonedata); 00949 zone->zonedata = NULL; 00950 } 00951 zone->zonedata = zonedata_create(); 00952 } 00953 } else { 00954 se_log_deeebug("unable to recover denial of existence from file " 00955 "%s.denial: no such file or directory", zone->name); 00956 error = 1; 00957 } 00958 if (error) { 00959 goto abort_recover; 00960 } 00961 00962 /* zone data */ 00963 filename = se_build_path(zone->name, ".unsorted", 0); 00964 error = adfile_read(zone, filename, 1); 00965 se_free((void*)filename); 00966 if (error) { 00967 se_log_error("unable to recover unsorted zone from file " 00968 "%s.unsorted: parse error", zone->name); 00969 if (zone->zonedata) { 00970 zonedata_cleanup(zone->zonedata); 00971 zone->zonedata = NULL; 00972 } 00973 zone->zonedata = zonedata_create(); 00974 goto abort_recover; 00975 } 00976 00977 /* time for the keys and nsec3params file */ 00978 filename = se_build_path(zone->name, ".dnskeys", 0); 00979 fd = se_fopen(filename, NULL, "r"); 00980 se_free((void*)filename); 00981 if (fd) { 00982 error = zone_recover_dnskeys_from_backup(zone, fd); 00983 se_fclose(fd); 00984 if (error) { 00985 se_log_error("unable to recover dnskeys from file %s.dnskeys: " 00986 "file corrupted", zone->name); 00987 } 00988 } else { 00989 se_log_deeebug("unable to recover dnskeys from file %s.dnskeys: ", 00990 "no such file or directory", zone->name); 00991 error = 1; 00992 } 00993 if (error) { 00994 goto abort_recover; 00995 } 00996 00997 /* retrieve signatures */ 00998 filename = se_build_path(zone->name, ".rrsigs", 0); 00999 fd = se_fopen(filename, NULL, "r"); 01000 se_free((void*)filename); 01001 if (fd) { 01002 error = zone_recover_rrsigs_from_backup(zone, fd); 01003 se_fclose(fd); 01004 if (error) { 01005 se_log_error("unable to recover rrsigs from file %s.rrsigs: " 01006 "file corrupted", zone->name); 01007 } 01008 } else { 01009 se_log_deeebug("unable to recover rrsigs from file %s.rrsigs: ", 01010 "no such file or directory", zone->name); 01011 } 01012 01013 abort_recover: 01014 01015 /* task */ 01016 filename = se_build_path(zone->name, ".task", 0); 01017 zone->task = task_recover_from_backup((const char*) filename, zone); 01018 se_free((void*)filename); 01019 01020 if (!zone->task) { 01021 now = time_now(); 01022 zone->task = task_create(TASK_READ, now, zone->name, zone); 01023 } 01024 if (!zone->task) { 01025 se_log_error("failed to create task for zone %s", zone->name); 01026 } else { 01027 if (error) { 01028 zone->task->what = TASK_READ; 01029 } 01030 01031 task = tasklist_schedule_task(tl, zone->task, 1); 01032 if (!task) { 01033 se_log_error("failed to schedule task for zone %s", zone->name); 01034 } 01035 } 01036 01037 if (error) { 01038 zone->signconf->last_modified = 0; 01039 } 01040 return; 01041 } 01042 01043 01048 void 01049 zone_cleanup(zone_type* zone) 01050 { 01051 if (zone) { 01052 if (zone->dname) { 01053 ldns_rdf_deep_free(zone->dname); 01054 zone->dname = NULL; 01055 } 01056 if (zone->notify_ns) { 01057 se_free((void*)zone->notify_ns); 01058 zone->notify_ns = NULL; 01059 } 01060 if (zone->inbound_adapter) { 01061 adapter_cleanup(zone->inbound_adapter); 01062 zone->inbound_adapter = NULL; 01063 } 01064 if (zone->outbound_adapter) { 01065 adapter_cleanup(zone->outbound_adapter); 01066 zone->outbound_adapter = NULL; 01067 } 01068 if (zone->signconf) { 01069 signconf_cleanup(zone->signconf); 01070 zone->signconf = NULL; 01071 } 01072 if (zone->stats) { 01073 stats_cleanup(zone->stats); 01074 zone->stats = NULL; 01075 } 01076 if (zone->zonedata) { 01077 zonedata_cleanup(zone->zonedata); 01078 zone->zonedata = NULL; 01079 } 01080 if (zone->nsec3params) { 01081 nsec3params_cleanup(zone->nsec3params); 01082 zone->nsec3params = NULL; 01083 } 01084 if (zone->policy_name) { 01085 se_free((void*) zone->policy_name); 01086 zone->policy_name = NULL; 01087 } 01088 if (zone->signconf_filename) { 01089 se_free((void*) zone->signconf_filename); 01090 zone->signconf_filename = NULL; 01091 } 01092 if (zone->name) { 01093 se_free((void*) zone->name); 01094 zone->name = NULL; 01095 } 01096 01097 lock_basic_destroy(&zone->zone_lock); 01098 se_free((void*) zone); 01099 } else { 01100 se_log_warning("cleanup emtpy zone"); 01101 } 01102 return; 01103 } 01104 01105 01110 void 01111 zone_print(FILE* out, zone_type* zone) 01112 { 01113 se_log_assert(out); 01114 se_log_assert(zone); 01115 se_log_assert(zone->zonedata); 01116 01117 zonedata_print(out, zone->zonedata); 01118 return; 01119 }