diff options
author | Ondřej Surý <ondrej@sury.org> | 2013-06-28 12:59:40 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2013-06-28 12:59:40 +0200 |
commit | 124965832295a277b9ca6ae9fac4f45a74a36b2a (patch) | |
tree | f299e2335863f74e0be0707f84b85211baaf2d03 /src/libknot/packet | |
parent | 3d2d198c71a6b844b60fa9ef68801b66bba93361 (diff) | |
download | knot-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.c | 316 | ||||
-rw-r--r-- | src/libknot/packet/packet.h | 96 | ||||
-rw-r--r-- | src/libknot/packet/query.c | 89 | ||||
-rw-r--r-- | src/libknot/packet/query.h | 3 | ||||
-rw-r--r-- | src/libknot/packet/response.c | 849 | ||||
-rw-r--r-- | src/libknot/packet/response.h | 76 |
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, ¶m); - 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_ */ |