]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
Straightforward implementation of name compression when converting packets to wireformat.
authorCalle Dybedahl <calle@init.se>
Wed, 25 Jun 2014 10:52:51 +0000 (12:52 +0200)
committerWillem Toorop <willem@nlnetlabs.nl>
Thu, 3 Jul 2014 14:12:41 +0000 (16:12 +0200)
host2wire.c
ldns/host2wire.h

index 8fb5c3a2ba598f8618065a075d4578324d06fb67..a461a2e356d550407b8b5de2eef511332d98c5b1 100644 (file)
 
 #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));
        }
@@ -157,12 +228,18 @@ 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)) {
@@ -178,8 +255,8 @@ ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section)
                        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,
@@ -214,6 +291,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 +307,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 +341,54 @@ ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *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);
                }
        }
        
@@ -319,7 +407,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 +416,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;
 }
 
index f3e3d43f10ace25b05f719bff4993b72bf8f6f2f..94693cda36666e2327bc0d0940ffcf88ffaa0ec3 100644 (file)
@@ -39,6 +39,15 @@ extern "C" {
  */
 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
@@ -47,6 +56,15 @@ ldns_status ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name);
  */
 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
@@ -70,6 +88,20 @@ ldns_status ldns_rr2buffer_wire(ldns_buffer *output,
                                                  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