update.c revision 8803b0510877fd08044542edbb55e2be72fae36f
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Copyright (C) 1999 Internet Software Consortium.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Permission to use, copy, modify, and distribute this software for any
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * purpose with or without fee is hereby granted, provided that the above
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * copyright notice and this permission notice appear in all copies.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * This module implements dynamic update as in RFC2136.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson - document strict minimality
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson/**************************************************************************/
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * Convenience macro of common isc_log_write() arguments
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * to use in reportings server errors.
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, \
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * Convenience macro of common isc_log_write() arguments
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * to use in tracing dynamic update protocol requests.
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, \
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * Convenience macro of common isc_log_write() arguments
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * to use in low-level debug tracing.
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE, \
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * Check an operation for failure. These macros all assume that
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * the function using them has a 'result' variable and a 'failure'
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson if (result != DNS_R_SUCCESS) goto failure; \
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * Fail unconditionally with result 'code', which must not
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * be DNS_R_SUCCESS. The reason for failure presumably has
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * been logged already.
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * Fail unconditionally and log as a client error.
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "dynamic update failed: %s (%s)", \
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson * Fail unconditionally and log as a server error.
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "dynamic update error: %s: %s", \
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* dns_name_t name; */
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafssontypedef struct update_event update_event_t;
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson/**************************************************************************/
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson * Forward declarations.
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafssonstatic void update_action(isc_task_t *task, isc_event_t *event);
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafssonstatic void updatedone_action(isc_task_t *task, isc_event_t *event);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Update a single RR in version 'ver' of 'db' and log the
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * update in 'diff'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * '*tuple' == NULL. Either the tuple is freed, or its
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * ownership has been transferred to the diff.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Create a singleton diff */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Apply it to the database. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_diff_apply(&temp_diff, db, ver);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Merge it into the current pending journal entry. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Do not clear temp_diff. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonupdate_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_difftuple_create(diff->mctx, op,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson return (do_one_tuple(&tuple, db, ver, diff));
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Callback-style iteration over rdatasets and rdatas.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * foreach_rrset() can be used to iterate over the RRsets
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * of a name and call a callback function with each
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * one. Similarly, foreach_rr() can be used to iterate
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * over the individual RRs at name, optionally restricted
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * to RRs of a given type.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * The callback functions are called "actions" and take
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * two arguments: a void pointer for passing arbitrary
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * context information, and a pointer to the current RRset
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * or RR. By convention, their names end in "_action".
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * XXXRTH We might want to make this public somewhere in libdns.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Function type for foreach_rrset() iterator actions. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontypedef dns_result_t rrset_func(void *data, dns_rdataset_t *rrset);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Function type for foreach_rr() iterator actions. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontypedef dns_result_t rr_func(void *data, rr_t *rr);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Internal context struct for foreach_node_rr(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontypedef struct {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Internal helper function for foreach_node_rr(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonforeach_node_rr_action(void *data, dns_rdataset_t *rdataset)
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson for (result = dns_rdataset_first(rdataset);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_rdataset_current(rdataset, &rr.rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * For each rdataset of 'name' in 'ver' of 'db', call 'action'
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * with the rdataset and 'action_data' as arguments. If the name
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * does not exist, do nothing.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * If 'action' returns an error, abort iteration and return the error.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_db_findnode(db, name, ISC_FALSE, &node);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_db_allrdatasets(db, node, ver,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson for (result = dns_rdatasetiter_first(iter);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_rdatasetiter_current(iter, &rdataset);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = (*action)(action_data, &rdataset);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * For each RR of 'name' in 'ver' of 'db', call 'action'
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * with the RR and 'action_data' as arguments. If the name
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * does not exist, do nothing.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * If 'action' returns an error, abort iteration
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * and return the error.
732e0731dec1922747bb3b3147cf2c3d16b22eaaBob Halley * For each of the RRs specified by 'db', 'ver', 'name', 'type',
732e0731dec1922747bb3b3147cf2c3d16b22eaaBob Halley * (which can be dns_rdatatype_any to match any type), and 'covers', call
732e0731dec1922747bb3b3147cf2c3d16b22eaaBob Halley * 'action' with the RR and 'action_data' as arguments. If the name
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * does not exist, or if no RRset of the given type exists at the name,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * If 'action' returns an error, abort iteration and return the error.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_db_findnode(db, name, ISC_FALSE, &node);
732e0731dec1922747bb3b3147cf2c3d16b22eaaBob Halley result = dns_db_findrdataset(db, node, ver, type, covers,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson for (result = dns_rdataset_first(&rdataset);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_rdataset_current(&rdataset, &rr.rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = (*rr_action)(rr_action_data, &rr);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Various tests on the database contents (for prerequisites, etc).
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Function type for predicate functions that compare a database RR 'db_rr'
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * against an update RR 'update_rr'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontypedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Helper function for rrset_exists(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonrrset_exists_action(void *data, rr_t *rr) /*ARGSUSED*/
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * Utility macro for RR existence checking functions.
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * If the variable 'result' has the value DNS_R_EXISTS or
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * DNS_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * respectively, and return success.
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * If 'result' has any other value, there was a failure.
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * Return the failure result code and do not set *exists.
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * This would be more readable as "do { if ... } while(0)",
f4c0131a46ea183238027ef9c3400cc6079b8b85Andreas Gustafsson * but that form generates tons of warnings on Solaris 2.6.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Set '*exists' to true iff an rrset of the given type exists,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * to false otherwise.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonrrset_exists(dns_db_t *db, dns_dbversion_t *ver,
732e0731dec1922747bb3b3147cf2c3d16b22eaaBob Halley dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Helper function for cname_incompatible_rrset_exists */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssoncname_compatibility_action(void *data, dns_rdataset_t *rrset)
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if (rrset->type != dns_rdatatype_cname &&
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Check whether there is an rrset incompatible with adding a CNAME RR,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * i.e., anything but another CNAME (which can be replaced) or a
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * DNSSEC RR (which can coexist).
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * If such an incompatible rrset exists, set '*exists' to ISC_TRUE.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Otherwise, set it to ISC_FALSE.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssoncname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_name_t *name, isc_boolean_t *exists) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Helper function for rr_count(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssoncount_rr_action(void *data, rr_t *rr) /*ARGSUSED*/ {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonrr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
732e0731dec1922747bb3b3147cf2c3d16b22eaaBob Halley dns_rdatatype_t type, dns_rdatatype_t covers, int *countp)
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Context struct for matching_rr_exists(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontypedef struct {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Helper function for matching_rr_exists(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonmatching_rr_exists_action(void *data, rr_t *rr) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if ((*ctx->predicate)(ctx->update_rr, &rr->rdata))
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Compare the 'update_rr' with all RRs in the RRset specified by 'db',
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * 'ver', 'name', and 'type' using 'predicate'. If the predicate returns
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * true for at least one of them, set '*exists' to ISC_TRUE. Otherwise,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * set it to ISC_FALSE.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonmatching_rr_exists(rr_predicate *predicate,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Context struct and helper function for name_exists() */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonname_exists_action(void *data, dns_rdataset_t *rrset) /*ARGSUSED*/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Set '*exists' to true iff the given name exists, to false otherwise.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonname_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Checking of "RRset exists (value dependent)" prerequisites.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * In the RFC2136 section 3.2.5, this is the pseudocode involving
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * a variable called "temp", a mapping of <name, type> tuples to rrsets.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Here, we represent the "temp" data structure as (non-minimial) "dns_diff_t"
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * where each typle has op==DNS_DIFFOP_EXISTS.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Append a tuple asserting the existence of the RR with
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * 'name' and 'rdata' to 'diff'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontemp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata)
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson ISC_LIST_APPEND(diff->tuples, tuple, link);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Compare two rdatasets represented as sorted lists of tuples.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * All list elements must have the same owner name and type.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Return DNS_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset)
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontemp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson INSIST(a->op == DNS_DIFFOP_EXISTS && b->op == DNS_DIFFOP_EXISTS);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson INSIST(dns_name_equal(&a->name, &b->name));
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if (dns_rdata_compare(&a->rdata, &b->rdata) != 0)
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * A comparison function defining the sorting order for the entries
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * in the "temp" data structure. The major sort key is the owner name,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * followed by the type and rdata.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontemp_order(const void *av, const void *bv)
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson r = dns_name_compare(&a->name, &b->name);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson r = dns_rdata_compare(&a->rdata, &b->rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Check the "RRset exists (value dependent)" prerequisite information
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * in 'temp' against the contents of the database 'db'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Return DNS_R_SUCCESS if the prerequisites are satisfied,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * rcode(dns_rcode_nxrrset) if not.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontemp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Exit early if the list is empty (for efficiency only). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Sort the prerequisite records by owner name,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * type, and rdata.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_diff_sort(temp, temp_order);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * For each name and type in the prerequisites,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * construct a sorted rdata list of the corresponding
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * database contents, and compare the lists.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson while (t != NULL) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* A new unique name begins here. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_db_findnode(db, name, ISC_FALSE, &node);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* A new unique type begins here. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson while (t != NULL && dns_name_equal(&t->name, name)) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson this name and type */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson this name and type */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Collect all database RRs for this name and type
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * onto d_rrs and sort them.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_db_findrdataset(db, node, ver, type,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson for (result = dns_rdataset_first(&rdataset);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = temp_append(&d_rrs, name, &rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_diff_sort(&d_rrs, temp_order);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Collect all update RRs for this name and type
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * onto u_rrs. No need to sort them here -
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * they are already sorted.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson while (t != NULL &&
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Compare the two sorted lists. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples),
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * We are done with the tuples, but we can't free
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * them yet because "name" still points into one
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * of them. Move them on a temporary list.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Conditional deletion of RRs.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Context structure for delete_if(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontypedef struct {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Predicate functions for delete_if(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Return true iff 'update_rr' is neither a SOA nor an NS RR. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontype_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) /*ARGSUSED*/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson return ((db_rr->type != dns_rdatatype_soa &&
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Return true always. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssontrue_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) /*ARGSUSED*/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Return true iff the two RRs have identical rdata. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonrr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * XXXRTH This is not a problem, but we should consider creating
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * dns_rdata_equal() (that used dns_name_equal()), since it
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * would be faster. Not a priority.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson return (dns_rdata_compare(update_rr, db_rr) == 0 ?
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Return true iff 'update_rr' should replace 'db_rr' according
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * to the special RFC2136 rules for CNAME, SOA, and WKS records.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonreplaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * RFC2136 does not mention NXT, but multiple NXTs make little
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * sense, so we replace those, too.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Compare the address and protocol fields only. These
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * form the first five bytes of the RR data. Do a
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * raw binary comparison; unpacking the WKS RRs using
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * dns_rdata_tostruct() might be cleaner in some ways,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * but it would require us to pass around an mctx.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson INSIST(db_rr->length >= 5 && update_rr->length >= 5);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson return (memcmp(db_rr->data, update_rr->data, 5) == 0 ?
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/* Internal helper function for delete_if(). */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Conditionally delete RRs. Apply 'predicate' to the RRs
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * specified by 'db', 'ver', 'name', and 'type' (which can
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * be dns_rdatatype_any to match any type). Delete those
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * RRs for which the predicate returns true, and log the
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * deletions in 'diff'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Miscellaneous subroutines.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Extract a single update RR from 'section' of dynamic update message
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * 'msg', with consistency checking.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Stores the owner name, rdata, and TTL of the update RR at 'name',
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * 'rdata', and 'ttl', respectively.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonget_current_rr(dns_message_t *msg, dns_section_t section,
732e0731dec1922747bb3b3147cf2c3d16b22eaaBob Halley dns_name_t **name, dns_rdata_t *rdata, dns_rdatatype_t *covers,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_message_currentname(msg, section, name);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson INSIST(dns_rdataset_next(rdataset) == DNS_R_NOMORE);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Increment the SOA serial number of database 'db', version 'ver'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Replace the SOA record in the database, and log the
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * change in 'diff'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * XXXRTH Failures in this routine will be worth logging, when
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * we have a logging system. Failure to find the zonename
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * or the SOA rdataset warrant at least an UNEXPECTED_ERROR().
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssonincrement_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(dns_difftuple_copy(deltuple, &addtuple));
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson serial = dns_soa_getserial(&addtuple->rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_soa_setserial(serial, &addtuple->rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(do_one_tuple(&addtuple, db, ver, diff));
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(do_one_tuple(&deltuple, db, ver, diff));
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Check that the new SOA record at 'update_rdata' does not
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * illegally cause the SOA serial number to decrease or stay
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * unchanged relative to the existing SOA in 'db'.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Sets '*ok' to ISC_TRUE if the update is legal, ISC_FALSE if not.
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * William King points out that RFC2136 is inconsistent about
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * the case where the serial number stays unchanged:
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * section 3.4.2.2 requires a server to ignore a SOA update request
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * if the serial number on the update SOA is less_than_or_equal to
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * the zone SOA serial.
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * section 3.6 requires a server to ignore a SOA update request if
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * the serial is less_than the zone SOA serial.
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson * Paul says 3.4.2.2 is correct.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafssoncheck_soa_increment(dns_db_t *db, dns_dbversion_t *ver,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson update_serial = dns_soa_getserial(update_rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_db_getsoaserial(db, ver, &db_serial);
c6e66777242752532a094561fc728233cab9bc2fAndreas Gustafsson if (DNS_SERIAL_GE(db_serial, update_serial)) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson/**************************************************************************/
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Incremental updating of NXTs and SIGs.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson#define MAXZONEKEYS 32 /* Maximum number of zone keys supported. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * We abuse the dns_diff_t type to represent a set of domain names
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * affected by the update.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonnamelist_append_name(dns_diff_t *list, dns_name_t *name) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson static dns_rdata_t dummy_rdata = { NULL, 0, 0, 0, { NULL, NULL } };
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonnamelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson for (result = dns_dbiterator_seek(dbit, name);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson result = dns_dbiterator_current(dbit, &node, child);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(namelist_append_name(affected, child));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson/* Helper function for non_nxt_rrset_exists(). */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonis_non_nxt_action(void *data, dns_rdataset_t *rrset)
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson if (!(rrset->type == dns_rdatatype_nxt ||
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Check whether there is an rrset other than a NXT or SIG NXT,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * i.e., anything that justifies the continued existence of a name
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * after a secure update.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * If such an rrset exists, set '*exists' to ISC_TRUE.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Otherwise, set it to ISC_FALSE.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonnon_nxt_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_name_t *name, isc_boolean_t *exists) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * A comparison function for sorting dns_diff_t:s by name.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonname_order(const void *av, const void *bv)
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson return (dns_name_compare(&a->name, &b->name));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson while (p != NULL) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson if (q == NULL || ! dns_name_equal(&p->name, &q->name))
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonis_glue(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson result = dns_db_find(db, name, ver, dns_rdatatype_any,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* XXX should omit non-delegation types from NXT */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Find the next/previous name that has a NXT record.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * In other words, skip empty database nodes and names that
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * have had their NXTs removed because they are obscured by
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonnext_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *oldname,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_name_t *newname, isc_boolean_t forward)
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_dbiterator_seek(dbit, oldname));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Wrap around. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_dbiterator_current(dbit, &node, newname);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * The iterator may hold the tree lock, and
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson * rrset_exists() calls dns_db_findnode() which
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * may try to reacquire it. To avoid deadlock
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * we must pause the iterator first.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Add a NXT record for "name", recording the change in "diff".
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonadd_nxt(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_diff_t *diff) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson unsigned char buffer[DNS_NXT_BUFFERSIZE];
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Find the successor name, aka NXT target. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(next_active(db, ver, name, target, ISC_TRUE));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Create the NXT RDATA. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_buildnxtrdata(db, ver, node, target, buffer, &rdata));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Create a diff tuple, update the database, and record the change. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(do_one_tuple(&tuple, db, ver, diff));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Add a placeholder NXT record for "name", recording the change in "diff".
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonadd_placeholder_nxt(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_diff_t *diff) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson unsigned char data[1] = { 0 }; /* The root domain, no bits. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nxt, &r);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(do_one_tuple(&tuple, db, ver, diff));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonfind_zone_keys(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson unsigned int maxkeys, dst_key_t **keys, unsigned int *nkeys)
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_dnssec_findzonekeys(db, ver, node, dns_db_origin(db),
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Add SIG records for an RRset, recording the change in "diff".
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonadd_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_rdatatype_t type, dns_diff_t *diff, dst_key_t **keys,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson unsigned int nkeys, isc_mem_t *mctx, isc_stdtime_t now,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson unsigned int i;
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson isc_buffer_init(&buffer, data, sizeof data, ISC_BUFFERTYPE_BINARY);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Get the rdataset to sign. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_db_findrdataset(db, node, ver, type, 0,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson for (i = 0; i < nkeys; i++) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Calculate the signature, creating a SIG RDATA. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Update the database and journal with the SIG. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* XXX inefficient - will cause dataset merging */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson if (dns_rdataset_isassociated(&rdataset))
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Update SIG and NXT records affected by an update. The original
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * update, including the SOA serial update but exluding the SIG & NXT
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * changes, is in "diff" and has already been applied to "newver" of "db".
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * The database version prior to the update is "oldver".
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * The necessary SIG and NXT changes will be applied to "newver"
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * and added (as a minimal diff) to "diff".
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafssonupdate_signatures(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *oldver,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_dbversion_t *newver, dns_diff_t *diff)
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson unsigned int nkeys = 0;
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson unsigned int i;
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson result = find_zone_keys(db, newver, mctx,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "could not get zone keys for secure "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "dynamic update");
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Find all RRsets directly affected by the update, and
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * update their SIGs. Also build a list of names affected
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * by the update in "diffnames".
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson while (t != NULL) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Now "name" is a new, unique name affected by the update. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(namelist_append_name(&diffnames, name));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson while (t != NULL && dns_name_equal(&t->name, name)) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Now "name" and "type" denote a new unique RRset
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * affected by the update.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Don't sign SIGs. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Delete all old SIGs covering this type, since they
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * are all invalid when the signed RRset has changed.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * We may not be able to recreate all of them - tough.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(delete_if(true_p, db, newver, name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * If this RRset still exists after the update,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * add a new signature for it.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(rrset_exists(db, newver, name, type, 0, &flag));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Skip any other updates to the same RRset. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson while (t != NULL &&
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Remove orphaned NXTs and SIG NXTs. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson for (t = ISC_LIST_HEAD(diffnames.tuples);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(non_nxt_rrset_exists(db, newver, &t->name, &flag));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(delete_if(true_p, db, newver, &t->name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * When a name is created or deleted, its predecessor needs to
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * have its NXT updated.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson for (t = ISC_LIST_HEAD(diffnames.tuples);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson prevname = dns_fixedname_name(&fixedname);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(name_exists(db, oldver, &t->name, &existed));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(name_exists(db, newver, &t->name, &exists));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Find the predecessor.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * When names become obscured or unobscured in this update
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * transaction, we may find the wrong predecessor because
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * the NXTs have not yet been updated to reflect the delegation
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * change. This should not matter because in this case,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * the correct predecessor is either the delegation node or
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * a newly unobscured node, and those nodes are on the
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * "affected" list in any case.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(next_active(db, newver, &t->name, prevname, ISC_FALSE));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(namelist_append_name(&affected, prevname));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Find names affected by delegation changes. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson for (t = ISC_LIST_HEAD(diffnames.tuples);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(rrset_exists(db, oldver, &t->name, dns_rdatatype_ns, 0,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * There was a delegation change. Mark all subdomains
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * of t->name as potentially needing a NXT update.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(namelist_append_subdomain(db, &t->name, &affected));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson INSIST(ISC_LIST_EMPTY(diffnames.tuples));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Determine which names should have NXTs, and delete/create
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * NXTs to make it so. We don't know the final NXT targets yet,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * so we just create placeholder NXTs with arbitrary contents
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * to indicate that their respective owner names should be part of
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * the NXT chain.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(name_exists(db, newver, &t->name, &exists));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(is_glue(db, newver, &t->name, &flag));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * This name is obscured. Delete any
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * existing NXT record.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(delete_if(true_p, db, newver, &t->name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* This name is not obscured. It should have a NXT. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson add_placeholder_nxt(db, newver, &t->name, diff);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Now we know which names are part of the NXT chain.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Make them all point at their correct targets.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * There is a NXT, but we don't know if it is correct.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Delete it and create a correct one to be sure.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * If the update was unnecessary, the diff minimization
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * will take care of eliminating it from the journal,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * The SIG bit should always be set in the NXTs
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * we generate, because they will all get SIG NXTs.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * (XXX what if the zone keys are missing?).
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Because the SIG NXTs have not necessarily been
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * created yet, the correctness of the bit mask relies
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * on the assumption that NXTs are only created if
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * there is other data, and if there is other data,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * there are other SIGs.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(delete_if(true_p, db, newver, &t->name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(add_nxt(db, newver, &t->name, &nxt_diff));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Minimize the set of NXT updates so that we don't
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * have to regenerate the SIG NXTs for NXTs that were
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * replaced with identical ones.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson while ((t = ISC_LIST_HEAD(nxt_diff.tuples)) != NULL) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson ISC_LIST_UNLINK(nxt_diff.tuples, t, link);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_diff_appendminimal(&nxt_mindiff, &t);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Update SIG NXTs. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson for (t = ISC_LIST_HEAD(nxt_mindiff.tuples);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(delete_if(true_p, db, newver, &t->name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson CHECK(add_sigs(db, newver, &t->name, dns_rdatatype_nxt,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson /* Record our changes for the journal. */
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson ISC_LIST_UNLINK(sig_diff.tuples, t, link);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson while ((t = ISC_LIST_HEAD(nxt_mindiff.tuples)) != NULL) {
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson ISC_LIST_UNLINK(nxt_mindiff.tuples, t, link);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson INSIST(ISC_LIST_EMPTY(nxt_mindiff.tuples));
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson for (i = 0; i < nkeys; i++)
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson/**************************************************************************/
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * The actual update code in all its glory. We try to follow
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * the RFC2136 pseudocode as closely as possible.
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafssonsend_update_event(ns_client_t *client, dns_zone_t *zone) {
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
999ae80184e3df1016ac74514124b0459ace4d01Andreas Gustafsson isc_task_send(zonetask, (isc_event_t **) &event);
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafssonrespond(ns_client_t *client, dns_result_t result) {
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson msg_result = dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson response->rcode = (result == DNS_R_SUCCESS ?
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson dns_rcode_noerror : dns_result_torcode(result));
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson response->flags = client->message->flags;
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "could not create update response message: %s",
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson dns_message_t *request = client->message;
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Interpret the zone section.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_message_firstname(request, DNS_SECTION_ZONE);
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "update zone section empty");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * The zone section must contain exactly one "question", and
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * it must be of type SOA.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_message_currentname(request, DNS_SECTION_ZONE, &zonename);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson zone_rdataset = ISC_LIST_HEAD(zonename->list);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if (zone_rdataset->type != dns_rdatatype_soa)
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "update zone section contains non-SOA");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if (ISC_LIST_NEXT(zone_rdataset, link) != NULL)
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "update zone section contains multiple RRs");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* The zone section must have exactly one name. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_message_nextname(request, DNS_SECTION_ZONE);
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "update zone section contains multiple RRs");
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson result = dns_zt_find(client->view->zonetable, zonename, NULL, &zone);
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "not authoritative for update zone");
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson break; /* OK. */
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "update forwarding"); /* XXX implement */
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "not authoritative for update zone");
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson * We failed without having sent an update event to the zone.
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson * We are still in the client task context, so we can
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson * simply give an error response without switching tasks.
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafssonupdate_action(isc_task_t *task, isc_event_t *event)
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson update_event_t *uev = (update_event_t *) event;
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson ns_client_t *client = (ns_client_t *) event->arg;
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson dns_diff_t temp; /* Pending RR existence assertions. */
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson isc_boolean_t soa_serial_changed = ISC_FALSE;
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson dns_message_t *request = client->message;
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Check prerequisites. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson FAILC(DNS_R_FORMERR, "prerequisite TTL is not zero");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if (! dns_name_issubdomain(name, zonename))
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "prerequisite name is out of zone");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if (update_class == dns_rdataclass_any) {
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "class ANY prerequisite "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "RDATA is not empty");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(name_exists(db, ver, name, &flag));
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "'name in use' prerequisite "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "not satisfied");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* RRset does not exist. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson "'rrset exists (value independent)' "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "prerequisite not satisfied");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson } else if (update_class == dns_rdataclass_none) {
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "class NONE prerequisite"
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "RDATA is not empty");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(name_exists(db, ver, name, &flag));
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "'name not in use' prerequisite "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "not satisfied");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* RRset exists. */
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "'rrset does not exist' "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "prerequisite not satisfied");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* "temp<rr.name, rr.type> += rr;" */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = temp_append(&temp, name, &rdata);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson "temp entry creation failed: %s",
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson FAILC(DNS_R_FORMERR, "malformed prerequisite");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Perform the final check of the "rrset exists (value dependent)"
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * prerequisites.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = temp_check(mctx, &temp, db, ver);
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson FAILC(result, "'RRset exists (value dependent)' "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "prerequisite not satisfied");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(UPDATE_DEBUG_LOGARGS, "prerequisites are OK");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* XXX Check Requestor's Permissions Here */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Perform the Update Section Prescan. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_message_nextname(request, DNS_SECTION_UPDATE))
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson if (! dns_name_issubdomain(name, zonename))
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "update RR is outside zone");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Check for meta-RRs. The RFC2136 pseudocode says
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * check for ANY|AXFR|MAILA|MAILB, but the text adds
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * "or any other QUERY metatype"
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "meta-RR in update");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson } else if (update_class == dns_rdataclass_any) {
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "meta-RR in update");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson } else if (update_class == dns_rdataclass_none) {
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "meta-RR in update");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "update RR has incorrect class %d",
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * draft-ietf-dnsind-simple-secure-update-01 says
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * "Unlike traditional dynamic update, the client
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * is forbidden from updating NXT records."
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson if (dns_db_issecure(db) && rdata.type == dns_rdatatype_nxt) {
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "explicit NXT updates are not allowed "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "in secure zones");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(UPDATE_DEBUG_LOGARGS, "update section prescan OK");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson /* Process the Update Section. */
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_message_nextname(request, DNS_SECTION_UPDATE))
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(cname_incompatible_rrset_exists(db, ver,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "attempt to add CNAME "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "alongside non-CNAME "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "attempt to add non-CNAME "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "alongside CNAME ignored");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "attempt to create 2nd "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "SOA ignored");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(check_soa_increment(db, ver, &rdata,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "SOA update failed to "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "increment serial, "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "ignoring it");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * Add an RR. If an identical RR already exists,
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * do nothing. If a similar but not identical
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * CNAME, SOA, or WKS exists, remove it first.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(matching_rr_exists(rr_equal_p, db, ver, name,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "adding an RR");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(delete_if(replaces_p, db, ver, name,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "attempt to add existing RR "
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson } else if (update_class == dns_rdataclass_any) {
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "delete all rrsets from a name");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson } else if (dns_name_equal(name, zonename) &&
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "attempt to delete all SOA "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "or NS records ignored");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "deleting an rrset");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson } else if (update_class == dns_rdataclass_none) {
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "attempt to delete SOA ignored");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "attempt to delete last "
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "NS ignored");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "deleting an RR");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(delete_if(rr_equal_p, db, ver, name,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * If any changes were made, increment the SOA serial number,
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * update SIGs and NXTs (if zone is secure), and write the update
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * to the journal.
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * Increment the SOA serial, but only if it was not
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson * changed as a result of an update operation.
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson CHECK(increment_soa_serial(db, ver, &diff, mctx));
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE,
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "SIG/NXT update failed: %s",
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(UPDATE_DEBUG_LOGARGS, "writing journal");
999ae80184e3df1016ac74514124b0459ace4d01Andreas Gustafsson result = dns_journal_open(mctx, dns_zone_getixfrlog(zone),
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson result = dns_journal_write_transaction(journal, &diff);
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * XXXRTH Just a note that this committing code will have to change
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * to handle databases that need two-phase commit, but this
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson * isn't a priority.
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson isc_log_write(UPDATE_DEBUG_LOGARGS, "committing update transaction");
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson /* The reason for failure should have been logged at this point. */
8803b0510877fd08044542edbb55e2be72fae36fAndreas Gustafsson "rolling back");
4cd3d6df39927315e3fadc07a8da3788175f4195Andreas Gustafsson dns_db_closeversion(db, &ver, ISC_FALSE);
b2c71d98dfc4dab5c6b8c8f39cf8fed3d899e94cAndreas Gustafsson dns_db_closeversion(db, &oldver, ISC_FALSE);
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafssonupdatedone_action(isc_task_t *task, isc_event_t *event)
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson update_event_t *uev = (update_event_t *) event;
581db30788a4920ba8558287a0dccf3c1a210c5aAndreas Gustafsson ns_client_t *client = (ns_client_t *) event->arg;