OpenDNSSEC-signer  2.0.3
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 "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 
45 static const char* zl_str = "zonelist";
46 
47 
52 static int
53 zone_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  lock_basic_init(&zlist->zl_lock);
92  return zlist;
93 }
94 
95 
100 static ods_status
101 zonelist_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 
121 static ldns_rbnode_t*
122 zone2node(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 
138 static zone_type*
139 zonelist_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 
156 zone_type*
157 zonelist_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 
181 zone_type*
182 zonelist_lookup_zone_by_dname(zonelist_type* zonelist, ldns_rdf* dname,
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 
200 zone_type*
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 
237 zone_type*
239 {
240  ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
241  if (!zone) {
242  return NULL;
243  }
244  if (!zlist || !zlist->zones) {
245  goto zone_not_present;
246  }
247  old_node = ldns_rbtree_delete(zlist->zones, zone);
248  if (!old_node) {
249  goto zone_not_present;
250  }
251  free((void*) old_node);
252  return zone;
253 
254 zone_not_present:
255  ods_log_warning("[%s] unable to delete zone %s: not present", zl_str,
256  zone->name);
257  return zone;
258 }
259 
260 
265 static void
266 zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
267 {
268  zone_type* z1 = NULL;
269  zone_type* z2 = NULL;
270  ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
271  ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
272  int ret = 0;
273 
274  ods_log_assert(zl1);
275  ods_log_assert(zl2);
276  ods_log_assert(zl1->zones);
277  ods_log_assert(zl2->zones);
278  ods_log_debug("[%s] merge two zone lists", zl_str);
279 
280  n1 = ldns_rbtree_first(zl1->zones);
281  n2 = ldns_rbtree_first(zl2->zones);
282  while (n2 && n2 != LDNS_RBTREE_NULL) {
283  z2 = (zone_type*) n2->data;
284  if (n1 && n1 != LDNS_RBTREE_NULL) {
285  z1 = (zone_type*) n1->data;
286  } else {
287  z1 = NULL;
288  }
289  if (!z2) {
290  /* no more zones to merge into zl1 */
291  return;
292  } else if (!z1) {
293  /* just add remaining zones from zl2 */
294  z2 = zonelist_add_zone(zl1, z2);
295  if (!z2) {
296  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
297  return;
298  }
299  n2 = ldns_rbtree_next(n2);
300  } else {
301  /* compare the zones z1 and z2 */
302  ret = zone_compare(z1, z2);
303  if (ret < 0) {
304  /* remove zone z1, it is not present in the new list zl2 */
306  zl1->just_removed++;
307  n1 = ldns_rbtree_next(n1);
308  } else if (ret > 0) {
309  /* add the new zone z2 */
310  z2 = zonelist_add_zone(zl1, z2);
311  if (!z2) {
312  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
313  return;
314  }
315  n2 = ldns_rbtree_next(n2);
316  } else {
317  /* just update zone z1 */
318  n1 = ldns_rbtree_next(n1);
319  n2 = ldns_rbtree_next(n2);
320  zone_merge(z1, z2);
321  zone_cleanup(z2);
322  if (z1->zl_status == ZONE_ZL_UPDATED) {
323  zl1->just_updated++;
324  }
326  }
327  }
328  }
329  /* remove remaining zones from z1 */
330  while (n1 && n1 != LDNS_RBTREE_NULL) {
331  z1 = (zone_type*) n1->data;
333  zl1->just_removed++;
334  n1 = ldns_rbtree_next(n1);
335  }
336  zl1->last_modified = zl2->last_modified;
337 }
338 
339 
344 ods_status
345 zonelist_update(zonelist_type* zl, const char* zlfile)
346 {
347  zonelist_type* new_zlist = NULL;
348  time_t st_mtime = 0;
349  ods_status status = ODS_STATUS_OK;
350  char* datestamp = NULL;
351 
352  ods_log_debug("[%s] update zone list", zl_str);
353  if (!zl|| !zl->zones || !zlfile) {
354  return ODS_STATUS_ASSERT_ERR;
355  }
356  /* is the file updated? */
357  /* OPENDNSSEC-686: changes happening within one second will not be
358  * seen
359  */
360  st_mtime = ods_file_lastmodified(zlfile);
361  if (st_mtime <= zl->last_modified) {
362  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
363  ods_log_debug("[%s] zonelist file %s is unchanged since %s",
364  zl_str, zlfile, datestamp?datestamp:"Unknown");
365  free((void*)datestamp);
366  return ODS_STATUS_UNCHANGED;
367  }
368  /* create new zonelist */
369  new_zlist = zonelist_create();
370  if (!new_zlist) {
371  ods_log_error("[%s] unable to update zonelist: zonelist_create() "
372  "failed", zl_str);
373  return ODS_STATUS_ERR;
374  }
375  /* read zonelist */
376  status = zonelist_read(new_zlist, zlfile);
377  if (status == ODS_STATUS_OK) {
378  zl->just_removed = 0;
379  zl->just_added = 0;
380  zl->just_updated = 0;
381  new_zlist->last_modified = st_mtime;
382  zonelist_merge(zl, new_zlist);
383  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
384  ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile,
385  datestamp?datestamp:"Unknown");
386  free((void*)datestamp);
387  } else {
388  ods_log_error("[%s] unable to update zonelist: read file %s failed "
389  "(%s)", zl_str, zlfile, ods_status2str(status));
390  }
391  zonelist_free(new_zlist);
392  return status;
393 }
394 
395 
400 static void
401 zone_delfunc(ldns_rbnode_t* elem)
402 {
403  zone_type* zone;
404  if (elem && elem != LDNS_RBTREE_NULL) {
405  zone = (zone_type*) elem->data;
406  zone_delfunc(elem->left);
407  zone_delfunc(elem->right);
408  ods_log_deeebug("[%s] cleanup zone %s", zl_str, zone->name);
409  zone_cleanup(zone);
410  free((void*)elem);
411  }
412 }
413 
414 
419 static void
420 node_delfunc(ldns_rbnode_t* elem)
421 {
422  if (elem && elem != LDNS_RBTREE_NULL) {
423  node_delfunc(elem->left);
424  node_delfunc(elem->right);
425  free((void*)elem);
426  }
427 }
428 
429 
434 void
436 {
437  if (!zl) {
438  return;
439  }
440  ods_log_debug("[%s] cleanup zonelist", zl_str);
441  if (zl->zones) {
442  zone_delfunc(zl->zones->root);
443  ldns_rbtree_free(zl->zones);
444  zl->zones = NULL;
445  }
446  lock_basic_destroy(&zl->zl_lock);
447  free(zl);
448 }
449 
450 
455 void
457 {
458  if (!zl) {
459  return;
460  }
461  if (zl->zones) {
462  node_delfunc(zl->zones->root);
463  ldns_rbtree_free(zl->zones);
464  zl->zones = NULL;
465  }
466  lock_basic_destroy(&zl->zl_lock);
467  free(zl);
468 }
void zone_cleanup(zone_type *zone)
Definition: zone.c:807
int just_updated
Definition: zonelist.h:48
void zone_merge(zone_type *z1, zone_type *z2)
Definition: zone.c:742
ldns_rbtree_t * zones
Definition: zonelist.h:45
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition: confparser.c:55
zone_zl_status zl_status
Definition: zone.h:70
int just_removed
Definition: zonelist.h:49
zone_type * zone_create(char *name, ldns_rr_class klass)
Definition: zone.c:54
zone_type * zonelist_add_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:201
zone_type * zonelist_del_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:238
zone_type * zonelist_lookup_zone_by_dname(zonelist_type *zonelist, ldns_rdf *dname, ldns_rr_class klass)
Definition: zonelist.c:182
ods_status parse_zonelist_zones(void *zlist, const char *zlfile)
time_t last_modified
Definition: zonelist.h:46
ldns_rr_class klass
Definition: zone.h:60
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:157
const char * name
Definition: zone.h:67
void zonelist_cleanup(zonelist_type *zl)
Definition: zonelist.c:435
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:345
void zonelist_free(zonelist_type *zl)
Definition: zonelist.c:456
zonelist_type * zonelist_create()
Definition: zonelist.c:74
ldns_rdf * apex
Definition: zone.h:59
lock_basic_type zl_lock
Definition: zonelist.h:50