OpenDNSSEC-signer 1.2.1

/build/buildd-opendnssec_1.2.1.dfsg-1-ia64-j6OroR/opendnssec-1.2.1.dfsg/signer/src/signer/zonelist.c

Go to the documentation of this file.
00001 /*
00002  * $Id: zonelist.c 4294 2011-01-13 19:58:29Z jakob $
00003  *
00004  * Copyright (c) 2009 NLNet Labs. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00034 #include "config.h"
00035 #include "daemon/engine.h"
00036 #include "parser/confparser.h"
00037 #include "parser/zonelistparser.h"
00038 #include "scheduler/task.h"
00039 #include "signer/zone.h"
00040 #include "signer/zonelist.h"
00041 #include "util/file.h"
00042 #include "util/log.h"
00043 #include "util/se_malloc.h"
00044 
00045 #include <ldns/ldns.h> /* ldns_dname_compare(), ldns_rbtree_*() */
00046 
00047 
00052 static int
00053 zone_compare(const void* a, const void* b)
00054 {
00055     zone_type* x = (zone_type*)a;
00056     zone_type* y = (zone_type*)b;
00057 
00058     se_log_assert(x);
00059     se_log_assert(y);
00060 
00061     if (x->klass != y->klass) {
00062         if (x->klass < y->klass) {
00063             return -1;
00064         }
00065         return 1;
00066     }
00067     return ldns_dname_compare(x->dname, y->dname);
00068 }
00069 
00070 
00075 zonelist_type*
00076 zonelist_create(void)
00077 {
00078     zonelist_type* zlist = (zonelist_type*) se_malloc(sizeof(zonelist_type));
00079     zlist->zones = ldns_rbtree_create(zone_compare);
00080     zlist->last_modified = 0;
00081     return zlist;
00082 }
00083 
00084 
00089 zonelist_type*
00090 zonelist_read(const char* zonelistfile, time_t last_modified)
00091 {
00092     zonelist_type* zlist = NULL;
00093     const char* rngfile = ODS_SE_RNGDIR "/zonelist.rng";
00094     time_t st_mtime = 0;
00095 
00096     se_log_assert(zonelistfile);
00097     se_log_verbose("read zone list file %s",
00098         zonelistfile?zonelistfile:"(null)");
00099 
00100     /* is the file updated? */
00101     st_mtime = se_file_lastmodified(zonelistfile);
00102     if (st_mtime <= last_modified) {
00103         se_log_debug("zone list file %s is unchanged",
00104             zonelistfile?zonelistfile:"(null)");
00105         return NULL;
00106     }
00107     /* does the file have no parse errors? */
00108     if (parse_file_check(zonelistfile, rngfile) != 0) {
00109         se_log_error("unable to parse zone list file %s",
00110             zonelistfile?zonelistfile:"(null)");
00111         return NULL;
00112     }
00113     /* ok, parse it! */
00114     zlist = parse_zonelist_zones(zonelistfile);
00115     if (zlist) {
00116         zlist->last_modified = st_mtime;
00117     } else {
00118         se_log_error("unable to read zone list file %s",
00119             zonelistfile?zonelistfile:"(null)");
00120         return NULL;
00121     }
00122     return zlist;
00123 }
00124 
00125 
00130 void
00131 zonelist_lock(zonelist_type* zonelist)
00132 {
00133     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00134     zone_type* zone = NULL;
00135 
00136     se_log_assert(zonelist);
00137     se_log_assert(zonelist->zones);
00138 
00139     node = ldns_rbtree_first(zonelist->zones);
00140     while (node && node != LDNS_RBTREE_NULL) {
00141         zone = (zone_type*) node->key;
00142         lock_basic_lock(&zone->zone_lock);
00143         node = ldns_rbtree_next(node);
00144     }
00145     return;
00146 }
00147 
00152 void
00153 zonelist_unlock(zonelist_type* zonelist)
00154 {
00155     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00156     zone_type* zone = NULL;
00157 
00158     se_log_assert(zonelist);
00159     se_log_assert(zonelist->zones);
00160 
00161     node = ldns_rbtree_first(zonelist->zones);
00162     while (node && node != LDNS_RBTREE_NULL) {
00163         zone = (zone_type*) node->key;
00164         lock_basic_unlock(&zone->zone_lock);
00165         node = ldns_rbtree_next(node);
00166     }
00167     return;
00168 }
00169 
00170 
00175 static ldns_rbnode_t*
00176 zone2node(zone_type* zone)
00177 {
00178     ldns_rbnode_t* node = (ldns_rbnode_t*) se_malloc(sizeof(ldns_rbnode_t));
00179     node->key = zone;
00180     node->data = zone;
00181     return node;
00182 }
00183 
00184 
00189 static zone_type*
00190 zonelist_lookup_zone(zonelist_type* zonelist, zone_type* zone)
00191 {
00192     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00193 
00194     se_log_assert(zonelist);
00195     se_log_assert(zonelist->zones);
00196     se_log_assert(zone);
00197 
00198     node = ldns_rbtree_search(zonelist->zones, zone);
00199     if (node) {
00200         return (zone_type*) node->key;
00201     }
00202     return NULL;
00203 }
00204 
00205 
00210 zone_type*
00211 zonelist_lookup_zone_by_name(zonelist_type* zonelist, const char* name)
00212 {
00213     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00214     zone_type* zone = NULL;
00215 
00216     se_log_assert(zonelist);
00217     se_log_assert(zonelist->zones);
00218     se_log_assert(name);
00219 
00220     if (zonelist->zones) {
00221         node = ldns_rbtree_first(zonelist->zones);
00222     }
00223     while (node != LDNS_RBTREE_NULL) {
00224         zone = (zone_type*) node->key;
00225         if (se_strcmp(zone->name, name) == 0) {
00226             return zone;
00227         }
00228         node = ldns_rbtree_next(node);
00229     }
00230     return NULL;
00231 }
00232 
00233 
00238 zone_type*
00239 zonelist_add_zone(zonelist_type* zonelist, zone_type* zone)
00240 {
00241     ldns_rbnode_t* new_node = NULL;
00242 
00243     se_log_assert(zonelist);
00244     se_log_assert(zonelist->zones);
00245     se_log_assert(zone);
00246 
00247     if (zonelist_lookup_zone(zonelist, zone) != NULL) {
00248         se_log_warning("unable to add zone %s: already present",
00249             zone->name?zone->name:"(null)");
00250         zone_cleanup(zone);
00251         return NULL;
00252     }
00253 
00254     new_node = zone2node(zone);
00255     if (ldns_rbtree_insert(zonelist->zones, new_node) == NULL) {
00256         se_log_error("unable to add zone %s: rbtree insert failed",
00257             zone->name?zone->name:"(null)");
00258         zone_cleanup(zone);
00259         se_free((void*) new_node);
00260         return NULL;
00261     }
00262     zone->just_added = 1;
00263     return zone;
00264 }
00265 
00266 
00271 static zone_type*
00272 zonelist_delete_zone(zonelist_type* zonelist, zone_type* zone)
00273 {
00274     ldns_rbnode_t* old_node = LDNS_RBTREE_NULL;
00275 
00276     se_log_assert(zonelist);
00277     se_log_assert(zonelist->zones);
00278     se_log_assert(zone);
00279 
00280     old_node = ldns_rbtree_delete(zonelist->zones, zone);
00281     if (!old_node) {
00282         se_log_warning("unable to delete zone %s: not present",
00283             zone->name?zone->name:"(null)");
00284         return zone;
00285     }
00286 
00287     se_free((void*) old_node);
00288     zone_cleanup(zone);
00289     return NULL;
00290 }
00291 
00292 
00297 void
00298 zonelist_update(zonelist_type* zl, struct tasklist_struct* tl,
00299     const char* cmd, char* buf)
00300 {
00301     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00302     zone_type* zone = NULL;
00303     task_type* task = NULL;
00304     int just_removed = 0;
00305     int just_added = 0;
00306     int just_updated = 0;
00307 
00308     se_log_debug("update zone list");
00309 
00310     node = ldns_rbtree_first(zl->zones);
00311     while (node && node != LDNS_RBTREE_NULL) {
00312         zone = (zone_type*) node->key;
00313         /* removed */
00314         if (zone->tobe_removed) {
00315             if (zone->task) {
00316                 /* remove task from queue */
00317                 task = tasklist_delete_task(tl, zone->task);
00318                 task_cleanup(task);
00319             }
00320             node = ldns_rbtree_next(node);
00321             se_log_debug("delete zone %s from zone list",
00322                 zone->name?zone->name:"(null)");
00323             lock_basic_unlock(&zone->zone_lock);
00324             (void)zonelist_delete_zone(zl, zone);
00325             zone = NULL;
00326             just_removed++;
00327             continue;
00328         }
00329         /* added */
00330         else if (zone->just_added) {
00331             zone->just_added = 0;
00332             if (cmd && !zone->notify_ns) {
00333                 set_notify_ns(zone, cmd);
00334             }
00335             just_added++;
00336         }
00337         /* updated */
00338         else if (zone->just_updated) {
00339             zone->just_updated = 0;
00340             just_updated++;
00341         }
00342 
00343         node = ldns_rbtree_next(node);
00344     }
00345 
00346     if (buf) {
00347         (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: "
00348             "%i removed, %i added, %i updated.\n",
00349             just_removed, just_added, just_updated);
00350     }
00351     return;
00352 }
00353 
00354 
00359 void
00360 zonelist_merge(zonelist_type* zl1, zonelist_type* zl2)
00361 {
00362     zone_type* z1 = NULL;
00363     zone_type* z2 = NULL;
00364     ldns_rbnode_t* n1 = LDNS_RBTREE_NULL;
00365     ldns_rbnode_t* n2 = LDNS_RBTREE_NULL;
00366     int ret = 0;
00367 
00368     se_log_assert(zl1);
00369     se_log_assert(zl2);
00370     se_log_assert(zl1->zones);
00371     se_log_assert(zl2->zones);
00372 
00373     n1 = ldns_rbtree_first(zl1->zones);
00374     n2 = ldns_rbtree_first(zl2->zones);
00375     while (n2 && n2 != LDNS_RBTREE_NULL) {
00376         z2 = (zone_type*) n2->key;
00377         if (n1 && n1 != LDNS_RBTREE_NULL) {
00378             z1 = (zone_type*) n1->key;
00379         } else {
00380             z1 = NULL;
00381         }
00382 
00383         if (!z2) {
00384             /* no more zones to merge into zl1 */
00385             return;
00386         } else if (!z1) {
00387             /* just add remaining zones from zl2 */
00388             se_log_debug("add zone %s to zone list",
00389                 z2->name?z2->name:"(null)");
00390             z2 = zonelist_add_zone(zl1, z2);
00391             if (!z2) {
00392                 se_log_error("zone list merge failed, z2 not added");
00393                 return;
00394             }
00395             lock_basic_lock(&z2->zone_lock);
00396             n2 = ldns_rbtree_next(n2);
00397         } else {
00398             /* compare the zones z1 and z2 */
00399             ret = zone_compare(z1, z2);
00400             if (ret < 0) {
00401                 /* remove zone z1, it is not present in the new zonelist zl2 */
00402                 z1->tobe_removed = 1;
00403                 n1 = ldns_rbtree_next(n1);
00404             } else if (ret > 0) {
00405                 /* add the new zone z2 */
00406                 se_log_debug("add zone %s to zone list",
00407                     z2->name?z2->name:"(null)");
00408                 z2 = zonelist_add_zone(zl1, z2);
00409                 if (!z2) {
00410                     se_log_error("zone list merge failed, z2 not added");
00411                     return;
00412                 }
00413                 lock_basic_lock(&z2->zone_lock);
00414                 n2 = ldns_rbtree_next(n2);
00415             } else {
00416                 /* just update zone z1 */
00417                 n1 = ldns_rbtree_next(n1);
00418                 n2 = ldns_rbtree_next(n2);
00419                 zone_update_zonelist(z1, z2);
00420             }
00421         }
00422     }
00423 
00424     /* remove remaining zones from z1 */
00425     while (n1 && n1 != LDNS_RBTREE_NULL) {
00426         z1 = (zone_type*) n1->key;
00427         z1->tobe_removed = 1;
00428         n1 = ldns_rbtree_next(n1);
00429     }
00430 
00431     zl1->last_modified = zl2->last_modified;
00432     if (zl2->zones) {
00433         se_rbnode_free(zl2->zones->root);
00434         ldns_rbtree_free(zl2->zones);
00435     }
00436     se_free((void*) zl2);
00437     return;
00438 }
00439 
00440 
00445 void
00446 zonelist_cleanup(zonelist_type* zonelist)
00447 {
00448     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00449     zone_type* zone = NULL;
00450 
00451     if (zonelist) {
00452         if (zonelist->zones) {
00453             node = ldns_rbtree_first(zonelist->zones);
00454             while (node != LDNS_RBTREE_NULL) {
00455                 zone = (zone_type*) node->key;
00456                 zone_cleanup(zone);
00457                 node = ldns_rbtree_next(node);
00458             }
00459             se_rbnode_free(zonelist->zones->root);
00460             ldns_rbtree_free(zonelist->zones);
00461             zonelist->zones = NULL;
00462         }
00463         se_free((void*) zonelist);
00464     } else {
00465         se_log_warning("cleanup empty zone list");
00466     }
00467 }