]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
neater code layout.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 1 Jun 2007 12:25:38 +0000 (12:25 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 1 Jun 2007 12:25:38 +0000 (12:25 +0000)
git-svn-id: file:///svn/unbound/trunk@356 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
doc/Changelog
iterator/iterator.c
services/outside_network.c
testcode/fake_event.c
testcode/unitmsgparse.c
util/data/msgencode.c [new file with mode: 0644]
util/data/msgencode.h [new file with mode: 0644]
util/data/msgreply.c
util/data/msgreply.h

index 78ef5d0a0c3be4491e787794d8d773d841f4876c..f4f493bcdc53738d27e7ca9f58faa8c8bdce6c49 100644 (file)
@@ -55,6 +55,7 @@
 #include "services/outbound_list.h"
 #include "services/cache/rrset.h"
 #include "util/data/msgparse.h"
+#include "util/data/msgencode.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
index 75a352889d5f68b6887ee5b7fc04e2c4f1ff1e7b..57b1c8a026680a9082150a315b963c18fd6d85ae 100644 (file)
@@ -2,6 +2,7 @@
        - normalize incoming messages. Like unbound-java, with CNAME chain
          checked, DNAME checked, CNAME's synthesized, glue checked.
        - sanitize incoming messages.
+       - split msgreply encode functions into own file msgencode.c.
 
 31 May 2007: Wouter
        - querytargets state.
index e4d6e84a2c7f19b7486117426c7a47782471a32d..49eb818fef14cf77f85122121bd24c437095904b 100644 (file)
@@ -53,6 +53,7 @@
 #include "util/net_help.h"
 #include "util/region-allocator.h"
 #include "util/data/dname.h"
+#include "util/data/msgencode.h"
 
 /** iterator init */
 static int 
index 22b764744da9b24b9984e45df471018fc262fa59..cf5ae88f4e06ddeefb0da00f13ad3d1b4a5aaceb 100644 (file)
@@ -45,6 +45,7 @@
 #include "services/cache/infra.h"
 #include "util/data/msgparse.h"
 #include "util/data/msgreply.h"
+#include "util/data/msgencode.h"
 #include "util/netevent.h"
 #include "util/log.h"
 #include "util/net_help.h"
index ee60f11669bc7f35ab9256060319c879d68df88d..a30640c47e9de4582f56659aef019996fc9872c3 100644 (file)
@@ -50,6 +50,7 @@
 #include "util/net_help.h"
 #include "util/data/msgparse.h"
 #include "util/data/msgreply.h"
+#include "util/data/msgencode.h"
 #include "services/listen_dnsport.h"
 #include "services/outside_network.h"
 #include "testcode/replay.h"
index 27f3790e2a7163bb127e5253497cc5d2c763d789..4060c1ea6e118261ad4a729328aac82c63ea5f6c 100644 (file)
@@ -43,6 +43,7 @@
 #include "testcode/unitmain.h"
 #include "util/data/msgparse.h"
 #include "util/data/msgreply.h"
+#include "util/data/msgencode.h"
 #include "util/alloc.h"
 #include "util/region-allocator.h"
 #include "util/net_help.h"
diff --git a/util/data/msgencode.c b/util/data/msgencode.c
new file mode 100644 (file)
index 0000000..ce1802f
--- /dev/null
@@ -0,0 +1,687 @@
+/*
+ * util/data/msgencode.c - Encode DNS messages, queries and replies.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains a routines to encode DNS messages.
+ */
+
+#include "config.h"
+#include "util/data/msgencode.h"
+#include "util/data/msgreply.h"
+#include "util/data/msgparse.h"
+#include "util/data/dname.h"
+#include "util/log.h"
+#include "util/region-allocator.h"
+#include "util/net_help.h"
+
+/** return code that means the function ran out of memory. negative so it does
+ * not conflict with DNS rcodes. */
+#define RETVAL_OUTMEM  -2
+/** return code that means the data did not fit (completely) in the packet */
+#define RETVAL_TRUNC   -4
+/** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
+#define RETVAL_OK      0
+
+/**
+ * Data structure to help domain name compression in outgoing messages.
+ * A tree of dnames and their offsets in the packet is kept.
+ * It is kept sorted, not canonical, but by label at least, so that after
+ * a lookup of a name you know its closest match, and the parent from that
+ * closest match. These are possible compression targets.
+ *
+ * It is a binary tree, not a rbtree or balanced tree, as the effort
+ * of keeping it balanced probably outweighs usefulness (given typical
+ * DNS packet size).
+ */
+struct compress_tree_node {
+       /** left node in tree, all smaller to this */
+       struct compress_tree_node* left;
+       /** right node in tree, all larger than this */
+       struct compress_tree_node* right;
+
+       /** the parent node - not for tree, but zone parent. One less label */
+       struct compress_tree_node* parent;
+       /** the domain name for this node. Pointer to uncompressed memory. */
+       uint8_t* dname;
+       /** number of labels in domain name, kept to help compare func. */
+       int labs;
+       /** offset in packet that points to this dname */
+       size_t offset;
+};
+
+/**
+ * Find domain name in tree, returns exact and closest match.
+ * @param tree: root of tree.
+ * @param dname: pointer to uncompressed dname.
+ * @param labs: number of labels in domain name.
+ * @param match: closest or exact match.
+ *     guaranteed to be smaller or equal to the sought dname.
+ *     can be null if the tree is empty.
+ * @param matchlabels: number of labels that match with closest match.
+ *     can be zero is there is no match.
+ * @return: 0 if no exact match.
+ */
+static int
+compress_tree_search(struct compress_tree_node* tree, uint8_t* dname,
+       int labs, struct compress_tree_node** match, int* matchlabels)
+{
+       int c, n, closen=0;
+       struct compress_tree_node* p = tree;
+       struct compress_tree_node* close = 0;
+       while(p) {
+               if((c = dname_lab_cmp(dname, labs, p->dname, p->labs, &n)) 
+                       == 0) {
+                       *matchlabels = n;
+                       *match = p;
+                       return 1;
+               }
+               if(c<0) p = p->left;
+               else    {
+                       closen = n;
+                       close = p; /* p->dname is smaller than dname */
+                       p = p->right;
+               }
+       }
+       *matchlabels = closen;
+       *match = close;
+       return 0;
+}
+
+/**
+ * Lookup a domain name in compression tree.
+ * @param tree: root of tree (not the node with '.').
+ * @param dname: pointer to uncompressed dname.
+ * @param labs: number of labels in domain name.
+ * @return: 0 if not found or compress treenode with best compression.
+ */
+static struct compress_tree_node*
+compress_tree_lookup(struct compress_tree_node* tree, uint8_t* dname,
+       int labs)
+{
+       struct compress_tree_node* p;
+       int m;
+       if(labs <= 1)
+               return 0; /* do not compress root node */
+       if(compress_tree_search(tree, dname, labs, &p, &m)) {
+               /* exact match */
+               return p;
+       }
+       /* return some ancestor of p that compresses well. */
+       if(m>1) {
+               /* www.example.com. (labs=4) matched foo.example.com.(labs=4)
+                * then matchcount = 3. need to go up. */
+               while(p && p->labs > m)
+                       p = p->parent;
+               return p;
+       }
+       return 0;
+}
+
+/**
+ * Insert node into domain name compression tree.
+ * @param tree: root of tree (may be modified)
+ * @param dname: pointer to uncompressed dname (stored in tree).
+ * @param labs: number of labels in dname.
+ * @param offset: offset into packet for dname.
+ * @param region: how to allocate memory for new node.
+ * @return new node or 0 on malloc failure.
+ */
+static struct compress_tree_node*
+compress_tree_insert(struct compress_tree_node** tree, uint8_t* dname,
+       int labs, size_t offset, region_type* region)
+{
+       int c, m;
+       struct compress_tree_node* p, **prev;
+       struct compress_tree_node* n = (struct compress_tree_node*)
+               region_alloc(region, sizeof(struct compress_tree_node));
+       if(!n) return 0;
+       n->left = 0;
+       n->right = 0;
+       n->parent = 0;
+       n->dname = dname;
+       n->labs = labs;
+       n->offset = offset;
+
+       /* find spot to insert it into */
+       prev = tree;
+       p = *tree;
+       while(p) {
+               c = dname_lab_cmp(dname, labs, p->dname, p->labs, &m);
+               log_assert(c != 0); /* may not already be in tree */
+               if(c==0) return p; /* insert only once */
+               if(c<0) {
+                       prev = &p->left;
+                       p = p->left;
+               } else {
+                       prev = &p->right;
+                       p = p->right;
+               }
+       }
+       *prev = n;
+       return n;
+}
+
+/**
+ * Store domain name and ancestors into compression tree.
+ * @param tree: root of tree (may be modified)
+ * @param dname: pointer to uncompressed dname (stored in tree).
+ * @param labs: number of labels in dname.
+ * @param offset: offset into packet for dname.
+ * @param region: how to allocate memory for new node.
+ * @param closest: match from previous lookup, used to compress dname.
+ *     may be NULL if no previous match.
+ *     if the tree has an ancestor of dname already, this must be it.
+ * @return: 0 on memory error.
+ */
+static int
+compress_tree_store(struct compress_tree_node** tree, uint8_t* dname,
+       int labs, size_t offset, region_type* region,
+       struct compress_tree_node* closest)
+{
+       uint8_t lablen;
+       struct compress_tree_node** lastparentptr = 0;
+       struct compress_tree_node* newnode;
+       int uplabs = labs-1; /* does not store root in tree */
+       if(closest) uplabs = labs - closest->labs;
+       log_assert(uplabs >= 0);
+       while(uplabs--) {
+               if(offset > PTR_MAX_OFFSET) {
+                       if(lastparentptr) 
+                               *lastparentptr = closest;
+                       return 1; /* compression pointer no longer useful */
+               }
+               /* store dname, labs, offset */
+               if(!(newnode = compress_tree_insert(tree, dname, labs, offset, 
+                       region))) {
+                       if(lastparentptr) 
+                               *lastparentptr = closest;
+                       return 0;
+               }
+               if(lastparentptr)
+                       *lastparentptr = newnode;
+               lastparentptr = &newnode->parent;
+
+               /* next label */
+               lablen = *dname++;
+               dname += lablen;
+               offset += lablen+1;
+               labs--;
+       }
+       if(lastparentptr)
+               *lastparentptr = closest;
+       return 1;
+}
+
+/** compress a domain name */
+static int
+write_compressed_dname(ldns_buffer* pkt, uint8_t* dname, int labs,
+       struct compress_tree_node* p)
+{
+       /* compress it */
+       int labcopy = labs - p->labs;
+       uint8_t lablen;
+       uint16_t ptr;
+
+       if(labs == 1) {
+               /* write root label */
+               if(ldns_buffer_remaining(pkt) < 1)
+                       return 0;
+               ldns_buffer_write_u8(pkt, 0);
+               return 1;
+       }
+
+       /* copy the first couple of labels */
+       while(labcopy--) {
+               lablen = *dname++;
+               if(ldns_buffer_remaining(pkt) < (size_t)lablen+1)
+                       return 0;
+               ldns_buffer_write_u8(pkt, lablen);
+               ldns_buffer_write(pkt, dname, lablen);
+               dname += lablen;
+       }
+       /* insert compression ptr */
+       if(ldns_buffer_remaining(pkt) < 2)
+               return 0;
+       ptr = PTR_CREATE(p->offset);
+       ldns_buffer_write_u16(pkt, ptr);
+       return 1;
+}
+
+/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
+static int
+compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, 
+       region_type* region, struct compress_tree_node** tree, 
+       size_t owner_pos, uint16_t* owner_ptr, int owner_labs)
+{
+       struct compress_tree_node* p;
+       if(!*owner_ptr) {
+               /* compress first time dname */
+               if((p = compress_tree_lookup(*tree, key->rk.dname, 
+                       owner_labs))) {
+                       if(p->labs == owner_labs) 
+                               /* avoid ptr chains, since some software is
+                                * not capable of decoding ptr after a ptr. */
+                               *owner_ptr = htons(PTR_CREATE(p->offset));
+                       if(!write_compressed_dname(pkt, key->rk.dname, 
+                               owner_labs, p))
+                               return RETVAL_TRUNC;
+                       /* check if typeclass+4 ttl + rdatalen is available */
+                       if(ldns_buffer_remaining(pkt) < 4+4+2)
+                               return RETVAL_TRUNC;
+               } else {
+                       /* no compress */
+                       if(ldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2)
+                               return RETVAL_TRUNC;
+                       ldns_buffer_write(pkt, key->rk.dname, 
+                               key->rk.dname_len);
+                       if(owner_pos <= PTR_MAX_OFFSET)
+                               *owner_ptr = htons(PTR_CREATE(owner_pos));
+               }
+               if(!compress_tree_store(tree, key->rk.dname, 
+                       owner_labs, owner_pos, region, p))
+                       return RETVAL_OUTMEM;
+       } else {
+               /* always compress 2nd-further RRs in RRset */
+               if(owner_labs == 1) {
+                       if(ldns_buffer_remaining(pkt) < 1+4+4+2) 
+                               return RETVAL_TRUNC;
+                       ldns_buffer_write_u8(pkt, 0);
+               } else {
+                       if(ldns_buffer_remaining(pkt) < 2+4+4+2) 
+                               return RETVAL_TRUNC;
+                       ldns_buffer_write(pkt, owner_ptr, 2);
+               }
+       }
+       return RETVAL_OK;
+}
+
+/** compress any domain name to the packet, return RETVAL_* */
+static int
+compress_any_dname(uint8_t* dname, ldns_buffer* pkt, int labs, 
+       region_type* region, struct compress_tree_node** tree)
+{
+       struct compress_tree_node* p;
+       size_t pos = ldns_buffer_position(pkt);
+       if((p = compress_tree_lookup(*tree, dname, labs))) {
+               if(!write_compressed_dname(pkt, dname, labs, p))
+                       return RETVAL_TRUNC;
+       } else {
+               if(!dname_buffer_write(pkt, dname))
+                       return RETVAL_TRUNC;
+       }
+       if(!compress_tree_store(tree, dname, labs, pos, region, p))
+               return RETVAL_OUTMEM;
+       return RETVAL_OK;
+}
+
+/** return true if type needs domain name compression in rdata */
+static const ldns_rr_descriptor*
+type_rdata_compressable(struct ub_packed_rrset_key* key)
+{
+       uint16_t t = ntohs(key->rk.type);
+       if(ldns_rr_descript(t) && 
+               ldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS)
+               return ldns_rr_descript(t);
+       return 0;
+}
+
+/** compress domain names in rdata, return RETVAL_* */
+static int
+compress_rdata(ldns_buffer* pkt, uint8_t* rdata, size_t todolen, 
+       region_type* region, struct compress_tree_node** tree, 
+       const ldns_rr_descriptor* desc)
+{
+       int labs, r, rdf = 0;
+       size_t dname_len, len, pos = ldns_buffer_position(pkt);
+       uint8_t count = desc->_dname_count;
+
+       ldns_buffer_skip(pkt, 2); /* rdata len fill in later */
+       /* space for rdatalen checked for already */
+       rdata += 2;
+       todolen -= 2;
+       while(todolen > 0 && count) {
+               switch(desc->_wireformat[rdf]) {
+               case LDNS_RDF_TYPE_DNAME:
+                       labs = dname_count_size_labels(rdata, &dname_len);
+                       if((r=compress_any_dname(rdata, pkt, labs, region, 
+                               tree)) != RETVAL_OK)
+                               return r;
+                       rdata += dname_len;
+                       todolen -= dname_len;
+                       count--;
+                       len = 0;
+                       break;
+               case LDNS_RDF_TYPE_STR:
+                       len = *rdata + 1;
+                       break;
+               default:
+                       len = get_rdf_size(desc->_wireformat[rdf]);
+               }
+               if(len) {
+                       /* copy over */
+                       if(ldns_buffer_remaining(pkt) < len)
+                               return RETVAL_TRUNC;
+                       ldns_buffer_write(pkt, rdata, len);
+                       todolen -= len;
+                       rdata += len;
+               }
+               rdf++;
+       }
+       /* copy remainder */
+       if(todolen > 0) {
+               if(ldns_buffer_remaining(pkt) < todolen)
+                       return RETVAL_TRUNC;
+               ldns_buffer_write(pkt, rdata, todolen);
+       }
+
+       /* set rdata len */
+       ldns_buffer_write_u16_at(pkt, pos, ldns_buffer_position(pkt)-pos-2);
+       return RETVAL_OK;
+}
+
+/** store rrset in buffer in wireformat, return RETVAL_* */
+static int
+packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, 
+       uint16_t* num_rrs, uint32_t timenow, region_type* region,
+       int do_data, int do_sig, struct compress_tree_node** tree)
+{
+       size_t i, owner_pos;
+       int r, owner_labs;
+       uint16_t owner_ptr = 0;
+       struct packed_rrset_data* data = (struct packed_rrset_data*)
+               key->entry.data;
+
+       owner_labs = dname_count_labels(key->rk.dname);
+       owner_pos = ldns_buffer_position(pkt);
+
+       if(do_data) {
+               const ldns_rr_descriptor* c = type_rdata_compressable(key);
+               for(i=0; i<data->count; i++) {
+                       if((r=compress_owner(key, pkt, region, tree, 
+                               owner_pos, &owner_ptr, owner_labs))
+                               != RETVAL_OK)
+                               return r;
+                       ldns_buffer_write(pkt, &key->rk.type, 2);
+                       ldns_buffer_write(pkt, &key->rk.rrset_class, 2);
+                       ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow);
+                       if(c) {
+                               if((r=compress_rdata(pkt, data->rr_data[i],
+                                       data->rr_len[i], region, tree, c))
+                                       != RETVAL_OK)
+                                       return r;
+                       } else {
+                               if(ldns_buffer_remaining(pkt) < data->rr_len[i])
+                                       return RETVAL_TRUNC;
+                               ldns_buffer_write(pkt, data->rr_data[i], 
+                                       data->rr_len[i]);
+                       }
+               }
+       }
+       /* insert rrsigs */
+       if(do_sig) {
+               size_t total = data->count+data->rrsig_count;
+               for(i=data->count; i<total; i++) {
+                       if(owner_ptr && owner_labs != 1) {
+                               if(ldns_buffer_remaining(pkt) <
+                                       2+4+4+data->rr_len[i]) 
+                                       return RETVAL_TRUNC;
+                               ldns_buffer_write(pkt, &owner_ptr, 2);
+                       } else {
+                               if((r=compress_any_dname(key->rk.dname, 
+                                       pkt, owner_labs, region, tree))
+                                       != RETVAL_OK)
+                                       return r;
+                               if(ldns_buffer_remaining(pkt) < 
+                                       4+4+data->rr_len[i])
+                                       return RETVAL_TRUNC;
+                       }
+                       ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
+                       ldns_buffer_write(pkt, &key->rk.rrset_class, 2);
+                       ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow);
+                       /* rrsig rdata cannot be compressed, perform 100+ byte
+                        * memcopy. */
+                       ldns_buffer_write(pkt, data->rr_data[i],
+                               data->rr_len[i]);
+               }
+       }
+       /* change rrnum only after we are sure it fits */
+       if(do_data)
+               *num_rrs += data->count;
+       if(do_sig)
+               *num_rrs += data->rrsig_count;
+
+       return RETVAL_OK;
+}
+
+/** store msg section in wireformat buffer, return RETVAL_* */
+static int
+insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
+       ldns_buffer* pkt, size_t rrsets_before, uint32_t timenow, 
+       region_type* region, int addit, struct compress_tree_node** tree)
+{
+       int r;
+       size_t i, setstart;
+       *num_rrs = 0;
+       if(!addit) {
+               for(i=0; i<num_rrsets; i++) {
+                       setstart = ldns_buffer_position(pkt);
+                       if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 
+                               pkt, num_rrs, timenow, region, 1, 1, tree))
+                               != RETVAL_OK) {
+                               /* Bad, but if due to size must set TC bit */
+                               /* trim off the rrset neatly. */
+                               ldns_buffer_set_position(pkt, setstart);
+                               return r;
+                       }
+               }
+       } else {
+               for(i=0; i<num_rrsets; i++) {
+                       setstart = ldns_buffer_position(pkt);
+                       if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 
+                               pkt, num_rrs, timenow, region, 1, 0, tree))
+                               != RETVAL_OK) {
+                               ldns_buffer_set_position(pkt, setstart);
+                               return r;
+                       }
+               }
+               for(i=0; i<num_rrsets; i++) {
+                       setstart = ldns_buffer_position(pkt);
+                       if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 
+                               pkt, num_rrs, timenow, region, 0, 1, tree))
+                               != RETVAL_OK) {
+                               ldns_buffer_set_position(pkt, setstart);
+                               return r;
+                       }
+               }
+       }
+       return RETVAL_OK;
+}
+
+int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
+       uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, 
+       region_type* region, uint16_t udpsize)
+{
+       uint16_t ancount=0, nscount=0, arcount=0;
+       struct compress_tree_node* tree = 0;
+       int r;
+
+       ldns_buffer_clear(buffer);
+       if(udpsize < ldns_buffer_limit(buffer))
+               ldns_buffer_set_limit(buffer, udpsize);
+       if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
+               return 0;
+
+       ldns_buffer_write(buffer, &id, sizeof(uint16_t));
+       ldns_buffer_write_u16(buffer, flags);
+       ldns_buffer_write_u16(buffer, rep->qdcount);
+       /* set an, ns, ar counts to zero in case of small packets */
+       ldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);
+
+       /* insert query section */
+       if(rep->qdcount) {
+               if(ldns_buffer_remaining(buffer) < 
+                       qinfo->qname_len+sizeof(uint16_t)*2)
+                       return 0; /* buffer too small */
+               if(!compress_tree_store(&tree, qinfo->qname, 
+                       dname_count_labels(qinfo->qname), 
+                       ldns_buffer_position(buffer), region, NULL))
+                       return 0;
+               ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
+               ldns_buffer_write_u16(buffer, qinfo->qtype);
+               ldns_buffer_write_u16(buffer, qinfo->qclass);
+       }
+
+       /* insert answer section */
+       if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 
+               0, timenow, region, 0, &tree)) != RETVAL_OK) {
+               if(r == RETVAL_TRUNC) {
+                       /* create truncated message */
+                       ldns_buffer_write_u16_at(buffer, 6, ancount);
+                       LDNS_TC_SET(ldns_buffer_begin(buffer));
+                       ldns_buffer_flip(buffer);
+                       return 1;
+               }
+               return 0;
+       }
+       ldns_buffer_write_u16_at(buffer, 6, ancount);
+
+       /* insert auth section */
+       if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, 
+               rep->an_numrrsets, timenow, region, 0, &tree)) != RETVAL_OK) {
+               if(r == RETVAL_TRUNC) {
+                       /* create truncated message */
+                       ldns_buffer_write_u16_at(buffer, 8, nscount);
+                       LDNS_TC_SET(ldns_buffer_begin(buffer));
+                       ldns_buffer_flip(buffer);
+                       return 1;
+               }
+               return 0;
+       }
+       ldns_buffer_write_u16_at(buffer, 8, nscount);
+
+       /* insert add section */
+       if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, 
+               rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 
+               1, &tree)) != RETVAL_OK) {
+               if(r == RETVAL_TRUNC) {
+                       /* no need to set TC bit, this is the additional */
+                       ldns_buffer_write_u16_at(buffer, 10, arcount);
+                       ldns_buffer_flip(buffer);
+                       return 1;
+               }
+               return 0;
+       }
+       ldns_buffer_write_u16_at(buffer, 10, arcount);
+       ldns_buffer_flip(buffer);
+       return 1;
+}
+
+uint16_t
+calc_edns_field_size(struct edns_data* edns)
+{
+       if(!edns || !edns->edns_present) 
+               return 0;
+       /* domain root '.' + type + class + ttl + rdatalen(=0) */
+       return 1 + 2 + 2 + 4 + 2;
+}
+
+void
+attach_edns_record(ldns_buffer* pkt, struct edns_data* edns)
+{
+       size_t len;
+       if(!edns || !edns->edns_present)
+               return;
+       /* inc additional count */
+       ldns_buffer_write_u16_at(pkt, 10,
+               ldns_buffer_read_u16_at(pkt, 10) + 1);
+       len = ldns_buffer_limit(pkt);
+       ldns_buffer_clear(pkt);
+       ldns_buffer_set_position(pkt, len);
+       /* write EDNS record */
+       ldns_buffer_write_u8(pkt, 0); /* '.' label */
+       ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
+       ldns_buffer_write_u16(pkt, edns->udp_size); /* class */
+       ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
+       ldns_buffer_write_u8(pkt, edns->edns_version);
+       ldns_buffer_write_u16(pkt, edns->bits);
+       ldns_buffer_write_u16(pkt, 0); /* rdatalen */
+       ldns_buffer_flip(pkt);
+}
+
+int 
+reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, 
+       uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow,
+       int cached, struct region* region, uint16_t udpsize, 
+       struct edns_data* edns)
+{
+       uint16_t flags;
+
+       if(!cached) {
+               /* original flags, copy RD bit from query. */
+               flags = rep->flags | (qflags & BIT_RD); 
+       } else {
+               /* remove AA bit, copy RD and CD bits from query. */
+               flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); 
+       }
+       log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
+       if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns))
+               return 0; /* packet too small to contain edns... */
+       udpsize -= calc_edns_field_size(edns);
+       if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
+               udpsize)) {
+               log_err("reply encode: out of memory");
+               return 0;
+       }
+       attach_edns_record(pkt, edns);
+       return 1;
+}
+
+void 
+qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo)
+{
+       uint16_t flags = 0; /* QUERY, NOERROR */
+       ldns_buffer_clear(pkt);
+       log_assert(ldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
+       ldns_buffer_skip(pkt, 2); /* id done later */
+       ldns_buffer_write_u16(pkt, flags);
+       ldns_buffer_write_u16(pkt, 1); /* query count */
+       ldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
+       ldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len);
+       ldns_buffer_write_u16(pkt, qinfo->qtype);
+       ldns_buffer_write_u16(pkt, qinfo->qclass);
+       ldns_buffer_flip(pkt);
+}
diff --git a/util/data/msgencode.h b/util/data/msgencode.h
new file mode 100644 (file)
index 0000000..de49404
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * util/data/msgencode.h - encode compressed DNS messages.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file contains temporary data structures and routines to create
+ * compressed DNS messages.
+ */
+
+#ifndef UTIL_DATA_MSGENCODE_H
+#define UTIL_DATA_MSGENCODE_H
+struct query_info;
+struct reply_info;
+struct region;
+struct edns_data;
+
+/** 
+ * Generate answer from reply_info.
+ * @param qinf: query information that provides query section in packet.
+ * @param rep: reply to fill in.
+ * @param id: id word from the query.
+ * @param qflags: flags word from the query.
+ * @param dest: buffer to put message into; will truncate if it does not fit.
+ * @param timenow: time to subtract.
+ * @param cached: set true if a cached reply (so no AA bit).
+ *     set false for the first reply.
+ * @param region: where to allocate temp variables (for compression).
+ * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
+ * @param edns: EDNS data included in the answer, NULL for none.
+ *     or if edns_present = 0, it is not included.
+ * @return: 0 on error (server failure).
+ */
+int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, 
+       uint16_t id, uint16_t qflags, ldns_buffer* dest, uint32_t timenow,
+       int cached, struct region* region, uint16_t udpsize, 
+       struct edns_data* edns);
+
+/**
+ * Regenerate the wireformat from the stored msg reply.
+ * If the buffer is too small then the message is truncated at a whole
+ * rrset and the TC bit set, or whole rrsets are left out of the additional
+ * and the TC bit is not set.
+ * @param qinfo: query info to store.
+ * @param rep: reply to store.
+ * @param id: id value to store, network order.
+ * @param flags: flags value to store, host order.
+ * @param buffer: buffer to store the packet into.
+ * @param timenow: time now, to adjust ttl values.
+ * @param region: to store temporary data in.
+ * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
+ * @return: nonzero is success, or 
+ *     0 on error: malloc failure (no log_err has been done).
+ */
+int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
+       uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, 
+       struct region* region, uint16_t udpsize);
+
+/**
+ * Encode query packet. Assumes the buffer is large enough.
+ * @param pkt: where to store the packet.
+ * @param qinfo: query info.
+ */
+void qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo);
+
+/**
+ * Estimate size of EDNS record in packet. EDNS record will be no larger.
+ * @param edns: edns data or NULL.
+ * @return octets to reserve for EDNS.
+ */
+uint16_t calc_edns_field_size(struct edns_data* edns);
+
+/**
+ * Attach EDNS record to buffer. Buffer has complete packet. There must
+ * be enough room left for the EDNS record.
+ * @param pkt: packet added to.
+ * @param edns: if NULL or present=0, nothing is added to the packet.
+ */
+void attach_edns_record(ldns_buffer* pkt, struct edns_data* edns);
+
+
+#endif /* UTIL_DATA_MSGENCODE_H */
index d49b3e895590cf99d2d0be95aa1522e8f8dd6fff..3c904eaaa33e926c9149a323cc6f331e421c1ccf 100644 (file)
 #include "util/region-allocator.h"
 #include "util/data/msgparse.h"
 
