OpenDNSSEC-signer 2.1.13
zonelist.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 "config.h"
33#include "parser/confparser.h"
35#include "duration.h"
36#include "file.h"
37#include "log.h"
38#include "status.h"
39#include "signer/zone.h"
40#include "signer/zonelist.h"
41
42#include <ldns/ldns.h>
43#include <stdlib.h>
44
45static const char* zl_str = "zonelist";
46
47
52static int
53zone_compare(const void* a, const void* b)
54{
55 zone_type* x = (zone_type*)a;
56 zone_type* y = (zone_type*)b;
57 ods_log_assert(x);
58 ods_log_assert(y);
59 if (x->klass != y->klass) {
60 if (x->klass < y->klass) {
61 return -1;
62 }
63 return 1;
64 }
65 return ldns_dname_compare(x->apex, y->apex);
66}
67
68
75{
76 zonelist_type* zlist = NULL;
77 CHECKALLOC(zlist = (zonelist_type*) malloc(sizeof(zonelist_type)));
78 if (!zlist) {
79 ods_log_error("[%s] unable to create zonelist: allocator_alloc() "
80 "failed", zl_str);
81 return NULL;
82 }
83 zlist->zones = ldns_rbtree_create(zone_compare);
84 if (!zlist->zones) {
85 ods_log_error("[%s] unable to create zonelist: ldns_rbtree_create() "
86 "failed", zl_str);
87 free(zlist);
88 return NULL;
89 }
90 zlist->last_modified = 0;
91 pthread_mutex_init(&zlist->zl_lock, NULL);
92 return zlist;
93}
94
95
100static ods_status
101zonelist_read(zonelist_type* zl, const char* zlfile)
102{
103 const char* rngfile = ODS_SE_RNGDIR "/zonelist.rng";
104 ods_status status = ODS_STATUS_OK;
105 ods_log_assert(zlfile);
106 ods_log_verbose("[%s] read file %s", zl_str, zlfile);
107 status = parse_file_check(zlfile, rngfile);
108 if (status != ODS_STATUS_OK) {
109 ods_log_error("[%s] unable to read file: parse error in %s", zl_str,
110 zlfile);
111 return status;
112 }
113 return parse_zonelist_zones((struct zonelist_struct*) zl, zlfile);
114}
115
116
121static ldns_rbnode_t*
122zone2node(zone_type* zone)
123{
124 ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
125 if (!node) {
126 return NULL;
127 }
128 node->key = zone;
129 node->data = zone;
130 return node;
131}
132
133
138static zone_type*
139zonelist_lookup_zone(zonelist_type* zonelist, zone_type* zone)
140{
141 ldns_rbnode_t* node = LDNS_RBTREE_NULL;
142 if (zonelist && zonelist->zones && zone) {
143 node = ldns_rbtree_search(zonelist->zones, zone);
144 if (node) {
145 return (zone_type*) node->data;
146 }
147 }
148 return NULL;
149}
150
151
157zonelist_lookup_zone_by_name(zonelist_type* zonelist, const char* name,
158 ldns_rr_class klass)
159{
160 zone_type* zone = NULL;
161 zone_type* result = NULL;
162 if (zonelist && zonelist->zones && name && klass) {
163 zone = zone_create((char*) name, klass);
164 if (!zone) {
165 ods_log_error("[%s] unable to lookup zone %s: "
166 "zone_create() failed", zl_str, name);
167 /* result stays NULL */
168 } else {
169 result = zonelist_lookup_zone(zonelist, zone);
170 zone_cleanup(zone);
171 }
172 }
173 return result;
174}
175
176
183 ldns_rr_class klass)
184{
185 char* name = NULL;
186 zone_type* result = NULL;
187 if (zonelist && zonelist->zones && dname && klass) {
188 name = ldns_rdf2str(dname);
189 result = zonelist_lookup_zone_by_name(zonelist, name, klass);
190 free((void*)name);
191 }
192 return result;
193}
194
195
202{
203 ldns_rbnode_t* new_node = NULL;
204 if (!zone) {
205 return NULL;
206 }
207 if (!zlist || !zlist->zones) {
208 zone_cleanup(zone);
209 return NULL;
210 }
211 /* look up */
212 if (zonelist_lookup_zone(zlist, zone) != NULL) {
213 ods_log_warning("[%s] unable to add zone %s: already present", zl_str,
214 zone->name);
215 zone_cleanup(zone);
216 return NULL;
217 }
218 /* add */
219 new_node = zone2node(zone);
220 if (ldns_rbtree_insert(zlist->zones, new_node) == NULL) {
221 ods_log_error("[%s] unable to add zone %s: ldns_rbtree_insert() "
222 "failed", zl_str, zone->name);
223 free((void*) new_node);
224 zone_cleanup(zone);
225 return NULL;
226 }
227 zone->zl_status = ZONE_ZL_ADDED;
228 zlist->just_added++;
229 return zone;
230}
231
232
237void
239{
240 ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
241 assert(zone);
242 if (!zlist || !zlist->zones) {
243 goto zone_not_present;
244 }
245 old_node = ldns_rbtree_delete(zlist->zones, zone);
246 if (!old_node) {
247 goto zone_not_present;
248 }
249 free((void*) old_node);
250 return;
251
252zone_not_present:
253 ods_log_warning("[%s] unable to delete zone %s: not present", zl_str,
254 zone->name);
255}
256
257
262static void
263zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
264{
265 zone_type* z1 = NULL;
266 zone_type* z2 = NULL;
267 ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
268 ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
269 int ret = 0;
270
271 ods_log_assert(zl1);
272 ods_log_assert(zl2);
273 ods_log_assert(zl1->zones);
274 ods_log_assert(zl2->zones);
275 ods_log_debug("[%s] merge two zone lists", zl_str);
276
277 n1 = ldns_rbtree_first(zl1->zones);
278 n2 = ldns_rbtree_first(zl2->zones);
279 while (n2 && n2 != LDNS_RBTREE_NULL) {
280 z2 = (zone_type*) n2->data;
281 if (n1 && n1 != LDNS_RBTREE_NULL) {
282 z1 = (zone_type*) n1->data;
283 } else {
284 z1 = NULL;
285 }
286 if (!z2) {
287 /* no more zones to merge into zl1 */
288 return;
289 } else if (!z1) {
290 /* just add remaining zones from zl2 */
291 z2 = zonelist_add_zone(zl1, z2);
292 if (!z2) {
293 ods_log_crit("[%s] merge failed: z2 not added", zl_str);
294 return;
295 }
296 n2 = ldns_rbtree_next(n2);
297 } else {
298 /* compare the zones z1 and z2 */
299 ret = zone_compare(z1, z2);
300 if (ret < 0) {
301 /* remove zone z1, it is not present in the new list zl2 */
303 zl1->just_removed++;
304 n1 = ldns_rbtree_next(n1);
305 } else if (ret > 0) {
306 /* add the new zone z2 */
307 z2 = zonelist_add_zone(zl1, z2);
308 if (!z2) {
309 ods_log_crit("[%s] merge failed: z2 not added", zl_str);
310 return;
311 }
312 n2 = ldns_rbtree_next(n2);
313 } else {
314 /* just update zone z1 */
315 n1 = ldns_rbtree_next(n1);
316 n2 = ldns_rbtree_next(n2);
317 zone_merge(z1, z2);
318 zone_cleanup(z2);
319 if (z1->zl_status == ZONE_ZL_UPDATED) {
320 zl1->just_updated++;
321 }
323 }
324 }
325 }
326 /* remove remaining zones from z1 */
327 while (n1 && n1 != LDNS_RBTREE_NULL) {
328 z1 = (zone_type*) n1->data;
330 zl1->just_removed++;
331 n1 = ldns_rbtree_next(n1);
332 }
333 zl1->last_modified = zl2->last_modified;
334}
335
336
341ods_status
342zonelist_update(zonelist_type* zl, const char* zlfile)
343{
344 zonelist_type* new_zlist = NULL;
345 time_t st_mtime = 0;
346 ods_status status = ODS_STATUS_OK;
347 char* datestamp = NULL;
348
349 ods_log_debug("[%s] update zone list", zl_str);
350 if (!zl|| !zl->zones || !zlfile) {
351 return ODS_STATUS_ASSERT_ERR;
352 }
353 /* is the file updated? */
354 /* OPENDNSSEC-686: changes happening within one second will not be
355 * seen
356 */
357 st_mtime = ods_file_lastmodified(zlfile);
358 if (st_mtime <= zl->last_modified) {
359 (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
360 ods_log_debug("[%s] zonelist file %s is unchanged since %s",
361 zl_str, zlfile, datestamp?datestamp:"Unknown");
362 free((void*)datestamp);
363 return ODS_STATUS_UNCHANGED;
364 }
365 /* create new zonelist */
366 new_zlist = zonelist_create();
367 if (!new_zlist) {
368 ods_log_error("[%s] unable to update zonelist: zonelist_create() "
369 "failed", zl_str);
370 return ODS_STATUS_ERR;
371 }
372 /* read zonelist */
373 status = zonelist_read(new_zlist, zlfile);
374 if (status == ODS_STATUS_OK) {
375 zl->just_removed = 0;
376 zl->just_added = 0;
377 zl->just_updated = 0;
378 new_zlist->last_modified = st_mtime;
379 zonelist_merge(zl, new_zlist);
380 (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
381 ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile,
382 datestamp?datestamp:"Unknown");
383 free((void*)datestamp);
384 } else {
385 ods_log_error("[%s] unable to update zonelist: read file %s failed "
386 "(%s)", zl_str, zlfile, ods_status2str(status));
387 }
388 zonelist_free(new_zlist);
389 return status;
390}
391
392
397static void
398zone_delfunc(ldns_rbnode_t* elem)
399{
400 zone_type* zone;
401 if (elem && elem != LDNS_RBTREE_NULL) {
402 zone = (zone_type*) elem->data;
403 zone_delfunc(elem->left);
404 zone_delfunc(elem->right);
405 ods_log_deeebug("[%s] cleanup zone %s", zl_str, zone->name);
406 zone_cleanup(zone);
407 free((void*)elem);
408 }
409}
410
411
416static void
417node_delfunc(ldns_rbnode_t* elem)
418{
419 if (elem && elem != LDNS_RBTREE_NULL) {
420 node_delfunc(elem->left);
421 node_delfunc(elem->right);
422 free((void*)elem);
423 }
424}
425
426
431void
433{
434 if (!zl) {
435 return;
436 }
437 ods_log_debug("[%s] cleanup zonelist", zl_str);
438 if (zl->zones) {
439 zone_delfunc(zl->zones->root);
440 ldns_rbtree_free(zl->zones);
441 zl->zones = NULL;
442 }
443 pthread_mutex_destroy(&zl->zl_lock);
444 free(zl);
445}
446
447
452void
454{
455 if (!zl) {
456 return;
457 }
458 if (zl->zones) {
459 node_delfunc(zl->zones->root);
460 ldns_rbtree_free(zl->zones);
461 zl->zones = NULL;
462 }
463 pthread_mutex_destroy(&zl->zl_lock);
464 free(zl);
465}
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition: confparser.c:55
ldns_rr_class klass
Definition: zone.h:62
ldns_rdf * apex
Definition: zone.h:61
zone_zl_status zl_status
Definition: zone.h:72
const char * name
Definition: zone.h:69
int just_updated
Definition: zonelist.h:48
time_t last_modified
Definition: zonelist.h:46
int just_removed
Definition: zonelist.h:49
pthread_mutex_t zl_lock
Definition: zonelist.h:50
ldns_rbtree_t * zones
Definition: zonelist.h:45
void zone_merge(zone_type *z1, zone_type *z2)
Definition: zone.c:694
void zone_cleanup(zone_type *zone)
Definition: zone.c:759
zone_type * zone_create(char *name, ldns_rr_class klass)
Definition: zone.c:55
@ ZONE_ZL_REMOVED
Definition: zone.h:37
@ ZONE_ZL_ADDED
Definition: zone.h:35
@ ZONE_ZL_UPDATED
Definition: zone.h:36
zone_type * zonelist_lookup_zone_by_dname(zonelist_type *zonelist, ldns_rdf *dname, ldns_rr_class klass)
Definition: zonelist.c:182
zonelist_type * zonelist_create()
Definition: zonelist.c:74
void zonelist_del_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:238
void zonelist_free(zonelist_type *zl)
Definition: zonelist.c:453
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:342
void zonelist_cleanup(zonelist_type *zl)
Definition: zonelist.c:432
zone_type * zonelist_add_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:201
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:157
ods_status parse_zonelist_zones(void *zlist, const char *zlfile)