OpenDNSSEC-signer  1.4.3
zonelist.c
Go to the documentation of this file.
1 /*
2  * $Id: zonelist.c 6166 2012-02-14 15:36:44Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "config.h"
35 #include "parser/confparser.h"
36 #include "parser/zonelistparser.h"
37 #include "shared/allocator.h"
38 #include "shared/duration.h"
39 #include "shared/file.h"
40 #include "shared/log.h"
41 #include "shared/status.h"
42 #include "signer/zone.h"
43 #include "signer/zonelist.h"
44 
45 #include <ldns/ldns.h>
46 #include <stdlib.h>
47 
48 static const char* zl_str = "zonelist";
49 
50 
55 static int
56 zone_compare(const void* a, const void* b)
57 {
58  zone_type* x = (zone_type*)a;
59  zone_type* y = (zone_type*)b;
60  ods_log_assert(x);
61  ods_log_assert(y);
62  if (x->klass != y->klass) {
63  if (x->klass < y->klass) {
64  return -1;
65  }
66  return 1;
67  }
68  return ldns_dname_compare(x->apex, y->apex);
69 }
70 
71 
78 {
79  zonelist_type* zlist = NULL;
80  if (allocator) {
81  zlist = (zonelist_type*) allocator_alloc(allocator, sizeof(zonelist_type));
82  }
83  if (!zlist) {
84  ods_log_error("[%s] unable to create zonelist: allocator_alloc() "
85  "failed", zl_str);
86  return NULL;
87  }
88  zlist->allocator = allocator;
89  zlist->zones = ldns_rbtree_create(zone_compare);
90  if (!zlist->zones) {
91  ods_log_error("[%s] unable to create zonelist: ldns_rbtree_create() "
92  "failed", zl_str);
93  allocator_deallocate(allocator, (void*) zlist);
94  return NULL;
95  }
96  zlist->last_modified = 0;
97  lock_basic_init(&zlist->zl_lock);
98  return zlist;
99 }
100 
101 
106 static ods_status
107 zonelist_read(zonelist_type* zl, const char* zlfile)
108 {
109  const char* rngfile = ODS_SE_RNGDIR "/zonelist.rng";
110  ods_status status = ODS_STATUS_OK;
111  ods_log_assert(zlfile);
112  ods_log_verbose("[%s] read file %s", zl_str, zlfile);
113  status = parse_file_check(zlfile, rngfile);
114  if (status != ODS_STATUS_OK) {
115  ods_log_error("[%s] unable to read file: parse error in %s", zl_str,
116  zlfile);
117  return status;
118  }
119  return parse_zonelist_zones((struct zonelist_struct*) zl, zlfile);
120 }
121 
122 
127 static ldns_rbnode_t*
128 zone2node(zone_type* zone)
129 {
130  ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
131  if (!node) {
132  return NULL;
133  }
134  node->key = zone;
135  node->data = zone;
136  return node;
137 }
138 
139 
144 static zone_type*
145 zonelist_lookup_zone(zonelist_type* zonelist, zone_type* zone)
146 {
147  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
148  if (zonelist && zonelist->zones && zone) {
149  node = ldns_rbtree_search(zonelist->zones, zone);
150  if (node) {
151  return (zone_type*) node->data;
152  }
153  }
154  return NULL;
155 }
156 
157 
162 zone_type*
163 zonelist_lookup_zone_by_name(zonelist_type* zonelist, const char* name,
164  ldns_rr_class klass)
165 {
166  zone_type* zone = NULL;
167  zone_type* result = NULL;
168  if (zonelist && zonelist->zones && name && klass) {
169  zone = zone_create((char*) name, klass);
170  if (!zone) {
171  ods_log_error("[%s] unable to lookup zone %s: "
172  "zone_create() failed", zl_str, name);
173  /* result stays NULL */
174  } else {
175  result = zonelist_lookup_zone(zonelist, zone);
176  zone_cleanup(zone);
177  }
178  }
179  return result;
180 }
181 
182 
187 zone_type*
188 zonelist_lookup_zone_by_dname(zonelist_type* zonelist, ldns_rdf* dname,
189  ldns_rr_class klass)
190 {
191  char* name = NULL;
192  zone_type* result = NULL;
193  if (zonelist && zonelist->zones && dname && klass) {
194  name = ldns_rdf2str(dname);
195  result = zonelist_lookup_zone_by_name(zonelist, name, klass);
196  free((void*)name);
197  }
198  return result;
199 }
200 
201 
206 zone_type*
208 {
209  ldns_rbnode_t* new_node = NULL;
210  if (!zone) {
211  return NULL;
212  }
213  if (!zlist || !zlist->zones) {
214  zone_cleanup(zone);
215  return NULL;
216  }
217  /* look up */
218  if (zonelist_lookup_zone(zlist, zone) != NULL) {
219  ods_log_warning("[%s] unable to add zone %s: already present", zl_str,
220  zone->name);
221  zone_cleanup(zone);
222  return NULL;
223  }
224  /* add */
225  new_node = zone2node(zone);
226  if (ldns_rbtree_insert(zlist->zones, new_node) == NULL) {
227  ods_log_error("[%s] unable to add zone %s: ldns_rbtree_insert() "
228  "failed", zl_str, zone->name);
229  free((void*) new_node);
230  zone_cleanup(zone);
231  return NULL;
232  }
233  zone->zl_status = ZONE_ZL_ADDED;
234  zlist->just_added++;
235  return zone;
236 }
237 
238 
243 zone_type*
245 {
246  ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
247  if (!zone) {
248  return NULL;
249  }
250  if (!zlist || !zlist->zones) {
251  goto zone_not_present;
252  }
253  old_node = ldns_rbtree_delete(zlist->zones, zone);
254  if (!old_node) {
255  goto zone_not_present;
256  }
257  free((void*) old_node);
258  return zone;
259 
260 zone_not_present:
261  ods_log_warning("[%s] unable to delete zone %s: not present", zl_str,
262  zone->name);
263  return zone;
264 }
265 
266 
271 static void
272 zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
273 {
274  zone_type* z1 = NULL;
275  zone_type* z2 = NULL;
276  ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
277  ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
278  int ret = 0;
279 
280  ods_log_assert(zl1);
281  ods_log_assert(zl2);
282  ods_log_assert(zl1->zones);
283  ods_log_assert(zl2->zones);
284  ods_log_debug("[%s] merge two zone lists", zl_str);
285 
286  n1 = ldns_rbtree_first(zl1->zones);
287  n2 = ldns_rbtree_first(zl2->zones);
288  while (n2 && n2 != LDNS_RBTREE_NULL) {
289  z2 = (zone_type*) n2->data;
290  if (n1 && n1 != LDNS_RBTREE_NULL) {
291  z1 = (zone_type*) n1->data;
292  } else {
293  z1 = NULL;
294  }
295  if (!z2) {
296  /* no more zones to merge into zl1 */
297  return;
298  } else if (!z1) {
299  /* just add remaining zones from zl2 */
300  z2 = zonelist_add_zone(zl1, z2);
301  if (!z2) {
302  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
303  return;
304  }
305  n2 = ldns_rbtree_next(n2);
306  } else {
307  /* compare the zones z1 and z2 */
308  ret = zone_compare(z1, z2);
309  if (ret < 0) {
310  /* remove zone z1, it is not present in the new list zl2 */
312  zl1->just_removed++;
313  n1 = ldns_rbtree_next(n1);
314  } else if (ret > 0) {
315  /* add the new zone z2 */
316  z2 = zonelist_add_zone(zl1, z2);
317  if (!z2) {
318  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
319  return;
320  }
321  n2 = ldns_rbtree_next(n2);
322  } else {
323  /* just update zone z1 */
324  n1 = ldns_rbtree_next(n1);
325  n2 = ldns_rbtree_next(n2);
326  zone_merge(z1, z2);
327  zone_cleanup(z2);
328  if (z1->zl_status == ZONE_ZL_UPDATED) {
329  zl1->just_updated++;
330  }
332  }
333  }
334  }
335  /* remove remaining zones from z1 */
336  while (n1 && n1 != LDNS_RBTREE_NULL) {
337  z1 = (zone_type*) n1->data;
339  zl1->just_removed++;
340  n1 = ldns_rbtree_next(n1);
341  }
342  zl1->last_modified = zl2->last_modified;
343  return;
344 }
345 
346 
352 zonelist_update(zonelist_type* zl, const char* zlfile)
353 {
354  zonelist_type* new_zlist = NULL;
355  allocator_type* tmp_alloc = NULL;
356  time_t st_mtime = 0;
357  ods_status status = ODS_STATUS_OK;
358  char* datestamp = NULL;
359 
360  ods_log_debug("[%s] update zone list", zl_str);
361  if (!zl|| !zl->zones || !zlfile) {
362  return ODS_STATUS_ASSERT_ERR;
363  }
364  /* is the file updated? */
365  st_mtime = ods_file_lastmodified(zlfile);
366  if (st_mtime <= zl->last_modified) {
367  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
368  ods_log_debug("[%s] zonelist file %s is unchanged since %s",
369  zl_str, zlfile, datestamp?datestamp:"Unknown");
370  free((void*)datestamp);
371  return ODS_STATUS_UNCHANGED;
372  }
373  /* create new zonelist */
374  tmp_alloc = allocator_create(malloc, free);
375  if (!tmp_alloc) {
376  return ODS_STATUS_MALLOC_ERR;
377  }
378  new_zlist = zonelist_create(tmp_alloc);
379  if (!new_zlist) {
380  ods_log_error("[%s] unable to update zonelist: zonelist_create() "
381  "failed", zl_str);
382  allocator_cleanup(tmp_alloc);
383  return ODS_STATUS_ERR;
384  }
385  /* read zonelist */
386  status = zonelist_read(new_zlist, zlfile);
387  if (status == ODS_STATUS_OK) {
388  zl->just_removed = 0;
389  zl->just_added = 0;
390  zl->just_updated = 0;
391  new_zlist->last_modified = st_mtime;
392  zonelist_merge(zl, new_zlist);
393  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
394  ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile,
395  datestamp?datestamp:"Unknown");
396  free((void*)datestamp);
397  } else {
398  ods_log_error("[%s] unable to update zonelist: read file %s failed "
399  "(%s)", zl_str, zlfile, ods_status2str(status));
400  }
401  zonelist_free(new_zlist);
402  allocator_cleanup(tmp_alloc);
403  return status;
404 }
405 
406 
411 static void
412 zone_delfunc(ldns_rbnode_t* elem)
413 {
414  zone_type* zone;
415  if (elem && elem != LDNS_RBTREE_NULL) {
416  zone = (zone_type*) elem->data;
417  zone_delfunc(elem->left);
418  zone_delfunc(elem->right);
419  ods_log_deeebug("[%s] cleanup zone %s", zl_str, zone->name);
420  zone_cleanup(zone);
421  free((void*)elem);
422  }
423  return;
424 }
425 
426 
431 static void
432 node_delfunc(ldns_rbnode_t* elem)
433 {
434  if (elem && elem != LDNS_RBTREE_NULL) {
435  node_delfunc(elem->left);
436  node_delfunc(elem->right);
437  free((void*)elem);
438  }
439  return;
440 }
441 
442 
447 void
449 {
450  allocator_type* allocator;
451  lock_basic_type zl_lock;
452  if (!zl) {
453  return;
454  }
455  ods_log_debug("[%s] cleanup zonelist", zl_str);
456  if (zl->zones) {
457  zone_delfunc(zl->zones->root);
458  ldns_rbtree_free(zl->zones);
459  zl->zones = NULL;
460  }
461  allocator = zl->allocator;
462  zl_lock = zl->zl_lock;
463  allocator_deallocate(allocator, (void*) zl);
464  lock_basic_destroy(&zl_lock);
465  return;
466 }
467 
468 
473 void
475 {
476  allocator_type* allocator;
477  lock_basic_type zl_lock;
478  if (!zl) {
479  return;
480  }
481  if (zl->zones) {
482  node_delfunc(zl->zones->root);
483  ldns_rbtree_free(zl->zones);
484  zl->zones = NULL;
485  }
486  allocator = zl->allocator;
487  zl_lock = zl->zl_lock;
488  allocator_deallocate(allocator, (void*) zl);
489  lock_basic_destroy(&zl_lock);
490  return;
491 }
void zone_cleanup(zone_type *zone)
Definition: zone.c:741
void ods_log_debug(const char *format,...)
Definition: log.c:272
int just_updated
Definition: zonelist.h:55
uint32_t time_datestamp(time_t tt, const char *format, char **str)
Definition: duration.c:533
void zone_merge(zone_type *z1, zone_type *z2)
Definition: zone.c:675
#define lock_basic_destroy(lock)
Definition: locks.h:92
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:68
ldns_rbtree_t * zones
Definition: zonelist.h:52
enum ods_enum_status ods_status
Definition: status.h:91
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition: confparser.c:55
time_t ods_file_lastmodified(const char *file)
Definition: file.c:290
void ods_log_error(const char *format,...)
Definition: log.c:336
const char * ods_status2str(ods_status status)
Definition: status.c:112
zone_zl_status zl_status
Definition: zone.h:81
int just_removed
Definition: zonelist.h:56
zone_type * zone_create(char *name, ldns_rr_class klass)
Definition: zone.c:56
void ods_log_crit(const char *format,...)
Definition: log.c:352
zone_type * zonelist_add_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:207
zone_type * zonelist_del_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:244
allocator_type * allocator_create(void *(*allocator)(size_t size), void(*deallocator)(void *))
Definition: allocator.c:49
zone_type * zonelist_lookup_zone_by_dname(zonelist_type *zonelist, ldns_rdf *dname, ldns_rr_class klass)
Definition: zonelist.c:188
int lock_basic_type
Definition: locks.h:90
ods_status parse_zonelist_zones(void *zlist, const char *zlfile)
allocator_type * allocator
Definition: zonelist.h:51
time_t last_modified
Definition: zonelist.h:53
void ods_log_verbose(const char *format,...)
Definition: log.c:288
ldns_rr_class klass
Definition: zone.h:71
#define lock_basic_init(lock)
Definition: locks.h:91
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:163
void allocator_cleanup(allocator_type *allocator)
Definition: allocator.c:153
const char * name
Definition: zone.h:78
void zonelist_cleanup(zonelist_type *zl)
Definition: zonelist.c:448
void ods_log_deeebug(const char *format,...)
Definition: log.c:256
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:137
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:352
void zonelist_free(zonelist_type *zl)
Definition: zonelist.c:474
zonelist_type * zonelist_create(allocator_type *allocator)
Definition: zonelist.c:77
#define ods_log_assert(x)
Definition: log.h:156
void ods_log_warning(const char *format,...)
Definition: log.c:320
ldns_rdf * apex
Definition: zone.h:70
lock_basic_type zl_lock
Definition: zonelist.h:57