-/** return code that means the function ran out of memory. negative so it does
- * not conflict with DNS rcodes. */
-#define RETVAL_OUTMEM  -2
-/** return code that means the data did not fit (completely) in the packet */
-#define RETVAL_TRUNC   -4
-/** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
-#define RETVAL_OK      0
-
 /** allocate qinfo, return 0 on error. */
 static int
 parse_create_qinfo(ldns_buffer* pkt, struct msg_parse* msg, 
@@ -515,620 +507,6 @@ query_info_hash(struct query_info *q)
        return h;
 }
 
-/**
- * Data structure to help domain name compression in outgoing messages.
- * A tree of dnames and their offsets in the packet is kept.
- * It is kept sorted, not canonical, but by label at least, so that after
- * a lookup of a name you know its closest match, and the parent from that
- * closest match. These are possible compression targets.
- *
- * It is a binary tree, not a rbtree or balanced tree, as the effort
- * of keeping it balanced probably outweighs usefulness (given typical
- * DNS packet size).
- */
-struct compress_tree_node {
-       /** left node in tree, all smaller to this */
-       struct compress_tree_node* left;
-       /** right node in tree, all larger than this */
-       struct compress_tree_node* right;
-
-       /** the parent node - not for tree, but zone parent. One less label */
-       struct compress_tree_node* parent;
-       /** the domain name for this node. Pointer to uncompressed memory. */
-       uint8_t* dname;
-       /** number of labels in domain name, kept to help compare func. */
-       int labs;
-       /** offset in packet that points to this dname */
-       size_t offset;
-};
-
-/**
- * Find domain name in tree, returns exact and closest match.
- * @param tree: root of tree.
- * @param dname: pointer to uncompressed dname.
- * @param labs: number of labels in domain name.
- * @param match: closest or exact match.
- *     guaranteed to be smaller or equal to the sought dname.
- *     can be null if the tree is empty.
- * @param matchlabels: number of labels that match with closest match.
- *     can be zero is there is no match.
- * @return: 0 if no exact match.
- */
-static int
-compress_tree_search(struct compress_tree_node* tree, uint8_t* dname,
-       int labs, struct compress_tree_node** match, int* matchlabels)
-{
-       int c, n, closen=0;
-       struct compress_tree_node* p = tree;
-       struct compress_tree_node* close = 0;
-       while(p) {
-               if((c = dname_lab_cmp(dname, labs, p->dname, p->labs, &n)) 
-                       == 0) {
-                       *matchlabels = n;
-                       *match = p;
-                       return 1;
-               }
-               if(c<0) p = p->left;
-               else    {
-                       closen = n;
-                       close = p; /* p->dname is smaller than dname */
-                       p = p->right;
-               }
-       }
-       *matchlabels = closen;
-       *match = close;
-       return 0;
-}
-
-/**
- * Lookup a domain name in compression tree.
- * @param tree: root of tree (not the node with '.').
- * @param dname: pointer to uncompressed dname.
- * @param labs: number of labels in domain name.
- * @return: 0 if not found or compress treenode with best compression.
- */
-static struct compress_tree_node*
-compress_tree_lookup(struct compress_tree_node* tree, uint8_t* dname,
-       int labs)
-{
-       struct compress_tree_node* p;
-       int m;
-       if(labs <= 1)
-               return 0; /* do not compress root node */
-       if(compress_tree_search(tree, dname, labs, &p, &m)) {
-               /* exact match */
-               return p;
-       }
-       /* return some ancestor of p that compresses well. */
-       if(m>1) {
-               /* www.example.com. (labs=4) matched foo.example.com.(labs=4)
-                * then matchcount = 3. need to go up. */
-               while(p && p->labs > m)
-                       p = p->parent;
-               return p;
-       }
-       return 0;
-}
-
-/**
- * Insert node into domain name compression tree.
- * @param tree: root of tree (may be modified)
- * @param dname: pointer to uncompressed dname (stored in tree).
- * @param labs: number of labels in dname.
- * @param offset: offset into packet for dname.
- * @param region: how to allocate memory for new node.
- * @return new node or 0 on malloc failure.
- */
-static struct compress_tree_node*
-compress_tree_insert(struct compress_tree_node** tree, uint8_t* dname,
-       int labs, size_t offset, region_type* region)
-{
-       int c, m;
-       struct compress_tree_node* p, **prev;
-       struct compress_tree_node* n = (struct compress_tree_node*)
-               region_alloc(region, sizeof(struct compress_tree_node));
-       if(!n) return 0;
-       n->left = 0;
-       n->right = 0;
-       n->parent = 0;
-       n->dname = dname;
-       n->labs = labs;
-       n->offset = offset;
-
-       /* find spot to insert it into */
-       prev = tree;
-       p = *tree;
-       while(p) {
-               c = dname_lab_cmp(dname, labs, p->dname, p->labs, &m);
-               log_assert(c != 0); /* may not already be in tree */
-               if(c==0) return p; /* insert only once */
-               if(c<0) {
-                       prev = &p->left;
-                       p = p->left;
-               } else {
-                       prev = &p->right;
-                       p = p->right;
-               }
-       }
-       *prev = n;
-       return n;
-}
-
-/**
- * Store domain name and ancestors into compression tree.
- * @param tree: root of tree (may be modified)
- * @param dname: pointer to uncompressed dname (stored in tree).
- * @param labs: number of labels in dname.
- * @param offset: offset into packet for dname.
- * @param region: how to allocate memory for new node.
- * @param closest: match from previous lookup, used to compress dname.
- *     may be NULL if no previous match.
- *     if the tree has an ancestor of dname already, this must be it.
- * @return: 0 on memory error.
- */
-static int
-compress_tree_store(struct compress_tree_node** tree, uint8_t* dname,
-       int labs, size_t offset, region_type* region,
-       struct compress_tree_node* closest)
-{
-       uint8_t lablen;
-       struct compress_tree_node** lastparentptr = 0;
-       struct compress_tree_node* newnode;
-       int uplabs = labs-1; /* does not store root in tree */
-       if(closest) uplabs = labs - closest->labs;
-       log_assert(uplabs >= 0);
-       while(uplabs--) {
-               if(offset > PTR_MAX_OFFSET) {
-                       if(lastparentptr) 
-                               *lastparentptr = closest;
-                       return 1; /* compression pointer no longer useful */
-               }
-               /* store dname, labs, offset */
-               if(!(newnode = compress_tree_insert(tree, dname, labs, offset, 
-                       region))) {
-                       if(lastparentptr) 
-                               *lastparentptr = closest;
-                       return 0;
-               }
-               if(lastparentptr)
-                       *lastparentptr = newnode;
-               lastparentptr = &newnode->parent;
-
-               /* next label */
-               lablen = *dname++;
-               dname += lablen;
-               offset += lablen+1;
-               labs--;
-       }
-       if(lastparentptr)
-               *lastparentptr = closest;
-       return 1;
-}
-
-/** compress a domain name */
-static int
-write_compressed_dname(ldns_buffer* pkt, uint8_t* dname, int labs,
-       struct compress_tree_node* p)
-{
-       /* compress it */
-       int labcopy = labs - p->labs;
-       uint8_t lablen;
-       uint16_t ptr;
-
-       if(labs == 1) {
-               /* write root label */
-               if(ldns_buffer_remaining(pkt) < 1)
-                       return 0;
-               ldns_buffer_write_u8(pkt, 0);
-               return 1;
-       }
-
-       /* copy the first couple of labels */
-       while(labcopy--) {
-               lablen = *dname++;
-               if(ldns_buffer_remaining(pkt) < (size_t)lablen+1)
-                       return 0;
-               ldns_buffer_write_u8(pkt, lablen);
-               ldns_buffer_write(pkt, dname, lablen);
-               dname += lablen;
-       }
-       /* insert compression ptr */
-       if(ldns_buffer_remaining(pkt) < 2)
-               return 0;
-       ptr = PTR_CREATE(p->offset);
-       ldns_buffer_write_u16(pkt, ptr);
-       return 1;
-}
-
-/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
-static int
-compress_owner(struct ub_packed_rrset_key* key, ldns_buffer* pkt, 
-       region_type* region, struct compress_tree_node** tree, 
-       size_t owner_pos, uint16_t* owner_ptr, int owner_labs)
-{
-       struct compress_tree_node* p;
-       if(!*owner_ptr) {
-               /* compress first time dname */
-               if((p = compress_tree_lookup(*tree, key->rk.dname, 
-                       owner_labs))) {
-                       if(p->labs == owner_labs) 
-                               /* avoid ptr chains, since some software is
-                                * not capable of decoding ptr after a ptr. */
-                               *owner_ptr = htons(PTR_CREATE(p->offset));
-                       if(!write_compressed_dname(pkt, key->rk.dname, 
-                               owner_labs, p))
-                               return RETVAL_TRUNC;
-                       /* check if typeclass+4 ttl + rdatalen is available */
-                       if(ldns_buffer_remaining(pkt) < 4+4+2)
-                               return RETVAL_TRUNC;
-               } else {
-                       /* no compress */
-                       if(ldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2)
-                               return RETVAL_TRUNC;
-                       ldns_buffer_write(pkt, key->rk.dname, 
-                               key->rk.dname_len);
-                       if(owner_pos <= PTR_MAX_OFFSET)
-                               *owner_ptr = htons(PTR_CREATE(owner_pos));
-               }
-               if(!compress_tree_store(tree, key->rk.dname, 
-                       owner_labs, owner_pos, region, p))
-                       return RETVAL_OUTMEM;
-       } else {
-               /* always compress 2nd-further RRs in RRset */
-               if(owner_labs == 1) {
-                       if(ldns_buffer_remaining(pkt) < 1+4+4+2) 
-                               return RETVAL_TRUNC;
-                       ldns_buffer_write_u8(pkt, 0);
-               } else {
-                       if(ldns_buffer_remaining(pkt) < 2+4+4+2) 
-                               return RETVAL_TRUNC;
-                       ldns_buffer_write(pkt, owner_ptr, 2);
-               }
-       }
-       return RETVAL_OK;
-}
-
-/** compress any domain name to the packet, return RETVAL_* */
-static int
-compress_any_dname(uint8_t* dname, ldns_buffer* pkt, int labs, 
-       region_type* region, struct compress_tree_node** tree)
-{
-       struct compress_tree_node* p;
-       size_t pos = ldns_buffer_position(pkt);
-       if((p = compress_tree_lookup(*tree, dname, labs))) {
-               if(!write_compressed_dname(pkt, dname, labs, p))
-                       return RETVAL_TRUNC;
-       } else {
-               if(!dname_buffer_write(pkt, dname))
-                       return RETVAL_TRUNC;
-       }
-       if(!compress_tree_store(tree, dname, labs, pos, region, p))
-               return RETVAL_OUTMEM;
-       return RETVAL_OK;
-}
-
-/** return true if type needs domain name compression in rdata */
-static const ldns_rr_descriptor*
-type_rdata_compressable(struct ub_packed_rrset_key* key)
-{
-       uint16_t t = ntohs(key->rk.type);
-       if(ldns_rr_descript(t) && 
-               ldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS)
-               return ldns_rr_descript(t);
-       return 0;
-}
-
-/** compress domain names in rdata, return RETVAL_* */
-static int
-compress_rdata(ldns_buffer* pkt, uint8_t* rdata, size_t todolen, 
-       region_type* region, struct compress_tree_node** tree, 
-       const ldns_rr_descriptor* desc)
-{
-       int labs, r, rdf = 0;
-       size_t dname_len, len, pos = ldns_buffer_position(pkt);
-       uint8_t count = desc->_dname_count;
-
-       ldns_buffer_skip(pkt, 2); /* rdata len fill in later */
-       /* space for rdatalen checked for already */
-       rdata += 2;
-       todolen -= 2;
-       while(todolen > 0 && count) {
-               switch(desc->_wireformat[rdf]) {
-               case LDNS_RDF_TYPE_DNAME:
-                       labs = dname_count_size_labels(rdata, &dname_len);
-                       if((r=compress_any_dname(rdata, pkt, labs, region, 
-                               tree)) != RETVAL_OK)
-                               return r;
-                       rdata += dname_len;
-                       todolen -= dname_len;
-                       count--;
-                       len = 0;
-                       break;
-               case LDNS_RDF_TYPE_STR:
-                       len = *rdata + 1;
-                       break;
-               default:
-                       len = get_rdf_size(desc->_wireformat[rdf]);
-               }
-               if(len) {
-                       /* copy over */
-                       if(ldns_buffer_remaining(pkt) < len)
-                               return RETVAL_TRUNC;
-                       ldns_buffer_write(pkt, rdata, len);
-                       todolen -= len;
-                       rdata += len;
-               }
-               rdf++;
-       }
-       /* copy remainder */
-       if(todolen > 0) {
-               if(ldns_buffer_remaining(pkt) < todolen)
-                       return RETVAL_TRUNC;
-               ldns_buffer_write(pkt, rdata, todolen);
-       }
-
-       /* set rdata len */
-       ldns_buffer_write_u16_at(pkt, pos, ldns_buffer_position(pkt)-pos-2);
-       return RETVAL_OK;
-}
-
-/** store rrset in buffer in wireformat, return RETVAL_* */
-static int
-packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt, 
-       uint16_t* num_rrs, uint32_t timenow, region_type* region,
-       int do_data, int do_sig, struct compress_tree_node** tree)
-{
-       size_t i, owner_pos;
-       int r, owner_labs;
-       uint16_t owner_ptr = 0;
-       struct packed_rrset_data* data = (struct packed_rrset_data*)
-               key->entry.data;
-
-       owner_labs = dname_count_labels(key->rk.dname);
-       owner_pos = ldns_buffer_position(pkt);
-
-       if(do_data) {
-               const ldns_rr_descriptor* c = type_rdata_compressable(key);
-               for(i=0; i<data->count; i++) {
-                       if((r=compress_owner(key, pkt, region, tree, 
-                               owner_pos, &owner_ptr, owner_labs))
-                               != RETVAL_OK)
-                               return r;
-                       ldns_buffer_write(pkt, &key->rk.type, 2);
-                       ldns_buffer_write(pkt, &key->rk.rrset_class, 2);
-                       ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow);
-                       if(c) {
-                               if((r=compress_rdata(pkt, data->rr_data[i],
-                                       data->rr_len[i], region, tree, c))
-                                       != RETVAL_OK)
-                                       return r;
-                       } else {
-                               if(ldns_buffer_remaining(pkt) < data->rr_len[i])
-                                       return RETVAL_TRUNC;
-                               ldns_buffer_write(pkt, data->rr_data[i], 
-                                       data->rr_len[i]);
-                       }
-               }
-       }
-       /* insert rrsigs */
-       if(do_sig) {
-               size_t total = data->count+data->rrsig_count;
-               for(i=data->count; i<total; i++) {
-                       if(owner_ptr && owner_labs != 1) {
-                               if(ldns_buffer_remaining(pkt) <
-                                       2+4+4+data->rr_len[i]) 
-                                       return RETVAL_TRUNC;
-                               ldns_buffer_write(pkt, &owner_ptr, 2);
-                       } else {
-                               if((r=compress_any_dname(key->rk.dname, 
-                                       pkt, owner_labs, region, tree))
-                                       != RETVAL_OK)
-                                       return r;
-                               if(ldns_buffer_remaining(pkt) < 
-                                       4+4+data->rr_len[i])
-                                       return RETVAL_TRUNC;
-                       }
-                       ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
-                       ldns_buffer_write(pkt, &key->rk.rrset_class, 2);
-                       ldns_buffer_write_u32(pkt, data->rr_ttl[i]-timenow);
-                       /* rrsig rdata cannot be compressed, perform 100+ byte
-                        * memcopy. */
-                       ldns_buffer_write(pkt, data->rr_data[i],
-                               data->rr_len[i]);
-               }
-       }
-       /* change rrnum only after we are sure it fits */
-       if(do_data)
-               *num_rrs += data->count;
-       if(do_sig)
-               *num_rrs += data->rrsig_count;
-
-       return RETVAL_OK;
-}
-
-/** store msg section in wireformat buffer, return RETVAL_* */
-static int
-insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
-       ldns_buffer* pkt, size_t rrsets_before, uint32_t timenow, 
-       region_type* region, int addit, struct compress_tree_node** tree)
-{
-       int r;
-       size_t i, setstart;
-       *num_rrs = 0;
-       if(!addit) {
-               for(i=0; i<num_rrsets; i++) {
-                       setstart = ldns_buffer_position(pkt);
-                       if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 
-                               pkt, num_rrs, timenow, region, 1, 1, tree))
-                               != RETVAL_OK) {
-                               /* Bad, but if due to size must set TC bit */
-                               /* trim off the rrset neatly. */
-                               ldns_buffer_set_position(pkt, setstart);
-                               return r;
-                       }
-               }
-       } else {
-               for(i=0; i<num_rrsets; i++) {
-                       setstart = ldns_buffer_position(pkt);
-                       if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 
-                               pkt, num_rrs, timenow, region, 1, 0, tree))
-                               != RETVAL_OK) {
-                               ldns_buffer_set_position(pkt, setstart);
-                               return r;
-                       }
-               }
-               for(i=0; i<num_rrsets; i++) {
-                       setstart = ldns_buffer_position(pkt);
-                       if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], 
-                               pkt, num_rrs, timenow, region, 0, 1, tree))
-                               != RETVAL_OK) {
-                               ldns_buffer_set_position(pkt, setstart);
-                               return r;
-                       }
-               }
-       }
-       return RETVAL_OK;
-}
-
-int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
-       uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, 
-       region_type* region, uint16_t udpsize)
-{
-       uint16_t ancount=0, nscount=0, arcount=0;
-       struct compress_tree_node* tree = 0;
-       int r;
-
-       ldns_buffer_clear(buffer);
-       if(udpsize < ldns_buffer_limit(buffer))
-               ldns_buffer_set_limit(buffer, udpsize);
-       if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
-               return 0;
-
-       ldns_buffer_write(buffer, &id, sizeof(uint16_t));
-       ldns_buffer_write_u16(buffer, flags);
-       ldns_buffer_write_u16(buffer, rep->qdcount);
-       /* set an, ns, ar counts to zero in case of small packets */
-       ldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);
-
-       /* insert query section */
-       if(rep->qdcount) {
-               if(ldns_buffer_remaining(buffer) < 
-                       qinfo->qname_len+sizeof(uint16_t)*2)
-                       return 0; /* buffer too small */
-               if(!compress_tree_store(&tree, qinfo->qname, 
-                       dname_count_labels(qinfo->qname), 
-                       ldns_buffer_position(buffer), region, NULL))
-                       return 0;
-               ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
-               ldns_buffer_write_u16(buffer, qinfo->qtype);
-               ldns_buffer_write_u16(buffer, qinfo->qclass);
-       }
-
-       /* insert answer section */
-       if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 
-               0, timenow, region, 0, &tree)) != RETVAL_OK) {
-               if(r == RETVAL_TRUNC) {
-                       /* create truncated message */
-                       ldns_buffer_write_u16_at(buffer, 6, ancount);
-                       LDNS_TC_SET(ldns_buffer_begin(buffer));
-                       ldns_buffer_flip(buffer);
-                       return 1;
-               }
-               return 0;
-       }
-       ldns_buffer_write_u16_at(buffer, 6, ancount);
-
-       /* insert auth section */
-       if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, 
-               rep->an_numrrsets, timenow, region, 0, &tree)) != RETVAL_OK) {
-               if(r == RETVAL_TRUNC) {
-                       /* create truncated message */
-                       ldns_buffer_write_u16_at(buffer, 8, nscount);
-                       LDNS_TC_SET(ldns_buffer_begin(buffer));
-                       ldns_buffer_flip(buffer);
-                       return 1;
-               }
-               return 0;
-       }
-       ldns_buffer_write_u16_at(buffer, 8, nscount);
-
-       /* insert add section */
-       if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, 
-               rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 
-               1, &tree)) != RETVAL_OK) {
-               if(r == RETVAL_TRUNC) {
-                       /* no need to set TC bit, this is the additional */
-                       ldns_buffer_write_u16_at(buffer, 10, arcount);
-                       ldns_buffer_flip(buffer);
-                       return 1;
-               }
-               return 0;
-       }
-       ldns_buffer_write_u16_at(buffer, 10, arcount);
-       ldns_buffer_flip(buffer);
-       return 1;
-}
-
-uint16_t
-calc_edns_field_size(struct edns_data* edns)
-{
-       if(!edns || !edns->edns_present) 
-               return 0;
-       /* domain root '.' + type + class + ttl + rdatalen(=0) */
-       return 1 + 2 + 2 + 4 + 2;
-}
-
-void
-attach_edns_record(ldns_buffer* pkt, struct edns_data* edns)
-{
-       size_t len;
-       if(!edns || !edns->edns_present)
-               return;
-       /* inc additional count */
-       ldns_buffer_write_u16_at(pkt, 10,
-               ldns_buffer_read_u16_at(pkt, 10) + 1);
-       len = ldns_buffer_limit(pkt);
-       ldns_buffer_clear(pkt);
-       ldns_buffer_set_position(pkt, len);
-       /* write EDNS record */
-       ldns_buffer_write_u8(pkt, 0); /* '.' label */
-       ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
-       ldns_buffer_write_u16(pkt, edns->udp_size); /* class */
-       ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
-       ldns_buffer_write_u8(pkt, edns->edns_version);
-       ldns_buffer_write_u16(pkt, edns->bits);
-       ldns_buffer_write_u16(pkt, 0); /* rdatalen */
-       ldns_buffer_flip(pkt);
-}
-
-int 
-reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, 
-       uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow,
-       int cached, struct region* region, uint16_t udpsize, 
-       struct edns_data* edns)
-{
-       uint16_t flags;
-
-       if(!cached) {
-               /* original flags, copy RD bit from query. */
-               flags = rep->flags | (qflags & BIT_RD); 
-       } else {
-               /* remove AA bit, copy RD and CD bits from query. */
-               flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); 
-       }
-       log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
-       if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns))
-               return 0; /* packet too small to contain edns... */
-       udpsize -= calc_edns_field_size(edns);
-       if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
-               udpsize)) {
-               log_err("reply encode: out of memory");
-               return 0;
-       }
-       attach_edns_record(pkt, edns);
-       return 1;
-}
-
 struct msgreply_entry* 
 query_info_entrysetup(struct query_info* q, struct reply_info* r, 
        hashvalue_t h)
