summaryrefslogtreecommitdiff
path: root/src/libknot/rrset.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libknot/rrset.c')
-rw-r--r--src/libknot/rrset.c2836
1 files changed, 2271 insertions, 565 deletions
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index f5a9f5f..24ddb88 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -19,59 +19,821 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
+#include <inttypes.h>
+#include "consts.h"
#include "common.h"
+#include "common/mempattern.h"
#include "rrset.h"
-#include "util/descriptor.h"
+#include "common/descriptor.h"
#include "util/debug.h"
#include "util/utils.h"
+#include "packet/response.h"
+#include "util/wire.h"
/*----------------------------------------------------------------------------*/
/* Non-API functions */
/*----------------------------------------------------------------------------*/
-static void knot_rrset_disconnect_rdata(knot_rrset_t *rrset,
- knot_rdata_t *prev, knot_rdata_t *rdata)
+static int rrset_retain_dnames_in_rr(knot_dname_t **dname, void *data)
{
- if (prev == NULL) {
- // find the previous RDATA in the series, as its pointer must
- // be changed
- prev = rdata->next;
- while (prev->next != rdata) {
- prev = prev->next;
+ UNUSED(data);
+ if (dname == NULL || *dname == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_dname_retain(*dname);
+ return KNOT_EOK;
+}
+
+static int rrset_release_dnames_in_rr(knot_dname_t **dname, void *data)
+{
+ UNUSED(data);
+ if (dname == NULL || *dname == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ knot_dname_release(*dname);
+ return KNOT_EOK;
+}
+
+static uint32_t rrset_rdata_offset(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || rrset->rdata_indices == NULL ||
+ pos >= rrset->rdata_count || pos == 0) {
+ return 0;
+ }
+
+ assert(rrset->rdata_count >= 2);
+ return rrset->rdata_indices[pos - 1];
+}
+
+static uint8_t *rrset_rdata_pointer(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || rrset->rdata == NULL
+ || pos >= rrset->rdata_count) {
+ return NULL;
+ }
+
+ return rrset->rdata + rrset_rdata_offset(rrset, pos);
+}
+
+static uint16_t rrset_rdata_naptr_bin_chunk_size(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ size_t size = 0;
+ uint8_t *rdata = rrset_rdata_pointer(rrset, pos);
+ assert(rdata);
+
+ /* Two shorts at the beginning. */
+ size += 4;
+ /* 3 binary TXTs with length in the first byte. */
+ for (int i = 0; i < 3; i++) {
+ size += *(rdata + size) + 1;
+ }
+
+ /*
+ * Dname remaning, but we usually want to get to the DNAME, so
+ * there's no need to include it in the returned size.
+ */
+
+ return size;
+}
+
+void knot_rrset_rdata_dump(const knot_rrset_t *rrset, size_t rdata_pos)
+{
+dbg_rrset_exec_detail(
+ dbg_rrset_detail(" ------- RDATA pos=%zu -------\n", rdata_pos);
+ if (rrset->rdata_count == 0) {
+ dbg_rrset_detail(" There are no rdata in this RRset!\n");
+ dbg_rrset_detail(" ------- RDATA -------\n");
+ return;
+ }
+ const rdata_descriptor_t *desc =
+ get_rdata_descriptor(knot_rrset_type(rrset));
+
+ size_t offset = 0;
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+ int item = desc->block_types[i];
+ const uint8_t *rdata = rrset_rdata_pointer(rrset, rdata_pos);
+ if (descriptor_item_is_dname(item)) {
+ knot_dname_t *dname;
+ memcpy(&dname, rdata + offset, sizeof(knot_dname_t *));
+ char *name = knot_dname_to_str(dname);
+ if (dname == NULL) {
+ dbg_rrset_detail("DNAME error.\n");
+ return;
+ }
+ dbg_rrset_detail("block=%d: (%p) DNAME=%s\n",
+ i, dname, name);
+ free(name);
+ offset += sizeof(knot_dname_t *);
+ } else if (descriptor_item_is_fixed(item)) {
+ dbg_rrset_detail("block=%d Raw data (size=%d):\n",
+ i, item);
+ dbg_rrset_hex_detail((char *)(rdata + offset), item);
+ offset += item;
+ } else if (descriptor_item_is_remainder(item)) {
+ dbg_rrset_detail("block=%d Remainder (size=%zu):\n",
+ i, rrset_rdata_item_size(rrset,
+ rdata_pos) - offset);
+ dbg_rrset_hex_detail((char *)(rdata + offset),
+ rrset_rdata_item_size(rrset,
+ rdata_pos) - offset);
+ } else {
+ assert(rrset->type == KNOT_RRTYPE_NAPTR);
+ uint16_t naptr_chunk_size =
+ rrset_rdata_naptr_bin_chunk_size(rrset, rdata_pos);
+ dbg_rrset_detail("NAPTR, REGEXP block (size=%u):\n",
+ naptr_chunk_size);
+ dbg_rrset_hex_detail((char *)(rdata + offset), naptr_chunk_size);
+ offset += naptr_chunk_size;
}
}
+);
+}
- assert(prev);
- assert(prev->next == rdata);
+static size_t rrset_rdata_remainder_size(const knot_rrset_t *rrset,
+ size_t offset, size_t pos)
+{
+ assert(rrset_rdata_item_size(rrset, pos) != 0);
- prev->next = rdata->next;
+ size_t ret = rrset_rdata_item_size(rrset, pos) - offset;
+ assert(ret <= rrset_rdata_size_total(rrset));
+ return ret;
+}
- if (rrset->rdata == rdata) {
- if (rdata->next == rdata) {
- rrset->rdata = NULL;
+/* [code-review] Please document at least parameters & return values. */
+static int rrset_rdata_compare_one(const knot_rrset_t *rrset1,
+ const knot_rrset_t *rrset2,
+ size_t pos1, size_t pos2)
+{
+ /* [code-review] Just to be sure. */
+ assert(rrset1 != NULL);
+ assert(rrset2 != NULL);
+
+ uint8_t *r1 = rrset_rdata_pointer(rrset1, pos1);
+ uint8_t *r2 = rrset_rdata_pointer(rrset2, pos2);
+ assert(rrset1->type == rrset2->type);
+ const rdata_descriptor_t *desc = get_rdata_descriptor(rrset1->type);
+ int cmp = 0;
+ size_t offset = 0;
+
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+ if (descriptor_item_is_dname(desc->block_types[i])) {
+ knot_dname_t *dname1 = NULL;
+ memcpy(&dname1, r1 + offset, sizeof(knot_dname_t *));
+ knot_dname_t *dname2 = NULL;
+ memcpy(&dname2, r2 + offset, sizeof(knot_dname_t *));
+ cmp = knot_dname_compare(dname1, dname2);
+ offset += sizeof(knot_dname_t *);
+ } else if (descriptor_item_is_fixed(desc->block_types[i])) {
+ cmp = memcmp(r1 + offset, r2 + offset,
+ desc->block_types[i]);
+ offset += desc->block_types[i];
+ } else if (descriptor_item_is_remainder(desc->block_types[i])) {
+ size_t size1 = rrset_rdata_remainder_size(rrset1, offset,
+ pos1);
+ size_t size2 = rrset_rdata_remainder_size(rrset2, offset,
+ pos2);
+ cmp = memcmp(r1 + offset, r2 + offset,
+ size1 <= size2 ? size1 : size2);
+ if (cmp == 0 && size1 != size2) {
+ cmp = size1 < size2 ? -1 : 1;
+ }
+ /* No need to move offset, this should be end anyway. */
+ assert(desc->block_types[i + 1] == KNOT_RDATA_WF_END);
} else {
- rrset->rdata = rdata->next;
+ assert(rrset1->type == KNOT_RRTYPE_NAPTR);
+ uint16_t naptr_chunk_size1 =
+ rrset_rdata_naptr_bin_chunk_size(rrset1, pos1);
+ uint16_t naptr_chunk_size2 =
+ rrset_rdata_naptr_bin_chunk_size(rrset2, pos2);
+ cmp = memcmp(r1, r2,
+ naptr_chunk_size1 <= naptr_chunk_size2 ?
+ naptr_chunk_size1 : naptr_chunk_size2);
+ if (cmp == 0 && naptr_chunk_size1 == naptr_chunk_size2) {
+ cmp = naptr_chunk_size1 < naptr_chunk_size2 ? -1 : 1;
+ }
+
+ /*
+ * It does not matter which one we assign. If the
+ * offsets were different, then cmp != 0, if yes,
+ * NAPTR DNAME will be on correct offset.
+ */
+ offset += naptr_chunk_size1;
+ }
+
+ if (cmp != 0) {
+ return cmp;
}
}
- rdata->next = NULL;
+ assert(cmp == 0);
+ return 0;
+}
+
+static int knot_rrset_header_to_wire(const knot_rrset_t *rrset,
+ uint8_t **pos, size_t max_size,
+ knot_compr_t *compr, size_t *size)
+{
+ // Common size of items: type, class and ttl.
+ const size_t type_cls_ttl_len = 2 * sizeof(uint16_t) + sizeof(uint32_t);
+ // Rdata length item size.
+ const size_t rrlen_len = sizeof(uint16_t);
+
+ if (rrset->owner == NULL) {
+ return KNOT_EMALF;
+ }
+
+ const uint8_t *owner;
+ uint8_t owner_len;
+
+ // Use compressed owner.
+ if (compr) {
+ owner = compr->owner.wire + compr->owner.pos;
+ owner_len = compr->owner.size;
+ // Use rrset owner.
+ } else {
+ owner = knot_dname_name(rrset->owner);
+ owner_len = knot_dname_size(rrset->owner);
+ }
+
+ dbg_response("Max size: %zu, compressed owner: %s, owner size: %u\n",
+ max_size, compr ? "yes" : "no", owner_len);
+
+ // Check wire space for header.
+ if (*size + owner_len + type_cls_ttl_len + rrlen_len > max_size) {
+ dbg_rrset_detail("Header does not fit into wire.\n");
+ return KNOT_ESPACE;
+ }
+
+ // Write owner, type, class and ttl to wire.
+ memcpy(*pos, owner, owner_len);
+ *pos += owner_len;
+
+ dbg_rrset_detail(" Type: %u\n", rrset->type);
+ knot_wire_write_u16(*pos, rrset->type);
+ *pos += sizeof(uint16_t);
+
+ dbg_rrset_detail(" Class: %u\n", rrset->rclass);
+ knot_wire_write_u16(*pos, rrset->rclass);
+ *pos += sizeof(uint16_t);
+
+ dbg_rrset_detail(" TTL: %u\n", rrset->ttl);
+ knot_wire_write_u32(*pos, rrset->ttl);
+ *pos += sizeof(uint32_t);
+
+ *size += owner_len + type_cls_ttl_len;
+
+ return KNOT_EOK;
+}
+
+/* [code-review] Split to more functions, this one's too long. */
+static int knot_rrset_rdata_to_wire_one(const knot_rrset_t *rrset,
+ size_t rdata_pos, uint8_t **pos,
+ size_t max_size, size_t *rr_size,
+ knot_compr_t *compr)
+{
+ assert(rrset);
+ assert(pos);
+
+ /* Put RR header to wire. */
+ size_t size = 0;
+ int ret = knot_rrset_header_to_wire(rrset, pos, max_size,
+ compr, &size);
+ if (ret != KNOT_EOK) {
+ dbg_response("Failed to convert RR header to wire (%s).\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ // save space for RDLENGTH
+ uint8_t *rdlength_pos = *pos;
+ *pos += 2;
+ size += 2;
+
+ if (compr) {
+ compr->wire_pos += size;
+ }
+
+ /* Get pointer into RDATA array. */
+ uint8_t *rdata = rrset_rdata_pointer(rrset, rdata_pos);
+ assert(rdata);
+ /* Offset into one RDATA array. */
+ size_t offset = 0;
+ /* Actual RDLENGTH. */
+ uint16_t rdlength = 0;
+
+ const rdata_descriptor_t *desc = get_rdata_descriptor(rrset->type);
+
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+ int item = desc->block_types[i];
+ if (compr && descriptor_item_is_compr_dname(item)) {
+ knot_dname_t *dname;
+ memcpy(&dname, rdata + offset, sizeof(knot_dname_t *));
+ assert(dname);
+ int ret = knot_response_compress_dname(dname,
+ compr, *pos,
+ max_size - size - rdlength);
+ if (ret < 0) {
+ return KNOT_ESPACE;
+ }
+ assert(ret + size + rdlength <= max_size);
+dbg_response_exec_detail(
+ char *name = knot_dname_to_str(dname);
+ dbg_response_detail("Compressed dname=%s size: %d\n",
+ name, ret);
+ free(name);
+);
+ *pos += ret;
+ rdlength += ret;
+ offset += sizeof(knot_dname_t *);
+ compr->wire_pos += ret;
+ } else if (descriptor_item_is_dname(item)) {
+ knot_dname_t *dname;
+ memcpy(&dname, rdata + offset, sizeof(knot_dname_t *));
+ assert(dname && dname->name);
+ if (size + rdlength + knot_dname_size(dname) > max_size) {
+ dbg_rrset("rr: to_wire: DNAME does not fit into RR.\n");
+ return KNOT_ESPACE;
+ }
+dbg_rrset_exec_detail(
+ char *name = knot_dname_to_str(dname);
+ dbg_rrset_detail("Saving this DNAME=%s\n", name);
+ free(name);
+);
+ // save whole domain name
+ memcpy(*pos, knot_dname_name(dname),
+ knot_dname_size(dname));
+ dbg_rrset_detail("Uncompressed dname size: %d\n",
+ knot_dname_size(dname));
+ *pos += knot_dname_size(dname);
+ rdlength += knot_dname_size(dname);
+ offset += sizeof(knot_dname_t *);
+ if (compr) {
+ compr->wire_pos += knot_dname_size(dname);
+ }
+ } else if (descriptor_item_is_fixed(item)) {
+ dbg_rrset_detail("Saving static chunk, size=%d\n",
+ item);
+ /* Fixed length chunk. */
+ if (size + rdlength + item > max_size) {
+ return KNOT_ESPACE;
+ }
+ memcpy(*pos, rdata + offset, item);
+ *pos += item;
+ rdlength += item;
+ offset += item;
+ if (compr) {
+ compr->wire_pos += item;
+ }
+ } else if (descriptor_item_is_remainder(item)) {
+ /* Check that the remainder fits to stream. */
+ size_t remainder_size =
+ rrset_rdata_remainder_size(rrset, offset,
+ rdata_pos);
+ dbg_rrset_detail("Saving remaining chunk, size=%zu, "
+ "size with remainder=%zu\n",
+ remainder_size,
+ size + rdlength + remainder_size);
+ if (size + rdlength + remainder_size > max_size) {
+ dbg_rrset("rr: to_wire: Remainder does not fit "
+ "to wire.\n");
+ return KNOT_ESPACE;
+ }
+ memcpy(*pos, rdata + offset, remainder_size);
+ *pos += remainder_size;
+ rdlength += remainder_size;
+ offset += remainder_size;
+ if (compr) {
+ compr->wire_pos += remainder_size;
+ }
+ } else {
+ assert(rrset->type == KNOT_RRTYPE_NAPTR);
+ /* Store the binary chunk. */
+ uint16_t chunk_size =
+ rrset_rdata_naptr_bin_chunk_size(rrset, rdata_pos);
+ if (size + rdlength + chunk_size > max_size) {
+ dbg_rrset("rr: to_wire: NAPTR chunk does not "
+ "fit to wire.\n");
+ return KNOT_ESPACE;
+ }
+ memcpy(*pos, rdata + offset, chunk_size);
+ *pos += chunk_size;
+ rdlength += chunk_size;
+ offset += chunk_size;
+ if (compr) {
+ compr->wire_pos += chunk_size;
+ }
+ }
+ }
+
+ knot_wire_write_u16(rdlength_pos, rdlength);
+ size += rdlength;
+
+ *rr_size = size;
+ assert(size <= max_size);
+ return KNOT_EOK;
+}
+
+static int knot_rrset_to_wire_aux(const knot_rrset_t *rrset, uint8_t **pos,
+ size_t max_size, compression_param_t *comp)
+{
+ uint8_t wf_owner[256];
+ size_t size = 0;
+
+ assert(rrset != NULL);
+ assert(rrset->owner != NULL);
+ assert(pos != NULL);
+ assert(*pos != NULL);
+
+ dbg_rrset_detail("Max size: %zu, owner: %p, owner size: %d\n",
+ max_size, rrset->owner, rrset->owner->size);
+
+ knot_compr_t compr_info;
+ if (comp) {
+ dbg_response_detail("Compressing RR owner: %s.\n",
+ rrset->owner->name);
+ compr_info.table = comp->compressed_dnames;
+ compr_info.wire = comp->wire;
+ compr_info.wire_pos = comp->wire_pos;
+ int ret = knot_response_compress_dname(rrset->owner, &compr_info,
+ wf_owner, max_size);
+ if (ret < 0) {
+ return KNOT_ESPACE;
+ }
+
+ compr_info.owner.pos = 0;
+ compr_info.owner.wire = wf_owner;
+ compr_info.owner.size = ret;
+
+ dbg_response_detail("Compressed owner has size=%d\n",
+ compr_info.owner.size);
+ }
+
+ dbg_rrset_detail("Max size: %zu, size: %zu\n", max_size, size);
+
+ // No RDATA, just save header and 0 RDLENGTH.
+ if (rrset->rdata_count == 0) {
+ size_t header_size = 0;
+ int ret = knot_rrset_header_to_wire(rrset, pos, max_size,
+ comp ? &compr_info : NULL,
+ &header_size);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+
+ // Save zero rdata length.
+ knot_wire_write_u16(*pos, 0);
+ *pos += sizeof(uint16_t);
+ header_size += sizeof(uint16_t);
+
+ return header_size;
+ }
+
+ // Save rrset records.
+ for (uint16_t i = 0; i < rrset->rdata_count; ++i) {
+ dbg_rrset_detail("rrset: to_wire: Current max_size=%zu\n",
+ max_size);
+ size_t rr_size = 0;
+ int ret = knot_rrset_rdata_to_wire_one(rrset, i, pos, max_size,
+ &rr_size,
+ comp ? &compr_info : NULL);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rrset: to_wire: Cannot convert RR. "
+ "Reason: %s.\n", knot_strerror(ret));
+ return ret;
+ }
+ dbg_rrset_detail("Converted RR nr=%d, size=%zu\n", i, rr_size);
+ /* Change size of whole RRSet. */
+ size += rr_size;
+ /* Change max size. */
+ max_size -= rr_size;
+ }
+
+ dbg_rrset_detail("Max size: %zu, size: %zu\n", max_size, size);
+
+ return size;
+}
+
+static int knot_rrset_rdata_store_binary(uint8_t *rdata, size_t *offset,
+ size_t packet_offset,
+ const uint8_t *wire,
+ size_t *pos,
+ size_t rdlength,
+ size_t size)
+{
+ assert(rdata);
+ assert(wire);
+
+ /* Check that size is OK. */
+ if ((*pos - packet_offset) + size > rdlength) {
+ dbg_rrset("rrset: rdata_store_binary: Read of size=%zu on "
+ "position %zu exceeded RDLENGTH by %zu octets.\n", size,
+ *pos, ((*pos - packet_offset) + size) - rdlength);
+ return KNOT_ESPACE;
+ }
+
+ /* Store actual data. */
+ memcpy(rdata + *offset, wire + *pos, size);
+ *offset += size;
+ *pos += size;
+
+ return KNOT_EOK;
+}
+
+static int rrset_type_multiple_dnames(const knot_rrset_t *rrset)
+{
+ if (rrset->type == KNOT_RRTYPE_SOA || rrset->type == KNOT_RRTYPE_MINFO ||
+ rrset->type == KNOT_RRTYPE_RP) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int rrset_find_rr_pos_for_pointer(const knot_rrset_t *rrset,
+ knot_dname_t **p, size_t *pos)
+{
+ if (p == NULL) {
+ return 0;
+ }
+
+ /* [code-review] Added check of 'p' validity - whether it
+ * points to the RDATA array of 'rrset'.
+ */
+ if ((size_t)p < (size_t)rrset->rdata
+ || (size_t)p > (size_t)rrset->rdata
+ + rrset_rdata_size_total(rrset)) {
+ // 'p' is not within the RDATA array
+ return KNOT_ERANGE;
+ }
+
+ size_t offset = (size_t)p - (size_t)rrset->rdata;
+
+ if (offset < rrset_rdata_item_size(rrset, 0)) {
+ return 0;
+ }
+ for (uint16_t i = 0; i < rrset->rdata_count; ++i) {
+ if (rrset_rdata_offset(rrset, i) > offset) {
+ *pos = i - 1;
+ return KNOT_EOK;
+ } else if (rrset_rdata_offset(rrset, i) == offset) {
+ *pos = i;
+ return KNOT_EOK;
+ }
+ }
+ *pos = rrset->rdata_count - 1;
+ return KNOT_EOK;
+}
+
+static size_t rrset_binary_size_one(const knot_rrset_t *rrset,
+ size_t rdata_pos)
+{
+ const rdata_descriptor_t *desc =
+ get_rdata_descriptor(knot_rrset_type(rrset));
+
+ size_t offset = 0;
+ size_t size = 0;
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+ int item = desc->block_types[i];
+ uint8_t *rdata = rrset_rdata_pointer(rrset, rdata_pos);
+ if (descriptor_item_is_dname(item)) {
+ knot_dname_t *dname;
+ memcpy(&dname, rdata + offset, sizeof(knot_dname_t *));
+ assert(dname);
+ offset += sizeof(knot_dname_t *);
+ size += knot_dname_size(dname) + 1; // extra 1 - we need a size
+ } else if (descriptor_item_is_fixed(item)) {
+ offset += item;
+ size += item;
+ } else if (descriptor_item_is_remainder(item)) {
+ size += rrset_rdata_item_size(rrset, rdata_pos) -
+ offset;
+ } else {
+ assert(rrset->type == KNOT_RRTYPE_NAPTR);
+ uint16_t naptr_chunk_size =
+ rrset_rdata_naptr_bin_chunk_size(rrset, rdata_pos);
+ /*
+ * Regular expressions in NAPTR are TXT's, so they
+ * can be upto 64k long.
+ */
+ size += naptr_chunk_size + 2;
+ offset += naptr_chunk_size;
+ }
+ }
+
+ return size;
+}
+
+static void rrset_serialize_rr(const knot_rrset_t *rrset, size_t rdata_pos,
+ uint8_t *stream, size_t *size)
+{
+ const rdata_descriptor_t *desc =
+ get_rdata_descriptor(knot_rrset_type(rrset));
+
+ size_t offset = 0;
+ *size = 0;
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+ int item = desc->block_types[i];
+ uint8_t *rdata = rrset_rdata_pointer(rrset, rdata_pos);
+ if (descriptor_item_is_dname(item)) {
+ knot_dname_t *dname;
+ memcpy(&dname, rdata + offset, sizeof(knot_dname_t *));
+ assert(dname);
+ memcpy(stream + *size, &dname->size, 1);
+ *size += 1;
+ memcpy(stream + *size, dname->name, dname->size);
+ offset += sizeof(knot_dname_t *);
+ *size += dname->size;
+ } else if (descriptor_item_is_fixed(item)) {
+ memcpy(stream + *size, rdata + offset, item);
+ offset += item;
+ *size += item;
+ } else if (descriptor_item_is_remainder(item)) {
+ uint16_t remainder_size =
+ rrset_rdata_item_size(rrset,
+ rdata_pos) - offset;
+ memcpy(stream + *size, rdata + offset, remainder_size);
+ *size += remainder_size;
+ } else {
+ assert(rrset->type == KNOT_RRTYPE_NAPTR);
+ /* Copy static chunk. */
+ uint16_t naptr_chunk_size =
+ rrset_rdata_naptr_bin_chunk_size(rrset, rdata_pos);
+ /* We need a length. */
+ memcpy(stream + *size, &naptr_chunk_size,
+ sizeof(uint16_t));
+ *size += sizeof(uint16_t);
+ /* Write data. */
+ memcpy(stream + *size, rdata + offset, naptr_chunk_size);
+ }
+ }
+
+ dbg_rrset_detail("RR nr=%zu serialized, size=%zu\n", rdata_pos, *size);
+}
+
+static int rrset_deserialize_rr(knot_rrset_t *rrset, size_t rdata_pos,
+ uint8_t *stream, uint32_t rdata_size,
+ size_t *read)
+{
+ const rdata_descriptor_t *desc =
+ get_rdata_descriptor(knot_rrset_type(rrset));
+
+ size_t stream_offset = 0;
+ size_t rdata_offset = 0;
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+ int item = desc->block_types[i];
+ uint8_t *rdata = rrset_rdata_pointer(rrset, rdata_pos);
+ if (descriptor_item_is_dname(item)) {
+ /* Read dname size. */
+ uint8_t dname_size = 0;
+ memcpy(&dname_size, stream + stream_offset, 1);
+ stream_offset += 1;
+ knot_dname_t *dname =
+ knot_dname_new_from_wire(stream + stream_offset,
+ dname_size, NULL);
+ if (dname == NULL) {
+ return KNOT_ERROR;
+ }
+ assert(dname->size == dname_size);
+ memcpy(rdata + rdata_offset, &dname,
+ sizeof(knot_dname_t *));
+ stream_offset += dname_size;
+ rdata_offset += sizeof(knot_dname_t *);
+ } else if (descriptor_item_is_fixed(item)) {
+ memcpy(rdata + rdata_offset, stream + stream_offset, item);
+ rdata_offset += item;
+ stream_offset += item;
+ } else if (descriptor_item_is_remainder(item)) {
+ size_t remainder_size = rdata_size - stream_offset;
+ memcpy(rdata + rdata_offset, stream + stream_offset,
+ remainder_size);
+ stream_offset += remainder_size;
+ } else {
+ assert(rrset->type == KNOT_RRTYPE_NAPTR);
+ /* Read size. */
+ uint16_t naptr_chunk_size;
+ memcpy(&naptr_chunk_size, stream + stream_offset,
+ sizeof(uint16_t));
+ stream_offset += sizeof(uint16_t);
+ memcpy(rdata + rdata_offset, stream + stream_offset,
+ naptr_chunk_size);
+ stream_offset += naptr_chunk_size;
+ rdata_offset += rdata_offset;
+ }
+ }
+ *read = stream_offset;
+ return KNOT_EOK;
+}
+
+int knot_rrset_remove_rdata_pos(knot_rrset_t *rrset, size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return KNOT_EINVAL;
+ }
+
+ /* Handle DNAMEs inside RDATA. */
+ int ret = rrset_rr_dnames_apply(rrset, pos, rrset_release_dnames_in_rr,
+ NULL);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rr: remove_rdata_pos: Could not release DNAMEs "
+ "within RDATA (%s).\n", knot_strerror(ret));
+ return ret;
+ }
+
+ /* Reorganize the actual RDATA array. */
+ uint8_t *rdata_to_remove = rrset_rdata_pointer(rrset, pos);
+ dbg_rrset_detail("rr: remove_rdata_pos: Removing data=%p on "
+ "position=%zu\n", rdata_to_remove, pos);
+ assert(rdata_to_remove);
+ if (pos != rrset->rdata_count - 1) {
+ /* Not the last item in array - we need to move the data. */
+ uint8_t *next_rdata = rrset_rdata_pointer(rrset, pos + 1);
+ assert(next_rdata);
+ size_t remainder_size = rrset_rdata_size_total(rrset)
+ - rrset_rdata_offset(rrset, pos + 1);
+ /*
+ * Copy the all following RR data to where this item is.
+ * No need to worry about exceeding allocated space now.
+ */
+ memmove(rdata_to_remove, next_rdata, remainder_size);
+ }
+
+ uint32_t removed_size = rrset_rdata_item_size(rrset, pos);
+ uint32_t new_size = rrset_rdata_size_total(rrset) - removed_size;
+
+ /*! \todo Realloc might not be needed. Only if the RRSet is large. */
+ if (new_size == 0) {
+ assert(rrset->rdata_count == 1);
+ free(rrset->rdata);
+ rrset->rdata = NULL;
+ free(rrset->rdata_indices);
+ rrset->rdata_indices = NULL;
+ } else {
+ /* [code-review] Should not be done always - as said in the TODO
+ * above. But also, why here and not in the part
+ * handling the RDATA array?
+ */
+ rrset->rdata = xrealloc(rrset->rdata, new_size);
+ /*
+ * Handle RDATA indices. All indices larger than the removed one
+ * have to be adjusted. Last index will be changed later.
+ */
+ /* [code-review] The upper bound should be rdata_count - 2, it
+ * has not yet been adjusted.
+ */
+ for (uint16_t i = pos; i < rrset->rdata_count - 1; ++i) {
+ rrset->rdata_indices[i] = rrset->rdata_indices[i + 1] - removed_size;
+ }
+
+ /* Save size of the whole RDATA array. Note: probably not needed! */
+ rrset->rdata_indices[rrset->rdata_count - 2] = new_size;
+
+ /* Resize indices, might not be needed, but we'll do it to be proper. */
+ rrset->rdata_indices =
+ xrealloc(rrset->rdata_indices,
+ (rrset->rdata_count - 1) * sizeof(uint32_t));
+ }
+
+ --rrset->rdata_count;
+
+ dbg_rrset_detail("rrset: remove rdata pos: RR after removal:\n");
+ knot_rrset_dump(rrset);
+
+ return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
/* API functions */
/*----------------------------------------------------------------------------*/
-knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type,
- uint16_t rclass, uint32_t ttl)
+uint32_t rrset_rdata_size_total(const knot_rrset_t *rrset)
{
- knot_rrset_t *ret = malloc(sizeof(knot_rrset_t));
- if (ret == NULL) {
- ERR_ALLOC_FAILED;
- return NULL;
+ if (rrset == NULL || rrset->rdata_indices == NULL ||
+ rrset->rdata_count == 0) {
+ return 0;
}
+ /* Last index denotes end of all RRs. */
+ return (rrset->rdata_indices[rrset->rdata_count - 1]);
+}
+
+knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type,
+ uint16_t rclass, uint32_t ttl)
+{
+ knot_rrset_t *ret = xmalloc(sizeof(knot_rrset_t));
+
ret->rdata = NULL;
+ ret->rdata_count = 0;
+ ret->rdata_indices = NULL;
/* Retain reference to owner. */
knot_dname_retain(owner);
@@ -85,107 +847,73 @@ knot_rrset_t *knot_rrset_new(knot_dname_t *owner, uint16_t type,
return ret;
}
-/*----------------------------------------------------------------------------*/
-
-int knot_rrset_add_rdata(knot_rrset_t *rrset, knot_rdata_t *rdata)
+int knot_rrset_add_rdata(knot_rrset_t *rrset,
+ const uint8_t *rdata, uint16_t size)
{
- if (rrset == NULL || rdata == NULL) {
+ if (rrset == NULL || rdata == NULL || size == 0) {
return KNOT_EINVAL;
}
- if (rrset->rdata == NULL) {
- rrset->rdata = rdata;
- rrset->rdata->next = rrset->rdata;
- } else {
- knot_rdata_t *tmp;
-
- tmp = rrset->rdata;
+ uint8_t *p = knot_rrset_create_rdata(rrset, size);
+ memcpy(p, rdata, size);
- while (tmp->next != rrset->rdata) {
- tmp = tmp->next;
- }
- rdata->next = tmp->next;
- tmp->next = rdata;
- }
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
-int knot_rrset_add_rdata_order(knot_rrset_t *rrset, knot_rdata_t *rdata)
+uint8_t* knot_rrset_create_rdata(knot_rrset_t *rrset, uint16_t size)
{
- if (rrset == NULL || rdata == NULL) {
- dbg_rrset("rrset: add_rdata_order: NULL arguments.\n");
- return KNOT_EINVAL;
+ if (rrset == NULL || size == 0) {
+ return NULL;
}
-
- if (rrset->rdata == NULL) {
- /* Easy peasy, just insert the first item. */
- rrset->rdata = rdata;
- rrset->rdata->next = rrset->rdata;
+
+ uint32_t total_size = rrset_rdata_size_total(rrset);
+
+ /* Realloc indices. We will allocate exact size to save space. */
+ /* TODO this sucks big time - allocation of length 1. */
+ /* But another variable holding allocated count is out of question. What now?*/
+ rrset->rdata_indices = xrealloc(rrset->rdata_indices,
+ (rrset->rdata_count + 1) * sizeof(uint32_t));
+
+ /* Realloc actual data. */
+ rrset->rdata = xrealloc(rrset->rdata, total_size + size);
+
+ /* Pointer to new memory. */
+ uint8_t *dst = rrset->rdata + total_size;
+
+ /* Update indices. */
+ if (rrset->rdata_count == 0) {
+ rrset->rdata_indices[0] = size;
} else {
- knot_rdata_t *walk = NULL;
- char found = 0;
- knot_rdata_t *insert_after = rrset->rdata;
- while (((walk = knot_rrset_rdata_get_next(rrset,
- walk)) != NULL) &&
- (!found)) {
- const knot_rrtype_descriptor_t *desc =
- knot_rrtype_descriptor_by_type(rrset->type);
- assert(desc);
- int cmp = knot_rdata_compare(rdata, walk,
- desc->wireformat);
- if (cmp < 1) {
- /* We've found place for this item. */
- } else if (cmp == 0) {
- /* This item will not be inserted. */
- found = 1;
- insert_after = NULL;
- }
- assert(cmp > 1);
- /* Continue the search. */
- insert_after = walk;
- }
- if (insert_after != NULL) {
- rdata->next = insert_after->next;
- insert_after->next = rdata;
- } else {
- ;
- /* Consider returning something different than EOK. */
- }
+ rrset->rdata_indices[rrset->rdata_count - 1] = total_size;
+ rrset->rdata_indices[rrset->rdata_count] = total_size + size;
}
- return KNOT_EOK;
+
+ ++rrset->rdata_count;
+
+ return dst;
}
/*----------------------------------------------------------------------------*/
-knot_rdata_t *knot_rrset_remove_rdata(knot_rrset_t *rrset,
- const knot_rdata_t *rdata)
-{
- if (rrset == NULL || rdata == NULL) {
- return NULL;
- }
- knot_rdata_t *prev = NULL;
- knot_rdata_t *rr = rrset->rdata;
- knot_rrtype_descriptor_t *desc =
- knot_rrtype_descriptor_by_type(rrset->type);
-
- if (desc == NULL) {
- return NULL;
+uint16_t rrset_rdata_item_size(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || rrset->rdata_indices == NULL ||
+ rrset->rdata_count == 0) {
+ //invalid case
+ return 0;
}
- while (rr != NULL) {
- /*! \todo dnames are compared case-insensitive. is it OK?*/
- if (knot_rdata_compare(rr, rdata, desc->wireformat) == 0) {
- knot_rrset_disconnect_rdata(rrset, prev, rr);
- return rr;
- }
- prev = rr;
- rr = knot_rrset_rdata_get_next(rrset, rr);
+ if (rrset->rdata_count == 1 || pos == 0) {
+ //first RR or only one RR (either size of first RR or total size)
+ return rrset->rdata_indices[0];
}
- return NULL;
+ assert(rrset->rdata_count >= 2 && pos != 0);
+ return rrset->rdata_indices[pos] - rrset->rdata_indices[pos - 1];
}
/*----------------------------------------------------------------------------*/
@@ -203,31 +931,27 @@ int knot_rrset_set_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs)
/*----------------------------------------------------------------------------*/
int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs,
- knot_rrset_dupl_handling_t dupl)
+ knot_rrset_dupl_handling_t dupl)
{
if (rrset == NULL || rrsigs == NULL
- || knot_dname_compare(rrset->owner, rrsigs->owner) != 0) {
+ || knot_dname_compare_non_canon(rrset->owner, rrsigs->owner) != 0) {
return KNOT_EINVAL;
}
int rc;
if (rrset->rrsigs != NULL) {
if (dupl == KNOT_RRSET_DUPL_MERGE) {
- rc = knot_rrset_merge_no_dupl((void **)&rrset->rrsigs,
- (void **)&rrsigs);
- if (rc < 0) {
+ int merged, deleted_rrs;
+ rc = knot_rrset_merge_no_dupl(rrset->rrsigs, rrsigs,
+ &merged, &deleted_rrs);
+ if (rc != KNOT_EOK) {
return rc;
- } else {
+ } else if (merged || deleted_rrs) {
return 1;
+ } else {
+ return 0;
}
} else if (dupl == KNOT_RRSET_DUPL_SKIP) {
-// rc = knot_rrset_merge_no_dupl((void **)&rrset->rrsigs,
-// (void **)&rrsigs);
-// if (rc != KNOT_EOK) {
-// return rc;
-// } else {
-// return 1;
-// }
return 2;
} else if (dupl == KNOT_RRSET_DUPL_REPLACE) {
rrset->rrsigs = rrsigs;
@@ -236,7 +960,6 @@ int knot_rrset_add_rrsigs(knot_rrset_t *rrset, knot_rrset_t *rrsigs,
if (rrset->ttl != rrsigs->ttl) {
rrsigs->ttl = rrset->ttl;
}
-
rrset->rrsigs = rrsigs;
}
@@ -259,7 +982,7 @@ knot_dname_t *knot_rrset_get_owner(const knot_rrset_t *rrset)
/*----------------------------------------------------------------------------*/
-void knot_rrset_set_owner(knot_rrset_t *rrset, knot_dname_t* owner)
+void knot_rrset_set_owner(knot_rrset_t *rrset, knot_dname_t *owner)
{
if (rrset) {
/* Retain new owner and release old owner. */
@@ -280,15 +1003,6 @@ void knot_rrset_set_ttl(knot_rrset_t *rrset, uint32_t ttl)
/*----------------------------------------------------------------------------*/
-void knot_rrset_set_class(knot_rrset_t *rrset, uint16_t rclass)
-{
- if (rrset) {
- rrset->rclass = rclass;
- }
-}
-
-/*----------------------------------------------------------------------------*/
-
uint16_t knot_rrset_type(const knot_rrset_t *rrset)
{
return rrset->type;
@@ -310,69 +1024,20 @@ uint32_t knot_rrset_ttl(const knot_rrset_t *rrset)
/*----------------------------------------------------------------------------*/
-const knot_rdata_t *knot_rrset_rdata(const knot_rrset_t *rrset)
+uint8_t *knot_rrset_get_rdata(const knot_rrset_t *rrset, size_t rdata_pos)
{
- return rrset->rdata;
+ return rrset_rdata_pointer(rrset, rdata_pos);
}
/*----------------------------------------------------------------------------*/
-const knot_rdata_t *knot_rrset_rdata_next(const knot_rrset_t *rrset,
- const knot_rdata_t *rdata)
+uint16_t knot_rrset_rdata_rr_count(const knot_rrset_t *rrset)
{
- if (rdata == NULL) {
- return rrset->rdata;
- }
- if (rdata->next == rrset->rdata) {
- return NULL;
+ if (rrset != NULL) {
+ return rrset->rdata_count;
} else {
- return rdata->next;
- }
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_rdata_t *knot_rrset_get_rdata(knot_rrset_t *rrset)
-{
- if (rrset == NULL) {
- return NULL;
- } else {
- return rrset->rdata;
- }
-}
-
-/*----------------------------------------------------------------------------*/
-
-knot_rdata_t *knot_rrset_rdata_get_next(knot_rrset_t *rrset,
- knot_rdata_t *rdata)
-{
- if (!rdata || !rrset) {
- return NULL;
- }
- if (rdata->next == rrset->rdata) {
- return NULL;
- } else {
- return rdata->next;
- }
-}
-
-/*----------------------------------------------------------------------------*/
-
-int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset)
-{
- if (rrset == NULL) {
return 0;
}
-
- int count = 0;
- const knot_rdata_t *rdata = rrset->rdata;
-
- while (rdata != NULL) {
- ++count;
- rdata = knot_rrset_rdata_next(rrset, rdata);
- }
-
- return count;
}
/*----------------------------------------------------------------------------*/
@@ -380,7 +1045,6 @@ int knot_rrset_rdata_rr_count(const knot_rrset_t *rrset)
const knot_rrset_t *knot_rrset_rrsigs(const knot_rrset_t *rrset)
{
if (rrset == NULL) {
- assert(0);
return NULL;
} else {
return rrset->rrsigs;
@@ -392,255 +1056,268 @@ const knot_rrset_t *knot_rrset_rrsigs(const knot_rrset_t *rrset)
knot_rrset_t *knot_rrset_get_rrsigs(knot_rrset_t *rrset)
{
if (rrset == NULL) {
- assert(0);
return NULL;
} else {
return rrset->rrsigs;
}
}
-/*----------------------------------------------------------------------------*/
-
-int knot_rrset_compare_rdata(const knot_rrset_t *r1, const knot_rrset_t *r2)
+int knot_rrset_rdata_equal(const knot_rrset_t *r1, const knot_rrset_t *r2)
{
- if (r1 == NULL || r2 == NULL) {
- return KNOT_EINVAL;
- }
-
- knot_rrtype_descriptor_t *desc =
- knot_rrtype_descriptor_by_type(r1->type);
- if (desc == NULL) {
+ if (r1 == NULL || r2 == NULL || (r1->type != r2->type) ||
+ r1->rdata_count == 0 || r2->rdata_count == 0) {
return KNOT_EINVAL;
}
// compare RDATA sets (order is not significant)
- const knot_rdata_t *rdata1 = knot_rrset_rdata(r1);
- const knot_rdata_t *rdata2;
// find all RDATA from r1 in r2
- while (rdata1 != NULL) {
- rdata2 = knot_rrset_rdata(r2);
- while (rdata2 != NULL && knot_rdata_compare(rdata1, rdata2,
- desc->wireformat)) {
- rdata2 = knot_rrset_rdata_next(r2, rdata2);
- }
-
- if (rdata2 == NULL) {
- // RDATA from r1 not found in r2
- return 0;
- }
-
- // otherwise it was found, continue with next r1 RDATA
- rdata1 = knot_rrset_rdata_next(r1, rdata1);
+ int found = 0;
+ for (uint16_t i = 0; i < r1->rdata_count; i++) {
+ found = 0;
+ for (uint16_t j = 0; j < r2->rdata_count && !found; j++) {
+ found = !rrset_rdata_compare_one(r1, r2, i, j);
+ }
}
- // find all RDATA from r2 in r1 (this can be done in a better way)
- rdata2 = knot_rrset_rdata(r2);
- while (rdata2 != NULL) {
- rdata1 = knot_rrset_rdata(r1);
-
- while (rdata2 != NULL && rdata1 != NULL
- && knot_rdata_compare(rdata1, rdata2,
- desc->wireformat)) {
- rdata1 = knot_rrset_rdata_next(r1, rdata1);
- }
+ if (!found) {
+ return 0;
+ }
- if (rdata1 == NULL) {
- // RDATA from r2 not found in r1
- return 0;
- }
+ // other way around
+ for (uint16_t i = 0; i < r2->rdata_count; i++) {
+ found = 0;
+ for (uint16_t j = 0; j < r1->rdata_count && !found; j++) {
+ found = !rrset_rdata_compare_one(r1, r2, j, i);
+ }
+ }
- // otherwise it was found, continue with next r1 RDATA
- rdata2 = knot_rrset_rdata_next(r2, rdata2);
+ if (!found) {
+ return 0;
}
- // all RDATA found
return 1;
}
/*----------------------------------------------------------------------------*/
-static int knot_rrset_rr_to_wire(const knot_rrset_t *rrset,
- const knot_rdata_t *rdata, uint8_t **pos,
- size_t max_size)
+int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size,
+ size_t max_size, uint16_t *rr_count, void *data)
{
- int size = 0;
-
- assert(rrset != NULL);
- assert(rrset->owner != NULL);
- assert(rdata != NULL);
- assert(pos != NULL);
- assert(*pos != NULL);
-
- dbg_rrset_detail("Max size: %zu, owner: %p, owner size: %d\n",
- max_size, rrset->owner, rrset->owner->size);
-
- // check if owner fits
- if (size + knot_dname_size(rrset->owner) + 10 > max_size) {
- return KNOT_ESPACE;
+ if (rrset == NULL || wire == NULL || size == NULL || rr_count == NULL) {
+ return KNOT_EINVAL;
}
-
- memcpy(*pos, knot_dname_name(rrset->owner),
- knot_dname_size(rrset->owner));
- *pos += knot_dname_size(rrset->owner);
- size += knot_dname_size(rrset->owner);
-
- dbg_rrset_detail("Max size: %zu, size: %d\n", max_size, size);
-
- dbg_rrset_detail("Wire format:\n");
-
- // put rest of RR 'header'
- knot_wire_write_u16(*pos, rrset->type);
- dbg_rrset_detail(" Type: %u\n", rrset->type);
- *pos += 2;
-
- knot_wire_write_u16(*pos, rrset->rclass);
- dbg_rrset_detail(" Class: %u\n", rrset->rclass);
- *pos += 2;
-
- knot_wire_write_u32(*pos, rrset->ttl);
- dbg_rrset_detail(" TTL: %u\n", rrset->ttl);
- *pos += 4;
-
- // save space for RDLENGTH
- uint8_t *rdlength_pos = *pos;
- *pos += 2;
-
- size += 10;
-
- dbg_rrset_detail("Max size: %zu, size: %d\n", max_size, size);
- knot_rrtype_descriptor_t *desc =
- knot_rrtype_descriptor_by_type(rrset->type);
+ compression_param_t *comp_data = (compression_param_t *)data;
+ uint8_t *pos = wire;
- uint16_t rdlength = 0;
+dbg_rrset_exec_detail(
+ dbg_rrset_detail("Converting following RRSet:\n");
+ knot_rrset_dump(rrset);
+);
- for (int i = 0; i < rdata->count; ++i) {
- if (max_size < size + rdlength) {
- return KNOT_ESPACE;
- }
-
- switch (desc->wireformat[i]) {
- case KNOT_RDATA_WF_COMPRESSED_DNAME:
- case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
- case KNOT_RDATA_WF_LITERAL_DNAME: {
- knot_dname_t *dname =
- knot_rdata_item(rdata, i)->dname;
- if (size + rdlength + dname->size > max_size) {
- return KNOT_ESPACE;
- }
+ int ret = knot_rrset_to_wire_aux(rrset, &pos, max_size, comp_data);
+ if (ret < 0) {
+ // some RR didn't fit in, so no RRs should be used
+ // TODO: remove last entries from compression table
+ dbg_rrset_verb("Some RR didn't fit in.\n");
+ return KNOT_ESPACE;
+ }
- // save whole domain name
- memcpy(*pos, knot_dname_name(dname),
- knot_dname_size(dname));
- dbg_rrset_detail("Uncompressed dname size: %d\n",
- knot_dname_size(dname));
- *pos += knot_dname_size(dname);
- rdlength += knot_dname_size(dname);
- break;
- }
- default: {
- uint16_t *raw_data =
- knot_rdata_item(rdata, i)->raw_data;
+ // Check if the whole RRSet fit into packet.
+ assert(ret <= max_size);
+ assert(pos - wire == ret);
- if (size + rdlength + raw_data[0] > max_size) {
- return KNOT_ESPACE;
- }
+ *size = ret;
- // copy just the rdata item data (without size)
- memcpy(*pos, raw_data + 1, raw_data[0]);
- dbg_rrset_detail("Raw data size: %d\n", raw_data[0]);
- *pos += raw_data[0];
- rdlength += raw_data[0];
- break;
- }
- }
- }
-
- dbg_rrset_detail("Max size: %zu, size: %d\n", max_size, size);
+ dbg_rrset_detail("Size after: %zu\n", *size);
- assert(size + rdlength <= max_size);
- size += rdlength;
- knot_wire_write_u16(rdlength_pos, rdlength);
+ // If the rrset is empty set record counter to 1.
+ *rr_count = rrset->rdata_count > 0 ? rrset->rdata_count : 1;
- return size;
+ return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
-int knot_rrset_to_wire(const knot_rrset_t *rrset, uint8_t *wire, size_t *size,
- int *rr_count)
+int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
+ const uint8_t *wire, size_t *pos,
+ size_t total_size, size_t rdlength)
{
- // if no RDATA in RRSet, return
- if (rrset->rdata == NULL) {
- *size = 0;
- *rr_count = 0;
+ /* [code-review] Missing parameter checks. */
+
+ if (rdlength == 0) {
+ /* Nothing to parse, */
return KNOT_EOK;
}
-
-
- uint8_t *pos = wire;
- int rrs = 0;
- short rrset_size = 0;
- const knot_rdata_t *rdata = rrset->rdata;
- do {
- int ret = knot_rrset_rr_to_wire(rrset, rdata, &pos,
- *size - rrset_size);
+ dbg_rrset_detail("rr: parse_rdata_wire: Parsing RDATA of size=%zu,"
+ " wire_size=%zu, type=%d.\n", rdlength, total_size,
+ rrset->type);
- assert(ret != 0);
+ size_t extra_dname_size = 0;
+ const rdata_descriptor_t *desc = get_rdata_descriptor(rrset->type);
- if (ret < 0) {
- // some RR didn't fit in, so no RRs should be used
- // TODO: remove last entries from compression table
- dbg_rrset_verb("Some RR didn't fit in.\n");
- return KNOT_ESPACE;
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; ++i) {
+ if (descriptor_item_is_dname(desc->block_types[i])) {
+ extra_dname_size += sizeof(knot_dname_t *) - 1;
}
+ }
- dbg_rrset_verb("RR of size %d added.\n", ret);
- rrset_size += ret;
- ++rrs;
- } while ((rdata = knot_rrset_rdata_next(rrset, rdata)) != NULL);
-
- // the whole RRSet did fit in
- assert(rrset_size <= *size);
- assert(pos - wire == rrset_size);
- *size = rrset_size;
+ /* [code-review] Isn't this invalid? You cannot do static allocation
+ * with dynamic data (parameter, local variable).
+ */
+ uint8_t rdata_buffer[rdlength + extra_dname_size];
+ memset(rdata_buffer, 0, rdlength + extra_dname_size);
+ dbg_rrset_detail("rr: parse_rdata_wire: Added %zu bytes to buffer to "
+ "store RDATA DNAME pointers.\n", extra_dname_size);
+
+ size_t offset = 0; // offset within in-memory RDATA
+ size_t parsed = 0; // actual count of parsed octets
+ const size_t packet_offset = *pos;
+
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END &&
+ parsed < rdlength; ++i) {
+ size_t pos2 = 0; //used for DNAME parsing
+ const int item = desc->block_types[i];
+ if (descriptor_item_is_dname(item)) {
+ pos2 = *pos;
+ knot_dname_t *dname = knot_dname_parse_from_wire(
+ wire, &pos2, total_size, NULL, NULL);
+ if (dname == NULL) {
+ return KNOT_EMALF;
+ }
+ knot_dname_to_lower(dname);
+ memcpy(rdata_buffer + offset, &dname,
+ sizeof(knot_dname_t *));
+ parsed += pos2 - *pos;
+ dbg_rrset_detail("rr: parse_rdata_wire: Parsed DNAME, "
+ "length=%zu.\n", pos2 - *pos);
+dbg_rrset_exec_detail(
+ char *name = knot_dname_to_str(dname);
+ dbg_rrset_detail("rr: parse_rdata_wire: Parsed "
+ "DNAME=%s\n", name);
+ free(name);
+);
+ *pos = pos2;
+ offset += sizeof(knot_dname_t *);
+ } else if (descriptor_item_is_fixed(item)) {
+ dbg_rrset_detail("rr: parse_rdata_wire: Saving static "
+ "chunk of size=%u\n", item);
+ int ret = knot_rrset_rdata_store_binary(rdata_buffer,
+ &offset,
+ packet_offset,
+ wire,
+ pos,
+ rdlength,
+ item);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rrset: rdata_from_wire: "
+ "Cannot store fixed RDATA chunk. "
+ "Reason: %s.\n", knot_strerror(ret));
+ return ret;
+ }
+ parsed += item;
+ } else if (descriptor_item_is_remainder(item)) {
+ /* Item size has to be calculated. */
+ size_t remainder_size = rdlength - parsed;
+ dbg_rrset_detail("rr: parse_rdata_wire: Saving remaining "
+ "chunk of size=%zu\n", remainder_size);
+ int ret = knot_rrset_rdata_store_binary(rdata_buffer,
+ &offset,
+ packet_offset,
+ wire,
+ pos,
+ rdlength,
+ remainder_size);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rrset: rdata_from_wire: "
+ "Cannot store RDATA remainder of "
+ "size=%zu, RDLENGTH=%zu. "
+ "Reason: %s.\n", remainder_size,
+ rdlength, knot_strerror(ret));
+ return ret;
+ }
+ parsed += remainder_size;
+ } else {
+ assert(rrset->type == KNOT_RRTYPE_NAPTR);
+ /* Read fixed part - 2 shorts. */
+ const size_t naptr_fixed_part_size = 4;
+ int ret = knot_rrset_rdata_store_binary(rdata_buffer,
+ &offset,
+ packet_offset,
+ wire,
+ pos,
+ rdlength,
+ naptr_fixed_part_size);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rrset: rdata_from_wire: "
+ "Cannot store NAPTR fixed part. "
+ "Reason: %s.\n", knot_strerror(ret));
+ return ret;
+ }
+ parsed += naptr_fixed_part_size;
+ for (int j = 0; j < 3; ++j) {
+ /* Read sizes of TXT's - one byte. */
+ uint8_t txt_size = *(wire + (*pos)) + 1;
+ dbg_rrset_detail("rrset: rdata_from_wire: "
+ "Read TXT nr=%d size=%d\n", j,
+ txt_size);
+ int ret = knot_rrset_rdata_store_binary(rdata_buffer,
+ &offset,
+ packet_offset,
+ wire,
+ pos,
+ rdlength,
+ txt_size);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rrset: rdata_from_wire: "
+ "Cannot store NAPTR TXTs. "
+ "Reason: %s.\n", knot_strerror(ret));
+ return ret;
+ }
+ parsed += txt_size;
+ }
+ }
+ }
- dbg_rrset_detail("Size after: %zu\n", *size);
+ uint8_t *rdata = knot_rrset_create_rdata(rrset, offset);
+ if (rdata == NULL) {
+ return KNOT_ENOMEM;
+ }
- *rr_count = rrs;
+ memcpy(rdata, rdata_buffer, offset);
return KNOT_EOK;
}
-/*----------------------------------------------------------------------------*/
-
-int knot_rrset_match(const knot_rrset_t *r1,
- const knot_rrset_t *r2,
- knot_rrset_compare_type_t cmp)
+int knot_rrset_equal(const knot_rrset_t *r1,
+ const knot_rrset_t *r2,
+ knot_rrset_compare_type_t cmp)
{
if (cmp == KNOT_RRSET_COMPARE_PTR) {
- return (r1 == r2);
+ return r1 == r2;
}
- int res = ((r1->rclass == r2->rclass)
- && (r1->type == r2->type)
-// && (r1->ttl == r2->ttl)
- && knot_dname_compare(r1->owner, r2->owner) == 0);
+ int res = knot_dname_compare_non_canon(r1->owner, r2->owner);
+ if (res != 0) {
+ return 0;
+ }
- if (cmp == KNOT_RRSET_COMPARE_WHOLE && res) {
- res = knot_rrset_compare_rdata(r1, r2);
- if (res < 0) {
- return 0;
- }
+ if (r1->rclass == r2->rclass &&
+ r1->type == r2->type) {
+ res = 1;
+ } else {
+ res = 0;
+ }
+
+ if (cmp == KNOT_RRSET_COMPARE_WHOLE && res == 1) {
+ res = knot_rrset_rdata_equal(r1, r2);
}
return res;
}
-/*----------------------------------------------------------------------------*/
-
int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to,
int copy_rdata_dnames)
{
@@ -648,48 +1325,72 @@ int knot_rrset_deep_copy(const knot_rrset_t *from, knot_rrset_t **to,
return KNOT_EINVAL;
}
- int ret;
+ dbg_rrset_detail("rr: deep_copy: Copying RRs of type %d\n",
+ from->type);
- *to = (knot_rrset_t *)calloc(1, sizeof(knot_rrset_t));
- CHECK_ALLOC_LOG(*to, KNOT_ENOMEM);
+ *to = xmalloc(sizeof(knot_rrset_t));
+
+ (*to)->owner = knot_dname_deep_copy(from->owner);
+ if ((*to)->owner == NULL) {
+ free(*to);
+ *to = NULL;
+ return KNOT_ENOMEM;
+ }
- (*to)->owner = from->owner;
- knot_dname_retain((*to)->owner);
(*to)->rclass = from->rclass;
(*to)->ttl = from->ttl;
(*to)->type = from->type;
+ (*to)->rdata_count = from->rdata_count;
if (from->rrsigs != NULL) {
- ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs,
+ int ret = knot_rrset_deep_copy(from->rrsigs, &(*to)->rrsigs,
copy_rdata_dnames);
if (ret != KNOT_EOK) {
- knot_rrset_deep_free(to, 1, 0, 0);
+ knot_rrset_deep_free(to, 1, 0);
return ret;
}
+ } else {
+ (*to)->rrsigs = NULL;
}
- assert((*to)->rrsigs == NULL || from->rrsigs != NULL);
- const knot_rdata_t *rdata = knot_rrset_rdata(from);
-
- /*! \note Order of RDATA will be reversed. */
- while (rdata != NULL) {
- knot_rdata_t *rdata_copy = knot_rdata_deep_copy(rdata,
- knot_rrset_type(from),
- copy_rdata_dnames);
+ /* Just copy arrays - actual data + indices. */
+ (*to)->rdata = xmalloc(rrset_rdata_size_total(from));
+ memcpy((*to)->rdata, from->rdata, rrset_rdata_size_total(from));
+
+ (*to)->rdata_indices = xmalloc(sizeof(uint32_t) * from->rdata_count);
+ memcpy((*to)->rdata_indices, from->rdata_indices,
+ sizeof(uint32_t) * from->rdata_count);
+ /* Here comes the hard part. */
+ if (copy_rdata_dnames) {
+ knot_dname_t **dname_from = NULL;
+ knot_dname_t **dname_to = NULL;
+ knot_dname_t *dname_copy = NULL;
+ while ((dname_from = knot_rrset_get_next_dname(from, dname_from))) {
dbg_rrset_exec_detail(
- char *name = knot_dname_to_str(knot_rrset_owner(from));
- dbg_rrset_detail("Copying RDATA from RRSet with owner: %s, type"
- ": %s. Old RDATA ptr: %p, new RDATA ptr: %p\n",
- name,
- knot_rrtype_to_string(knot_rrset_type(from)),
- rdata, rdata_copy);
- free(name);
+ char *name = knot_dname_to_str(*dname_from);
+ dbg_rrset_detail("rrset: deep_copy: copying RDATA DNAME"
+ "=%s\n", name);
+ free(name);
);
- ret = knot_rrset_add_rdata(*to, rdata_copy);
- if (ret != KNOT_EOK) {
- knot_rrset_deep_free(to, 1, 1, 1);
- return ret;
+ size_t off = (uint8_t*)dname_from - from->rdata;
+ dname_to = (knot_dname_t **)((*to)->rdata + off);
+ /* These pointers have to be the same. */
+ assert(*dname_from == *dname_to);
+ dname_copy = knot_dname_deep_copy(*dname_from);
+ if (dname_copy == NULL) {
+ dbg_rrset("rrset: deep_copy: Cannot copy RDATA"
+ " dname.\n");
+ /*! \todo This will leak. Is it worth fixing? */
+ /* [code-review] Why will it leak? */
+ knot_rrset_deep_free(&(*to)->rrsigs, 1,
+ copy_rdata_dnames);
+ free((*to)->rdata);
+ free((*to)->rdata_indices);
+ free(*to);
+ return KNOT_ENOMEM;
+ }
+
+ *dname_to = dname_copy;
}
- rdata = knot_rrset_rdata_next(from, rdata);
}
return KNOT_EOK;
@@ -701,12 +1402,12 @@ int knot_rrset_shallow_copy(const knot_rrset_t *from, knot_rrset_t **to)
{
*to = (knot_rrset_t *)malloc(sizeof(knot_rrset_t));
CHECK_ALLOC_LOG(*to, KNOT_ENOMEM);
-
+
memcpy(*to, from, sizeof(knot_rrset_t));
/* Retain owner. */
knot_dname_retain((*to)->owner);
-
+
return KNOT_EOK;
}
@@ -733,103 +1434,124 @@ void knot_rrset_free(knot_rrset_t **rrset)
*rrset = NULL;
}
-/*----------------------------------------------------------------------------*/
-
void knot_rrset_deep_free(knot_rrset_t **rrset, int free_owner,
- int free_rdata, int free_rdata_dnames)
+ int free_rdata_dnames)
{
if (rrset == NULL || *rrset == NULL) {
return;
}
- if (free_rdata) {
- knot_rdata_t *tmp_rdata;
- knot_rdata_t *next_rdata;
- tmp_rdata = (*rrset)->rdata;
+ if ((*rrset)->rrsigs != NULL) {
+ knot_rrset_deep_free(&(*rrset)->rrsigs, free_owner, free_rdata_dnames);
+ }
- while ((tmp_rdata != NULL)
- && (tmp_rdata->next != (*rrset)->rdata)
- && (tmp_rdata->next != NULL)) {
- next_rdata = tmp_rdata->next;
- knot_rdata_deep_free(&tmp_rdata, (*rrset)->type,
- free_rdata_dnames);
- tmp_rdata = next_rdata;
- }
+ if (free_rdata_dnames) {
+ rrset_dnames_apply(*rrset, rrset_release_dnames_in_rr,
+ NULL);
+ }
- assert(tmp_rdata == NULL
- || tmp_rdata->next == (*rrset)->rdata);
+ free((*rrset)->rdata);
+ free((*rrset)->rdata_indices);
- knot_rdata_deep_free(&tmp_rdata, (*rrset)->type,
- free_rdata_dnames);
+ if (free_owner) {
+ knot_dname_release((*rrset)->owner);
}
- // RRSIGs should have the same owner as this RRSet, so do not delete it
- if ((*rrset)->rrsigs != NULL) {
- knot_rrset_deep_free(&(*rrset)->rrsigs, 0, 1,
- free_rdata_dnames);
+ free(*rrset);
+ *rrset = NULL;
+}
+
+void knot_rrset_deep_free_no_sig(knot_rrset_t **rrset, int free_owner,
+ int free_rdata_dnames)
+{
+ if (rrset == NULL || *rrset == NULL) {
+ return;
}
- knot_dname_release((*rrset)->owner);
+ if (free_rdata_dnames) {
+ int ret = rrset_dnames_apply(*rrset, rrset_release_dnames_in_rr,
+ NULL);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rr: deep_free: Could not free DNAMEs in RDATA.\n");
+ }
+ }
+
+ free((*rrset)->rdata);
+ free((*rrset)->rdata_indices);
+
+ if (free_owner) {
+ knot_dname_release((*rrset)->owner);
+ }
free(*rrset);
*rrset = NULL;
}
-/*----------------------------------------------------------------------------*/
-
-int knot_rrset_merge(void **r1, void **r2)
+int knot_rrset_merge(knot_rrset_t *rrset1, const knot_rrset_t *rrset2)
{
- knot_rrset_t *rrset1 = (knot_rrset_t *)(*r1);
- knot_rrset_t *rrset2 = (knot_rrset_t *)(*r2);
-
- if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0)
- || rrset1->rclass != rrset2->rclass
- || rrset1->type != rrset2->type) {
+ if (rrset1 == NULL || rrset2 == NULL) {
return KNOT_EINVAL;
}
- // add all RDATAs from rrset2 to rrset1 (i.e. concatenate linked lists)
+ /* Check, that we really merge RRSets? */
+ if (rrset1->type != rrset2->type ||
+ rrset1->rclass != rrset2->rclass ||
+ (knot_dname_compare_non_canon(rrset1->owner, rrset2->owner) != 0)) {
+ return KNOT_EINVAL;
+ }
- // no RDATA in RRSet 1
- assert(rrset1 && rrset2);
- if (rrset1->rdata == NULL) {
- rrset1->rdata = rrset2->rdata;
+ /* Merging empty RRSets is OK. */
+ if (rrset1->rdata_count == 0 && rrset2->rdata_count == 0) {
return KNOT_EOK;
}
- knot_rdata_t *tmp_rdata = rrset1->rdata;
+ /* Add all RDATAs from rrset2 to rrset1 (i.e. concatenate two arrays) */
- if (!tmp_rdata) {
- return KNOT_EOK;
- }
+ /*! \note The following code should work for
+ * all the cases i.e. R1 or R2 are empty.
+ */
- while (tmp_rdata->next != rrset1->rdata) {
- tmp_rdata = tmp_rdata->next;
- }
+ /* Reallocate actual RDATA array. */
+ rrset1->rdata = xrealloc(rrset1->rdata, rrset_rdata_size_total(rrset1) +
+ rrset_rdata_size_total(rrset2));
- tmp_rdata->next = rrset2->rdata;
+ /* The space is ready, copy the actual data. */
+ memcpy(rrset1->rdata + rrset_rdata_size_total(rrset1),
+ rrset2->rdata, rrset_rdata_size_total(rrset2));
- tmp_rdata = rrset2->rdata; //maybe unnecessary, but is clearer
+ /* Indices have to be readjusted. But space has to be made first. */
+ rrset1->rdata_indices =
+ xrealloc(rrset1->rdata_indices,
+ (rrset1->rdata_count + rrset2->rdata_count) *
+ sizeof(uint32_t));
+
+ uint32_t rrset1_total_size = rrset_rdata_size_total(rrset1);
+ uint32_t rrset2_total_size = rrset_rdata_size_total(rrset2);
+
+ /*
+ * Move the indices. Discard the last item in the first array, as it
+ * contains total length of the data, which is now different.
+ */
+ memcpy(rrset1->rdata_indices + rrset1->rdata_count,
+ rrset2->rdata_indices, rrset2->rdata_count);
- while (tmp_rdata->next != rrset2->rdata) {
- tmp_rdata = tmp_rdata->next;
+ /* Go through the second part of index array and adjust offsets. */
+ for (uint16_t i = 0; i < rrset2->rdata_count - 1; i++) {
+ rrset1->rdata_indices[rrset1->rdata_count + i] +=
+ rrset1_total_size;
}
- tmp_rdata->next = rrset1->rdata;
- rrset2->rdata = rrset1->rdata;
+ rrset1->rdata_indices[rrset1->rdata_count + rrset2->rdata_count - 1] =
+ rrset1_total_size + rrset2_total_size;
+
+ rrset1->rdata_count += rrset2->rdata_count;
return KNOT_EOK;
}
-int knot_rrset_merge_no_dupl(void **r1, void **r2)
+int knot_rrset_merge_no_dupl(knot_rrset_t *rrset1, const knot_rrset_t *rrset2,
+ int *merged, int *deleted_rrs)
{
- if (r1 == NULL || r2 == NULL) {
- dbg_rrset("rrset: merge_no_dupl: NULL arguments.");
- return KNOT_EINVAL;
- }
-
- knot_rrset_t *rrset1 = (knot_rrset_t *)(*r1);
- knot_rrset_t *rrset2 = (knot_rrset_t *)(*r2);
if (rrset1 == NULL || rrset2 == NULL) {
dbg_rrset("rrset: merge_no_dupl: NULL arguments.");
return KNOT_EINVAL;
@@ -841,7 +1563,7 @@ dbg_rrset_exec_detail(
free(name);
);
- if ((knot_dname_compare(rrset1->owner, rrset2->owner) != 0)
+ if ((knot_dname_compare_non_canon(rrset1->owner, rrset2->owner) != 0)
|| rrset1->rclass != rrset2->rclass
|| rrset1->type != rrset2->type) {
dbg_rrset("rrset: merge_no_dupl: Trying to merge "
@@ -849,124 +1571,1108 @@ dbg_rrset_exec_detail(
return KNOT_EINVAL;
}
- knot_rdata_t *walk2 = rrset2->rdata;
- int deleted = 0;
+ *deleted_rrs = 0;
+ *merged = 0;
+ /* For each item in second RRSet, make sure it is not duplicated. */
+ for (uint16_t i = 0; i < rrset2->rdata_count; i++) {
+ int duplicated = 0;
+ /* Compare with all RRs in the first RRSet. */
+ for (uint16_t j = 0; j < rrset1->rdata_count && !duplicated;
+ j++) {
+ duplicated = !rrset_rdata_compare_one(rrset1, rrset2,
+ j, i);
+ }
- // no RDATA in RRSet 1
- if (rrset1->rdata == NULL && rrset2->rdata != NULL) {
- /*
- * This function has to assure that there are no duplicates in
- * second RRSet's list. This can be done by putting a first
- * item from the second list as a first item of the first list
- * and then simply continuing with inserting items from second
- * list to the first one.
- *
- * However, we must store pointer to second item in the second
- * list, as the 'next' pointer of the first item will be altered
- */
+ if (!duplicated) {
+ *merged += 1; // = need to shallow free rrset2
+ // This index goes to merged RRSet.
+ int ret = knot_rrset_add_rdata(rrset1,
+ rrset_rdata_pointer(rrset2, i),
+ rrset_rdata_item_size(rrset2, i));
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rrset: merge_no_dupl: Could not "
+ "add RDATA to RRSet. (%s)\n",
+ knot_strerror(ret));
+ return ret;
+ }
+ } else {
+ *deleted_rrs += 1; // = need to shallow free rrset2
+ }
+ }
- // Store pointer to the second item in RRSet2 RDATA so that
- // we later start from this item.
- walk2 = knot_rrset_rdata_get_next(rrset2, walk2);
- assert(walk2 == rrset2->rdata->next || walk2 == NULL);
+ return KNOT_EOK;
+}
- // Connect the first item from second list to the first list.
- rrset1->rdata = rrset2->rdata;
- // Close the cyclic list (by pointing to itself).
- rrset1->rdata->next = rrset1->rdata;
- } else if (rrset2->rdata == NULL) {
- return KNOT_EOK;
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_rrset_rdata_cname_name(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
}
-
- /*
- * Check that rrset1 does not contain any rdata from rrset2, if so
- * such RDATA shall not be inserted.
- */
-
- /* Get last RDATA from first rrset, we'll need it for insertion. */
- knot_rdata_t *insert_after = rrset1->rdata;
- while (insert_after->next != rrset1->rdata) {
- dbg_rrset_detail("rrset: merge_dupl: first rrset rdata: %p.\n",
- insert_after);
- insert_after = insert_after->next;
- }
- assert(insert_after->next == rrset1->rdata);
-
- while (walk2 != NULL) {
- knot_rdata_t *walk1 = rrset1->rdata;
- char dupl = 0;
- while ((walk1 != NULL) &&
- !dupl) {
- const knot_rrtype_descriptor_t *desc =
- knot_rrtype_descriptor_by_type(rrset1->type);
- assert(desc);
- /* If walk1 and walk2 are equal, do not insert. */
- dupl = !knot_rdata_compare(walk1, walk2,
- desc->wireformat);
- walk1 = knot_rrset_rdata_get_next(rrset1, walk1);
- dbg_rrset_detail("rrset: merge_dupl: next item: %p.\n",
- walk1);
- }
- if (!dupl) {
- dbg_rrset_detail("rrset: merge_dupl: Inserting "
- "unique item (%p).\n",
- walk2);
- knot_rdata_t *tmp = walk2;
- /*
- * We need to move this, insertion
- * will corrupt pointers.
+
+ knot_dname_t *dname;
+ memcpy(&dname, rrset->rdata, sizeof(knot_dname_t *));
+ return dname;
+}
+
+/*----------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_rrset_rdata_dname_target(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+ knot_dname_t *dname;
+ memcpy(&dname, rrset->rdata, sizeof(knot_dname_t *));
+ return dname;
+}
+
+/*---------------------------------------------------------------------------*/
+
+const knot_dname_t *knot_rrset_rdata_soa_primary_ns(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+ knot_dname_t *dname;
+ memcpy(&dname, rrset->rdata, sizeof(knot_dname_t *));
+ return dname;
+}
+
+const knot_dname_t *knot_rrset_rdata_soa_mailbox(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+ knot_dname_t *dname;
+ memcpy(&dname, rrset->rdata + sizeof(knot_dname_t *),
+ sizeof(knot_dname_t *));
+ return dname;
+}
+
+const knot_dname_t *knot_rrset_rdata_rp_first_dname(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return NULL;
+ }
+
+ knot_dname_t *dname;
+ memcpy(&dname, knot_rrset_get_rdata(rrset, pos), sizeof(knot_dname_t *));
+ return dname;
+}
+
+const knot_dname_t *knot_rrset_rdata_rp_second_dname(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return NULL;
+ }
+
+ knot_dname_t *dname;
+ memcpy(&dname, knot_rrset_get_rdata(rrset, pos) + sizeof(knot_dname_t *),
+ sizeof(knot_dname_t *));
+ return dname;
+}
+
+const knot_dname_t *knot_rrset_rdata_minfo_first_dname(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ return knot_rrset_rdata_rp_first_dname(rrset, pos);
+}
+
+const knot_dname_t *knot_rrset_rdata_minfo_second_dname(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ return knot_rrset_rdata_rp_second_dname(rrset, pos);
+}
+
+uint32_t knot_rrset_rdata_soa_serial(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(rrset->rdata + sizeof(knot_dname_t *) * 2);
+}
+
+/*---------------------------------------------------------------------------*/
+
+void knot_rrset_rdata_soa_serial_set(knot_rrset_t *rrset, uint32_t serial)
+{
+ if (rrset == NULL) {
+ return;
+ }
+
+ // the number is in network byte order, transform it
+ knot_wire_write_u32(rrset->rdata + sizeof(knot_dname_t *) * 2,
+ serial);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint32_t knot_rrset_rdata_soa_refresh(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(rrset->rdata +
+ sizeof(knot_dname_t *) * 2 + 4);
+}
+
+/*---------------------------------------------------------------------------*/
+
+
+uint32_t knot_rrset_rdata_soa_retry(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(rrset->rdata +
+ sizeof(knot_dname_t *) * 2 + 8);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint32_t knot_rrset_rdata_soa_expire(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(rrset->rdata +
+ sizeof(knot_dname_t *) * 2 + 12);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint32_t knot_rrset_rdata_soa_minimum(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(rrset->rdata +
+ sizeof(knot_dname_t *) * 2 + 16);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint16_t knot_rrset_rdata_rrsig_type_covered(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return knot_wire_read_u16(rrset->rdata);
+}
+
+uint8_t knot_rrset_rdata_rrsig_algorithm(const knot_rrset_t *rrset,
+ size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return *(knot_rrset_get_rdata(rrset, rr_pos) + 2);
+}
+
+uint8_t knot_rrset_rdata_rrsig_labels(const knot_rrset_t *rrset,
+ size_t rr_pos)
+
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return *(knot_rrset_get_rdata(rrset, rr_pos) + 3);
+}
+
+uint32_t knot_rrset_rdata_rrsig_original_ttl(const knot_rrset_t *rrset,
+ size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(knot_rrset_get_rdata(rrset, rr_pos) + 4);
+}
+
+uint32_t knot_rrset_rdata_rrsig_sig_expiration(const knot_rrset_t *rrset,
+ size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(knot_rrset_get_rdata(rrset, rr_pos) + 8);
+}
+
+uint32_t knot_rrset_rdata_rrsig_sig_inception(const knot_rrset_t *rrset,
+ size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return knot_wire_read_u32(knot_rrset_get_rdata(rrset, rr_pos) + 12);
+}
+
+uint16_t knot_rrset_rdata_rrsig_key_tag(const knot_rrset_t *rrset,
+ size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return knot_wire_read_u16(knot_rrset_get_rdata(rrset, rr_pos) + 16);
+}
+
+const knot_dname_t *knot_rrset_rdata_rrsig_signer_name(const knot_rrset_t *rrset,
+ size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return NULL;
+ }
+
+ const knot_dname_t *dname = NULL;
+ memcpy(&dname, knot_rrset_get_rdata(rrset, rr_pos) + 18,
+ sizeof(knot_dname_t *));
+
+ return dname;
+}
+
+uint16_t knot_rrset_rdata_dnskey_flags(const knot_rrset_t *rrset, size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return knot_wire_read_u16(knot_rrset_get_rdata(rrset, rr_pos));
+}
+
+uint8_t knot_rrset_rdata_dnskey_proto(const knot_rrset_t *rrset, size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return *(knot_rrset_get_rdata(rrset, rr_pos) + 2);
+}
+
+uint8_t knot_rrset_rdata_dnskey_alg(const knot_rrset_t *rrset, size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return *(knot_rrset_get_rdata(rrset, rr_pos) + 3);
+}
+
+void knot_rrset_rdata_dnskey_key(const knot_rrset_t *rrset, size_t rr_pos,
+ uint8_t **key, uint16_t *key_size)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return;
+ }
+
+ *key = knot_rrset_get_rdata(rrset, rr_pos) + 4;
+ *key_size = rrset_rdata_item_size(rrset, rr_pos) - 4;
+}
+
+const knot_dname_t *knot_rrset_rdata_nsec_next(const knot_rrset_t *rrset,
+ size_t rr_pos)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ const knot_dname_t *dname;
+ memcpy(&dname, rrset_rdata_pointer(rrset, rr_pos),
+ sizeof(knot_dname_t *));
+ return dname;
+}
+
+void knot_rrset_rdata_nsec_bitmap(const knot_rrset_t *rrset, size_t rr_pos,
+ uint8_t **bitmap, uint16_t *size)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return;
+ }
+
+ *bitmap = knot_rrset_get_rdata(rrset, rr_pos) + sizeof(knot_dname_t *);
+ *size = rrset_rdata_item_size(rrset, rr_pos) - sizeof(knot_dname_t *);
+}
+
+void knot_rrset_rdata_nsec3_bitmap(const knot_rrset_t *rrset, size_t rr_pos,
+ uint8_t **bitmap, uint16_t *size)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return;
+ }
+
+ /* Bitmap is last, skip all the items. */
+ size_t offset = 1; //hash alg.
+ offset += 1; //flags
+ offset += 2; //iterations
+ offset += 1; //salt lenght
+ offset += knot_rrset_rdata_nsec3_salt_length(rrset, rr_pos); //sal
+ uint8_t *next_hashed = NULL;
+ uint8_t next_hashed_size = 0;
+ knot_rrset_rdata_nsec3_next_hashed(rrset, rr_pos, &next_hashed,
+ &next_hashed_size);
+ offset += 1; //hash length
+ offset += next_hashed_size; //hash
+ *bitmap = knot_rrset_get_rdata(rrset, rr_pos) + offset;
+ *size = rrset_rdata_item_size(rrset, rr_pos) - offset;
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint8_t knot_rrset_rdata_nsec3_algorithm(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return *(rrset_rdata_pointer(rrset, pos));
+}
+
+uint8_t knot_rrset_rdata_nsec3_flags(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return *(rrset_rdata_pointer(rrset, pos) + 1);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint16_t knot_rrset_rdata_nsec3_iterations(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return knot_wire_read_u16(rrset_rdata_pointer(rrset, pos) + 2);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint8_t knot_rrset_rdata_nsec3param_flags(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return *(rrset_rdata_pointer(rrset, 0) + 1);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint8_t knot_rrset_rdata_nsec3param_algorithm(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return *(rrset_rdata_pointer(rrset, 0));
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint16_t knot_rrset_rdata_nsec3param_iterations(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return knot_wire_read_u16(rrset_rdata_pointer(rrset, 0) + 2);
+}
+
+/*---------------------------------------------------------------------------*/
+
+uint8_t knot_rrset_rdata_nsec3param_salt_length(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return 0;
+ }
+
+ return *(rrset_rdata_pointer(rrset, 0) + 4);
+}
+
+/*---------------------------------------------------------------------------*/
+
+const uint8_t *knot_rrset_rdata_nsec3param_salt(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ return rrset_rdata_pointer(rrset, 0) + 5;
+}
+
+/*---------------------------------------------------------------------------*/
+
+
+uint8_t knot_rrset_rdata_nsec3_salt_length(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return 0;
+ }
+
+ return *(rrset_rdata_pointer(rrset, pos) + 4);
+}
+
+void knot_rrset_rdata_nsec3_next_hashed(const knot_rrset_t *rrset, size_t pos,
+ uint8_t **name, uint8_t *name_size)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return;
+ }
+
+ uint8_t salt_size = knot_rrset_rdata_nsec3_salt_length(rrset, pos);
+ *name_size = *(knot_rrset_get_rdata(rrset, pos) + 4 + salt_size + 1);
+ *name = knot_rrset_get_rdata(rrset, pos) + 4 + salt_size + 2;
+}
+
+/*---------------------------------------------------------------------------*/
+
+const uint8_t *knot_rrset_rdata_nsec3_salt(const knot_rrset_t *rrset,
+ size_t pos)
+{
+ if (rrset == NULL || pos >= rrset->rdata_count) {
+ return NULL;
+ }
+
+ return rrset_rdata_pointer(rrset, pos) + 5;
+}
+
+knot_dname_t **knot_rrset_get_next_rr_dname(const knot_rrset_t *rrset,
+ knot_dname_t **prev_dname,
+ size_t rr_pos)
+{
+ if (rrset == NULL || rr_pos >= rrset->rdata_count) {
+ return NULL;
+ }
+
+ uint8_t *rdata = rrset_rdata_pointer(rrset, rr_pos);
+ if (rrset_type_multiple_dnames(rrset)) {
+ if (prev_dname == NULL) {
+ /* The very first DNAME. */
+ /* [code-review] How do you know the dname is the first
+ * item in the RDATA?
*/
- walk2 = knot_rrset_rdata_get_next(rrset2, walk2);
- /* Insert this item at the end of first list. */
- tmp->next = insert_after->next;
- insert_after->next = tmp;
- insert_after = tmp;
- /*!< \todo This message has to be removed after bugfix. */
- dbg_rrset_detail("rrset: merge_no_dupl: Insert after=%p"
- ", tmp=%p, tmp->next=%p, "
- " rrset1->rdata=%p"
- "\n",
- insert_after, tmp, tmp->next,
- rrset1->rdata);
- assert(tmp->next == rrset1->rdata);
+ return (knot_dname_t **)rdata;
+ }
+ assert((size_t)prev_dname >= (size_t)rdata);
+ if ((size_t)prev_dname - (size_t)rdata == sizeof(knot_dname_t *)) {
+ /* No DNAMEs left to return. */
+ return NULL;
} else {
- dbg_rrset_detail("rrset: merge_dupl: Skipping and "
- "freeing duplicated item "
- "of type: %s (%p).\n",
- knot_rrtype_to_string(rrset1->type),
- walk2);
- /*
- * Not freeing this item will result in a leak.
- * Since this operation destroys the second
- * list, we have to free the item here.
- */
- knot_rdata_t *tmp = walk2;
- dbg_rrset_detail("rrset: merge_dupl: freeing: %p.\n",
- tmp);
- walk2 = knot_rrset_rdata_get_next(rrset2, walk2);
- knot_rdata_deep_free(&tmp, rrset1->type, 1);
- assert(tmp == NULL);
- /* Maybe caller should be warned about this. */
- ++deleted;
- }
- }
-
- assert(walk2 == NULL);
+ /* Return second DNAME from RR. */
+ assert((size_t)prev_dname == (size_t)rdata);
+ return (knot_dname_t **)(rdata + sizeof(knot_dname_t *));
+ }
+ } else {
+ /*
+ * Return DNAME from normal RR, if any.
+ * Find DNAME in blocks. No need to check remainder.
+ */
+ if (prev_dname) {
+ /* Nothing left to return. */
+ return NULL;
+ }
+ size_t offset = 0;
+ const rdata_descriptor_t *desc =
+ get_rdata_descriptor(rrset->type);
+ for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; ++i) {
+ if (descriptor_item_is_dname(desc->block_types[i])) {
+ return (knot_dname_t **)(rdata + offset);
+ } else if (descriptor_item_is_fixed(desc->block_types[i])) {
+ offset += desc->block_types[i];
+ } else if (!descriptor_item_is_remainder(desc->block_types[i])) {
+ assert(rrset->type == KNOT_RRTYPE_NAPTR);
+ offset +=
+ rrset_rdata_naptr_bin_chunk_size(rrset,
+ rr_pos);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+knot_dname_t **knot_rrset_get_next_dname(const knot_rrset_t *rrset,
+ knot_dname_t **prev_dname)
+{
+ if (rrset == NULL || rrset->rdata_count == 0) {
+ return NULL;
+ }
+
+ /* 1) Find in which RR is the given dname. */
+ size_t pos = 0;
+ int ret = rrset_find_rr_pos_for_pointer(rrset, prev_dname, &pos);
+ if (ret != KNOT_EOK) {
+ return NULL;
+ }
+
+ /* 2) Try to get next dname from the RR. */
+ knot_dname_t **next =
+ knot_rrset_get_next_rr_dname(rrset, prev_dname, pos);
+
+ /* 3) If not found and there is a next RR to search in, try it. */
+ if (next == NULL && pos < rrset->rdata_count - 1) {
+ // prev_dname = NULL because in this RR we haven't searched yet
+ next = knot_rrset_get_next_rr_dname(rrset, NULL, pos + 1);
+ }
+
+ return next;
+}
+
+void knot_rrset_dump(const knot_rrset_t *rrset)
+{
dbg_rrset_exec_detail(
- dbg_rrset_detail("rrset: merge_dupl: RDATA after merge:\n ");
- knot_rdata_t *walk1 = rrset1->rdata;
- while (walk1 != NULL) {
- dbg_rrset_detail("%p ->\n", walk1);
- walk1 = knot_rrset_rdata_get_next(rrset1, walk1);
- }
- dbg_rrset_detail("rrset: merge_dupl: RDATA after merge: r1:%p r2: %p\n",
- rrset1->rdata, rrset2->rdata);
+ if (rrset == NULL) {
+ return;
+ }
+
+ dbg_rrset_detail(" ------- RRSET -------\n");
+
+ char *name = knot_dname_to_str(rrset->owner);
+ dbg_rrset_detail(" owner: %s\n", name);
+ free(name);
+ dbg_rrset_detail(" type: %u\n", rrset->type);
+ dbg_rrset_detail(" class: %d\n", rrset->rclass);
+ dbg_rrset_detail(" ttl: %d\n", rrset->ttl);
+ dbg_rrset_detail(" RDATA count: %d\n", rrset->rdata_count);
+
+ dbg_rrset_detail(" RRSIGs:\n");
+ if (rrset->rrsigs != NULL) {
+ knot_rrset_dump(rrset->rrsigs);
+ } else {
+ dbg_rrset_detail(" none\n");
+ }
+
+ dbg_rrset_detail("RDATA indices (total=%d):\n",
+ rrset_rdata_size_total(rrset));
+
+ for (uint16_t i = 0; i < rrset->rdata_count; i++) {
+ dbg_rrset_detail("%d=%d ", i, rrset_rdata_offset(rrset, i));
+ }
+ dbg_rrset_detail("\n");
+
+ if (knot_rrset_rdata_rr_count(rrset) == 0) {
+ dbg_rrset_detail("NO RDATA\n");
+ }
+
+ for (uint16_t i = 0; i < knot_rrset_rdata_rr_count(rrset); i++) {
+ knot_rrset_rdata_dump(rrset, i);
+ }
);
+}
+
+uint64_t rrset_binary_size(const knot_rrset_t *rrset)
+{
+ if (rrset == NULL || rrset->rdata_count == 0) {
+ return 0;
+ }
+ uint64_t size = sizeof(uint64_t) + // size at the beginning
+ 1 + // owner size
+ knot_dname_size(knot_rrset_owner(rrset)) + // owner data
+ sizeof(uint16_t) + // type
+ sizeof(uint16_t) + // class
+ sizeof(uint32_t) + // ttl
+ sizeof(uint16_t) + //RR count
+ sizeof(uint32_t) * rrset->rdata_count; //RR indices
+ for (uint16_t i = 0; i < rrset->rdata_count; i++) {
+ /* Space to store length of one RR. */
+ size += sizeof(uint32_t);
+ /* Actual data. */
+ size += rrset_binary_size_one(rrset, i);
+ }
+
+ return size;
+}
+
+int rrset_serialize(const knot_rrset_t *rrset, uint8_t *stream, size_t *size)
+{
+ if (rrset == NULL || rrset->rdata_count == 0) {
+ return KNOT_EINVAL;
+ }
+
+ uint64_t rrset_length = rrset_binary_size(rrset);
+ dbg_rrset_detail("rr: serialize: Binary size=%"PRIu64"\n", rrset_length);
+ memcpy(stream, &rrset_length, sizeof(uint64_t));
+
+ size_t offset = sizeof(uint64_t);
+ /* Save RR indices. Size first. */
+ memcpy(stream + offset, &rrset->rdata_count, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ memcpy(stream + offset, rrset->rdata_indices,
+ rrset->rdata_count * sizeof(uint32_t));
+ offset += sizeof(uint32_t) * rrset->rdata_count;
+ /* Save owner. Size first. */
+ memcpy(stream + offset, &rrset->owner->size, 1);
+ ++offset;
+ memcpy(stream + offset, knot_dname_name(rrset->owner),
+ knot_dname_size(rrset->owner));
+ offset += knot_dname_size(rrset->owner);
+
+ /* Save static data. */
+ memcpy(stream + offset, &rrset->type, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ memcpy(stream + offset, &rrset->rclass, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ memcpy(stream + offset, &rrset->ttl, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+
+ /* Copy RDATA. */
+ for (uint16_t i = 0; i < rrset->rdata_count; i++) {
+ size_t size_one = 0;
+ /* This cannot fail, if it does, RDATA are malformed. TODO */
+ /* TODO this can be written later. */
+ uint32_t rr_size = rrset_binary_size_one(rrset, i);
+ dbg_rrset_detail("rr: serialize: RR index=%d size=%d\n",
+ i, rr_size);
+ memcpy(stream + offset, &rr_size, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+ rrset_serialize_rr(rrset, i, stream + offset, &size_one);
+ assert(size_one == rr_size);
+ offset += size_one;
+ }
+
+ *size = offset;
+ assert(*size == rrset_length);
+ dbg_rrset_detail("rr: serialize: RRSet serialized, size=%zu\n", *size);
+ return KNOT_EOK;
+}
+
+int rrset_serialize_alloc(const knot_rrset_t *rrset, uint8_t **stream,
+ size_t *size)
+{
+ /* Get the binary size. */
+ *size = rrset_binary_size(rrset);
+ if (*size == 0) {
+ /* Nothing to serialize. */
+ dbg_rrset("rrset: serialize alloc: No data to serialize.\n");
+ return KNOT_EINVAL;
+ }
+
+ /* Prepare memory. */
+ *stream = malloc(*size);
+ if (*stream == NULL) {
+ return KNOT_ENOMEM;
+ }
+
+ return rrset_serialize(rrset, *stream, size);
+}
+
+int rrset_deserialize(uint8_t *stream, size_t *stream_size,
+ knot_rrset_t **rrset)
+{
+ if (sizeof(uint64_t) > *stream_size) {
+ dbg_rrset("rr: deserialize: No space for length.\n");
+ return KNOT_ESPACE;
+ }
+ uint64_t rrset_length = 0;
+ memcpy(&rrset_length, stream, sizeof(uint64_t));
+ if (rrset_length > *stream_size) {
+ dbg_rrset("rr: deserialize: No space for whole RRSet. "
+ "(given=%zu needed=%"PRIu64")\n", *stream_size,
+ rrset_length);
+ return KNOT_ESPACE;
+ }
+
+ size_t offset = sizeof(uint64_t);
+ uint16_t rdata_count = 0;
+ memcpy(&rdata_count, stream + offset, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ uint32_t *rdata_indices = xmalloc(rdata_count * sizeof(uint32_t));
+ memcpy(rdata_indices, stream + offset,
+ rdata_count * sizeof(uint32_t));
+ offset += rdata_count * sizeof(uint32_t);
+ /* Read owner from the stream. */
+ uint8_t owner_size = *(stream + offset);
+ offset += 1;
+ knot_dname_t *owner = knot_dname_new_from_wire(stream + offset,
+ owner_size, NULL);
+ assert(owner);
+ offset += owner_size;
+ /* Read type. */
+ uint16_t type = 0;
+ memcpy(&type, stream + offset, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ /* Read class. */
+ uint16_t rclass = 0;
+ memcpy(&rclass, stream + offset, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ /* Read TTL. */
+ uint32_t ttl = 0;
+ memcpy(&ttl, stream + offset, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+
+ /* Create new RRSet. */
+ *rrset = knot_rrset_new(owner, type, rclass, ttl);
+ if (*rrset == NULL) {
+ return KNOT_ENOMEM;
+ }
+ knot_dname_release(owner);
+
+ (*rrset)->rdata_indices = rdata_indices;
+ (*rrset)->rdata_count = rdata_count;
+
+ (*rrset)->rdata = xmalloc(rdata_indices[rdata_count - 1]);
+ memset((*rrset)->rdata, 0, rdata_indices[rdata_count - 1]);
+ /* Read RRs. */
+ for (uint16_t i = 0; i < (*rrset)->rdata_count; i++) {
+ /*
+ * There's always size of rdata in the beginning.
+ * Needed because of remainders.
+ */
+ uint32_t rdata_size = 0;
+ memcpy(&rdata_size, stream + offset, sizeof(uint32_t));
+ offset += sizeof(uint32_t);
+ size_t read = 0;
+ int ret = rrset_deserialize_rr((*rrset), i, stream + offset,
+ rdata_size, &read);
+ if (ret != KNOT_EOK) {
+ free((*rrset)->rdata);
+ free(rdata_indices);
+ knot_dname_release(owner);
+ return ret;
+ }
+ /* TODO handle malformations. */
+ dbg_rrset_detail("rr: deserialaze: RR read size=%zu,"
+ "actual=%"PRIu32"\n", read, rdata_size);
+ assert(read == rdata_size);
+ offset += read;
+ }
+
+dbg_rrset_exec_detail(
+ dbg_rrset_detail("RRSet deserialized:\n");
+ knot_rrset_dump(*rrset);
+);
+ *stream_size = *stream_size - offset;
+
+ return KNOT_EOK;
+}
+
+const knot_dname_t *knot_rrset_rdata_ns_name(const knot_rrset_t *rrset,
+ size_t rdata_pos)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ const knot_dname_t *dname;
+ memcpy(&dname, rrset_rdata_pointer(rrset, rdata_pos),
+ sizeof(knot_dname_t *));
+ return dname;
+}
+
+const knot_dname_t *knot_rrset_rdata_mx_name(const knot_rrset_t *rrset,
+ size_t rdata_pos)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ knot_dname_t *dname;
+ memcpy(&dname, rrset_rdata_pointer(rrset, rdata_pos) + 2,
+ sizeof(knot_dname_t *));
+ return dname;
+}
+
+const knot_dname_t *knot_rrset_rdata_srv_name(const knot_rrset_t *rrset,
+ size_t rdata_pos)
+{
+ if (rrset == NULL) {
+ return NULL;
+ }
+
+ knot_dname_t *dname;
+ memcpy(&dname, rrset_rdata_pointer(rrset, rdata_pos) + 6,
+ sizeof(knot_dname_t *));
+ return dname;
+}
+
+const knot_dname_t *knot_rrset_rdata_name(const knot_rrset_t *rrset,
+ size_t rdata_pos)
+{
+ if (rrset == NULL || rrset->rdata_count <= rdata_pos) {
+ return NULL;
+ }
+
+ switch (rrset->type) {
+ case KNOT_RRTYPE_NS:
+ return knot_rrset_rdata_ns_name(rrset, rdata_pos);
+ case KNOT_RRTYPE_MX:
+ return knot_rrset_rdata_mx_name(rrset, rdata_pos);
+ case KNOT_RRTYPE_SRV:
+ return knot_rrset_rdata_srv_name(rrset, rdata_pos);
+ case KNOT_RRTYPE_CNAME:
+ return knot_rrset_rdata_cname_name(rrset);
+ }
+
+ return NULL;
+}
+
+int knot_rrset_find_rr_pos(const knot_rrset_t *rr_search_in,
+ const knot_rrset_t *rr_reference, size_t pos,
+ size_t *pos_out)
+{
+ int found = 0;
+ for (uint16_t i = 0; i < rr_search_in->rdata_count && !found; ++i) {
+ if (rrset_rdata_compare_one(rr_search_in,
+ rr_reference, i, pos) == 0) {
+ *pos_out = i;
+ found = 1;
+ }
+ }
+
+ return found ? KNOT_EOK : KNOT_ENOENT;
+}
+
+int knot_rrset_remove_rr(knot_rrset_t *rrset,
+ const knot_rrset_t *rr_from, size_t rdata_pos)
+{
+ /* [code-review] Missing parameter checks. */
/*
- * Since there is a possibility of corrupted list for second RRSet, it
- * is safer to set its list to NULL, so that it cannot be used.
+ * Position in first and second rrset can differ, we have
+ * to search for position first.
*/
- rrset2->rdata = NULL;
+ size_t pos_to_remove = 0;
+ int ret = knot_rrset_find_rr_pos(rrset, rr_from, rdata_pos,
+ &pos_to_remove);
+ if (ret == KNOT_EOK) {
+ /* Position found, can be removed. */
+ dbg_rrset_detail("rr: remove_rr: Counter position found=%zu\n",
+ pos_to_remove);
+ assert(pos_to_remove < rrset->rdata_count);
+ ret = knot_rrset_remove_rdata_pos(rrset, pos_to_remove);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("Cannot remove RDATA from RRSet (%s).\n",
+ knot_strerror(ret));
+ return ret;
+ }
+ } else {
+ dbg_rrset_verb("rr: remove_rr: RDATA not found (%s).\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+int knot_rrset_rdata_reset(knot_rrset_t *rrset)
+{
+ if (rrset == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ rrset->rdata = NULL;
+ rrset->rdata_indices = NULL;
+ rrset->rdata_count = 0;
+
+ return KNOT_EOK;
+}
+
+int rrset_rr_dnames_apply(knot_rrset_t *rrset, size_t rdata_pos,
+ int (*func)(knot_dname_t **, void *), void *data)
+{
+ if (rrset == NULL || rdata_pos >= rrset->rdata_count || func == NULL) {
+ return KNOT_EINVAL;
+ }
+
+
+ knot_dname_t **dname = NULL;
+ while ((dname = knot_rrset_get_next_rr_dname(rrset, dname,
+ rdata_pos))) {
+ assert(dname && *dname);
+ int ret = func(dname, data);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rr: rr_dnames_apply: Function could not be"
+ "applied (%s).\n", knot_strerror(ret));
+ return ret;
+ }
+ }
- return deleted;
+ return KNOT_EOK;
+}
+
+int rrset_dnames_apply(knot_rrset_t *rrset, int (*func)(knot_dname_t **, void *),
+ void *data)
+{
+ if (rrset == NULL || rrset->rdata_count == 0 || func == NULL) {
+ return KNOT_EINVAL;
+ }
+
+ for (uint16_t i = 0; i < rrset->rdata_count; ++i) {
+ int ret = rrset_rr_dnames_apply(rrset, i, func, data);
+ if (ret != KNOT_EOK) {
+ return ret;
+ }
+ }
+
+ return KNOT_EOK;
+}
+
+int knot_rrset_add_rr_from_rrset(knot_rrset_t *dest, const knot_rrset_t *source,
+ size_t rdata_pos)
+{
+ if (dest == NULL || source == NULL ||
+ rdata_pos >= source->rdata_count) {
+ return KNOT_EINVAL;
+ }
+
+ /* Get size of RDATA to be copied. */
+ uint16_t item_size = rrset_rdata_item_size(source, rdata_pos);
+ /* Reserve space in dest RRSet. */
+ uint8_t *rdata = knot_rrset_create_rdata(dest, item_size);
+ if (rdata == NULL) {
+ dbg_rrset("rr: add_rr_from_rrset: Could not create RDATA.\n");
+ return KNOT_ERROR;
+ }
+
+ /* Copy actual data. */
+ memcpy(rdata, rrset_rdata_pointer(source, rdata_pos), item_size);
+
+ /* Retain DNAMEs inside RDATA. */
+ int ret = rrset_rr_dnames_apply((knot_rrset_t *)source, rdata_pos,
+ rrset_retain_dnames_in_rr, NULL);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("rr: add_rr_from_rrset: Could not retain DNAMEs"
+ " in RR (%s).\n", knot_strerror(ret));
+ return ret;
+ }
+
+ return KNOT_EOK;
+}
+
+int knot_rrset_remove_rr_using_rrset(knot_rrset_t *from,
+ const knot_rrset_t *what,
+ knot_rrset_t **rr_deleted, int ddns_check)
+{
+ /* [code-review] Missing parameter checks. */
+
+ knot_rrset_t *return_rr = NULL;
+ int ret = knot_rrset_shallow_copy(what, &return_rr);
+ if (ret != KNOT_EOK) {
+ dbg_rrset("remove_rr_using_rrset: Could not copy RRSet (%s).\n",
+ knot_strerror(ret));
+ return ret;
+ }
+ /* Reset RDATA of returned RRSet. */
+ knot_rrset_rdata_reset(return_rr);
+ return_rr->rrsigs = NULL;
+
+ for (uint16_t i = 0; i < what->rdata_count; ++i) {
+ /*
+ * DDNS special handling - last apex NS should remain in the
+ * zone.
+ *
+ * TODO: this is not correct, the last NS from the 'what' RRSet
+ * may not even be in the zone.
+ */
+ //TODO REVIEW LS : relevant?
+ /* [code-review] Hm, it seems OK, but the variable should be
+ * documented, maybe even named differently.
+ * Setting it to 1 means: 'leave the last RR in
+ * the RRSet'. Deciding whether to leave the last
+ * there is on the caller. Thus the assert() is
+ * wrong (it MAY be used in other cases).
+ * Also there can be just break; instead of the
+ * parameter setting and return.
+ */
+ if (ddns_check && i == what->rdata_count - 1) {
+ assert(knot_rrset_type(from) == KNOT_RRTYPE_NS);
+ *rr_deleted = return_rr;
+ return KNOT_EOK;
+ }
+
+ ret = knot_rrset_remove_rr(from, what, i);
+ if (ret == KNOT_EOK) {
+ /* RR was removed, can be added to 'return' RRSet. */
+ ret = knot_rrset_add_rr_from_rrset(return_rr, what, i);
+ if (ret != KNOT_EOK) {
+ knot_rrset_deep_free(&return_rr, 0, 0);
+ dbg_xfrin("xfr: Could not add RR (%s).\n",
+ knot_strerror(ret));
+ return ret;
+ }
+ dbg_rrset_detail("rrset: remove_rr_using_rrset: "
+ "Successfuly removed and returned this RR:\n");
+ knot_rrset_rdata_dump(return_rr, return_rr->rdata_count - 1);
+ } else if (ret != KNOT_ENOENT) {
+ /* NOENT is OK, but other errors are not. */
+ dbg_rrset("rrset: remove_using_rrset: "
+ "RRSet removal failed (%s).\n",
+ knot_strerror(ret));
+ knot_rrset_deep_free(&return_rr, 0, 0);
+ return ret;
+ }
+ }
+
+ *rr_deleted = return_rr;
+ return KNOT_EOK;
+}
+
+int knot_rrset_remove_rr_using_rrset_del(knot_rrset_t *from,
+ const knot_rrset_t *what)
+{
+ knot_rrset_t *rr_removed = NULL;
+ int ret = knot_rrset_remove_rr_using_rrset(from, what, &rr_removed, 0);
+ knot_rrset_deep_free(&rr_removed, 1, 1);
+ return ret;
+// for (uint16_t i = 0; i < what->rdata_count; ++i) {
+// int ret = knot_rrset_remove_rr(from, what, i);
+// if (ret != KNOT_ENOENT || ret != KNOT_EOK) {
+// /* NOENT is OK, but other errors are not. */
+// dbg_rrset("rrset: remove_rr_using_rrset: "
+// "RRSet removal failed (%s).\n",
+// knot_strerror(ret));
+// return ret;
+// }
+// }
+
+// return KNOT_EOK;
+}
+
+void knot_rrset_set_class(knot_rrset_t *rrset, uint16_t rclass)
+{
+ if (!rrset) {
+ return;
+ }
+
+ rrset->rclass = rclass;
+}
+
+int knot_rrset_ds_check(const knot_rrset_t *rrset)
+{
+ // Check if the legth of the digest corresponds to the proper size of
+ // the digest according to the given algorithm
+ for (uint16_t i = 0; i < rrset->rdata_count; ++i) {
+ /* 4 bytes before actual digest. */
+ if (rrset_rdata_item_size(rrset, i) < 4) {
+ /* Not even keytag, alg and alg type. */
+ return KNOT_EMALF;
+ }
+ uint16_t len = rrset_rdata_item_size(rrset, i) - 4;
+ uint8_t type = *(rrset_rdata_pointer(rrset, i) + 3);
+ if (type == 0 || len == 0) {
+ return KNOT_EINVAL;
+ } else if (len != knot_ds_digest_length(type)) {
+ return KNOT_EDSDIGESTLEN;
+ }
+ }
+ return KNOT_EOK;
}