aboutsummaryrefslogtreecommitdiffstats
path: root/host2wire.c
diff options
context:
space:
mode:
Diffstat (limited to 'host2wire.c')
-rw-r--r--host2wire.c162
1 files changed, 133 insertions, 29 deletions
diff --git a/host2wire.c b/host2wire.c
index 8fb5c3a2ba59..4d8aa30f2d85 100644
--- a/host2wire.c
+++ b/host2wire.c
@@ -16,25 +16,100 @@
#include <ldns/ldns.h>
-/* TODO Jelte
- add a pointer to a 'possiblecompression' structure
- to all the needed functions?
- something like an array of name, pointer values?
- every dname part could be added to it
-*/
-
ldns_status
ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name)
{
- if (ldns_buffer_reserve(buffer, ldns_rdf_size(name))) {
- ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
+ return ldns_dname2buffer_wire_compress(buffer, name, NULL);
+}
+
+ldns_status
+ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data)
+{
+ ldns_rbnode_t *node;
+ uint8_t *data;
+ size_t size;
+ ldns_rdf *label;
+ ldns_rdf *rest;
+ ldns_status s;
+
+ /* If no tree, just add the data */
+ if(!compression_data)
+ {
+ if (ldns_buffer_reserve(buffer, ldns_rdf_size(name)))
+ {
+ ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name));
+ }
+ return ldns_buffer_status(buffer);
+ }
+
+ /* No labels left, write final zero */
+ if(ldns_dname_label_count(name)==0)
+ {
+ if(ldns_buffer_reserve(buffer,1))
+ {
+ ldns_buffer_write_u8(buffer, 0);
+ }
+ return ldns_buffer_status(buffer);
+ }
+
+ /* Can we find the name in the tree? */
+ if((node = ldns_rbtree_search(compression_data, name)) != NULL)
+ {
+ /* Found */
+ uint16_t position = (uint16_t) (intptr_t) node->data | 0xC000;
+ if (ldns_buffer_reserve(buffer, 2))
+ {
+ ldns_buffer_write_u16(buffer, position);
+ }
+ return ldns_buffer_status(buffer);
+ }
+ else
+ {
+ /* Not found. Write cache entry, take off first label, write it, */
+ /* try again with the rest of the name. */
+ node = LDNS_MALLOC(ldns_rbnode_t);
+ if(!node)
+ {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ if (ldns_buffer_position(buffer) < 16384) {
+ node->key = ldns_rdf_clone(name);
+ node->data = (void *) (intptr_t) ldns_buffer_position(buffer);
+ if(!ldns_rbtree_insert(compression_data,node))
+ {
+ /* fprintf(stderr,"Name not found but now it's there?\n"); */
+ }
+ }
+ label = ldns_dname_label(name, 0);
+ rest = ldns_dname_left_chop(name);
+ size = ldns_rdf_size(label) - 1; /* Don't want the final zero */
+ data = ldns_rdf_data(label);
+ if(ldns_buffer_reserve(buffer, size))
+ {
+ ldns_buffer_write(buffer, data, size);
+ }
+ ldns_rdf_deep_free(label);
+ s = ldns_dname2buffer_wire_compress(buffer, rest, compression_data);
+ ldns_rdf_deep_free(rest);
+ return s;
}
- return ldns_buffer_status(buffer);
}
ldns_status
ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf)
{
+ return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL);
+}
+
+ldns_status
+ldns_rdf2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *rdf, ldns_rbtree_t *compression_data)
+{
+ /* If it's a DNAME, call that function to get compression */
+ if(compression_data && ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME)
+ {
+ return ldns_dname2buffer_wire_compress(buffer,rdf,compression_data);
+ }
+
if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) {
ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf));
}
@@ -158,11 +233,17 @@ ldns_rr2buffer_wire_canonical(ldns_buffer *buffer,
ldns_status
ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
{
+ return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL);
+}
+
+ldns_status
+ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data)
+{
uint16_t i;
uint16_t rdl_pos = 0;
-
+
if (ldns_rr_owner(rr)) {
- (void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr));
+ (void) ldns_dname2buffer_wire_compress(buffer, ldns_rr_owner(rr), compression_data);
}
if (ldns_buffer_reserve(buffer, 4)) {
@@ -177,9 +258,18 @@ ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
rdl_pos = ldns_buffer_position(buffer);
ldns_buffer_write_u16(buffer, 0);
}
- for (i = 0; i < ldns_rr_rd_count(rr); i++) {
- (void) ldns_rdf2buffer_wire(
- buffer, ldns_rr_rdf(rr, i));
+ if (LDNS_RR_COMPRESS ==
+ ldns_rr_descript(ldns_rr_get_type(rr))->_compress) {
+
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ (void) ldns_rdf2buffer_wire_compress(buffer,
+ ldns_rr_rdf(rr, i), compression_data);
+ }
+ } else {
+ for (i = 0; i < ldns_rr_rd_count(rr); i++) {
+ (void) ldns_rdf2buffer_wire(
+ buffer, ldns_rr_rdf(rr, i));
+ }
}
if (rdl_pos != 0) {
ldns_buffer_write_u16_at(buffer, rdl_pos,
@@ -214,6 +304,7 @@ ldns_status
ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr)
{
uint16_t i;
+
/* convert all the rdf's */
for (i = 0; i < ldns_rr_rd_count(rr); i++) {
(void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i));
@@ -229,7 +320,7 @@ ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
{
uint8_t flags;
uint16_t arcount;
-
+
if (ldns_buffer_reserve(buffer, 12)) {
ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
@@ -263,44 +354,54 @@ ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
return ldns_buffer_status(buffer);
}
+static void
+compression_node_free(ldns_rbnode_t *node, void *arg)
+{
+ (void)arg; /* Yes, dear compiler, it is used */
+ ldns_rdf_deep_free((ldns_rdf *)node->key);
+ LDNS_FREE(node);
+}
+
ldns_status
ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
{
ldns_rr_list *rr_list;
uint16_t i;
-
+
/* edns tmp vars */
ldns_rr *edns_rr;
uint8_t edata[4];
+
+ ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare);
(void) ldns_hdr2buffer_wire(buffer, packet);
rr_list = ldns_pkt_question(packet);
if (rr_list) {
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
- (void) ldns_rr2buffer_wire(buffer,
- ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION);
+ (void) ldns_rr2buffer_wire_compress(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION, compression_data);
}
}
rr_list = ldns_pkt_answer(packet);
if (rr_list) {
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
- (void) ldns_rr2buffer_wire(buffer,
- ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER);
+ (void) ldns_rr2buffer_wire_compress(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER, compression_data);
}
}
rr_list = ldns_pkt_authority(packet);
if (rr_list) {
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
- (void) ldns_rr2buffer_wire(buffer,
- ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY);
+ (void) ldns_rr2buffer_wire_compress(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY, compression_data);
}
}
rr_list = ldns_pkt_additional(packet);
if (rr_list) {
for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) {
- (void) ldns_rr2buffer_wire(buffer,
- ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL);
+ (void) ldns_rr2buffer_wire_compress(buffer,
+ ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL, compression_data);
}
}
@@ -319,7 +420,7 @@ ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
/* don't forget to add the edns rdata (if any) */
if (packet->_edns_data)
ldns_rr_push_rdf (edns_rr, packet->_edns_data);
- (void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL);
+ (void)ldns_rr2buffer_wire_compress(buffer, edns_rr, LDNS_SECTION_ADDITIONAL, compression_data);
/* take the edns rdata back out of the rr before we free rr */
if (packet->_edns_data)
(void)ldns_rr_pop_rdf (edns_rr);
@@ -328,10 +429,13 @@ ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet)
/* add TSIG to additional if it is there */
if (ldns_pkt_tsig(packet)) {
- (void) ldns_rr2buffer_wire(buffer,
- ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL);
+ (void) ldns_rr2buffer_wire_compress(buffer,
+ ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL, compression_data);
}
-
+
+ ldns_traverse_postorder(compression_data,compression_node_free,NULL);
+ ldns_rbtree_free(compression_data);
+
return LDNS_STATUS_OK;
}