OpenDNSSEC-signer  2.1.7
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  pthread_mutex_init(&zlist->zl_lock, NULL);
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 void
239 {
240  ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
241  assert(zone);
242  if (!zlist || !zlist->zones) {
243  goto zone_not_present;
244  }
245  old_node = ldns_rbtree_delete(zlist->zones, zone);
246  if (!old_node) {
247  goto zone_not_present;
248  }
249  free((void*) old_node);
250  return;
251 
252 zone_not_present:
253  ods_log_warning("[%s] unable to delete zone %s: not present", zl_str,
254  zone->name);
255 }
256 
257 
262 static void
263 zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
264 {
265  zone_type* z1 = NULL;
266  zone_type* z2 = NULL;
267  ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
268  ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
269  int ret = 0;
270 
271  ods_log_assert(zl1);
272  ods_log_assert(zl2);
273  ods_log_assert(zl1->zones);
274  ods_log_assert(zl2->zones);
275  ods_log_debug("[%s] merge two zone lists", zl_str);
276 
277  n1 = ldns_rbtree_first(zl1->zones);
278  n2 = ldns_rbtree_first(zl2->zones);
279  while (n2 && n2 != LDNS_RBTREE_NULL) {
280  z2 = (zone_type*) n2->data;
281  if (n1 && n1 != LDNS_RBTREE_NULL) {
282  z1 = (zone_type*) n1->data;
283  } else {
284  z1 = NULL;
285  }
286  if (!z2) {
287  /* no more zones to merge into zl1 */
288  return;
289  } else if (!z1) {
290  /* just add remaining zones from zl2 */
291  z2 = zonelist_add_zone(zl1, z2);
292  if (!z2) {
293  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
294  return;
295  }
296  n2 = ldns_rbtree_next(n2);
297  } else {
298  /* compare the zones z1 and z2 */
299  ret = zone_compare(z1, z2);
300  if (ret < 0) {
301  /* remove zone z1, it is not present in the new list zl2 */
303  zl1->just_removed++;
304  n1 = ldns_rbtree_next(n1);
305  } else if (ret > 0) {
306  /* add the new zone z2 */
307  z2 = zonelist_add_zone(zl1, z2);
308  if (!z2) {
309  ods_log_crit("[%s] merge failed: z2 not added", zl_str);
310  return;
311  }
312  n2 = ldns_rbtree_next(n2);
313  } else {
314  /* just update zone z1 */
315  n1 = ldns_rbtree_next(n1);
316  n2 = ldns_rbtree_next(n2);
317  zone_merge(z1, z2);
318  zone_cleanup(z2);
319  if (z1->zl_status == ZONE_ZL_UPDATED) {
320  zl1->just_updated++;
321  }
323  }
324  }
325  }
326  /* remove remaining zones from z1 */
327  while (n1 && n1 != LDNS_RBTREE_NULL) {
328  z1 = (zone_type*) n1->data;
330  zl1->just_removed++;
331  n1 = ldns_rbtree_next(n1);
332  }
333  zl1->last_modified = zl2->last_modified;
334 }
335 
336 
341 ods_status
342 zonelist_update(zonelist_type* zl, const char* zlfile)
343 {
344  zonelist_type* new_zlist = NULL;
345  time_t st_mtime = 0;
346  ods_status status = ODS_STATUS_OK;
347  char* datestamp = NULL;
348 
349  ods_log_debug("[%s] update zone list", zl_str);
350  if (!zl|| !zl->zones || !zlfile) {
351  return ODS_STATUS_ASSERT_ERR;
352  }
353  /* is the file updated? */
354  /* OPENDNSSEC-686: changes happening within one second will not be
355  * seen
356  */
357  st_mtime = ods_file_lastmodified(zlfile);
358  if (st_mtime <= zl->last_modified) {
359  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
360  ods_log_debug("[%s] zonelist file %s is unchanged since %s",
361  zl_str, zlfile, datestamp?datestamp:"Unknown");
362  free((void*)datestamp);
363  return ODS_STATUS_UNCHANGED;
364  }
365  /* create new zonelist */
366  new_zlist = zonelist_create();
367  if (!new_zlist) {
368  ods_log_error("[%s] unable to update zonelist: zonelist_create() "
369  "failed", zl_str);
370  return ODS_STATUS_ERR;
371  }
372  /* read zonelist */
373  status = zonelist_read(new_zlist, zlfile);
374  if (status == ODS_STATUS_OK) {
375  zl->just_removed = 0;
376  zl->just_added = 0;
377  zl->just_updated = 0;
378  new_zlist->last_modified = st_mtime;
379  zonelist_merge(zl, new_zlist);
380  (void)time_datestamp(zl->last_modified, "%Y-%m-%d %T", &datestamp);
381  ods_log_debug("[%s] file %s is modified since %s", zl_str, zlfile,
382  datestamp?datestamp:"Unknown");
383  free((void*)datestamp);
384  } else {
385  ods_log_error("[%s] unable to update zonelist: read file %s failed "
386  "(%s)", zl_str, zlfile, ods_status2str(status));
387  }
388  zonelist_free(new_zlist);
389  return status;
390 }
391 
392 
397 static void
398 zone_delfunc(ldns_rbnode_t* elem)
399 {
400  zone_type* zone;
401  if (elem && elem != LDNS_RBTREE_NULL) {
402  zone = (zone_type*) elem->data;
403  zone_delfunc(elem->left);
404  zone_delfunc(elem->right);
405  ods_log_deeebug("[%s] cleanup zone %s", zl_str, zone->name);
406  zone_cleanup(zone);
407  free((void*)elem);
408  }
409 }
410 
411 
416 static void
417 node_delfunc(ldns_rbnode_t* elem)
418 {
419  if (elem && elem != LDNS_RBTREE_NULL) {
420  node_delfunc(elem->left);
421  node_delfunc(elem->right);
422  free((void*)elem);
423  }
424 }
425 
426 
431 void
433 {
434  if (!zl) {
435  return;
436  }
437  ods_log_debug("[%s] cleanup zonelist", zl_str);
438  if (zl->zones) {
439  zone_delfunc(zl->zones->root);
440  ldns_rbtree_free(zl->zones);
441  zl->zones = NULL;
442  }
443  pthread_mutex_destroy(&zl->zl_lock);
444  free(zl);
445 }
446 
447 
452 void
454 {
455  if (!zl) {
456  return;
457  }
458  if (zl->zones) {
459  node_delfunc(zl->zones->root);
460  ldns_rbtree_free(zl->zones);
461  zl->zones = NULL;
462  }
463  pthread_mutex_destroy(&zl->zl_lock);
464  free(zl);
465 }
ods_status parse_file_check(const char *cfgfile, const char *rngfile)
Definition: confparser.c:55
ldns_rr_class klass
Definition: zone.h:62
ldns_rdf * apex
Definition: zone.h:61
zone_zl_status zl_status
Definition: zone.h:72
const char * name
Definition: zone.h:69
int just_updated
Definition: zonelist.h:48
time_t last_modified
Definition: zonelist.h:46
int just_removed
Definition: zonelist.h:49
pthread_mutex_t zl_lock
Definition: zonelist.h:50
ldns_rbtree_t * zones
Definition: zonelist.h:45
void zone_merge(zone_type *z1, zone_type *z2)
Definition: zone.c:696
zone_type * zone_create(char *name, ldns_rr_class klass)
Definition: zone.c:55
void zone_cleanup(zone_type *zone)
Definition: zone.c:761
@ ZONE_ZL_REMOVED
Definition: zone.h:37
@ ZONE_ZL_ADDED
Definition: zone.h:35
@ ZONE_ZL_UPDATED
Definition: zone.h:36
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:157
void zonelist_del_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:238
void zonelist_free(zonelist_type *zl)
Definition: zonelist.c:453
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:342
void zonelist_cleanup(zonelist_type *zl)
Definition: zonelist.c:432
zonelist_type * zonelist_create()
Definition: zonelist.c:74
zone_type * zonelist_add_zone(zonelist_type *zlist, zone_type *zone)
Definition: zonelist.c:201
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)