]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
RRSIG parsing and outputting.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 24 Apr 2007 13:39:23 +0000 (13:39 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 24 Apr 2007 13:39:23 +0000 (13:39 +0000)
git-svn-id: file:///svn/unbound/trunk@255 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
testcode/unitmsgparse.c
util/data/dname.c
util/data/dname.h
util/data/msgparse.c
util/data/msgparse.h
util/data/msgreply.c
util/data/packed_rrset.h
util/log.c

index 19b56dec4d464f364fa5834126f5f3ec3195d30f..0768764d84afce53b1b9351c490f8e520d1407cb 100644 (file)
@@ -1,7 +1,16 @@
+24 April 2007: Wouter
+       - ttl per RR, for RRSIG rrsets and others.
+       - dname_print debug function.
+       - if type is not known, size calc will skip DNAME decompression.
+       - RRSIG parsing and storing and putting in messages.
+       - dnssec enabled unit tests (from nlnetlabs.nl and se queries).
+       - EDNS extraction routine.
+
 20 April 2007: Wouter
        - code comes through all of the unit tests now.
        - disabled warning about spurious extra data.
        - documented the RRSIG parse plan in msgparse.h.
+       - rrsig reading and outputting.
 
 19 April 2007: Wouter
        - fix unit test to actually to tests.
index 7e3657ef4fd0a4a9164ba61f392296e97a6a9841..69a80b8454f1b9dc6fdf2c9ab0319158cad2e544 100644 (file)
@@ -98,8 +98,12 @@ static int
 match_list(ldns_rr_list* q, ldns_rr_list *p)
 {
        size_t i;
-       if(ldns_rr_list_rr_count(q) != ldns_rr_list_rr_count(p))
+       if(ldns_rr_list_rr_count(q) != ldns_rr_list_rr_count(p)) {
+               verbose(3, "rrlistcount different %d %d", 
+                       (int)ldns_rr_list_rr_count(q), 
+                       (int)ldns_rr_list_rr_count(p));
                return 0;
+       }
        for(i=0; i<ldns_rr_list_rr_count(q); i++)
        {
                if(ldns_rr_compare(ldns_rr_list_rr(q, i),
@@ -165,9 +169,9 @@ match_all(ldns_pkt* q, ldns_pkt* p)
        if(!match_list(ldns_pkt_answer(q), ldns_pkt_answer(p)))
        { verbose(3, "allmatch: an section different"); return 0;}
        if(!match_list(ldns_pkt_authority(q), ldns_pkt_authority(p)))
-       { verbose(3, "allmatch: ar section different"); return 0;}
-       if(!match_list(ldns_pkt_additional(q), ldns_pkt_additional(p)))
        { verbose(3, "allmatch: ns section different"); return 0;}
+       if(!match_list(ldns_pkt_additional(q), ldns_pkt_additional(p)))
+       { verbose(3, "allmatch: ar section different"); return 0;}
        return 1;
 }
 
@@ -185,6 +189,30 @@ test_buffers(ldns_buffer* pkt, ldns_buffer* out)
                                (unsigned)ldns_buffer_limit(pkt));
                return 1;
        }
+
+       if(vbmp) {
+               size_t sz = 16;
+               size_t count;
+               size_t lim = ldns_buffer_limit(out);
+               if(ldns_buffer_limit(pkt) < lim)
+                       lim = ldns_buffer_limit(pkt);
+               for(count=0; count<lim; count+=sz) {
+                       size_t rem = sz;
+                       if(lim-count < sz) rem = lim-count;
+                       if(memcmp(ldns_buffer_at(pkt, count), 
+                               ldns_buffer_at(out, count), rem) == 0) {
+                               log_info("same %d %d", count, rem);
+                               log_hex("same: ", ldns_buffer_at(pkt, count),
+                                       rem);
+                       } else {
+                               log_info("diff %d %d", count, rem);
+                               log_hex("difp: ", ldns_buffer_at(pkt, count),
+                                       rem);
+                               log_hex("difo: ", ldns_buffer_at(out, count),
+                                       rem);
+                       }
+               }
+       }
        /* check if it 'means the same' */
        s1 = ldns_buffer2pkt_wire(&p1, pkt);
        s2 = ldns_buffer2pkt_wire(&p2, out);
@@ -357,6 +385,7 @@ static void
 testfromdrillfile(ldns_buffer* pkt, struct alloc_cache* alloc, 
        ldns_buffer* out, const char* fname)
 {
+       /*  ;-- is used to indicate a new message */
        FILE* in = fopen(fname, "r");
        char buf[102400];
        char *np = buf;
@@ -365,14 +394,19 @@ testfromdrillfile(ldns_buffer* pkt, struct alloc_cache* alloc,
                return;
        }
        while(fgets(np, (int)sizeof(buf) - (np-buf), in)) {
+               if(strncmp(np, ";--", 3) == 0) {
+                       /* new entry */
+                       /* test previous */
+                       if(np != buf)
+                               testpkt(pkt, alloc, out, buf);
+                       /* set for new entry */
+                       np = buf;
+                       continue;
+               }
                if(np[0] == ';') /* comment */
                        continue;
                np = &np[strlen(np)];
        }
-       if(vbmp) {
-               printf("test %s", buf);
-               fflush(stdout);
-       }
        testpkt(pkt, alloc, out, buf);
        fclose(in);
 }
@@ -388,10 +422,12 @@ void msgparse_test()
 
        printf("testmsgparse\n");
        simpletest(pkt, &alloc, out);
+       /* plain hex dumps, like pcat */
        testfromfile(pkt, &alloc, out, "testdata/test_packets.1");
        testfromfile(pkt, &alloc, out, "testdata/test_packets.2");
        testfromfile(pkt, &alloc, out, "testdata/test_packets.3");
-       if(0) testfromdrillfile(pkt, &alloc, out, "blabla");
+       /* like from drill -w - */
+       testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.4");
 
        /* cleanup */
        alloc_clear(&alloc);
index 7c2c7da89e2b73337b8ef6cdb1c5b3fd7e7101c2..4b36730b0e804810ede7400f4942ef2d0cc61e3b 100644 (file)
@@ -302,3 +302,34 @@ void dname_pkt_copy(ldns_buffer* pkt, uint8_t* to, uint8_t* dname)
        /* copy last \0 */
        *to = 0;
 }
+
+void dname_print(FILE* out, ldns_buffer* pkt, uint8_t* dname)
+{
+       uint8_t lablen;
+       if(!out) out = stdout;
+       if(!dname) return;
+
+       lablen = *dname++;
+       if(!lablen) 
+               fputc('.', out);
+       while(lablen) {
+               if(LABEL_IS_PTR(lablen)) {
+                       /* follow pointer */
+                       if(!pkt) {
+                               fputs("??compressionptr??", out);
+                               return;
+                       }
+                       dname = ldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
+                       lablen = *dname++;
+                       continue;
+               }
+               if(lablen > LDNS_MAX_LABELLEN) {
+                       fputs("??extendedlabel??", out);
+                       return;
+               }
+               while(lablen--)
+                       fputc((int)*dname++, out);
+               fputc('.', out);
+               lablen = *dname++;
+       }
+}
index 90d2aaf9f600df6ea883caa9b6a229bd1abbf026..9633ce312f713d1e13f40ac8397e6ea3bab4305d 100644 (file)
@@ -119,4 +119,11 @@ hashvalue_t dname_pkt_hash(ldns_buffer* pkt, uint8_t* dname, hashvalue_t h);
  */
 void dname_pkt_copy(ldns_buffer* pkt, uint8_t* to, uint8_t* dname);
 
+/** debug helper. Print wireformat dname to output. 
+ * @param out: like stdout or a file.
+ * @param pkt: if not NULL, the packet for resolving compression ptrs.
+ * @param dname: pointer to (start of) dname.
+ */
+void dname_print(FILE* out, ldns_buffer* pkt, uint8_t* dname);
+
 #endif /* UTIL_DATA_DNAME_H */
index 189e1760999c8c18e5e04fbfd0bb48c2dd5fdfd6..d4fccfffa75bbd7229cceb02486fd92da3d52e38 100644 (file)
@@ -62,6 +62,40 @@ smart_compare(ldns_buffer* pkt, uint8_t* dnow,
        return dname_pkt_compare(pkt, dnow, dprlast);
 }
 
+/**
+ * Allocate new rrset in region, fill with data.
+ */
+static struct rrset_parse* 
+new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen, 
+       uint16_t type, uint16_t dclass, hashvalue_t hash, 
+       uint32_t rrset_flags, ldns_pkt_section section, region_type* region)
+{
+       struct rrset_parse* p = region_alloc(region, sizeof(*p));
+       if(!p) return NULL;
+       p->rrset_bucket_next = msg->hashtable[hash & (PARSE_TABLE_SIZE-1)];
+       msg->hashtable[hash & (PARSE_TABLE_SIZE-1)] = p;
+       p->rrset_all_next = 0;
+       if(msg->rrset_last)
+               msg->rrset_last->rrset_all_next = p;
+       else    msg->rrset_first = p;
+       msg->rrset_last = p;
+       p->hash = hash;
+       p->section = section;
+       p->dname = dname;
+       p->dname_len = dnamelen;
+       p->type = type;
+       p->rrset_class = dclass;
+       p->flags = rrset_flags;
+       p->rr_count = 0;
+       p->size = 0;
+       p->rr_first = 0;
+       p->rr_last = 0;
+       p->rrsig_count = 0;
+       p->rrsig_first = 0;
+       p->rrsig_last = 0;
+       return p;
+}
+
 /** See if next rrset is nsec at zone apex. */
 static int
 nsec_at_apex(ldns_buffer* pkt)
