diff --git a/Knot.files b/Knot.files index 873e4f9b89c1904839031dbbd9247fd3c777a7b8..ab823637f9a139d368ef2a2366aaca651eb8381e 100644 --- a/Knot.files +++ b/Knot.files @@ -212,6 +212,8 @@ src/knot/worker/pool.c src/knot/worker/pool.h src/knot/worker/queue.c src/knot/worker/queue.h +src/knot/zone/adjust.c +src/knot/zone/adjust.h src/knot/zone/contents.c src/knot/zone/contents.h src/knot/zone/node.c diff --git a/src/knot/Makefile.inc b/src/knot/Makefile.inc index 36e922810266be5d5f91b39e49122c71fcb0f9a7..cb8a6f9fe097d16225bd6881a966b1bb08460717 100644 --- a/src/knot/Makefile.inc +++ b/src/knot/Makefile.inc @@ -147,6 +147,8 @@ libknotd_la_SOURCES = \ knot/worker/pool.h \ knot/worker/queue.c \ knot/worker/queue.h \ + knot/zone/adjust.c \ + knot/zone/adjust.h \ knot/zone/contents.c \ knot/zone/contents.h \ knot/zone/node.c \ diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c index 8928d9a6451bfa85989ef8671982001a36aced2b..069bb4d3df364100027b07044baaa29cd7b8fa82 100644 --- a/src/knot/dnssec/zone-events.c +++ b/src/knot/dnssec/zone-events.c @@ -50,11 +50,6 @@ static int sign_init(zone_contents_t *zone, zone_sign_flags_t flags, zone_sign_r } } - r = zone_contents_adjust_full(zone); - if (r != KNOT_EOK) { - return r; - } - // update policy based on the zone content update_policy_from_zone(ctx->policy, zone); diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c index 173cb2b42d3c064c2bebe669932985438ac7246a..7f47d4b1b1f280c846a03ae01430bea54fafae92 100644 --- a/src/knot/dnssec/zone-sign.c +++ b/src/knot/dnssec/zone-sign.c @@ -26,6 +26,7 @@ #include "knot/dnssec/key_records.h" #include "knot/dnssec/rrset-sign.h" #include "knot/dnssec/zone-sign.h" +#include "knot/zone/adjust.h" #include "libknot/libknot.h" #include "contrib/dynarray.h" #include "contrib/macros.h" @@ -1197,8 +1198,7 @@ int knot_zone_sign_update(zone_update_t *update, int ret = KNOT_EOK; - - ret = apply_prepare_to_sign(update->a_ctx); + ret = zone_adjust_update(update, adjust_cb_flags_and_additionals, adjust_cb_nsec3_flags); if (ret != KNOT_EOK) { return ret; } diff --git a/src/knot/events/handlers/refresh.c b/src/knot/events/handlers/refresh.c index 37b638800199e19d42b33b6e6398b1b28c101c72..78245a93a4cb9bd912eb1c4b986e78d41f840a88 100644 --- a/src/knot/events/handlers/refresh.c +++ b/src/knot/events/handlers/refresh.c @@ -212,12 +212,7 @@ static int axfr_finalize(struct refresh_data *data) { zone_contents_t *new_zone = data->axfr.zone; - int ret = zone_contents_adjust_full(new_zone); - if (ret != KNOT_EOK) { - return ret; - } - - ret = xfr_validate(new_zone, data); + int ret = xfr_validate(new_zone, data); if (ret != KNOT_EOK) { return ret; } diff --git a/src/knot/updates/apply.c b/src/knot/updates/apply.c index f9c8b3ddd02760d0cf09645a1f57c16b17d8d43e..722687672b5d7431ef1c1279cfea8afd6c27565d 100644 --- a/src/knot/updates/apply.c +++ b/src/knot/updates/apply.c @@ -218,16 +218,30 @@ static int apply_single(apply_ctx_t *ctx, const changeset_t *chset) /* ------------------------------- API -------------------------------------- */ -void apply_init_ctx(apply_ctx_t *ctx, zone_contents_t *contents, uint32_t flags) +int apply_init_ctx(apply_ctx_t *ctx, zone_contents_t *contents, uint32_t flags) { - assert(ctx); + if (ctx == NULL) { + return KNOT_EINVAL; + } ctx->contents = contents; init_list(&ctx->old_data); init_list(&ctx->new_data); + ctx->node_ptrs = zone_tree_create(); + if (ctx->node_ptrs == NULL) { + return KNOT_ENOMEM; + } + ctx->nsec3_ptrs = zone_tree_create(); + if (ctx->nsec3_ptrs == NULL) { + zone_tree_free(&ctx->node_ptrs); + return KNOT_ENOMEM; + } + ctx->flags = flags; + + return KNOT_EOK; } int apply_prepare_zone_copy(zone_contents_t *old_contents, @@ -265,6 +279,8 @@ int apply_add_rr(apply_ctx_t *ctx, const knot_rrset_t *rr) if (node == NULL) { return KNOT_ENOMEM; } + zone_tree_insert(knot_rrset_is_nsec3rel(rr) ? ctx->nsec3_ptrs : ctx->node_ptrs, node); + // re-inserting makes no harm knot_rrset_t changed_rrset = node_rrset(node, rr->type); if (!knot_rrset_empty(&changed_rrset)) { @@ -327,8 +343,9 @@ int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr) return KNOT_EOK; } - zone_tree_t *tree = knot_rrset_is_nsec3rel(rr) ? - contents->nsec3_nodes : contents->nodes; + bool nsec3 = knot_rrset_is_nsec3rel(rr); + zone_tree_insert(nsec3 ? ctx->nsec3_ptrs : ctx->node_ptrs, node); + zone_tree_t *tree = nsec3 ? contents->nsec3_nodes : contents->nodes; knot_rrset_t removed_rrset = node_rrset(node, rr->type); knot_rdata_t *old_data = removed_rrset.rrs.rdata; @@ -364,6 +381,7 @@ int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr) node_remove_rdataset(node, rr->type); // If node is empty now, delete it from zone tree. if (node->rrset_count == 0 && node != contents->apex) { + zone_tree_remove_node(nsec3 ? ctx->nsec3_ptrs: ctx->node_ptrs, node->owner); zone_tree_delete_empty(tree, node); } } @@ -393,11 +411,6 @@ int apply_replace_soa(apply_ctx_t *ctx, const changeset_t *chset) return apply_add_rr(ctx, chset->soa_to); } -int apply_prepare_to_sign(apply_ctx_t *ctx) -{ - return zone_contents_adjust_pointers(ctx->contents); -} - int apply_changesets_directly(apply_ctx_t *ctx, list_t *chsets) { if (ctx == NULL || ctx->contents == NULL || chsets == NULL) { @@ -412,7 +425,7 @@ int apply_changesets_directly(apply_ctx_t *ctx, list_t *chsets) } } - return zone_contents_adjust_full(ctx->contents); + return KNOT_EOK; } int apply_changeset_directly(apply_ctx_t *ctx, const changeset_t *ch) @@ -427,26 +440,18 @@ int apply_changeset_directly(apply_ctx_t *ctx, const changeset_t *ch) return ret; } - ret = zone_contents_adjust_full(ctx->contents); - if (ret != KNOT_EOK) { - update_rollback(ctx); - return ret; - } - return KNOT_EOK; } -int apply_finalize(apply_ctx_t *ctx) -{ - return zone_contents_adjust_full(ctx->contents); -} - void update_cleanup(apply_ctx_t *ctx) { if (ctx == NULL) { return; } + zone_tree_free(&ctx->node_ptrs); + zone_tree_free(&ctx->nsec3_ptrs); + // Delete old RR data rrs_list_clear(&ctx->old_data, NULL); init_list(&ctx->old_data); @@ -461,6 +466,9 @@ void update_rollback(apply_ctx_t *ctx) return; } + zone_tree_free(&ctx->node_ptrs); + zone_tree_free(&ctx->nsec3_ptrs); + // Delete new RR data rrs_list_clear(&ctx->new_data, NULL); init_list(&ctx->new_data); diff --git a/src/knot/updates/apply.h b/src/knot/updates/apply.h index 14538d21e5e54cf7cd68534e5f7001e9fabc0be6..4747081289c095ffa3233218b61a16f12fd9c5c2 100644 --- a/src/knot/updates/apply.h +++ b/src/knot/updates/apply.h @@ -28,6 +28,8 @@ struct apply_ctx { zone_contents_t *contents; list_t old_data; /*!< Old data, to be freed after successful update. */ list_t new_data; /*!< New data, to be freed after failed update. */ + zone_tree_t *node_ptrs; /*!< Just pointers to the affected nodes in contents. */ + zone_tree_t *nsec3_ptrs; /*!< The same for NSEC3 nodes. */ uint32_t flags; }; @@ -39,8 +41,10 @@ typedef struct apply_ctx apply_ctx_t; * \param ctx Context to be initialized. * \param contents Zone contents to apply changes onto. * \param flags Flags to control the application process. + * + * \return KNOT_E* */ -void apply_init_ctx(apply_ctx_t *ctx, zone_contents_t *contents, uint32_t flags); +int apply_init_ctx(apply_ctx_t *ctx, zone_contents_t *contents, uint32_t flags); /*! * \brief Creates a shallow zone contents copy. @@ -83,17 +87,6 @@ int apply_remove_rr(apply_ctx_t *ctx, const knot_rrset_t *rr); */ int apply_replace_soa(apply_ctx_t *ctx, const changeset_t *ch); -/*! - * \brief Prepares the new zone contents for signing. - * - * Adjusted pointers are required for DNSSEC. - * - * \param ctx Apply context. - * - * \return KNOT_E* - */ -int apply_prepare_to_sign(apply_ctx_t *ctx); - /*! * \brief Applies changesets directly to the zone, without copying it. * @@ -116,17 +109,6 @@ int apply_changesets_directly(apply_ctx_t *ctx, list_t *chsets); */ int apply_changeset_directly(apply_ctx_t *ctx, const changeset_t *ch); -/*! - * \brief Finalizes the zone contents for publishing. - * - * Fully adjusts the zone. - * - * \param ctx Apply context. - * - * \return KNOT_E* - */ -int apply_finalize(apply_ctx_t *ctx); - /*! * \brief Cleanups successful zone update. * diff --git a/src/knot/updates/zone-update.c b/src/knot/updates/zone-update.c index cd5d47696f68b08b36b3da694c7a22feb010c902..2007404a0f59e22b5b841f554023469afb843337 100644 --- a/src/knot/updates/zone-update.c +++ b/src/knot/updates/zone-update.c @@ -17,6 +17,7 @@ #include "knot/common/log.h" #include "knot/dnssec/zone-events.h" #include "knot/updates/zone-update.h" +#include "knot/zone/adjust.h" #include "knot/zone/serial.h" #include "knot/zone/zone-diff.h" #include "contrib/mempattern.h" @@ -50,7 +51,11 @@ static int init_incremental(zone_update_t *update, zone_t *zone, zone_contents_t } uint32_t apply_flags = update->flags & UPDATE_STRICT ? APPLY_STRICT : 0; - apply_init_ctx(update->a_ctx, update->new_cont, apply_flags); + ret = apply_init_ctx(update->a_ctx, update->new_cont, apply_flags); + if (ret != KNOT_EOK) { + changeset_clear(&update->change); + return ret; + } /* Copy base SOA RR. */ update->change.soa_from = @@ -73,7 +78,11 @@ static int init_full(zone_update_t *update, zone_t *zone) update->new_cont_deep_copy = true; - apply_init_ctx(update->a_ctx, update->new_cont, 0); + int ret = apply_init_ctx(update->a_ctx, update->new_cont, 0); + if (ret != KNOT_EOK) { + zone_contents_free(update->new_cont); + return ret; + } return KNOT_EOK; } @@ -224,7 +233,12 @@ int zone_update_from_contents(zone_update_t *update, zone_t *zone_without_conten } uint32_t apply_flags = update->flags & UPDATE_STRICT ? APPLY_STRICT : 0; - apply_init_ctx(update->a_ctx, update->new_cont, apply_flags); + int ret = apply_init_ctx(update->a_ctx, update->new_cont, apply_flags); + if (ret != KNOT_EOK) { + changeset_clear(&update->change); + free(update->a_ctx); + return ret; + } return KNOT_EOK; } @@ -584,23 +598,13 @@ int zone_update_increment_soa(zone_update_t *update, conf_t *conf) return set_new_soa(update, conf_opt(&val)); } -static int commit_incremental(conf_t *conf, zone_update_t *update, - zone_contents_t **contents_out) +static int commit_incremental(conf_t *conf, zone_update_t *update) { assert(update); - assert(contents_out); - - if (changeset_empty(&update->change)) { - changeset_clear(&update->change); - if (update->zone->contents == NULL || update->new_cont_deep_copy) { - *contents_out = update->new_cont; - } - return KNOT_EOK; - } zone_contents_t *new_contents = update->new_cont; int ret = KNOT_EOK; - if (zone_update_to(update) == NULL) { + if (zone_update_to(update) == NULL && !changeset_empty(&update->change)) { /* No SOA in the update, create one according to the current policy */ ret = zone_update_increment_soa(update, conf); if (ret != KNOT_EOK) { @@ -609,7 +613,7 @@ static int commit_incremental(conf_t *conf, zone_update_t *update, } } - ret = apply_finalize(update->a_ctx); + ret = zone_adjust_full(new_contents); if (ret != KNOT_EOK) { zone_update_clear(update); return ret; @@ -617,22 +621,19 @@ static int commit_incremental(conf_t *conf, zone_update_t *update, /* Write changes to journal if all went well. */ conf_val_t val = conf_zone_get(conf, C_JOURNAL_CONTENT, update->zone->name); - if (conf_opt(&val) != JOURNAL_CONTENT_NONE) { + if (conf_opt(&val) != JOURNAL_CONTENT_NONE && !changeset_empty(&update->change)) { ret = zone_change_store(conf, update->zone, &update->change); if (ret != KNOT_EOK) { return ret; } } - *contents_out = new_contents; - return KNOT_EOK; } -static int commit_full(conf_t *conf, zone_update_t *update, zone_contents_t **contents_out) +static int commit_full(conf_t *conf, zone_update_t *update) { assert(update); - assert(contents_out); /* Check if we have SOA. We might consider adding full semantic check here. * But if we wanted full sem-check I'd consider being it controlled by a flag @@ -641,7 +642,7 @@ static int commit_full(conf_t *conf, zone_update_t *update, zone_contents_t **co return KNOT_ESEMCHECK; } - int ret = zone_contents_adjust_full(update->new_cont); + int ret = zone_adjust_full(update->new_cont); if (ret != KNOT_EOK) { zone_update_clear(update); return ret; @@ -655,8 +656,6 @@ static int commit_full(conf_t *conf, zone_update_t *update, zone_contents_t **co ret = zone_changes_clear(conf, update->zone); } - *contents_out = update->new_cont; - return ret; } @@ -703,26 +702,25 @@ int zone_update_commit(conf_t *conf, zone_update_t *update) } int ret = KNOT_EOK; - zone_contents_t *new_contents = NULL; if (update->flags & UPDATE_INCREMENTAL) { - ret = commit_incremental(conf, update, &new_contents); + if (changeset_empty(&update->change) && + update->zone->contents != NULL && !update->new_cont_deep_copy) { + changeset_clear(&update->change); + return KNOT_EOK; + } + ret = commit_incremental(conf, update); } else { - ret = commit_full(conf, update, &new_contents); + ret = commit_full(conf, update); } if (ret != KNOT_EOK) { return ret; } - /* If there is anything to change. */ - if (new_contents == NULL) { - return KNOT_EOK; - } - /* Check the zone size. */ conf_val_t val = conf_zone_get(conf, C_MAX_ZONE_SIZE, update->zone->name); size_t size_limit = conf_int(&val); - if (new_contents->size > size_limit) { + if (update->new_cont->size > size_limit) { /* Recoverable error. */ return KNOT_EZONESIZE; } @@ -737,7 +735,7 @@ int zone_update_commit(conf_t *conf, zone_update_t *update) /* Switch zone contents. */ zone_contents_t *old_contents; - old_contents = zone_switch_contents(update->zone, new_contents); + old_contents = zone_switch_contents(update->zone, update->new_cont); /* Sync RCU. */ if (update->flags & UPDATE_FULL) { diff --git a/src/knot/zone/adjust.c b/src/knot/zone/adjust.c new file mode 100644 index 0000000000000000000000000000000000000000..c950a57fbcb0d9066791602f28e41c37bb1ad2d0 --- /dev/null +++ b/src/knot/zone/adjust.c @@ -0,0 +1,395 @@ +/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "knot/zone/adjust.h" + +#include "libdnssec/error.h" +#include "contrib/macros.h" +#include "knot/common/log.h" +#include "knot/dnssec/zone-nsec.h" + +int adjust_cb_flags(zone_node_t *node, const zone_contents_t *zone) +{ + // clear Removed NSEC flag so that no relicts remain + node->flags &= ~NODE_FLAGS_REMOVED_NSEC; + + // check if this node is not a wildcard child of its parent + if (knot_dname_is_wildcard(node->owner)) { + assert(node->parent != NULL); + node->parent->flags |= NODE_FLAGS_WILDCARD_CHILD; + } + + // set flags (delegation point, non-authoritative) + if (node->parent && + (node->parent->flags & NODE_FLAGS_DELEG || + node->parent->flags & NODE_FLAGS_NONAUTH)) { + node->flags |= NODE_FLAGS_NONAUTH; + } else if (node_rrtype_exists(node, KNOT_RRTYPE_NS) && node != zone->apex) { + node->flags |= NODE_FLAGS_DELEG; + } else { + // Default. + node->flags = NODE_FLAGS_AUTH; + } + + return KNOT_EOK; // always returns this value :) +} + +int adjust_cb_point_to_nsec3(zone_node_t *node, const zone_contents_t *zone) +{ + if (!knot_is_nsec3_enabled(zone)) { + node->nsec3_node = NULL; + return KNOT_EOK; + } + node->nsec3_wildcard_prev = NULL; + uint8_t nsec3_name[KNOT_DNAME_MAXLEN]; + int ret = knot_create_nsec3_owner(nsec3_name, sizeof(nsec3_name), node->owner, + zone->apex->owner, &zone->nsec3_params); + if (ret == KNOT_EOK) { + node->nsec3_node = zone_tree_get(zone->nsec3_nodes, nsec3_name); + } + return ret; +} + +int adjust_cb_wildcard_nsec3(zone_node_t *node, const zone_contents_t *zone) +{ + if (!knot_is_nsec3_enabled(zone)) { + node->nsec3_wildcard_prev = NULL; + return KNOT_EOK; + } + + const zone_node_t *ignored; + int ret = KNOT_EOK; + size_t wildcard_size = knot_dname_size(node->owner) + 2; + if (wildcard_size <= KNOT_DNAME_MAXLEN) { + assert(wildcard_size > 2); + knot_dname_t wildcard[wildcard_size]; + memcpy(wildcard, "\x01""*", 2); + memcpy(wildcard + 2, node->owner, wildcard_size - 2); + ret = zone_contents_find_nsec3_for_name(zone, wildcard, &ignored, + (const zone_node_t **)&node->nsec3_wildcard_prev); + if (ret == ZONE_NAME_FOUND) { + node->nsec3_wildcard_prev = NULL; + ret = KNOT_EOK; + } + } + return ret; +} + +static bool nsec3_params_match(const knot_rdataset_t *rrs, + const dnssec_nsec3_params_t *params, + size_t rdata_pos) +{ + assert(rrs != NULL); + assert(params != NULL); + + knot_rdata_t *rdata = knot_rdataset_at(rrs, rdata_pos); + + return (knot_nsec3_alg(rdata) == params->algorithm + && knot_nsec3_iters(rdata) == params->iterations + && knot_nsec3_salt_len(rdata) == params->salt.size + && memcmp(knot_nsec3_salt(rdata), params->salt.data, + params->salt.size) == 0); +} + +int adjust_cb_nsec3_flags(zone_node_t *node, const zone_contents_t *zone) +{ + // check if this node belongs to correct chain + const knot_rdataset_t *nsec3_rrs = node_rdataset(node, KNOT_RRTYPE_NSEC3); + for (uint16_t i = 0; nsec3_rrs != NULL && i < nsec3_rrs->count; i++) { + if (nsec3_params_match(nsec3_rrs, &zone->nsec3_params, i)) { + node->flags |= NODE_FLAGS_IN_NSEC3_CHAIN; + } + } + return KNOT_EOK; +} + +/*! \brief Link pointers to additional nodes for this RRSet. */ +static int discover_additionals(const knot_dname_t *owner, struct rr_data *rr_data, + const zone_contents_t *zone) +{ + assert(rr_data != NULL); + + /* Drop possible previous additional nodes. */ + additional_clear(rr_data->additional); + rr_data->additional = NULL; + + const knot_rdataset_t *rrs = &rr_data->rrs; + uint16_t rdcount = rrs->count; + + uint16_t mandatory_count = 0; + uint16_t others_count = 0; + glue_t mandatory[rdcount]; + glue_t others[rdcount]; + + /* Scan new additional nodes. */ + for (uint16_t i = 0; i < rdcount; i++) { + knot_rdata_t *rdata = knot_rdataset_at(rrs, i); + const knot_dname_t *dname = knot_rdata_name(rdata, rr_data->type); + const zone_node_t *node = NULL, *encloser = NULL; + + /* Try to find node for the dname in the RDATA. */ + zone_contents_find_dname(zone, dname, &node, &encloser, NULL); + if (node == NULL && encloser != NULL + && (encloser->flags & NODE_FLAGS_WILDCARD_CHILD)) { + /* Find wildcard child in the zone. */ + node = zone_contents_find_wildcard_child(zone, encloser); + assert(node != NULL); + } + + if (node == NULL) { + continue; + } + + glue_t *glue; + if ((node->flags & (NODE_FLAGS_DELEG | NODE_FLAGS_NONAUTH)) && + rr_data->type == KNOT_RRTYPE_NS && + knot_dname_in_bailiwick(node->owner, owner) >= 0) { + glue = &mandatory[mandatory_count++]; + glue->optional = false; + } else { + glue = &others[others_count++]; + glue->optional = true; + } + glue->node = node; + glue->ns_pos = i; + } + + /* Store sorted additionals by the type, mandatory first. */ + size_t total_count = mandatory_count + others_count; + if (total_count > 0) { + rr_data->additional = malloc(sizeof(additional_t)); + if (rr_data->additional == NULL) { + return KNOT_ENOMEM; + } + rr_data->additional->count = total_count; + + size_t size = total_count * sizeof(glue_t); + rr_data->additional->glues = malloc(size); + if (rr_data->additional->glues == NULL) { + free(rr_data->additional); + return KNOT_ENOMEM; + } + + size_t mandatory_size = mandatory_count * sizeof(glue_t); + memcpy(rr_data->additional->glues, mandatory, mandatory_size); + memcpy(rr_data->additional->glues + mandatory_count, others, + size - mandatory_size); + } + + return KNOT_EOK; +} + +int adjust_cb_additionals(zone_node_t *node, const zone_contents_t *zone) +{ + /* Lookup additional records for specific nodes. */ + for(uint16_t i = 0; i < node->rrset_count; ++i) { + struct rr_data *rr_data = &node->rrs[i]; + if (knot_rrtype_additional_needed(rr_data->type)) { + int ret = discover_additionals(node->owner, rr_data, zone); + if (ret != KNOT_EOK) { + return ret; + } + } + } + return KNOT_EOK; +} + +int adjust_cb_flags_and_additionals(zone_node_t *node, const zone_contents_t *zone) +{ + int ret = adjust_cb_flags(node, zone); + if (ret == KNOT_EOK) { + ret = adjust_cb_additionals(node, zone); + } + return ret; +} + +int adjust_cb_flags_and_nsec3(zone_node_t *node, const zone_contents_t *zone) +{ + int ret = adjust_cb_flags(node, zone); + if (ret == KNOT_EOK) { + ret = adjust_cb_point_to_nsec3(node, zone); + } + return ret; +} + +int adjust_cb_nsec3_and_additionals(zone_node_t *node, const zone_contents_t *zone) +{ + int ret = adjust_cb_point_to_nsec3(node, zone); + if (ret == KNOT_EOK) { + ret = adjust_cb_wildcard_nsec3(node, zone); + } + if (ret == KNOT_EOK) { + ret = adjust_cb_additionals(node, zone); + } + return ret; +} + +int adjust_cb_void(zone_node_t *node, const zone_contents_t *zone) +{ + UNUSED(node); + UNUSED(zone); + return KNOT_EOK; +} + +typedef struct { + zone_node_t *first_node; + const zone_contents_t *zone; + zone_node_t *previous_node; + size_t zone_size; + uint32_t zone_max_ttl; + adjust_cb_t adjust_cb; + bool adjust_prevs; +} zone_adjust_arg_t; + +static int adjust_single(zone_node_t **tnode, void *data) +{ + assert(tnode != NULL); + assert(data != NULL); + + zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; + zone_node_t *node = *tnode; + + // remember first node + if (args->first_node == NULL) { + args->first_node = node; + } + + // set pointer to previous node + if (args->adjust_prevs) { + node->prev = args->previous_node; + } + + // update remembered previous pointer only if authoritative + if (!(node->flags & NODE_FLAGS_NONAUTH) && node->rrset_count > 0) { + args->previous_node = node; + } + + node_size(node, &args->zone_size); + node_max_ttl(node, &args->zone_max_ttl); + + return args->adjust_cb(node, args->zone); +} + +static int zone_adjust_tree(zone_tree_t *tree, const zone_contents_t *zone, adjust_cb_t adjust_cb, + size_t *tree_size, uint32_t *tree_max_ttl, bool adjust_prevs) +{ + if (zone_tree_is_empty(tree)) { + return KNOT_EOK; + } + + zone_adjust_arg_t arg = { + .zone = zone, + .adjust_cb = adjust_cb, + .adjust_prevs = adjust_prevs + }; + + int ret = zone_tree_apply(tree, adjust_single, &arg); + if (ret != KNOT_EOK) { + return ret; + } + + if (adjust_prevs && arg.first_node != NULL) { + arg.first_node->prev = arg.previous_node; + } + + if (tree_size != NULL) { + *tree_size = arg.zone_size; + } + if (tree_max_ttl != NULL) { + *tree_max_ttl = arg.zone_max_ttl; + } + return KNOT_EOK; +} + +static int load_nsec3param(zone_contents_t *contents) +{ + assert(contents); + assert(contents->apex); + + const knot_rdataset_t *rrs = NULL; + rrs = node_rdataset(contents->apex, KNOT_RRTYPE_NSEC3PARAM); + if (rrs == NULL) { + dnssec_nsec3_params_free(&contents->nsec3_params); + return KNOT_EOK; + } + + if (rrs->count < 1) { + return KNOT_EINVAL; + } + + dnssec_binary_t rdata = { + .size = rrs->rdata->len, + .data = rrs->rdata->data, + }; + + dnssec_nsec3_params_t new_params = { 0 }; + int r = dnssec_nsec3_params_from_rdata(&new_params, &rdata); + if (r != DNSSEC_EOK) { + return KNOT_EMALF; + } + + dnssec_nsec3_params_free(&contents->nsec3_params); + contents->nsec3_params = new_params; + return KNOT_EOK; +} + +int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb) +{ + int ret = load_nsec3param(zone); + if (ret != KNOT_EOK) { + log_zone_error(zone->apex->owner, + "failed to load NSEC3 parameters (%s)", + knot_strerror(ret)); + return ret; + } + zone->dnssec = node_rrtype_is_signed(zone->apex, KNOT_RRTYPE_SOA); + + size_t nodes_size = 0, nsec3_size = 0; + uint32_t nodes_max_ttl = 0, nsec3_max_ttl = 0; + + if (nsec3_cb != NULL) { + ret = zone_adjust_tree(zone->nsec3_nodes, zone, nsec3_cb, &nsec3_size, &nsec3_max_ttl, true); + } + if (ret == KNOT_EOK && nodes_cb != NULL) { + ret = zone_adjust_tree(zone->nodes, zone, nodes_cb, &nodes_size, &nodes_max_ttl, true); + } + if (ret == KNOT_EOK && nodes_cb != NULL && nsec3_cb != NULL) { + zone->size = nodes_size + nsec3_size; + zone->max_ttl = MAX(nodes_max_ttl, nsec3_max_ttl); + } + return ret; +} + +int zone_adjust_update(zone_update_t *update, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb) +{ + int ret = KNOT_EOK; + if (nsec3_cb != NULL) { + ret = zone_adjust_tree(update->a_ctx->nsec3_ptrs, update->new_cont, nsec3_cb, NULL, NULL, false); + } + if (ret == KNOT_EOK && nodes_cb != NULL) { + ret = zone_adjust_tree(update->a_ctx->node_ptrs, update->new_cont, nodes_cb, NULL, NULL, false); + } + return ret; +} + +int zone_adjust_full(zone_contents_t *zone) +{ + int ret = zone_adjust_contents(zone, adjust_cb_flags, adjust_cb_nsec3_flags); + if (ret == KNOT_EOK) { + ret = zone_adjust_contents(zone, adjust_cb_nsec3_and_additionals, NULL); + } + return ret; +} diff --git a/src/knot/zone/adjust.h b/src/knot/zone/adjust.h new file mode 100644 index 0000000000000000000000000000000000000000..5469bed301b575eca19a906fa95deb7c44676361 --- /dev/null +++ b/src/knot/zone/adjust.h @@ -0,0 +1,96 @@ +/* Copyright (C) 2018 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "knot/zone/contents.h" +#include "knot/updates/zone-update.h" + +typedef int (*adjust_cb_t)(zone_node_t *, const zone_contents_t *); + +/* + * \brief Varoius callbacks for adjusting zone node's params and pointers. + * + * \param node Node to be adjusted. Must be already inside the zone contents! + * \param zone Zone being adjusted. + * + * \return KNOT_E* + */ + +// fix NORMAL node flags, like NODE_FLAGS_NONAUTH, NODE_FLAGS_DELEG etc. +int adjust_cb_flags(zone_node_t *node, const zone_contents_t *zone); + +// fix NORMAL node pointer to corresponding NSEC3 node +int adjust_cb_point_to_nsec3(zone_node_t *node, const zone_contents_t *zone); + +// fix NORMAL node pointer to NSEC3 node proving nonexistence of wildcard +int adjust_cb_wildcard_nsec3(zone_node_t *node, const zone_contents_t *zone); + +// fix NSEC3 node flags: NODE_FLAGS_IN_NSEC3_CHAIN +int adjust_cb_nsec3_flags(zone_node_t *node, const zone_contents_t *zone); + +// fix NORMAL node flags to additionals, like NS records and glue... +int adjust_cb_additionals(zone_node_t *node, const zone_contents_t *zone); + +// adjust_cb_flags and adjust_cb_additionals at once +int adjust_cb_flags_and_additionals(zone_node_t *node, const zone_contents_t *zone); + +// adjust_cb_flags and adjust_cb_flags at once +int adjust_cb_flags_and_nsec3(zone_node_t *node, const zone_contents_t *zone); + +// adjust_cb_point_to_nsec3, adjust_cb_wildcard_nsec3 and adjust_cb_additionals at once +int adjust_cb_nsec3_and_additionals(zone_node_t *node, const zone_contents_t *zone); + +// dummy callback, just make prev pointers adjusting and zone size measuring work +int adjust_cb_void(zone_node_t *node, const zone_contents_t *zone); + +/*! + * \brief Apply callback to NSEC3 and NORMAL nodes. Fix PREV pointers and measure zone size. + * + * \param zone Zone to be adjusted. + * \param nodes_cb Callback for NORMAL nodes. + * \param nsec3_cb Callback for NSEC3 nodes. + * + * \return KNOT_E* + */ +int zone_adjust_contents(zone_contents_t *zone, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb); + +/*! + * \brief Apply callback to nodes affected by the zone update. + * + * \note Fixing PREV pointers and zone measurement does not make sense since we are not + * iterating over whole zone. The same applies for callback that reference other + * (unchanged, but indirecty affected) zone nodes. + * + * \param update Zone update being finalized. + * \param nodes_cb Callback for NORMAL nodes. + * \param nsec3_cb Callback for NSEC3 nodes. + * + * \return KNOT_E* + */ +int zone_adjust_update(zone_update_t *update, adjust_cb_t nodes_cb, adjust_cb_t nsec3_cb); + +/*! + * \brief Do a general-purpose full update. + * + * This operates in two phases, first fix basic node flags and prev pointers, + * than nsec3-related pointers and additionals. + * + * \param zone Zone to be adjusted. + * + * \return KNOT_E* + */ +int zone_adjust_full(zone_contents_t *zone); diff --git a/src/knot/zone/contents.c b/src/knot/zone/contents.c index 2446f2e524b9f549483f18ab8ccaeb18887a2406..eef1d113756b29b535acc6422c210bef2868aa71 100644 --- a/src/knot/zone/contents.c +++ b/src/knot/zone/contents.c @@ -17,6 +17,7 @@ #include <assert.h> #include "libdnssec/error.h" +#include "knot/zone/adjust.h" #include "knot/zone/contents.h" #include "knot/common/log.h" #include "knot/dnssec/zone-nsec.h" @@ -29,12 +30,6 @@ typedef struct { void *data; } zone_tree_func_t; -typedef struct { - zone_node_t *first_node; - zone_contents_t *zone; - zone_node_t *previous_node; -} zone_adjust_arg_t; - static int tree_apply_cb(zone_node_t **node, void *data) { if (node == NULL || data == NULL) { @@ -93,311 +88,15 @@ static int destroy_node_rrsets_from_tree(zone_node_t **node, void *data) return KNOT_EOK; } -static int create_nsec3_name(uint8_t *out, size_t out_size, - const zone_contents_t *zone, - const knot_dname_t *name) -{ - assert(out); - assert(zone); - assert(name); - - if (!knot_is_nsec3_enabled(zone)) { - return KNOT_ENSEC3PAR; - } - - return knot_create_nsec3_owner(out, out_size, name, zone->apex->owner, - &zone->nsec3_params); -} - -/*! \brief Link pointers to additional nodes for this RRSet. */ -static int discover_additionals(const knot_dname_t *owner, struct rr_data *rr_data, - zone_contents_t *zone) -{ - assert(rr_data != NULL); - - /* Drop possible previous additional nodes. */ - additional_clear(rr_data->additional); - rr_data->additional = NULL; - - const knot_rdataset_t *rrs = &rr_data->rrs; - uint16_t rdcount = rrs->count; - - uint16_t mandatory_count = 0; - uint16_t others_count = 0; - glue_t mandatory[rdcount]; - glue_t others[rdcount]; - - /* Scan new additional nodes. */ - for (uint16_t i = 0; i < rdcount; i++) { - knot_rdata_t *rdata = knot_rdataset_at(rrs, i); - const knot_dname_t *dname = knot_rdata_name(rdata, rr_data->type); - const zone_node_t *node = NULL, *encloser = NULL, *prev = NULL; - - /* Try to find node for the dname in the RDATA. */ - zone_contents_find_dname(zone, dname, &node, &encloser, &prev); - if (node == NULL && encloser != NULL - && (encloser->flags & NODE_FLAGS_WILDCARD_CHILD)) { - /* Find wildcard child in the zone. */ - node = zone_contents_find_wildcard_child(zone, encloser); - assert(node != NULL); - } - - if (node == NULL) { - continue; - } - - glue_t *glue; - if ((node->flags & (NODE_FLAGS_DELEG | NODE_FLAGS_NONAUTH)) && - rr_data->type == KNOT_RRTYPE_NS && - knot_dname_in_bailiwick(node->owner, owner) >= 0) { - glue = &mandatory[mandatory_count++]; - glue->optional = false; - } else { - glue = &others[others_count++]; - glue->optional = true; - } - glue->node = node; - glue->ns_pos = i; - } - - /* Store sorted additionals by the type, mandatory first. */ - size_t total_count = mandatory_count + others_count; - if (total_count > 0) { - rr_data->additional = malloc(sizeof(additional_t)); - if (rr_data->additional == NULL) { - return KNOT_ENOMEM; - } - rr_data->additional->count = total_count; - - size_t size = total_count * sizeof(glue_t); - rr_data->additional->glues = malloc(size); - if (rr_data->additional->glues == NULL) { - free(rr_data->additional); - return KNOT_ENOMEM; - } - - size_t mandatory_size = mandatory_count * sizeof(glue_t); - memcpy(rr_data->additional->glues, mandatory, mandatory_size); - memcpy(rr_data->additional->glues + mandatory_count, others, - size - mandatory_size); - } - - return KNOT_EOK; -} - -static int adjust_pointers(zone_node_t **tnode, void *data) -{ - assert(tnode != NULL); - assert(data != NULL); - - zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; - zone_node_t *node = *tnode; - - // remember first node - if (args->first_node == NULL) { - args->first_node = node; - } - - // clear Removed NSEC flag so that no relicts remain - node->flags &= ~NODE_FLAGS_REMOVED_NSEC; - - // check if this node is not a wildcard child of its parent - if (knot_dname_is_wildcard(node->owner)) { - assert(node->parent != NULL); - node->parent->flags |= NODE_FLAGS_WILDCARD_CHILD; - } - - // set flags (delegation point, non-authoritative) - if (node->parent && - (node->parent->flags & NODE_FLAGS_DELEG || - node->parent->flags & NODE_FLAGS_NONAUTH)) { - node->flags |= NODE_FLAGS_NONAUTH; - } else if (node_rrtype_exists(node, KNOT_RRTYPE_NS) && node != args->zone->apex) { - node->flags |= NODE_FLAGS_DELEG; - } else { - // Default. - node->flags = NODE_FLAGS_AUTH; - } - - // set pointer to previous node - node->prev = args->previous_node; - - // update remembered previous pointer only if authoritative - if (!(node->flags & NODE_FLAGS_NONAUTH) && node->rrset_count > 0) { - args->previous_node = node; - } - - return KNOT_EOK; -} - -static int adjust_nsec3_pointers(zone_node_t **tnode, void *data) -{ - assert(data != NULL); - assert(tnode != NULL); - - zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; - zone_node_t *node = *tnode; - const zone_node_t *ignored; - - // Connect to NSEC3 node (only if NSEC3 tree is not empty) - node->nsec3_wildcard_prev = NULL; - uint8_t nsec3_name[KNOT_DNAME_MAXLEN]; - int ret = create_nsec3_name(nsec3_name, sizeof(nsec3_name), args->zone, - node->owner); - if (ret == KNOT_EOK) { - node->nsec3_node = zone_tree_get(args->zone->nsec3_nodes, nsec3_name); - - // Connect to NSEC3 node proving nonexistence of wildcard. - size_t wildcard_size = knot_dname_size(node->owner) + 2; - if (wildcard_size <= KNOT_DNAME_MAXLEN) { - assert(wildcard_size > 2); - knot_dname_t wildcard[wildcard_size]; - memcpy(wildcard, "\x01""*", 2); - memcpy(wildcard + 2, node->owner, wildcard_size - 2); - ret = zone_contents_find_nsec3_for_name(args->zone, wildcard, &ignored, - (const zone_node_t **)&node->nsec3_wildcard_prev); - if (ret == ZONE_NAME_FOUND) { - node->nsec3_wildcard_prev = NULL; - ret = KNOT_EOK; - } - } - } else if (ret == KNOT_ENSEC3PAR) { - node->nsec3_node = NULL; - ret = KNOT_EOK; - } - - return ret; -} - static int measure_size(zone_node_t *node, void *data){ - size_t *size = data; - int rrset_count = node->rrset_count; - for (int i = 0; i < rrset_count; i++) { - knot_rrset_t rrset = node_rrset_at(node, i); - *size += knot_rrset_size(&rrset); - } + node_size(node, data); return KNOT_EOK; } static int measure_max_ttl(zone_node_t *node, void *data){ - uint32_t *max = data; - int rrset_count = node->rrset_count; - for (int i = 0; i < rrset_count; i++) { - *max = MAX(*max, node->rrs[i].ttl); - } - return KNOT_EOK; -} - -static bool nsec3_params_match(const knot_rdataset_t *rrs, - const dnssec_nsec3_params_t *params, - size_t rdata_pos) -{ - assert(rrs != NULL); - assert(params != NULL); - - knot_rdata_t *rdata = knot_rdataset_at(rrs, rdata_pos); - - return (knot_nsec3_alg(rdata) == params->algorithm - && knot_nsec3_iters(rdata) == params->iterations - && knot_nsec3_salt_len(rdata) == params->salt.size - && memcmp(knot_nsec3_salt(rdata), params->salt.data, - params->salt.size) == 0); -} - -/*! - * \brief Adjust normal (non NSEC3) node. - * - * Set: - * - pointer to wildcard childs in parent nodes if applicable - * - flags (delegation point, non-authoritative) - * - pointer to previous node - * - parent pointers - * - * \param tnode Zone node to adjust. - * \param data Adjusting parameters (zone_adjust_arg_t *). - */ -static int adjust_normal_node(zone_node_t **tnode, void *data) -{ - assert(tnode != NULL && *tnode); - assert(data != NULL); - - // Do cheap operations first - int ret = adjust_pointers(tnode, data); - if (ret != KNOT_EOK) { - return ret; - } - - zone_adjust_arg_t *arg = data; - measure_size(*tnode, &arg->zone->size); - measure_max_ttl(*tnode, &arg->zone->max_ttl); - - // Connect nodes to their NSEC3 nodes - return adjust_nsec3_pointers(tnode, data); -} - -/*! - * \brief Adjust NSEC3 node. - * - * Set: - * - pointer to previous node - * - pointer to node stored in owner dname - * - * \param tnode Zone node to adjust. - * \param data Adjusting parameters (zone_adjust_arg_t *). - */ -static int adjust_nsec3_node(zone_node_t **tnode, void *data) -{ - assert(data != NULL); - assert(tnode != NULL); - - zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; - zone_node_t *node = *tnode; - - // remember first node - if (args->first_node == NULL) { - args->first_node = node; - } - - // set previous node - node->prev = args->previous_node; - args->previous_node = node; - - measure_size(*tnode, &args->zone->size); - measure_max_ttl(*tnode, &args->zone->max_ttl); - - // check if this node belongs to correct chain - const knot_rdataset_t *nsec3_rrs = node_rdataset(node, KNOT_RRTYPE_NSEC3); - for (uint16_t i = 0; nsec3_rrs != NULL && i < nsec3_rrs->count; i++) { - if (nsec3_params_match(nsec3_rrs, &args->zone->nsec3_params, i)) { - node->flags |= NODE_FLAGS_IN_NSEC3_CHAIN; - } - } - - return KNOT_EOK; -} - -/*! \brief Discover additional records for affected nodes. */ -static int adjust_additional(zone_node_t **tnode, void *data) -{ - assert(data != NULL); - assert(tnode != NULL); - - zone_adjust_arg_t *args = (zone_adjust_arg_t *)data; - zone_node_t *node = *tnode; - - /* Lookup additional records for specific nodes. */ - for(uint16_t i = 0; i < node->rrset_count; ++i) { - struct rr_data *rr_data = &node->rrs[i]; - if (knot_rrtype_additional_needed(rr_data->type)) { - int ret = discover_additionals(node->owner, rr_data, args->zone); - if (ret != KNOT_EOK) { - return ret; - } - } - } - + node_max_ttl(node, data); return KNOT_EOK; } @@ -827,7 +526,7 @@ int zone_contents_find_dname(const zone_contents_t *zone, const zone_node_t **closest, const zone_node_t **previous) { - if (!zone || !name || !match || !closest || !previous) { + if (!zone || !name || !match || !closest) { return KNOT_EINVAL; } @@ -842,7 +541,7 @@ int zone_contents_find_dname(const zone_contents_t *zone, if (found < 0) { // error return found; - } else if (found == 1) { + } else if (found == 1 && previous != NULL) { // exact match assert(node && prev); @@ -851,6 +550,14 @@ int zone_contents_find_dname(const zone_contents_t *zone, *closest = node; *previous = prev; + return ZONE_NAME_FOUND; + } else if (found == 1 && previous == NULL) { + // exact match, zone not adjusted yet + + assert(node); + *match = node; + *closest = node; + return ZONE_NAME_FOUND; } else { // closest match @@ -866,7 +573,9 @@ int zone_contents_find_dname(const zone_contents_t *zone, *match = NULL; *closest = node; - *previous = prev; + if (previous != NULL) { + *previous = prev; + } return ZONE_NAME_NOT_FOUND; } @@ -896,9 +605,13 @@ int zone_contents_find_nsec3_for_name(const zone_contents_t *zone, if (zone_tree_is_empty(zone->nsec3_nodes)) { return KNOT_ENSEC3CHAIN; } + if (!knot_is_nsec3_enabled(zone)) { + return KNOT_ENSEC3PAR; + } uint8_t nsec3_name[KNOT_DNAME_MAXLEN]; - int ret = create_nsec3_name(nsec3_name, sizeof(nsec3_name), zone, name); + int ret = knot_create_nsec3_owner(nsec3_name, sizeof(nsec3_name), + name, zone->apex->owner, &zone->nsec3_params); if (ret != KNOT_EOK) { return ret; } @@ -946,107 +659,6 @@ const zone_node_t *zone_contents_find_wildcard_child(const zone_contents_t *cont return zone_contents_find_node(contents, wildcard); } -static int adjust_nodes(zone_tree_t *nodes, zone_adjust_arg_t *adjust_arg, - zone_tree_apply_cb_t callback) -{ - assert(adjust_arg); - assert(callback); - - if (zone_tree_is_empty(nodes)) { - return KNOT_EOK; - } - - adjust_arg->first_node = NULL; - adjust_arg->previous_node = NULL; - - int ret = zone_tree_apply(nodes, callback, adjust_arg); - - if (adjust_arg->first_node) { - adjust_arg->first_node->prev = adjust_arg->previous_node; - } - - return ret; -} - -static int load_nsec3param(zone_contents_t *contents) -{ - assert(contents); - assert(contents->apex); - - const knot_rdataset_t *rrs = NULL; - rrs = node_rdataset(contents->apex, KNOT_RRTYPE_NSEC3PARAM); - if (rrs == NULL) { - dnssec_nsec3_params_free(&contents->nsec3_params); - return KNOT_EOK; - } - - if (rrs->count < 1) { - return KNOT_EINVAL; - } - - dnssec_binary_t rdata = { - .size = rrs->rdata->len, - .data = rrs->rdata->data, - }; - - dnssec_nsec3_params_t new_params = { 0 }; - int r = dnssec_nsec3_params_from_rdata(&new_params, &rdata); - if (r != DNSSEC_EOK) { - return KNOT_EMALF; - } - - dnssec_nsec3_params_free(&contents->nsec3_params); - contents->nsec3_params = new_params; - return KNOT_EOK; -} - -static int contents_adjust(zone_contents_t *contents, bool normal) -{ - if (contents == NULL || contents->apex == NULL) { - return KNOT_EINVAL; - } - - int ret = load_nsec3param(contents); - if (ret != KNOT_EOK) { - log_zone_error(contents->apex->owner, - "failed to load NSEC3 parameters (%s)", - knot_strerror(ret)); - return ret; - } - - zone_adjust_arg_t arg = { - .zone = contents - }; - - contents->size = 0; - contents->dnssec = node_rrtype_is_signed(contents->apex, KNOT_RRTYPE_SOA); - - // NSEC3 nodes must be adjusted first, because we already need the NSEC3 chain - // to be closed before we adjust NSEC3 pointers in adjust_normal_node - ret = adjust_nodes(contents->nsec3_nodes, &arg, adjust_nsec3_node); - if (ret != KNOT_EOK) { - return ret; - } - - ret = adjust_nodes(contents->nodes, &arg, - normal ? adjust_normal_node : adjust_pointers); - if (ret != KNOT_EOK) { - return ret; - } - - return adjust_nodes(contents->nodes, &arg, adjust_additional); -} - -int zone_contents_adjust_pointers(zone_contents_t *contents) -{ - return contents_adjust(contents, false); -} - -int zone_contents_adjust_full(zone_contents_t *contents) -{ - return contents_adjust(contents, true); -} - int zone_contents_apply(zone_contents_t *contents, zone_contents_apply_cb_t function, void *data) { diff --git a/src/knot/zone/contents.h b/src/knot/zone/contents.h index e8ffa96103675025d39f4534771dac1cd8e80e27..22c25951ca2938fdede76fb3ca476cdc92a786d3 100644 --- a/src/knot/zone/contents.h +++ b/src/knot/zone/contents.h @@ -173,22 +173,6 @@ int zone_contents_find_nsec3_for_name(const zone_contents_t *contents, const zone_node_t *zone_contents_find_wildcard_child(const zone_contents_t *contents, const zone_node_t *parent); -/*! - * \brief Sets parent and previous pointers and node flags. (cheap operation) - * For both normal and NSEC3 tree - * - * \param contents Zone contents to be adjusted. - */ -int zone_contents_adjust_pointers(zone_contents_t *contents); - -/*! - * \brief Sets parent and previous pointers, sets node flags and NSEC3 links. - * This has to be called before the zone can be served. - * - * \param contents Zone contents to be adjusted. - */ -int zone_contents_adjust_full(zone_contents_t *contents); - /*! * \brief Applies the given function to each regular node in the zone. * diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c index 4d920717d4b1072985b8ec9673ec8e8ab51efdb9..117d3c81a5651a6b729758eb87f42a16f81a7428 100644 --- a/src/knot/zone/node.c +++ b/src/knot/zone/node.c @@ -16,6 +16,7 @@ #include "knot/zone/node.h" #include "libknot/libknot.h" +#include "contrib/macros.h" #include "contrib/mempattern.h" void additional_clear(additional_t *additional) @@ -310,3 +311,20 @@ bool node_bitmap_equal(const zone_node_t *a, const zone_node_t *b) } return true; } + +void node_size(const zone_node_t *node, size_t *size) +{ + int rrset_count = node->rrset_count; + for (int i = 0; i < rrset_count; i++) { + knot_rrset_t rrset = node_rrset_at(node, i); + *size += knot_rrset_size(&rrset); + } +} + +void node_max_ttl(const zone_node_t *node, uint32_t *max) +{ + int rrset_count = node->rrset_count; + for (int i = 0; i < rrset_count; i++) { + *max = MAX(*max, node->rrs[i].ttl); + } +} diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h index b380e8fefebcc14b250335b7d5884ca1963b64b0..198785f899ab417baba5c772bd6e4f0ab1808c92 100644 --- a/src/knot/zone/node.h +++ b/src/knot/zone/node.h @@ -276,3 +276,19 @@ static inline knot_rrset_t node_rrset_at(const zone_node_t *node, size_t pos) rrset.additional = rr_data->additional; return rrset; } + +/*! + * \brief Compute node size. + * + * \param node Node in question. + * \param size In/out: node size will be added to this value. + */ +void node_size(const zone_node_t *node, size_t *size); + +/*! + * \brief Compute node maximum TTL. + * + * \param node Node in question. + * \param size In/out: this value will be maximalized with max TTL of node rrsets. + */ +void node_max_ttl(const zone_node_t *node, uint32_t *max); diff --git a/src/knot/zone/zone-load.c b/src/knot/zone/zone-load.c index ff241fae3fa5663b6b00686b169e9fc75e6e888c..ccbb738ac6bdd5446347234bb61b4862d2db3797 100644 --- a/src/knot/zone/zone-load.c +++ b/src/knot/zone/zone-load.c @@ -85,7 +85,11 @@ int zone_load_journal(conf_t *conf, zone_t *zone, zone_contents_t *contents) /* Apply changesets. */ apply_ctx_t a_ctx = { 0 }; - apply_init_ctx(&a_ctx, contents, 0); + ret = apply_init_ctx(&a_ctx, contents, 0); + if (ret != KNOT_EOK) { + changesets_free(&chgs); + return ret; + } ret = apply_changesets_directly(&a_ctx, &chgs); if (ret == KNOT_EOK) { @@ -126,7 +130,12 @@ int zone_load_from_journal(conf_t *conf, zone_t *zone, zone_contents_t **content } apply_ctx_t a_ctx = { 0 }; - apply_init_ctx(&a_ctx, *contents, 0); + ret = apply_init_ctx(&a_ctx, *contents, 0); + if (ret != KNOT_EOK) { + changesets_free(&chgs); + return ret; + } + ret = apply_changesets_directly(&a_ctx, &chgs); if (ret == KNOT_EOK) { log_zone_info(zone->name, "zone loaded from journal, serial %u", diff --git a/src/knot/zone/zone-tree.c b/src/knot/zone/zone-tree.c index 443682f17cf1356b30dc59e496fa17d1e4ab7a8d..b638dd18295a941c1ee357e760070ef3b817a5c7 100644 --- a/src/knot/zone/zone-tree.c +++ b/src/knot/zone/zone-tree.c @@ -114,11 +114,9 @@ int zone_tree_get_less_or_equal(zone_tree_t *tree, } /*! \brief Removes node with the given owner from the zone tree. */ -static void remove_node(zone_tree_t *tree, const knot_dname_t *owner) +void zone_tree_remove_node(zone_tree_t *tree, const knot_dname_t *owner) { - assert(owner); - - if (zone_tree_is_empty(tree)) { + if (zone_tree_is_empty(tree) || owner == NULL) { return; } @@ -159,7 +157,7 @@ void zone_tree_delete_empty(zone_tree_t *tree, zone_node_t *node) } // Delete node - remove_node(tree, node->owner); + zone_tree_remove_node(tree, node->owner); node_free(node, NULL); } } diff --git a/src/knot/zone/zone-tree.h b/src/knot/zone/zone-tree.h index baac735bf34c571ce147bab7f276788493f3e546..e31ae2c22df4439304eb957c91c4d550de586252 100644 --- a/src/knot/zone/zone-tree.h +++ b/src/knot/zone/zone-tree.h @@ -107,6 +107,14 @@ int zone_tree_get_less_or_equal(zone_tree_t *tree, zone_node_t **found, zone_node_t **previous); +/*! + * \brief Remove a node from a tree with no checks. + * + * \param tree The tree to remove from. + * \param owner The node to remove. + */ +void zone_tree_remove_node(zone_tree_t *tree, const knot_dname_t *owner); + /*! * \brief Delete a node that has no RRSets and no children. * diff --git a/src/knot/zone/zonefile.c b/src/knot/zone/zonefile.c index dcbfbaa9c2b39315842d8906dd4ba53d468ef5c6..8caa0ab36c9daab54c512a0c5702f3e341658abe 100644 --- a/src/knot/zone/zonefile.c +++ b/src/knot/zone/zonefile.c @@ -30,6 +30,7 @@ #include "knot/common/log.h" #include "knot/dnssec/zone-nsec.h" #include "knot/zone/semantic-check.h" +#include "knot/zone/adjust.h" #include "knot/zone/contents.h" #include "knot/zone/zonefile.h" #include "knot/zone/zone-dump.h" @@ -225,7 +226,7 @@ zone_contents_t *zonefile_load(zloader_t *loader) goto fail; } - ret = zone_contents_adjust_full(zc->z); + ret = zone_adjust_contents(zc->z, adjust_cb_flags_and_nsec3, adjust_cb_nsec3_flags); if (ret != KNOT_EOK) { ERROR(zname, "failed to finalize zone contents (%s)", knot_strerror(ret)); diff --git a/tests/knot/test_server.h b/tests/knot/test_server.h index 64d69b023bee071e3d047ad7e956af924a327a0b..8107215645c3735a51b023945695fc1b22003c32 100644 --- a/tests/knot/test_server.h +++ b/tests/knot/test_server.h @@ -18,6 +18,7 @@ #include "test_conf.h" #include "knot/server/server.h" +#include "knot/zone/adjust.h" #include "contrib/mempattern.h" /* Some domain names. */ @@ -52,7 +53,7 @@ static inline void create_root_zone(server_t *server, knot_mm_t *mm) knot_rrset_free(soa, mm); /* Bake the zone. */ - zone_contents_adjust_full(root->contents); + (void)zone_adjust_full(root->contents); /* Switch zone db. */ knot_zonedb_free(&server->zone_db);