diff options
Diffstat (limited to 'src/libknot/updates/ddns.c')
-rw-r--r-- | src/libknot/updates/ddns.c | 691 |
1 files changed, 369 insertions, 322 deletions
diff --git a/src/libknot/updates/ddns.c b/src/libknot/updates/ddns.c index 79b28fb..7f4f14f 100644 --- a/src/libknot/updates/ddns.c +++ b/src/libknot/updates/ddns.c @@ -14,16 +14,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> #include <assert.h> +#include <stdlib.h> +#include <inttypes.h> #include "updates/ddns.h" #include "updates/changesets.h" #include "util/debug.h" #include "packet/packet.h" +#include "common.h" #include "consts.h" #include "common/mempattern.h" #include "nameserver/name-server.h" // ns_serial_compare() - TODO: extract #include "updates/xfr-in.h" +#include "common/descriptor.h" /*----------------------------------------------------------------------------*/ // Copied from XFR - maybe extract somewhere else @@ -37,7 +42,7 @@ static int knot_ddns_prereq_check_rrsets(knot_rrset_t ***rrsets, if (ret < 0) { return KNOT_ENOMEM; } - + *rrsets = (knot_rrset_t**)arr; return KNOT_EOK; @@ -55,7 +60,7 @@ static int knot_ddns_prereq_check_dnames(knot_dname_t ***dnames, if (ret < 0) { return KNOT_ENOMEM; } - + *dnames = (knot_dname_t**)arr; return KNOT_EOK; @@ -70,10 +75,9 @@ static int knot_ddns_add_prereq_rrset(const knot_rrset_t *rrset, // check if such RRSet is not already there and merge if needed int ret; for (int i = 0; i < *count; ++i) { - if (knot_rrset_match(rrset, (*rrsets)[i], + if (knot_rrset_equal(rrset, (*rrsets)[i], KNOT_RRSET_COMPARE_HEADER) == 1) { - ret = knot_rrset_merge((void **)&((*rrsets)[i]), - (void **)&rrset); + ret = knot_rrset_merge((*rrsets)[i], rrset); if (ret != KNOT_EOK) { return ret; } else { @@ -132,13 +136,15 @@ static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs, assert(rrset != NULL); if (knot_rrset_ttl(rrset) != 0) { + dbg_ddns("ddns: add_prereq: Wrong TTL.\n"); return KNOT_EMALF; } int ret; if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) { - if (knot_rrset_rdata(rrset) != NULL) { + if (knot_rrset_rdata_rr_count(rrset)) { + dbg_ddns("ddns: add_prereq: Extra data\n"); return KNOT_EMALF; } if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) { @@ -153,7 +159,8 @@ static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs, &prereqs->exist_allocd); } } else if (knot_rrset_class(rrset) == KNOT_CLASS_NONE) { - if (knot_rrset_rdata(rrset) != NULL) { + if (knot_rrset_rdata_rr_count(rrset)) { + dbg_ddns("ddns: add_prereq: Extra data\n"); return KNOT_EMALF; } if (knot_rrset_type(rrset) == KNOT_RRTYPE_ANY) { @@ -173,6 +180,7 @@ static int knot_ddns_add_prereq(knot_ddns_prereq_t *prereqs, &prereqs->exist_full_count, &prereqs->exist_full_allocd); } else { + dbg_ddns("ddns: add_prereq: Bad class.\n"); return KNOT_EMALF; } @@ -202,8 +210,8 @@ static int knot_ddns_check_remove_rr(knot_changeset_t *changeset, &changeset->add_count, i); dbg_ddns_detail("Removed RRSet from " "chgset:\n"); - knot_rrset_dump(remove, 0); - knot_rrset_deep_free(&remove, 1, 1, 1); + knot_rrset_dump(remove); + knot_rrset_deep_free(&remove, 1, 1); } } else if (knot_rrset_type(rr) == knot_rrset_type(changeset->add[i])){ @@ -213,15 +221,14 @@ static int knot_ddns_check_remove_rr(knot_changeset_t *changeset, assert(knot_rrset_class(rr) == KNOT_CLASS_NONE); // Removing specific RR from a RRSet - knot_rdata_t *rdata = knot_rrset_remove_rdata( - changeset->add[i], - knot_rrset_rdata(rr)); - - dbg_ddns_detail("Removed RR from chgset: \n"); - knot_rdata_dump(rdata, knot_rrset_type(rr), 0); + int ret = + knot_rrset_remove_rr_using_rrset_del(changeset->add[i], rr); + if (ret != KNOT_EOK) { + dbg_ddns("ddns: Could not remove RDATA from RRSet (%s).\n", + knot_strerror(ret)); + return ret; + } - knot_rdata_deep_free(&rdata, - knot_rrset_type(changeset->add[i]), 1); // if the RRSet is empty, remove from changeset if (knot_rrset_rdata_rr_count(changeset->add[i]) == 0) { @@ -231,7 +238,7 @@ static int knot_ddns_check_remove_rr(knot_changeset_t *changeset, &changeset->add_count, i); dbg_ddns_detail("RRSet empty, removing." "\n"); - knot_rrset_deep_free(&remove, 1, 1, 1); + knot_rrset_deep_free(&remove, 1, 1); } } } @@ -257,7 +264,7 @@ static int knot_ddns_add_update(knot_changeset_t *changeset, * copy. */ *rrset_copy = NULL; - ret = knot_rrset_deep_copy(rrset, rrset_copy, 0); + ret = knot_rrset_deep_copy(rrset, rrset_copy, 1); if (ret != KNOT_EOK) { return ret; } @@ -286,7 +293,7 @@ static int knot_ddns_add_update(knot_changeset_t *changeset, ret = knot_ddns_check_remove_rr(changeset, *rrset_copy); if (ret != KNOT_EOK) { - knot_rrset_deep_free(rrset_copy, 1, 1, 1); + knot_rrset_deep_free(rrset_copy, 1, 1); return ret; } @@ -307,7 +314,7 @@ static int knot_ddns_check_exist(const knot_zone_contents_t *zone, assert(zone != NULL); assert(rrset != NULL); assert(rcode != NULL); - assert(knot_rrset_rdata(rrset) == NULL); + assert(knot_rrset_rdata_rr_count(rrset) == 0); assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); assert(knot_rrset_ttl(rrset) == 0); assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY); @@ -334,13 +341,13 @@ static int knot_ddns_check_exist(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, - const knot_rrset_t *rrset, + const knot_rrset_t *rrset, knot_rcode_t *rcode) { assert(zone != NULL); assert(rrset != NULL); assert(rcode != NULL); - assert(knot_rrset_rdata(rrset) == NULL); + assert(knot_rrset_rdata_rr_count(rrset) == 0); assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); assert(knot_rrset_ttl(rrset) == 0); assert(knot_rrset_class(rrset) == KNOT_CLASS_ANY); @@ -367,7 +374,7 @@ static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, assert(knot_rrset_type(found) == knot_rrset_type(rrset)); assert(knot_dname_compare(knot_rrset_owner(found), knot_rrset_owner(rrset)) == 0); - if (knot_rrset_compare_rdata(found, rrset) <= 0) { + if (knot_rrset_rdata_equal(found, rrset) <= 0) { *rcode = KNOT_RCODE_NXRRSET; return KNOT_EPREREQ; } @@ -379,13 +386,13 @@ static int knot_ddns_check_exist_full(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone, - const knot_rrset_t *rrset, + const knot_rrset_t *rrset, knot_rcode_t *rcode) { assert(zone != NULL); assert(rrset != NULL); assert(rcode != NULL); - assert(knot_rrset_rdata(rrset) == NULL); + assert(knot_rrset_rdata_rr_count(rrset) == 0); assert(knot_rrset_type(rrset) != KNOT_RRTYPE_ANY); assert(knot_rrset_ttl(rrset) == 0); assert(knot_rrset_class(rrset) == KNOT_CLASS_NONE); @@ -404,7 +411,7 @@ static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone, } else if (knot_node_rrset(node, knot_rrset_type(rrset)) == NULL) { return KNOT_EOK; } - + /* RDATA is always empty for simple RRset checks. */ *rcode = KNOT_RCODE_YXRRSET; @@ -414,7 +421,7 @@ static int knot_ddns_check_not_exist(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ static int knot_ddns_check_in_use(const knot_zone_contents_t *zone, - const knot_dname_t *dname, + const knot_dname_t *dname, knot_rcode_t *rcode) { assert(zone != NULL); @@ -444,7 +451,7 @@ static int knot_ddns_check_in_use(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone, - const knot_dname_t *dname, + const knot_dname_t *dname, knot_rcode_t *rcode) { assert(zone != NULL); @@ -474,7 +481,7 @@ static int knot_ddns_check_not_in_use(const knot_zone_contents_t *zone, /* API functions */ /*----------------------------------------------------------------------------*/ -int knot_ddns_check_zone(const knot_zone_contents_t *zone, +int knot_ddns_check_zone(const knot_zone_contents_t *zone, const knot_packet_t *query, knot_rcode_t *rcode) { if (zone == NULL || query == NULL || rcode == NULL) { @@ -511,7 +518,7 @@ int knot_ddns_process_prereqs(const knot_packet_t *query, if (query == NULL || prereqs == NULL || rcode == NULL) { return KNOT_EINVAL; } - + dbg_ddns("Processing prerequisities.\n"); // allocate space for the prerequisities @@ -523,6 +530,8 @@ int knot_ddns_process_prereqs(const knot_packet_t *query, for (int i = 0; i < knot_packet_answer_rrset_count(query); ++i) { // we must copy the RRSets, because all those stored in the // packet will be destroyed + dbg_ddns_detail("Creating prereqs from following RRSet:\n"); + knot_rrset_dump(knot_packet_answer_rrset(query, i)); ret = knot_ddns_add_prereq(*prereqs, knot_packet_answer_rrset(query, i), knot_packet_qclass(query)); @@ -545,7 +554,7 @@ int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, knot_ddns_prereq_t **prereqs, knot_rcode_t *rcode) { int i, ret; - + dbg_ddns("Checking 'exist' prerequisities.\n"); for (i = 0; i < (*prereqs)->exist_count; ++i) { @@ -599,7 +608,7 @@ int knot_ddns_check_prereqs(const knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ static int knot_ddns_check_update(const knot_rrset_t *rrset, - const knot_packet_t *query, + const knot_packet_t *query, knot_rcode_t *rcode) { /* Accept both subdomain and dname match. */ @@ -618,7 +627,7 @@ static int knot_ddns_check_update(const knot_rrset_t *rrset, return KNOT_EMALF; } } else if (knot_rrset_class(rrset) == KNOT_CLASS_ANY) { - if (knot_rrset_rdata(rrset) != NULL + if (knot_rrset_rdata_rr_count(rrset) || (knot_rrtype_is_metatype(knot_rrset_type(rrset)) && knot_rrset_type(rrset) != KNOT_RRTYPE_ANY)) { *rcode = KNOT_RCODE_FORMERR; @@ -658,7 +667,7 @@ int knot_ddns_process_update(const knot_zone_contents_t *zone, KNOT_RRTYPE_SOA); knot_rrset_t *soa_begin = NULL; knot_rrset_t *soa_end = NULL; - ret = knot_rrset_deep_copy(soa, &soa_begin, 0); + ret = knot_rrset_deep_copy(soa, &soa_begin, 1); if (ret == KNOT_EOK) { knot_changeset_store_soa(&changeset->soa_from, &changeset->serial_from, soa_begin); @@ -668,7 +677,7 @@ int knot_ddns_process_update(const knot_zone_contents_t *zone, } /* Current SERIAL */ - int64_t sn = knot_rdata_soa_serial(knot_rrset_rdata(soa_begin)); + int64_t sn = knot_rrset_rdata_soa_serial(soa_begin); int64_t sn_new; /* Incremented SERIAL * We must set it now to be able to compare SERIAL from SOAs in the @@ -721,10 +730,9 @@ int knot_ddns_process_update(const knot_zone_contents_t *zone, * RRSet. This should be handled somehow. */ if (knot_rrset_type(rrset) == KNOT_RRTYPE_SOA - && ns_serial_compare(knot_rdata_soa_serial( - knot_rrset_rdata(rrset)), + && ns_serial_compare(knot_rrset_rdata_soa_serial(rrset), sn_new) > 0) { - sn_new = knot_rdata_soa_serial(knot_rrset_rdata(rrset)); + sn_new = knot_rrset_rdata_soa_serial(rrset); soa_end = (knot_rrset_t *)rrset_copy; } } @@ -734,8 +742,12 @@ int knot_ddns_process_update(const knot_zone_contents_t *zone, /* If not set */ assert(sn_new == (uint32_t)sn + 1); ret = knot_rrset_deep_copy(soa, &soa_end, 1); - knot_rdata_t *rd = knot_rrset_get_rdata(soa_end); - knot_rdata_soa_serial_set(rd, sn_new); + if (ret != KNOT_EOK) { + dbg_ddns("ddns: Could not copy SOA RRSet (%s).\n ", + knot_strerror(ret)); + return ret; + } + knot_rrset_rdata_soa_serial_set(soa_end, sn_new); } knot_changeset_store_soa(&changeset->soa_to, @@ -754,17 +766,17 @@ void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq) int i; for (i = 0; i < (*prereq)->exist_count; ++i) { - knot_rrset_deep_free(&(*prereq)->exist[i], 1, 1, 1); + knot_rrset_deep_free(&(*prereq)->exist[i], 1, 1); } free((*prereq)->exist); for (i = 0; i < (*prereq)->exist_full_count; ++i) { - knot_rrset_deep_free(&(*prereq)->exist_full[i], 1, 1, 1); + knot_rrset_deep_free(&(*prereq)->exist_full[i], 1, 1); } free((*prereq)->exist_full); for (i = 0; i < (*prereq)->not_exist_count; ++i) { - knot_rrset_deep_free(&(*prereq)->not_exist[i], 1, 1, 1); + knot_rrset_deep_free(&(*prereq)->not_exist[i], 1, 1); } free((*prereq)->not_exist); @@ -788,7 +800,7 @@ void knot_ddns_prereqs_free(knot_ddns_prereq_t **prereq) static int knot_ddns_check_remove_rr2(knot_changeset_t *changeset, const knot_dname_t *owner, - uint16_t type, const knot_rdata_t *rdata, + const knot_rrset_t *rr, knot_rrset_t ***removed, size_t *removed_count) { @@ -800,6 +812,7 @@ static int knot_ddns_check_remove_rr2(knot_changeset_t *changeset, *removed = (knot_rrset_t **)malloc(changeset->add_count * sizeof(knot_rrset_t *)); if (*removed == NULL) { + ERR_ALLOC_FAILED; return KNOT_ENOMEM; } @@ -814,27 +827,30 @@ static int knot_ddns_check_remove_rr2(knot_changeset_t *changeset, dbg_ddns_verb("Removing possible redundant RRs from changeset.\n"); for (int i = 0; i < changeset->add_count; ++i) { // Removing RR(s) from this owner - if (knot_dname_compare(knot_rrset_owner(changeset->add[i]), - owner) == 0) { +dbg_ddns_exec_detail( + char *name = knot_dname_to_str(changeset->add[i]->owner); + dbg_ddns_detail("ddns: remove_rr2: Removing RR of type=%u owned by %s\n", + knot_rrset_type(changeset->add[i]), name); + free(name); +); + if (knot_dname_compare_non_canon(knot_rrset_owner(changeset->add[i]), + owner) == 0) { // Removing one or all RRSets - if (rdata == NULL - && (type == knot_rrset_type(changeset->add[i]) - || type == KNOT_RRTYPE_ANY)) { + if ((knot_rrset_rdata_rr_count(rr) == 0) + && (knot_rrset_type(rr) == knot_rrset_type(changeset->add[i]) + || knot_rrset_type(rr) == KNOT_RRTYPE_ANY)) { dbg_ddns_detail("Removing one or all RRSets\n"); - remove = knot_changeset_remove_rr( - changeset->add, - &changeset->add_count, i); - } else if (type == knot_rrset_type(changeset->add[i])) { + remove = knot_changeset_remove_rr( + changeset->add, + &changeset->add_count, i); + } else if (knot_rrset_type(rr) == + knot_rrset_type(changeset->add[i])) { // Removing specific RR - assert(rdata != NULL); - - knot_rrtype_descriptor_t *desc = - knot_rrtype_descriptor_by_type(type); + assert(knot_rrset_rdata_rr_count(rr) != 0); // We must check if the RDATA match - if (knot_rdata_compare(rdata, - knot_rrset_rdata(changeset->add[i]), - desc->wireformat)) { + if (knot_rrset_rdata_equal(rr, + changeset->add[i])) { remove = knot_changeset_remove_rr( changeset->add, &changeset->add_count, i); @@ -842,7 +858,7 @@ static int knot_ddns_check_remove_rr2(knot_changeset_t *changeset, } dbg_ddns_detail("Removed RRSet from chgset:\n"); - knot_rrset_dump(remove, 0); + knot_rrset_dump(remove); (*removed)[(*removed_count)++] = remove; } } @@ -861,19 +877,19 @@ static void knot_ddns_check_add_rr(knot_changeset_t *changeset, assert(removed != NULL); *removed = NULL; - + dbg_ddns_verb("Removing possible redundant RRs from changeset.\n"); for (int i = 0; i < changeset->remove_count; ++i) { - /* Just check exact match, the changeset contains only + /* Just check exact match, the changeset contains only * whole RRs that have been removed. */ - if (knot_rrset_match(rr, changeset->remove[i], + if (knot_rrset_equal(rr, changeset->remove[i], KNOT_RRSET_COMPARE_WHOLE) == 1) { *removed = knot_changeset_remove_rr( changeset->remove, &changeset->remove_count, i); dbg_ddns_detail("Removed RRSet from chgset:\n"); - knot_rrset_dump(*removed, 0); + knot_rrset_dump(*removed); break; } } @@ -887,8 +903,8 @@ static int knot_ddns_rr_is_nsec3(const knot_rrset_t *rr) if ((knot_rrset_type(rr) == KNOT_RRTYPE_NSEC3) || (knot_rrset_type(rr) == KNOT_RRTYPE_RRSIG - && knot_rrset_rdata(rr) - && knot_rdata_rrsig_type_covered(knot_rrset_rdata(rr)) + && knot_rrset_rdata_rr_count(rr) + && knot_rrset_rdata_rrsig_type_covered(rr) == KNOT_RRTYPE_NSEC3)) { dbg_ddns_detail("This is NSEC3-related RRSet.\n"); @@ -917,9 +933,9 @@ static knot_node_t *knot_ddns_add_new_node(knot_zone_contents_t *zone, // insert the node into zone structures and create parents if // necessary if (is_nsec3) { - ret = knot_zone_contents_add_nsec3_node(zone, node, 1, 0, 1); + ret = knot_zone_contents_add_nsec3_node(zone, node, 1, 0); } else { - ret = knot_zone_contents_add_node(zone, node, 1, 0, 1); + ret = knot_zone_contents_add_node(zone, node, 1, 0); } if (ret != KNOT_EOK) { dbg_xfrin("Failed to add new node to zone contents.\n"); @@ -961,7 +977,7 @@ static knot_node_t *knot_ddns_get_node(knot_zone_contents_t *zone, /*----------------------------------------------------------------------------*/ -static int knot_ddns_process_add_cname(knot_node_t *node, +static int knot_ddns_process_add_cname(knot_node_t *node, const knot_rrset_t *rr, knot_changeset_t *changeset, knot_changes_t *changes) @@ -970,29 +986,29 @@ static int knot_ddns_process_add_cname(knot_node_t *node, assert(rr != NULL); assert(changeset != NULL); assert(changes != NULL); - + dbg_ddns_detail("Adding CNAME RR.\n"); - + int ret = 0; - + /* Get the current CNAME RR from the node. */ knot_rrset_t *removed = knot_node_get_rrset(node, KNOT_RRTYPE_CNAME); - + if (removed != NULL) { /* If they are identical, ignore. */ - if (knot_rrset_match(removed, rr, KNOT_RRSET_COMPARE_WHOLE) + if (knot_rrset_equal(removed, rr, KNOT_RRSET_COMPARE_WHOLE) == 1) { dbg_ddns_verb("CNAME identical to one in the node.\n"); return 1; } - + /*! \note * Together with the removed CNAME we remove also its RRSIGs as * they would not be valid for the new CNAME anyway. * * \todo Document!! */ - + /* b) Store it to 'changes', together with its RRSIGs. */ ret = knot_changes_add_old_rrsets(&removed, 1, changes, 1); if (ret != KNOT_EOK) { @@ -1002,41 +1018,40 @@ static int knot_ddns_process_add_cname(knot_node_t *node, } /* c) And remove it from the node. */ - (void)knot_node_remove_rrset(node, KNOT_RRTYPE_CNAME); - + UNUSED(knot_node_remove_rrset(node, KNOT_RRTYPE_CNAME)); + /* d) Check if this CNAME was not previously added by - * the UPDATE. If yes, remove it from the ADD + * the UPDATE. If yes, remove it from the ADD * section and do not add it to the REMOVE section. */ knot_rrset_t **from_chgset = NULL; size_t from_chgset_count = 0; ret = knot_ddns_check_remove_rr2( changeset, knot_rrset_owner(removed), - KNOT_RRTYPE_CNAME, knot_rrset_rdata(removed), - &from_chgset, &from_chgset_count); + removed, &from_chgset, &from_chgset_count); if (ret != KNOT_EOK) { dbg_ddns("Failed to remove possible redundant " - "RRs from ADD section: %s.\n", + "RRs from ADD section: %s.\n", knot_strerror(ret)); free(from_chgset); return ret; } - + assert(from_chgset_count <= 1); - + if (from_chgset_count == 1) { /* Just delete the RRSet. */ - knot_rrset_deep_free(&(from_chgset[0]), 1, 1, 1); + knot_rrset_deep_free(&(from_chgset[0]), 1, 1); /* Okay, &(from_chgset[0]) is basically equal to just * from_chgset, but it's more clear this way that we are * deleting the first RRSet in the array ;-) */ } else { - /* Otherwise copy the removed CNAME and add it + /* Otherwise copy the removed CNAME and add it * to the REMOVE section. */ knot_rrset_t *removed_copy; - ret = knot_rrset_deep_copy(removed, + ret = knot_rrset_deep_copy(removed, &removed_copy, 1); if (ret != KNOT_EOK) { dbg_ddns("Failed to copy removed RRSet:" @@ -1044,15 +1059,15 @@ static int knot_ddns_process_add_cname(knot_node_t *node, free(from_chgset); return ret; } - + ret = knot_changeset_add_rrset( &changeset->remove, &changeset->remove_count, &changeset->remove_allocated, removed_copy); if (ret != KNOT_EOK) { - knot_rrset_deep_free(&removed_copy, - 1, 1, 1); + knot_rrset_deep_free(&removed_copy, + 1, 1); dbg_ddns("Failed to add removed CNAME " "to changeset: %s\n", knot_strerror(ret)); @@ -1065,50 +1080,48 @@ static int knot_ddns_process_add_cname(knot_node_t *node, /* 2) Other occupied node => ignore. */ return 1; } - + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -static int knot_ddns_process_add_soa(knot_node_t *node, +static int knot_ddns_process_add_soa(knot_node_t *node, const knot_rrset_t *rr, knot_changes_t *changes) { assert(node != NULL); assert(rr != NULL); assert(changes != NULL); - + dbg_ddns_detail("Adding SOA RR.\n"); - + int ret = 0; - + /* - * Just remove the SOA from the node, together with its RRSIGs. + * Just remove the SOA from the node, together with its RRSIGs. * Adding the RR is done in the caller function. Note that only SOA * with larger SERIAL than the current one will get to these functions, * so we don't have to check the SERIALS again. But an assert won't * hurt. */ - + /* Get the current SOA RR from the node. */ knot_rrset_t *removed = knot_node_get_rrset(node, KNOT_RRTYPE_SOA); - + if (removed != NULL) { dbg_ddns_detail("Found SOA in the node.\n"); /* If they are identical, ignore. */ - if (knot_rrset_match(removed, rr, KNOT_RRSET_COMPARE_WHOLE) + if (knot_rrset_equal(removed, rr, KNOT_RRSET_COMPARE_WHOLE) == 1) { dbg_ddns_detail("Old and new SOA identical.\n"); return 1; } - + /* Check that the serial is indeed larger than the current one*/ - assert(ns_serial_compare(knot_rdata_soa_serial( - knot_rrset_rdata(removed)), - knot_rdata_soa_serial( - knot_rrset_rdata(rr))) < 0); - + assert(ns_serial_compare(knot_rrset_rdata_soa_serial(removed), + knot_rrset_rdata_soa_serial(rr)) < 0); + /* 1) Store it to 'changes', together with its RRSIGs. */ ret = knot_changes_add_old_rrsets( &removed, 1, changes, 1); @@ -1119,15 +1132,15 @@ static int knot_ddns_process_add_soa(knot_node_t *node, } /* 2) And remove it from the node. */ - (void)knot_node_remove_rrset(node, KNOT_RRTYPE_SOA); - + UNUSED(knot_node_remove_rrset(node, KNOT_RRTYPE_SOA)); + /* No changeset processing needed in this case. */ } else { dbg_ddns_detail("No SOA in node, ignoring.\n"); /* If there is no SOA in the node, ignore. */ return 1; } - + return KNOT_EOK; } @@ -1139,40 +1152,40 @@ static int knot_ddns_add_rr_new_normal(knot_node_t *node, knot_rrset_t *rr_copy, assert(node != NULL); assert(rr_copy != NULL); assert(changes != NULL); - + dbg_ddns_verb("Adding normal RR.\n"); - + /* Add the RRSet to 'changes'. */ int ret = knot_changes_add_new_rrsets(&rr_copy, 1, changes, 1); if (ret != KNOT_EOK) { - knot_rrset_deep_free(&rr_copy, 1, 1, 1); + knot_rrset_deep_free(&rr_copy, 1, 1); dbg_ddns("Failed to store copy of the added RR: " "%s\n", knot_strerror(ret)); return ret; } - + /* Add the RRSet to the node. */ - ret = knot_node_add_rrset(node, rr_copy, 0); + ret = knot_node_add_rrset_no_merge(node, rr_copy); if (ret != KNOT_EOK) { dbg_ddns("Failed to add RR to node: %s\n", knot_strerror(ret)); return ret; } - + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ static int knot_ddns_add_rr_new_rrsig(knot_node_t *node, knot_rrset_t *rr_copy, - knot_changes_t *changes, + knot_changes_t *changes, uint16_t type_covered) { assert(node != NULL); assert(rr_copy != NULL); assert(changes != NULL); - + dbg_ddns_verb("Adding RRSIG RR.\n"); - + /* Create RRSet to be covered by the RRSIG. */ knot_rrset_t *covered_rrset = knot_rrset_new( knot_rrset_get_owner(rr_copy), type_covered, @@ -1181,47 +1194,47 @@ static int knot_ddns_add_rr_new_rrsig(knot_node_t *node, knot_rrset_t *rr_copy, if (covered_rrset == NULL) { dbg_ddns("Failed to create RRSet to be covered" " by the UPDATE RRSIG RR.\n"); - knot_rrset_deep_free(&rr_copy, 1, 1, 1); + knot_rrset_deep_free(&rr_copy, 1, 1); return KNOT_ENOMEM; } - + /* Add the RRSet to the node. */ - int ret = knot_node_add_rrset(node, covered_rrset, 0); + int ret = knot_node_add_rrset_no_merge(node, covered_rrset); if (ret != KNOT_EOK) { dbg_ddns("Failed to add the RRSet to be covered to the node: %s" ".\n", knot_strerror(ret)); - knot_rrset_deep_free(&rr_copy, 1, 1, 1); - knot_rrset_deep_free(&covered_rrset, 1, 1, 1); + knot_rrset_deep_free(&rr_copy, 1, 1); + knot_rrset_deep_free(&covered_rrset, 1, 1); return KNOT_ENOMEM; } - + /* Add the RRSet to 'changes'. */ ret = knot_changes_add_new_rrsets(&covered_rrset, 1, changes, 0); if (ret != KNOT_EOK) { dbg_xfrin("Failed to add new RRSet (covered) to list: %s.\n", knot_strerror(ret)); - knot_rrset_deep_free(&rr_copy, 1, 1, 1); - knot_rrset_deep_free(&covered_rrset, 1, 1, 1); + knot_rrset_deep_free(&rr_copy, 1, 1); + knot_rrset_deep_free(&covered_rrset, 1, 1); return ret; } /* Add the RRSIG RRSet to 'changes'. */ ret = knot_changes_add_new_rrsets(&rr_copy, 1, changes, 1); if (ret != KNOT_EOK) { - knot_rrset_deep_free(&rr_copy, 1, 1, 1); + knot_rrset_deep_free(&rr_copy, 1, 1); dbg_ddns("Failed to store copy of the added RRSIG: %s\n", knot_strerror(ret)); return ret; } - + /* Add the RRSIG RRSet to the covered RRSet. */ - ret = knot_rrset_add_rrsigs(covered_rrset, rr_copy, + ret = knot_rrset_add_rrsigs(covered_rrset, rr_copy, KNOT_RRSET_DUPL_SKIP); if (ret != KNOT_EOK) { dbg_ddns("Failed to add RRSIG RR to the covered RRSet.\n"); return ret; } - + return KNOT_EOK; } @@ -1233,42 +1246,44 @@ static int knot_ddns_add_rr_merge_normal(knot_rrset_t *node_rrset_copy, assert(node_rrset_copy != NULL); assert(rr_copy != NULL); assert(*rr_copy != NULL); - + dbg_ddns_verb("Merging normal RR to existing RRSet.\n"); - - /* In case the RRSet is empty (and only remained there because - * of the RRSIGs) it may happen that the TTL may be different - * than that of he new RRs. Update the TTL according to the + + /* In case the RRSet is empty (and only remained there because + * of the RRSIGs) it may happen that the TTL may be different + * than that of he new RRs. Update the TTL according to the * first RR. - */ - if (knot_rrset_rdata(node_rrset_copy) == NULL - && knot_rrset_ttl(node_rrset_copy) + */ + if (knot_rrset_rdata_rr_count(node_rrset_copy) == 0 + && knot_rrset_ttl(node_rrset_copy) != knot_rrset_ttl(*rr_copy)) { - knot_rrset_set_ttl(node_rrset_copy, + knot_rrset_set_ttl(node_rrset_copy, knot_rrset_ttl(*rr_copy)); } int rdata_in_copy = knot_rrset_rdata_rr_count(*rr_copy); - int ret = knot_rrset_merge_no_dupl((void **)&node_rrset_copy, - (void **)rr_copy); + int merged, deleted_rrs; + int ret = knot_rrset_merge_no_dupl(node_rrset_copy, *rr_copy, &merged, + &deleted_rrs); dbg_ddns_detail("Merge returned: %d\n", ret); - if (ret < 0) { + if (ret != KNOT_EOK) { dbg_ddns("Failed to merge UPDATE RR to node RRSet: %s." "\n", knot_strerror(ret)); return ret; } - knot_rrset_free(rr_copy); + knot_rrset_deep_free(rr_copy, 1, 0); + - if (rdata_in_copy == ret) { + if (rdata_in_copy == deleted_rrs) { /* All RDATA have been removed, because they were duplicates * or there were none (0). In general this means, that no * change was made. */ return 1; } - + return KNOT_EOK; } @@ -1282,12 +1297,12 @@ static int knot_ddns_add_rr_merge_rrsig(knot_rrset_t *node_rrset_copy, assert(rr_copy != NULL); assert(*rr_copy != NULL); assert(changes != NULL); - + dbg_ddns_verb("Adding RRSIG RR to existing RRSet.\n"); - + knot_rrset_t *rrsigs_old = knot_rrset_get_rrsigs(node_rrset_copy); int ret = 0; - + if (rrsigs_old != NULL) { /* If there is an RRSIG RRSet already, copy it too. */ knot_rrset_t *rrsigs_copy = NULL; @@ -1298,33 +1313,34 @@ static int knot_ddns_add_rr_merge_rrsig(knot_rrset_t *node_rrset_copy, "%s\n", knot_strerror(ret)); return ret; } - + /* Replace the RRSIGs by the copy. */ ret = knot_rrset_set_rrsigs(node_rrset_copy, rrsigs_copy); if (ret != KNOT_EOK) { dbg_ddns("Failed to replace RRSIGs in " - "the RRSet: %s\n", + "the RRSet: %s\n", knot_strerror(ret)); return ret; } - + /* Merge the UPDATE RR to the copied RRSIG * RRSet. */ dbg_ddns_detail("Merging RRSIG to the one in the RRSet.\n"); int rdata_in_copy = knot_rrset_rdata_rr_count(*rr_copy); - ret = knot_rrset_merge_no_dupl( - (void **)&rrsigs_copy, (void **)rr_copy); + int merged, deleted_rrs; + ret = knot_rrset_merge_no_dupl(rrsigs_copy, *rr_copy, &merged, + &deleted_rrs); if (ret < 0) { dbg_xfrin("Failed to merge UPDATE RRSIG to copy: %s.\n", knot_strerror(ret)); return KNOT_ERROR; } - - knot_rrset_free(rr_copy); + knot_rrset_deep_free(rr_copy, 1, 0); + - if (rdata_in_copy == ret) { + if (rdata_in_copy == deleted_rrs) { /* All RDATA have been removed, because they were * duplicates or there were none (0). In general this * means, that no change was made. @@ -1342,7 +1358,7 @@ static int knot_ddns_add_rr_merge_rrsig(knot_rrset_t *node_rrset_copy, knot_strerror(ret)); return ret; } - + /* Add the RRSet to the covered RRSet. */ ret = knot_rrset_add_rrsigs(node_rrset_copy, *rr_copy, KNOT_RRSET_DUPL_SKIP); @@ -1352,7 +1368,7 @@ static int knot_ddns_add_rr_merge_rrsig(knot_rrset_t *node_rrset_copy, return ret; } } - + return KNOT_EOK; } @@ -1371,7 +1387,7 @@ static int knot_ddns_add_rr(knot_node_t *node, const knot_rrset_t *rr, assert(rr != NULL); assert(changes != NULL); assert(rr_copy != NULL); - + /* Copy the RRSet from the packet. */ //knot_rrset_t *rr_copy; int ret = knot_rrset_deep_copy(rr, rr_copy, 1); @@ -1379,45 +1395,46 @@ static int knot_ddns_add_rr(knot_node_t *node, const knot_rrset_t *rr, dbg_ddns("Failed to copy RR: %s\n", knot_strerror(ret)); return ret; } - + uint16_t type = knot_rrset_type(rr); - uint16_t type_covered = (type == KNOT_RRTYPE_RRSIG) - ? knot_rdata_rrsig_type_covered(knot_rrset_rdata(rr)) + uint16_t type_covered = (type == KNOT_RRTYPE_RRSIG) + ? knot_rrset_rdata_rrsig_type_covered(rr) : type; - + /* If the RR belongs to a RRSet already present in the node, we must * take this RRSet from the node, copy it, and merge this RR into it. * * This code is more or less copied from xfr-in.c. */ knot_rrset_t *node_rrset_copy = NULL; - ret = xfrin_copy_rrset(node, type_covered, &node_rrset_copy, changes, + ret = xfrin_copy_rrset(node, type_covered, &node_rrset_copy, changes, 0); - + if (node_rrset_copy == NULL) { /* No such RRSet in the node. Add the whole UPDATE RRSet. */ dbg_ddns_detail("Adding whole UPDATE RR to the zone.\n"); if (type_covered != type) { /* Adding RRSIG. */ - ret = knot_ddns_add_rr_new_rrsig(node, *rr_copy, + ret = knot_ddns_add_rr_new_rrsig(node, *rr_copy, changes, type_covered); } else { - ret = knot_ddns_add_rr_new_normal(node, *rr_copy, + ret = knot_ddns_add_rr_new_normal(node, *rr_copy, changes); } if (ret != KNOT_EOK) { dbg_ddns("Failed to add new RR to node.\n"); return ret; } + dbg_ddns_detail("RRSet added successfully.\n"); } else { /* We have copied the RRSet from the node. */ dbg_ddns_exec_detail( dbg_ddns_detail("Merging RR to an existing RRSet.\n"); - knot_rrset_dump(node_rrset_copy, 1); + knot_rrset_dump(node_rrset_copy); dbg_ddns_detail("New RR:\n"); - knot_rrset_dump(*rr_copy, 0); + knot_rrset_dump(*rr_copy); ); - + if (type_covered != type) { /* Adding RRSIG. */ ret = knot_ddns_add_rr_merge_rrsig(node_rrset_copy, @@ -1429,27 +1446,27 @@ dbg_ddns_exec_detail( dbg_ddns_exec_detail( dbg_ddns_detail("After merge:\n"); - knot_rrset_dump(node_rrset_copy, 1); + knot_rrset_dump(node_rrset_copy); ); if (ret < KNOT_EOK) { dbg_ddns("Failed to merge UPDATE RR to node RRSet.\n"); - knot_rrset_deep_free(rr_copy, 1, 1, 1); - knot_rrset_deep_free(&node_rrset_copy, 1, 1, 1); + knot_rrset_deep_free(rr_copy, 1, 1); + knot_rrset_deep_free(&node_rrset_copy, 1, 1); return ret; } - + // save the new RRSet together with the new RDATA to 'changes' // do not overwrite 'ret', it have to be returned int r = knot_changes_add_new_rrsets(&node_rrset_copy, 1, changes, 1); if (r != KNOT_EOK) { dbg_ddns("Failed to store RRSet copy to 'changes'\n"); - knot_rrset_deep_free(&node_rrset_copy, 1, 1, 1); + knot_rrset_deep_free(&node_rrset_copy, 1, 1); return r; } } - + assert(ret >= 0); return ret; } @@ -1461,7 +1478,7 @@ static int knot_ddns_final_soa_to_chgset(const knot_rrset_t *soa, { assert(soa != NULL); assert(changeset != NULL); - + knot_rrset_t *soa_copy = NULL; int ret = knot_rrset_deep_copy(soa, &soa_copy, 1); if (ret != KNOT_EOK) { @@ -1469,11 +1486,11 @@ static int knot_ddns_final_soa_to_chgset(const knot_rrset_t *soa, "%s\n", knot_strerror(ret)); return ret; } - + knot_changeset_store_soa(&changeset->soa_to, &changeset->serial_to, soa_copy); - + return KNOT_EOK; } @@ -1484,7 +1501,7 @@ static int knot_ddns_add_rr_to_chgset(const knot_rrset_t *rr, { assert(rr != NULL); assert(changeset != NULL); - + int ret = 0; knot_rrset_t *chgset_rr = NULL; knot_ddns_check_add_rr(changeset, rr, &chgset_rr); @@ -1501,15 +1518,15 @@ static int knot_ddns_add_rr_to_chgset(const knot_rrset_t *rr, &changeset->add_allocated, chgset_rr); if (ret != KNOT_EOK) { - knot_rrset_deep_free(&chgset_rr, 1, 1, 1); + knot_rrset_deep_free(&chgset_rr, 1, 1); dbg_ddns("Failed to add RR to changeset: %s.\n", knot_strerror(ret)); return ret; } } else { - knot_rrset_deep_free(&chgset_rr, 1, 1, 1); + knot_rrset_deep_free(&chgset_rr, 1, 1); } - + return KNOT_EOK; } @@ -1527,7 +1544,7 @@ static int knot_ddns_process_add(const knot_rrset_t *rr, assert(changeset != NULL); assert(changes != NULL); assert(rr_copy != NULL); - + dbg_ddns_verb("Adding RR.\n"); if (node == NULL) { @@ -1541,11 +1558,11 @@ static int knot_ddns_process_add(const knot_rrset_t *rr, return KNOT_ERROR; } } - + uint16_t type = knot_rrset_type(rr); *rr_copy = NULL; int ret = 0; - + /* * First, rule out special cases: CNAME, SOA and adding to CNAME node. */ @@ -1564,7 +1581,7 @@ static int knot_ddns_process_add(const knot_rrset_t *rr, */ return KNOT_EOK; } - + if (ret == 1) { dbg_ddns_detail("Ignoring the added RR.\n"); // Ignore @@ -1573,11 +1590,11 @@ static int knot_ddns_process_add(const knot_rrset_t *rr, dbg_ddns_detail("Adding RR failed.\n"); return ret; } - + /* * In all other cases, the RR should just be added to the node. */ - + /* Add the RRSet to the node (RRSIGs handled in the function). */ dbg_ddns_detail("Adding RR to the node.\n"); ret = knot_ddns_add_rr(node, rr, changes, rr_copy); @@ -1585,7 +1602,7 @@ static int knot_ddns_process_add(const knot_rrset_t *rr, dbg_ddns("Failed to add RR to the node.\n"); return ret; } - + /* * If adding SOA, it should not be stored in the changeset. * (This is done in the calling function, and the SOA is stored in the @@ -1594,9 +1611,9 @@ static int knot_ddns_process_add(const knot_rrset_t *rr, if (type == KNOT_RRTYPE_SOA) { return KNOT_EOK; } - + /* Add the RR to ADD section of the changeset. */ - /* If the RR was previously removed, do not add it to the + /* If the RR was previously removed, do not add it to the * changeset, and remove the entry from the REMOVE section. * * If there was no change (i.e. all RDATA were duplicates), do not add @@ -1655,7 +1672,7 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, assert(type != KNOT_RRTYPE_SOA); int is_apex = knot_node_rrset(node, KNOT_RRTYPE_SOA) != NULL; - + /* If removing NS from an apex and there is only one NS left, ignore * this removal right away. We do not have to check if the RRs match: * - if they don't match, the removal will be ignored @@ -1670,7 +1687,7 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, * 1) Copy the RRSet. */ uint16_t type_to_copy = (type != KNOT_RRTYPE_RRSIG) ? type - : knot_rdata_rrsig_type_covered(knot_rrset_rdata(rr)); + : knot_rrset_rdata_rrsig_type_covered(rr); knot_rrset_t *rrset_copy = NULL; int ret = xfrin_copy_rrset(node, type_to_copy, &rrset_copy, changes, 1); if (ret < 0) { @@ -1683,31 +1700,29 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, dbg_ddns_verb("RRSet not found.\n"); return KNOT_EOK; } - + /* * Set some variables needed, according to the modified RR type. */ - - int rdata_count; + + int rdata_count = 0; knot_rrset_t *to_modify; if (type == KNOT_RRTYPE_RRSIG) { - rdata_count = knot_rrset_rdata_rr_count( - knot_rrset_rrsigs(rrset_copy)); + rdata_count = knot_rrset_rdata_rr_count(knot_rrset_rrsigs(rrset_copy)); to_modify = knot_rrset_get_rrsigs(rrset_copy); } else { rdata_count = knot_rrset_rdata_rr_count(rrset_copy); to_modify = rrset_copy; } - + /* * 1.5) Prepare place for the removed RDATA. * We don't know if there are some, but if this fails, at least we * haven't removed them yet. */ ret = knot_changes_rdata_reserve(&changes->old_rdata, - &changes->old_rdata_types, changes->old_rdata_count, - &changes->old_rdata_allocated, + &changes->old_rdata_allocated, rdata_count); if (ret != KNOT_EOK) { dbg_ddns("Failed to reserve place for RDATA.\n"); @@ -1717,32 +1732,39 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, /* * 2) Remove the proper RDATA from the RRSet copy, or its RRSIGs. */ - knot_rdata_t *removed = knot_rrset_remove_rdata(to_modify, - knot_rrset_rdata(rr)); + knot_rrset_t *rr_remove = NULL; + ret = knot_rrset_remove_rr_using_rrset(to_modify, rr, &rr_remove, 0); + if (ret != KNOT_EOK) { + dbg_ddns("ddns: proces_rem_rr: Could not remove RDATA from" + " RRSet (%s).\n", knot_strerror(ret)); + return ret; + } /* No such RR in the RRSet. */ - if (removed == NULL) { + if (knot_rrset_rdata_rr_count(rr_remove) == 0) { + knot_rrset_free(&rr_remove); dbg_ddns_detail("No such RR found to be removed.\n"); return KNOT_EOK; } /* If we removed NS from apex, there should be at least one more. */ - assert(!is_apex || type != KNOT_RRTYPE_NS - || knot_rrset_rdata(rrset_copy) != NULL); + assert(!is_apex || type != KNOT_RRTYPE_NS + || knot_rrset_rdata_rr_count(rrset_copy)); /* * 3) Store the removed RDATA in 'changes'. */ - knot_changes_add_rdata(changes->old_rdata, changes->old_rdata_types, - &changes->old_rdata_count, removed, type); + knot_changes_add_rdata(changes->old_rdata, &changes->old_rdata_count, + rr_remove); /* * 4) If the RRSet is empty, remove it and store in 'changes'. - * Do this also if the RRSIGs are empty. + * Do this also if the RRSIGs are empty. * And if both are empty, remove both. + * RRSIG handling first, */ - if (type == KNOT_RRTYPE_RRSIG - && knot_rrset_rdata(to_modify) == NULL) { + if (type == KNOT_RRTYPE_RRSIG && + knot_rrset_rdata_rr_count(to_modify) == 0) { /* Empty RRSIGs, remove the RRSIG RRSet */ ret = knot_changes_rrsets_reserve(&changes->old_rrsets, &changes->old_rrsets_count, @@ -1751,45 +1773,44 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, if (ret == KNOT_EOK) { knot_rrset_t *rrsig = knot_rrset_get_rrsigs(rrset_copy); dbg_xfrin_detail("Removed RRSIG RRSet (%p).\n", rrsig); - - assert(rrsig == to_modify); + + assert(rrsig && rrsig == to_modify); // add the removed RRSet to list of old RRSets changes->old_rrsets[changes->old_rrsets_count++] = rrsig; - + // remove it from the RRSet knot_rrset_set_rrsigs(rrset_copy, NULL); } else { dbg_ddns("Failed to reserve space for empty RRSet.\n"); } } - - /*! \note Copied from xfr-in.c - maybe extract to some function. */ - /*! \note This is not needed as rrset is already on the old_rrsets */ -// if (knot_rrset_rdata(rrset_copy) == NULL -// && knot_rrset_rrsigs(rrset_copy) == NULL) { -// // The RRSet should not be empty if we were removing NSs from -// // apex in case of DDNS -// assert(!is_apex); - -// ret = knot_changes_rrsets_reserve(&changes->old_rrsets, -// &changes->old_rrsets_count, -// &changes->old_rrsets_allocated, -// 1); -// if (ret == KNOT_EOK) { -// knot_rrset_t *tmp = knot_node_remove_rrset(node, type); -// dbg_xfrin_detail("Removed whole RRSet (%p).\n", tmp); - -// assert(tmp == rrset_copy); - -// // add the removed RRSet to list of old RRSets -// changes->old_rrsets[changes->old_rrsets_count++] -// = rrset_copy; -// } else { -// dbg_ddns("Failed to reserve space for empty RRSet.\n"); -// } -// } + + // Remove empty RRSet from node and store to changeset + if (type != KNOT_RRTYPE_RRSIG && + knot_rrset_rdata_rr_count(to_modify) == 0) { + // The RRSet should not be empty if we were removing NSs from + // apex in case of DDNS + assert(!is_apex); + + ret = knot_changes_rrsets_reserve(&changes->old_rrsets, + &changes->old_rrsets_count, + &changes->old_rrsets_allocated, + 1); + if (ret == KNOT_EOK) { + knot_rrset_t *tmp = knot_node_remove_rrset(node, type); + dbg_xfrin_detail("Removed whole RRSet (%p).\n", tmp); + + assert(tmp == rrset_copy); + + // add the removed RRSet to list of old RRSets + changes->old_rrsets[changes->old_rrsets_count++] + = rrset_copy; + } else { + dbg_ddns("Failed to reserve space for empty RRSet.\n"); + } + } /* * 5) Check if the RR is not in the ADD section. If yes, remove it @@ -1798,8 +1819,7 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, knot_rrset_t **from_chgset = NULL; size_t from_chgset_count = 0; ret = knot_ddns_check_remove_rr2(changeset, knot_node_owner(node), - type, knot_rrset_rdata(rr), - &from_chgset, &from_chgset_count); + rr, &from_chgset, &from_chgset_count); if (ret != KNOT_EOK) { dbg_ddns("Failed to remove possible redundant RRs from ADD " "section: %s.\n", knot_strerror(ret)); @@ -1811,13 +1831,13 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, if (from_chgset_count == 1) { /* Just delete the RRSet. */ - knot_rrset_deep_free(&(from_chgset[0]), 1, 1, 1); + knot_rrset_deep_free(&(from_chgset[0]), 1, 1); /* Finish processing, no adding to changeset. */ free(from_chgset); return KNOT_EOK; } - + free(from_chgset); /* @@ -1841,7 +1861,7 @@ static int knot_ddns_process_rem_rr(const knot_rrset_t *rr, if (ret != KNOT_EOK) { dbg_ddns("Failed to store the RRSet copy to changeset: %s.\n", knot_strerror(ret)); - knot_rrset_deep_free(&to_chgset, 1, 1, 1); + knot_rrset_deep_free(&to_chgset, 1, 1); return ret; } @@ -1858,9 +1878,9 @@ static int knot_ddns_process_rem_rrsig(knot_node_t *node, assert(node != NULL); assert(rrset != NULL); assert(changes != NULL); - + knot_rrset_t *rrset_copy = NULL; - + /* Copy RRSet. */ int ret = xfrin_copy_old_rrset(rrset, &rrset_copy, changes, 1); if (ret != KNOT_EOK) { @@ -1868,29 +1888,29 @@ static int knot_ddns_process_rem_rrsig(knot_node_t *node, knot_strerror(ret)); return ret; } - + /* Remove RRSIGs from the copy. */ *rrsig = knot_rrset_get_rrsigs(rrset_copy); if (*rrsig != NULL) { knot_rrset_set_rrsigs(rrset_copy, NULL); } - + /* Put the copy to the node. */ - ret = knot_node_add_rrset(node, rrset_copy, 0); + ret = knot_node_add_rrset_no_merge(node, rrset_copy); if (ret != KNOT_EOK) { dbg_ddns("Failed to add RRSet copy to the node: %s\n", knot_strerror(ret)); - knot_rrset_deep_free(&rrset_copy, 1, 1, 1); + knot_rrset_deep_free(&rrset_copy, 1, 1); return ret; } - + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -static int knot_ddns_process_rem_rrsigs(knot_node_t *node, - knot_changes_t *changes, +static int knot_ddns_process_rem_rrsigs(knot_node_t *node, + knot_changes_t *changes, knot_rrset_t ***removed, size_t *removed_count) { @@ -1898,33 +1918,37 @@ static int knot_ddns_process_rem_rrsigs(knot_node_t *node, assert(removed != NULL); assert(removed_count != NULL); assert(changes != NULL); - - /* If removing RRSIGs, we must remove them from all RRSets in - * the node. This means to copy all RRSets and then remove the + + /* If removing RRSIGs, we must remove them from all RRSets in + * the node. This means to copy all RRSets and then remove the * RRSIGs from them. */ dbg_ddns_verb("Removing all RRSIGs from node.\n"); - + knot_rrset_t **rrsets = knot_node_get_rrsets(node); if (rrsets == NULL) { // No RRSets in the node, nothing to remove return KNOT_EOK; } - + /* Allocate space for the removed RRSIGs. There may be as many as there * are RRSets. */ short rrset_count = knot_node_rrset_count(node); - + *removed = malloc(rrset_count * sizeof(knot_rrset_t *)); - CHECK_ALLOC_LOG(*removed, KNOT_ENOMEM); + if (*removed == NULL) { + ERR_ALLOC_FAILED; + free(rrsets); + return KNOT_ENOMEM; + } *removed_count = 0; - + /* Remove all the RRSets from the node, so that we may insert the copies * right away. */ knot_node_remove_all_rrsets(node); - + knot_rrset_t *rrsig = NULL; int ret = 0; for (int i = 0; i < rrset_count; ++i) { @@ -1932,41 +1956,47 @@ static int knot_ddns_process_rem_rrsigs(knot_node_t *node, &rrsig); if (ret != KNOT_EOK) { dbg_ddns("Failed to remove RRSIG.\n"); + free(rrsets); + free(*removed); + *removed = NULL; return ret; } /* Store the RRSIGs to the array of removed RRSets. */ (*removed)[(*removed_count)++] = rrsig; } - + free(rrsets); - - + + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -static int knot_ddns_process_rem_rrset(uint16_t type, +static int knot_ddns_process_rem_rrset(const knot_rrset_t *rrset, knot_node_t *node, knot_changeset_t *changeset, knot_changes_t *changes) { assert(node != NULL); + assert(rrset != NULL); assert(changeset != NULL); assert(changes != NULL); + uint16_t type = knot_rrset_type(rrset); + /*! \note * We decided to automatically remove RRSIGs together with the removed - * RRSet as they are no longer valid or required anyway. + * RRSet as they are no longer valid or required anyway. * * Also refer to RFC3007, section 4.3: - * 'When the contents of an RRset are updated, the server MAY delete + * 'When the contents of an RRset are updated, the server MAY delete * all associated SIG records, since they will no longer be valid.' * * (Although we are compliant with this RFC only selectively. The next - * section says: 'If any changes are made, the server MUST, if - * necessary, generate a new SOA record and new NXT records, and sign - * these with the appropriate zone keys.' and we are definitely not + * section says: 'If any changes are made, the server MUST, if + * necessary, generate a new SOA record and new NXT records, and sign + * these with the appropriate zone keys.' and we are definitely not * doing this... * * \todo Document!! @@ -1980,15 +2010,20 @@ static int knot_ddns_process_rem_rrset(uint16_t type, // if removing NS from apex, ignore return KNOT_EOK; } - + knot_rrset_t **removed = NULL; size_t removed_count = 0; int ret = 0; - + if (type == KNOT_RRTYPE_RRSIG) { /* Remove all RRSIGs from the node. */ ret = knot_ddns_process_rem_rrsigs(node, changes, &removed, &removed_count); + if (ret != KNOT_EOK) { + dbg_ddns("Failed to remove RRSIGs. (%s)\n", + knot_strerror(ret)); + return ret; + } } else { /* Remove the RRSet from the node. */ removed = malloc(sizeof(knot_rrset_t *)); @@ -1998,23 +2033,28 @@ static int knot_ddns_process_rem_rrset(uint16_t type, } dbg_ddns_detail("Removing RRSet of type: %d\n", type); - + *removed = knot_node_remove_rrset(node, type); - removed_count = 1; + if (*removed != NULL) { + removed_count = 1; + } else { + removed_count = 0; + } } - dbg_ddns_detail("Removed: %p (first item: %p), removed count: %d\n", - removed, (removed == NULL) ? "none" : *removed, + dbg_ddns_detail("Removed: %p (first item: %p), removed count: %zu\n", + removed, (removed == NULL) ? (void *)"none" : *removed, removed_count); // no such RR - if (removed_count == 0 || removed == NULL) { + if (removed_count == 0) { // ignore + free(removed); return KNOT_EOK; } /* 2) Store them to 'changes' for later deallocation, together with - * their RRSIGs. + * their RRSIGs. */ ret = knot_changes_add_old_rrsets(removed, removed_count, changes, 1); if (ret != KNOT_EOK) { @@ -2025,7 +2065,7 @@ static int knot_ddns_process_rem_rrset(uint16_t type, } /* 3) Copy the RRSets, so that they can be stored to the changeset. */ - knot_rrset_t **to_chgset = malloc(removed_count + knot_rrset_t **to_chgset = malloc(removed_count * sizeof(knot_rrset_t *)); if (to_chgset == NULL) { dbg_ddns("Failed to allocate space for RRSets going to " @@ -2033,21 +2073,21 @@ static int knot_ddns_process_rem_rrset(uint16_t type, free(removed); return KNOT_ENOMEM; } - + for (int i = 0; i < removed_count; ++i) { ret = knot_rrset_deep_copy(removed[i], &to_chgset[i], 1); if (ret != KNOT_EOK) { dbg_ddns("Failed to copy the removed RRSet: %s.\n", knot_strerror(ret)); for (int j = 0; j < i; ++j) { - knot_rrset_deep_free(&to_chgset[j], 1, 1, 1); + knot_rrset_deep_free(&to_chgset[j], 1, 1); } free(to_chgset); free(removed); return ret; } } - + free(removed); /* 4) But we must check if some of the RRs were not previously added @@ -2059,22 +2099,28 @@ static int knot_ddns_process_rem_rrset(uint16_t type, size_t from_chgset_count = 0; /* 4 a) Remove redundant RRs from the ADD section of the changeset. */ - ret = knot_ddns_check_remove_rr2(changeset, knot_node_owner(node), type, - NULL, &from_chgset, + knot_rrset_t *empty_rrset = + knot_rrset_new(rrset->owner, type, rrset->rclass, rrset->ttl); + if (empty_rrset == NULL) { + return KNOT_ENOMEM; + } + ret = knot_ddns_check_remove_rr2(changeset, knot_node_owner(node), + empty_rrset, &from_chgset, &from_chgset_count); if (ret != KNOT_EOK) { dbg_ddns("Failed to remove possible redundant RRs from ADD " "section: %s.\n", knot_strerror(ret)); for (int i = 0; i < removed_count; ++i) { - knot_rrset_deep_free(&to_chgset[i], 1, 1, 1); + knot_rrset_deep_free(&to_chgset[i], 1, 1); } free(from_chgset); free(to_chgset); + knot_rrset_free(&empty_rrset); return ret; } + knot_rrset_free(&empty_rrset); /* 4 b) Remove these RRs from the copy of the RRSets removed from zone*/ - knot_rdata_t *rem = NULL; for (int j = 0; j < removed_count; ++j) { /* In each RRSet removed from the node (each can have more * RDATAs) ... @@ -2083,18 +2129,21 @@ static int knot_ddns_process_rem_rrset(uint16_t type, /* ...try to remove redundant RDATA. Each RRSet in * 'from_chgset' contains only one RDATA. */ - rem = knot_rrset_remove_rdata(to_chgset[j], - knot_rrset_rdata( - from_chgset[i])); - /* And delete it right away, no use for that. */ - knot_rdata_deep_free(&rem, knot_rrset_type( - from_chgset[i]), 1); + ret = knot_rrset_remove_rr_using_rrset_del(to_chgset[j], + from_chgset[i]); + if (ret != KNOT_EOK) { + dbg_ddns("Failed to remove RR from RRSet" + "(%s).\n", knot_strerror(ret)); + free(from_chgset); + free(to_chgset); + return ret; + } } } - + /* The array is cleared, we may delete the redundant RRs. */ for (int i = 0; i < from_chgset_count; ++i) { - knot_rrset_deep_free(&from_chgset[i], 1, 1, 1); + knot_rrset_deep_free(&from_chgset[i], 1, 1); } free(from_chgset); @@ -2110,13 +2159,13 @@ static int knot_ddns_process_rem_rrset(uint16_t type, dbg_ddns("Failed to store the RRSet copy to changeset: " "%s.\n", knot_strerror(ret)); for (int j = i; j < removed_count; ++j) { - knot_rrset_deep_free(&to_chgset[j], 1, 1, 1); + knot_rrset_deep_free(&to_chgset[j], 1, 1); } free(to_chgset); return ret; } } - + free(to_chgset); return KNOT_EOK; @@ -2139,13 +2188,13 @@ static int knot_ddns_process_rem_all(knot_node_t *node, * In case of SOA and NS in apex, the RRSets should not be removed, but * what about their RRSIGs?? * - * If the zone has to remain properly signed, the UPDATE will have to + * If the zone has to remain properly signed, the UPDATE will have to * contain at least new SOA and RRSIGs for it (as the auto-incremented - * SOA would not be signed). So it should not matter if we leave the + * SOA would not be signed). So it should not matter if we leave the * RRSIGs there or not. But in case of the NSs it's not that clear. * * For now, we will leave the RRSIGs there. It's easier to implement. - * + * * \todo Should document this!! */ int ret = 0; @@ -2169,8 +2218,8 @@ static int knot_ddns_process_rem_all(knot_node_t *node, continue; } - ret = knot_ddns_process_rem_rrset(knot_rrset_type(rrsets[i]), - node, changeset, changes); + ret = knot_ddns_process_rem_rrset(rrsets[i], node, changeset, + changes); if (ret != KNOT_EOK) { dbg_ddns("Failed to remove RRSet: %s\n", knot_strerror(ret)); @@ -2178,7 +2227,7 @@ static int knot_ddns_process_rem_all(knot_node_t *node, return ret; } } - + free(rrsets); return KNOT_EOK; @@ -2211,14 +2260,13 @@ static int knot_ddns_process_rr(const knot_rrset_t *rr, return KNOT_EOK; } else if (knot_rrset_class(rr) == KNOT_CLASS_NONE) { return knot_ddns_process_rem_rr(rr, node, zone, changeset, - changes, qclass); + changes, qclass); } else if (knot_rrset_class(rr) == KNOT_CLASS_ANY) { if (knot_rrset_type(rr) == KNOT_RRTYPE_ANY) { return knot_ddns_process_rem_all(node, changeset, changes); } else { - return knot_ddns_process_rem_rrset(knot_rrset_type(rr), - node, changeset, + return knot_ddns_process_rem_rrset(rr, node, changeset, changes); } } else { @@ -2258,7 +2306,7 @@ int knot_ddns_process_update2(knot_zone_contents_t *zone, KNOT_RRTYPE_SOA); knot_rrset_t *soa_begin = NULL; knot_rrset_t *soa_end = NULL; - ret = knot_rrset_deep_copy(soa, &soa_begin, 0); + ret = knot_rrset_deep_copy(soa, &soa_begin, 1); if (ret == KNOT_EOK) { knot_changeset_store_soa(&changeset->soa_from, &changeset->serial_from, soa_begin); @@ -2268,7 +2316,7 @@ int knot_ddns_process_update2(knot_zone_contents_t *zone, } /* Current SERIAL */ - int64_t sn = knot_rdata_soa_serial(knot_rrset_rdata(soa_begin)); + int64_t sn = knot_rrset_rdata_soa_serial(soa_begin); int64_t sn_new; /* Incremented SERIAL @@ -2320,13 +2368,14 @@ int knot_ddns_process_update2(knot_zone_contents_t *zone, if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA && (knot_rrset_class(rr) == KNOT_CLASS_NONE || knot_rrset_class(rr) == KNOT_CLASS_ANY - || ns_serial_compare(knot_rdata_soa_serial( - knot_rrset_rdata(rr)), sn_new) < 0)) { + || ns_serial_compare(knot_rrset_rdata_soa_serial(rr), + sn_new) < 0)) { // This ignores also SOA removals dbg_ddns_verb("Ignoring SOA...\n"); continue; } + dbg_ddns_verb("Processing RR %p...\n", rr); ret = knot_ddns_process_rr(rr, zone, changeset, changes, knot_packet_qclass(query), &rr_copy); @@ -2341,10 +2390,9 @@ int knot_ddns_process_update2(knot_zone_contents_t *zone, // we need the RR copy, that's why this code is here if (knot_rrset_type(rr) == KNOT_RRTYPE_SOA) { - int64_t sn_rr = knot_rdata_soa_serial( - knot_rrset_rdata(rr)); - dbg_ddns_verb("Replacing SOA. Old serial: %d, new " - "serial: %d\n", sn_new, sn_rr); + int64_t sn_rr = knot_rrset_rdata_soa_serial(rr); + dbg_ddns_verb("Replacing SOA. Old serial: %"PRId64", " + "new serial: %"PRId64"\n", sn_new, sn_rr); assert(ns_serial_compare(sn_rr, sn_new) >= 0); assert(rr_copy != NULL); sn_new = sn_rr; @@ -2354,14 +2402,14 @@ int knot_ddns_process_update2(knot_zone_contents_t *zone, /* Ending SOA (not in the UPDATE) */ if (soa_end == NULL) { - /* If the changeset is empty, do not process anything further + /* If the changeset is empty, do not process anything further * and indicate this to the caller, so that the changeset is not * saved and zone is not switched. */ if (knot_changeset_is_empty(changeset)) { return 1; } - + /* If not set, create new SOA. */ assert(sn_new == (uint32_t)sn + 1); ret = knot_rrset_deep_copy(soa, &soa_end, 1); @@ -2371,9 +2419,8 @@ int knot_ddns_process_update2(knot_zone_contents_t *zone, *rcode = KNOT_RCODE_SERVFAIL; return ret; } - knot_rdata_t *rd = knot_rrset_get_rdata(soa_end); - knot_rdata_soa_serial_set(rd, sn_new); - + knot_rrset_rdata_soa_serial_set(soa_end, sn_new); + /* And replace it in the zone. */ ret = xfrin_replace_rrset_in_node( knot_zone_contents_get_apex(zone), |