diff options
Diffstat (limited to 'host2wire.c')
-rw-r--r-- | host2wire.c | 162 |
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; } |