summaryrefslogtreecommitdiff
path: root/src/libknot/packet
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2013-06-28 12:59:40 +0200
committerOndřej Surý <ondrej@sury.org>2013-06-28 12:59:40 +0200
commit124965832295a277b9ca6ae9fac4f45a74a36b2a (patch)
treef299e2335863f74e0be0707f84b85211baaf2d03 /src/libknot/packet
parent3d2d198c71a6b844b60fa9ef68801b66bba93361 (diff)
downloadknot-upstream/1.3.0_rc3.tar.gz
New upstream version 1.3.0~rc3upstream/1.3.0_rc3
Diffstat (limited to 'src/libknot/packet')
-rw-r--r--src/libknot/packet/packet.c316
-rw-r--r--src/libknot/packet/packet.h96
-rw-r--r--src/libknot/packet/query.c89
-rw-r--r--src/libknot/packet/query.h3
-rw-r--r--src/libknot/packet/response.c849
-rw-r--r--src/libknot/packet/response.h76
6 files changed, 443 insertions, 986 deletions
diff --git a/src/libknot/packet/packet.c b/src/libknot/packet/packet.c
index 2e6e922..52ed72b 100644
--- a/src/libknot/packet/packet.c
+++ b/src/libknot/packet/packet.c
@@ -14,12 +14,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <config.h>
#include <assert.h>
+#include <stdlib.h>
#include "packet/packet.h"
#include "util/debug.h"
#include "common.h"
-#include "util/descriptor.h"
+#include "common/descriptor.h"
#include "util/wire.h"
#include "tsig.h"
@@ -35,13 +37,6 @@
? DEFAULT_##type##_QUERY \
: DEFAULT_##type)
-
-
-typedef enum {
- KNOT_PACKET_DUPL_IGNORE,
- KNOT_PACKET_DUPL_SKIP,
- KNOT_PACKET_DUPL_MERGE
-} knot_packet_duplicate_handling_t;
/*----------------------------------------------------------------------------*/
/* Non-API functions */
/*----------------------------------------------------------------------------*/
@@ -52,7 +47,7 @@ typedef enum {
static void knot_packet_init_pointers_response(knot_packet_t *pkt)
{
dbg_packet_detail("Packet pointer: %p\n", pkt);
-
+
char *pos = (char *)pkt + PREALLOC_PACKET;
// put QNAME directly after the structure
@@ -66,10 +61,6 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt)
pkt->question.qname->labels = (uint8_t *)pos;
pos += PREALLOC_QNAME_LABELS;
- pkt->owner_tmp = (uint8_t *)pos;
- dbg_packet_detail("Tmp owner: %p\n", pkt->owner_tmp);
- pos += PREALLOC_RR_OWNER;
-
// then answer, authority and additional sections
if (DEFAULT_ANCOUNT == 0) {
pkt->answer = NULL;
@@ -77,14 +68,14 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt)
pkt->answer = (const knot_rrset_t **)pos;
pos += DEFAULT_ANCOUNT * sizeof(const knot_rrset_t *);
}
-
+
if (DEFAULT_NSCOUNT == 0) {
pkt->authority = NULL;
} else {
pkt->authority = (const knot_rrset_t **)pos;
pos += DEFAULT_NSCOUNT * sizeof(const knot_rrset_t *);
}
-
+
if (DEFAULT_ARCOUNT == 0) {
pkt->additional = NULL;
} else {
@@ -100,21 +91,6 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt)
pkt->max_ns_rrsets = DEFAULT_NSCOUNT;
pkt->max_ar_rrsets = DEFAULT_ARCOUNT;
- // then domain names for compression and offsets
- pkt->compression.dnames = (const knot_dname_t **)pos;
- pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(const knot_dname_t *);
- pkt->compression.offsets = (size_t *)pos;
- pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t);
- pkt->compression.to_free = (int *)pos;
- pos += DEFAULT_DOMAINS_IN_RESPONSE * sizeof(int);
-
- dbg_packet_detail("Compression dnames: %p\n", pkt->compression.dnames);
- dbg_packet_detail("Compression offsets: %p\n", pkt->compression.offsets);
- dbg_packet_detail("Compression to_free: %p\n", pkt->compression.to_free);
-
- pkt->compression.max = DEFAULT_DOMAINS_IN_RESPONSE;
- pkt->compression.default_count = DEFAULT_DOMAINS_IN_RESPONSE;
-
// wildcard nodes and SNAMEs associated with them
pkt->wildcard_nodes.nodes = (const knot_node_t **)pos;
pos += DEFAULT_WILDCARD_NODES * sizeof(const knot_node_t *);
@@ -145,7 +121,7 @@ static void knot_packet_init_pointers_response(knot_packet_t *pkt)
static void knot_packet_init_pointers_query(knot_packet_t *pkt)
{
dbg_packet_detail("Packet pointer: %p\n", pkt);
-
+
char *pos = (char *)pkt + PREALLOC_PACKET;
// put QNAME directly after the structure
@@ -169,14 +145,14 @@ static void knot_packet_init_pointers_query(knot_packet_t *pkt)
pkt->answer = (const knot_rrset_t **)pos;
pos += DEFAULT_ANCOUNT_QUERY * sizeof(const knot_rrset_t *);
}
-
+
if (DEFAULT_NSCOUNT_QUERY == 0) {
pkt->authority = NULL;
} else {
pkt->authority = (const knot_rrset_t **)pos;
pos += DEFAULT_NSCOUNT_QUERY * sizeof(const knot_rrset_t *);
}
-
+
if (DEFAULT_ARCOUNT_QUERY == 0) {
pkt->additional = NULL;
} else {
@@ -232,10 +208,8 @@ static int knot_packet_parse_header(const uint8_t *wire, size_t *pos,
}
header->id = knot_wire_get_id(wire);
- // copy some of the flags: OPCODE and RD
- // do this by copying flags1 and setting QR to 1, AA to 0 and TC to 0
header->flags1 = knot_wire_get_flags1(wire);
- // do not copy flags2 (all set by server)
+ header->flags2 = knot_wire_get_flags2(wire);
header->qdcount = knot_wire_get_qdcount(wire);
header->ancount = knot_wire_get_ancount(wire);
@@ -298,6 +272,7 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos,
if (question->qname == NULL) {
return KNOT_ENOMEM;
}
+ knot_dname_to_lower(question->qname);
} else {
assert(question->qname != NULL); /* When alloc=0, must be set. */
void *parsed = knot_dname_parse_from_wire(wire, pos,
@@ -306,6 +281,7 @@ static int knot_packet_parse_question(const uint8_t *wire, size_t *pos,
if (!parsed) {
return KNOT_EMALF;
}
+ knot_dname_to_lower(question->qname);
}
question->qtype = knot_wire_read_u16(wire + i + 1);
question->qclass = knot_wire_read_u16(wire + i + 3);
@@ -356,26 +332,74 @@ static int knot_packet_realloc_rrsets(const knot_rrset_t ***rrsets,
/*----------------------------------------------------------------------------*/
-static knot_rdata_t *knot_packet_parse_rdata(const uint8_t *wire,
- size_t *pos, size_t total_size, size_t rdlength,
- const knot_rrtype_descriptor_t *desc)
+static int knot_packet_parse_rdata(knot_rrset_t *rr, const uint8_t *wire,
+ size_t *pos, size_t total_size,
+ size_t rdlength)
{
- knot_rdata_t *rdata = knot_rdata_new();
- if (rdata == NULL) {
- return NULL;
+ if (!rr || !wire || !pos || rdlength == 0) {
+ return KNOT_EINVAL;
}
- int rc = knot_rdata_from_wire(rdata, wire, pos, total_size, rdlength,
- desc);
- if (rc != KNOT_EOK) {
- dbg_packet("rdata_from_wire() returned: %s\n",
- knot_strerror(rc));
- knot_rdata_free(&rdata);
- return NULL;
- }
- return rdata;
+ /*! \todo As I'm revising it, seems highly inefficient to me.
+ * We just need to skim through the packet,
+ * check if it is in valid format and store pointers to various
+ * parts in rdata instead of copying memory blocks and
+ * parsing domain names (with additional allocation) and then
+ * use use the wireformat for lookup again. Compression could
+ * be handled in-situ without additional memory allocs...
+ */
+
+ int ret = knot_rrset_rdata_from_wire_one(rr, wire, pos, total_size,
+ rdlength);
+ if (ret != KNOT_EOK) {
+ dbg_packet("packet: parse_rdata: Failed to parse RDATA (%s).\n",
+ knot_strerror(ret));
+ return ret;
+ }
+
+// uint8_t* rd = knot_rrset_create_rdata(rr, rdlength);
+// if (!rd) {
+// return KNOT_ERROR;
+// }
+// uint8_t* np = rd + rdlength;
+
+// const rdata_descriptor_t *desc = get_rdata_descriptor(knot_rrset_type(rr));
+// if (!desc) {
+// /*! \todo Free rdata mem ? Not essential, but nice. */
+// return KNOT_EINVAL;
+// }
+
+// for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; i++) {
+// const int id = desc->block_types[i];
+// if (descriptor_item_is_dname(id)) {
+// knot_dname_t *dn = NULL;
+// dn = knot_dname_parse_from_wire(wire, pos, total_size, NULL, NULL);
+// if (dn == NULL) {
+// return KNOT_EMALF;
+// }
+// /* Store ptr in rdata. */
+// *((knot_dname_t**)rd) = dn;
+// rd += sizeof(knot_dname_t*);
+// } else if (descriptor_item_is_fixed(id)) {
+// memcpy(rd, wire + *pos, id);
+// rd += id; /* Item represents fixed len here */
+// *pos += id;
+// } else if (descriptor_item_is_remainder(id)) {
+// size_t rchunk = np - rd;
+// memcpy(rd, wire + *pos, rchunk);
+// rd += rchunk;
+// *pos += rchunk;
+// } else {
+// //NAPTR
+// assert(knot_rrset_type(rr) == KNOT_RRTYPE_NAPTR);
+// assert(0);
+// }
+
+// }
+
+ return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
@@ -393,6 +417,7 @@ static knot_rrset_t *knot_packet_parse_rr(const uint8_t *wire, size_t *pos,
if (owner == NULL) {
return NULL;
}
+ knot_dname_to_lower(owner);
dbg_packet_exec_verb(
char *name = knot_dname_to_str(owner);
@@ -435,7 +460,7 @@ dbg_packet_exec_verb(
if (size - *pos < rdlength) {
dbg_packet("Malformed RR: Not enough data to parse RR"
" RDATA (size: %zu, position: %zu).\n", size, *pos);
- knot_rrset_deep_free(&rrset, 1, 1, 0);
+ knot_rrset_deep_free(&rrset, 1, 1);
return NULL;
}
@@ -445,20 +470,14 @@ dbg_packet_exec_verb(
return rrset;
}
+
// parse RDATA
- knot_rdata_t *rdata = knot_packet_parse_rdata(wire, pos, size,
- rdlength,
- knot_rrtype_descriptor_by_type(rrset->type));
- if (rdata == NULL) {
+ /*! \todo Merge with add_rdata_to_rr in zcompile, should be a rrset func
+ * probably. */
+ int ret = knot_packet_parse_rdata(rrset, wire, pos, size, rdlength);
+ if (ret != KNOT_EOK) {
dbg_packet("Malformed RR: Could not parse RDATA.\n");
- knot_rrset_deep_free(&rrset, 1, 1, 0);
- return NULL;
- }
-
- if (knot_rrset_add_rdata(rrset, rdata) != KNOT_EOK) {
- dbg_packet("Malformed RR: Could not add RDATA to RRSet.\n");
- knot_rdata_free(&rdata);
- knot_rrset_deep_free(&rrset, 1, 1, 0);
+ knot_rrset_deep_free(&rrset, 1, 1);
return NULL;
}
@@ -473,7 +492,7 @@ static int knot_packet_add_rrset(knot_rrset_t *rrset,
short *max_rrsets,
short default_rrsets,
const knot_packet_t *packet,
- knot_packet_duplicate_handling_t dupl)
+ knot_packet_flag_t flags)
{
assert(rrset != NULL);
assert(rrsets != NULL);
@@ -482,8 +501,8 @@ static int knot_packet_add_rrset(knot_rrset_t *rrset,
dbg_packet_exec_verb(
char *name = knot_dname_to_str(rrset->owner);
- dbg_packet_verb("packet_add_rrset(), owner: %s, type: %s\n",
- name, knot_rrtype_to_string(rrset->type));
+ dbg_packet_verb("packet_add_rrset(), owner: %s, type: %u\n",
+ name, rrset->type);
free(name);
);
@@ -493,33 +512,30 @@ dbg_packet_exec_verb(
return KNOT_ENOMEM;
}
- if (dupl == KNOT_PACKET_DUPL_SKIP &&
+ if ((flags & KNOT_PACKET_DUPL_SKIP) &&
knot_packet_contains(packet, rrset, KNOT_RRSET_COMPARE_PTR)) {
- /*! \todo This should also return > 0, as it means that the
- RRSet was not used actually. */
- return KNOT_EOK;
+ return 2;
}
- if (dupl == KNOT_PACKET_DUPL_MERGE) {
+ // Try to merge rdata to rrset if flag NO_MERGE isn't set.
+ if ((flags & KNOT_PACKET_DUPL_NO_MERGE) == 0) {
// try to find the RRSet in this array of RRSets
for (int i = 0; i < *rrset_count; ++i) {
-
dbg_packet_exec_detail(
char *name = knot_dname_to_str((*rrsets)[i]->owner);
dbg_packet_detail("Comparing to RRSet: owner: %s, "
- "type: %s\n", name,
- knot_rrtype_to_string(
- (*rrsets)[i]->type));
+ "type: %u\n", name,
+ (*rrsets)[i]->type);
free(name);
);
- if (knot_rrset_match((*rrsets)[i], rrset,
+ if (knot_rrset_equal((*rrsets)[i], rrset,
KNOT_RRSET_COMPARE_HEADER)) {
/*! \todo Test this!!! */
// no duplicate checking here, the packet should
// look exactly as it came from wire
int rc = knot_rrset_merge(
- (void **)((*rrsets) + i), (void **)&rrset);
+ ((knot_rrset_t *)(*rrsets)[i]), rrset);
if (rc != KNOT_EOK) {
return rc;
}
@@ -542,7 +558,8 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos,
const knot_rrset_t ***rrsets,
short *rrset_count, short *max_rrsets,
short default_rrsets,
- knot_packet_t *packet)
+ knot_packet_t *packet,
+ knot_packet_flag_t flags)
{
assert(pos != NULL);
assert(wire != NULL);
@@ -573,13 +590,15 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos,
++(*parsed_rrs);
err = knot_packet_add_rrset(rrset, rrsets, rrset_count,
- max_rrsets, default_rrsets, packet,
- KNOT_PACKET_DUPL_MERGE);
+ max_rrsets, default_rrsets, packet, flags);
if (err < 0) {
break;
- } else if (err > 0) { // merged
+ } else if (err == 1) { // merged, shallow data copy
dbg_packet_detail("RRSet merged, freeing.\n");
- knot_rrset_deep_free(&rrset, 1, 0, 0); // TODO: ok??
+ knot_rrset_deep_free(&rrset, 1, 0);
+ continue;
+ } else if (err == 2) { // skipped
+ knot_rrset_deep_free(&rrset, 1, 1);
continue;
}
@@ -588,7 +607,7 @@ static int knot_packet_parse_rrs(const uint8_t *wire, size_t *pos,
// remove the last RRSet from the list of RRSets
// - just decrement the count
--(*rrset_count);
- knot_rrset_deep_free(&rrset, 1, 1, 1);
+ knot_rrset_deep_free(&rrset, 1, 1);
break;
}
@@ -638,12 +657,6 @@ static void knot_packet_free_allocated_space(knot_packet_t *pkt)
free(pkt->additional);
}
- if (pkt->compression.max > pkt->compression.default_count) {
- free(pkt->compression.dnames);
- free(pkt->compression.offsets);
- free(pkt->compression.to_free);
- }
-
if (pkt->wildcard_nodes.max > pkt->wildcard_nodes.default_count) {
free(pkt->wildcard_nodes.nodes);
free(pkt->wildcard_nodes.snames);
@@ -656,8 +669,8 @@ static void knot_packet_free_allocated_space(knot_packet_t *pkt)
/*----------------------------------------------------------------------------*/
-static int knot_packet_parse_rr_sections(knot_packet_t *packet,
- size_t *pos)
+static int knot_packet_parse_rr_sections(knot_packet_t *packet, size_t *pos,
+ knot_packet_flag_t flags)
{
assert(packet != NULL);
assert(packet->wireformat != NULL);
@@ -673,7 +686,7 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet,
if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
packet->size, packet->header.ancount, &packet->parsed_an,
&packet->answer, &packet->an_rrsets, &packet->max_an_rrsets,
- DEFAULT_RRSET_COUNT(ANCOUNT, packet), packet)) != KNOT_EOK) {
+ DEFAULT_RRSET_COUNT(ANCOUNT, packet), packet, flags)) != KNOT_EOK) {
return err;
}
@@ -686,7 +699,7 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet,
if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
packet->size, packet->header.nscount, &packet->parsed_ns,
&packet->authority, &packet->ns_rrsets, &packet->max_ns_rrsets,
- DEFAULT_RRSET_COUNT(NSCOUNT, packet), packet)) != KNOT_EOK) {
+ DEFAULT_RRSET_COUNT(NSCOUNT, packet), packet, flags)) != KNOT_EOK) {
return err;
}
@@ -699,7 +712,7 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet,
if ((err = knot_packet_parse_rrs(packet->wireformat, pos,
packet->size, packet->header.arcount, &packet->parsed_ar,
&packet->additional, &packet->ar_rrsets, &packet->max_ar_rrsets,
- DEFAULT_RRSET_COUNT(ARCOUNT, packet), packet)) != KNOT_EOK) {
+ DEFAULT_RRSET_COUNT(ARCOUNT, packet), packet, flags)) != KNOT_EOK) {
return err;
}
@@ -744,7 +757,14 @@ static int knot_packet_parse_rr_sections(knot_packet_t *packet,
knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc)
{
- knot_packet_t *pkt;
+ mm_ctx_t mm;
+ mm_ctx_init(&mm);
+ return knot_packet_new_mm(prealloc, &mm);
+}
+
+knot_packet_t *knot_packet_new_mm(knot_packet_prealloc_type_t prealloc, mm_ctx_t *mm)
+{
+ knot_packet_t *pkt = NULL;
void (*init_pointers)(knot_packet_t *pkt) = NULL;
size_t size = 0;
@@ -762,9 +782,10 @@ knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc)
break;
}
- pkt = (knot_packet_t *)malloc(size);
+ pkt = (knot_packet_t *)mm->alloc(mm->ctx, size);
CHECK_ALLOC_LOG(pkt, NULL);
memset(pkt, 0, size);
+ memcpy(&pkt->mm, mm, sizeof(mm_ctx_t));
if (init_pointers != NULL) {
init_pointers(pkt);
}
@@ -781,7 +802,7 @@ knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc)
int knot_packet_parse_from_wire(knot_packet_t *packet,
const uint8_t *wireformat, size_t size,
- int question_only)
+ int question_only, knot_packet_flag_t flags)
{
if (packet == NULL || wireformat == NULL) {
return KNOT_EINVAL;
@@ -821,7 +842,7 @@ int knot_packet_parse_from_wire(knot_packet_t *packet,
if (packet->header.qdcount == 1) {
if ((err = knot_packet_parse_question(wireformat, &pos, size,
- &packet->question, packet->prealloc_type
+ &packet->question, packet->prealloc_type
== KNOT_PACKET_PREALLOC_NONE)
) != KNOT_EOK) {
return err;
@@ -838,7 +859,7 @@ dbg_packet_exec_detail(
}
/*! \todo Replace by call to parse_rest()? */
- err = knot_packet_parse_rest(packet);
+ err = knot_packet_parse_rest(packet, flags);
dbg_packet_exec_detail(
knot_packet_dump(packet);
@@ -849,7 +870,7 @@ dbg_packet_exec_detail(
/*----------------------------------------------------------------------------*/
-int knot_packet_parse_rest(knot_packet_t *packet)
+int knot_packet_parse_rest(knot_packet_t *packet, knot_packet_flag_t flags)
{
if (packet == NULL) {
return KNOT_EINVAL;
@@ -864,13 +885,13 @@ int knot_packet_parse_rest(knot_packet_t *packet)
// If there is less data then required, the next function will find out.
// If there is more data than required, it also returns EMALF.
-
+
size_t pos = packet->parsed;
/*! \todo If we already parsed some part of the packet, it is not ok
* to begin parsing from the Answer section.
*/
- return knot_packet_parse_rr_sections(packet, &pos);
+ return knot_packet_parse_rr_sections(packet, &pos, flags);
}
/*----------------------------------------------------------------------------*/
@@ -898,7 +919,7 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
if (packet->parsed_an == packet->header.ancount) {
assert(packet->parsed < packet->size);
//dbg_packet("Trailing garbage, ignoring...\n");
- // there may be other data in the packet
+ // there may be other data in the packet
// (authority or additional).
return KNOT_EOK;
}
@@ -911,7 +932,7 @@ int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
dbg_packet_verb("Failed to parse RR!\n");
return KNOT_EMALF;
}
-
+
dbg_packet_detail("Parsed. Pos: %zu.\n", pos);
packet->parsed = pos;
@@ -960,7 +981,7 @@ int knot_packet_parse_next_rr_additional(knot_packet_t *packet,
dbg_packet_verb("Failed to parse RR!\n");
return KNOT_EMALF;
}
-
+
dbg_packet_detail("Parsed. Pos: %zu.\n", pos);
packet->parsed = pos;
@@ -981,6 +1002,13 @@ size_t knot_packet_size(const knot_packet_t *packet)
/*----------------------------------------------------------------------------*/
+size_t knot_packet_max_size(const knot_packet_t *packet)
+{
+ return packet->max_size;
+}
+
+/*----------------------------------------------------------------------------*/
+
size_t knot_packet_question_size(const knot_packet_t *packet)
{
return (KNOT_WIRE_HEADER_SIZE + 4
@@ -1005,7 +1033,7 @@ int knot_packet_set_max_size(knot_packet_t *packet, int max_size)
if (packet->max_size < max_size) {
// reallocate space for the wire format (and copy anything
// that might have been there before
- uint8_t *wire_new = (uint8_t *)malloc(max_size);
+ uint8_t *wire_new = packet->mm.alloc(packet->mm.ctx, max_size);
if (wire_new == NULL) {
return KNOT_ENOMEM;
}
@@ -1016,7 +1044,8 @@ int knot_packet_set_max_size(knot_packet_t *packet, int max_size)
packet->wireformat = wire_new;
if (packet->max_size > 0 && packet->free_wireformat) {
- free(wire_old);
+ if (packet->mm.free)
+ packet->mm.free(wire_old);
}
packet->free_wireformat = 1;
@@ -1068,6 +1097,14 @@ uint8_t knot_packet_opcode(const knot_packet_t *packet)
/*----------------------------------------------------------------------------*/
+knot_question_t *knot_packet_question(knot_packet_t *packet)
+{
+ if (packet == NULL) return NULL;
+ return &packet->question;
+}
+
+/*----------------------------------------------------------------------------*/
+
const knot_dname_t *knot_packet_qname(const knot_packet_t *packet)
{
if (packet == NULL) {
@@ -1087,7 +1124,7 @@ uint16_t knot_packet_qtype(const knot_packet_t *packet)
/*----------------------------------------------------------------------------*/
-void knot_packet_set_qtype(knot_packet_t *packet, knot_rr_type_t qtype)
+void knot_packet_set_qtype(knot_packet_t *packet, uint16_t qtype)
{
assert(packet != NULL);
packet->question.qtype = qtype;
@@ -1130,7 +1167,7 @@ int knot_packet_rcode(const knot_packet_t *packet)
if (packet == NULL) {
return KNOT_EINVAL;
}
-
+
return knot_wire_flags_get_rcode(packet->header.flags2);
}
@@ -1141,7 +1178,7 @@ int knot_packet_tc(const knot_packet_t *packet)
if (packet == NULL) {
return KNOT_EINVAL;
}
-
+
return knot_wire_flags_get_tc(packet->header.flags1);
}
@@ -1290,19 +1327,19 @@ int knot_packet_contains(const knot_packet_t *packet,
}
for (int i = 0; i < packet->an_rrsets; ++i) {
- if (knot_rrset_match(packet->answer[i], rrset, cmp)) {
+ if (knot_rrset_equal(packet->answer[i], rrset, cmp)) {
return 1;
}
}
for (int i = 0; i < packet->ns_rrsets; ++i) {
- if (knot_rrset_match(packet->authority[i], rrset, cmp)) {
+ if (knot_rrset_equal(packet->authority[i], rrset, cmp)) {
return 1;
}
}
for (int i = 0; i < packet->ar_rrsets; ++i) {
- if (knot_rrset_match(packet->additional[i], rrset, cmp)) {
+ if (knot_rrset_equal(packet->additional[i], rrset, cmp)) {
return 1;
}
}
@@ -1351,18 +1388,18 @@ dbg_packet_exec(
char *name = knot_dname_to_str(
(((knot_rrset_t **)(pkt->tmp_rrsets))[i])->owner);
dbg_packet_verb("Freeing tmp RRSet on ptr: %p (ptr to ptr:"
- " %p, type: %s, owner: %s)\n",
+ " %p, type: %u, owner: %s)\n",
(((knot_rrset_t **)(pkt->tmp_rrsets))[i]),
&(((knot_rrset_t **)(pkt->tmp_rrsets))[i]),
- knot_rrtype_to_string(
- (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->type),
+ (((knot_rrset_t **)(pkt->tmp_rrsets))[i])->type,
name);
free(name);
);
// TODO: this is quite ugly, but better than copying whole
// function (for reallocating rrset array)
+ // TODO sort out freeing, this WILL leak.
knot_rrset_deep_free(
- &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]), 1, 1, 1);
+ &(((knot_rrset_t **)(pkt->tmp_rrsets))[i]), 1, 1);
}
}
@@ -1490,32 +1527,22 @@ void knot_packet_free(knot_packet_t **packet)
dbg_packet("Freeing tmp RRSets...\n");
knot_packet_free_tmp_rrsets(*packet);
- dbg_packet("Freeing copied dnames for compression...\n");
- for (int i = 0; i < (*packet)->compression.count; ++i) {
- if ((*packet)->compression.to_free[i]) {
- knot_dname_release(
- (knot_dname_t *)(*packet)->compression.dnames[i]);
- }
- }
-
- /*! \note The above code will free the domain names pointed to by
- * the list of wildcard nodes. It should not matter, however.
- */
-
// check if some additional space was allocated for the packet
dbg_packet("Freeing additional allocated space...\n");
knot_packet_free_allocated_space(*packet);
// free the space for wireformat
if ((*packet)->wireformat != NULL && (*packet)->free_wireformat) {
- free((*packet)->wireformat);
+ if ((*packet)->mm.free)
+ (*packet)->mm.free((*packet)->wireformat);
}
// free EDNS options
knot_edns_free_options(&(*packet)->opt_rr);
dbg_packet("Freeing packet structure\n");
- free(*packet);
+ if ((*packet)->mm.free)
+ (*packet)->mm.free(*packet);
*packet = NULL;
}
@@ -1527,7 +1554,7 @@ static void knot_packet_dump_rrsets(const knot_rrset_t **rrsets,
assert((rrsets != NULL && *rrsets != NULL) || count < 1);
for (int i = 0; i < count; ++i) {
- knot_rrset_dump(rrsets[i], 0);
+ knot_rrset_dump(rrsets[i]);
}
}
#endif
@@ -1566,10 +1593,10 @@ void knot_packet_dump(const knot_packet_t *packet)
char *qname = knot_dname_to_str(packet->question.qname);
dbg_packet(" QNAME: %s\n", qname);
free(qname);
- dbg_packet(" QTYPE: %u (%s)\n", packet->question.qtype,
- knot_rrtype_to_string(packet->question.qtype));
- dbg_packet(" QCLASS: %u (%s)\n", packet->question.qclass,
- knot_rrclass_to_string(packet->question.qclass));
+ dbg_packet(" QTYPE: %u (%u)\n", packet->question.qtype,
+ packet->question.qtype);
+ dbg_packet(" QCLASS: %u (%u)\n", packet->question.qclass,
+ packet->question.qclass);
}
dbg_packet("\nAnswer RRSets:\n");
@@ -1592,3 +1619,18 @@ void knot_packet_dump(const knot_packet_t *packet)
#endif
}
+static int knot_packet_free_section(const knot_rrset_t **s, short count) {
+ /*! \todo The API is really incompatible here. */
+ for (short i = 0; i < count; ++i)
+ knot_rrset_deep_free((knot_rrset_t **)s + i, 1, 1);
+ return count;
+}
+
+int knot_packet_free_rrsets(knot_packet_t *packet)
+{
+ int ret = 0;
+ ret += knot_packet_free_section(packet->answer, packet->an_rrsets);
+ ret += knot_packet_free_section(packet->authority, packet->ns_rrsets);
+ ret += knot_packet_free_section(packet->additional, packet->ar_rrsets);
+ return ret;
+}
diff --git a/src/libknot/packet/packet.h b/src/libknot/packet/packet.h
index ba85aed..0921fba 100644
--- a/src/libknot/packet/packet.h
+++ b/src/libknot/packet/packet.h
@@ -37,24 +37,6 @@
#include "zone/zone.h"
/*----------------------------------------------------------------------------*/
-/*!
- * \brief Structure for holding information needed for compressing domain names.
- *
- * It's a simple table of domain names and their offsets in wire format of the
- * packet.
- *
- * \todo Consider using some better lookup structure, such as skip-list.
- */
-struct knot_compressed_dnames {
- const knot_dname_t **dnames; /*!< Domain names present in packet. */
- size_t *offsets; /*!< Offsets of domain names in the packet. */
- int *to_free; /*< Indices of dnames to free. */
- short count; /*!< Count of items in the previous arrays. */
- short max; /*!< Capacity of the structure (allocated). */
- short default_count;
-};
-
-typedef struct knot_compressed_dnames knot_compressed_dnames_t;
struct knot_wildcard_nodes {
const knot_node_t **nodes; /*!< Wildcard nodes from CNAME processing. */
@@ -101,6 +83,18 @@ enum knot_packet_prealloc_type {
typedef enum knot_packet_prealloc_type knot_packet_prealloc_type_t;
+/* Maximum number of compressed names. */
+#define COMPR_MAXLEN 64
+/* Volatile portion of the compression table. */
+#define COMPR_VOLATILE (COMPR_MAXLEN / 4)
+#define COMPR_FIXEDLEN (COMPR_MAXLEN - COMPR_VOLATILE)
+
+/* Compression table pointer. */
+typedef struct {
+ uint16_t off; /*!< Packet data offset. */
+ uint8_t lbcount; /*!< Dname label count. */
+} knot_compr_ptr_t;
+
/*----------------------------------------------------------------------------*/
/*!
* \brief Structure representing a DNS packet.
@@ -120,8 +114,6 @@ struct knot_packet {
*/
knot_question_t question;
- uint8_t *owner_tmp; /*!< Allocated space for RRSet owner wire format.*/
-
const knot_rrset_t **answer; /*!< Answer RRSets. */
const knot_rrset_t **authority; /*!< Authority RRSets. */
const knot_rrset_t **additional; /*!< Additional RRSets. */
@@ -148,7 +140,7 @@ struct knot_packet {
size_t max_size; /*!< Maximum allowed size of the packet. */
/*! \brief Information needed for compressing domain names in packet. */
- knot_compressed_dnames_t compression;
+ knot_compr_ptr_t compression[COMPR_MAXLEN];
/*! \brief Wildcard nodes to be processed for NSEC/NSEC3. */
knot_wildcard_nodes_t wildcard_nodes;
@@ -161,11 +153,12 @@ struct knot_packet {
struct knot_packet *query; /*!< Associated query. */
knot_packet_prealloc_type_t prealloc_type;
-
+
size_t tsig_size; /*!< Space to reserve for the TSIG RR. */
knot_rrset_t *tsig_rr; /*!< TSIG RR stored in the packet. */
uint16_t flags; /*!< Packet flags. */
const knot_zone_t *zone; /*!< Associated zone. */
+ mm_ctx_t mm; /*!< Memory allocation context. */
};
typedef struct knot_packet knot_packet_t;
@@ -235,25 +228,6 @@ enum {
PREALLOC_QNAME = PREALLOC_QNAME_DNAME
+ PREALLOC_QNAME_NAME
+ PREALLOC_QNAME_LABELS,
- /*!
- * \brief Space for RR owner wire format.
- *
- * Temporary buffer, used when putting RRSets to the response.
- */
- PREALLOC_RR_OWNER = 256,
-
- /*! \brief Space for one part of the compression table (domain names).*/
- PREALLOC_DOMAINS =
- DEFAULT_DOMAINS_IN_RESPONSE * sizeof(knot_dname_t *),
- /*! \brief Space for other part of the compression table (offsets). */
- PREALLOC_OFFSETS =
- DEFAULT_DOMAINS_IN_RESPONSE * sizeof(size_t),
-
- PREALLOC_TO_FREE =
- DEFAULT_DOMAINS_IN_RESPONSE * sizeof(int),
-
- PREALLOC_COMPRESSION = PREALLOC_DOMAINS + PREALLOC_OFFSETS
- + PREALLOC_TO_FREE,
PREALLOC_WC_NODES =
DEFAULT_WILDCARD_NODES * sizeof(knot_node_t *),
@@ -271,15 +245,21 @@ enum {
/*! \brief Total preallocated size for the response. */
PREALLOC_RESPONSE = PREALLOC_PACKET
+ PREALLOC_QNAME
- + PREALLOC_RR_OWNER
+ PREALLOC_RRSETS(DEFAULT_ANCOUNT)
+ PREALLOC_RRSETS(DEFAULT_NSCOUNT)
+ PREALLOC_RRSETS(DEFAULT_ARCOUNT)
- + PREALLOC_COMPRESSION
+ PREALLOC_WC
+ PREALLOC_RRSETS(DEFAULT_TMP_RRSETS)
};
+/*! \brief Flags which control packet parsing. */
+typedef enum {
+ // Don't add duplicate rdata to rrset.
+ KNOT_PACKET_DUPL_NO_MERGE = 1,
+ // Skip RR if RRSet is not empty
+ KNOT_PACKET_DUPL_SKIP = 2
+} knot_packet_flag_t;
+
/*----------------------------------------------------------------------------*/
/*!
* \brief Creates new empty packet structure.
@@ -291,6 +271,13 @@ enum {
knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc);
/*!
+ * \brief Memory managed version of new packet create.
+ *
+ * See knot_packet_new() for info about parameters and output.
+ */
+knot_packet_t *knot_packet_new_mm(knot_packet_prealloc_type_t prealloc, mm_ctx_t *mm);
+
+/*!
* \brief Parses the DNS packet from wire format.
*
* \param packet Packet structure to parse into.
@@ -299,14 +286,15 @@ knot_packet_t *knot_packet_new(knot_packet_prealloc_type_t prealloc);
* \param question_only Set to <> 0 if you do not want to parse the whole
* packet. In such case the parsing will end after the
* Question section. Set to 0 to parse the whole packet.
+ * \param flags Can control packet processing.
*
* \retval KNOT_EOK
*/
int knot_packet_parse_from_wire(knot_packet_t *packet,
const uint8_t *wireformat, size_t size,
- int question_only);
+ int question_only, knot_packet_flag_t flags);
-int knot_packet_parse_rest(knot_packet_t *packet);
+int knot_packet_parse_rest(knot_packet_t *packet, knot_packet_flag_t flags);
int knot_packet_parse_next_rr_answer(knot_packet_t *packet,
knot_rrset_t **rr);
@@ -316,6 +304,8 @@ int knot_packet_parse_next_rr_additional(knot_packet_t *packet,
size_t knot_packet_size(const knot_packet_t *packet);
+size_t knot_packet_max_size(const knot_packet_t *packet);
+
/*! \brief Returns size of the wireformat of Header and Question sections. */
size_t knot_packet_question_size(const knot_packet_t *packet);
@@ -361,6 +351,15 @@ void knot_packet_set_random_id(knot_packet_t *packet);
uint8_t knot_packet_opcode(const knot_packet_t *packet);
/*!
+ * \brief Return question section from the packet.
+ *
+ * \param packet Packet instance.
+ *
+ * \return pointer to question section.
+ */
+knot_question_t *knot_packet_question(knot_packet_t *packet);
+
+/*!
* \brief Returns the QNAME from the packet.
*
* \param packet Packet (with parsed query) to get the QNAME from.
@@ -384,7 +383,7 @@ uint16_t knot_packet_qtype(const knot_packet_t *packet);
* \param packet Packet containing question.
* \param qtype New QTYPE for question.
*/
-void knot_packet_set_qtype(knot_packet_t *packet, knot_rr_type_t qtype);
+void knot_packet_set_qtype(knot_packet_t *packet, uint16_t qtype);
/*!
@@ -573,6 +572,11 @@ void knot_packet_free(knot_packet_t **packet);
*/
void knot_packet_dump(const knot_packet_t *packet);
+/*!
+ * \brief Free all rrsets associated with packet.
+ */
+int knot_packet_free_rrsets(knot_packet_t *packet);
+
#endif /* _KNOT_PACKET_H_ */
/*! @} */
diff --git a/src/libknot/packet/query.c b/src/libknot/packet/query.c
index 8f4cf18..4bededc 100644
--- a/src/libknot/packet/query.c
+++ b/src/libknot/packet/query.c
@@ -14,6 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <config.h>
#include <stdlib.h>
#include "packet/query.h"
#include "util/wire.h"
@@ -21,74 +22,6 @@
/*----------------------------------------------------------------------------*/
-int knot_query_rr_to_wire(const knot_rrset_t *rrset, const knot_rdata_t *rdata,
- uint8_t **wire, uint8_t *endp)
-{
- /* Store owner. */
- knot_dname_t *owner = rrset->owner;
- if (*wire + owner->size > endp) {
- return KNOT_ENOMEM;
- }
- memcpy(*wire, owner->name, owner->size);
- *wire += owner->size;
-
- if (*wire + 10 > endp) {
- return KNOT_ENOMEM;
- }
-
- /* Write RR header. */
- knot_wire_write_u16(*wire, rrset->type); *wire += 2;
- knot_wire_write_u16(*wire, rrset->rclass); *wire += 2;
- knot_wire_write_u32(*wire, rrset->ttl); *wire += 4;
- knot_wire_write_u16(*wire, 0); *wire += 2; /* RDLENGTH reserve. */
- uint8_t *rdlength_p = *wire - 2;
- uint16_t rdlength = 0;
-
- /* Write data. */
- knot_dname_t *dname = 0;
- uint16_t *raw_data = 0;
- knot_rrtype_descriptor_t *desc =
- knot_rrtype_descriptor_by_type(rrset->type);
-
- for (int i = 0; i < rdata->count; ++i) {
- switch (desc->wireformat[i]) {
- case KNOT_RDATA_WF_COMPRESSED_DNAME:
- case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
- case KNOT_RDATA_WF_LITERAL_DNAME:
-
- /* Check space for dname. */
- dname = knot_rdata_item(rdata, i)->dname;
- if (*wire + dname->size > endp) {
- return KNOT_ESPACE;
- }
-
- /* Save domain name. */
- memcpy(*wire, dname->name, dname->size);
- *wire += dname->size;
- rdlength += dname->size;
- break;
- default:
- raw_data = knot_rdata_item(rdata, i)->raw_data;
- if (*wire + raw_data[0] > endp) {
- return KNOT_ESPACE;
- }
-
- /* Copy data. */
- memcpy(*wire, raw_data + 1, raw_data[0]);
- *wire += raw_data[0];
- rdlength += raw_data[0];
- break;
-
- }
- }
-
- /* Store rdlength. */
- knot_wire_write_u16(rdlength_p, rdlength);
-
- return KNOT_EOK;
-}
-/*----------------------------------------------------------------------------*/
-
int knot_query_dnssec_requested(const knot_packet_t *query)
{
if (query == NULL) {
@@ -153,9 +86,7 @@ int knot_query_set_question(knot_packet_t *query,
query->header.qdcount = 1;
// convert the Question to wire format right away
- knot_packet_question_to_wire(query);
-
- return KNOT_EOK;
+ return knot_packet_question_to_wire(query);
}
/*----------------------------------------------------------------------------*/
@@ -203,26 +134,24 @@ int knot_query_add_rrset_authority(knot_packet_t *query,
/* Write to wire. */
uint8_t *startp = query->wireformat + query->size;
uint8_t *endp = query->wireformat + query->max_size;
-
+
assert(endp - startp > query->opt_rr.size + query->tsig_size);
// reserve space for OPT RR
/*! \todo Why here??? */
endp -= query->opt_rr.size;
/* Reserve space for TSIG RR */
endp -= query->tsig_size;
-
- uint8_t *pos = startp;
- const knot_rdata_t *rdata = 0;
- while ((rdata = knot_rrset_rdata_next(rrset, rdata))) {
- knot_query_rr_to_wire(rrset, rdata, &pos, endp);
+ size_t written = 0;
+ uint16_t rr_count = 0;
+ int ret = knot_rrset_to_wire(rrset, startp, &written, query->max_size,
+ &rr_count, NULL);
+ if (ret != KNOT_EOK) {
+ return ret;
}
-
- size_t written = (pos - startp);
query->size += written;
++query->ns_rrsets;
++query->header.nscount;
return KNOT_EOK;
}
-
diff --git a/src/libknot/packet/query.h b/src/libknot/packet/query.h
index 3ca4fd3..ee5418a 100644
--- a/src/libknot/packet/query.h
+++ b/src/libknot/packet/query.h
@@ -81,9 +81,6 @@ int knot_query_set_opcode(knot_packet_t *query, uint8_t opcode);
int knot_query_add_rrset_authority(knot_packet_t *query,
const knot_rrset_t *rrset);
-int knot_query_rr_to_wire(const knot_rrset_t *rrset, const knot_rdata_t *rdata,
- uint8_t **wire, uint8_t *endp);
-
#endif /* _KNOT_QUERY_H_ */
/*! @} */
diff --git a/src/libknot/packet/response.c b/src/libknot/packet/response.c
index 69678c7..015cdb1 100644
--- a/src/libknot/packet/response.c
+++ b/src/libknot/packet/response.c
@@ -14,725 +14,159 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <config.h>
#include <stdlib.h>
+#include <stdint.h>
#include "packet/response.h"
#include "util/wire.h"
-#include "util/descriptor.h"
#include "common.h"
#include "util/debug.h"
+#include "rrset.h"
#include "packet/packet.h"
#include "edns.h"
-#define COMPRESSION_PEDANTIC
-
/*----------------------------------------------------------------------------*/
-/*!
- * \brief Holds information about compressed domain name.
- *
- * Used only to pass information between functions.
- *
- * \todo This description should be revised and clarified.
- */
-struct knot_compr_owner {
- /*!
- * \brief Place where the name is stored in the wire format of the
- * packet.
- */
- uint8_t *wire;
- short size; /*!< Size of the domain name in bytes. */
- /*! \brief Position of the name relative to the start of the packet. */
- size_t pos;
-};
-
-typedef struct knot_compr_owner knot_compr_owner_t;
/*!
- * \brief Holds information about compressed domain names in packet.
- *
- * Used only to pass information between functions.
+ * \brief Compare suffixes and calculate score (number of matching labels).
*
- * \todo This description should be revised and clarified.
+ * Update current best score.
*/
-struct knot_compr {
- knot_compressed_dnames_t *table; /*!< Compression table. */
- size_t wire_pos; /*!< Current position in the wire format. */
- knot_compr_owner_t owner; /*!< Information about the current name. */
-};
-
-typedef struct knot_compr knot_compr_t;
-
-static const size_t KNOT_RESPONSE_MAX_PTR = 16383;
-
-/*----------------------------------------------------------------------------*/
-/* Non-API functions */
-/*----------------------------------------------------------------------------*/
-/*!
- * \brief Reallocates space for compression table.
- *
- * \param table Compression table to reallocate space for.
- *
- * \retval KNOT_EOK
- * \retval KNOT_ENOMEM
- */
-static int knot_response_realloc_compr(knot_compressed_dnames_t *table)
+static bool knot_response_compr_score(uint8_t *n, uint8_t *p, uint8_t labels,
+ uint8_t *wire, knot_compr_ptr_t *match)
{
- int free_old = table->max != table->default_count;
- size_t *old_offsets = table->offsets;
- int *old_to_free = table->to_free;
- const knot_dname_t **old_dnames = table->dnames;
-
- short new_max_count = table->max + STEP_DOMAINS;
-
- size_t *new_offsets = (size_t *)malloc(new_max_count * sizeof(size_t));
- CHECK_ALLOC_LOG(new_offsets, -1);
-
- int *new_to_free = (int *)malloc(new_max_count * sizeof(int));
- if (new_to_free == NULL) {
- ERR_ALLOC_FAILED;
- free(new_offsets);
- return KNOT_ENOMEM;
- }
-
- const knot_dname_t **new_dnames = (const knot_dname_t **)malloc(
- new_max_count * sizeof(knot_dname_t *));
- if (new_dnames == NULL) {
- ERR_ALLOC_FAILED;
- free(new_offsets);
- free(new_to_free);
- return KNOT_ENOMEM;
- }
-
- memcpy(new_offsets, table->offsets, table->max * sizeof(size_t));
- memcpy(new_to_free, table->to_free, table->max * sizeof(int));
- memcpy(new_dnames, table->dnames,
- table->max * sizeof(knot_dname_t *));
-
- table->offsets = new_offsets;
- table->to_free = new_to_free;
- table->dnames = new_dnames;
- table->max = new_max_count;
-
- if (free_old) {
- free(old_offsets);
- free(old_to_free);
- free(old_dnames);
- }
-
- return KNOT_EOK;
-}
-
-/*----------------------------------------------------------------------------*/
-/*!
- * \brief Stores new mapping between domain name and offset in the compression
- * table.
- *
- * If the domain name is already present in the table, it is not inserted again.
- *
- * \param table Compression table to save the mapping into.
- * \param dname Domain name to insert.
- * \param pos Position of the domain name in the packet's wire format.
- */
-static void knot_response_compr_save(knot_compressed_dnames_t *table,
- const knot_dname_t *dname, size_t pos,
- int copied_dname)
-{
- assert(table->count < table->max);
-
- for (int i = 0; i < table->count; ++i) {
- if (table->dnames[i] == dname) {
- dbg_response("Already present, skipping..\n");
- return;
- }
- }
-
- table->dnames[table->count] = dname;
- table->offsets[table->count] = pos;
- table->to_free[table->count] = copied_dname;
- ++table->count;
-}
-
-/*----------------------------------------------------------------------------*/
-/*!
- * \brief Stores domain name position and positions of its parent domain names
- * to the compression table.
- *
- * If part of the domain name (\a dname) was not found previously in the
- * compression table, this part and all its parent domains is stored also, to
- * maximize compression potential.
- *
- * \param table Compression table to save the information into.
- * \param dname Domain name to save.
- * \param not_matched Count of labels not matched when previously searching in
- * the compression table for \a dname.
- * \param pos Position of the domain name in the wire format of the packet.
- * \param unmatched_offset Position of the unmatched parent domain of \a dname.
- *
- * \retval KNOT_EOK
- * \retval KNOT_ENOMEM
- */
-static int knot_response_store_dname_pos(knot_compressed_dnames_t *table,
- const knot_dname_t *dname,
- int not_matched, size_t pos,
- size_t unmatched_offset,
- int compr_cs)
-{
-dbg_response_exec(
- char *name = knot_dname_to_str(dname);
- dbg_response_detail("Putting dname %s into compression table."
- " Labels not matched: %d, position: %zu,"
- ", pointer: %p, unmatched off: %zu\n", name,
- not_matched, pos, dname, unmatched_offset);
- free(name);
-);
- if (pos > KNOT_RESPONSE_MAX_PTR) {
- dbg_response("Pointer larger than it can be, not saving\n");
- return KNOT_EDNAMEPTR;
- }
-
- if (table->count == table->max &&
- knot_response_realloc_compr(table) != 0) {
- return KNOT_ENOMEM;
- }
-
- /*
- * Store positions of ancestors if more than 1 label was not matched.
- *
- * In case the name is not in the zone, the counting to not_matched
- * may be limiting, because the search stopped before after the first
- * label (i.e. not_matched == 1). So we do not store the parents in
- * this case. However, storing them will require creating those domain
- * names, as they do not exist.
- *
- * The same problem is with domain names synthetized from wildcards.
- * These also do not have any node to follow.
- *
- * We accept this as performance has higher
- * priority than the best possible compression.
- */
- const knot_dname_t *to_save = dname;
- size_t parent_pos = pos;
- int i = 0, copied = 0;
-
- while (to_save != NULL && i < knot_dname_label_count(dname)
- && parent_pos <= KNOT_RESPONSE_MAX_PTR) {
- if (i == not_matched) {
- parent_pos = unmatched_offset;
- }
-
-dbg_response_exec_detail(
- char *name = knot_dname_to_str(to_save);
- dbg_response_detail("Putting dname %s into compression table."
- " Position: %zu, pointer: %p\n",
- name, parent_pos, to_save);
- free(name);
-);
-
- if (table->count == table->max &&
- knot_response_realloc_compr(table) != 0) {
- dbg_response("Unable to realloc.\n");
- return KNOT_ENOMEM;
- }
-
- knot_response_compr_save(table, to_save, parent_pos, copied);
-
- /*! \todo Remove '!compr_cs'. */
- // This is a temporary hack to avoid the wrong behaviour
- // when the wrong not_matched count is used to compare with i
- // and resulting in using the 0 offset.
- // If case-sensitive search is in place, we should not save the
- // node's parent's positions.
-
- // Added check to rule out wildcard-covered dnames
- // (in such case the offset is not right)
-
- /*! \todo The whole compression requires a serious refactoring.
- * Or better - a rewrite!
- */
- const knot_dname_t *to_save_new =
- (!compr_cs && knot_dname_node(to_save) != NULL
- && knot_node_owner(knot_dname_node(to_save))
- != to_save
- && knot_node_parent(knot_dname_node(to_save))
- != NULL)
- ? knot_node_owner(knot_node_parent(
- knot_dname_node(to_save)))
- : NULL;
-
-#ifdef COMPRESSION_PEDANTIC
- if (to_save_new == NULL) {
- // copied name - must be freed later
- to_save_new = knot_dname_left_chop(to_save);
- copied = 1;
+ uint16_t score = 0;
+ uint16_t off = 0;
+ while (*n != '\0') {
+ /* Can't exceed current best coverage. */
+ if (score + labels <= match->lbcount)
+ return false; /* Early cut. */
+ /* Keep track of contiguous matches. */
+ if (*n == *p && memcmp(n + 1, p + 1, *n) == 0) {
+ if (score == 0)
+ off = (p - wire);
+ ++score;
} else {
- copied = 0;
+ score = 0; /* Non-contiguous match. */
}
-#endif
-
- to_save = to_save_new;
-
- dbg_response("i: %d\n", i);
- parent_pos += knot_dname_label_size(dname, i) + 1;
- ++i;
+ n = knot_wire_next_label(n, wire);
+ p = knot_wire_next_label(p, wire);
+ --labels;
}
- if (copied == 1 && to_save != NULL) {
- // The last name was not used, free it
- dbg_response("Freeing last chopped dname.\n");
- knot_dname_release((knot_dname_t *)to_save);
+ /* New best score. */
+ if (score > match->lbcount && off <= KNOT_WIRE_PTR_MAX) {
+ match->lbcount = score;
+ match->off = off;
+ return true;
}
- return KNOT_EOK;
+ return false;
}
-/*---------------------------------------------------------------------------*/
/*!
- * \brief Tries to find offset of domain name in the compression table.
- *
- * \param table Compression table to search in.
- * \param dname Domain name to search for.
- * \param compr_cs Set to <> 0 if dname compression should use case sensitive
- * comparation. Set to 0 otherwise.
- *
- * \return Offset of \a dname stored in the compression table or -1 if the name
- * was not found in the table.
+ * \brief Align name and reference to a common number of suffix labels.
*/
-static size_t knot_response_find_dname_pos(
- const knot_compressed_dnames_t *table,
- const knot_dname_t *dname, int compr_cs)
+static uint8_t knot_response_compr_align(uint8_t **name, uint8_t nlabels,
+ uint8_t **ref, uint8_t reflabels,
+ uint8_t *wire)
{
- for (int i = 0; i < table->count; ++i) {
- int ret = (compr_cs)
- ? knot_dname_compare_cs(table->dnames[i], dname)
- : knot_dname_compare(table->dnames[i], dname);
- if (ret == 0) {
- dbg_response_detail("Found offset: %zu\n",
- table->offsets[i]);
- return table->offsets[i];
- }
- }
- return 0;
-}
+ for (unsigned j = nlabels; j < reflabels; ++j)
+ *ref = knot_wire_next_label(*ref, wire);
-/*---------------------------------------------------------------------------*/
-/*!
- * \brief Put a compressed domain name to the wire format of the packet.
- *
- * Puts the not matched part of the domain name to the wire format and puts
- * a pointer to the rest of the name after that.
- *
- * \param dname Domain name to put to the wire format.
- * \param not_matched Size of the part of domain name that cannot be compressed.
- * \param offset Position of the rest of the domain name in the packet's wire
- * format.
- * \param wire Place where to put the wire format of the name.
- * \param max Maximum available size of the place for the wire format.
- *
- * \return Size of the compressed domain name put into the wire format or
- * KNOT_ESPACE if it did not fit.
- */
-static int knot_response_put_dname_ptr(const knot_dname_t *dname,
- int not_matched, size_t offset,
- uint8_t *wire, size_t max)
-{
- // put the not matched labels
- short size = knot_dname_size_part(dname, not_matched);
- if (size + 2 > max) {
- return KNOT_ESPACE;
- }
+ for (unsigned j = reflabels; j < nlabels; ++j)
+ *name = knot_wire_next_label(*name, wire);
- memcpy(wire, knot_dname_name(dname), size);
- knot_wire_put_pointer(wire + size, offset);
-
- dbg_response_detail("Size of the dname with ptr: %d\n", size + 2);
-
- return size + 2;
+ return (nlabels < reflabels) ? nlabels : reflabels;
}
-/*----------------------------------------------------------------------------*/
-/*!
- * \brief Tries to compress domain name and creates its wire format.
- *
- * \param dname Domain name to convert and compress.
- * \param compr Compression table holding information about offsets of domain
- * names in the packet.
- * \param dname_wire Place where to put the wire format of the name.
- * \param max Maximum available size of the place for the wire format.
- * \param compr_cs Set to <> 0 if dname compression should use case sensitive
- * comparation. Set to 0 otherwise.
- *
- * \return Size of the domain name's wire format or KNOT_ESPACE if it did not
- * fit into the provided space.
- */
-static int knot_response_compress_dname(const knot_dname_t *dname,
- knot_compr_t *compr, uint8_t *dname_wire, size_t max, int compr_cs)
+int knot_response_compress_dname(const knot_dname_t *dname, knot_compr_t *compr,
+ uint8_t *dst, size_t max)
{
- int size = 0;
- if (!dname || !compr || !dname_wire) {
+ if (!dname || !compr || !dst) {
return KNOT_EINVAL;
}
- // try to find the name or one of its ancestors in the compr. table
-#ifdef COMPRESSION_PEDANTIC
- knot_dname_t *to_find = (knot_dname_t *)dname;
- int copied = 0;
-#else
- const knot_dname_t *to_find = dname;
-#endif
- size_t offset = 0;
- int not_matched = 0;
-
- while (to_find != NULL && knot_dname_label_count(to_find) != 0) {
-dbg_response_exec_detail(
- char *name = knot_dname_to_str(to_find);
- dbg_response_detail("Searching for name %s in the compression"
- " table, not matched labels: %d\n", name,
- not_matched);
- free(name);
-);
- offset = knot_response_find_dname_pos(compr->table, to_find,
- compr_cs);
- if (offset == 0) {
- ++not_matched;
- } else {
- break;
+ /* Do not compress small dnames. */
+ uint8_t *name = dname->name;
+ if (dname->size <= 2) {
+ if (dname->size > max)
+ return KNOT_ESPACE;
+ memcpy(dst, name, dname->size);
+ return dname->size;
+ }
+
+ /* Align and compare name and pointer in the compression table. */
+ unsigned i = 0;
+ unsigned lbcount = 0;
+ unsigned match_id = 0;
+ knot_compr_ptr_t match = { 0, 0 };
+ for (; i < COMPR_MAXLEN && compr->table[i].off > 0; ++i) {
+ uint8_t *name = dname->name;
+ uint8_t *ref = compr->wire + compr->table[i].off;
+ lbcount = knot_response_compr_align(&name, dname->label_count,
+ &ref, compr->table[i].lbcount,
+ compr->wire);
+
+ if (knot_response_compr_score(name, ref, lbcount, compr->wire,
+ &match)) {
+ match_id = i;
+ if (match.lbcount == dname->label_count)
+ break; /* Best match, break. */
}
-#ifdef COMPRESSION_PEDANTIC
- if (compr_cs || to_find->node == NULL
- || to_find->node->owner != to_find
- || to_find->node->parent == NULL) {
- if (!copied) {
- to_find = knot_dname_left_chop(to_find);
- copied = 1;
- } else {
- knot_dname_left_chop_no_copy(to_find);
- }
- } else {
- assert(knot_dname_node(to_find) !=
- knot_node_parent(knot_dname_node(to_find)));
- assert(to_find != knot_node_owner(
- knot_node_parent(knot_dname_node(to_find))));
- to_find = knot_node_get_owner(
- knot_node_parent(knot_dname_node(to_find)));
- }
- dbg_response_detail("New to_find: %p\n", to_find);
-#else
- // if case-sensitive comparation, we cannot just take the parent
- if (compr_cs || knot_dname_node(to_find) == NULL
- || knot_node_owner(knot_dname_node(to_find)) != to_find
- || knot_node_parent(knot_dname_node(to_find))
- == NULL) {
- dbg_response_detail("compr_cs: %d\n", compr_cs);
- dbg_response_detail("knot_dname_node(to_find, 1) == %p"
- "\n", knot_dname_node(to_find));
-
- if (knot_dname_node(to_find) != NULL) {
- dbg_response_detail("knot_node_owner(knot_dname_node("
- "to_find, 1)) = %p, to_find = %p\n",
- knot_node_owner(knot_dname_node(to_find)),
- to_find);
- dbg_response_detail("knot_node_parent(knot_dname_node("
- "to_find, 1), 1) = %p\n",
- knot_node_parent(knot_dname_node(to_find)));
- }
- break;
- } else {
- assert(knot_dname_node(to_find) !=
- knot_node_parent(knot_dname_node(to_find)));
- assert(to_find != knot_node_owner(
- knot_node_parent(knot_dname_node(to_find))));
- to_find = knot_node_owner(
- knot_node_parent(knot_dname_node(to_find)));
- dbg_response_detail("New to_find: %p\n", to_find);
- }
-#endif
}
-#ifdef COMPRESSION_PEDANTIC
- if (copied) {
- knot_dname_free(&to_find);
- }
-#endif
-
- dbg_response_detail("Max size available for domain name: %zu\n", max);
-
- if (offset > 0) {
- // found such dname somewhere in the packet
- // the pointer should be legal as no illegal pointers are stored
- assert(offset <= KNOT_RESPONSE_MAX_PTR);
- dbg_response_detail("Found name in the compression table.\n");
- assert(offset >= KNOT_WIRE_HEADER_SIZE);
- size = knot_response_put_dname_ptr(dname, not_matched, offset,
- dname_wire, max);
- if (size <= 0) {
+ /* Write non-matching prefix. */
+ unsigned written = 0;
+ for (unsigned j = match.lbcount; j < dname->label_count; ++j) {
+ if (written + *name + 1 > max)
return KNOT_ESPACE;
- }
- } else {
- dbg_response_detail("Not found, putting whole name.\n");
- // now just copy the dname without compressing
- if (dname->size > max) {
- return KNOT_ESPACE;
- }
-
- memcpy(dname_wire, dname->name, dname->size);
- size = dname->size;
- }
-
- // in either way, put info into the compression table
- /*! \todo This is useless if the name was already in the table.
- * It is meaningful only if the found name is the one from QNAME
- * and thus its parents are not stored yet.
- */
- // only put legal pointers (#2131)
- if (knot_response_store_dname_pos(compr->table, dname, not_matched,
- compr->wire_pos, offset, compr_cs)
- != 0) {
- dbg_response_detail("Compression info could not be stored.\n");
- }
-
- return size;
-}
-
-/*---------------------------------------------------------------------------*/
-/*!
- * \brief Convert one RR into wire format.
- *
- * \param[in] rrset RRSet to which the RR belongs.
- * \param[in] rdata The actual RDATA of this RR.
- * \param[in] compr Information about compressed domain names in the packet.
- * \param[out] rrset_wire Place to put the wire format of the RR into.
- * \param[in] max_size Size of space available for the wire format.
- * \param[in] compr_cs Set to <> 0 if dname compression should use case
- * sensitive comparation. Set to 0 otherwise.
- *
- * \return Size of the RR's wire format or KNOT_ESPACE if it did not fit into
- * the provided space.
- */
-static int knot_response_rr_to_wire(const knot_rrset_t *rrset,
- const knot_rdata_t *rdata,
- knot_compr_t *compr,
- uint8_t **rrset_wire, size_t max_size,
- int compr_cs)
-{
- int size = 0;
-
- dbg_response_detail("Max size: %zu, owner pos: %zu, owner size: %d\n",
- max_size, compr->owner.pos, compr->owner.size);
-
- if (size + ((compr->owner.pos == 0
- || compr->owner.pos > KNOT_RESPONSE_MAX_PTR)
- ? compr->owner.size : 2) + 10
- > max_size) {
- return KNOT_ESPACE;
+ memcpy(dst + written, name, *name + 1);
+ written += *name + 1;
+ name = knot_wire_next_label(name, compr->wire);
}
- dbg_response_detail("Owner position: %zu\n", compr->owner.pos);
-
- // put owner if needed (already compressed)
- if (compr->owner.pos == 0 || compr->owner.pos > KNOT_RESPONSE_MAX_PTR) {
- memcpy(*rrset_wire, compr->owner.wire, compr->owner.size);
- compr->owner.pos = compr->wire_pos;
- *rrset_wire += compr->owner.size;
- size += compr->owner.size;
+ /* Write out pointer covering suffix. */
+ if (*name != '\0') {
+ if (written + sizeof(uint16_t) > max)
+ return KNOT_ESPACE;
+ knot_wire_put_pointer(dst + written, match.off);
+ written += sizeof(uint16_t);
} else {
- dbg_response_detail("Putting pointer: %zu\n",
- compr->owner.pos);
- knot_wire_put_pointer(*rrset_wire, compr->owner.pos);
- *rrset_wire += 2;
- size += 2;
- }
-
- dbg_response_detail("Max size: %zu, size: %d\n", max_size, size);
-
- dbg_response_detail("Wire format:\n");
-
- // put rest of RR 'header'
- knot_wire_write_u16(*rrset_wire, rrset->type);
- dbg_response_detail(" Type: %u\n", rrset->type);
- *rrset_wire += 2;
-
- knot_wire_write_u16(*rrset_wire, rrset->rclass);
- dbg_response_detail(" Class: %u\n", rrset->rclass);
- *rrset_wire += 2;
-
- knot_wire_write_u32(*rrset_wire, rrset->ttl);
- dbg_response_detail(" TTL: %u\n", rrset->ttl);
- *rrset_wire += 4;
-
- // save space for RDLENGTH
- uint8_t *rdlength_pos = *rrset_wire;
- *rrset_wire += 2;
-
- size += 10;
- compr->wire_pos += size;
-
- dbg_response_detail("Max size: %zu, size: %d\n", max_size, size);
-
- knot_rrtype_descriptor_t *desc =
- knot_rrtype_descriptor_by_type(rrset->type);
-
- uint16_t rdlength = 0;
-
- for (int i = 0; i < rdata->count; ++i) {
- if (max_size < size + rdlength) {
+ /* Not covered by compression table, write terminal. */
+ if (written + 1 > max)
return KNOT_ESPACE;
- }
-
- switch (desc->wireformat[i]) {
- case KNOT_RDATA_WF_COMPRESSED_DNAME: {
- int ret = knot_response_compress_dname(
- knot_rdata_item(rdata, i)->dname,
- compr, *rrset_wire, max_size - size - rdlength,
- compr_cs);
-
- if (ret < 0) {
- return KNOT_ESPACE;
- }
-
- dbg_response_detail("Compressed dname size: %d\n", ret);
- *rrset_wire += ret;
- rdlength += ret;
- compr->wire_pos += ret;
- // TODO: compress domain name
- break;
- }
- 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;
- }
-
- // save whole domain name
- memcpy(*rrset_wire, dname->name, dname->size);
- dbg_response_detail("Uncompressed dname size: %d\n",
- dname->size);
- *rrset_wire += dname->size;
- rdlength += dname->size;
- compr->wire_pos += dname->size;
- break;
- }
- default: {
- uint16_t *raw_data =
- knot_rdata_item(rdata, i)->raw_data;
-
- if (size + rdlength + raw_data[0] > max_size) {
- return KNOT_ESPACE;
- }
-
- // copy just the rdata item data (without size)
- memcpy(*rrset_wire, raw_data + 1, raw_data[0]);
- dbg_response_detail("Raw data size: %d\n",
- raw_data[0]);
- *rrset_wire += raw_data[0];
- rdlength += raw_data[0];
- compr->wire_pos += raw_data[0];
- break;
- }
- }
+ *(dst + written) = '\0';
+ written += 1;
}
-
- dbg_response_detail("Max size: %zu, size: %d\n", max_size, size);
-
- assert(size + rdlength <= max_size);
- size += rdlength;
- knot_wire_write_u16(rdlength_pos, rdlength);
-
- return size;
-}
-
-/*---------------------------------------------------------------------------*/
-/*!
- * \brief Convert whole RRSet into wire format.
- *
- * \param[in] rrset RRSet to convert
- * \param[out] pos Place where to put the wire format.
- * \param[out] size Size of the converted wire format.
- * \param[in] max_size Maximum available space for the wire format.
- * \param wire_pos Current position in the wire format of the whole packet.
- * \param owner_tmp Wire format of the RRSet's owner, possibly compressed.
- * \param compr Information about compressed domain names in the packet.
- * \param compr_cs Set to <> 0 if dname compression should use case sensitive
- * comparation. Set to 0 otherwise.
- *
- * \return Size of the RRSet's wire format or KNOT_ESPACE if it did not fit
- * into the provided space.
- */
-static int knot_response_rrset_to_wire(const knot_rrset_t *rrset,
- uint8_t **pos, size_t *size,
- size_t max_size, size_t wire_pos,
- uint8_t *owner_tmp,
- knot_compressed_dnames_t *compr,
- int compr_cs)
-{
-dbg_response_exec_verb(
- char *name = knot_dname_to_str(rrset->owner);
- dbg_response_verb("Converting RRSet with owner %s, type %s\n",
- name, knot_rrtype_to_string(rrset->type));
- free(name);
- dbg_response_verb(" Size before: %zu\n", *size);
-);
- // if no RDATA in RRSet, return
- if (rrset->rdata == NULL) {
- return KNOT_EOK;
+ /* Promote good matches. */
+ if (match_id > 1) {
+ match = compr->table[match_id];
+ compr->table[match_id] = compr->table[match_id - 1];
+ compr->table[match_id - 1] = match;
}
- /*
- * We may pass the current position to the compression function
- * because if the owner will be put somewhere, it will be on the
- * current position (first item of a RR). If it will not be put into
- * the wireformat, we may remove the dname (and possibly its parents)
- * from the compression table.
- */
+ /* Do not insert if exceeds bounds or full match. */
+ if (match.lbcount == dname->label_count ||
+ compr->wire_pos > KNOT_WIRE_PTR_MAX)
+ return written;
- knot_compr_t compr_info;
- compr_info.table = compr;
- compr_info.wire_pos = wire_pos;
- compr_info.owner.pos = 0;
- compr_info.owner.wire = owner_tmp;
- compr_info.owner.size =
- knot_response_compress_dname(rrset->owner, &compr_info,
- owner_tmp, max_size, compr_cs);
-
- dbg_response_detail(" Owner size: %d, position: %zu\n",
- compr_info.owner.size, compr_info.owner.pos);
- if (compr_info.owner.size < 0) {
- return KNOT_ESPACE;
+ /* If table is full, elect name from the lower 1/4 of the table
+ * and replace it. */
+ if (i == COMPR_MAXLEN) {
+ i = COMPR_FIXEDLEN + rand() % COMPR_VOLATILE;
+ compr->table[i].off = 0;
}
- int rrs = 0;
- short rrset_size = 0;
-
- const knot_rdata_t *rdata = rrset->rdata;
- do {
- int ret = knot_response_rr_to_wire(rrset, rdata, &compr_info,
- pos, max_size - rrset_size,
- compr_cs);
-
- assert(ret != 0);
-
- if (ret < 0) {
- // some RR didn't fit in, so no RRs should be used
- // TODO: remove last entries from compression table
- dbg_response("Some RR didn't fit in.\n");
- return KNOT_ESPACE;
- }
-
- dbg_response_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 <= max_size);
- *size += rrset_size;
-
- dbg_response_verb(" Size after: %zu\n", *size);
+ /* Store in dname table. */
+ if (compr->table[i].off == 0) {
+ compr->table[i].off = (uint16_t)compr->wire_pos;
+ compr->table[i].lbcount = dname->label_count;
+ }
- return rrs;
+ return written;
}
/*----------------------------------------------------------------------------*/
@@ -752,8 +186,6 @@ dbg_response_exec_verb(
* \param rrset RRSet to add.
* \param tc Set to <> 0 if omitting the RRSet should cause the TC bit to be
* set in the response.
- * \param compr_cs Set to <> 0 if dname compression should use case sensitive
- * comparation. Set to 0 otherwise.
*
* \return Count of RRs added to the response or KNOT_ESPACE if the RRSet did
* not fit in the available space.
@@ -762,29 +194,36 @@ static int knot_response_try_add_rrset(const knot_rrset_t **rrsets,
short *rrset_count,
knot_packet_t *resp,
size_t max_size,
- const knot_rrset_t *rrset, int tc,
- int compr_cs)
+ const knot_rrset_t *rrset, int tc)
{
//short size = knot_response_rrset_size(rrset, &resp->compression);
dbg_response_exec(
char *name = knot_dname_to_str(rrset->owner);
- dbg_response_verb("\nAdding RRSet with owner %s and type %s: \n",
- name, knot_rrtype_to_string(rrset->type));
+ dbg_response_verb("\nAdding RRSet with owner %s and type %u: \n",
+ name, rrset->type);
free(name);
);
-
uint8_t *pos = resp->wireformat + resp->size;
- size_t size = 0;
- int rrs = knot_response_rrset_to_wire(rrset, &pos, &size, max_size,
- resp->size, resp->owner_tmp,
- &resp->compression, compr_cs);
+ size_t size = max_size;
+ compression_param_t param;
+ param.compressed_dnames = resp->compression;
+ param.wire_pos = resp->size;
+ param.wire = resp->wireformat;
+ uint16_t rr_count = 0;
+ int ret = knot_rrset_to_wire(rrset, pos, &size, max_size,
+ &rr_count, &param);
- if (rrs >= 0) {
+ if (ret != KNOT_EOK) {
+ dbg_response("Failed to convert RRSet to wire. (%s).\n,",
+ knot_strerror(ret));
+ }
+
+ if (rr_count > 0) {
rrsets[(*rrset_count)++] = rrset;
resp->size += size;
dbg_response_verb("RRset added, size: %zu, RRs: %d, total "
- "size of response: %zu\n\n", size, rrs,
+ "size of response: %zu\n\n", size, rr_count,
resp->size);
} else if (tc) {
dbg_response_verb("Setting TC bit.\n");
@@ -792,7 +231,7 @@ dbg_response_exec(
knot_wire_set_tc(resp->wireformat);
}
- return rrs;
+ return rr_count > 0 ? rr_count : ret;
}
/*----------------------------------------------------------------------------*/
@@ -917,7 +356,6 @@ int knot_response_init_from_query(knot_packet_t *response,
// copy the header from the query
memcpy(&response->header, &query->header, sizeof(knot_header_t));
- int err = 0;
/*! \todo Constant. */
size_t to_copy = 12;
@@ -926,13 +364,10 @@ int knot_response_init_from_query(knot_packet_t *response,
memcpy(&response->question, &query->question,
sizeof(knot_question_t));
- // put the qname into the compression table
- // TODO: get rid of the numeric constants
- if ((err = knot_response_store_dname_pos(&response->compression,
- response->question.qname, 0, 12, 12, 0))
- != KNOT_EOK) {
- return err;
- }
+ /* Insert QNAME into compression table. */
+ response->compression[0].off = KNOT_WIRE_HEADER_SIZE;
+ response->compression[0].lbcount = response->question.qname->label_count;
+
/*! \todo Constant. */
to_copy += 4 + knot_dname_size(response->question.qname);
@@ -942,7 +377,9 @@ int knot_response_init_from_query(knot_packet_t *response,
}
assert(response->max_size >= to_copy);
- memcpy(response->wireformat, query->wireformat, to_copy);
+ if (response->wireformat != query->wireformat) {
+ memcpy(response->wireformat, query->wireformat, to_copy);
+ }
response->size = to_copy;
// set the qr bit to 1
@@ -952,11 +389,11 @@ int knot_response_init_from_query(knot_packet_t *response,
// clear TC flag
knot_wire_flags_clear_tc(&response->header.flags1);
knot_wire_clear_tc(response->wireformat);
-
+
// clear AD flag
knot_wire_flags_clear_ad(&response->header.flags2);
knot_wire_clear_ad(response->wireformat);
-
+
// clear RA flag
knot_wire_flags_clear_ra(&response->header.flags2);
knot_wire_clear_ad(response->wireformat);
@@ -989,14 +426,8 @@ void knot_response_clear(knot_packet_t *resp, int clear_question)
resp->ns_rrsets = 0;
resp->ar_rrsets = 0;
- // free copied names for compression
- for (int i = 0; i < resp->compression.count; ++i) {
- if (resp->compression.to_free[i]) {
- knot_dname_release(
- (knot_dname_t *)resp->compression.dnames[i]);
- }
- }
- resp->compression.count = 0;
+ /* Clear compression table. */
+ memset(resp->compression, 0, COMPR_MAXLEN * sizeof(knot_compr_ptr_t));
/*! \todo Temporary RRSets are not deallocated, which may potentially
* lead to memory leaks should this function be used in other
@@ -1089,7 +520,7 @@ int knot_response_add_opt(knot_packet_t *resp,
int knot_response_add_rrset_answer(knot_packet_t *response,
knot_rrset_t *rrset, int tc,
- int check_duplicates, int compr_cs,
+ int check_duplicates,
int rotate)
{
if (response == NULL || rrset == NULL) {
@@ -1122,7 +553,7 @@ int knot_response_add_rrset_answer(knot_packet_t *response,
- response->size
- response->opt_rr.size
- response->tsig_size,
- rrset, tc, compr_cs);
+ rrset, tc);
if (rrs >= 0) {
response->header.ancount += rrs;
@@ -1142,7 +573,7 @@ int knot_response_add_rrset_answer(knot_packet_t *response,
int knot_response_add_rrset_authority(knot_packet_t *response,
knot_rrset_t *rrset, int tc,
- int check_duplicates, int compr_cs,
+ int check_duplicates,
int rotate)
{
if (response == NULL || rrset == NULL) {
@@ -1171,7 +602,7 @@ int knot_response_add_rrset_authority(knot_packet_t *response,
- response->size
- response->opt_rr.size
- response->tsig_size,
- rrset, tc, compr_cs);
+ rrset, tc);
if (rrs >= 0) {
response->header.nscount += rrs;
@@ -1191,7 +622,7 @@ int knot_response_add_rrset_authority(knot_packet_t *response,
int knot_response_add_rrset_additional(knot_packet_t *response,
knot_rrset_t *rrset, int tc,
- int check_duplicates, int compr_cs,
+ int check_duplicates,
int rotate)
{
if (response == NULL || rrset == NULL) {
@@ -1225,8 +656,8 @@ int knot_response_add_rrset_additional(knot_packet_t *response,
&response->ar_rrsets, response,
response->max_size
- response->size
- - response->tsig_size, rrset,
- tc, compr_cs);
+ - response->tsig_size, rrset,
+ tc);
if (rrs >= 0) {
response->header.arcount += rrs;
diff --git a/src/libknot/packet/response.h b/src/libknot/packet/response.h
index 277b1aa..b68ca45 100644
--- a/src/libknot/packet/response.h
+++ b/src/libknot/packet/response.h
@@ -24,8 +24,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _KNOT_response_H_
-#define _KNOT_response_H_
+#ifndef _KNOT_RESPONSE_H_
+#define _KNOT_RESPONSE_H_
#include <stdint.h>
#include <string.h>
@@ -37,6 +37,50 @@
#include "edns.h"
/*!
+ * \brief Holds information about compressed domain name.
+ *
+ * Used only to pass information between functions.
+ *
+ * \todo This description should be revised and clarified.
+ */
+struct knot_compr_owner {
+ /*!
+ * \brief Place where the name is stored in the wire format of the
+ * packet.
+ */
+ uint8_t *wire;
+ uint8_t size; /*!< Size of the domain name in bytes. */
+ /*! \brief Position of the name relative to the start of the packet. */
+ size_t pos;
+};
+
+typedef struct knot_compr_owner knot_compr_owner_t;
+
+/*!
+ * \brief Holds information about compressed domain names in packet.
+ *
+ * Used only to pass information between functions.
+ *
+ * \todo This description should be revised and clarified.
+ */
+struct knot_compr {
+ knot_compr_ptr_t *table; /*!< Compression table. */
+ uint8_t *wire;
+ size_t wire_pos; /*!< Current position in the wire format. */
+ knot_compr_owner_t owner; /*!< Information about the current name. */
+};
+
+typedef struct knot_compr knot_compr_t;
+
+struct compression_param {
+ uint8_t *wire;
+ size_t wire_pos;
+ knot_compr_ptr_t *compressed_dnames;
+};
+
+typedef struct compression_param compression_param_t;
+
+/*!
* \brief Default maximum DNS response size
*
* This size must be supported by all servers and clients.
@@ -109,8 +153,6 @@ int knot_response_add_opt(knot_packet_t *resp,
* Otherwise set to 0.
* \param check_duplicates Set to <> 0 if the RRSet should not be added to the
* response in case it is already there.
- * \param compr_cs Set to <> 0 if dname compression should use case sensitive
- * comparation. Set to 0 otherwise.
*
* \retval KNOT_EOK if successful, or the RRSet was already in the answer.
* \retval KNOT_ENOMEM
@@ -118,7 +160,7 @@ int knot_response_add_opt(knot_packet_t *resp,
*/
int knot_response_add_rrset_answer(knot_packet_t *response,
knot_rrset_t *rrset, int tc,
- int check_duplicates, int compr_cs,
+ int check_duplicates,
int rotate);
/*!
@@ -130,8 +172,6 @@ int knot_response_add_rrset_answer(knot_packet_t *response,
* Otherwise set to 0.
* \param check_duplicates Set to <> 0 if the RRSet should not be added to the
* response in case it is already there.
- * \param compr_cs Set to <> 0 if dname compression should use case sensitive
- * comparation. Set to 0 otherwise.
*
* \retval KNOT_EOK if successful, or the RRSet was already in the answer.
* \retval KNOT_ENOMEM
@@ -139,7 +179,7 @@ int knot_response_add_rrset_answer(knot_packet_t *response,
*/
int knot_response_add_rrset_authority(knot_packet_t *response,
knot_rrset_t *rrset, int tc,
- int check_duplicates, int compr_cs,
+ int check_duplicates,
int rotate);
/*!
@@ -151,8 +191,6 @@ int knot_response_add_rrset_authority(knot_packet_t *response,
* Otherwise set to 0.
* \param check_duplicates Set to <> 0 if the RRSet should not be added to the
* response in case it is already there.
- * \param compr_cs Set to <> 0 if dname compression should use case sensitive
- * comparation. Set to 0 otherwise.
*
* \retval KNOT_EOK if successful, or the RRSet was already in the answer.
* \retval KNOT_ENOMEM
@@ -160,7 +198,7 @@ int knot_response_add_rrset_authority(knot_packet_t *response,
*/
int knot_response_add_rrset_additional(knot_packet_t *response,
knot_rrset_t *rrset, int tc,
- int check_duplicates, int compr_cs,
+ int check_duplicates,
int rotate);
/*!
@@ -201,6 +239,22 @@ int knot_response_add_nsid(knot_packet_t *response, const uint8_t *data,
int knot_response_add_wildcard_node(knot_packet_t *response,
const knot_node_t *node,
const knot_dname_t *sname);
+/*----------------------------------------------------------------------------*/
+/*!
+ * \brief Tries to compress domain name and creates its wire format.
+ *
+ * \param dname Domain name to convert and compress.
+ * \param compr Compression table holding information about offsets of domain
+ * names in the packet.
+ * \param dst Place where to put the wire format of the name.
+ * \param max Maximum available size of the place for the wire format.
+ *
+ * \return Size of the domain name's wire format or KNOT_ESPACE if it did not
+ * fit into the provided space.
+ */
+int knot_response_compress_dname(const knot_dname_t *dname,
+ knot_compr_t *compr, uint8_t *dst, size_t max);
+
#endif /* _KNOT_response_H_ */