@@ -107,21 +141,29 @@ nsec_at_apex(ldns_buffer* pkt)
        return 0;
 }
 
+/** Calculate rrset flags */
+static uint32_t
+pkt_rrset_flags(struct msg_parse* msg, ldns_buffer* pkt, uint16_t type)
+{
+       uint32_t f;
+       if(msg->flags & BIT_CD)
+               f = PACKED_RRSET_CD;
+       else    f = 0;
+       if(type == htons(LDNS_RR_TYPE_NSEC) && nsec_at_apex(pkt)) {
+               f |= PACKED_RRSET_NSEC_AT_APEX;
+       }
+       return f;
+}
+
 /** Calculate hash value for rrset in packet. */
 static hashvalue_t
-pkt_hash_rrset(struct msg_parse* msg, ldns_buffer* pkt, uint8_t* dname, 
-       uint16_t type, uint16_t dclass, uint32_t* rrset_flags)
+pkt_hash_rrset(ldns_buffer* pkt, uint8_t* dname, uint16_t type, 
+       uint16_t dclass, uint32_t rrset_flags)
 {
        hashvalue_t h = 0xab;
-       if(msg->flags & BIT_CD)
-               *rrset_flags = PACKED_RRSET_CD;
-       else    *rrset_flags = 0;
-       if(type == htons(LDNS_RR_TYPE_NSEC) && nsec_at_apex(pkt))
-               *rrset_flags |= PACKED_RRSET_NSEC_AT_APEX;
-       
        h = hashlittle(&type, sizeof(type), h);
        h = hashlittle(&dclass, sizeof(dclass), h);
-       h = hashlittle(rrset_flags, sizeof(uint32_t), h);
+       h = hashlittle(&rrset_flags, sizeof(uint32_t), h);
        h = dname_pkt_hash(pkt, dname, h);
        return h;
 }
@@ -158,6 +200,203 @@ hashtable_lookup(struct msg_parse* msg, ldns_buffer* pkt, hashvalue_t h,
        return NULL;
 }
 