@@ -1148,19 +526,3 @@ query_info_entrysetup(struct query_info* q, struct reply_info* r,
        q->qname = NULL;
        return e;
 }
-
-void 
-qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo)
-{
-       uint16_t flags = 0; /* QUERY, NOERROR */
-       ldns_buffer_clear(pkt);
-       log_assert(ldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
-       ldns_buffer_skip(pkt, 2); /* id done later */
-       ldns_buffer_write_u16(pkt, flags);
-       ldns_buffer_write_u16(pkt, 1); /* query count */
-       ldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
-       ldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len);
-       ldns_buffer_write_u16(pkt, qinfo->qtype);
-       ldns_buffer_write_u16(pkt, qinfo->qclass);
-       ldns_buffer_flip(pkt);
-}
index 38d49bf8a6ff0882144da5c3f03e1e9a5cfa0b2e..f3e21aeee349e54cf40f171bfe3d4c832946cb5f 100644 (file)
@@ -246,54 +246,6 @@ void reply_info_delete(void* d, void* arg);
 /** calculate hash value of query_info, lowercases the qname. */
 hashvalue_t query_info_hash(struct query_info *q);
 
-/** 
- * Generate answer from reply_info.
- * @param qinf: query information that provides query section in packet.
- * @param rep: reply to fill in.
- * @param id: id word from the query.
- * @param qflags: flags word from the query.
- * @param dest: buffer to put message into; will truncate if it does not fit.
- * @param timenow: time to subtract.
- * @param cached: set true if a cached reply (so no AA bit).
- *     set false for the first reply.
- * @param region: where to allocate temp variables (for compression).
- * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
- * @param edns: EDNS data included in the answer, NULL for none.
- *     or if edns_present = 0, it is not included.
- * @return: 0 on error (server failure).
- */
-int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, 
-       uint16_t id, uint16_t qflags, ldns_buffer* dest, uint32_t timenow,
-       int cached, struct region* region, uint16_t udpsize, 
-       struct edns_data* edns);
-
-/**
- * Regenerate the wireformat from the stored msg reply.
- * If the buffer is too small then the message is truncated at a whole
- * rrset and the TC bit set, or whole rrsets are left out of the additional
- * and the TC bit is not set.
- * @param qinfo: query info to store.
- * @param rep: reply to store.
- * @param id: id value to store, network order.
- * @param flags: flags value to store, host order.
- * @param buffer: buffer to store the packet into.
- * @param timenow: time now, to adjust ttl values.
- * @param region: to store temporary data in.
- * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
- * @return: nonzero is success, or 
- *     0 on error: malloc failure (no log_err has been done).
- */
-int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, 
-       uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, 
-       struct region* region, uint16_t udpsize);
-
-/**
- * Encode query packet. Assumes the buffer is large enough.
- * @param pkt: where to store the packet.
- * @param qinfo: query info.
- */
-void qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo);
-
 /**
  * Setup query info entry
  * @param q: query info to copy. Emptied as if clear is called.
@@ -304,20 +256,4 @@ void qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo);
 struct msgreply_entry* query_info_entrysetup(struct query_info* q,
        struct reply_info* r, hashvalue_t h);
 
-/**
- * Estimate size of EDNS record in packet. EDNS record will be no larger.
- * @param edns: edns data or NULL.
- * @return octets to reserve for EDNS.
- */
-uint16_t calc_edns_field_size(struct edns_data* edns);
-
-/**
- * Attach EDNS record to buffer. Buffer has complete packet. There must
- * be enough room left for the EDNS record.
- * @param pkt: packet added to.
- * @param edns: if NULL or present=0, nothing is added to the packet.
- */
-void attach_edns_record(ldns_buffer* pkt, struct edns_data* edns);
-
-
 #endif /* UTIL_DATA_MSGREPLY_H */