From f449f278dd3c70e479a035f50a9bb817a9b433ba Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 17:24:08 +0200 Subject: Adding upstream version 3.2.6. Signed-off-by: Daniel Baumann --- src/knot/zone/node.c | 464 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 src/knot/zone/node.c (limited to 'src/knot/zone/node.c') diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c new file mode 100644 index 0000000..291454b --- /dev/null +++ b/src/knot/zone/node.c @@ -0,0 +1,464 @@ +/* Copyright (C) 2021 CZ.NIC, z.s.p.o. + + 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 . + */ + +#include "knot/zone/node.h" +#include "libknot/libknot.h" + +void additional_clear(additional_t *additional) +{ + if (additional == NULL) { + return; + } + + free(additional->glues); + free(additional); +} + +bool additional_equal(additional_t *a, additional_t *b) +{ + if (a == NULL || b == NULL || a->count != b->count) { + return false; + } + for (int i = 0; i < a->count; i++) { + glue_t *ag = &a->glues[i], *bg = &b->glues[i]; + if (ag->ns_pos != bg->ns_pos || ag->optional != bg->optional || + binode_first((zone_node_t *)ag->node) != binode_first((zone_node_t *)bg->node)) { + return false; + } + } + return true; +} + +/*! \brief Clears allocated data in RRSet entry. */ +static void rr_data_clear(struct rr_data *data, knot_mm_t *mm) +{ + knot_rdataset_clear(&data->rrs, mm); + memset(data, 0, sizeof(*data)); +} + +/*! \brief Clears allocated data in RRSet entry. */ +static int rr_data_from(const knot_rrset_t *rrset, struct rr_data *data, knot_mm_t *mm) +{ + int ret = knot_rdataset_copy(&data->rrs, &rrset->rrs, mm); + if (ret != KNOT_EOK) { + return ret; + } + data->ttl = rrset->ttl; + data->type = rrset->type; + data->additional = NULL; + + return KNOT_EOK; +} + +/*! \brief Adds RRSet to node directly. */ +static int add_rrset_no_merge(zone_node_t *node, const knot_rrset_t *rrset, + knot_mm_t *mm) +{ + if (node == NULL) { + return KNOT_EINVAL; + } + + const size_t prev_nlen = node->rrset_count * sizeof(struct rr_data); + const size_t nlen = (node->rrset_count + 1) * sizeof(struct rr_data); + void *p = mm_realloc(mm, node->rrs, nlen, prev_nlen); + if (p == NULL) { + return KNOT_ENOMEM; + } + node->rrs = p; + + // ensure rrsets are sorted by rrtype + struct rr_data *insert_pos = node->rrs, *end = node->rrs + node->rrset_count; + while (insert_pos != end && insert_pos->type < rrset->type) { + insert_pos++; + } + memmove(insert_pos + 1, insert_pos, (uint8_t *)end - (uint8_t *)insert_pos); + + int ret = rr_data_from(rrset, insert_pos, mm); + if (ret != KNOT_EOK) { + return ret; + } + ++node->rrset_count; + + return KNOT_EOK; +} + +/*! \brief Checks if the added RR has the same TTL as the first RR in the node. */ +static bool ttl_changed(struct rr_data *node_data, const knot_rrset_t *rrset) +{ + if (rrset->type == KNOT_RRTYPE_RRSIG || node_data->rrs.count == 0) { + return false; + } + + return rrset->ttl != node_data->ttl; +} + +zone_node_t *node_new(const knot_dname_t *owner, bool binode, bool second, knot_mm_t *mm) +{ + zone_node_t *ret = mm_alloc(mm, (binode ? 2 : 1) * sizeof(zone_node_t)); + if (ret == NULL) { + return NULL; + } + memset(ret, 0, sizeof(*ret)); + + if (owner) { + ret->owner = knot_dname_copy(owner, mm); + if (ret->owner == NULL) { + mm_free(mm, ret); + return NULL; + } + } + + // Node is authoritative by default. + ret->flags = NODE_FLAGS_AUTH; + + if (binode) { + ret->flags |= NODE_FLAGS_BINODE; + if (second) { + ret->flags |= NODE_FLAGS_DELETED; + } + memcpy(ret + 1, ret, sizeof(*ret)); + (ret + 1)->flags ^= NODE_FLAGS_SECOND | NODE_FLAGS_DELETED; + } + + return ret; +} + +zone_node_t *binode_counterpart(zone_node_t *node) +{ + zone_node_t *counterpart = NULL; + + assert(node == NULL || (node->flags & NODE_FLAGS_BINODE) || !(node->flags & NODE_FLAGS_SECOND)); + if (node != NULL && (node->flags & NODE_FLAGS_BINODE)) { + if ((node->flags & NODE_FLAGS_SECOND)) { + counterpart = node - 1; + assert(!(counterpart->flags & NODE_FLAGS_SECOND)); + } else { + counterpart = node + 1; + assert((counterpart->flags & NODE_FLAGS_SECOND)); + } + assert((counterpart->flags & NODE_FLAGS_BINODE)); + } + + return counterpart; +} + +void binode_unify(zone_node_t *node, bool free_deleted, knot_mm_t *mm) +{ + zone_node_t *counter = binode_counterpart(node); + if (counter != NULL) { + if (counter->rrs != node->rrs) { + for (uint16_t i = 0; i < counter->rrset_count; ++i) { + if (!binode_additional_shared(node, counter->rrs[i].type)) { + additional_clear(counter->rrs[i].additional); + } + if (!binode_rdata_shared(node, counter->rrs[i].type)) { + rr_data_clear(&counter->rrs[i], mm); + } + } + mm_free(mm, counter->rrs); + } + if (counter->nsec3_wildcard_name != node->nsec3_wildcard_name) { + free(counter->nsec3_wildcard_name); + } + if (!(counter->flags & NODE_FLAGS_NSEC3_NODE) && node->nsec3_hash != counter->nsec3_hash) { + free(counter->nsec3_hash); + } + assert(((node->flags ^ counter->flags) & NODE_FLAGS_SECOND)); + memcpy(counter, node, sizeof(*counter)); + counter->flags ^= NODE_FLAGS_SECOND; + + if (free_deleted && (node->flags & NODE_FLAGS_DELETED)) { + node_free(node, mm); + } + } +} + +int binode_prepare_change(zone_node_t *node, knot_mm_t *mm) +{ + zone_node_t *counter = binode_counterpart(node); + if (counter != NULL && counter->rrs == node->rrs && counter->rrs != NULL) { + size_t rrlen = sizeof(struct rr_data) * counter->rrset_count; + node->rrs = mm_alloc(mm, rrlen); + if (node->rrs == NULL) { + return KNOT_ENOMEM; + } + memcpy(node->rrs, counter->rrs, rrlen); + } + return KNOT_EOK; +} + +bool binode_rdata_shared(zone_node_t *node, uint16_t type) +{ + if (node == NULL || !(node->flags & NODE_FLAGS_BINODE)) { + return false; + } + zone_node_t *counterpart = ((node->flags & NODE_FLAGS_SECOND) ? node - 1 : node + 1); + if (counterpart->rrs == node->rrs) { + return true; + } + knot_rdataset_t *r1 = node_rdataset(node, type), *r2 = node_rdataset(counterpart, type); + return (r1 != NULL && r2 != NULL && r1->rdata == r2->rdata); +} + +static additional_t *node_type2addit(zone_node_t *node, uint16_t type) +{ + for (uint16_t i = 0; i < node->rrset_count; i++) { + if (node->rrs[i].type == type) { + return node->rrs[i].additional; + } + } + return NULL; +} + +bool binode_additional_shared(zone_node_t *node, uint16_t type) +{ + if (node == NULL || !(node->flags & NODE_FLAGS_BINODE)) { + return false; + } + zone_node_t *counter = ((node->flags & NODE_FLAGS_SECOND) ? node - 1 : node + 1); + if (counter->rrs == node->rrs) { + return true; + } + additional_t *a1 = node_type2addit(node, type), *a2 = node_type2addit(counter, type); + return (a1 == a2); +} + +bool binode_additionals_unchanged(zone_node_t *node, zone_node_t *counterpart) +{ + if (node == NULL || counterpart == NULL) { + return false; + } + if (counterpart->rrs == node->rrs) { + return true; + } + for (int i = 0; i < node->rrset_count; i++) { + struct rr_data *rr = &node->rrs[i]; + if (knot_rrtype_additional_needed(rr->type)) { + knot_rdataset_t *counterr = node_rdataset(counterpart, rr->type); + if (counterr == NULL || counterr->rdata != rr->rrs.rdata) { + return false; + } + } + } + for (int i = 0; i < counterpart->rrset_count; i++) { + struct rr_data *rr = &counterpart->rrs[i]; + if (knot_rrtype_additional_needed(rr->type)) { + knot_rdataset_t *counterr = node_rdataset(node, rr->type); + if (counterr == NULL || counterr->rdata != rr->rrs.rdata) { + return false; + } + } + } + return true; +} + +void node_free_rrsets(zone_node_t *node, knot_mm_t *mm) +{ + if (node == NULL) { + return; + } + + for (uint16_t i = 0; i < node->rrset_count; ++i) { + additional_clear(node->rrs[i].additional); + rr_data_clear(&node->rrs[i], mm); + } + + mm_free(mm, node->rrs); + node->rrs = NULL; + node->rrset_count = 0; +} + +void node_free(zone_node_t *node, knot_mm_t *mm) +{ + if (node == NULL) { + return; + } + + knot_dname_free(node->owner, mm); + + assert((node->flags & NODE_FLAGS_BINODE) || !(node->flags & NODE_FLAGS_SECOND)); + assert(binode_counterpart(node) == NULL || + binode_counterpart(node)->nsec3_wildcard_name == node->nsec3_wildcard_name); + + free(node->nsec3_wildcard_name); + if (!(node->flags & NODE_FLAGS_NSEC3_NODE)) { + free(node->nsec3_hash); + } + + if (node->rrs != NULL) { + mm_free(mm, node->rrs); + } + + mm_free(mm, binode_node(node, false)); +} + +int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm) +{ + if (node == NULL || rrset == NULL) { + return KNOT_EINVAL; + } + + node->flags &= ~NODE_FLAGS_RRSIGS_VALID; + + for (uint16_t i = 0; i < node->rrset_count; ++i) { + if (node->rrs[i].type == rrset->type) { + struct rr_data *node_data = &node->rrs[i]; + const bool ttl_change = ttl_changed(node_data, rrset); + if (ttl_change) { + node_data->ttl = rrset->ttl; + } + + int ret = knot_rdataset_merge(&node_data->rrs, + &rrset->rrs, mm); + if (ret != KNOT_EOK) { + return ret; + } else { + return ttl_change ? KNOT_ETTL : KNOT_EOK; + } + } + } + + // New RRSet (with one RR) + return add_rrset_no_merge(node, rrset, mm); +} + +void node_remove_rdataset(zone_node_t *node, uint16_t type) +{ + if (node == NULL) { + return; + } + + node->flags &= ~NODE_FLAGS_RRSIGS_VALID; + + for (int i = 0; i < node->rrset_count; ++i) { + if (node->rrs[i].type == type) { + if (!binode_additional_shared(node, type)) { + additional_clear(node->rrs[i].additional); + } + if (!binode_rdata_shared(node, type)) { + rr_data_clear(&node->rrs[i], NULL); + } + memmove(node->rrs + i, node->rrs + i + 1, + (node->rrset_count - i - 1) * sizeof(struct rr_data)); + --node->rrset_count; + return; + } + } +} + +int node_remove_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm) +{ + if (node == NULL || rrset == NULL) { + return KNOT_EINVAL; + } + + knot_rdataset_t *node_rrs = node_rdataset(node, rrset->type); + if (node_rrs == NULL) { + return KNOT_ENOENT; + } + + node->flags &= ~NODE_FLAGS_RRSIGS_VALID; + + int ret = knot_rdataset_subtract(node_rrs, &rrset->rrs, mm); + if (ret != KNOT_EOK) { + return ret; + } + + if (node_rrs->count == 0) { + node_remove_rdataset(node, rrset->type); + } + + return KNOT_EOK; +} + +knot_rrset_t *node_create_rrset(const zone_node_t *node, uint16_t type) +{ + if (node == NULL) { + return NULL; + } + + for (uint16_t i = 0; i < node->rrset_count; ++i) { + if (node->rrs[i].type == type) { + knot_rrset_t rrset = node_rrset_at(node, i); + return knot_rrset_copy(&rrset, NULL); + } + } + + return NULL; +} + +knot_rdataset_t *node_rdataset(const zone_node_t *node, uint16_t type) +{ + if (node == NULL) { + return NULL; + } + + for (uint16_t i = 0; i < node->rrset_count; ++i) { + if (node->rrs[i].type == type) { + return &node->rrs[i].rrs; + } + } + + return NULL; +} + +bool node_rrtype_is_signed(const zone_node_t *node, uint16_t type) +{ + if (node == NULL) { + return false; + } + + const knot_rdataset_t *rrsigs = node_rdataset(node, KNOT_RRTYPE_RRSIG); + if (rrsigs == NULL) { + return false; + } + + uint16_t rrsigs_rdata_count = rrsigs->count; + knot_rdata_t *rrsig = rrsigs->rdata; + for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) { + if (knot_rrsig_type_covered(rrsig) == type) { + return true; + } + rrsig = knot_rdataset_next(rrsig); + } + + return false; +} + +bool node_bitmap_equal(const zone_node_t *a, const zone_node_t *b) +{ + if (a == NULL || b == NULL || a->rrset_count != b->rrset_count) { + return false; + } + + uint16_t i; + // heuristics: try if they are equal including order + for (i = 0; i < a->rrset_count; i++) { + if (a->rrs[i].type != b->rrs[i].type) { + break; + } + } + if (i == a->rrset_count) { + return true; + } + + for (i = 0; i < a->rrset_count; i++) { + if (node_rdataset(b, a->rrs[i].type) == NULL) { + return false; + } + } + return true; +} -- cgit v1.2.3