OpenDNSSEC-signer  1.3.16
zonelist.c
Go to the documentation of this file.
1 /*
2  * $Id: zonelist.c 7295 2013-09-11 10:18:25Z 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 
61  ods_log_assert(x);
62  ods_log_assert(y);
63 
64  if (x->klass != y->klass) {
65  if (x->klass < y->klass) {
66  return -1;
67  }
68  return 1;
69  }
70  return ldns_dname_compare(x->dname, y->dname);
71 }
72 
73 
80 {
81  zonelist_type* zlist;
82  if (!allocator) {
83  ods_log_error("[%s] cannot create: no allocator available", zl_str);
84  return NULL;
85  }
86  ods_log_assert(allocator);
87 
88  zlist = (zonelist_type*) allocator_alloc(allocator, sizeof(zonelist_type));
89  if (!zlist) {
90  ods_log_error("[%s] cannot create: allocator failed", zl_str);
91  return NULL;
92  }
93  ods_log_assert(zlist);
94 
95  zlist->allocator = allocator;
96  zlist->zones = ldns_rbtree_create(zone_compare);
97  zlist->last_modified = 0;
98  zlist->zl_locked = 0;
99  lock_basic_init(&zlist->zl_lock);
100  return zlist;
101 }
102 
103 
108 static ods_status
109 zonelist_read(zonelist_type* zl, const char* zlfile)
110 {
111  const char* rngfile = ODS_SE_RNGDIR "/zonelist.rng";
112  ods_status status = ODS_STATUS_OK;
113 
114  ods_log_assert(zlfile);
115  ods_log_verbose("[%s] read file %s", zl_str, zlfile);
116 
117  /* does the file have no parse errors? */
118  status = parse_file_check(zlfile, rngfile);
119  if (status != ODS_STATUS_OK) {
120  ods_log_error("[%s] unable to parse file %s: %s", zl_str,
121  zlfile, ods_status2str(status));
122  return status;
123  }
124 
125  /* ok, parse it */
126  return parse_zonelist_zones((struct zonelist_struct*) zl, zlfile);
127 }
128 
129 
134 static ldns_rbnode_t*
135 zone2node(zone_type* zone)
136 {
137  ldns_rbnode_t* node = (ldns_rbnode_t*) malloc(sizeof(ldns_rbnode_t));
138  if (!node) {
139  return NULL;
140  }
141  node->key = zone;
142  node->data = zone;
143  return node;
144 }
145 
146 
151 static zone_type*
152 zonelist_lookup_zone(zonelist_type* zonelist, zone_type* zone)
153 {
154  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
155 
156  if (!zonelist || !zonelist->zones) {
157  ods_log_error("[%s] unable to lookup zone: no zonelist", zl_str);
158  return NULL;
159  }
160  ods_log_assert(zonelist);
161  ods_log_assert(zonelist->zones);
162  if (!zone) {
163  ods_log_error("[%s] unable to lookup zone: zone is null", zl_str);
164  return NULL;
165  }
166  ods_log_assert(zone);
167 
168  node = ldns_rbtree_search(zonelist->zones, zone);
169  if (node) {
170  return (zone_type*) node->data;
171  }
172  return NULL;
173 }
174 
175 
180 zone_type*
181 zonelist_lookup_zone_by_name(zonelist_type* zonelist, const char* name,
182  ldns_rr_class klass)
183 {
184  zone_type* zone = NULL;
185  zone_type* result = NULL;
186 
187  if (!zonelist || !zonelist->zones || !name || !klass) {
188  return NULL;
189  }
190  ods_log_assert(zonelist);
191  ods_log_assert(zonelist->zones);
192  ods_log_assert(name);
193  ods_log_assert(klass);
194 
195  zone = zone_create((char*) name, klass);
196  if (!zone) {
197  ods_log_error("[%s] unable to lookup zone: create zone failed", zl_str);
198  return NULL;
199  }
200  result = zonelist_lookup_zone(zonelist, zone);
201  zone_cleanup(zone);
202  return result;
203 }
204 
205 
210 zone_type*
212 {
213  ldns_rbnode_t* new_node = NULL;
214 
215  if (!zone) {
216  ods_log_error("[%s] unable to add zone: zone is null", zl_str);
217  return NULL;
218  }
219  ods_log_assert(zone);
220  if (!zlist || !zlist->zones) {
221  ods_log_error("[%s] unable to add zone %s: no zonelist", zl_str,
222  zone->name);
223  zone_cleanup(zone);
224  return NULL;
225  }
226  ods_log_assert(zlist);
227  ods_log_assert(zlist->zones);
228 
229  if (zonelist_lookup_zone(zlist, zone) != NULL) {
230  ods_log_warning("[%s] unable to add zone %s: already present", zl_str,
231  zone->name);
232  zone_cleanup(zone);
233  return NULL;
234  }
235 
236  new_node = zone2node(zone);
237  if (ldns_rbtree_insert(zlist->zones, new_node) == NULL) {
238  ods_log_error("[%s] unable to add zone %s: rbtree insert failed",
239  zl_str, zone->name);
240  free((void*) new_node);
241  zone_cleanup(zone);
242  return NULL;
243  }
244  zone->just_added = 1;
245  zlist->just_added++;
246  return zone;
247 }
248 
249 
254 zone_type*
256 {
257  ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
258 
259  if (!zone) {
260  ods_log_warning("[%s] unable to delete zone: zone is null", zl_str);
261  return NULL;
262  }
263  ods_log_assert(zone);
264  if (!zlist || !zlist->zones) {
265  ods_log_error("[%s] unable to delete zone %s: no zone list", zl_str,
266  zone->name);
267  return zone;
268  }
269  ods_log_assert(zlist);
270  ods_log_assert(zlist->zones);
271 
272  old_node = ldns_rbtree_delete(zlist->zones, zone);
273  if (!old_node) {
274  ods_log_warning("[%s] unable to delete zone %s: not present", zl_str,
275  zone->name);
276  return zone;
277  }
278  free((void*) old_node);
279  return zone;
280 }
281 
282 
287 static void
288 zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
289 {
290  zone_type* z1 = NULL;
291  zone_type* z2 = NULL;
292  ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
293  ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
294  int ret = 0;
295 
296  ods_log_assert(zl1);
297  ods_log_assert(zl2);
298  ods_log_assert(zl1->zones);
299  ods_log_assert(zl2->zones);
300  ods_log_debug("[%s] merge two zone lists", zl_str);
301 
302  n1 = ldns_rbtree_first(zl1->zones);
303  n2 = ldns_rbtree_first(zl2->zones);
304  while (n2 && n2 != LDNS_RBTREE_NULL) {
305  z2 = (zone_type*) n2->data;
306  if (n1 && n1 != LDNS_RBTREE_NULL) {
307  z1 = (zone_type*) n1->data;
308  } else {
309  z1 = NULL;
310  }
311 
312  if (!z2) {
313  /* no more zones to merge into zl1 */
314  return;
315  } else if (!z1) {
316  /* just add remaining zones from zl2 */
317  z2 = zonelist_add_zone(zl1, z2);
318  if (!z2) {
319  ods_log_error("[%s] merge failed: z2 not added", zl_str);
320  return;
321  }
322  n2 = ldns_rbtree_next(n2);
323  } else {
324  /* compare the zones z1 and z2 */
325  ret = zone_compare(z1, z2);
326  if (ret < 0) {
327  /* remove zone z1, it is not present in the new list zl2 */
328  z1->tobe_removed = 1;
329  zl1->just_removed++;
330  n1 = ldns_rbtree_next(n1);
331  } else if (ret > 0) {
332  /* add the new zone z2 */
333  z2 = zonelist_add_zone(zl1, z2);
334  if (!z2) {
335  ods_log_error("[%s] merge failed: z2 not added", zl_str);
336  return;
337  }
338  n2 = ldns_rbtree_next(n2);
339  } else {
340  /* just update zone z1 */
341  n1 = ldns_rbtree_next(n1);
342  n2 = ldns_rbtree_next(n2);
343  zone_merge(z1, z2);
344  zone_cleanup(z2);
345  if (z1->just_updated) {
346  zl1->just_updated++;
347  }
348  z1->just_updated = 1;
349  }
350  }
351  }
352 
353  /* remove remaining zones from z1 */
354  while (n1 && n1 != LDNS_RBTREE_NULL) {
355  z1 = (zone_type*) n1->data;
356  z1->tobe_removed = 1;
357  zl1->just_removed++;
358  n1 = ldns_rbtree_next(n1);
359  }
360 
361  zl1->last_modified = zl2->last_modified;
362  return;
363 }
364 
365 
371 zonelist_update(zonelist_type* zl, const char* zlfile)
372 {
373  zonelist_type* new_zlist = NULL;
374  allocator_type* tmp_alloc = NULL;
375  time_t st_mtime = 0;
376  ods_status status = ODS_STATUS_OK;
377  char* datestamp = NULL;
378  uint32_t ustamp = 0;
379 
380  ods_log_debug("[%s] update zone list", zl_str);
381  if (!zl|| !zl->zones) {
382  ods_log_error("[%s] cannot update: no zonelist storaga", zl_str);
383  return ODS_STATUS_ASSERT_ERR;
384  }
385  ods_log_assert(zl);
386  ods_log_assert(zl->zones);
387  if (!zlfile) {
388  ods_log_error("[%s] cannot update: no filename", zl_str);
389  return ODS_STATUS_ASSERT_ERR;
390  }
391  ods_log_assert(zlfile);
392 
393  /* is the file updated? */
394  st_mtime = ods_file_lastmodified(zlfile);
395  if (st_mtime <= zl->last_modified) {
396  ustamp = time_datestamp(zl->last_modified,
397  "%Y-%m-%d %T", &datestamp);
398  ods_log_debug("[%s] zonelist file %s is unchanged since %s",
399  zl_str, zlfile, datestamp?datestamp:"Unknown");
400  free((void*)datestamp);
401  return ODS_STATUS_UNCHANGED;
402  }
403 
404  /* create new zonelist */
405  tmp_alloc = allocator_create(malloc, free);
406  if (!tmp_alloc) {
407  ods_log_error("[%s] error creating allocator for zone list",
408  zl_str);
409  return ODS_STATUS_ERR;
410  }
411  new_zlist = zonelist_create(tmp_alloc);
412  if (!new_zlist) {
413  ods_log_error("[%s] error creating new zone list", zl_str);
414  allocator_cleanup(tmp_alloc);
415  return ODS_STATUS_ERR;
416  }
417 
418  /* read zonelist */
419  status = zonelist_read(new_zlist, zlfile);
420  if (status == ODS_STATUS_OK) {
421  zl->just_removed = 0;
422  zl->just_added = 0;
423  zl->just_updated = 0;
424  new_zlist->last_modified = st_mtime;
425  zonelist_merge(zl, new_zlist);
426  ustamp = time_datestamp(zl->last_modified, "%Y-%m-%d %T",
427  &datestamp);
428  ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile,
429  datestamp?datestamp:"Unknown");
430  free((void*)datestamp);
431  } else {
432  ods_log_error("[%s] unable to read file %s: %s", zl_str, zlfile,
433  ods_status2str(status));
434  }
435 
436  zonelist_free(new_zlist);
437  allocator_cleanup(tmp_alloc);
438  return status;
439 }
440 
441 
446 static void
447 zone_delfunc(ldns_rbnode_t* elem)
448 {
449  zone_type* zone;
450 
451  if (elem && elem != LDNS_RBTREE_NULL) {
452  zone = (zone_type*) elem->data;
453  zone_delfunc(elem->left);
454  zone_delfunc(elem->right);
455 
456  ods_log_debug("[%s] cleanup zone %s", zl_str, zone->name);
457  zone_cleanup(zone);
458  free((void*)elem);
459  }
460  return;
461 }
462 
463 
468 static void
469 node_delfunc(ldns_rbnode_t* elem)
470 {
471  if (elem && elem != LDNS_RBTREE_NULL) {
472  node_delfunc(elem->left);
473  node_delfunc(elem->right);
474  free((void*)elem);
475  }
476  return;
477 }
478 
479 
484 void
486 {
487  allocator_type* allocator;
488  lock_basic_type zl_lock;
489 
490  if (!zl) {
491  return;
492  }
493 
494  ods_log_debug("[%s] cleanup zonelist", zl_str);
495  if (zl->zones) {
496  zone_delfunc(zl->zones->root);
497  ldns_rbtree_free(zl->zones);
498  zl->zones = NULL;
499  }
500 
501  allocator = zl->allocator;
502  zl_lock = zl->zl_lock;
503 
504  allocator_deallocate(allocator, (void*) zl);
505  lock_basic_destroy(&zl_lock);
506  return;
507 }
508 
509 
514 void
516 {
517  allocator_type* allocator;
518  lock_basic_type zl_lock;
519 
520  if (!zl) {
521  return;
522  }
523 
524  if (zl->zones) {
525  node_delfunc(zl->zones->root);
526  ldns_rbtree_free(zl->zones);
527  zl->zones = NULL;
528  }
529 
530  allocator = zl->allocator;
531  zl_lock = zl->zl_lock;
532 
533  allocator_deallocate(allocator, (void*) zl);
534  lock_basic_destroy(&zl_lock);
535  return;
536 }
void zone_cleanup(zone_type *zone)
Definition: zone.c:1320
void ods_log_debug(const char *format,...)
Definition: log.c:285
int just_updated
Definition: zonelist.h:55
uint32_t time_datestamp(time_t tt, const char *format, char **str)
Definition: duration.c:497
void zone_merge(zone_type *z1, zone_type *z2)
Definition: zone.c:1095
#define lock_basic_destroy(lock)
Definition: locks.h:153
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:67
ldns_rbtree_t * zones
Definition: zonelist.h:52
enum ods_enum_status ods_status
Definition: status.h:64
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition: confparser.c:55
ldns_rdf * dname
Definition: zone.h:59
time_t ods_file_lastmodified(const char *file)
Definition: file.c:287
void ods_log_error(const char *format,...)
Definition: log.c:349
const char * ods_status2str(ods_status status)
Definition: status.c:84
int just_removed
Definition: zonelist.h:56
zone_type * zone_create(char *name, ldns_rr_class klass)
Definition: zone.c:61
zone_type * zonelist_add_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:211
zone_type * zonelist_del_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:255
allocator_type * allocator_create(void *(*allocator)(size_t size), void(*deallocator)(void *))
Definition: allocator.c:48
int lock_basic_type
Definition: locks.h:151
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:301
ldns_rr_class klass
Definition: zone.h:60
#define lock_basic_init(lock)
Definition: locks.h:152
ods_status parse_zonelist_zones(struct zonelist_struct *zlist, const char *zlfile)
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:181
void allocator_cleanup(allocator_type *allocator)
Definition: allocator.c:153
const char * name
Definition: zone.h:67
void zonelist_cleanup(zonelist_type *zl)
Definition: zonelist.c:485
int just_updated
Definition: zone.h:71
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:136
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:371
void zonelist_free(zonelist_type *zl)
Definition: zonelist.c:515
zonelist_type * zonelist_create(allocator_type *allocator)
Definition: zonelist.c:79
#define ods_log_assert(x)
Definition: log.h:141
int just_added
Definition: zone.h:70
void ods_log_warning(const char *format,...)
Definition: log.c:333
int tobe_removed
Definition: zone.h:72
lock_basic_type zl_lock
Definition: zonelist.h:57