+/** return type networkformat that rrsig in packet covers */
+static int
+pkt_rrsig_covered(ldns_buffer* pkt, uint8_t* here, uint16_t* type)
+{
+       size_t pos = ldns_buffer_position(pkt);
+       ldns_buffer_set_position(pkt, (size_t)(here-ldns_buffer_begin(pkt)));
+       /* ttl + len + size of small rrsig(rootlabel, no signature) */
+       if(ldns_buffer_remaining(pkt) < 4+2+19)
+               return 0;
+       ldns_buffer_skip(pkt, 4); /* ttl */
+       if(ldns_buffer_read_u16(pkt) < 19) /* too short */ {
+               ldns_buffer_set_position(pkt, pos);
+               return 0;
+       }
+       *type = ldns_buffer_read_u16(pkt);
+       ldns_buffer_set_position(pkt, pos);
+       return 1;
+}
+
+/** true if covered type equals prevtype */
+static int
+pkt_rrsig_covered_equals(ldns_buffer* pkt, uint8_t* here, uint16_t type)
+{
+       uint16_t t;
+       if(pkt_rrsig_covered(pkt, here, &t) && t == ntohs(type))
+               return 1;
+       return 0;
+}
+
+/** remove rrset from hash list */
+static void
+bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset)
+{
+       struct rrset_parse** p;
+       p = &msg->hashtable[ rrset->hash & (PARSE_TABLE_SIZE-1) ];
+       while(*p) {
+               if(*p == rrset) {
+                       *p = rrset->rrset_bucket_next;
+                       return;
+               }
+               p = &( (*p)->rrset_bucket_next );
+       }
+}
+
+/** change section of rrset from previous to current section */
+static void
+change_section(struct msg_parse* msg, struct rrset_parse* rrset,
+       ldns_pkt_section section)
+{
+       struct rrset_parse *p, *prev;
+       /* remove from list */
+       if(section == rrset->section)
+               return;
+       p = msg->rrset_first;
+       prev = 0;
+       while(p) {
+               if(p == rrset) {
+                       if(prev) prev->rrset_all_next = p->rrset_all_next;
+                       else    msg->rrset_first = p->rrset_all_next;
+                       if(msg->rrset_last == rrset)
+                               msg->rrset_last = prev;
+                       break;
+               }
+               prev = p;
+               p = p->rrset_all_next;
+       }
+       /* remove from count */
+       switch(rrset->section) {
+               case LDNS_SECTION_ANSWER: msg->an_rrsets--; break;
+               case LDNS_SECTION_AUTHORITY: msg->ns_rrsets--; break;
+               case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets--; break;
+               default: log_assert(0);
+       }
+       /* insert at end of list */
+       rrset->rrset_all_next = 0;
+       if(msg->rrset_last)
+               msg->rrset_last->rrset_all_next = rrset;
+       else    msg->rrset_first = rrset;
+       msg->rrset_last = rrset;
+       /* up count of new section */
+       switch(section) {
+               case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break;
+               case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break;
+               default: log_assert(0);
+       }
+       rrset->section = section;
+}
+
+/** see if rrset of type RRSIG contains sig over given type */
+static int
+rrset_has_sigover(ldns_buffer* pkt, struct rrset_parse* rrset, uint16_t type,
+       int* hasother)
+{
+       int res = 0;
+       struct rr_parse* rr = rrset->rr_first;
+       log_assert( htons(rrset->type) == LDNS_RR_TYPE_RRSIG );
+       while(rr) {
+               if(pkt_rrsig_covered_equals(pkt, rr->ttl_data, type))
+                       res = 1;
+               else    *hasother = 1;
+               rr = rr->next;
+       }
+       return res;
+}
+
+/** move rrsigs from sigset to dataset */
+static int
+moveover_rrsigs(ldns_buffer* pkt, region_type* region, 
+       struct rrset_parse* sigset, struct rrset_parse* dataset, int duplicate)
+{
+       struct rr_parse* sig = sigset->rr_first;
+       struct rr_parse* prev = NULL;
+       struct rr_parse* insert;
+       while(sig) {
+               if(pkt_rrsig_covered_equals(pkt, sig->ttl_data, 
+                       dataset->type)) {
+                       if(duplicate) {
+                               /* new */
+                               insert = (struct rr_parse*)region_alloc(region,
+                                       sizeof(struct rr_parse));
+                               insert->ttl_data = sig->ttl_data;
+                               insert->size = sig->size;
+                       } else {
+                               /* remove from sigset */
+                               if(prev) prev->next = sig->next;
+                               else    sigset->rr_first = sig->next;
+                               if(sigset->rr_last == sig)
+                                       sigset->rr_last = prev;
+                               sigset->rr_count--;
+                               sigset->size -= sig->size;
+                               insert = sig;
+                       }
+                       /* add to dataset */
+                       dataset->rrsig_count++;
+                       insert->next = 0;
+                       if(dataset->rrsig_last) 
+                               dataset->rrsig_last->next = insert;
+                       else    dataset->rrsig_first = insert;
+                       dataset->rrsig_last = insert;
+                       dataset->size += insert->size;
+               }
+               prev = sig;
+               sig = sig->next;
+       }
+       return 1;
+}
+
+/** change an rrsig rrset for use as data rrset */
+static struct rrset_parse*
+change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, 
+       ldns_buffer* pkt, uint16_t datatype, uint32_t rrset_flags,
+       int hasother, ldns_pkt_section section, region_type* region)
+{
+       struct rrset_parse* dataset = sigset;
+       hashvalue_t hash = pkt_hash_rrset(pkt, sigset->dname, sigset->type, 
+               sigset->rrset_class, rrset_flags);
+       log_assert( ntohs(sigset->type) == LDNS_RR_TYPE_RRSIG );
+       log_assert( ntohs(datatype) != LDNS_RR_TYPE_RRSIG );
+       if(hasother) {
+               /* need to make new rrset to hold data type */
+               dataset = new_rrset(msg, sigset->dname, sigset->dname_len, 
+                       datatype, sigset->rrset_class, hash, rrset_flags, 
+                       section, region);
+               if(!dataset) 
+                       return NULL;
+               switch(section) {
+                       case LDNS_SECTION_ANSWER: msg->an_rrsets++; break;
+                       case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break;
+                       case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break;
+                       default: log_assert(0);
+               }
+               if(!moveover_rrsigs(pkt, region, sigset, dataset, 
+                       ntohs(msg->qtype) == LDNS_RR_TYPE_RRSIG ||
+                       ntohs(msg->qtype) == LDNS_RR_TYPE_ANY ))
+                       return NULL;
+               return dataset;
+       }
+       /* changeover the type of the rrset to data set */
+       bucket_remove(msg, dataset);
+       /* insert into new hash bucket */
+       dataset->rrset_bucket_next = msg->hashtable[hash&(PARSE_TABLE_SIZE-1)];
+       msg->hashtable[hash&(PARSE_TABLE_SIZE-1)] = dataset;
+       dataset->hash = hash;
+       /* use section of data item for result */
+       change_section(msg, dataset, section);
+       dataset->type = datatype;
+       dataset->flags = rrset_flags;
+       dataset->rrsig_count += dataset->rr_count;
+       dataset->rr_count = 0;
+       /* move sigs to end of siglist */
+       if(dataset->rrsig_last)
+               dataset->rrsig_last->next = dataset->rr_first;
+       else    dataset->rrsig_first = dataset->rr_first;
+       dataset->rrsig_last = dataset->rr_last;
+       return dataset;
+}
+
 /** Find rrset. If equal to previous it is fast. hash if not so.
  * @param msg: the message with hash table.
  * @param pkt: the packet in wireformat (needed for compression ptrs).
@@ -173,16 +412,20 @@ hashtable_lookup(struct msg_parse* msg, ldns_buffer* pkt, hashvalue_t h,
  * @param prev_type: type of last seen RR.
  * @param prev_dclass: class of last seen RR.
  * @param rrset_prev: last seen RRset.
- * @return the rrset if found, or null if no matching rrset exists.
+ * @param section: the current section in the packet.
+ * @param region: used to allocate temporary parsing data.
+ * @return 0 on out of memory.
  */
