OpenDNSSEC-signer  1.4.9
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"
34 #include "parser/zonelistparser.h"
35 #include "shared/allocator.h"
36 #include "shared/duration.h"
37 #include "shared/file.h"
38 #include "shared/log.h"
39 #include "shared/status.h"
40 #include "signer/zone.h"
41 #include "signer/zonelist.h"
42 
43 #include <ldns/ldns.h>
44 #include <stdlib.h>
45 
46 static const char* zl_str = "zonelist";
47 
48 
53 static int
54 zone_compare(const void* a, const void* b)
55 {
56  zone_type* x = (zone_type*)a;
57  zone_type* y = (zone_type*)b;
58  ods_log_assert(x);
59  ods_log_assert(y);
60  if (x->klass != y->klass) {
61  if (x->klass < y->klass) {
62  return -1;
63  }
64  return 1;
65  }
66  return ldns_dname_compare(x->apex, y->apex);
67 }
68 
69 
76 {
77  zonelist_type* zlist = NULL;
78  if (allocator) {
79  zlist = (zonelist_type*) allocator_alloc(allocator, sizeof(zonelist_type));
80  }
81  if (!zlist) {
82  ods_log_error("[%s] unable to create zonelist: allocator_alloc() "
83  "failed", zl_str);
84  return NULL;
85  }
86  zlist->allocator = allocator;
87  zlist->zones = ldns_rbtree_create(zone_compare);
88  if (!zlist->zones) {
89  ods_log_error("[%s] unable to create zonelist: ldns_rbtree_create() "
90  "failed", zl_str);
91  allocator_deallocate(allocator, (void*) zlist);
92  return NULL;
93  }
94  zlist->last_modified = 0;
95  lock_basic_init(&zlist->zl_lock);
96  return zlist;
97 }
98 
99 
104 static ods_status
105 zonelist_read(zonelist_type* zl, const char* zlfile)
106 {
107  const char* rngfile = ODS_SE_RNGDIR "/zonelist.rng";
108  ods_status status = ODS_STATUS_OK;
109  ods_log_assert(zlfile);
110  ods_log_verbose("[%s] read file %s", zl_str, zlfile);
111  status = parse_file_check(zlfile, rngfile);
112  if (status != ODS_STATUS_OK) {
113  ods_log_error("[%s] unable to read file: parse error in %s", zl_str,
114  zlfile);
115  return status;
116  }
117  return parse_zonelist_zones((struct zonelist_struct*) zl, zlfile);
118 }
119 
120 
125 static ldns_rbnode_t*
126 zone2node(zone_type* zone)
127 {
128  ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
129  if (!node) {
130  return NULL;
131  }
132  node->key = zone;
133  node->data = zone;
134  return node;
135 }
136 
137 
142 static zone_type*
143 zonelist_lookup_zone(zonelist_type* zonelist, zone_type* zone)
144 {
145  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
146  if (zonelist && zonelist->zones && zone) {
147  node = ldns_rbtree_search(zonelist->zones, zone);
148  if (node) {
149  return (zone_type*) node->data;
150  }
151  }
152  return NULL;
153 }
154 
155 
160 zone_type*
161 zonelist_lookup_zone_by_name(zonelist_type* zonelist, const char* name,
162  ldns_rr_class klass)
163 {
164  zone_type* zone = NULL;
165  zone_type* result = NULL;
166  if (zonelist && zonelist->zones && name && klass) {
167  zone = zone_create((char*) name, klass);
168  if (!zone) {
169  ods_log_error("[%s] unable to lookup zone %s: "
170  "zone_create() failed", zl_str, name);
171  /* result stays NULL */
172  } else {
173  result = zonelist_lookup_zone(zonelist, zone);
174  zone_cleanup(zone);
175  }
176  }
177  return result;
178 }
179 
180 
185 zone_type*
186 zonelist_lookup_zone_by_dname(zonelist_type* zonelist, ldns_rdf* dname,
187  ldns_rr_class klass)
188 {
189  char* name = NULL;
190  zone_type* result = NULL;
191  if (zonelist && zonelist->zones && dname && klass) {
192  name = ldns_rdf2str(dname);
193  result = zonelist_lookup_zone_by_name(zonelist, name, klass);
194  free((void*)name);
195  }
196  return result;
197 }
198 
199 
204 zone_type*
206 {
207  ldns_rbnode_t* new_node = NULL;
208  if (!zone) {
209  return NULL;
210  }
211  if (!zlist || !zlist->zones) {
212  zone_cleanup(zone);
213  return NULL;
214  }
215  /* look up */
216  if (zonelist_lookup_zone(zlist, zone) != NULL) {
217  ods_log_warning("[%s] unable to add zone %s: already present", zl_str,
218  zone->name);
219  zone_cleanup(zone);
220  return NULL;
221  }
222  /* add */
223  new_node = zone2node(zone);
224  if (ldns_rbtree_insert(zlist->zones, new_node) == NULL) {
225  ods_log_error("[%s] unable to add zone %s: ldns_rbtree_insert() "
226  "failed", zl_str, zone->name);
227  free((void*) new_node);
228  zone_cleanup(zone);
229  return NULL;
230  }
231  zone->zl_status = ZONE_ZL_ADDED;
232  zlist->just_added++;
233  return zone;
234 }
235 
236 
241 zone_type*
243 {
244  ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
245  if (!zone) {
246  return NULL;
247  }
248  if (!zlist || !zlist->zones) {
249  goto zone_not_present;
250  }
251  old_node = ldns_rbtree_delete(zlist->zones, zone);
252  if (!old_node) {
253  goto zone_not_present;
254  }
255  free((void*) old_node);
256  return zone;
257 
258 zone_not_present:
259  ods_log_warning("[%s] unable to delete zone %s: not present", zl_str,
260  zone->name);
261  return zone;
262 }
263 
264 
269 static void
270 zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
271 {
272  zone_type* z1 = NULL;
273  zone_type* z2 = NULL;
274  ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
275  ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
276  int ret = 0;
277 
278  ods_log_assert(zl1);
279  ods_log_assert(zl2);
280  ods_log_assert(zl1->zones);
281  ods_log_assert(zl2->zones);
282  ods_log_debug("[%s] merge two zone lists", zl_str);
283 
284  n1 = ldns_rbtree_first(zl1->zones);
285  n2 = ldns_rbtree_first(zl2->zones);
286  while (n2 && n2 != LDNS_RBTREE_NULL) {
287  z2 = (zone_type*) n2->data;
288  if (n1 && n1 != LDNS_RBTREE_NULL) {
289  z1 = (zone_type*) n1->data;
290  } else {
291  z1 = NULL;
292  }
293  if (!z2) {
294  /* no more zones to merge into zl1 */
295  return;
296  } else if (!z1) {
297  /* just add remaining zones from zl2 */
298  z2 = zonelist_add_zone(zl1, z2);
299  if (!z2) {
300  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
301  return;
302  }
303  n2 = ldns_rbtree_next(n2);
304  } else {
305  /* compare the zones z1 and z2 */
306  ret = zone_compare(z1, z2);
307  if (ret < 0) {
308  /* remove zone z1, it is not present in the new list zl2 */
310  zl1->just_removed++;
311  n1 = ldns_rbtree_next(n1);
312  } else if (ret > 0) {
313  /* add the new zone z2 */
314  z2 = zonelist_add_zone(zl1, z2);
315  if (!z2) {
316  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
317  return;
318  }
319  n2 = ldns_rbtree_next(n2);
320  } else {
321  /* just update zone z1 */
322  n1 = ldns_rbtree_next(n1);
323  n2 = ldns_rbtree_next(n2);
324  zone_merge(z1, z2);
325  zone_cleanup(z2);
326  if (z1->zl_status == ZONE_ZL_UPDATED) {
327  zl1->just_updated++;
328  }
330  }
331  }
332  }
333  /* remove remaining zones from z1 */
334  while (n1 && n1 != LDNS_RBTREE_NULL) {
335  z1 = (zone_type*) n1->data;
337  zl1->just_removed++;
338  n1 = ldns_rbtree_next(n1);
339  }
340  zl1->last_modified = zl2->last_modified;
341  return;
342 }
343 
344 
350 zonelist_update(zonelist_type* zl, const char* zlfile)
351 {
352  zonelist_type* new_zlist = NULL;
353  allocator_type* tmp_alloc = NULL;
354  time_t st_mtime = 0;
355  ods_status status = ODS_STATUS_OK;
356  char* datestamp = NULL;
357 
358  ods_log_debug("[%s] update zone list", zl_str);
359  if (!zl|| !zl->zones || !zlfile) {
360  return ODS_STATUS_ASSERT_ERR;
361  }
362  /* is the file updated? */
363  st_mtime = ods_file_lastmodified(zlfile);
364  if (st_mtime <= zl->last_modified) {
365  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
366  ods_log_debug("[%s] zonelist file %s is unchanged since %s",
367  zl_str, zlfile, datestamp?datestamp:"Unknown");
368  free((void*)datestamp);
369  return ODS_STATUS_UNCHANGED;
370  }
371  /* create new zonelist */
372  tmp_alloc = allocator_create(malloc, free);
373  if (!tmp_alloc) {
374  return ODS_STATUS_MALLOC_ERR;
375  }
376  new_zlist = zonelist_create(tmp_alloc);
377  if (!new_zlist) {
378  ods_log_error("[%s] unable to update zonelist: zonelist_create() "
379  "failed", zl_str);
380  allocator_cleanup(tmp_alloc);
381  return ODS_STATUS_ERR;
382  }
383  /* read zonelist */
384  status = zonelist_read(new_zlist, zlfile);
385  if (status == ODS_STATUS_OK) {
386  zl->just_removed = 0;
387  zl->just_added = 0;
388  zl->just_updated = 0;
389  new_zlist->last_modified = st_mtime;
390  zonelist_merge(zl, new_zlist);
391  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
392  ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile,
393  datestamp?datestamp:"Unknown");
394  free((void*)datestamp);
395  } else {
396  ods_log_error("[%s] unable to update zonelist: read file %s failed "
397  "(%s)", zl_str, zlfile, ods_status2str(status));
398  }
399  zonelist_free(new_zlist);
400  allocator_cleanup(tmp_alloc);
401  return status;
402 }
403 
404 
409 static void
410 zone_delfunc(ldns_rbnode_t* elem)
411 {
412  zone_type* zone;
413  if (elem && elem != LDNS_RBTREE_NULL) {
414  zone = (zone_type*) elem->data;
415  zone_delfunc(elem->left);
416  zone_delfunc(elem->right);
417  ods_log_deeebug("[%s] cleanup zone %s", zl_str, zone->name);
418  zone_cleanup(zone);
419  free((void*)elem);
420  }
421  return;
422 }
423 
424 
429 static void
430 node_delfunc(ldns_rbnode_t* elem)
431 {
432  if (elem && elem != LDNS_RBTREE_NULL) {
433  node_delfunc(elem->left);
434  node_delfunc(elem->right);
435  free((void*)elem);
436  }
437  return;
438 }
439 
440 
445 void
447 {
448  allocator_type* allocator;
449  lock_basic_type zl_lock;
450  if (!zl) {
451  return;
452  }
453  ods_log_debug("[%s] cleanup zonelist", zl_str);
454  if (zl->zones) {
455  zone_delfunc(zl->zones->root);
456  ldns_rbtree_free(zl->zones);
457  zl->zones = NULL;
458  }
459  allocator = zl->allocator;
460  zl_lock = zl->zl_lock;
461  allocator_deallocate(allocator, (void*) zl);
462  lock_basic_destroy(&zl_lock);
463  return;
464 }
465 
466 
471 void
473 {
474  allocator_type* allocator;
475  lock_basic_type zl_lock;
476  if (!zl) {
477  return;
478  }
479  if (zl->zones) {
480  node_delfunc(zl->zones->root);
481  ldns_rbtree_free(zl->zones);
482  zl->zones = NULL;
483  }
484  allocator = zl->allocator;
485  zl_lock = zl->zl_lock;
486  allocator_deallocate(allocator, (void*) zl);
487  lock_basic_destroy(&zl_lock);
488  return;
489 }
void zone_cleanup(zone_type *zone)
Definition: zone.c:744
void ods_log_debug(const char *format,...)
Definition: log.c:270
int just_updated
Definition: zonelist.h:53
uint32_t time_datestamp(time_t tt, const char *format, char **str)
Definition: duration.c:531
void zone_merge(zone_type *z1, zone_type *z2)
Definition: zone.c:678
#define lock_basic_destroy(lock)
Definition: locks.h:93
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:66
ldns_rbtree_t * zones
Definition: zonelist.h:50
enum ods_enum_status ods_status
Definition: status.h:90
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition: confparser.c:53
time_t ods_file_lastmodified(const char *file)
Definition: file.c:293
void ods_log_error(const char *format,...)
Definition: log.c:334
const char * ods_status2str(ods_status status)
Definition: status.c:111
zone_zl_status zl_status
Definition: zone.h:79
int just_removed
Definition: zonelist.h:54
zone_type * zone_create(char *name, ldns_rr_class klass)
Definition: zone.c:54
void ods_log_crit(const char *format,...)
Definition: log.c:350
zone_type * zonelist_add_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:205
zone_type * zonelist_del_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:242
allocator_type * allocator_create(void *(*allocator)(size_t size), void(*deallocator)(void *))
Definition: allocator.c:47
zone_type * zonelist_lookup_zone_by_dname(zonelist_type *zonelist, ldns_rdf *dname, ldns_rr_class klass)
Definition: zonelist.c:186
int lock_basic_type
Definition: locks.h:91
ods_status parse_zonelist_zones(void *zlist, const char *zlfile)
allocator_type * allocator
Definition: zonelist.h:49
time_t last_modified
Definition: zonelist.h:51
void ods_log_verbose(const char *format,...)
Definition: log.c:286
ldns_rr_class klass
Definition: zone.h:69
#define lock_basic_init(lock)
Definition: locks.h:92
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:161
void allocator_cleanup(allocator_type *allocator)
Definition: allocator.c:151
const char * name
Definition: zone.h:76
void zonelist_cleanup(zonelist_type *zl)
Definition: zonelist.c:446
void ods_log_deeebug(const char *format,...)
Definition: log.c:254
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:135
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:350
void zonelist_free(zonelist_type *zl)
Definition: zonelist.c:472
zonelist_type * zonelist_create(allocator_type *allocator)
Definition: zonelist.c:75
#define ods_log_assert(x)
Definition: log.h:154
void ods_log_warning(const char *format,...)
Definition: log.c:318
ldns_rdf * apex
Definition: zone.h:68
lock_basic_type zl_lock
Definition: zonelist.h:55