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