-static struct rrset_parse*
+static int
 find_rrset(struct msg_parse* msg, ldns_buffer* pkt, uint8_t* dname, 
        size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_t* hash, 
        uint32_t* rrset_flags,
        uint8_t** prev_dname_first, uint8_t** prev_dname_last,
        size_t* prev_dnamelen, uint16_t* prev_type,
-       uint16_t* prev_dclass, struct rrset_parse** rrset_prev)
+       uint16_t* prev_dclass, struct rrset_parse** rrset_prev,
+       ldns_pkt_section section, region_type* region)
 {
+       uint16_t covtype;
        if(rrset_prev) {
                /* check if equal to previous item */
                if(type == *prev_type && dclass == *prev_dclass &&
@@ -191,12 +434,72 @@ find_rrset(struct msg_parse* msg, ldns_buffer* pkt, uint8_t* dname,
                                *prev_dname_last) == 0) {
                        /* same as previous */
                        *prev_dname_last = dname;
-                       return *rrset_prev;
+                       return 1;
+               }
+               /* check if rrsig over previous item */
+               if(ntohs(type) == LDNS_RR_TYPE_RRSIG && 
+                       dclass == *prev_dclass &&
+                       pkt_rrsig_covered_equals(pkt, ldns_buffer_current(pkt),
+                               *prev_type) &&
+                       smart_compare(pkt, dname, *prev_dname_first,
+                               *prev_dname_last) == 0) {
+                       /* covers previous */
+                       *prev_dname_last = dname;
+                       return 1;
                }
-
        }
        /* find by hashing and lookup in hashtable */
-       *hash = pkt_hash_rrset(msg, pkt, dname, type, dclass, rrset_flags);
+       *rrset_flags = pkt_rrset_flags(msg, pkt, type);
+       
+       /* if rrsig - try to lookup matching data set first */
+       if(ntohs(type) == LDNS_RR_TYPE_RRSIG && pkt_rrsig_covered(pkt, 
+               ldns_buffer_current(pkt), &covtype)) {
+               covtype = htons(covtype);
+               *hash = pkt_hash_rrset(pkt, dname, covtype, dclass, 
+                       *rrset_flags);
+               *rrset_prev = hashtable_lookup(msg, pkt, *hash, *rrset_flags, 
+                       dname, dnamelen, covtype, dclass);
+               if(!*rrset_prev && ntohs(covtype) == LDNS_RR_TYPE_NSEC) {
+                       /* if NSEC try with NSEC apex bit twiddled */
+                       *rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX;
+                       *hash = pkt_hash_rrset(pkt, dname, covtype, dclass, 
+                               *rrset_flags);
+                       *rrset_prev = hashtable_lookup(msg, pkt, *hash, 
+                               *rrset_flags, dname, dnamelen, covtype, dclass);
+               }
+               if(*rrset_prev) {
+                       *prev_dname_first = (*rrset_prev)->dname;
+                       *prev_dname_last = dname;
+                       *prev_dnamelen = dnamelen;
+                       *prev_type = covtype;
+                       *prev_dclass = dclass;
+                       return 1;
+               }
+       }
+       if(ntohs(type) != LDNS_RR_TYPE_RRSIG) {
+               int hasother = 0;
+               /* find matching rrsig */
+               *hash = pkt_hash_rrset(pkt, dname, htons(LDNS_RR_TYPE_RRSIG), 
+                       dclass, *rrset_flags);
+               *rrset_prev = hashtable_lookup(msg, pkt, *hash, *rrset_flags, 
+                       dname, dnamelen, htons(LDNS_RR_TYPE_RRSIG), dclass);
+               if(*rrset_prev && rrset_has_sigover(pkt, *rrset_prev, type,
+                       &hasother)) {
+                       /* yes! */
+                       *prev_dname_first = (*rrset_prev)->dname;
+                       *prev_dname_last = dname;
+                       *prev_dnamelen = dnamelen;
+                       *prev_type = type;
+                       *prev_dclass = dclass;
+                       *rrset_prev = change_rrsig_rrset(*rrset_prev, msg, 
+                               pkt, type, *rrset_flags, hasother, section, 
+                               region);
+                       if(!*rrset_prev) return 0;
+                       return 1;
+               }
+       }
+
+       *hash = pkt_hash_rrset(pkt, dname, type, dclass, *rrset_flags);
        *rrset_prev = hashtable_lookup(msg, pkt, *hash, *rrset_flags, 
                dname, dnamelen, type, dclass);
        if(*rrset_prev)
@@ -206,7 +509,7 @@ find_rrset(struct msg_parse* msg, ldns_buffer* pkt, uint8_t* dname,
        *prev_dnamelen = dnamelen;
        *prev_type = type;
        *prev_dclass = dclass;
-       return *rrset_prev;
+       return 1;
 }
 
 /**
@@ -236,40 +539,6 @@ parse_query_section(ldns_buffer* pkt, struct msg_parse* msg)
        return 0;
 }
 
-/**
- * Allocate new rrset in region, fill with data.
- */
-static struct rrset_parse* 
-new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen, 
-       uint16_t type, uint16_t dclass, hashvalue_t hash, 
-       uint32_t rrset_flags, ldns_pkt_section section, region_type* region)
-{
-       struct rrset_parse* p = region_alloc(region, sizeof(*p));
-       if(!p) return NULL;
-       p->rrset_bucket_next = msg->hashtable[hash & (PARSE_TABLE_SIZE-1)];
-       msg->hashtable[hash & (PARSE_TABLE_SIZE-1)] = p;
-       p->rrset_all_next = 0;
-       if(msg->rrset_last)
-               msg->rrset_last->rrset_all_next = p;
-       else    msg->rrset_first = p;
-       msg->rrset_last = p;
-       p->hash = hash;
-       p->section = section;
-       p->dname = dname;
-       p->dname_len = dnamelen;
-       p->type = type;
-       p->rrset_class = dclass;
-       p->flags = rrset_flags;
-       p->rr_count = 0;
-       p->size = 0;
-       p->rr_first = 0;
-       p->rr_last = 0;
-       p->rrsig_count = 0;
-       p->rrsig_first = 0;
-       p->rrsig_last = 0;
-       return p;
-}
-
 size_t
 get_rdf_size(ldns_rdf_type rdf)
 {
@@ -316,7 +585,7 @@ calc_size(ldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
        if(ldns_buffer_remaining(pkt) < pkt_len)
                return 0;
        desc = ldns_rr_descript(type);
-       if(pkt_len > 0 && desc->_dname_count > 0) {
+       if(pkt_len > 0 && desc && desc->_dname_count > 0) {
                int count = (int)desc->_dname_count;
                int rdf = 0;
                size_t len;
@@ -360,44 +629,113 @@ calc_size(ldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
        return 1;
 }
 
+/** skip rr ttl and rdata */
+static int
+skip_ttl_rdata(ldns_buffer* pkt) 
+{
+       uint16_t rdatalen;
+       if(ldns_buffer_remaining(pkt) < 6) /* ttl + rdatalen */
+               return 0;
+       ldns_buffer_skip(pkt, 4); /* ttl */
+       rdatalen = ldns_buffer_read_u16(pkt);
+       if(ldns_buffer_remaining(pkt) < rdatalen)
+               return 0;
+       ldns_buffer_skip(pkt, (ssize_t)rdatalen);
+       return 1;
+}
+
+/** see if RRSIG is a duplicate of another */
+static int
+sig_is_double(ldns_buffer* pkt, struct rrset_parse* rrset, uint8_t* ttldata)
+{
+       uint16_t rlen, siglen;
+       size_t pos = ldns_buffer_position(pkt);
+       struct rr_parse* sig;
+       if(ldns_buffer_remaining(pkt) < 6) 
+               return 0;
+       ldns_buffer_skip(pkt, 4); /* ttl */
+       rlen = ldns_buffer_read_u16(pkt);
+       if(ldns_buffer_remaining(pkt) < rlen) {
+               ldns_buffer_set_position(pkt, pos);
+               return 0;
+       }
+       ldns_buffer_set_position(pkt, pos);
+
+       sig = rrset->rrsig_first;
+       while(sig) {
+               /* check if rdatalen is same */
+               memmove(&siglen, sig->ttl_data+4, sizeof(siglen));
+               siglen = ntohs(siglen);
+               /* checks if data in packet is exactly the same, this means
+                * also dname in rdata is the same, but rrsig is not allowed
+                * to have compressed dnames anyway. If it is compressed anyway
+                * it will lead to duplicate rrs for qtype=RRSIG. (or ANY).
+                *
+                * Cannot use sig->size because size of the other one is not 
+                * calculated yet.
+                */
+               if(siglen == rlen) {
+                       if(siglen>0 && memcmp(sig->ttl_data+6, ttldata+6, 
+                               siglen) == 0) {
+                               /* same! */
+                               return 1;
+                       }
+               }
+               sig = sig->next;
+       }
+       return 0;
+}
 
 /** Add rr (from packet here) to rrset, skips rr */
 static int
 add_rr_to_rrset(struct rrset_parse* rrset, ldns_buffer* pkt, 
-       region_type* region, ldns_pkt_section section)
+       struct msg_parse* msg, region_type* region, 
+       ldns_pkt_section section, uint16_t type)
 {
-       uint16_t rdatalen;
        struct rr_parse* rr;
        /* check section of rrset. */
-       if(rrset->section != section) {
+       if(rrset->section != section && ntohs(type) != LDNS_RR_TYPE_RRSIG &&
+               ntohs(rrset->type) != LDNS_RR_TYPE_RRSIG) {
                /* silently drop it - it is a security problem, since
                 * trust in rr data depends on the section it is in. 
                 * the less trustworthy part is discarded. */
                verbose(VERB_DETAIL, "Packet contains rrset data in "
                        "multiple sections, dropped last part.");
                /* forwards */
-               if(ldns_buffer_remaining(pkt) < 6) /* ttl + rdatalen */
-                       return LDNS_RCODE_FORMERR;
-               ldns_buffer_skip(pkt, 4); /* ttl */
-               rdatalen = ldns_buffer_read_u16(pkt);
-               if(ldns_buffer_remaining(pkt) < rdatalen)
+               if(!skip_ttl_rdata(pkt))
                        return LDNS_RCODE_FORMERR;
-               ldns_buffer_skip(pkt, (ssize_t)rdatalen);
                return 0;
        } 
+
+       if( (ntohs(msg->qtype) == LDNS_RR_TYPE_RRSIG ||
+            ntohs(msg->qtype) == LDNS_RR_TYPE_ANY) 
+           && sig_is_double(pkt, rrset, ldns_buffer_current(pkt))) {
+               if(!skip_ttl_rdata(pkt))
+                       return LDNS_RCODE_FORMERR;
+               return 0;
+       }
+
        /* create rr */
        if(!(rr = (struct rr_parse*)region_alloc(region, sizeof(*rr))))
                return LDNS_RCODE_SERVFAIL;
        rr->ttl_data = ldns_buffer_current(pkt);
        rr->next = 0;
-       if(rrset->rr_last)
-               rrset->rr_last->next = rr;
-       else    rrset->rr_first = rr;
-       rrset->rr_last = rr;
-       rrset->rr_count++;
+       if(ntohs(type) == LDNS_RR_TYPE_RRSIG) {
+               if(rrset->rrsig_last) 
+                       rrset->rrsig_last->next = rr;
+               else    rrset->rrsig_first = rr;
+               rrset->rrsig_last = rr;
+               rrset->rrsig_count++;
+       } else {
+               if(rrset->rr_last)
+                       rrset->rr_last->next = rr;
+               else    rrset->rr_first = rr;
+               rrset->rr_last = rr;
+               rrset->rr_count++;
+       }
 
        /* calc decompressed size */
-       if(!calc_size(pkt, ntohs(rrset->type), rr))
+       if(!calc_size(pkt, ntohs(type), rr))
                return LDNS_RCODE_FORMERR;
        rrset->size += rr->size;
 
@@ -426,7 +764,7 @@ parse_section(ldns_buffer* pkt, struct msg_parse* msg, region_type* region,
        uint16_t dclass, prev_dclass = 0;
        uint32_t rrset_flags = 0;
        hashvalue_t hash = 0;
-       struct rrset_parse* rrset, *rrset_prev = NULL;
+       struct rrset_parse* rrset = NULL;
        int r;
 
        if(num_rrs == 0)
@@ -443,21 +781,37 @@ parse_section(ldns_buffer* pkt, struct msg_parse* msg, region_type* region,
                ldns_buffer_read(pkt, &type, sizeof(type));
                ldns_buffer_read(pkt, &dclass, sizeof(dclass));
 
+               if(0) { /* debug show what is being parsed. */
+                       printf("parse of %s(%d)",
+                               ldns_rr_descript(ntohs(type))?
+                               ldns_rr_descript(ntohs(type))->_name: "??",
+                               (int)ntohs(type));
+                       printf(" %s(%d) ",
+                               ldns_lookup_by_id(ldns_rr_classes, 
+                               (int)ntohs(dclass))?ldns_lookup_by_id(
+                               ldns_rr_classes, (int)ntohs(dclass))->name: 
+                               "??", (int)ntohs(dclass));
+                       dname_print(stdout, pkt, dname);
+                       printf("\n");
+               }
+
                /* see if it is part of an existing RR set */
-               if(!(rrset = find_rrset(msg, pkt, dname, dnamelen, type, dclass,
-                       &hash, &rrset_flags, &prev_dname_f, &prev_dname_l, 
-                       &prev_dnamelen, &prev_type, &prev_dclass, 
-                       &rrset_prev))) {
+               if(!find_rrset(msg, pkt, dname, dnamelen, type, dclass, &hash, 
+                       &rrset_flags, &prev_dname_f, &prev_dname_l, 
+                       &prev_dnamelen, &prev_type, &prev_dclass, &rrset, 
+                       section, region))
+                       return LDNS_RCODE_SERVFAIL;
+               if(!rrset) {
                        /* it is a new RR set. hash&flags already calculated.*/
                        (*num_rrsets)++;
                        rrset = new_rrset(msg, dname, dnamelen, type, dclass,
                                hash, rrset_flags, section, region);
                        if(!rrset) 
                                return LDNS_RCODE_SERVFAIL;
-                       rrset_prev = rrset;
                }
                /* add to rrset. */
-               if((r=add_rr_to_rrset(rrset, pkt, region, section)) != 0)
+               if((r=add_rr_to_rrset(rrset, pkt, msg, region, section, 
+                       type)) != 0)
                        return r;
        }
        return 0;
@@ -495,3 +849,60 @@ parse_packet(ldns_buffer* pkt, struct msg_parse* msg, region_type* region)
        msg->rrset_count = msg->an_rrsets + msg->ns_rrsets + msg->ar_rrsets;
        return 0;
 }
+
+int 
+parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
+{
+       struct rrset_parse* rrset = msg->rrset_first;
+       struct rrset_parse* prev = 0;
+       struct rrset_parse* found = 0;
+       struct rrset_parse* found_prev = 0;
+       /* since the class encodes the UDP size, we cannot use hash table to
+        * find the EDNS OPT record. Scan the packet. */
+       while(rrset) {
+               if(ntohs(rrset->type) == LDNS_RR_TYPE_OPT) {
+                       /* only one OPT RR allowed. */
+                       if(found) return LDNS_RCODE_FORMERR;
+                       /* found it! */
+                       found_prev = prev;
+                       found = rrset;
+               }
+               prev = rrset;
+               rrset = rrset->rrset_all_next;
+       }
+       if(!found) {
+               memset(edns, 0, sizeof(*edns));
+               edns->udp_size = 512;
+               return 0;
+       }
+       /* check the found RRset */
+       /* most lenient check possible. ignore dname, use last opt */
+       if(found->section != LDNS_SECTION_ADDITIONAL)
+               return LDNS_RCODE_FORMERR; 
+       if(found->rr_count == 0)
+               return LDNS_RCODE_FORMERR;
+       if(0) { /* strict checking of dname and RRcount */
+               if(found->dname_len != 1 || !found->dname 
+                       || found->dname[0] != 0) return LDNS_RCODE_FORMERR; 
+               if(found->rr_count != 1) return LDNS_RCODE_FORMERR; 
+       }
+       log_assert(found->rr_first == found->rr_last && found->rr_first);
+
+       /* remove from packet */
+       if(found_prev)  found_prev->rrset_all_next = found->rrset_all_next;
+       else    msg->rrset_first = found->rrset_all_next;
+       if(found == msg->rrset_last)
+               msg->rrset_last = found_prev;
+       msg->arcount --;
+       msg->ar_rrsets --;
+       msg->rrset_count --;
+       
+       /* take the data ! */
+       edns->edns_present = 1;
+       edns->ext_rcode = found->rr_last->ttl_data[0];
+       edns->edns_version = found->rr_last->ttl_data[1];
+       edns->bits = ldns_read_uint16(&found->rr_last->ttl_data[2]);
+       edns->udp_size = ntohs(found->rrset_class);
+       /* ignore rdata and rrsigs */
+       return 0;
+}
index 027b67836b96f19a23219290a174965d435e27de..1dab1ff4f26ead4b4c34454ad43cfcf8511a3c43 100644 (file)
@@ -181,6 +181,26 @@ struct rr_parse {
  * second octets of the compression pointer. */
 #define PTR_OFFSET(x, y) ( ((x)&0x3f)<<8 | (y) )
 
+/** error codes, extended with EDNS, so > 15. */
+#define EDNS_RCODE_BADVERS     16      /** bad EDNS version */
+
+/**
+ * EDNS data storage
+ * EDNS rdata is ignored.
+ */
+struct edns_data {
+       /** if EDNS OPT record was present */
+       int edns_present;
+       /** Extended RCODE */
+       uint8_t ext_rcode;
+       /** The EDNS version number */
+       uint8_t edns_version;
+       /** the EDNS bits field from ttl (host order): Z */
+       uint16_t bits;
+       /** UDP reassembly size. */
+       uint16_t udp_size;
+};
+
 /**
  * Obtain size in the packet of an rr type, that is before dname type.
  * Do TYPE_DNAME, and type STR, yourself. Gives size for most regular types.
@@ -200,4 +220,22 @@ size_t get_rdf_size(ldns_rdf_type rdf);
 int parse_packet(ldns_buffer* pkt, struct msg_parse* msg, 
        struct region* region);
 
+/**
+ * After parsing the packet, extract EDNS data from packet.
+ * If not present this is noted in the data structure.
+ * If a parse error happens, an error code is returned.
+ *
+ * Quirks:
+ *     o ignores OPT rdata.
+ *     o ignores OPT owner name.
+ *     o ignores extra OPT records, except the last one in the packet.
+ *
+ * @param msg: parsed message structure. Modified on exit, if EDNS was present
+ *     it is removed from the additional section.
+ * @param edns: the edns data is stored here. Does not have to be initialised.
+ * @return: 0 on success. or an RCODE on an error.
+ *     RCODE formerr if OPT in wrong section, and so on.
+ */
+int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
+
 #endif /* UTIL_DATA_MSGPARSE_H */
index 9664fab00d03bcec79bdee5aaa31388d861afd5c..3267bc5dc6f0f88fd6902a7defd9a873040ae720 100644 (file)
@@ -121,18 +121,20 @@ parse_alloc_rrset_keys(struct msg_parse* msg, struct reply_info* rep,
 
 /** do the rdata copy */
 static int
-rdata_copy(ldns_buffer* pkt, struct rrset_parse* pset,
-       struct packed_rrset_data* data, uint8_t* to, struct rr_parse* rr)
+rdata_copy(ldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 
+       struct rr_parse* rr, uint32_t* rr_ttl, uint16_t type)
 {
        uint16_t pkt_len;
-       uint32_t ttl;
        const ldns_rr_descriptor* desc;
        ldns_buffer_set_position(pkt, (size_t)
                (rr->ttl_data - ldns_buffer_begin(pkt)));
        log_assert(ldns_buffer_remaining(pkt) >= 6 /* ttl + rdatalen */);
-       ttl = ldns_buffer_read_u32(pkt);
-       if(ttl < data->ttl)
-               data->ttl = ttl;
+       *rr_ttl = ldns_buffer_read_u32(pkt);
+       /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
+       if(*rr_ttl & 0x80000000U)
+               *rr_ttl = 0;
+       if(*rr_ttl < data->ttl)
+               data->ttl = *rr_ttl;
        /* insert decompressed size into rdata len stored in memory */
        /* -2 because rdatalen bytes are not included. */
        pkt_len = htons(rr->size - 2);
@@ -143,8 +145,8 @@ rdata_copy(ldns_buffer* pkt, struct rrset_parse* pset,
        if(ldns_buffer_remaining(pkt) < pkt_len)
                return 0;
        log_assert((size_t)pkt_len+2 <= rr->size);
-       desc = ldns_rr_descript(ntohs(pset->type));
-       if(pkt_len > 0 && desc->_dname_count > 0) {
+       desc = ldns_rr_descript(type);
+       if(pkt_len > 0 && desc && desc->_dname_count > 0) {
                int count = (int)desc->_dname_count;
                int rdf = 0;
                size_t len;
@@ -193,23 +195,36 @@ parse_rr_copy(ldns_buffer* pkt, struct rrset_parse* pset,
        size_t i;
        struct rr_parse* rr = pset->rr_first;
        uint8_t* nextrdata;
+       size_t total = pset->rr_count + pset->rrsig_count;
        data->ttl = MAX_TTL;
        data->count = pset->rr_count;
+       data->rrsig_count = pset->rrsig_count;
        /* layout: struct - rr_len - rr_data - rdata - rrsig */
        data->rr_len = (size_t*)((uint8_t*)data + 
                sizeof(struct packed_rrset_data));
-       data->rr_data = (uint8_t**)&(data->rr_len[data->count]);
-       nextrdata = (uint8_t*)&(data->rr_data[data->count]);
-       data->rrsig_count = 0;
+       data->rr_ttl = (uint32_t*)&(data->rr_len[total]);
+       data->rr_data = (uint8_t**)&(data->rr_ttl[total]);
+       nextrdata = (uint8_t*)&(data->rr_data[total]);
        for(i=0; i<data->count; i++) {
                data->rr_len[i] = rr->size;
                data->rr_data[i] = nextrdata;
                nextrdata += rr->size;
-               if(!rdata_copy(pkt, pset, data, data->rr_data[i], rr))
+               if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
+                       &data->rr_ttl[i], ntohs(pset->type)))
                        return 0;
                rr = rr->next;
        }
        /* if rrsig, its rdata is at nextrdata */
+       rr = pset->rrsig_first;
+       for(i=data->count; i<total; i++) {
+               data->rr_len[i] = rr->size;
+               data->rr_data[i] = nextrdata;
+               nextrdata += rr->size;
+               if(!rdata_copy(pkt, data, data->rr_data[i], rr, 
+                       &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG))
+                       return 0;
+               rr = rr->next;
+       }
        return 1;
 }
 
@@ -219,7 +234,8 @@ parse_create_rrset(ldns_buffer* pkt, struct rrset_parse* pset,
        struct packed_rrset_data** data)
 {
        /* allocate */
-       *data = malloc(sizeof(struct packed_rrset_data) + pset->rr_count* 
+       *data = malloc(sizeof(struct packed_rrset_data) + 
+               (pset->rr_count + pset->rrsig_count) * 
                (sizeof(size_t)+sizeof(uint8_t*)+sizeof(uint32_t)) + 
                pset->size);
        if(!*data)
@@ -468,29 +484,74 @@ reply_info_answer(struct reply_info* rep, uint16_t qflags,
        ldns_buffer_flip(buffer);
 }
 
+/** bake a new type-class-ttl value, or 0 on malloc error */
+static uint32_t*
+bake_tcttl(int do_sig, region_type* region, 
+       struct packed_rrset_key* rk, uint32_t ttl, uint32_t timenow)
+{
+       /* type, class, ttl,
+          type-class-ttl used for rrsigs.
+          ttl used for data itself. */
+       uint32_t* t;
+       if(do_sig) {
+               t =  (uint32_t*)region_alloc(region, 2*sizeof(uint32_t));
+               if(!t) return 0;
+               ((uint16_t*)t)[0] = htons(LDNS_RR_TYPE_RRSIG);
+               memcpy( &(((uint16_t*)t)[1]), &(rk->dname[rk->dname_len+2]),
+                       sizeof(uint16_t));
+               t[1] = htonl(ttl - timenow);
+       } else {
+               t =  (uint32_t*)region_alloc(region, sizeof(uint32_t));
+               if(!t) return 0;
+               t[0] = htonl(ttl - timenow);
+       }
+       return t;
+}
+
 /** store rrset in iov vector */
 static int
 packed_rrset_iov(struct ub_packed_rrset_key* key, struct iovec* iov, 
        size_t max, uint16_t* num_rrs, uint32_t timenow, region_type* region,
-       size_t* used)
+       size_t* used, int do_data, int do_sig)
 {
        size_t i;
-       uint32_t* ttl = (uint32_t*)region_alloc(region, sizeof(uint32_t));
+       uint32_t* tcttl;
        struct packed_rrset_data* data = (struct packed_rrset_data*)
                key->entry.data;
-       *num_rrs += data->count;
-       if(!ttl) return 0;
-       *ttl = htonl(data->ttl - timenow);
-       for(i=0; i<data->count; i++) {
-               if(max - *used < 3) return 0;
-               /* no compression of dnames yet */
-               iov[*used].iov_base = (void*)key->rk.dname;
-               iov[*used].iov_len = key->rk.dname_len + 4;
-               iov[*used+1].iov_base = (void*)ttl;
-               iov[*used+1].iov_len = sizeof(uint32_t);
-               iov[*used+2].iov_base = (void*)data->rr_data[i];
-               iov[*used+2].iov_len = data->rr_len[i];
-               *used += 3;
+       if(do_data) {
+               *num_rrs += data->count;
+               for(i=0; i<data->count; i++) {
+                       if(max - *used < 3) return 0;
+                       if(!(tcttl = bake_tcttl(0, region, &key->rk, 
+                               data->rr_ttl[i], timenow)))
+                               return 0;
+                       /* no compression of dnames yet */
+                       iov[*used].iov_base = (void*)key->rk.dname;
+                       iov[*used].iov_len = key->rk.dname_len + 4;
+                       iov[*used+1].iov_base = (void*)tcttl;
+                       iov[*used+1].iov_len = sizeof(uint32_t);
+                       iov[*used+2].iov_base = (void*)data->rr_data[i];
+                       iov[*used+2].iov_len = data->rr_len[i];
+                       *used += 3;
+               }
+       }
+       /* insert rrsigs */
+       if(do_sig) {
+               *num_rrs += data->rrsig_count;
+               for(i=0; i<data->rrsig_count; i++) {
+                       if(max - *used < 3) return 0;
+                       if(!(tcttl = bake_tcttl(1, region, &key->rk, 
+                               data->rr_ttl[data->count+i], timenow)))
+                               return 0;
+                       /* no compression of dnames yet */
+                       iov[*used].iov_base = (void*)key->rk.dname;
+                       iov[*used].iov_len = key->rk.dname_len;
+                       iov[*used+1].iov_base = (void*)tcttl;
+                       iov[*used+1].iov_len = sizeof(uint32_t)*2;
+                       iov[*used+2].iov_base = (void*)data->rr_data[data->count+i];
+                       iov[*used+2].iov_len = data->rr_len[data->count+i];
+                       *used += 3;
+               }
        }
 
        return 1;
@@ -500,13 +561,23 @@ packed_rrset_iov(struct ub_packed_rrset_key* key, struct iovec* iov,
 static int
 insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
        struct iovec* iov, size_t max, size_t rrsets_before,
-       uint32_t timenow, region_type* region, size_t* used)
+       uint32_t timenow, region_type* region, size_t* used, int addit)
 {
        size_t i;
        *num_rrs = 0;
-       for(i=0; i<num_rrsets; i++) {
-               if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], iov,
-                       max, num_rrs, timenow, region, used))
+       if(!addit) {
+               for(i=0; i<num_rrsets; i++)
+                       if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], iov,
+                               max, num_rrs, timenow, region, used, 1, 1))
+                       return 0;
+       } else {
+               for(i=0; i<num_rrsets; i++)
+                       if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], iov,
+                               max, num_rrs, timenow, region, used, 1, 0))
+                       return 0;
+               for(i=0; i<num_rrsets; i++)
+                       if(!packed_rrset_iov(rep->rrsets[rrsets_before+i], iov,
+                               max, num_rrs, timenow, region, used, 0, 1))
                        return 0;
        }
        *num_rrs = htons(*num_rrs);
@@ -547,17 +618,18 @@ size_t reply_info_iov_regen(struct query_info* qinfo, struct reply_info* rep,
 
        /* insert answer section */
        if(!insert_section(rep, rep->an_numrrsets, &hdr[3], iov, max, 
-               0, timenow, region, &used))
+               0, timenow, region, &used, 0))
                return 0;
 
        /* insert auth section */
        if(!insert_section(rep, rep->ns_numrrsets, &hdr[4], iov, max, 
-               rep->an_numrrsets, timenow, region, &used))
+               rep->an_numrrsets, timenow, region, &used, 0))
                return 0;
 
        /* insert add section */
        if(!insert_section(rep, rep->ar_numrrsets, &hdr[5], iov, max, 
-               rep->an_numrrsets + rep->ns_numrrsets, timenow, region, &used))
+               rep->an_numrrsets + rep->ns_numrrsets, timenow, region, 
+               &used, 1))
                return 0;
 
        return used;
