update.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011-2015  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 #include <config.h>
00018 
00019 #include <time.h>
00020 
00021 #include <isc/log.h>
00022 #include <isc/magic.h>
00023 #include <isc/mem.h>
00024 #include <isc/netaddr.h>
00025 #include <isc/print.h>
00026 #include <isc/serial.h>
00027 #include <isc/stats.h>
00028 #include <isc/stdtime.h>
00029 #include <isc/string.h>
00030 #include <isc/taskpool.h>
00031 #include <isc/time.h>
00032 #include <isc/util.h>
00033 
00034 #include <dns/db.h>
00035 #include <dns/dbiterator.h>
00036 #include <dns/diff.h>
00037 #include <dns/dnssec.h>
00038 #include <dns/events.h>
00039 #include <dns/fixedname.h>
00040 #include <dns/journal.h>
00041 #include <dns/keyvalues.h>
00042 #include <dns/log.h>
00043 #include <dns/message.h>
00044 #include <dns/nsec.h>
00045 #include <dns/nsec3.h>
00046 #include <dns/private.h>
00047 #include <dns/rdataclass.h>
00048 #include <dns/rdataset.h>
00049 #include <dns/rdatasetiter.h>
00050 #include <dns/rdatastruct.h>
00051 #include <dns/rdatatype.h>
00052 #include <dns/result.h>
00053 #include <dns/soa.h>
00054 #include <dns/ssu.h>
00055 #include <dns/tsig.h>
00056 #include <dns/update.h>
00057 #include <dns/view.h>
00058 #include <dns/zone.h>
00059 #include <dns/zt.h>
00060 
00061 
00062 /**************************************************************************/
00063 
00064 #define STATE_MAGIC                     ISC_MAGIC('S', 'T', 'T', 'E')
00065 #define DNS_STATE_VALID(state)          ISC_MAGIC_VALID(state, STATE_MAGIC)
00066 
00067 /*%
00068  * Log level for tracing dynamic update protocol requests.
00069  */
00070 #define LOGLEVEL_PROTOCOL       ISC_LOG_INFO
00071 
00072 /*%
00073  * Log level for low-level debug tracing.
00074  */
00075 #define LOGLEVEL_DEBUG          ISC_LOG_DEBUG(8)
00076 
00077 /*%
00078  * Check an operation for failure.  These macros all assume that
00079  * the function using them has a 'result' variable and a 'failure'
00080  * label.
00081  */
00082 #define CHECK(op) \
00083         do { result = (op); \
00084                 if (result != ISC_R_SUCCESS) goto failure; \
00085         } while (0)
00086 
00087 /*%
00088  * Fail unconditionally with result 'code', which must not
00089  * be ISC_R_SUCCESS.  The reason for failure presumably has
00090  * been logged already.
00091  *
00092  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
00093  * from complaining about "end-of-loop code not reached".
00094  */
00095 
00096 #define FAIL(code) \
00097         do {                                                    \
00098                 result = (code);                                \
00099                 if (result != ISC_R_SUCCESS) goto failure;      \
00100         } while (0)
00101 
00102 /*%
00103  * Fail unconditionally and log as a client error.
00104  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
00105  * from complaining about "end-of-loop code not reached".
00106  */
00107 #define FAILC(code, msg) \
00108         do {                                                    \
00109                 const char *_what = "failed";                   \
00110                 result = (code);                                \
00111                 switch (result) {                               \
00112                 case DNS_R_NXDOMAIN:                            \
00113                 case DNS_R_YXDOMAIN:                            \
00114                 case DNS_R_YXRRSET:                             \
00115                 case DNS_R_NXRRSET:                             \
00116                         _what = "unsuccessful";                 \
00117                 }                                               \
00118                 update_log(log, zone, LOGLEVEL_PROTOCOL,        \
00119                            "update %s: %s (%s)", _what,         \
00120                            msg, isc_result_totext(result));     \
00121                 if (result != ISC_R_SUCCESS) goto failure;      \
00122         } while (0)
00123 
00124 #define FAILN(code, name, msg) \
00125         do {                                                            \
00126                 const char *_what = "failed";                           \
00127                 result = (code);                                        \
00128                 switch (result) {                                       \
00129                 case DNS_R_NXDOMAIN:                                    \
00130                 case DNS_R_YXDOMAIN:                                    \
00131                 case DNS_R_YXRRSET:                                     \
00132                 case DNS_R_NXRRSET:                                     \
00133                         _what = "unsuccessful";                         \
00134                 }                                                       \
00135                 if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) {    \
00136                         char _nbuf[DNS_NAME_FORMATSIZE];                \
00137                         dns_name_format(name, _nbuf, sizeof(_nbuf));    \
00138                         update_log(log, zone, LOGLEVEL_PROTOCOL,        \
00139                                    "update %s: %s: %s (%s)", _what, _nbuf, \
00140                                    msg, isc_result_totext(result));     \
00141                 }                                                       \
00142                 if (result != ISC_R_SUCCESS) goto failure;              \
00143         } while (0)
00144 
00145 #define FAILNT(code, name, type, msg) \
00146         do {                                                            \
00147                 const char *_what = "failed";                           \
00148                 result = (code);                                        \
00149                 switch (result) {                                       \
00150                 case DNS_R_NXDOMAIN:                                    \
00151                 case DNS_R_YXDOMAIN:                                    \
00152                 case DNS_R_YXRRSET:                                     \
00153                 case DNS_R_NXRRSET:                                     \
00154                         _what = "unsuccessful";                         \
00155                 }                                                       \
00156                 if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) {    \
00157                         char _nbuf[DNS_NAME_FORMATSIZE];                \
00158                         char _tbuf[DNS_RDATATYPE_FORMATSIZE];           \
00159                         dns_name_format(name, _nbuf, sizeof(_nbuf));    \
00160                         dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
00161                         update_log(log, zone, LOGLEVEL_PROTOCOL,        \
00162                                    "update %s: %s/%s: %s (%s)",         \
00163                                    _what, _nbuf, _tbuf, msg,            \
00164                                    isc_result_totext(result));          \
00165                 }                                                       \
00166                 if (result != ISC_R_SUCCESS) goto failure;              \
00167         } while (0)
00168 
00169 /*%
00170  * Fail unconditionally and log as a server error.
00171  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
00172  * from complaining about "end-of-loop code not reached".
00173  */
00174 #define FAILS(code, msg) \
00175         do {                                                    \
00176                 result = (code);                                \
00177                 update_log(log, zone, LOGLEVEL_PROTOCOL,        \
00178                            "error: %s: %s",                     \
00179                            msg, isc_result_totext(result));     \
00180                 if (result != ISC_R_SUCCESS) goto failure;      \
00181         } while (0)
00182 
00183 /**************************************************************************/
00184 
00185 typedef struct rr rr_t;
00186 
00187 struct rr {
00188         /* dns_name_t name; */
00189         isc_uint32_t            ttl;
00190         dns_rdata_t             rdata;
00191 };
00192 
00193 typedef struct update_event update_event_t;
00194 
00195 /**************************************************************************/
00196 
00197 static void
00198 update_log(dns_update_log_t *callback, dns_zone_t *zone,
00199            int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
00200 
00201 static void
00202 update_log(dns_update_log_t *callback, dns_zone_t *zone,
00203            int level, const char *fmt, ...)
00204 {
00205         va_list ap;
00206         char message[4096];
00207 
00208         if (callback == NULL)
00209                 return;
00210 
00211         if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
00212                 return;
00213 
00214 
00215         va_start(ap, fmt);
00216         vsnprintf(message, sizeof(message), fmt, ap);
00217         va_end(ap);
00218 
00219         (callback->func)(callback->arg, zone, level, message);
00220 }
00221 
00222 /*%
00223  * Update a single RR in version 'ver' of 'db' and log the
00224  * update in 'diff'.
00225  *
00226  * Ensures:
00227  * \li  '*tuple' == NULL.  Either the tuple is freed, or its
00228  *      ownership has been transferred to the diff.
00229  */
00230 static isc_result_t
00231 do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
00232              dns_diff_t *diff)
00233 {
00234         dns_diff_t temp_diff;
00235         isc_result_t result;
00236 
00237         /*
00238          * Create a singleton diff.
00239          */
00240         dns_diff_init(diff->mctx, &temp_diff);
00241         ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
00242 
00243         /*
00244          * Apply it to the database.
00245          */
00246         result = dns_diff_apply(&temp_diff, db, ver);
00247         ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
00248         if (result != ISC_R_SUCCESS) {
00249                 dns_difftuple_free(tuple);
00250                 return (result);
00251         }
00252 
00253         /*
00254          * Merge it into the current pending journal entry.
00255          */
00256         dns_diff_appendminimal(diff, tuple);
00257 
00258         /*
00259          * Do not clear temp_diff.
00260          */
00261         return (ISC_R_SUCCESS);
00262 }
00263 
00264 static isc_result_t
00265 update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
00266               dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
00267               dns_rdata_t *rdata)
00268 {
00269         dns_difftuple_t *tuple = NULL;
00270         isc_result_t result;
00271         result = dns_difftuple_create(diff->mctx, op,
00272                                       name, ttl, rdata, &tuple);
00273         if (result != ISC_R_SUCCESS)
00274                 return (result);
00275         return (do_one_tuple(&tuple, db, ver, diff));
00276 }
00277 
00278 /**************************************************************************/
00279 /*
00280  * Callback-style iteration over rdatasets and rdatas.
00281  *
00282  * foreach_rrset() can be used to iterate over the RRsets
00283  * of a name and call a callback function with each
00284  * one.  Similarly, foreach_rr() can be used to iterate
00285  * over the individual RRs at name, optionally restricted
00286  * to RRs of a given type.
00287  *
00288  * The callback functions are called "actions" and take
00289  * two arguments: a void pointer for passing arbitrary
00290  * context information, and a pointer to the current RRset
00291  * or RR.  By convention, their names end in "_action".
00292  */
00293 
00294 /*
00295  * XXXRTH  We might want to make this public somewhere in libdns.
00296  */
00297 
00298 /*%
00299  * Function type for foreach_rrset() iterator actions.
00300  */
00301 typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
00302 
00303 /*%
00304  * Function type for foreach_rr() iterator actions.
00305  */
00306 typedef isc_result_t rr_func(void *data, rr_t *rr);
00307 
00308 /*%
00309  * Internal context struct for foreach_node_rr().
00310  */
00311 typedef struct {
00312         rr_func *       rr_action;
00313         void *          rr_action_data;
00314 } foreach_node_rr_ctx_t;
00315 
00316 /*%
00317  * Internal helper function for foreach_node_rr().
00318  */
00319 static isc_result_t
00320 foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
00321         isc_result_t result;
00322         foreach_node_rr_ctx_t *ctx = data;
00323         for (result = dns_rdataset_first(rdataset);
00324              result == ISC_R_SUCCESS;
00325              result = dns_rdataset_next(rdataset))
00326         {
00327                 rr_t rr = { 0, DNS_RDATA_INIT };
00328 
00329                 dns_rdataset_current(rdataset, &rr.rdata);
00330                 rr.ttl = rdataset->ttl;
00331                 result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
00332                 if (result != ISC_R_SUCCESS)
00333                         return (result);
00334         }
00335         if (result != ISC_R_NOMORE)
00336                 return (result);
00337         return (ISC_R_SUCCESS);
00338 }
00339 
00340 /*%
00341  * For each rdataset of 'name' in 'ver' of 'db', call 'action'
00342  * with the rdataset and 'action_data' as arguments.  If the name
00343  * does not exist, do nothing.
00344  *
00345  * If 'action' returns an error, abort iteration and return the error.
00346  */
00347 static isc_result_t
00348 foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
00349               rrset_func *action, void *action_data)
00350 {
00351         isc_result_t result;
00352         dns_dbnode_t *node;
00353         dns_rdatasetiter_t *iter;
00354 
00355         node = NULL;
00356         result = dns_db_findnode(db, name, ISC_FALSE, &node);
00357         if (result == ISC_R_NOTFOUND)
00358                 return (ISC_R_SUCCESS);
00359         if (result != ISC_R_SUCCESS)
00360                 return (result);
00361 
00362         iter = NULL;
00363         result = dns_db_allrdatasets(db, node, ver,
00364                                      (isc_stdtime_t) 0, &iter);
00365         if (result != ISC_R_SUCCESS)
00366                 goto cleanup_node;
00367 
00368         for (result = dns_rdatasetiter_first(iter);
00369              result == ISC_R_SUCCESS;
00370              result = dns_rdatasetiter_next(iter))
00371         {
00372                 dns_rdataset_t rdataset;
00373 
00374                 dns_rdataset_init(&rdataset);
00375                 dns_rdatasetiter_current(iter, &rdataset);
00376 
00377                 result = (*action)(action_data, &rdataset);
00378 
00379                 dns_rdataset_disassociate(&rdataset);
00380                 if (result != ISC_R_SUCCESS)
00381                         goto cleanup_iterator;
00382         }
00383         if (result == ISC_R_NOMORE)
00384                 result = ISC_R_SUCCESS;
00385 
00386  cleanup_iterator:
00387         dns_rdatasetiter_destroy(&iter);
00388 
00389  cleanup_node:
00390         dns_db_detachnode(db, &node);
00391 
00392         return (result);
00393 }
00394 
00395 /*%
00396  * For each RR of 'name' in 'ver' of 'db', call 'action'
00397  * with the RR and 'action_data' as arguments.  If the name
00398  * does not exist, do nothing.
00399  *
00400  * If 'action' returns an error, abort iteration
00401  * and return the error.
00402  */
00403 static isc_result_t
00404 foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
00405                 rr_func *rr_action, void *rr_action_data)
00406 {
00407         foreach_node_rr_ctx_t ctx;
00408         ctx.rr_action = rr_action;
00409         ctx.rr_action_data = rr_action_data;
00410         return (foreach_rrset(db, ver, name,
00411                               foreach_node_rr_action, &ctx));
00412 }
00413 
00414 
00415 /*%
00416  * For each of the RRs specified by 'db', 'ver', 'name', 'type',
00417  * (which can be dns_rdatatype_any to match any type), and 'covers', call
00418  * 'action' with the RR and 'action_data' as arguments. If the name
00419  * does not exist, or if no RRset of the given type exists at the name,
00420  * do nothing.
00421  *
00422  * If 'action' returns an error, abort iteration and return the error.
00423  */
00424 static isc_result_t
00425 foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
00426            dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
00427            void *rr_action_data)
00428 {
00429 
00430         isc_result_t result;
00431         dns_dbnode_t *node;
00432         dns_rdataset_t rdataset;
00433 
00434         if (type == dns_rdatatype_any)
00435                 return (foreach_node_rr(db, ver, name,
00436                                         rr_action, rr_action_data));
00437 
00438         node = NULL;
00439         if (type == dns_rdatatype_nsec3 ||
00440             (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
00441                 result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
00442         else
00443                 result = dns_db_findnode(db, name, ISC_FALSE, &node);
00444         if (result == ISC_R_NOTFOUND)
00445                 return (ISC_R_SUCCESS);
00446         if (result != ISC_R_SUCCESS)
00447                 return (result);
00448 
00449         dns_rdataset_init(&rdataset);
00450         result = dns_db_findrdataset(db, node, ver, type, covers,
00451                                      (isc_stdtime_t) 0, &rdataset, NULL);
00452         if (result == ISC_R_NOTFOUND) {
00453                 result = ISC_R_SUCCESS;
00454                 goto cleanup_node;
00455         }
00456         if (result != ISC_R_SUCCESS)
00457                 goto cleanup_node;
00458 
00459         for (result = dns_rdataset_first(&rdataset);
00460              result == ISC_R_SUCCESS;
00461              result = dns_rdataset_next(&rdataset))
00462         {
00463                 rr_t rr = { 0, DNS_RDATA_INIT };
00464                 dns_rdataset_current(&rdataset, &rr.rdata);
00465                 rr.ttl = rdataset.ttl;
00466                 result = (*rr_action)(rr_action_data, &rr);
00467                 if (result != ISC_R_SUCCESS)
00468                         goto cleanup_rdataset;
00469         }
00470         if (result != ISC_R_NOMORE)
00471                 goto cleanup_rdataset;
00472         result = ISC_R_SUCCESS;
00473 
00474  cleanup_rdataset:
00475         dns_rdataset_disassociate(&rdataset);
00476  cleanup_node:
00477         dns_db_detachnode(db, &node);
00478 
00479         return (result);
00480 }
00481 
00482 /**************************************************************************/
00483 /*
00484  * Various tests on the database contents (for prerequisites, etc).
00485  */
00486 
00487 /*%
00488  * Function type for predicate functions that compare a database RR 'db_rr'
00489  * against an update RR 'update_rr'.
00490  */
00491 typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
00492 
00493 /*%
00494  * Helper function for rrset_exists().
00495  */
00496 static isc_result_t
00497 rrset_exists_action(void *data, rr_t *rr) {
00498         UNUSED(data);
00499         UNUSED(rr);
00500         return (ISC_R_EXISTS);
00501 }
00502 
00503 /*%
00504  * Utility macro for RR existence checking functions.
00505  *
00506  * If the variable 'result' has the value ISC_R_EXISTS or
00507  * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
00508  * respectively, and return success.
00509  *
00510  * If 'result' has any other value, there was a failure.
00511  * Return the failure result code and do not set *exists.
00512  *
00513  * This would be more readable as "do { if ... } while(0)",
00514  * but that form generates tons of warnings on Solaris 2.6.
00515  */
00516 #define RETURN_EXISTENCE_FLAG                           \
00517         return ((result == ISC_R_EXISTS) ?              \
00518                 (*exists = ISC_TRUE, ISC_R_SUCCESS) :   \
00519                 ((result == ISC_R_SUCCESS) ?            \
00520                  (*exists = ISC_FALSE, ISC_R_SUCCESS) : \
00521                  result))
00522 
00523 /*%
00524  * Set '*exists' to true iff an rrset of the given type exists,
00525  * to false otherwise.
00526  */
00527 static isc_result_t
00528 rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
00529              dns_rdatatype_t type, dns_rdatatype_t covers,
00530              isc_boolean_t *exists)
00531 {
00532         isc_result_t result;
00533         result = foreach_rr(db, ver, name, type, covers,
00534                             rrset_exists_action, NULL);
00535         RETURN_EXISTENCE_FLAG;
00536 }
00537 
00538 /*%
00539  * Set '*visible' to true if the RRset exists and is part of the
00540  * visible zone.  Otherwise '*visible' is set to false unless a
00541  * error occurs.
00542  */
00543 static isc_result_t
00544 rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
00545               dns_rdatatype_t type, isc_boolean_t *visible)
00546 {
00547         isc_result_t result;
00548         dns_fixedname_t fixed;
00549 
00550         dns_fixedname_init(&fixed);
00551         result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD,
00552                              (isc_stdtime_t) 0, NULL,
00553                              dns_fixedname_name(&fixed), NULL, NULL);
00554         switch (result) {
00555         case ISC_R_SUCCESS:
00556                 *visible = ISC_TRUE;
00557                 break;
00558         /*
00559          * Glue, obscured, deleted or replaced records.
00560          */
00561         case DNS_R_DELEGATION:
00562         case DNS_R_DNAME:
00563         case DNS_R_CNAME:
00564         case DNS_R_NXDOMAIN:
00565         case DNS_R_NXRRSET:
00566         case DNS_R_EMPTYNAME:
00567         case DNS_R_COVERINGNSEC:
00568                 *visible = ISC_FALSE;
00569                 result = ISC_R_SUCCESS;
00570                 break;
00571         default:
00572                 break;
00573         }
00574         return (result);
00575 }
00576 
00577 /*%
00578  * Context struct and helper function for name_exists().
00579  */
00580 
00581 static isc_result_t
00582 name_exists_action(void *data, dns_rdataset_t *rrset) {
00583         UNUSED(data);
00584         UNUSED(rrset);
00585         return (ISC_R_EXISTS);
00586 }
00587 
00588 /*%
00589  * Set '*exists' to true iff the given name exists, to false otherwise.
00590  */
00591 static isc_result_t
00592 name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
00593             isc_boolean_t *exists)
00594 {
00595         isc_result_t result;
00596         result = foreach_rrset(db, ver, name,
00597                                name_exists_action, NULL);
00598         RETURN_EXISTENCE_FLAG;
00599 }
00600 
00601 /**************************************************************************/
00602 /*
00603  * Checking of "RRset exists (value dependent)" prerequisites.
00604  *
00605  * In the RFC2136 section 3.2.5, this is the pseudocode involving
00606  * a variable called "temp", a mapping of <name, type> tuples to rrsets.
00607  *
00608  * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
00609  * where each tuple has op==DNS_DIFFOP_EXISTS.
00610  */
00611 
00612 /*%
00613  * A comparison function defining the sorting order for the entries
00614  * in the "temp" data structure.  The major sort key is the owner name,
00615  * followed by the type and rdata.
00616  */
00617 static int
00618 temp_order(const void *av, const void *bv) {
00619         dns_difftuple_t const * const *ap = av;
00620         dns_difftuple_t const * const *bp = bv;
00621         dns_difftuple_t const *a = *ap;
00622         dns_difftuple_t const *b = *bp;
00623         int r;
00624         r = dns_name_compare(&a->name, &b->name);
00625         if (r != 0)
00626                 return (r);
00627         r = (b->rdata.type - a->rdata.type);
00628         if (r != 0)
00629                 return (r);
00630         r = dns_rdata_casecompare(&a->rdata, &b->rdata);
00631         return (r);
00632 }
00633 
00634 /**************************************************************************/
00635 /*
00636  * Conditional deletion of RRs.
00637  */
00638 
00639 /*%
00640  * Context structure for delete_if().
00641  */
00642 
00643 typedef struct {
00644         rr_predicate *predicate;
00645         dns_db_t *db;
00646         dns_dbversion_t *ver;
00647         dns_diff_t *diff;
00648         dns_name_t *name;
00649         dns_rdata_t *update_rr;
00650 } conditional_delete_ctx_t;
00651 
00652 /*%
00653  * Predicate functions for delete_if().
00654  */
00655 
00656 /*%
00657  * Return true always.
00658  */
00659 static isc_boolean_t
00660 true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
00661         UNUSED(update_rr);
00662         UNUSED(db_rr);
00663         return (ISC_TRUE);
00664 }
00665 
00666 /*%
00667  * Return true if the record is a RRSIG.
00668  */
00669 static isc_boolean_t
00670 rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
00671         UNUSED(update_rr);
00672         return ((db_rr->type == dns_rdatatype_rrsig) ?
00673                 ISC_TRUE : ISC_FALSE);
00674 }
00675 
00676 /*%
00677  * Internal helper function for delete_if().
00678  */
00679 static isc_result_t
00680 delete_if_action(void *data, rr_t *rr) {
00681         conditional_delete_ctx_t *ctx = data;
00682         if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
00683                 isc_result_t result;
00684                 result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
00685                                        DNS_DIFFOP_DEL, ctx->name,
00686                                        rr->ttl, &rr->rdata);
00687                 return (result);
00688         } else {
00689                 return (ISC_R_SUCCESS);
00690         }
00691 }
00692 
00693 /*%
00694  * Conditionally delete RRs.  Apply 'predicate' to the RRs
00695  * specified by 'db', 'ver', 'name', and 'type' (which can
00696  * be dns_rdatatype_any to match any type).  Delete those
00697  * RRs for which the predicate returns true, and log the
00698  * deletions in 'diff'.
00699  */
00700 static isc_result_t
00701 delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
00702           dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
00703           dns_rdata_t *update_rr, dns_diff_t *diff)
00704 {
00705         conditional_delete_ctx_t ctx;
00706         ctx.predicate = predicate;
00707         ctx.db = db;
00708         ctx.ver = ver;
00709         ctx.diff = diff;
00710         ctx.name = name;
00711         ctx.update_rr = update_rr;
00712         return (foreach_rr(db, ver, name, type, covers,
00713                            delete_if_action, &ctx));
00714 }
00715 
00716 /**************************************************************************/
00717 /*
00718  * Incremental updating of NSECs and RRSIGs.
00719  */
00720 
00721 /*%
00722  * We abuse the dns_diff_t type to represent a set of domain names
00723  * affected by the update.
00724  */
00725 static isc_result_t
00726 namelist_append_name(dns_diff_t *list, dns_name_t *name) {
00727         isc_result_t result;
00728         dns_difftuple_t *tuple = NULL;
00729         static dns_rdata_t dummy_rdata = DNS_RDATA_INIT;
00730 
00731         CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0,
00732                                    &dummy_rdata, &tuple));
00733         dns_diff_append(list, &tuple);
00734  failure:
00735         return (result);
00736 }
00737 
00738 static isc_result_t
00739 namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
00740 {
00741         isc_result_t result;
00742         dns_fixedname_t fixedname;
00743         dns_name_t *child;
00744         dns_dbiterator_t *dbit = NULL;
00745 
00746         dns_fixedname_init(&fixedname);
00747         child = dns_fixedname_name(&fixedname);
00748 
00749         CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
00750 
00751         for (result = dns_dbiterator_seek(dbit, name);
00752              result == ISC_R_SUCCESS;
00753              result = dns_dbiterator_next(dbit))
00754         {
00755                 dns_dbnode_t *node = NULL;
00756                 CHECK(dns_dbiterator_current(dbit, &node, child));
00757                 dns_db_detachnode(db, &node);
00758                 if (! dns_name_issubdomain(child, name))
00759                         break;
00760                 CHECK(namelist_append_name(affected, child));
00761         }
00762         if (result == ISC_R_NOMORE)
00763                 result = ISC_R_SUCCESS;
00764  failure:
00765         if (dbit != NULL)
00766                 dns_dbiterator_destroy(&dbit);
00767         return (result);
00768 }
00769 
00770 
00771 
00772 /*%
00773  * Helper function for non_nsec_rrset_exists().
00774  */
00775 static isc_result_t
00776 is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
00777         UNUSED(data);
00778         if (!(rrset->type == dns_rdatatype_nsec ||
00779               rrset->type == dns_rdatatype_nsec3 ||
00780               (rrset->type == dns_rdatatype_rrsig &&
00781                (rrset->covers == dns_rdatatype_nsec ||
00782                 rrset->covers == dns_rdatatype_nsec3))))
00783                 return (ISC_R_EXISTS);
00784         return (ISC_R_SUCCESS);
00785 }
00786 
00787 /*%
00788  * Check whether there is an rrset other than a NSEC or RRSIG NSEC,
00789  * i.e., anything that justifies the continued existence of a name
00790  * after a secure update.
00791  *
00792  * If such an rrset exists, set '*exists' to ISC_TRUE.
00793  * Otherwise, set it to ISC_FALSE.
00794  */
00795 static isc_result_t
00796 non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
00797                      dns_name_t *name, isc_boolean_t *exists)
00798 {
00799         isc_result_t result;
00800         result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
00801         RETURN_EXISTENCE_FLAG;
00802 }
00803 
00804 /*%
00805  * A comparison function for sorting dns_diff_t:s by name.
00806  */
00807 static int
00808 name_order(const void *av, const void *bv) {
00809         dns_difftuple_t const * const *ap = av;
00810         dns_difftuple_t const * const *bp = bv;
00811         dns_difftuple_t const *a = *ap;
00812         dns_difftuple_t const *b = *bp;
00813         return (dns_name_compare(&a->name, &b->name));
00814 }
00815 
00816 static isc_result_t
00817 uniqify_name_list(dns_diff_t *list) {
00818         isc_result_t result;
00819         dns_difftuple_t *p, *q;
00820 
00821         CHECK(dns_diff_sort(list, name_order));
00822 
00823         p = ISC_LIST_HEAD(list->tuples);
00824         while (p != NULL) {
00825                 do {
00826                         q = ISC_LIST_NEXT(p, link);
00827                         if (q == NULL || ! dns_name_equal(&p->name, &q->name))
00828                                 break;
00829                         ISC_LIST_UNLINK(list->tuples, q, link);
00830                         dns_difftuple_free(&q);
00831                 } while (1);
00832                 p = ISC_LIST_NEXT(p, link);
00833         }
00834  failure:
00835         return (result);
00836 }
00837 
00838 static isc_result_t
00839 is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
00840           isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure)
00841 {
00842         isc_result_t result;
00843         dns_fixedname_t foundname;
00844         dns_fixedname_init(&foundname);
00845         result = dns_db_find(db, name, ver, dns_rdatatype_any,
00846                              DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
00847                              (isc_stdtime_t) 0, NULL,
00848                              dns_fixedname_name(&foundname),
00849                              NULL, NULL);
00850         if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
00851                 *flag = ISC_TRUE;
00852                 *cut = ISC_FALSE;
00853                 if (unsecure != NULL)
00854                         *unsecure = ISC_FALSE;
00855                 return (ISC_R_SUCCESS);
00856         } else if (result == DNS_R_ZONECUT) {
00857                 *flag = ISC_TRUE;
00858                 *cut = ISC_TRUE;
00859                 if (unsecure != NULL) {
00860                         /*
00861                          * We are at the zonecut.  Check to see if there
00862                          * is a DS RRset.
00863                          */
00864                         if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
00865                                         (isc_stdtime_t) 0, NULL,
00866                                         dns_fixedname_name(&foundname),
00867                                         NULL, NULL) == DNS_R_NXRRSET)
00868                                 *unsecure = ISC_TRUE;
00869                         else
00870                                 *unsecure = ISC_FALSE;
00871                 }
00872                 return (ISC_R_SUCCESS);
00873         } else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
00874                    result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
00875                 *flag = ISC_FALSE;
00876                 *cut = ISC_FALSE;
00877                 if (unsecure != NULL)
00878                         *unsecure = ISC_FALSE;
00879                 return (ISC_R_SUCCESS);
00880         } else {
00881                 /*
00882                  * Silence compiler.
00883                  */
00884                 *flag = ISC_FALSE;
00885                 *cut = ISC_FALSE;
00886                 if (unsecure != NULL)
00887                         *unsecure = ISC_FALSE;
00888                 return (result);
00889         }
00890 }
00891 
00892 /*%
00893  * Find the next/previous name that has a NSEC record.
00894  * In other words, skip empty database nodes and names that
00895  * have had their NSECs removed because they are obscured by
00896  * a zone cut.
00897  */
00898 static isc_result_t
00899 next_active(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
00900             dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname,
00901             isc_boolean_t forward)
00902 {
00903         isc_result_t result;
00904         dns_dbiterator_t *dbit = NULL;
00905         isc_boolean_t has_nsec = ISC_FALSE;
00906         unsigned int wraps = 0;
00907         isc_boolean_t secure = dns_db_issecure(db);
00908 
00909         CHECK(dns_db_createiterator(db, 0, &dbit));
00910 
00911         CHECK(dns_dbiterator_seek(dbit, oldname));
00912         do {
00913                 dns_dbnode_t *node = NULL;
00914 
00915                 if (forward)
00916                         result = dns_dbiterator_next(dbit);
00917                 else
00918                         result = dns_dbiterator_prev(dbit);
00919                 if (result == ISC_R_NOMORE) {
00920                         /*
00921                          * Wrap around.
00922                          */
00923                         if (forward)
00924                                 CHECK(dns_dbiterator_first(dbit));
00925                         else
00926                                 CHECK(dns_dbiterator_last(dbit));
00927                         wraps++;
00928                         if (wraps == 2) {
00929                                 update_log(log, zone, ISC_LOG_ERROR,
00930                                            "secure zone with no NSECs");
00931                                 result = DNS_R_BADZONE;
00932                                 goto failure;
00933                         }
00934                 }
00935                 CHECK(dns_dbiterator_current(dbit, &node, newname));
00936                 dns_db_detachnode(db, &node);
00937 
00938                 /*
00939                  * The iterator may hold the tree lock, and
00940                  * rrset_exists() calls dns_db_findnode() which
00941                  * may try to reacquire it.  To avoid deadlock
00942                  * we must pause the iterator first.
00943                  */
00944                 CHECK(dns_dbiterator_pause(dbit));
00945                 if (secure) {
00946                         CHECK(rrset_exists(db, ver, newname,
00947                                            dns_rdatatype_nsec, 0, &has_nsec));
00948                 } else {
00949                         dns_fixedname_t ffound;
00950                         dns_name_t *found;
00951                         dns_fixedname_init(&ffound);
00952                         found = dns_fixedname_name(&ffound);
00953                         result = dns_db_find(db, newname, ver,
00954                                              dns_rdatatype_soa,
00955                                              DNS_DBFIND_NOWILD, 0, NULL, found,
00956                                              NULL, NULL);
00957                         if (result == ISC_R_SUCCESS ||
00958                             result == DNS_R_EMPTYNAME ||
00959                             result == DNS_R_NXRRSET ||
00960                             result == DNS_R_CNAME ||
00961                             (result == DNS_R_DELEGATION &&
00962                              dns_name_equal(newname, found))) {
00963                                 has_nsec = ISC_TRUE;
00964                                 result = ISC_R_SUCCESS;
00965                         } else if (result != DNS_R_NXDOMAIN)
00966                                 break;
00967                 }
00968         } while (! has_nsec);
00969  failure:
00970         if (dbit != NULL)
00971                 dns_dbiterator_destroy(&dbit);
00972 
00973         return (result);
00974 }
00975 
00976 /*%
00977  * Add a NSEC record for "name", recording the change in "diff".
00978  * The existing NSEC is removed.
00979  */
00980 static isc_result_t
00981 add_nsec(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
00982          dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl,
00983          dns_diff_t *diff)
00984 {
00985         isc_result_t result;
00986         dns_dbnode_t *node = NULL;
00987         unsigned char buffer[DNS_NSEC_BUFFERSIZE];
00988         dns_rdata_t rdata = DNS_RDATA_INIT;
00989         dns_difftuple_t *tuple = NULL;
00990         dns_fixedname_t fixedname;
00991         dns_name_t *target;
00992 
00993         dns_fixedname_init(&fixedname);
00994         target = dns_fixedname_name(&fixedname);
00995 
00996         /*
00997          * Find the successor name, aka NSEC target.
00998          */
00999         CHECK(next_active(log, zone, db, ver, name, target, ISC_TRUE));
01000 
01001         /*
01002          * Create the NSEC RDATA.
01003          */
01004         CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
01005         dns_rdata_init(&rdata);
01006         CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
01007         dns_db_detachnode(db, &node);
01008 
01009         /*
01010          * Delete the old NSEC and record the change.
01011          */
01012         CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0,
01013                         NULL, diff));
01014         /*
01015          * Add the new NSEC and record the change.
01016          */
01017         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
01018                                    nsecttl, &rdata, &tuple));
01019         CHECK(do_one_tuple(&tuple, db, ver, diff));
01020         INSIST(tuple == NULL);
01021 
01022  failure:
01023         if (node != NULL)
01024                 dns_db_detachnode(db, &node);
01025         return (result);
01026 }
01027 
01028 /*%
01029  * Add a placeholder NSEC record for "name", recording the change in "diff".
01030  */
01031 static isc_result_t
01032 add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
01033                      dns_diff_t *diff)
01034 {
01035         isc_result_t result;
01036         dns_difftuple_t *tuple = NULL;
01037         isc_region_t r;
01038         unsigned char data[1] = { 0 }; /* The root domain, no bits. */
01039         dns_rdata_t rdata = DNS_RDATA_INIT;
01040 
01041         r.base = data;
01042         r.length = sizeof(data);
01043         dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
01044         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
01045                                    &rdata, &tuple));
01046         CHECK(do_one_tuple(&tuple, db, ver, diff));
01047  failure:
01048         return (result);
01049 }
01050 
01051 static isc_result_t
01052 find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
01053                isc_mem_t *mctx, unsigned int maxkeys,
01054                dst_key_t **keys, unsigned int *nkeys)
01055 {
01056         isc_result_t result;
01057         dns_dbnode_t *node = NULL;
01058         const char *directory = dns_zone_getkeydirectory(zone);
01059         CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
01060         CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
01061                                        directory, mctx, maxkeys, keys, nkeys));
01062  failure:
01063         if (node != NULL)
01064                 dns_db_detachnode(db, &node);
01065         return (result);
01066 }
01067 
01068 /*%
01069  * Add RRSIG records for an RRset, recording the change in "diff".
01070  */
01071 static isc_result_t
01072 add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
01073          dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type,
01074          dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
01075          isc_stdtime_t inception, isc_stdtime_t expire,
01076          isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
01077 {
01078         isc_result_t result;
01079         dns_dbnode_t *node = NULL;
01080         dns_rdataset_t rdataset;
01081         dns_rdata_t sig_rdata = DNS_RDATA_INIT;
01082         isc_buffer_t buffer;
01083         unsigned char data[1024]; /* XXX */
01084         unsigned int i, j;
01085         isc_boolean_t added_sig = ISC_FALSE;
01086         isc_mem_t *mctx = diff->mctx;
01087 
01088         dns_rdataset_init(&rdataset);
01089         isc_buffer_init(&buffer, data, sizeof(data));
01090 
01091         /* Get the rdataset to sign. */
01092         if (type == dns_rdatatype_nsec3)
01093                 CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
01094         else
01095                 CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
01096         CHECK(dns_db_findrdataset(db, node, ver, type, 0,
01097                                   (isc_stdtime_t) 0, &rdataset, NULL));
01098         dns_db_detachnode(db, &node);
01099 
01100 #define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
01101 #define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
01102 #define ALG(x) dst_key_alg(x)
01103 
01104         /*
01105          * If we are honoring KSK flags then we need to check that we
01106          * have both KSK and non-KSK keys that are not revoked per
01107          * algorithm.
01108          */
01109         for (i = 0; i < nkeys; i++) {
01110                 isc_boolean_t both = ISC_FALSE;
01111 
01112                 if (!dst_key_isprivate(keys[i]))
01113                         continue;
01114 
01115                 if (check_ksk && !REVOKE(keys[i])) {
01116                         isc_boolean_t have_ksk, have_nonksk;
01117                         if (KSK(keys[i])) {
01118                                 have_ksk = ISC_TRUE;
01119                                 have_nonksk = ISC_FALSE;
01120                         } else {
01121                                 have_ksk = ISC_FALSE;
01122                                 have_nonksk = ISC_TRUE;
01123                         }
01124                         for (j = 0; j < nkeys; j++) {
01125                                 if (j == i || ALG(keys[i]) != ALG(keys[j]))
01126                                         continue;
01127                                 if (REVOKE(keys[j]))
01128                                         continue;
01129                                 if (KSK(keys[j]))
01130                                         have_ksk = ISC_TRUE;
01131                                 else
01132                                         have_nonksk = ISC_TRUE;
01133                                 both = have_ksk && have_nonksk;
01134                                 if (both)
01135                                         break;
01136                         }
01137                 }
01138 
01139                 if (both) {
01140                         if (type == dns_rdatatype_dnskey) {
01141                                 if (!KSK(keys[i]) && keyset_kskonly)
01142                                         continue;
01143                         } else if (KSK(keys[i]))
01144                                 continue;
01145                 } else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey)
01146                         continue;
01147 
01148                 /* Calculate the signature, creating a RRSIG RDATA. */
01149                 CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
01150                                       &inception, &expire,
01151                                       mctx, &buffer, &sig_rdata));
01152 
01153                 /* Update the database and journal with the RRSIG. */
01154                 /* XXX inefficient - will cause dataset merging */
01155                 CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, name,
01156                                     rdataset.ttl, &sig_rdata));
01157                 dns_rdata_reset(&sig_rdata);
01158                 isc_buffer_init(&buffer, data, sizeof(data));
01159                 added_sig = ISC_TRUE;
01160         }
01161         if (!added_sig) {
01162                 update_log(log, zone, ISC_LOG_ERROR,
01163                            "found no active private keys, "
01164                            "unable to generate any signatures");
01165                 result = ISC_R_NOTFOUND;
01166         }
01167 
01168  failure:
01169         if (dns_rdataset_isassociated(&rdataset))
01170                 dns_rdataset_disassociate(&rdataset);
01171         if (node != NULL)
01172                 dns_db_detachnode(db, &node);
01173         return (result);
01174 }
01175 
01176 /*
01177  * Delete expired RRsigs and any RRsigs we are about to re-sign.
01178  * See also zone.c:del_sigs().
01179  */
01180 static isc_result_t
01181 del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
01182             dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys)
01183 {
01184         isc_result_t result;
01185         dns_dbnode_t *node = NULL;
01186         dns_rdataset_t rdataset;
01187         dns_rdata_t rdata = DNS_RDATA_INIT;
01188         unsigned int i;
01189         dns_rdata_rrsig_t rrsig;
01190         isc_boolean_t found;
01191 
01192         dns_rdataset_init(&rdataset);
01193 
01194         result = dns_db_findnode(db, name, ISC_FALSE, &node);
01195         if (result == ISC_R_NOTFOUND)
01196                 return (ISC_R_SUCCESS);
01197         if (result != ISC_R_SUCCESS)
01198                 goto failure;
01199         result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
01200                                      dns_rdatatype_dnskey, (isc_stdtime_t) 0,
01201                                      &rdataset, NULL);
01202         dns_db_detachnode(db, &node);
01203 
01204         if (result == ISC_R_NOTFOUND)
01205                 return (ISC_R_SUCCESS);
01206         if (result != ISC_R_SUCCESS)
01207                 goto failure;
01208 
01209         for (result = dns_rdataset_first(&rdataset);
01210              result == ISC_R_SUCCESS;
01211              result = dns_rdataset_next(&rdataset)) {
01212                 dns_rdataset_current(&rdataset, &rdata);
01213                 result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
01214                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
01215                 found = ISC_FALSE;
01216                 for (i = 0; i < nkeys; i++) {
01217                         if (rrsig.keyid == dst_key_id(keys[i])) {
01218                                 found = ISC_TRUE;
01219                                 if (!dst_key_isprivate(keys[i]) &&
01220                                     !dst_key_inactive(keys[i]))
01221                                 {
01222                                         /*
01223                                          * The re-signing code in zone.c
01224                                          * will mark this as offline.
01225                                          * Just skip the record for now.
01226                                          */
01227                                         break;
01228                                 }
01229                                 result = update_one_rr(db, ver, diff,
01230                                                        DNS_DIFFOP_DEL, name,
01231                                                        rdataset.ttl, &rdata);
01232                                 break;
01233                         }
01234                 }
01235                 /*
01236                  * If there is not a matching DNSKEY then delete the RRSIG.
01237                  */
01238                 if (!found)
01239                         result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
01240                                                name, rdataset.ttl, &rdata);
01241                 dns_rdata_reset(&rdata);
01242                 if (result != ISC_R_SUCCESS)
01243                         break;
01244         }
01245         dns_rdataset_disassociate(&rdataset);
01246         if (result == ISC_R_NOMORE)
01247                 result = ISC_R_SUCCESS;
01248 failure:
01249         if (node != NULL)
01250                 dns_db_detachnode(db, &node);
01251         return (result);
01252 }
01253 
01254 static isc_result_t
01255 add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
01256                  dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut,
01257                  dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
01258                  isc_stdtime_t inception, isc_stdtime_t expire,
01259                  isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly,
01260                  unsigned int *sigs)
01261 {
01262         isc_result_t result;
01263         dns_dbnode_t *node;
01264         dns_rdatasetiter_t *iter;
01265 
01266         node = NULL;
01267         result = dns_db_findnode(db, name, ISC_FALSE, &node);
01268         if (result == ISC_R_NOTFOUND)
01269                 return (ISC_R_SUCCESS);
01270         if (result != ISC_R_SUCCESS)
01271                 return (result);
01272 
01273         iter = NULL;
01274         result = dns_db_allrdatasets(db, node, ver,
01275                                      (isc_stdtime_t) 0, &iter);
01276         if (result != ISC_R_SUCCESS)
01277                 goto cleanup_node;
01278 
01279         for (result = dns_rdatasetiter_first(iter);
01280              result == ISC_R_SUCCESS;
01281              result = dns_rdatasetiter_next(iter))
01282         {
01283                 dns_rdataset_t rdataset;
01284                 dns_rdatatype_t type;
01285                 isc_boolean_t flag;
01286 
01287                 dns_rdataset_init(&rdataset);
01288                 dns_rdatasetiter_current(iter, &rdataset);
01289                 type = rdataset.type;
01290                 dns_rdataset_disassociate(&rdataset);
01291 
01292                 /*
01293                  * We don't need to sign unsigned NSEC records at the cut
01294                  * as they are handled elsewhere.
01295                  */
01296                 if ((type == dns_rdatatype_rrsig) ||
01297                     (cut && type != dns_rdatatype_ds))
01298                         continue;
01299                 result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
01300                                       type, &flag);
01301                 if (result != ISC_R_SUCCESS)
01302                         goto cleanup_iterator;
01303                 if (flag)
01304                         continue;;
01305                 result = add_sigs(log, zone, db, ver, name, type, diff,
01306                                   keys, nkeys, inception, expire,
01307                                   check_ksk, keyset_kskonly);
01308                 if (result != ISC_R_SUCCESS)
01309                         goto cleanup_iterator;
01310                 (*sigs)++;
01311         }
01312         if (result == ISC_R_NOMORE)
01313                 result = ISC_R_SUCCESS;
01314 
01315  cleanup_iterator:
01316         dns_rdatasetiter_destroy(&iter);
01317 
01318  cleanup_node:
01319         dns_db_detachnode(db, &node);
01320 
01321         return (result);
01322 }
01323 
01324 /*%
01325  * Update RRSIG, NSEC and NSEC3 records affected by an update.  The original
01326  * update, including the SOA serial update but excluding the RRSIG & NSEC
01327  * changes, is in "diff" and has already been applied to "newver" of "db".
01328  * The database version prior to the update is "oldver".
01329  *
01330  * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
01331  * and added (as a minimal diff) to "diff".
01332  *
01333  * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
01334  */
01335 isc_result_t
01336 dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
01337                       dns_dbversion_t *oldver, dns_dbversion_t *newver,
01338                       dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
01339 {
01340         return (dns_update_signaturesinc(log, zone, db, oldver, newver, diff,
01341                                          sigvalidityinterval, NULL));
01342 }
01343 
01344 struct dns_update_state {
01345         unsigned int magic;
01346         dns_diff_t diffnames;
01347         dns_diff_t affected;
01348         dns_diff_t sig_diff;
01349         dns_diff_t nsec_diff;
01350         dns_diff_t nsec_mindiff;
01351         dns_diff_t work;
01352         dst_key_t *zone_keys[DNS_MAXZONEKEYS];
01353         unsigned int nkeys;
01354         isc_stdtime_t inception, expire;
01355         dns_ttl_t nsecttl;
01356         isc_boolean_t check_ksk, keyset_kskonly;
01357         enum { sign_updates, remove_orphaned, build_chain, process_nsec,
01358                sign_nsec, update_nsec3, process_nsec3, sign_nsec3 } state;
01359 };
01360 
01361 isc_result_t
01362 dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
01363                          dns_dbversion_t *oldver, dns_dbversion_t *newver,
01364                          dns_diff_t *diff, isc_uint32_t sigvalidityinterval,
01365                          dns_update_state_t **statep)
01366 {
01367         isc_result_t result = ISC_R_SUCCESS;
01368         dns_update_state_t mystate, *state;
01369 
01370         dns_difftuple_t *t, *next;
01371         isc_boolean_t flag, build_nsec, build_nsec3;
01372         unsigned int i;
01373         isc_stdtime_t now;
01374         dns_rdata_soa_t soa;
01375         dns_rdata_t rdata = DNS_RDATA_INIT;
01376         dns_rdataset_t rdataset;
01377         dns_dbnode_t *node = NULL;
01378         isc_boolean_t unsecure;
01379         isc_boolean_t cut;
01380         dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
01381         unsigned int sigs = 0;
01382         unsigned int maxsigs = dns_zone_getsignatures(zone);
01383 
01384         if (statep == NULL || (statep != NULL && *statep == NULL)) {
01385                 if (statep == NULL) {
01386                         state = &mystate;
01387                 } else {
01388                         state = isc_mem_get(diff->mctx, sizeof(*state));
01389                         if (state == NULL)
01390                                 return (ISC_R_NOMEMORY);
01391                 }
01392 
01393                 dns_diff_init(diff->mctx, &state->diffnames);
01394                 dns_diff_init(diff->mctx, &state->affected);
01395                 dns_diff_init(diff->mctx, &state->sig_diff);
01396                 dns_diff_init(diff->mctx, &state->nsec_diff);
01397                 dns_diff_init(diff->mctx, &state->nsec_mindiff);
01398                 dns_diff_init(diff->mctx, &state->work);
01399                 state->nkeys = 0;
01400 
01401                 result = find_zone_keys(zone, db, newver, diff->mctx,
01402                                         DNS_MAXZONEKEYS, state->zone_keys,
01403                                         &state->nkeys);
01404                 if (result != ISC_R_SUCCESS) {
01405                         update_log(log, zone, ISC_LOG_ERROR,
01406                                    "could not get zone keys for secure "
01407                                    "dynamic update");
01408                         goto failure;
01409                 }
01410 
01411                 isc_stdtime_get(&now);
01412                 state->inception = now - 3600; /* Allow for some clock skew. */
01413                 state->expire = now + sigvalidityinterval;
01414 
01415                 /*
01416                  * Do we look at the KSK flag on the DNSKEY to determining which
01417                  * keys sign which RRsets?  First check the zone option then
01418                  * check the keys flags to make sure at least one has a ksk set
01419                  * and one doesn't.
01420                  */
01421                 state->check_ksk = ISC_TF((dns_zone_getoptions(zone) &
01422                                     DNS_ZONEOPT_UPDATECHECKKSK) != 0);
01423                 state->keyset_kskonly = ISC_TF((dns_zone_getoptions(zone) &
01424                                         DNS_ZONEOPT_DNSKEYKSKONLY) != 0);
01425 
01426                 /*
01427                  * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
01428                  */
01429                 CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
01430                 dns_rdataset_init(&rdataset);
01431                 CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa,
01432                                           0, (isc_stdtime_t) 0, &rdataset,
01433                                           NULL));
01434                 CHECK(dns_rdataset_first(&rdataset));
01435                 dns_rdataset_current(&rdataset, &rdata);
01436                 CHECK(dns_rdata_tostruct(&rdata, &soa, NULL));
01437                 state->nsecttl = soa.minimum;
01438                 dns_rdataset_disassociate(&rdataset);
01439                 dns_db_detachnode(db, &node);
01440 
01441                 /*
01442                  * Find all RRsets directly affected by the update, and
01443                  * update their RRSIGs.  Also build a list of names affected
01444                  * by the update in "diffnames".
01445                  */
01446                 CHECK(dns_diff_sort(diff, temp_order));
01447                 state->state = sign_updates;
01448                 state->magic = STATE_MAGIC;
01449                 if (statep != NULL)
01450                         *statep = state;
01451         } else {
01452                 REQUIRE(DNS_STATE_VALID(*statep));
01453                 state = *statep;
01454         }
01455 
01456  next_state:
01457         switch (state->state) {
01458         case sign_updates:
01459                 t = ISC_LIST_HEAD(diff->tuples);
01460                 while (t != NULL) {
01461                         dns_name_t *name = &t->name;
01462                         /*
01463                          * Now "name" is a new, unique name affected by the
01464                          * update.
01465                          */
01466 
01467                         CHECK(namelist_append_name(&state->diffnames, name));
01468 
01469                         while (t != NULL && dns_name_equal(&t->name, name)) {
01470                                 dns_rdatatype_t type;
01471                                 type = t->rdata.type;
01472 
01473                                 /*
01474                                  * Now "name" and "type" denote a new unique
01475                                  * RRset affected by the update.
01476                                  */
01477 
01478                                 /* Don't sign RRSIGs. */
01479                                 if (type == dns_rdatatype_rrsig)
01480                                         goto skip;
01481 
01482                                 /*
01483                                  * Delete all old RRSIGs covering this type,
01484                                  * since they are all invalid when the signed
01485                                  * RRset has changed.  We may not be able to
01486                                  * recreate all of them - tough.
01487                                  * Special case changes to the zone's DNSKEY
01488                                  * records to support offline KSKs.
01489                                  */
01490                                 if (type == dns_rdatatype_dnskey)
01491                                         del_keysigs(db, newver, name,
01492                                                     &state->sig_diff,
01493                                                     state->zone_keys,
01494                                                     state->nkeys);
01495                                 else
01496                                         CHECK(delete_if(true_p, db, newver,
01497                                                         name,
01498                                                         dns_rdatatype_rrsig,
01499                                                         type, NULL,
01500                                                         &state->sig_diff));
01501 
01502                                 /*
01503                                  * If this RRset is still visible after the
01504                                  * update, add a new signature for it.
01505                                  */
01506                                 CHECK(rrset_visible(db, newver, name, type,
01507                                                    &flag));
01508                                 if (flag) {
01509                                         CHECK(add_sigs(log, zone, db, newver,
01510                                                        name, type,
01511                                                        &state->sig_diff,
01512                                                        state->zone_keys,
01513                                                        state->nkeys,
01514                                                        state->inception,
01515                                                        state->expire,
01516                                                        state->check_ksk,
01517                                                        state->keyset_kskonly));
01518                                         sigs++;
01519                                 }
01520                         skip:
01521                                 /* Skip any other updates to the same RRset. */
01522                                 while (t != NULL &&
01523                                        dns_name_equal(&t->name, name) &&
01524                                        t->rdata.type == type)
01525                                 {
01526                                         next = ISC_LIST_NEXT(t, link);
01527                                         ISC_LIST_UNLINK(diff->tuples, t, link);
01528                                         ISC_LIST_APPEND(state->work.tuples, t,
01529                                                         link);
01530                                         t = next;
01531                                 }
01532                         }
01533                         if (state != &mystate && sigs > maxsigs)
01534                                 return (DNS_R_CONTINUE);
01535                 }
01536                 ISC_LIST_APPENDLIST(diff->tuples, state->work.tuples, link);
01537 
01538                 update_log(log, zone, ISC_LOG_DEBUG(3),
01539                            "updated data signatures");
01540                 /*FALLTHROUGH*/
01541         case remove_orphaned:
01542                 state->state = remove_orphaned;
01543 
01544                 /* Remove orphaned NSECs and RRSIG NSECs. */
01545                 for (t = ISC_LIST_HEAD(state->diffnames.tuples);
01546                      t != NULL;
01547                      t = ISC_LIST_NEXT(t, link))
01548                 {
01549                         CHECK(non_nsec_rrset_exists(db, newver,
01550                                                     &t->name, &flag));
01551                         if (!flag) {
01552                                 CHECK(delete_if(true_p, db, newver, &t->name,
01553                                                 dns_rdatatype_any, 0,
01554                                                 NULL, &state->sig_diff));
01555                         }
01556                 }
01557                 update_log(log, zone, ISC_LOG_DEBUG(3),
01558                            "removed any orphaned NSEC records");
01559 
01560                 /*
01561                  * See if we need to build NSEC or NSEC3 chains.
01562                  */
01563                 CHECK(dns_private_chains(db, newver, privatetype, &build_nsec,
01564                                          &build_nsec3));
01565                 if (!build_nsec) {
01566                         state->state = update_nsec3;
01567                         goto next_state;
01568                 }
01569 
01570                 update_log(log, zone, ISC_LOG_DEBUG(3),
01571                            "rebuilding NSEC chain");
01572 
01573                 /*FALLTHROUGH*/
01574         case build_chain:
01575                 state->state = build_chain;
01576                 /*
01577                  * When a name is created or deleted, its predecessor needs to
01578                  * have its NSEC updated.
01579                  */
01580                 for (t = ISC_LIST_HEAD(state->diffnames.tuples);
01581                      t != NULL;
01582                      t = ISC_LIST_NEXT(t, link))
01583                 {
01584                         isc_boolean_t existed, exists;
01585                         dns_fixedname_t fixedname;
01586                         dns_name_t *prevname;
01587 
01588                         dns_fixedname_init(&fixedname);
01589                         prevname = dns_fixedname_name(&fixedname);
01590 
01591                         if (oldver != NULL)
01592                                 CHECK(name_exists(db, oldver, &t->name,
01593                                                   &existed));
01594                         else
01595                                 existed = ISC_FALSE;
01596                         CHECK(name_exists(db, newver, &t->name, &exists));
01597                         if (exists == existed)
01598                                 continue;
01599 
01600                         /*
01601                          * Find the predecessor.
01602                          * When names become obscured or unobscured in this
01603                          * update transaction, we may find the wrong
01604                          * predecessor because the NSECs have not yet been
01605                          * updated to reflect the delegation change.  This
01606                          * should not matter because in this case, the correct
01607                          * predecessor is either the delegation node or a
01608                          * newly unobscured node, and those nodes are on the
01609                          * "affected" list in any case.
01610                          */
01611                         CHECK(next_active(log, zone, db, newver,
01612                                           &t->name, prevname, ISC_FALSE));
01613                         CHECK(namelist_append_name(&state->affected, prevname));
01614                 }
01615 
01616                 /*
01617                  * Find names potentially affected by delegation changes
01618                  * (obscured by adding an NS or DNAME, or unobscured by
01619                  * removing one).
01620                  */
01621                 for (t = ISC_LIST_HEAD(state->diffnames.tuples);
01622                      t != NULL;
01623                      t = ISC_LIST_NEXT(t, link))
01624                 {
01625                         isc_boolean_t ns_existed, dname_existed;
01626                         isc_boolean_t ns_exists, dname_exists;
01627 
01628                         if (oldver != NULL)
01629                                 CHECK(rrset_exists(db, oldver, &t->name,
01630                                                   dns_rdatatype_ns, 0,
01631                                                   &ns_existed));
01632                         else
01633                                 ns_existed = ISC_FALSE;
01634                         if (oldver != NULL)
01635                                 CHECK(rrset_exists(db, oldver, &t->name,
01636                                                    dns_rdatatype_dname, 0,
01637                                                    &dname_existed));
01638                         else
01639                                 dname_existed = ISC_FALSE;
01640                         CHECK(rrset_exists(db, newver, &t->name,
01641                                            dns_rdatatype_ns, 0, &ns_exists));
01642                         CHECK(rrset_exists(db, newver, &t->name,
01643                                            dns_rdatatype_dname, 0,
01644                                            &dname_exists));
01645                         if ((ns_exists || dname_exists) ==
01646                             (ns_existed || dname_existed))
01647                                 continue;
01648                         /*
01649                          * There was a delegation change.  Mark all subdomains
01650                          * of t->name as potentially needing a NSEC update.
01651                          */
01652                         CHECK(namelist_append_subdomain(db, &t->name,
01653                                                         &state->affected));
01654                 }
01655                 ISC_LIST_APPENDLIST(state->affected.tuples,
01656                                     state->diffnames.tuples, link);
01657                 INSIST(ISC_LIST_EMPTY(state->diffnames.tuples));
01658 
01659                 CHECK(uniqify_name_list(&state->affected));
01660 
01661                 /*FALLTHROUGH*/
01662         case process_nsec:
01663                 state->state = process_nsec;
01664 
01665                 /*
01666                  * Determine which names should have NSECs, and delete/create
01667                  * NSECs to make it so.  We don't know the final NSEC targets
01668                  * yet, so we just create placeholder NSECs with arbitrary
01669                  * contents to indicate that their respective owner names
01670                  * should be part of the NSEC chain.
01671                  */
01672                 while ((t = ISC_LIST_HEAD(state->affected.tuples)) != NULL) {
01673                         isc_boolean_t exists;
01674                         dns_name_t *name = &t->name;
01675 
01676                         CHECK(name_exists(db, newver, name, &exists));
01677                         if (! exists)
01678                                 goto unlink;
01679                         CHECK(is_active(db, newver, name, &flag, &cut, NULL));
01680                         if (!flag) {
01681                                 /*
01682                                  * This name is obscured.  Delete any
01683                                  * existing NSEC record.
01684                                  */
01685                                 CHECK(delete_if(true_p, db, newver, name,
01686                                                 dns_rdatatype_nsec, 0,
01687                                                 NULL, &state->nsec_diff));
01688                                 CHECK(delete_if(rrsig_p, db, newver, name,
01689                                                 dns_rdatatype_any, 0, NULL,
01690                                                 diff));
01691                         } else {
01692                                 /*
01693                                  * This name is not obscured.  It needs to have
01694                                  * a NSEC unless it is the at the origin, in
01695                                  * which case it should already exist if there
01696                                  * is a complete NSEC chain and if there isn't
01697                                  * a complete NSEC chain we don't want to add
01698                                  * one as that would signal that there is a
01699                                  * complete NSEC chain.
01700                                  */
01701                                 if (!dns_name_equal(name, dns_db_origin(db))) {
01702                                         CHECK(rrset_exists(db, newver, name,
01703                                                            dns_rdatatype_nsec,
01704                                                            0, &flag));
01705                                         if (!flag)
01706                                                 CHECK(add_placeholder_nsec(db,
01707                                                           newver, name, diff));
01708                                 }
01709                                 CHECK(add_exposed_sigs(log, zone, db, newver,
01710                                                        name, cut,
01711                                                        &state->sig_diff,
01712                                                        state->zone_keys,
01713                                                        state->nkeys,
01714                                                        state->inception,
01715                                                        state->expire,
01716                                                        state->check_ksk,
01717                                                        state->keyset_kskonly,
01718                                                        &sigs));
01719                         }
01720          unlink:
01721                         ISC_LIST_UNLINK(state->affected.tuples, t, link);
01722                         ISC_LIST_APPEND(state->work.tuples, t, link);
01723                         if (state != &mystate && sigs > maxsigs)
01724                                 return (DNS_R_CONTINUE);
01725                 }
01726                 ISC_LIST_APPENDLIST(state->affected.tuples,
01727                                     state->work.tuples, link);
01728 
01729                 /*
01730                  * Now we know which names are part of the NSEC chain.
01731                  * Make them all point at their correct targets.
01732                  */
01733                 for (t = ISC_LIST_HEAD(state->affected.tuples);
01734                      t != NULL;
01735                      t = ISC_LIST_NEXT(t, link))
01736                 {
01737                         CHECK(rrset_exists(db, newver, &t->name,
01738                                            dns_rdatatype_nsec, 0, &flag));
01739                         if (flag) {
01740                                 /*
01741                                  * There is a NSEC, but we don't know if it
01742                                  * is correct. Delete it and create a correct
01743                                  * one to be sure. If the update was
01744                                  * unnecessary, the diff minimization
01745                                  * will take care of eliminating it from the
01746                                  * journal, IXFRs, etc.
01747                                  *
01748                                  * The RRSIG bit should always be set in the
01749                                  * NSECs we generate, because they will all
01750                                  * get RRSIG NSECs.
01751                                  * (XXX what if the zone keys are missing?).
01752                                  * Because the RRSIG NSECs have not necessarily
01753                                  * been created yet, the correctness of the
01754                                  * bit mask relies on the assumption that NSECs
01755                                  * are only created if there is other data, and
01756                                  * if there is other data, there are other
01757                                  * RRSIGs.
01758                                  */
01759                                 CHECK(add_nsec(log, zone, db, newver, &t->name,
01760                                                state->nsecttl,
01761                                                &state->nsec_diff));
01762                         }
01763                 }
01764 
01765                 /*
01766                  * Minimize the set of NSEC updates so that we don't
01767                  * have to regenerate the RRSIG NSECs for NSECs that were
01768                  * replaced with identical ones.
01769                  */
01770                 while ((t = ISC_LIST_HEAD(state->nsec_diff.tuples)) != NULL) {
01771                         ISC_LIST_UNLINK(state->nsec_diff.tuples, t, link);
01772                         dns_diff_appendminimal(&state->nsec_mindiff, &t);
01773                 }
01774 
01775                 update_log(log, zone, ISC_LOG_DEBUG(3),
01776                            "signing rebuilt NSEC chain");
01777 
01778                 /*FALLTHROUGH*/
01779         case sign_nsec:
01780                 state->state = sign_nsec;
01781                 /* Update RRSIG NSECs. */
01782                 while ((t = ISC_LIST_HEAD(state->nsec_mindiff.tuples)) != NULL)
01783                 {
01784                         if (t->op == DNS_DIFFOP_DEL) {
01785                                 CHECK(delete_if(true_p, db, newver, &t->name,
01786                                                 dns_rdatatype_rrsig,
01787                                                 dns_rdatatype_nsec,
01788                                                 NULL, &state->sig_diff));
01789                         } else if (t->op == DNS_DIFFOP_ADD) {
01790                                 CHECK(add_sigs(log, zone, db, newver, &t->name,
01791                                                dns_rdatatype_nsec,
01792                                                &state->sig_diff,
01793                                                state->zone_keys, state->nkeys,
01794                                                state->inception, state->expire,
01795                                                state->check_ksk,
01796                                                state->keyset_kskonly));
01797                                 sigs++;
01798                         } else {
01799                                 INSIST(0);
01800                         }
01801                         ISC_LIST_UNLINK(state->nsec_mindiff.tuples, t, link);
01802                         ISC_LIST_APPEND(state->work.tuples, t, link);
01803                         if (state != &mystate && sigs > maxsigs)
01804                                 return (DNS_R_CONTINUE);
01805                 }
01806                 ISC_LIST_APPENDLIST(state->nsec_mindiff.tuples,
01807                                     state->work.tuples, link);
01808                 /*FALLTHROUGH*/
01809         case update_nsec3:
01810                 state->state = update_nsec3;
01811 
01812                 /* Record our changes for the journal. */
01813                 while ((t = ISC_LIST_HEAD(state->sig_diff.tuples)) != NULL) {
01814                         ISC_LIST_UNLINK(state->sig_diff.tuples, t, link);
01815                         dns_diff_appendminimal(diff, &t);
01816                 }
01817                 while ((t = ISC_LIST_HEAD(state->nsec_mindiff.tuples)) != NULL)
01818                 {
01819                         ISC_LIST_UNLINK(state->nsec_mindiff.tuples, t, link);
01820                         dns_diff_appendminimal(diff, &t);
01821                 }
01822 
01823                 INSIST(ISC_LIST_EMPTY(state->sig_diff.tuples));
01824                 INSIST(ISC_LIST_EMPTY(state->nsec_diff.tuples));
01825                 INSIST(ISC_LIST_EMPTY(state->nsec_mindiff.tuples));
01826 
01827                 if (!build_nsec3) {
01828                         update_log(log, zone, ISC_LOG_DEBUG(3),
01829                                    "no NSEC3 chains to rebuild");
01830                         goto failure;
01831                 }
01832 
01833                 update_log(log, zone, ISC_LOG_DEBUG(3),
01834                            "rebuilding NSEC3 chains");
01835 
01836                 dns_diff_clear(&state->diffnames);
01837                 dns_diff_clear(&state->affected);
01838 
01839                 CHECK(dns_diff_sort(diff, temp_order));
01840 
01841                 /*
01842                  * Find names potentially affected by delegation changes
01843                  * (obscured by adding an NS or DNAME, or unobscured by
01844                  * removing one).
01845                  */
01846                 t = ISC_LIST_HEAD(diff->tuples);
01847                 while (t != NULL) {
01848                         dns_name_t *name = &t->name;
01849 
01850                         isc_boolean_t ns_existed, dname_existed;
01851                         isc_boolean_t ns_exists, dname_exists;
01852                         isc_boolean_t exists, existed;
01853 
01854                         if (t->rdata.type == dns_rdatatype_nsec ||
01855                             t->rdata.type == dns_rdatatype_rrsig) {
01856                                 t = ISC_LIST_NEXT(t, link);
01857                                 continue;
01858                         }
01859 
01860                         CHECK(namelist_append_name(&state->affected, name));
01861 
01862                         if (oldver != NULL)
01863                                 CHECK(rrset_exists(db, oldver, name,
01864                                                    dns_rdatatype_ns,
01865                                                    0, &ns_existed));
01866                         else
01867                                 ns_existed = ISC_FALSE;
01868                         if (oldver != NULL)
01869                                 CHECK(rrset_exists(db, oldver, name,
01870                                                    dns_rdatatype_dname, 0,
01871                                                    &dname_existed));
01872                         else
01873                                 dname_existed = ISC_FALSE;
01874                         CHECK(rrset_exists(db, newver, name, dns_rdatatype_ns,
01875                                            0, &ns_exists));
01876                         CHECK(rrset_exists(db, newver, name,
01877                                            dns_rdatatype_dname, 0,
01878                                            &dname_exists));
01879 
01880                         exists = ns_exists || dname_exists;
01881                         existed = ns_existed || dname_existed;
01882                         if (exists == existed)
01883                                 goto nextname;
01884                         /*
01885                          * There was a delegation change.  Mark all subdomains
01886                          * of t->name as potentially needing a NSEC3 update.
01887                          */
01888                         CHECK(namelist_append_subdomain(db, name,
01889                                                         &state->affected));
01890 
01891         nextname:
01892                         while (t != NULL && dns_name_equal(&t->name, name))
01893                                 t = ISC_LIST_NEXT(t, link);
01894                 }
01895 
01896                 /*FALLTHROUGH*/
01897         case process_nsec3:
01898                 state->state = process_nsec3;
01899                 while ((t = ISC_LIST_HEAD(state->affected.tuples)) != NULL) {
01900                         dns_name_t *name = &t->name;
01901 
01902                         unsecure = ISC_FALSE;   /* Silence compiler warning. */
01903                         CHECK(is_active(db, newver, name, &flag, &cut,
01904                                         &unsecure));
01905 
01906                         if (!flag) {
01907                                 CHECK(delete_if(rrsig_p, db, newver, name,
01908                                                 dns_rdatatype_any, 0, NULL,
01909                                                 diff));
01910                                 CHECK(dns_nsec3_delnsec3sx(db, newver, name,
01911                                                            privatetype,
01912                                                            &state->nsec_diff));
01913                         } else {
01914                                 CHECK(add_exposed_sigs(log, zone, db, newver,
01915                                                        name, cut,
01916                                                        &state->sig_diff,
01917                                                        state->zone_keys,
01918                                                        state->nkeys,
01919                                                        state->inception,
01920                                                        state->expire,
01921                                                        state->check_ksk,
01922                                                        state->keyset_kskonly,
01923                                                        &sigs));
01924                                 CHECK(dns_nsec3_addnsec3sx(db, newver, name,
01925                                                            state->nsecttl,
01926                                                            unsecure,
01927                                                            privatetype,
01928                                                            &state->nsec_diff));
01929                         }
01930                         ISC_LIST_UNLINK(state->affected.tuples, t, link);
01931                         ISC_LIST_APPEND(state->work.tuples, t, link);
01932                         if (state != &mystate && sigs > maxsigs)
01933                                 return (DNS_R_CONTINUE);
01934                 }
01935                 ISC_LIST_APPENDLIST(state->affected.tuples,
01936                                     state->work.tuples, link);
01937 
01938                 /*
01939                  * Minimize the set of NSEC3 updates so that we don't
01940                  * have to regenerate the RRSIG NSEC3s for NSEC3s that were
01941                  * replaced with identical ones.
01942                  */
01943                 while ((t = ISC_LIST_HEAD(state->nsec_diff.tuples)) != NULL) {
01944                         ISC_LIST_UNLINK(state->nsec_diff.tuples, t, link);
01945                         dns_diff_appendminimal(&state->nsec_mindiff, &t);
01946                 }
01947 
01948                 update_log(log, zone, ISC_LOG_DEBUG(3),
01949                            "signing rebuilt NSEC3 chain");
01950 
01951                 /*FALLTHROUGH*/
01952         case sign_nsec3:
01953                 state->state = sign_nsec3;
01954                 /* Update RRSIG NSEC3s. */
01955                 while ((t = ISC_LIST_HEAD(state->nsec_mindiff.tuples)) != NULL)
01956                 {
01957                         if (t->op == DNS_DIFFOP_DEL) {
01958                                 CHECK(delete_if(true_p, db, newver, &t->name,
01959                                                 dns_rdatatype_rrsig,
01960                                                 dns_rdatatype_nsec3,
01961                                                 NULL, &state->sig_diff));
01962                         } else if (t->op == DNS_DIFFOP_ADD) {
01963                                 CHECK(add_sigs(log, zone, db, newver, &t->name,
01964                                                dns_rdatatype_nsec3,
01965                                                &state->sig_diff,
01966                                                state->zone_keys,
01967                                                state->nkeys, state->inception,
01968                                                state->expire, state->check_ksk,
01969                                                state->keyset_kskonly));
01970                                 sigs++;
01971                         } else {
01972                                 INSIST(0);
01973                         }
01974                         ISC_LIST_UNLINK(state->nsec_mindiff.tuples, t, link);
01975                         ISC_LIST_APPEND(state->work.tuples, t, link);
01976                         if (state != &mystate && sigs > maxsigs)
01977                                 return (DNS_R_CONTINUE);
01978                 }
01979                 ISC_LIST_APPENDLIST(state->nsec_mindiff.tuples,
01980                                     state->work.tuples, link);
01981 
01982                 /* Record our changes for the journal. */
01983                 while ((t = ISC_LIST_HEAD(state->sig_diff.tuples)) != NULL) {
01984                         ISC_LIST_UNLINK(state->sig_diff.tuples, t, link);
01985                         dns_diff_appendminimal(diff, &t);
01986                 }
01987                 while ((t = ISC_LIST_HEAD(state->nsec_mindiff.tuples)) != NULL)
01988                 {
01989                         ISC_LIST_UNLINK(state->nsec_mindiff.tuples, t, link);
01990                         dns_diff_appendminimal(diff, &t);
01991                 }
01992 
01993                 INSIST(ISC_LIST_EMPTY(state->sig_diff.tuples));
01994                 INSIST(ISC_LIST_EMPTY(state->nsec_diff.tuples));
01995                 INSIST(ISC_LIST_EMPTY(state->nsec_mindiff.tuples));
01996                 break;
01997         default:
01998                 INSIST(0);
01999         }
02000 
02001  failure:
02002         dns_diff_clear(&state->sig_diff);
02003         dns_diff_clear(&state->nsec_diff);
02004         dns_diff_clear(&state->nsec_mindiff);
02005 
02006         dns_diff_clear(&state->affected);
02007         dns_diff_clear(&state->diffnames);
02008         dns_diff_clear(&state->work);
02009 
02010         for (i = 0; i < state->nkeys; i++)
02011                 dst_key_free(&state->zone_keys[i]);
02012 
02013         if (state != &mystate && state != NULL) {
02014                 *statep = NULL;
02015                 state->magic = 0;
02016                 isc_mem_put(diff->mctx, state, sizeof(*state));
02017         }
02018 
02019         return (result);
02020 }
02021 
02022 static isc_stdtime_t
02023 epoch_to_yyyymmdd(time_t when) {
02024         struct tm *tm;
02025         tm = localtime(&when);
02026         return (((tm->tm_year + 1900) * 10000) +
02027                 ((tm->tm_mon + 1) * 100) + tm->tm_mday);
02028 }
02029 
02030 isc_uint32_t
02031 dns_update_soaserial(isc_uint32_t serial, dns_updatemethod_t method) {
02032         isc_stdtime_t now;
02033         isc_uint32_t new_serial;
02034 
02035         switch (method) {
02036         case dns_updatemethod_none:
02037                 return (serial);
02038         case dns_updatemethod_unixtime:
02039                 isc_stdtime_get(&now);
02040                 if (now != 0 && isc_serial_gt(now, serial))
02041                         return (now);
02042                 break;
02043         case dns_updatemethod_date:
02044                 isc_stdtime_get(&now);
02045                 new_serial = epoch_to_yyyymmdd((time_t) now) * 100;
02046                 if (new_serial != 0 && isc_serial_gt(new_serial, serial))
02047                         return (new_serial);
02048         case dns_updatemethod_increment:
02049                 break;
02050         }
02051 
02052         /* RFC1982 */
02053         serial = (serial + 1) & 0xFFFFFFFF;
02054         if (serial == 0)
02055                 serial = 1;
02056 
02057         return (serial);
02058 }

Generated on Tue Apr 28 17:41:02 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha