OpenDNSSEC-signer 1.3.0
|
00001 /* 00002 * $Id: zonelist.c 5320 2011-07-12 10:42:26Z jakob $ 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 "config.h" 00035 #include "parser/confparser.h" 00036 #include "parser/zonelistparser.h" 00037 #include "shared/allocator.h" 00038 #include "shared/duration.h" 00039 #include "shared/file.h" 00040 #include "shared/log.h" 00041 #include "shared/status.h" 00042 #include "signer/zone.h" 00043 #include "signer/zonelist.h" 00044 00045 #include <ldns/ldns.h> 00046 #include <stdlib.h> 00047 00048 static const char* zl_str = "zonelist"; 00049 00050 00055 static int 00056 zone_compare(const void* a, const void* b) 00057 { 00058 zone_type* x = (zone_type*)a; 00059 zone_type* y = (zone_type*)b; 00060 00061 ods_log_assert(x); 00062 ods_log_assert(y); 00063 00064 if (x->klass != y->klass) { 00065 if (x->klass < y->klass) { 00066 return -1; 00067 } 00068 return 1; 00069 } 00070 return ldns_dname_compare(x->dname, y->dname); 00071 } 00072 00073 00078 zonelist_type* 00079 zonelist_create(allocator_type* allocator) 00080 { 00081 zonelist_type* zlist; 00082 if (!allocator) { 00083 ods_log_error("[%s] cannot create: no allocator available", zl_str); 00084 return NULL; 00085 } 00086 ods_log_assert(allocator); 00087 00088 zlist = (zonelist_type*) allocator_alloc(allocator, sizeof(zonelist_type)); 00089 if (!zlist) { 00090 ods_log_error("[%s] cannot create: allocator failed", zl_str); 00091 return NULL; 00092 } 00093 ods_log_assert(zlist); 00094 00095 zlist->allocator = allocator; 00096 zlist->zones = ldns_rbtree_create(zone_compare); 00097 zlist->last_modified = 0; 00098 lock_basic_init(&zlist->zl_lock); 00099 return zlist; 00100 } 00101 00102 00107 static ods_status 00108 zonelist_read(zonelist_type* zl, const char* zlfile) 00109 { 00110 const char* rngfile = ODS_SE_RNGDIR "/zonelist.rng"; 00111 ods_status status = ODS_STATUS_OK; 00112 00113 ods_log_assert(zlfile); 00114 ods_log_verbose("[%s] read file %s", zl_str, zlfile); 00115 00116 /* does the file have no parse errors? */ 00117 status = parse_file_check(zlfile, rngfile); 00118 if (status != ODS_STATUS_OK) { 00119 ods_log_error("[%s] unable to parse file %s: %s", zl_str, 00120 zlfile, ods_status2str(status)); 00121 return status; 00122 } 00123 00124 /* ok, parse it */ 00125 return parse_zonelist_zones((struct zonelist_struct*) zl, zlfile); 00126 } 00127 00128 00133 static ldns_rbnode_t* 00134 zone2node(zone_type* zone) 00135 { 00136 ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t)); 00137 if (!node) { 00138 return NULL; 00139 } 00140 node->key = zone; 00141 node->data = zone; 00142 return node; 00143 } 00144 00145 00150 static zone_type* 00151 zonelist_lookup_zone(zonelist_type* zonelist, zone_type* zone) 00152 { 00153 ldns_rbnode_t* node = LDNS_RBTREE_NULL; 00154 00155 if (!zonelist || !zonelist->zones) { 00156 ods_log_error("[%s] unable to lookup zone: no zonelist", zl_str); 00157 return NULL; 00158 } 00159 ods_log_assert(zonelist); 00160 ods_log_assert(zonelist->zones); 00161 if (!zone) { 00162 ods_log_error("[%s] unable to lookup zone: zone is null", zl_str); 00163 return NULL; 00164 } 00165 ods_log_assert(zone); 00166 00167 node = ldns_rbtree_search(zonelist->zones, zone); 00168 if (node) { 00169 return (zone_type*) node->data; 00170 } 00171 return NULL; 00172 } 00173 00174 00179 zone_type* 00180 zonelist_lookup_zone_by_name(zonelist_type* zonelist, const char* name, 00181 ldns_rr_class klass) 00182 { 00183 zone_type* zone = NULL; 00184 zone_type* result = NULL; 00185 00186 if (!zonelist || !zonelist->zones || !name || !klass) { 00187 return NULL; 00188 } 00189 ods_log_assert(zonelist); 00190 ods_log_assert(zonelist->zones); 00191 ods_log_assert(name); 00192 ods_log_assert(klass); 00193 00194 zone = zone_create((char*) name, klass); 00195 if (!zone) { 00196 ods_log_error("[%s] unable to lookup zone: create zone failed", zl_str); 00197 return NULL; 00198 } 00199 result = zonelist_lookup_zone(zonelist, zone); 00200 zone_cleanup(zone); 00201 return result; 00202 } 00203 00204 00209 zone_type* 00210 zonelist_add_zone(zonelist_type* zlist, zone_type* zone) 00211 { 00212 ldns_rbnode_t* new_node = NULL; 00213 00214 if (!zone) { 00215 ods_log_error("[%s] unable to add zone: zone is null", zl_str); 00216 return NULL; 00217 } 00218 ods_log_assert(zone); 00219 if (!zlist || !zlist->zones) { 00220 ods_log_error("[%s] unable to add zone %s: no zonelist", zl_str, 00221 zone->name); 00222 zone_cleanup(zone); 00223 return NULL; 00224 } 00225 ods_log_assert(zlist); 00226 ods_log_assert(zlist->zones); 00227 00228 if (zonelist_lookup_zone(zlist, zone) != NULL) { 00229 ods_log_warning("[%s] unable to add zone %s: already present", zl_str, 00230 zone->name); 00231 zone_cleanup(zone); 00232 return NULL; 00233 } 00234 00235 new_node = zone2node(zone); 00236 if (ldns_rbtree_insert(zlist->zones, new_node) == NULL) { 00237 ods_log_error("[%s] unable to add zone %s: rbtree insert failed", 00238 zl_str, zone->name); 00239 free((void*) new_node); 00240 zone_cleanup(zone); 00241 return NULL; 00242 } 00243 zone->just_added = 1; 00244 zlist->just_added++; 00245 return zone; 00246 } 00247 00248 00253 zone_type* 00254 zonelist_del_zone(zonelist_type* zlist, zone_type* zone) 00255 { 00256 ldns_rbnode_t* old_node = LDNS_RBTREE_NULL; 00257 00258 if (!zone) { 00259 ods_log_warning("[%s] unable to delete zone: zone is null", zl_str); 00260 return NULL; 00261 } 00262 ods_log_assert(zone); 00263 if (!zlist || !zlist->zones) { 00264 ods_log_error("[%s] unable to delete zone %s: no zone list", zl_str, 00265 zone->name); 00266 return zone; 00267 } 00268 ods_log_assert(zlist); 00269 ods_log_assert(zlist->zones); 00270 00271 old_node = ldns_rbtree_delete(zlist->zones, zone); 00272 if (!old_node) { 00273 ods_log_warning("[%s] unable to delete zone %s: not present", zl_str, 00274 zone->name); 00275 return zone; 00276 } 00277 free((void*) old_node); 00278 return zone; 00279 } 00280 00281 00286 static void 00287 zonelist_merge(zonelist_type* zl1, zonelist_type* zl2) 00288 { 00289 zone_type* z1 = NULL; 00290 zone_type* z2 = NULL; 00291 ldns_rbnode_t* n1 = LDNS_RBTREE_NULL; 00292 ldns_rbnode_t* n2 = LDNS_RBTREE_NULL; 00293 int ret = 0; 00294 00295 ods_log_assert(zl1); 00296 ods_log_assert(zl2); 00297 ods_log_assert(zl1->zones); 00298 ods_log_assert(zl2->zones); 00299 ods_log_debug("[%s] merge two zone lists", zl_str); 00300 00301 n1 = ldns_rbtree_first(zl1->zones); 00302 n2 = ldns_rbtree_first(zl2->zones); 00303 while (n2 && n2 != LDNS_RBTREE_NULL) { 00304 z2 = (zone_type*) n2->data; 00305 if (n1 && n1 != LDNS_RBTREE_NULL) { 00306 z1 = (zone_type*) n1->data; 00307 } else { 00308 z1 = NULL; 00309 } 00310 00311 if (!z2) { 00312 /* no more zones to merge into zl1 */ 00313 return; 00314 } else if (!z1) { 00315 /* just add remaining zones from zl2 */ 00316 z2 = zonelist_add_zone(zl1, z2); 00317 if (!z2) { 00318 ods_log_error("[%s] merge failed: z2 not added", zl_str); 00319 return; 00320 } 00321 n2 = ldns_rbtree_next(n2); 00322 } else { 00323 /* compare the zones z1 and z2 */ 00324 ret = zone_compare(z1, z2); 00325 if (ret < 0) { 00326 /* remove zone z1, it is not present in the new list zl2 */ 00327 z1->tobe_removed = 1; 00328 zl1->just_removed++; 00329 n1 = ldns_rbtree_next(n1); 00330 } else if (ret > 0) { 00331 /* add the new zone z2 */ 00332 z2 = zonelist_add_zone(zl1, z2); 00333 if (!z2) { 00334 ods_log_error("[%s] merge failed: z2 not added", zl_str); 00335 return; 00336 } 00337 n2 = ldns_rbtree_next(n2); 00338 } else { 00339 /* just update zone z1 */ 00340 n1 = ldns_rbtree_next(n1); 00341 n2 = ldns_rbtree_next(n2); 00342 zone_merge(z1, z2); 00343 zone_cleanup(z2); 00344 if (z1->just_updated) { 00345 zl1->just_updated++; 00346 } 00347 z1->just_updated = 1; 00348 } 00349 } 00350 } 00351 00352 /* remove remaining zones from z1 */ 00353 while (n1 && n1 != LDNS_RBTREE_NULL) { 00354 z1 = (zone_type*) n1->data; 00355 z1->tobe_removed = 1; 00356 zl1->just_removed++; 00357 n1 = ldns_rbtree_next(n1); 00358 } 00359 00360 zl1->last_modified = zl2->last_modified; 00361 return; 00362 } 00363 00364 00369 ods_status 00370 zonelist_update(zonelist_type* zl, const char* zlfile) 00371 { 00372 zonelist_type* new_zlist = NULL; 00373 allocator_type* tmp_alloc = NULL; 00374 time_t st_mtime = 0; 00375 ods_status status = ODS_STATUS_OK; 00376 char* datestamp = NULL; 00377 uint32_t ustamp = 0; 00378 00379 ods_log_debug("[%s] update zone list", zl_str); 00380 if (!zl|| !zl->zones) { 00381 ods_log_error("[%s] cannot update: no zonelist storaga", zl_str); 00382 return ODS_STATUS_ASSERT_ERR; 00383 } 00384 ods_log_assert(zl); 00385 ods_log_assert(zl->zones); 00386 if (!zlfile) { 00387 ods_log_error("[%s] cannot update: no filename", zl_str); 00388 return ODS_STATUS_ASSERT_ERR; 00389 } 00390 ods_log_assert(zlfile); 00391 00392 /* is the file updated? */ 00393 st_mtime = ods_file_lastmodified(zlfile); 00394 if (st_mtime <= zl->last_modified) { 00395 ustamp = time_datestamp(zl->last_modified, 00396 "%Y-%m-%d %T", &datestamp); 00397 ods_log_debug("[%s] zonelist file %s is unchanged since %s", 00398 zl_str, zlfile, datestamp?datestamp:"Unknown"); 00399 free((void*)datestamp); 00400 return ODS_STATUS_UNCHANGED; 00401 } 00402 00403 /* create new zonelist */ 00404 tmp_alloc = allocator_create(malloc, free); 00405 if (!tmp_alloc) { 00406 ods_log_error("[%s] error creating allocator for zone list", 00407 zl_str); 00408 return ODS_STATUS_ERR; 00409 } 00410 new_zlist = zonelist_create(tmp_alloc); 00411 if (!new_zlist) { 00412 ods_log_error("[%s] error creating new zone list", zl_str); 00413 allocator_cleanup(tmp_alloc); 00414 return ODS_STATUS_ERR; 00415 } 00416 00417 /* read zonelist */ 00418 status = zonelist_read(new_zlist, zlfile); 00419 if (status == ODS_STATUS_OK) { 00420 zl->just_removed = 0; 00421 zl->just_added = 0; 00422 zl->just_updated = 0; 00423 new_zlist->last_modified = st_mtime; 00424 zonelist_merge(zl, new_zlist); 00425 ustamp = time_datestamp(zl->last_modified, "%Y-%m-%d %T", 00426 &datestamp); 00427 ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile, 00428 datestamp?datestamp:"Unknown"); 00429 free((void*)datestamp); 00430 } else { 00431 ods_log_error("[%s] unable to read file %s: %s", zl_str, zlfile, 00432 ods_status2str(status)); 00433 } 00434 00435 zonelist_free(new_zlist); 00436 allocator_cleanup(tmp_alloc); 00437 return status; 00438 } 00439 00440 00445 static void 00446 zone_delfunc(ldns_rbnode_t* elem) 00447 { 00448 zone_type* zone; 00449 00450 if (elem && elem != LDNS_RBTREE_NULL) { 00451 zone = (zone_type*) elem->data; 00452 zone_delfunc(elem->left); 00453 zone_delfunc(elem->right); 00454 00455 ods_log_debug("[%s] cleanup zone %s", zl_str, zone->name); 00456 zone_cleanup(zone); 00457 free((void*)elem); 00458 } 00459 return; 00460 } 00461 00462 00467 static void 00468 node_delfunc(ldns_rbnode_t* elem) 00469 { 00470 if (elem && elem != LDNS_RBTREE_NULL) { 00471 node_delfunc(elem->left); 00472 node_delfunc(elem->right); 00473 free((void*)elem); 00474 } 00475 return; 00476 } 00477 00478 00483 void 00484 zonelist_cleanup(zonelist_type* zl) 00485 { 00486 allocator_type* allocator; 00487 lock_basic_type zl_lock; 00488 00489 if (!zl) { 00490 return; 00491 } 00492 00493 ods_log_debug("[%s] cleanup zonelist", zl_str); 00494 if (zl->zones) { 00495 zone_delfunc(zl->zones->root); 00496 ldns_rbtree_free(zl->zones); 00497 zl->zones = NULL; 00498 } 00499 00500 allocator = zl->allocator; 00501 zl_lock = zl->zl_lock; 00502 00503 allocator_deallocate(allocator, (void*) zl); 00504 lock_basic_destroy(&zl_lock); 00505 return; 00506 } 00507 00508 00513 void 00514 zonelist_free(zonelist_type* zl) 00515 { 00516 allocator_type* allocator; 00517 lock_basic_type zl_lock; 00518 00519 if (!zl) { 00520 return; 00521 } 00522 00523 if (zl->zones) { 00524 node_delfunc(zl->zones->root); 00525 ldns_rbtree_free(zl->zones); 00526 zl->zones = NULL; 00527 } 00528 00529 allocator = zl->allocator; 00530 zl_lock = zl->zl_lock; 00531 00532 allocator_deallocate(allocator, (void*) zl); 00533 lock_basic_destroy(&zl_lock); 00534 return; 00535 }