index dfa5b7758b74fe9df40c6d15c055e6deb9858cd3..41f2bf267b3ea12deaca462fb0df3e745c899d16 100644 (file)
@@ -114,6 +114,7 @@ struct ub_packed_rrset_key {
  * memory layout:
  *     o base struct
  *     o rr_len size_t array
+ *     o rr_ttl uint32_t array
  *     o rr_data uint8_t* array
  *     o rr_data rdata wireformats
  *     o rrsig_data rdata wireformat(s)
@@ -144,6 +145,8 @@ struct packed_rrset_data {
        size_t rrsig_count;
        /** length of every rr's rdata, rr_len[i] is size of rr_data[i]. */
        size_t* rr_len;
+       /** ttl of every rr. rr_ttl[i] ttl of rr i. */
+       uint32_t *rr_ttl;
        /** 
         * Array of pointers to every rr's rdata. 
         * The rr_data[i] rdata is stored in uncompressed wireformat. 
index 9eb598d0cf908f23862628c70cbd6301fdebbba9..c9bfdd60aab4034e9cb6a8fb3bd5666827ee118c 100644 (file)
@@ -44,7 +44,7 @@
 #include <time.h>
 #endif
 
-enum verbosity_value verbosity = 4;
+enum verbosity_value verbosity = 0;
 /** the file logged to. */
 static FILE* logfile = 0;
 /** if key has been created */