diff --git a/src/knot/dnssec/nsec-chain.c b/src/knot/dnssec/nsec-chain.c index 495007d3dc63323f1307fa939ed575bedeb9aebc..9b0429c323b6fc243cefebef36e1cc84adcf18ed 100644 --- a/src/knot/dnssec/nsec-chain.c +++ b/src/knot/dnssec/nsec-chain.c @@ -23,110 +23,6 @@ #include "knot/dnssec/zone-sign.h" #include "knot/dnssec/zone-nsec.h" -/* - Forward declarations --------------------------------------------------- */ - -static knot_rrset_t *create_nsec_rrset(const knot_node_t *, - const knot_node_t *, - uint32_t); - -/* - Helper functions ------------------------------------------------------- */ - -/*! - * \brief Returns true if NSEC is only RRSet in node. - */ -static bool only_nsec_in_node(const knot_node_t *n) -{ - assert(n); - return n->rrset_count <= 2 && (knot_node_rrset(n, KNOT_RRTYPE_NSEC) - && knot_node_rrset(n, KNOT_RRTYPE_RRSIG)); -} - -/*! - * \brief Updates last used node and DNAME. - * - * \param data Data to be updated. - * \param d DNAME to be set. - * \param n Node to be set. - */ -static void update_last_used(chain_fix_data_t *data, const knot_dname_t *d, - const knot_node_t *n) -{ - assert(data && d); - data->last_used_dname = d; - data->last_used_node = n; -} - -/*! - * \brief Checks whether NSEC in zone is valid and updates it if needed. - * - * \param from Start node for NSEC link. - * \param to End node for NSEC link. - * \param out_ch Changes are stored here. - * \param soa_min TTL to use for NSEC RRs. - * - * \return KNOT_E* - */ -static int update_nsec(const knot_node_t *from, const knot_node_t *to, - knot_changeset_t *out_ch, uint32_t soa_min) -{ - assert(from && to && out_ch); - const knot_rrset_t *nsec_rrset = knot_node_rrset(from, - KNOT_RRTYPE_NSEC); - // Create new NSEC - knot_rrset_t *new_nsec; - if (only_nsec_in_node(from)) { - // Just NSEC present, it has to be dropped - new_nsec = NULL; - } else { - new_nsec = create_nsec_rrset(from, to, soa_min); - if (new_nsec == NULL) { - return KNOT_ERROR; - } - } - - // If node in zone has NSEC record, drop it if needed - if (nsec_rrset && new_nsec) { - if (!knot_rrset_equal(new_nsec, nsec_rrset, - KNOT_RRSET_COMPARE_WHOLE)) { - dbg_dnssec_detail("Creating new NSEC for %s\n", - knot_dname_to_str(new_nsec->owner)); - // Drop old - int ret = knot_nsec_changeset_remove(from, out_ch); - if (ret != KNOT_EOK) { - knot_rrset_deep_free(&new_nsec, 1, NULL); - return ret; - } - // Add new - ret = knot_changeset_add_rrset(out_ch, new_nsec, - KNOT_CHANGESET_ADD); - if (ret != KNOT_EOK) { - knot_rrset_deep_free(&new_nsec, 1, NULL); - return ret; - } - } else { - // All good, no need to update - knot_rrset_deep_free(&new_nsec, 1, NULL); - return KNOT_EOK; - } - } else if (new_nsec) { - // Add new NSEC record - int ret = knot_changeset_add_rrset(out_ch, new_nsec, - KNOT_CHANGESET_ADD); - if (ret != KNOT_EOK) { - knot_rrset_deep_free(&new_nsec, 1, NULL); - return ret; - } - } else { - // Drop old, no longer needed - int ret = knot_nsec_changeset_remove(from, out_ch); - if (ret != KNOT_EOK) { - knot_rrset_deep_free(&new_nsec, 1, NULL); - return ret; - } - } - return KNOT_EOK; -} - /* - NSEC chain construction ------------------------------------------------ */ /*! @@ -253,245 +149,6 @@ static int connect_nsec_nodes(knot_node_t *a, knot_node_t *b, KNOT_CHANGESET_ADD); } -/* - NSEC chain fix --------------------------------------------------------- */ - -/*! - * \brief Handles node that has been deleted by DDNS/reload. - * - * \param node Deleted node - * \param fix_data Chain fix data. - * - * \return KNOT_E*, NSEC_NODE_SKIP - */ -static int handle_deleted_node(const knot_node_t *node, - chain_fix_data_t *fix_data) -{ - if (node == NULL) { - // This node was deleted and used to be non-auth - assert(knot_node_is_non_auth(node)); - return NSEC_NODE_SKIP; - } - - int ret = knot_nsec_changeset_remove(node, fix_data->out_ch); - if (ret != KNOT_EOK) { - return ret; - } - - /*! - * This node should be ignored, but we might need the next dname from - * previous node. - */ - if (fix_data->next_dname == NULL) { - const knot_rrset_t *old_nsec = - knot_node_rrset(node, KNOT_RRTYPE_NSEC); - assert(old_nsec); - fix_data->next_dname = - (knot_dname_t *)knot_rdata_nsec_next(old_nsec); - assert(fix_data->next_dname); - } - - return NSEC_NODE_SKIP; -} - -/*! - * \brief Fixes 'gaps' between old and new NSEC chain. - * - * \param fix_data Chain fix data. - * \param a Dname that should be connected to old chain. - * \param a_node Node that should be connected to old chain. - * - * \return KNOT_E*, or NSEC_NODE_RESET if needed. - */ -static int handle_nsec_next_dname(chain_fix_data_t *fix_data, - const knot_dname_t *a, - const knot_node_t *a_node) -{ - assert(fix_data && fix_data->next_dname && a && a_node); - int ret = KNOT_EOK; - if (knot_dname_is_equal(fix_data->next_dname, a)) { - // We cannot point to the same record here, extract next->next - const knot_rrset_t *nsec_rrset = - knot_node_rrset(a_node, KNOT_RRTYPE_NSEC); - assert(nsec_rrset); - const knot_node_t *next_node = - knot_zone_contents_find_node(fix_data->zone, - knot_rdata_nsec_next(nsec_rrset)); - assert(next_node); - update_last_used(fix_data, next_node->owner, next_node); - ret = update_nsec(a_node, next_node, fix_data->out_ch, - fix_data->ttl); - } else { - // We have no immediate previous node, connect broken chain - const knot_node_t *next_node = - knot_zone_contents_find_node(fix_data->zone, - fix_data->next_dname); - assert(next_node); - update_last_used(fix_data, next_node->owner, next_node); - ret = update_nsec(a_node, next_node, fix_data->out_ch, - fix_data->ttl); - } - fix_data->next_dname = NULL; - return ret == KNOT_EOK ? NSEC_NODE_RESET : ret; -} - -/*! - * \brief Finds previous usable NSEC node in zone. - * - * \param z Zone to be searched. - * \param d DNAME to search for. - * - * \return Previous NSEC node for 'd'. - */ -static const knot_node_t *find_prev_nsec_node(const knot_zone_contents_t *z, - const knot_dname_t *d) -{ - // Find previous node for the dname, return node that will be used later - const knot_node_t *prev_zone_node = knot_zone_contents_find_previous(z, - d); - bool nsec_node_found = !knot_node_is_non_auth(prev_zone_node) && - !only_nsec_in_node(prev_zone_node); - while (!nsec_node_found) { - // Get previous node from zone tree - prev_zone_node = - knot_zone_contents_find_previous(z, - prev_zone_node->owner); - assert(prev_zone_node); - // Infinite loop check - if (knot_dname_is_equal(d, prev_zone_node->owner)) { - return prev_zone_node; - } - nsec_node_found = !knot_node_is_non_auth(prev_zone_node) && - !only_nsec_in_node(prev_zone_node); - } - assert(nsec_node_found); - return prev_zone_node; -} - -/*! - * \brief Fixes NSEC chain for 'a' and 'b'. 'a' is always < 'b'. - * - * \param a First DNAME from changeset. - * \param b Second DNAME from changeset. - * \param fix_data Chain fix data. - * - * \return KNOT_E*, NSEC_NODE_SKIP, NSEC_NODE_RESET if needed. - */ -static int fix_nsec_chain(knot_dname_t *a, knot_dname_t *b, - chain_fix_data_t *fix_data) -{ - assert(b); - assert(fix_data); - // Get changed nodes from zone - const knot_node_t *b_node = knot_zone_contents_find_node(fix_data->zone, - b); - assert(b_node); - if (knot_node_is_non_auth(b_node)) { - // Nothing to fix in this node - return NSEC_NODE_SKIP; - } - const knot_node_t *a_node = knot_zone_contents_find_node(fix_data->zone, - a); - // Find previous node in zone - const knot_node_t *prev_zone_node = find_prev_nsec_node(fix_data->zone, - b); - if (prev_zone_node == NULL) { - return KNOT_ERROR; - } - - // Handle removals - bool node_deleted = only_nsec_in_node(b_node); - if (node_deleted) { - /*! - * If DDNS only contains removals, we need at least - * one 'last_used_dname'. - */ - if (fix_data->last_used_dname == NULL) { - assert(fix_data->last_used_node == NULL); - update_last_used(fix_data, prev_zone_node->owner, - prev_zone_node); - } - return handle_deleted_node(b_node, fix_data); - } - - // Find out whether the previous node is also part of the changeset. - bool dname_equal = - a && knot_dname_is_equal(prev_zone_node->owner, a); - if (dname_equal) { - // No valid data for the previous node, create the forward link - update_last_used(fix_data, b_node->owner, b_node); - return update_nsec(a_node, b_node, fix_data->out_ch, - fix_data->ttl); - } else { - // Use data from zone or next_dname - if (fix_data->next_dname) { - return handle_nsec_next_dname(fix_data, a, a_node); - } - - // Previous node was not changed in DDNS, it has to have NSEC - const knot_rrset_t *nsec_rrset = - knot_node_rrset(prev_zone_node, KNOT_RRTYPE_NSEC); - assert(nsec_rrset); - const knot_node_t *next_node = b_node; - - // Store next node for next iterations - fix_data->next_dname = - (knot_dname_t *)knot_rdata_nsec_next(nsec_rrset); - update_last_used(fix_data, next_node->owner, next_node); - // Fix NSEC - return update_nsec(prev_zone_node, next_node, fix_data->out_ch, - fix_data->ttl); - } - - return KNOT_EOK; -} - -/*! - * \brief Wrapper for iteration function to be used with NSEC, - * shortens the code a bit. - */ -static int fix_nsec_chain_wrap(knot_dname_t *a, knot_dname_t *a_hash, - knot_dname_t *b, knot_dname_t *b_hash, - chain_fix_data_t *d) -{ - UNUSED(a_hash); - UNUSED(b_hash); - return fix_nsec_chain(a, b, d); -} - -/*! - * \brief Finalizes NSEC chain. - * - * \param d Fix data. - * - * \return KNOT_E* - */ -static int chain_finalize_nsec(chain_fix_data_t *fix_data) -{ - assert(fix_data); - assert(fix_data->last_used_dname && fix_data->next_dname); - const knot_node_t *from = fix_data->last_used_node; - assert(from); - const knot_node_t *to = NULL; - if (knot_dname_is_equal(fix_data->last_used_dname, - fix_data->zone->apex->owner)) { - // Everything but the apex deleted - to = fix_data->zone->apex; - } else if (knot_dname_is_equal(fix_data->last_used_dname, - fix_data->next_dname)) { - // NSEC cannot point to itself (except for the case above) - const knot_rrset_t *nsec_rrset = - knot_node_rrset(from, KNOT_RRTYPE_NSEC); - to = knot_zone_contents_find_node(fix_data->zone, - knot_rdata_nsec_next(nsec_rrset)); - } else { - // Normal case - to = knot_zone_contents_find_node(fix_data->zone, - fix_data->next_dname); - } - assert(to); - return update_nsec(from, to, fix_data->out_ch, fix_data->ttl); -} - /* - API - iterations ------------------------------------------------------- */ /*! @@ -545,68 +202,6 @@ int knot_nsec_chain_iterate_create(knot_zone_tree_t *nodes, callback(current, first, data); } - -/*! - * \brief Iterates sorted changeset and calls callback function - works for - * NSEC and NSEC3 chain. - */ -int knot_nsec_chain_iterate_fix(hattrie_t *nodes, chain_iterate_fix_cb callback, - chain_finalize_cb finalize, - chain_fix_data_t *data) -{ - assert(nodes); - assert(callback); - - bool sorted = true; - hattrie_iter_t *it = hattrie_iter_begin(nodes, sorted); - - if (!it) { - return KNOT_ENOMEM; - } - - if (hattrie_iter_finished(it)) { - hattrie_iter_free(it); - return KNOT_EINVAL; - } - - knot_dname_t *previous_original = NULL; - knot_dname_t *previous_hashed = NULL; - knot_dname_t *current_original = NULL; - knot_dname_t *current_hashed = NULL; - - int result = KNOT_EOK; - while (!hattrie_iter_finished(it)) { - signed_info_t *val = (signed_info_t *)(*hattrie_iter_val(it)); - current_original = val->dname; - current_hashed = val->hashed_dname; - - result = callback(previous_original, previous_hashed, - current_original, current_hashed, data); - if (result == NSEC_NODE_SKIP) { - // No NSEC should be created for 'current' node, skip - hattrie_iter_next(it); - } else if (result == NSEC_NODE_RESET) { - /*! - * Used previous node, call once again so that - * we don't lose this current node. - */ - previous_original = NULL; - previous_hashed = NULL; - } else if (result == KNOT_EOK) { - previous_original = current_original; - previous_hashed = current_hashed; - hattrie_iter_next(it); - } else { - hattrie_iter_free(it); - return result; - } - } - - hattrie_iter_free(it); - - return finalize(data); -} - /* - API - utility functions ------------------------------------------------ */ /*! @@ -696,7 +291,7 @@ bool knot_nsec_only_nsec_and_rrsigs_in_node(const knot_node_t *n) return true; } -/* - API - Chain creation and fix ------------------------------------------- */ +/* - API - Chain creation --------------------------------------------------- */ /*! * \brief Create new NSEC chain, add differences from current into a changeset. @@ -714,17 +309,3 @@ int knot_nsec_create_chain(const knot_zone_contents_t *zone, uint32_t ttl, connect_nsec_nodes, &data); } -/*! - * \brief Fixes NSEC chain after DDNS/reload - */ -int knot_nsec_fix_chain(hattrie_t *sorted_changes, - chain_fix_data_t *fix_data) -{ - if (sorted_changes == NULL || fix_data == NULL) { - return KNOT_EINVAL; - } - - hattrie_build_index(sorted_changes); - return knot_nsec_chain_iterate_fix(sorted_changes, fix_nsec_chain_wrap, - chain_finalize_nsec, fix_data); -} diff --git a/src/knot/dnssec/nsec-chain.h b/src/knot/dnssec/nsec-chain.h index 39f0ac7304db5d801000d82f2282116d79553904..e4bce7004f52a7109cb65f81a290d3b8de2c2e68 100644 --- a/src/knot/dnssec/nsec-chain.h +++ b/src/knot/dnssec/nsec-chain.h @@ -17,7 +17,6 @@ * \file nsec-chain.h * * \author Jan Vcelak <jan.vcelak@nic.cz> (chain creation) - * \author Jan Kadlec <jan.kadlec@nic.cz> (chain fix) * * \brief NSEC chain fix and creation. * @@ -35,21 +34,6 @@ #include "knot/updates/changesets.h" #include "libknot/dnssec/bitmap.h" -/*! - * \brief Parameters to be used when fixing NSEC(3) chain. - */ -typedef struct chain_fix_data { - const knot_zone_contents_t *zone; // Zone to fix - knot_changeset_t *out_ch; // Outgoing changes - const knot_dname_t *chain_start; // Possible new starting node - bool old_connected; // Marks old start connection - const knot_dname_t *last_used_dname; // Last dname used in chain - const knot_node_t *last_used_node; // Last covered node used in chain - knot_dname_t *next_dname; // Used to reconnect broken chain - const hattrie_t *sorted_changes; // Iterated trie - uint32_t ttl; // TTL for NSEC(3) records -} chain_fix_data_t; - /*! * \brief Parameters to be used in connect_nsec_nodes callback. */ @@ -64,18 +48,7 @@ typedef struct { */ enum { NSEC_NODE_SKIP = 1, - NSEC_NODE_RESET = 2 }; -/*! - * \brief Callback used when fixing NSEC chains. - */ -typedef int (*chain_iterate_fix_cb)(knot_dname_t *, knot_dname_t *, - knot_dname_t *, knot_dname_t *, - chain_fix_data_t *); -/*! - * \brief Callback used when finalizing NSEC chains. - */ -typedef int (*chain_finalize_cb)(chain_fix_data_t *); /*! * \brief Callback used when creating NSEC chains. @@ -116,25 +89,6 @@ int knot_nsec_chain_iterate_create(knot_zone_tree_t *nodes, chain_iterate_create_cb callback, nsec_chain_iterate_data_t *data); -/*! - * \brief Iterates sorted changeset and calls callback function - works for - * NSEC and NSEC3 chain. - * - * \note If the callback function returns anything other than KNOT_EOK, the - * iteration is terminated and the error code is propagated. - * - * \param nodes Tree to fix. - * \param callback Callback to call. - * \param finalize Finalization callback. - * \param data Data needed for fixing. - * - * \return KNOT_E* - */ -int knot_nsec_chain_iterate_fix(hattrie_t *nodes, - chain_iterate_fix_cb callback, - chain_finalize_cb finalize, - chain_fix_data_t *data); - /*! * \brief Add entry for removed NSEC(3) and its RRSIG to the changeset. * @@ -169,16 +123,4 @@ bool knot_nsec_only_nsec_and_rrsigs_in_node(const knot_node_t *n); int knot_nsec_create_chain(const knot_zone_contents_t *zone, uint32_t ttl, knot_changeset_t *changeset); -/*! - * \brief Fixes NSEC chain after DDNS/reload - * - * \param sorted_changes Sorted changes created by changeset sign function. - * \param fix_data Chain fix data. - * - * \return KNOT_E* - */ -int knot_nsec_fix_chain(hattrie_t *sorted_changes, - chain_fix_data_t *fix_data); - - #endif // _KNOT_DNSSEC_NSEC_CHAIN_FIX_H_ diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c index fbe33e90a324ff16c74214ec1219aa61da09cbc4..36b9da583299e26a520d3a24904ea3fd86e839c9 100644 --- a/src/knot/dnssec/nsec3-chain.c +++ b/src/knot/dnssec/nsec3-chain.c @@ -78,152 +78,6 @@ static bool are_nsec3_nodes_equal(const knot_node_t *a, const knot_node_t *b) return knot_rrset_equal(a_rrset, b_rrset, KNOT_RRSET_COMPARE_WHOLE); } -/* - Chain fix data helpers ------------------------------------------------- */ - -/*! - * \brief Creates knot_dname_t * from 'next hashed' NSEC3 RR field. - * - * \param rr NSEC3 RRSet. - * \param zone_apex Zone apex dname. - * - * \return Created dname if successful, NULL otherwise. - */ -static knot_dname_t *next_dname_from_nsec3_rrset(const knot_rrset_t *rr, - const knot_dname_t *zone_apex) -{ - int apex_size = knot_dname_size(zone_apex); - if (apex_size < 0) { - return NULL; - } - uint8_t *next_hashed = NULL; - uint8_t hashed_size = 0; - knot_rdata_nsec3_next_hashed(rr, 0, &next_hashed, &hashed_size); - uint8_t *encoded = NULL; - int32_t encoded_size = base32hex_encode_alloc(next_hashed, hashed_size, - &encoded); - if (encoded_size < 0) { - return NULL; - } - - uint8_t catted_hash[encoded_size + apex_size]; - *catted_hash = encoded_size; - memcpy(catted_hash + 1, encoded, encoded_size); - free(encoded); - memcpy(catted_hash + 1 + encoded_size, - zone_apex, apex_size); - knot_dname_t *next_dname = knot_dname_copy(catted_hash); - if (next_dname == NULL) { - return NULL; - } - knot_dname_to_lower(next_dname); - return next_dname; -} - -/*! - * \brief Updates 'chain_start' field in 'chain_fix_data_t'. - * - * \param data Data to be updated. - * \param d DNAME to be set. - */ -static void update_chain_start(chain_fix_data_t *data, const knot_dname_t *d) -{ - assert(data && d); - data->chain_start = d; -} - -/*! - * \brief Updates last used node and DNAME. - * - * \param data Data to be updated. - * \param d DNAME to be set. - * \param n Node to be set. - */ -static void update_last_used(chain_fix_data_t *data, const knot_dname_t *d, - const knot_node_t *n) -{ - assert(data && d); - data->last_used_dname = d; - data->last_used_node = n; -} - -/*! - * \brief Updates next dname with 'next_hashed' from d's NSEC3 RR. - * - * \param fix_data Data to be updated. - * \param d DNAME to search for. - */ -static void update_next_nsec3_dname(chain_fix_data_t *fix_data, - const knot_dname_t *d) - -{ - knot_dname_free(&fix_data->next_dname); - if (d == NULL) { - fix_data->next_dname = NULL; - } else { - const knot_node_t *nsec3_node = - knot_zone_contents_find_nsec3_node(fix_data->zone, d); - assert(nsec3_node); - const knot_rrset_t *nsec3_rrset = knot_node_rrset(nsec3_node, - KNOT_RRTYPE_NSEC3); - assert(nsec3_rrset); - fix_data->next_dname = - next_dname_from_nsec3_rrset(nsec3_rrset, - fix_data->zone->apex->owner); - } -} - -/* - Misc. helpers ---------------------------------------------------------- */ - -/*! - * \brief Helper function - sets variables by looking for data in the zone. - */ -static void fetch_nodes_from_zone(const knot_zone_contents_t *z, - const knot_dname_t *a, - const knot_dname_t *b, - const knot_dname_t *a_hash, - const knot_dname_t *b_hash, - const knot_node_t **a_node, - const knot_node_t **b_node, - const knot_node_t **a_nsec3_node, - const knot_node_t **b_nsec3_node) -{ - *a_node = knot_zone_contents_find_node(z, a); - *b_node = knot_zone_contents_find_node(z, b); - *a_nsec3_node = knot_zone_contents_find_nsec3_node(z, a_hash); - *b_nsec3_node = knot_zone_contents_find_nsec3_node(z, b_hash); -} - -/*! - * \brief Checks whether NSEC3 covered was not changed and is now non-auth. - * - * \param z Zone to be searched. - * \param d_hashed Hash to look for. - * \param sorted_changes DDNS/reload changes. - * - * \return True if this node can be used, false otherwise. - */ -static bool covered_node_usable(const knot_zone_contents_t *z, - const knot_dname_t *d_hashed, - const hattrie_t *sorted_changes) -{ - uint8_t lf[KNOT_DNAME_MAXLEN]; - knot_dname_lf(lf, d_hashed, NULL); - value_t *val = hattrie_tryget((hattrie_t *)sorted_changes, - (char *)lf+1, *lf); - if (val == NULL) { - return false; - } else { - signed_info_t *info = (signed_info_t *)(*val); - assert(knot_dname_is_equal(info->hashed_dname, d_hashed)); - // Get normal node - const knot_node_t *normal_node = - knot_zone_contents_find_node(z, info->dname); - // Usable if not deleted and not non-auth - return normal_node != NULL && - !knot_node_is_non_auth(normal_node); - } -} - /*! * \brief Check whether at least one RR type in node should be signed, * used when signing with NSEC3. @@ -253,159 +107,6 @@ static bool node_should_be_signed_nsec3(const knot_node_t *n) return false; } -/*! - * \brief Checks whether NSEC3 RR in zone is valid and updates it if needed. - * - * \param from Start hash in NSEC3 link. - * \param to Destination hash in NSEC3 link. - * \param covered_node Node covered by 'from' hash. - * \param out_ch Changes go here. - * \param zone Changed zone. - * \param soa_min TTL to use for new NSEC3 RRs. - * - * \return KNOT_E* - */ -static int update_nsec3(const knot_dname_t *from, const knot_dname_t *to, - const knot_node_t *covered_node, - knot_changeset_t *out_ch, - const knot_zone_contents_t *zone, uint32_t soa_min) -{ - assert(from && to && out_ch && zone); - // Get old NSEC3 RR (there might not be any) - const knot_node_t *from_node = knot_zone_contents_find_nsec3_node(zone, - from); - const knot_rrset_t *old_nsec3 = from_node ? - knot_node_rrset(from_node, - KNOT_RRTYPE_NSEC3) : NULL; - - // Create new NSEC3 - start with binary next hashed name - uint8_t *b32_hash = (uint8_t *)knot_dname_to_str(to); - assert(zone->nsec3_params.algorithm != 0); - size_t b32_length = - knot_nsec3_hash_b32_length(zone->nsec3_params.algorithm); - if (b32_hash == NULL) { - return KNOT_ENOMEM; - } - uint8_t *binary_next = NULL; - int32_t written = base32hex_decode_alloc(b32_hash, b32_length, - &binary_next); - free(b32_hash); - if (written < 0) { - return written; - } - - knot_rrset_t *gen_nsec3 = NULL; - // Create or reuse - if (covered_node) { - // Use bitmap from given node - bitmap_t bm = { '\0' }; - bitmap_add_node_rrsets(&bm, covered_node); - if (node_should_be_signed_nsec3(covered_node)) { - bitmap_add_type(&bm, KNOT_RRTYPE_RRSIG); - } - // Create owner - knot_dname_t *owner = knot_dname_copy(from); - if (owner == NULL) { - free(binary_next); - return KNOT_ENOMEM; - } - // Create the RRSet - gen_nsec3 = create_nsec3_rrset(owner, &zone->nsec3_params, - &bm, binary_next, soa_min); - if (gen_nsec3 == NULL) { - free(binary_next); - knot_dname_free(&owner); - return KNOT_ERROR; - } - } else { - assert(old_nsec3); - // Reuse bitmap and data from old NSEC3 - int ret = knot_rrset_deep_copy(old_nsec3, &gen_nsec3, NULL); - if (ret != KNOT_EOK) { - free(binary_next); - return ret; - } - uint8_t *next_hashed = NULL; - uint8_t next_hashed_size; - knot_rdata_nsec3_next_hashed(gen_nsec3, 0, &next_hashed, - &next_hashed_size); - assert(next_hashed); - if (next_hashed_size != written) { - // Possible algo mismatch - free(binary_next); - knot_rrset_deep_free(&gen_nsec3, 1, NULL); - return KNOT_ERROR; - } - memcpy(next_hashed, binary_next, next_hashed_size); - } - free(binary_next); - - if (old_nsec3 && knot_rrset_equal(old_nsec3, gen_nsec3, - KNOT_RRSET_COMPARE_WHOLE)) { - // Nothing to update - knot_rrset_deep_free(&gen_nsec3, 1, NULL); - return KNOT_EOK; - } else { - // Drop old - int ret = KNOT_EOK; - if (old_nsec3) { - ret = knot_nsec_changeset_remove(from_node, out_ch); - if (ret != KNOT_EOK) { - knot_rrset_deep_free(&gen_nsec3, 1, NULL); - return ret; - } - } - - // Add new - ret = knot_changeset_add_rrset(out_ch, gen_nsec3, - KNOT_CHANGESET_ADD); - if (ret != KNOT_EOK) { - knot_rrset_deep_free(&gen_nsec3, 1, NULL); - return ret; - } - } - - return KNOT_EOK; -} - -/*! - * \brief Gets first NSEC3 node from zone. - * - * \param z Zone to be searched. - * - * \return first NSEC3 node on success, NULL otherwise. - */ -static const knot_node_t *zone_first_nsec3_node(const knot_zone_contents_t *z) -{ - assert(z && hattrie_weight(z->nsec3_nodes) > 0); - hattrie_iter_t *i = hattrie_iter_begin(z->nsec3_nodes, true); - if (i == NULL) { - return NULL; - } - knot_node_t *first_node = (knot_node_t *)*hattrie_iter_val(i); - assert(first_node); - hattrie_iter_free(i); - return first_node; -} - -/*! - * \brief Gets last NSEC3 node from zone. - * - * \param z Zone to be searched. - * - * \return last NSEC3 node on success, NULL otherwise. - */ -static const knot_node_t *zone_last_nsec3_node(const knot_zone_contents_t *z) -{ - // Get first node - const knot_node_t *first_node = zone_first_nsec3_node(z); - if (first_node == NULL) { - return NULL; - } - // Get node previous to first = last node - return knot_zone_contents_find_previous_nsec3(z, first_node->owner); -} - /* - RRSIGs handling for NSEC3 ---------------------------------------------- */ /*! @@ -777,612 +478,6 @@ static int create_nsec3_nodes(const knot_zone_contents_t *zone, uint32_t ttl, return result; } -/* - NSEC3 chain fix -------------------------------------------------------- */ - -/* - Nonterminal handling --------------------------------------------------- */ - -/*! - * \brief Cuts DNAME and looks for all the labels in the zone. - * - * \param dname DNAME to be cut. - * \param zone Zone to be searched. - * \param t Trie that contains empty non-terminals. - * - * \return KNOT_E* - */ -static int walk_dname_and_store_empty_nonterminals(const knot_dname_t *dname, - const knot_zone_contents_t *zone, - hattrie_t *t) -{ - assert(dname); - assert(zone); - assert(t); - - if (knot_dname_size(dname) == 1) { - // Root dname - assert(*dname == '\0'); - return KNOT_EOK; - } - if (knot_dname_is_equal(dname, zone->apex->owner)) { - // Apex - return KNOT_EOK; - } - - // Start after the first cut - const knot_dname_t *cut = knot_wire_next_label(dname, NULL); - while (*cut != '\0' && !knot_dname_is_equal(cut, zone->apex->owner)) { - // Search for name in the zone - const knot_node_t *n = knot_zone_contents_find_node(zone, cut); - if (n == NULL || n->rrset_count == 0) { - /*! - * n == NULL: - * This means that RR *removal* caused non-terminal - * deletion - NSEC3 has to be dropped. - * - * n->rrset_count == 0: - * This means that RR *addition* created new empty - * non-terminal - NSEC3 has to be added. - */ - hattrie_insert_dname(t, (knot_dname_t *)cut); - } - cut = knot_wire_next_label(cut, NULL); - } - return KNOT_EOK; -} -/*! - * \brief Cuts labels and looks for nodes in zone, if an empty node is found - * adds it into trie. There may be multiple nodes. Not all nodes - * have to be checked, but not doing that would bloat the code. - * - * \param zone - * \param sorted_changes - * - * \return KNOT_E* - */ -static int update_changes_with_empty_non_terminals(const knot_zone_contents_t *zone, - hattrie_t *sorted_changes) -{ - assert(zone); - assert(sorted_changes); - - /*! - * Create trie with newly created nonterminals, as we cannot (probably) - * insert to the trie in the middle of iteration. - */ - hattrie_t *nterminal_t = hattrie_create(); - if (nterminal_t == NULL) { - return KNOT_ENOMEM; - } - - // Start trie iteration - const bool sorted = false; - hattrie_iter_t *itt = hattrie_iter_begin(sorted_changes, sorted); - if (itt == NULL) { - return KNOT_ERROR; - } - for (; !hattrie_iter_finished(itt); hattrie_iter_next(itt)) { - signed_info_t *info = (signed_info_t *)*hattrie_iter_val(itt); - knot_dname_t *node_dname = info->dname; - assert(node_dname); - int ret = walk_dname_and_store_empty_nonterminals(node_dname, - zone, - nterminal_t); - if (ret != KNOT_EOK) { - hattrie_free(nterminal_t); - return ret; - } - } - hattrie_iter_free(itt); - - // Reinsert updated nonterminals into trie (dname already converted) - itt = hattrie_iter_begin(nterminal_t, sorted); - if (itt == NULL) { - return KNOT_ERROR; - } - for (; !hattrie_iter_finished(itt); hattrie_iter_next(itt)) { - // Store keys from table directly to trie - size_t key_size = 0; - const char *k = hattrie_iter_key(itt, &key_size); - assert(k && key_size > 0); - // Create dummy value - signed_info_t *info = malloc(sizeof(signed_info_t)); - if (info == NULL) { - ERR_ALLOC_FAILED; - hattrie_iter_free(itt); - hattrie_free(nterminal_t); - return KNOT_ENOMEM; - } - memset(info, 0, sizeof(signed_info_t)); - info->dname = - knot_dname_copy((knot_dname_t *)(*hattrie_iter_val(itt))); - if (info->dname == NULL) { - hattrie_iter_free(itt); - hattrie_free(nterminal_t); - return KNOT_ENOMEM; - } - *hattrie_get(sorted_changes, k, key_size) = info; - } - - hattrie_iter_free(itt); - hattrie_free(nterminal_t); - - return KNOT_EOK; -} - -/* - Changeset hashing ------------------------------------------------------ */ - -/*! - * \brief Iterates through changes made by DDNS/reload and NSEC3-hashes each name. - * - * \param sorted_changes Changes to be iterated. - * \param zone Changed zone. - * \param out NSEC3 hashes are saved here with original DNAMEs. - * - * \return KNOT_E* - */ -static int create_nsec3_hashes_from_trie(const hattrie_t *sorted_changes, - const knot_zone_contents_t *zone, - hattrie_t **out) -{ - assert(sorted_changes); - assert(hattrie_weight(sorted_changes) > 0); - *out = hattrie_create(); - if (*out == NULL) { - return KNOT_ENOMEM; - } - - const bool sort = false; - hattrie_iter_t *itt = hattrie_iter_begin(sorted_changes, sort); - if (itt == NULL) { - hattrie_free(*out); - return KNOT_ERROR; - } - - for (; !hattrie_iter_finished(itt); hattrie_iter_next(itt)) { - signed_info_t *val = (signed_info_t *)(*hattrie_iter_val(itt)); - const knot_dname_t *original_dname = val->dname; - knot_dname_t *nsec3_name = - knot_create_nsec3_owner(original_dname, - zone->apex->owner, - &zone->nsec3_params); - if (nsec3_name == NULL) { - hattrie_iter_free(itt); - hattrie_free(*out); - return KNOT_ERROR; - } - knot_dname_to_lower(nsec3_name); - val->hashed_dname = nsec3_name; - - // Convert NSEC3 hash to sortable format - uint8_t lf[KNOT_DNAME_MAXLEN]; - knot_dname_lf(lf, nsec3_name, NULL); - // Store into new trie - *hattrie_get(*out, (char *)lf+1, *lf) = val; - } - hattrie_iter_free(itt); - return KNOT_EOK; -} - -/* - Actual chain fix ------------------------------------------------------- */ - -/*! - * \brief Fetches covered node for 'hash' from zone. - * - * \param fix_data Chain fix data. - * \param hash Hash to search for. - * - * \return Covered node if changed via DDNS/reload, NULL otherwise. - */ -static const knot_node_t *fetch_covered_node(chain_fix_data_t *fix_data, - const knot_dname_t *hash) -{ - uint8_t lf[KNOT_DNAME_MAXLEN]; - knot_dname_lf(lf, hash, NULL); - value_t *val = hattrie_tryget((hattrie_t *)fix_data->sorted_changes, - (char *)lf+1, *lf); - if (val == NULL) { - // No change, old bitmap can be reused - return NULL; - } else { - signed_info_t *info = (signed_info_t *)*val; - return knot_zone_contents_find_node(fix_data->zone, - info->dname); - } -} - -/*! - * \brief Handles fixing of 'gaps' in NSEC3 chain. - * - * \param fix_data Chain fix data. - * \param a_hash Hash of DNAME we want to connect to. - * \param a_node Node covered by 'a_hash' (normal node). - * \param a_nsec3_node NSEC3 node for 'a_hash'. - * - * \return KNOT_E* - */ -static int handle_nsec3_next_dname(chain_fix_data_t *fix_data, - const knot_dname_t *a_hash, - const knot_node_t *a_node, - const knot_node_t *a_nsec3_node) -{ - assert(fix_data && fix_data->next_dname && a_hash && a_node); - int ret = KNOT_EOK; - if (knot_dname_is_equal(fix_data->next_dname, a_hash)) { - assert(a_nsec3_node); - // We have to take one more step in the chain - const knot_rrset_t *nsec3_rrset = - knot_node_rrset(a_nsec3_node, KNOT_RRTYPE_NSEC3); - assert(nsec3_rrset); - knot_dname_t *rr_next_dname = - next_dname_from_nsec3_rrset(nsec3_rrset, - fix_data->zone->apex->owner); - if (rr_next_dname == NULL) { - return KNOT_ENOMEM; - } - const knot_node_t *next_node = - knot_zone_contents_find_nsec3_node(fix_data->zone, - rr_next_dname); - assert(next_node); - knot_dname_free(&rr_next_dname); - update_last_used(fix_data, next_node->owner, - fetch_covered_node(fix_data, next_node->owner)); - ret = update_nsec3(a_hash, rr_next_dname, a_node, - fix_data->out_ch, - fix_data->zone, fix_data->ttl); - } else { - // Next dname is usable - update_last_used(fix_data, fix_data->next_dname, - fetch_covered_node(fix_data, fix_data->next_dname)); - ret = update_nsec3(a_hash, fix_data->next_dname, - a_node, fix_data->out_ch, - fix_data->zone, fix_data->ttl); - update_next_nsec3_dname(fix_data, NULL); - return ret == KNOT_EOK ? NSEC_NODE_RESET : ret; - } - update_next_nsec3_dname(fix_data, NULL); - return ret == KNOT_EOK ? NSEC_NODE_RESET : ret; -} - -/*! - * \brief Handles node that has been deleted by DDNS/reload. - * - * \param node Deleted node - * \param fix_data Chain fix data. - * - * \return KNOT_E*, NSEC_NODE_SKIP - */ -static int handle_deleted_node(const knot_node_t *node, - chain_fix_data_t *fix_data) -{ - if (node == NULL) { - // This node was deleted and used to be non-auth - assert(knot_node_is_non_auth(node)); - return NSEC_NODE_SKIP; - } - int ret = knot_nsec_changeset_remove(node, fix_data->out_ch); - if (ret != KNOT_EOK) { - return ret; - } - - /*! - * This node should be ignored, but we might need the next dname from - * previous node. - */ - if (fix_data->next_dname == NULL) { - const knot_rrset_t *old_nsec3 = - knot_node_rrset(node, KNOT_RRTYPE_NSEC3); - assert(old_nsec3); - fix_data->next_dname = - next_dname_from_nsec3_rrset(old_nsec3, - fix_data->zone->apex->owner); - if (fix_data->next_dname == NULL) { - return KNOT_ENOMEM; - } - } - - return NSEC_NODE_SKIP; -} - -/*! - * \brief Checks if old and new NSEC3 chains should be connected. - * - * \param fix_data Chain fix data. - * \param a Old chain end. - * \param b New chain start. - * \param zone_prev Previous node from zone for 'b'. - * - * \return True if chains should be connected, false if no. - */ -static bool should_connect_to_old(chain_fix_data_t *fix_data, - const knot_dname_t *a, const knot_dname_t *b, - const knot_dname_t *zone_prev) -{ - return fix_data->chain_start && !fix_data->old_connected && - a && knot_dname_cmp(a, zone_prev) < 0 && - knot_dname_cmp(zone_prev, b) < 0; -} - -/*! - * \brief Connects old NSEC3 chain and new NSE3 chain. - * - * \param fix_data Chain fix data. - * \param a_hash Old NSEC3 chain end. - * \param b_hash New NSEC3 chain beginning. - * \param a_node Node covered by 'a_hash', from changeset. - * \param zone_prev_node Nobe covered by 'a_hash', from zone. - * - * \return KNOT_E* - */ -static int connect_to_old_start(chain_fix_data_t *fix_data, - const knot_dname_t *a_hash, - const knot_dname_t *b_hash, - const knot_node_t *a_node, - const knot_node_t *zone_prev_node) -{ - fix_data->old_connected = true; - assert(fix_data && a_hash && b_hash && a_node && zone_prev_node); - int ret = update_nsec3(a_hash, zone_prev_node->owner, - a_node, fix_data->out_ch, fix_data->zone, - fix_data->ttl); - if (ret != KNOT_EOK) { - return ret; - } - - update_last_used(fix_data, b_hash, - fetch_covered_node(fix_data, b_hash)); - return update_nsec3(zone_prev_node->owner, b_hash, - fetch_covered_node(fix_data, zone_prev_node->owner), - fix_data->out_ch, fix_data->zone, fix_data->ttl); -} - -/*! - * \brief Decides whether to use previous hash from zone or changeset. - * - * \param a_hash Previous hash from changeset. - * \param b_hash Hash we want to connect to. - * \param zone_prev Previous hash from zone. - * - * \return True if previous dname from changeset should be used, false otherwise. - */ -static bool use_prev_from_changeset(const knot_dname_t *a_hash, - const knot_dname_t *b_hash, - const knot_dname_t *zone_prev) -{ - if (a_hash) { - // Direct hit from changeset, or fits between zone and changeset gap - bool name_eq_closer = knot_dname_cmp(a_hash, - zone_prev) >= 0; - // Previous node is no longer valid - new chain start was set - bool part_of_new_start = knot_dname_cmp(a_hash, - zone_prev) < 0 && - knot_dname_cmp(b_hash, - zone_prev) <= 0; - return name_eq_closer || part_of_new_start; - } else { - return false; - } -} - -/*! - * \brief Finds previous usable NSEC3 node in zone, checks if node node not - * deleted in changes. - * \param z Zone to be searched. - * \param d_hashed Hash to search for. - * \param sorted_changes DDNS/reload changes. - * - * \return Previous NSEC3 node for 'd_hashed'. - */ -static const knot_node_t *find_prev_nsec3_node(const knot_zone_contents_t *z, - const knot_dname_t *d_hashed, - const hattrie_t *sorted_changes) -{ - // Find previous node for the node - const knot_node_t *prev_nsec3_node = - knot_zone_contents_find_previous_nsec3(z, d_hashed); - assert(prev_nsec3_node); - bool prev_nsec3_found = !covered_node_usable(z, prev_nsec3_node->owner, - sorted_changes); - while (!prev_nsec3_found) { - prev_nsec3_node = - knot_zone_contents_find_previous_nsec3(z, - prev_nsec3_node->owner); - assert(prev_nsec3_node); - // Either the node is usable, or there's nothing more to find - prev_nsec3_found = covered_node_usable(z, - prev_nsec3_node->owner, - sorted_changes) || - knot_dname_is_equal(prev_nsec3_node->owner, - d_hashed); - } - return prev_nsec3_node; -} - -/*! - * \brief Fixes one link between 'a' and 'b', or rather between their hashes. - * 'a_hash' is always < 'b_hash'. Called only via iteration function. - * - * \param a Normal DNAME (changed in the update/reload) - * \param a_hash NSEC3 hash of 'a'. - * \param b Normal DNAME (changed in the update/reload) - * \param b_hash NSEC3 hash of 'b'. - * \param fix_data Fix data. - * - * \return KNOT_EOK if okay, KNOT_E* if something went wrong, - * NSEC_NODE_RESET, NSEC_NODE_SKIP if special handling is needed by the - * iteration funtion. - */ -static int fix_nsec3_chain(knot_dname_t *a, knot_dname_t *a_hash, - knot_dname_t *b, knot_dname_t *b_hash, - chain_fix_data_t *fix_data) -{ - assert(b && b_hash); - assert((!a && !a_hash) || (a && a_hash)); - assert(fix_data); - // Get nodes from zone - const knot_node_t *a_node, *b_node, *a_nsec3_node, *b_nsec3_node; - fetch_nodes_from_zone(fix_data->zone, a, b, a_hash, b_hash, &a_node, - &b_node, &a_nsec3_node, &b_nsec3_node); - // Find previous node in zone ('proper' node might not be in the zone yet) - const knot_node_t *prev_nsec3_node = - find_prev_nsec3_node(fix_data->zone, b_hash, - fix_data->sorted_changes); - if (prev_nsec3_node == NULL) { - // Should not happen, zone would have to have no NSEC3 chain - return KNOT_ERROR; - } - - // Handle possible node removal - bool node_deleted = b_node == NULL; - if (node_deleted) { - // The deleted node might have been authoritative, but not anymore - if (fix_data->last_used_dname == NULL) { - update_last_used(fix_data, prev_nsec3_node->owner, - fetch_covered_node(fix_data, - prev_nsec3_node->owner)); - } - return handle_deleted_node(b_nsec3_node, fix_data); - } - if (knot_node_is_non_auth(b_node)) { - // Nothing to fix in this node - return NSEC_NODE_SKIP; - } - - // Find out whether to use a node from changeset or from zone - bool use_prev_from_chgs = use_prev_from_changeset(a_hash, b_hash, - prev_nsec3_node->owner); - if (use_prev_from_chgs) { - // No valid data for the previous node, create the forward NSEC3 - update_last_used(fix_data, b_hash, b_node); - return update_nsec3(a_hash, b_hash, a_node, fix_data->out_ch, - fix_data->zone, fix_data->ttl); - } - if (should_connect_to_old(fix_data, - a_hash, b_hash, prev_nsec3_node->owner)) { - // Connect old start with new start - return connect_to_old_start(fix_data, a_hash, b_hash, a_node, - prev_nsec3_node); - } - - // Use either next_dname or data from zone - bool new_chain_start = - knot_dname_cmp(prev_nsec3_node->owner, b_hash) > 0 && - !(zone_first_nsec3_node(fix_data->zone) == b_nsec3_node); - if (new_chain_start) { - assert(a == NULL); // This has to be the first change - // New chain started by this change - update_last_used(fix_data, b_hash, b_node); - update_chain_start(fix_data, b_hash); - return KNOT_EOK; - } else if (fix_data->next_dname) { - return handle_nsec3_next_dname(fix_data, a_hash, - a_node, a_nsec3_node); - } else { - // Previous node was not changed in DDNS, NSEC3 has to be present - assert(knot_node_rrset(prev_nsec3_node, KNOT_RRTYPE_NSEC3)); - update_next_nsec3_dname(fix_data, prev_nsec3_node->owner); - update_last_used(fix_data, b_hash, b_node); - return update_nsec3(prev_nsec3_node->owner, b_hash, - fetch_covered_node(fix_data, prev_nsec3_node->owner), - fix_data->out_ch, fix_data->zone, - fix_data->ttl); - } - - return KNOT_EOK; -} - -/*! - * \brief Finalizes NSEC3 chain. - * - * \param fix_data Chain fix data. - * - * \return KNOT_E* - */ -static int chain_finalize_nsec3(chain_fix_data_t *fix_data) -{ - assert(fix_data); - if (fix_data->next_dname == NULL && fix_data->chain_start == NULL) { - // Nothing to fix - return KNOT_EOK; - } - const knot_dname_t *from = fix_data->last_used_dname; - assert(from); - const knot_node_t *from_node = fix_data->last_used_node; - const knot_dname_t *to = NULL; - if (fix_data->chain_start) { - /*! - * New chain start has to be closed - get last dname - * in the chain from zone or changeset. - */ - const knot_node_t *last_node = - zone_last_nsec3_node(fix_data->zone); - if (last_node == NULL) { - return KNOT_ENOMEM; - } - if (!fix_data->old_connected) { - /*! - * New chain was started, but not connected to - * the old one. - */ - const knot_node_t *first_nsec3 = - zone_first_nsec3_node(fix_data->zone); - if (first_nsec3 == NULL) { - return KNOT_ENOMEM; - } - - int ret = update_nsec3(fix_data->last_used_dname, - first_nsec3->owner, - fix_data->last_used_node, - fix_data->out_ch, - fix_data->zone, fix_data->ttl); - if (ret != KNOT_EOK) { - return ret; - } - } - // Close the chain - to = fix_data->chain_start; - if (knot_dname_cmp(last_node->owner, - fix_data->last_used_dname) > 0) { - // Use last zone node to close the chain - from = last_node->owner; - from_node = NULL; // Was not changed - } - } else if (knot_dname_is_equal(from, - fix_data->zone->apex->nsec3_node->owner)) { - // Special case where all nodes but the apex are deleted - to = fix_data->last_used_dname; - } else if (knot_dname_is_equal(from, fix_data->next_dname)) { - // We do not want to point it to itself, extract next - const knot_node_t *nsec3_node = - knot_zone_contents_find_nsec3_node(fix_data->zone, - from); - assert(nsec3_node); - const knot_rrset_t *nsec3_rrset = - knot_node_rrset(nsec3_node, KNOT_RRTYPE_NSEC3); - assert(nsec3_rrset); - knot_dname_free(&fix_data->next_dname); - knot_dname_t *next = - next_dname_from_nsec3_rrset(nsec3_rrset, - fix_data->zone->apex->owner); - if (next == NULL) { - return KNOT_ENOMEM; - } - // We have to call update here, since different name should be freed - int ret = update_nsec3(from, next, fix_data->last_used_node, - fix_data->out_ch, fix_data->zone, - fix_data->ttl); - knot_dname_free(&next); - return ret; - } else { - // Normal case - to = fix_data->next_dname; - } - assert(to); - int ret = update_nsec3(from, to, from_node, - fix_data->out_ch, fix_data->zone, fix_data->ttl); - knot_dname_free(&fix_data->next_dname); - return ret; -} - /*! * \brief Checks if NSEC3 should be generated for this node. * @@ -1542,31 +637,3 @@ int knot_nsec3_create_chain(const knot_zone_contents_t *zone, uint32_t ttl, return result; } -/*! - * \brief Fixes NSEC3 chain after DDNS/reload. - */ -int knot_nsec3_fix_chain(hattrie_t *sorted_changes, chain_fix_data_t *fix_data) -{ - // Empty non-terminals are not in the changes, update - int ret = update_changes_with_empty_non_terminals(fix_data->zone, - sorted_changes); - if (ret != KNOT_EOK) { - return ret; - } - // Create and sort NSEC3 hashes - hattrie_t *nsec3_names = NULL; - ret = create_nsec3_hashes_from_trie(sorted_changes, - fix_data->zone, - &nsec3_names); - if (ret != KNOT_EOK) { - return ret; - } - hattrie_build_index(nsec3_names); - fix_data->sorted_changes = nsec3_names; - - // Fix NSEC3 chain - ret = knot_nsec_chain_iterate_fix(nsec3_names, fix_nsec3_chain, - chain_finalize_nsec3, fix_data); - hattrie_free(nsec3_names); - return ret; -} diff --git a/src/knot/dnssec/nsec3-chain.h b/src/knot/dnssec/nsec3-chain.h index d2f1f072ed15cef5972d83fde759b16f4d0b8440..9437c29704adf9ce94d2f1fda601a610f94d4e68 100644 --- a/src/knot/dnssec/nsec3-chain.h +++ b/src/knot/dnssec/nsec3-chain.h @@ -16,10 +16,9 @@ /*! * \file nsec3-chain-fix.h * - * \author Jan Kadlec <jan.kadlec@nic.cz> (chain fix) * \author Jan Vcelak <jan.vcelak@nic.cz> (chain creation) * - * \brief NSEC3 chain fix and creation. + * \brief NSEC3 chain creation. * * \addtogroup dnssec * @{ @@ -43,14 +42,4 @@ int knot_nsec3_create_chain(const knot_zone_contents_t *zone, uint32_t ttl, knot_changeset_t *changeset); -/*! - * \brief Fixes NSEC3 chain after DDNS/reload. - * - * \param sorted_changes Sorted changes created by changeset sign function. - * \param fix_data Chain fix data. - * - * \return KNOT_E* - */ -int knot_nsec3_fix_chain(hattrie_t *sorted_changes, chain_fix_data_t *fix_data); - #endif // _KNOT_DNSSEC_NSEC3_CHAIN_FIX_H_ diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c index 2c5ce829a6a95e5b0261355c94ffb8cc71cc05ae..00872d41af56c7f1fb6f8bec543b6710cd8257fe 100644 --- a/src/knot/dnssec/zone-events.c +++ b/src/knot/dnssec/zone-events.c @@ -182,10 +182,9 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone, knot_changeset_t *out_ch, knot_update_serial_t soa_up, uint32_t *refresh_at, - uint32_t new_serial, - hattrie_t **sorted_changes) + uint32_t new_serial) { - if (!refresh_at || !sorted_changes) { + if (!refresh_at) { return KNOT_EINVAL; } @@ -210,7 +209,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone, } // Sign added and removed RRSets in changeset - ret = knot_zone_sign_changeset(zone, in_ch, out_ch, sorted_changes, + ret = knot_zone_sign_changeset(zone, in_ch, out_ch, &zone_keys, &policy); if (ret != KNOT_EOK) { log_zone_error("%s Failed to sign changeset (%s)\n", msgpref, @@ -220,13 +219,10 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone, return ret; } - assert(sorted_changes); - // Fix NSEC(3) chain - ret = knot_zone_fix_nsec_chain(zone, - *sorted_changes, out_ch, - &zone_keys, &policy); + // Create NSEC(3) chain + ret = knot_zone_create_nsec_chain(zone, out_ch, &zone_keys, &policy); if (ret != KNOT_EOK) { - log_zone_error("%s Failed to fix NSEC(3) chain (%s)\n", + log_zone_error("%s Failed to create NSEC(3) chain (%s)\n", msgpref, knot_strerror(ret)); knot_free_zone_keys(&zone_keys); free(msgpref); diff --git a/src/knot/dnssec/zone-events.h b/src/knot/dnssec/zone-events.h index cb94526f37cacb4e6f3459e64fbf299b7b034853..ab6f2fd5eca8dc94676fab3c218f312448ba4b11 100644 --- a/src/knot/dnssec/zone-events.h +++ b/src/knot/dnssec/zone-events.h @@ -75,7 +75,6 @@ int knot_dnssec_zone_sign_force(knot_zone_contents_t *zone, conf_zone_t *zone_co * \param soa_up SOA serial update policy. * \param refresh_at Signature refresh time of the new signatures. * \param new_serial New SOA serial. - * \param sorted_changes Info about made changes, used for partial adjustment. * * \return Error code, KNOT_EOK if successful. */ @@ -84,8 +83,7 @@ int knot_dnssec_sign_changeset(const knot_zone_contents_t *zone, const knot_changeset_t *in_ch, knot_changeset_t *out_ch, knot_update_serial_t soa_up, - uint32_t *refresh_at, uint32_t new_serial, - hattrie_t **sorted_changes); + uint32_t *refresh_at, uint32_t new_serial); #endif // _KNOT_DNSSEC_ZONE_EVENTS_H_ /*! @} */ diff --git a/src/knot/dnssec/zone-nsec.c b/src/knot/dnssec/zone-nsec.c index 67121f9296170d9c598df08450f85d2167865e4f..9e1ef9f51ebed924be2798d27c7d2b50aa33e667 100644 --- a/src/knot/dnssec/zone-nsec.c +++ b/src/knot/dnssec/zone-nsec.c @@ -287,44 +287,3 @@ int knot_zone_create_nsec_chain(const knot_zone_contents_t *zone, return knot_zone_sign_nsecs_in_changeset(zone_keys, policy, changeset); } -/*! - * \brief Fix NSEC or NSEC3 chain in the zone. - */ -int knot_zone_fix_nsec_chain(const knot_zone_contents_t *zone, - hattrie_t *sorted_changes, - knot_changeset_t *out_ch, - const knot_zone_keys_t *zone_keys, - const knot_dnssec_policy_t *policy) -{ - if (zone == NULL || sorted_changes == NULL || zone_keys == NULL || - policy == NULL) { - return KNOT_EINVAL; - } - - if (hattrie_weight(sorted_changes) == 0) { - // no changes, no fix - return KNOT_EOK; - } - - // Prepare data for chain fixing functions - chain_fix_data_t fix_data = { .zone = zone, - .out_ch = out_ch, - .next_dname = NULL, - .chain_start = NULL, - .old_connected = false, - .last_used_dname = NULL, - .last_used_node = NULL}; - get_zone_soa_min_ttl(zone, &fix_data.ttl); - int ret = KNOT_EOK; - if (knot_is_nsec3_enabled(zone)) { - ret = knot_nsec3_fix_chain(sorted_changes, &fix_data); - } else { - - // Fix NSEC chain - ret = knot_nsec_fix_chain(sorted_changes, &fix_data); - } - - dbg_dnssec_verb("NSEC(3) chain fixed (%s)\n", knot_strerror(ret)); - - return ret; -} diff --git a/src/knot/dnssec/zone-nsec.h b/src/knot/dnssec/zone-nsec.h index aa7f53956363fd9bc8347756201a2f3f0992f700..36bb35660694c1738eeacb9ffa8441cd2fca7701 100644 --- a/src/knot/dnssec/zone-nsec.h +++ b/src/knot/dnssec/zone-nsec.h @@ -85,25 +85,6 @@ int knot_zone_create_nsec_chain(const knot_zone_contents_t *zone, const knot_zone_keys_t *zone_keys, const knot_dnssec_policy_t *policy); -/*! - * \brief Fix NSEC or NSEC3 chain in the zone. - * - * \param zone Zone for which the NSEC(3) chain will be created. - * \param sorted_changes Sorted changes created by 'sign_changeset' function. - * This param is updated with normal node -> NSEC3 node - * links, to be used later when adjusting zone. - * \param out_ch Changeset into which the changes will be added. - * \param zone_keys Zone keys used for NSEC(3) creation. - * \param policy DNSSEC signing policy. - * - * \return Error code, KNOT_EOK if successful. - */ -int knot_zone_fix_nsec_chain(const knot_zone_contents_t *zone, - hattrie_t *sorted_changes, - knot_changeset_t *out_ch, - const knot_zone_keys_t *zone_keys, - const knot_dnssec_policy_t *policy); - #endif // _KNOT_DNSSEC_ZONE_NSEC_H_ /*! @} */ diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c index d6fde4384baea81422c9104fc0d064257ed846e1..7f87040b76e472035a700db8f0e99409cfd9c0fe 100644 --- a/src/knot/dnssec/zone-sign.c +++ b/src/knot/dnssec/zone-sign.c @@ -1204,6 +1204,12 @@ static int sign_changeset_wrap(knot_rrset_t *chg_rrset, void *data) return KNOT_EOK; } +/*! + * \brief Frees info node about update signing. + * + * \param val Node to free. + * \param d Unused. + */ static int free_helper_trie_node(value_t *val, void *d) { UNUSED(d); @@ -1218,6 +1224,18 @@ static int free_helper_trie_node(value_t *val, void *d) return KNOT_EOK; } +/*! + * \brief Clears trie with info about update signing. + * + * \param t Trie to clear. + */ +static void knot_zone_clear_sorted_changes(hattrie_t *t) +{ + if (t) { + hattrie_apply_rev(t, free_helper_trie_node, NULL); + } +} + /*- public API ---------------------------------------------------------------*/ /*! @@ -1369,12 +1387,10 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa, int knot_zone_sign_changeset(const knot_zone_contents_t *zone, const knot_changeset_t *in_ch, knot_changeset_t *out_ch, - hattrie_t **sorted_changes, const knot_zone_keys_t *zone_keys, const knot_dnssec_policy_t *policy) { - if (zone == NULL || in_ch == NULL || out_ch == NULL || - sorted_changes == NULL) { + if (zone == NULL || in_ch == NULL || out_ch == NULL) { return KNOT_EINVAL; } @@ -1398,13 +1414,11 @@ int knot_zone_sign_changeset(const knot_zone_contents_t *zone, ret = knot_changeset_apply((knot_changeset_t *)in_ch, KNOT_CHANGESET_REMOVE, sign_changeset_wrap, &args); - } else { - knot_zone_clear_sorted_changes(args.signed_tree); - hattrie_free(args.signed_tree); - args.signed_tree = NULL; } - *sorted_changes = args.signed_tree; + knot_zone_clear_sorted_changes(args.signed_tree); + hattrie_free(args.signed_tree); + return ret; } @@ -1492,9 +1506,3 @@ int knot_zone_sign_rr_should_be_signed(const knot_node_t *node, return KNOT_EOK; } -void knot_zone_clear_sorted_changes(hattrie_t *t) -{ - if (t) { - hattrie_apply_rev(t, free_helper_trie_node, NULL); - } -} diff --git a/src/knot/dnssec/zone-sign.h b/src/knot/dnssec/zone-sign.h index 752e63f8743d617dba749f7e86a077a511c3d7b1..95bb79060299ab1d3ec92ab7485aed007d08bffe 100644 --- a/src/knot/dnssec/zone-sign.h +++ b/src/knot/dnssec/zone-sign.h @@ -99,7 +99,6 @@ bool knot_zone_sign_soa_expired(const knot_zone_contents_t *zone, * \param zone New zone contents. * \param in_ch Changeset created bvy DDNS or zone-diff * \param out_ch New records will be added to this changeset. - * \param sorted_changes Sorted representation of changes. * \param zone_keys Keys to use for signing. * \param policy DNSSEC signing policy. * @@ -108,7 +107,6 @@ bool knot_zone_sign_soa_expired(const knot_zone_contents_t *zone, int knot_zone_sign_changeset(const knot_zone_contents_t *zone, const knot_changeset_t *in_ch, knot_changeset_t *out_ch, - hattrie_t **sorted_changes, const knot_zone_keys_t *zone_keys, const knot_dnssec_policy_t *policy); @@ -141,8 +139,6 @@ int knot_zone_sign_rr_should_be_signed(const knot_node_t *node, const knot_rrset_t *rrset, hattrie_t *trie, bool *should_sign); -void knot_zone_clear_sorted_changes(hattrie_t *t); - #endif // _KNOT_DNSSEC_ZONE_SIGN_H_ /*! @} */ diff --git a/src/knot/nameserver/update.c b/src/knot/nameserver/update.c index 90cc685df9dab6d8514893f84742ed4adc2c1c5c..c22830777403c0784c334a4624d97ea1e35213e5 100644 --- a/src/knot/nameserver/update.c +++ b/src/knot/nameserver/update.c @@ -230,8 +230,7 @@ int knot_ns_process_update(const knot_pkt_t *query, // 3) Finalize zone dbg_ns_verb("Finalizing updated zone...\n"); - ret = xfrin_finalize_updated_zone(contents_copy, false, - NULL); + ret = xfrin_finalize_updated_zone(contents_copy, false); if (ret != KNOT_EOK) { dbg_ns("Failed to finalize updated zone: %s\n", knot_strerror(ret)); @@ -348,8 +347,6 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, // Apply changeset to zone created by DDNS processing - hattrie_t *sorted_changes = NULL; - if (zone->conf->dnssec_enable) { /*! * Check if the UPDATE changed DNSKEYs. If yes, resign the whole @@ -368,7 +365,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, knot_changesets_get_last(chgsets), sec_ch, KNOT_SOA_SERIAL_KEEP, &refresh_at, - new_serial, &sorted_changes); + new_serial); } if (ret != KNOT_EOK) { @@ -403,10 +400,7 @@ static int zones_process_update_auth(zone_t *zone, knot_pkt_t *query, ret = xfrin_apply_changesets_dnssec_ddns(old_contents, new_contents, sec_chs, - chgsets, - sorted_changes); - knot_zone_clear_sorted_changes(sorted_changes); - hattrie_free(sorted_changes); + chgsets); if (ret != KNOT_EOK) { log_zone_error("%s: Failed to sign incoming update (%s)" "\n", msg, knot_strerror(ret)); diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index c8750f604059ddcda27254fc31d25d5a7aa148a5..b7c76f883fe093447362752d55b8afbfa33e43be 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -2027,7 +2027,7 @@ static int diff_after_load(zone_t *zone, zone_t *old_zone, if (ret == KNOT_EOK) { ret = xfrin_finalize_updated_zone( - zone->contents, true, NULL); + zone->contents, true); } if (ret != KNOT_EOK) { @@ -2115,7 +2115,7 @@ static int store_chgsets_after_load(zone_t *old_zone, zone_t *zone, diff_chs); if (ret == KNOT_EOK) { ret = xfrin_finalize_updated_zone( - zone->contents, true, NULL); + zone->contents, true); } } else { assert(old_zone != NULL); diff --git a/src/knot/updates/xfr-in.c b/src/knot/updates/xfr-in.c index 46a089ed211618a155f3da33584b4371c90209d9..c94f2719e72cb07f10e45983e504ef5aa6db9784 100644 --- a/src/knot/updates/xfr-in.c +++ b/src/knot/updates/xfr-in.c @@ -1506,42 +1506,6 @@ static int xfrin_remove_empty_nodes(knot_zone_contents_t *z) /*----------------------------------------------------------------------------*/ -static int adjust_nsec3_changes(knot_zone_contents_t *contents, - hattrie_t *changes) -{ - if (contents->nsec3_nodes == NULL) { - return KNOT_EOK; - } - hattrie_iter_t *itt = hattrie_iter_begin(changes, false); - if (itt == NULL) { - return KNOT_ENOMEM; - } - while (!hattrie_iter_finished(itt)) { - signed_info_t *val = (signed_info_t *)(*hattrie_iter_val(itt)); - const knot_dname_t *dname = val->dname; - assert(dname); - const knot_dname_t *hash = val->hashed_dname; - if (hash) { - knot_node_t *nsec3_node = - knot_zone_contents_get_nsec3_node(contents, hash); - if (nsec3_node) { - knot_node_t *normal_node = - knot_zone_contents_get_node(contents, - dname); - if (normal_node) { - normal_node->nsec3_node = nsec3_node; - } - } - } - hattrie_iter_next(itt); - } - - hattrie_iter_free(itt); - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - int xfrin_prepare_zone_copy(knot_zone_contents_t *old_contents, knot_zone_contents_t **new_contents) { @@ -1603,8 +1567,7 @@ int xfrin_prepare_zone_copy(knot_zone_contents_t *old_contents, /*----------------------------------------------------------------------------*/ int xfrin_finalize_updated_zone(knot_zone_contents_t *contents_copy, - bool set_nsec3_names, - const hattrie_t *sorted_changes) + bool set_nsec3_names) { if (contents_copy == NULL) { return KNOT_EINVAL; @@ -1632,14 +1595,8 @@ int xfrin_finalize_updated_zone(knot_zone_contents_t *contents_copy, dbg_xfrin("Adjusting zone contents.\n"); if (set_nsec3_names) { - if (sorted_changes) { - ret = knot_zone_contents_adjust_pointers(contents_copy); - ret = adjust_nsec3_changes(contents_copy, - (void *)sorted_changes); - } else { - ret = knot_zone_contents_adjust_full(contents_copy, - NULL, NULL); - } + ret = knot_zone_contents_adjust_full(contents_copy, + NULL, NULL); } else { ret = knot_zone_contents_adjust_pointers(contents_copy); } @@ -1681,8 +1638,7 @@ int xfrin_apply_changesets_directly(knot_zone_contents_t *contents, int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, knot_zone_contents_t *z_new, knot_changesets_t *sec_chsets, - knot_changesets_t *chsets, - const hattrie_t *sorted_changes) + knot_changesets_t *chsets) { if (z_old == NULL || z_new == NULL || sec_chsets == NULL || chsets == NULL) { @@ -1703,7 +1659,7 @@ int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, } const bool handle_nsec3 = true; - ret = xfrin_finalize_updated_zone(z_new, handle_nsec3, sorted_changes); + ret = xfrin_finalize_updated_zone(z_new, handle_nsec3); if (ret != KNOT_EOK) { dbg_xfrin("Failed to finalize updated zone: %s\n", knot_strerror(ret)); @@ -1766,7 +1722,7 @@ int xfrin_apply_changesets(zone_t *zone, */ dbg_xfrin_verb("Finalizing updated zone...\n"); - ret = xfrin_finalize_updated_zone(contents_copy, true, NULL); + ret = xfrin_finalize_updated_zone(contents_copy, true); if (ret != KNOT_EOK) { dbg_xfrin("Failed to finalize updated zone: %s\n", knot_strerror(ret)); diff --git a/src/knot/updates/xfr-in.h b/src/knot/updates/xfr-in.h index df11deefbf57051a9c8eb225ae4f1b3045d08696..474d2a82d3f81869e5d012f7e926f4c2e85e0c35 100644 --- a/src/knot/updates/xfr-in.h +++ b/src/knot/updates/xfr-in.h @@ -159,7 +159,6 @@ int xfrin_apply_changesets(zone_t *zone, * \param z_new Post DDNS/reload zone. * \param sec_chsets Changes with RRSIGs/NSEC(3)s. * \param chsets DDNS/reload changes, for rollback. - * \param sorted_changes Used for node->nsec3 node mapping. * \return KNOT_E* * * This function does not do shallow copy of the zone, as it is already created @@ -169,8 +168,7 @@ int xfrin_apply_changesets(zone_t *zone, int xfrin_apply_changesets_dnssec_ddns(knot_zone_contents_t *z_old, knot_zone_contents_t *z_new, knot_changesets_t *sec_chsets, - knot_changesets_t *chsets, - const hattrie_t *sorted_changes); + knot_changesets_t *chsets); /*! * \brief Applies changesets directly to the zone, without copying it. @@ -196,13 +194,10 @@ int xfrin_prepare_zone_copy(knot_zone_contents_t *old_contents, * \brief Sets pointers and NSEC3 nodes after signing/DDNS. * \param contents_copy Contents to be updated. * \param set_nsec3_names Set to true if NSEC3 hashes should be set. - * \param sorted_changes If this is non-NULL, it is used for normal node->NSEC3 - * node mapping, no hashes are calculated. * \return KNOT_E* */ int xfrin_finalize_updated_zone(knot_zone_contents_t *contents_copy, - bool set_nsec3_names, - const hattrie_t *sorted_changes); + bool set_nsec3_names); int xfrin_switch_zone(zone_t *zone, knot_zone_contents_t *new_contents,