#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;
+
+ /* 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, ldns_rdf_data(name))) != NULL)
+ {
+ /* Found */
+ uint16_t position = (49152 | (uint16_t)node->data);
+ 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. */
+ ldns_rbnode_t *node = LDNS_MALLOC(ldns_rbnode_t);
+ if(!node)
+ {
+ return LDNS_STATUS_MEM_ERR;
+ }
+ node->key = strdup((const char *)ldns_rdf_data(name));
+ node->data = (void *)ldns_buffer_position(buffer);
+ if(!ldns_rbtree_insert(compression_data,node))
+ {
+ /* fprintf(stderr,"Name not found but now it's there?\n"); */
+ }
+
+ ldns_rdf *label = ldns_dname_label(name,0);
+ ldns_rdf *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_free(label);
+ ldns_status s = ldns_dname2buffer_wire_compress(buffer, rest, compression_data);
+ ldns_rdf_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));
}
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)) {
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));
+ (void) ldns_rdf2buffer_wire_compress(
+ buffer, ldns_rr_rdf(rr, i), compression_data);
}
if (rdl_pos != 0) {
ldns_buffer_write_u16_at(buffer, rdl_pos,
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));
{
uint8_t flags;
uint16_t arcount;
-
+
if (ldns_buffer_reserve(buffer, 12)) {
ldns_buffer_write_u16(buffer, ldns_pkt_id(packet));
return ldns_buffer_status(buffer);
}
+void
+compression_node_free(ldns_rbnode_t *node, void *arg)
+{
+ (void)arg; /* Yes, dear compiler, it is used */
+ free((void *)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 *))strcasecmp);
(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);
}
}
/* 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);
/* 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;
}
*/
ldns_status ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name);
+/**
+ * Copies the dname data to the buffer in wire format
+ * \param[out] *buffer buffer to append the result to
+ * \param[in] *name rdata dname to convert
+ * \param[out] *compression_data data structure holding state for compression
+ * \return ldns_status
+ */
+ldns_status ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data);
+
/**
* Copies the rdata data to the buffer in wire format
* \param[out] *output buffer to append the result to
*/
ldns_status ldns_rdf2buffer_wire(ldns_buffer *output, const ldns_rdf *rdf);
+/**
+ * Copies the rdata data to the buffer in wire format
+ * \param[out] *output buffer to append the result to
+ * \param[in] *rdf rdata to convert
+ * \param[out] *compression_data data structure holding state for compression
+ * \return ldns_status
+ */
+ldns_status ldns_rdf2buffer_wire_compress(ldns_buffer *output, const ldns_rdf *rdf, ldns_rbtree_t *compression_data);
+
/**
* Copies the rdata data to the buffer in wire format
* If the rdata is a dname, the letters will be lowercased
const ldns_rr *rr,
int section);
+/**
+ * Copies the rr data to the buffer in wire format while doing DNAME compression
+ * \param[out] *output buffer to append the result to
+ * \param[in] *rr resource record to convert
+ * \param[in] section the section in the packet this rr is supposed to be in
+ * (to determine whether to add rdata or not)
+ * \param[out] *compression_data data structure holding state information for compression
+ * \return ldns_status
+ */
+ldns_status ldns_rr2buffer_wire_compress(ldns_buffer *output,
+ const ldns_rr *rr,
+ int section,
+ ldns_rbtree_t *compression_data);
+
/**
* Copies the rr data to the buffer in wire format, in canonical format
* according to RFC3597 (every dname in rdata fields of RR's mentioned in