diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c index 785a5bfedb6ff1c316acb6592a861e8efc13c949..abc05a62ce23ff3dbbbe17e070d063a9e82f068f 100644 --- a/src/knot/updates/ddns.c +++ b/src/knot/updates/ddns.c @@ -295,61 +295,70 @@ static int knot_ddns_check_prereq(const knot_rrset_t *rrset, /* ----------------------- changeset lists helpers -------------------------- */ +#warning TODO: Store changesets as a lookup structure + +/*!< \brief Returns true if \a cmp code returns true for one RR in list. */ +#define LIST_MATCH(l, cmp) \ + knot_rr_ln_t *_n; \ + WALK_LIST(_n, l) { \ + const knot_rrset_t *list_rr = _n->rr; \ + if (cmp) { \ + return true; \ + } \ + }; \ + return false; + +/*!< \brief Deletes RR from list if \a cmp code returns true for it. */ +#define LIST_DEL_MATCH(l, cmp) \ + knot_rr_ln_t *_n; \ + node_t *_nxt; \ + WALK_LIST_DELSAFE(_n, _nxt, l) { \ + knot_rrset_t *list_rr = _n->rr; \ + if (cmp) { \ + knot_rrset_free(&list_rr, NULL); \ + rem_node((node_t *)_n); \ + } \ + }; + /*!< \brief Checks whether RR was already removed. */ static bool removed_rr(const knot_changeset_t *changeset, const knot_rrset_t *rr) { - knot_rr_ln_t *n; - WALK_LIST(n, changeset->remove) { - const knot_rrset_t *list_rr = n->rr; - if (knot_rrset_equal(rr, list_rr, KNOT_RRSET_COMPARE_WHOLE)) { - return true; - } - }; + LIST_MATCH(changeset->remove, + knot_rrset_equal(rr, list_rr, KNOT_RRSET_COMPARE_WHOLE)); +} - return false; +/*!< \brief Checks whether any CNAME RR under dname was added. */ +static bool cname_added(const knot_changeset_t *changeset, const knot_dname_t *d) +{ + knot_rrset_t mock_cname; + knot_rrset_init(&mock_cname, (knot_dname_t *)d, + KNOT_RRTYPE_CNAME, KNOT_CLASS_IN); + LIST_MATCH(changeset->add, + knot_rrset_equal(&mock_cname, list_rr, KNOT_RRSET_COMPARE_HEADER)); +} + +/*!< \brief Checks whether any RR under given name was added. */ +static bool name_added(const knot_changeset_t *changeset, const knot_dname_t *d) +{ + LIST_MATCH(changeset->add, knot_dname_is_equal(d, list_rr->owner)); } /*!< \brief Removes RR from list, full equality check. */ static void remove_rr_from_list(list_t *l, const knot_rrset_t *rr) { - knot_rr_ln_t *rr_node = NULL; - node_t *nxt = NULL; - WALK_LIST_DELSAFE(rr_node, nxt, *l) { - knot_rrset_t *rrset = rr_node->rr; - if (knot_rrset_equal(rrset, rr, KNOT_RRSET_COMPARE_WHOLE)) { - knot_rrset_free(&rrset, NULL); - rem_node((node_t *)rr_node); - return; - } - } + LIST_DEL_MATCH(*l, knot_rrset_equal(list_rr, rr, KNOT_RRSET_COMPARE_WHOLE)); } /*!< \brief Removes RR from list, owner and type check. */ static void remove_header_from_list(list_t *l, const knot_rrset_t *rr) { - knot_rr_ln_t *rr_node = NULL; - node_t *nxt = NULL; - WALK_LIST_DELSAFE(rr_node, nxt, *l) { - knot_rrset_t *rrset = rr_node->rr; - if (knot_rrset_equal(rrset, rr, KNOT_RRSET_COMPARE_HEADER)) { - knot_rrset_free(&rrset, NULL); - rem_node((node_t *)rr_node); - } - } + LIST_DEL_MATCH(*l, knot_rrset_equal(list_rr, rr, KNOT_RRSET_COMPARE_HEADER)); } /*!< \brief Removes RR from list, owner check. */ static void remove_owner_from_list(list_t *l, const knot_dname_t *owner) { - knot_rr_ln_t *rr_node = NULL; - node_t *nxt = NULL; - WALK_LIST_DELSAFE(rr_node, nxt, *l) { - knot_rrset_t *rrset = rr_node->rr; - if (knot_dname_is_equal(rrset->owner, owner)) { - knot_rrset_free(&rrset, NULL); - rem_node((node_t *)rr_node); - } - } + LIST_DEL_MATCH(*l, knot_dname_is_equal(list_rr->owner, owner)); } /* --------------------- true/false helper functions ------------------------ */ @@ -393,9 +402,16 @@ static bool should_replace(const knot_rrset_t *chg_rrset, } /*!< \brief Returns true if node will be empty after update application. */ -static bool node_empty(const knot_node_t *node, const knot_changeset_t *changeset) +static bool node_empty(const knot_node_t *node, knot_dname_t *owner, + const knot_changeset_t *changeset) { + if (node == NULL && name_added(changeset, owner)) { + // Node created in update. + return false; + } + if (node == NULL) { + // Node empty. return true; } @@ -406,6 +422,7 @@ static bool node_empty(const knot_node_t *node, const knot_changeset_t *changese for (uint16_t j = 0; j < node_rrset.rrs.rr_count; ++j) { knot_rrset_add_rr_from_rrset(&node_rr, &node_rrset, j, NULL); if (!removed_rr(changeset, &node_rr)) { + // One of the RRs from node was not removed. knot_rrs_clear(&node_rr.rrs, NULL); return false; } @@ -437,9 +454,15 @@ static bool node_contains_rr(const knot_node_t *node, } /*!< \brief Returns true if CNAME is in this node. */ -static bool adding_to_cname(const knot_node_t *node, +static bool adding_to_cname(const knot_dname_t *owner, + const knot_node_t *node, knot_changeset_t *changeset) { + if (cname_added(changeset, owner)) { + // Added a CNAME in this update. + return true; + } + if (node == NULL) { // Node did not exist before update. return false; @@ -451,8 +474,13 @@ static bool adding_to_cname(const knot_node_t *node, return false; } - // Return true if we have not removed CNAME in this update. - return !removed_rr(changeset, &cname); + if (removed_rr(changeset, &cname)) { + // Node did contain CNAME, but it was removed in this update. + return false; + } + + // CNAME present + return true; } /*!< \brief Used to ignore SOA deletions and SOAs with lower serial than zone. */ @@ -481,7 +509,7 @@ static bool skip_record_addition(knot_changeset_t *changeset, if (should_replace(rr, rrset)) { // Replacing singleton RR. knot_rrset_free(&rrset, NULL); - rrset = rr; + rr_node->rr = rr; return true; } else if (knot_rrset_equal(rr, rrset, KNOT_RRSET_COMPARE_WHOLE)) { // Freeing duplication. @@ -599,7 +627,7 @@ static int process_add_cname(const knot_node_t *node, } return add_rr_to_chgset(rr, changeset, NULL); - } else if (!node_empty(node, changeset)) { + } else if (!node_empty(node, rr->owner, changeset)) { // Other occupied node => ignore. return KNOT_EOK; } else { @@ -665,7 +693,7 @@ static int process_add_normal(const knot_node_t *node, knot_changeset_t *changeset, int *apex_ns_rem) { - if (adding_to_cname(node, changeset)) { + if (adding_to_cname(rr->owner, node, changeset)) { // Adding RR to CNAME node, ignore. return KNOT_EOK; } @@ -708,16 +736,8 @@ static int process_rem_rr(const knot_rrset_t *rr, knot_changeset_t *changeset, int *apex_ns_rem) { - // Remove possible previously added RR - remove_rr_from_list(&changeset->add, rr); - if (node == NULL) { - // Removing from node that did not exists before update - return KNOT_EOK; - } - - uint16_t type = rr->type; const bool apex_ns = knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA) && - type == KNOT_RRTYPE_NS; + rr->type == KNOT_RRTYPE_NS; if (apex_ns) { const knot_rrs_t *ns_rrs = knot_node_rrs(node, KNOT_RRTYPE_NS); if (*apex_ns_rem == ns_rrs->rr_count - 1) { @@ -726,6 +746,13 @@ static int process_rem_rr(const knot_rrset_t *rr, } } + // Remove possible previously added RR + remove_rr_from_list(&changeset->add, rr); + if (node == NULL) { + // Removing from node that did not exists before update + return KNOT_EOK; + } + knot_rrset_t to_modify = knot_node_rrset(node, rr->type); if (knot_rrset_empty(&to_modify)) { // No such RRSet @@ -754,12 +781,6 @@ static int process_rem_rrset(const knot_rrset_t *rrset, const knot_node_t *node, knot_changeset_t *changeset) { - // Removing all previously added RRs with this owner and type from changeset - remove_header_from_list(&changeset->add, rrset); - if (node == NULL) { - return KNOT_EOK; - } - if (rrset->type == KNOT_RRTYPE_SOA || knot_rrtype_is_ddns_forbidden(rrset->type)) { // Ignore SOA and DNSSEC removals. @@ -772,6 +793,12 @@ static int process_rem_rrset(const knot_rrset_t *rrset, return KNOT_EOK; } + // Remove all previously added RRs with this owner and type from changeset + remove_header_from_list(&changeset->add, rrset); + if (node == NULL) { + return KNOT_EOK; + } + if (!knot_node_rrtype_exists(node, rrset->type)) { // no such RR, ignore return KNOT_EOK; diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h index f491d8140fd17525bb8d0df0b91e245e99ba79af..b374bdd5e182192862d36274c0906bcb9c00e80d 100644 --- a/src/knot/zone/node.h +++ b/src/knot/zone/node.h @@ -405,6 +405,7 @@ static void inline knot_node_fill_rrset(const knot_node_t *node, uint16_t type, knot_rrset_t *rrset) { if (node == NULL || rrset == NULL) { + knot_rrset_init_empty(rrset); return; } for (uint i = 0; i < node->rrset_count; ++i) {