From ae30307d6d99c898859637fda2c670095a94f59a Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Tue, 17 Apr 2007 09:14:45 +0000 Subject: [PATCH] copy and decompress. git-svn-id: file:///svn/unbound/trunk@242 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 3 + util/data/msgreply.c | 191 ++++++++++++++++++++++++++++++++------- util/data/packed_rrset.h | 1 - 3 files changed, 162 insertions(+), 33 deletions(-) diff --git a/doc/Changelog b/doc/Changelog index cd97c86de..d68cf5bbc 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +17 April 2007: Wouter + - copy and decompress dnames. + 16 April 2007: Wouter - following a small change in LDNS, parsing code calculates the memory size to allocate for rrs. diff --git a/util/data/msgreply.c b/util/data/msgreply.c index f8d8918ba..a02dbd2e3 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -54,6 +54,8 @@ struct rr_parse; /** number of buckets in parse rrset hash table. Must be power of 2. */ #define PARSE_TABLE_SIZE 1024 +/** Maximum TTL that is allowed. */ +#define MAX_TTL 3600*24*365*10 /* ten years */ /** * Data stored in scratch pad memory during parsing. @@ -593,6 +595,46 @@ parse_alloc_rrset_keys(struct msg_parse* msg, struct reply_info* rep, return 1; } +/** + * Obtain size in the packet of an rr type, that is before dname type. + * Do TYPE_DNAME, and type STR, yourself. + * @param rdf: the rdf type from the descriptor. + * @return: size in octets. 0 on failure. + */ +static size_t +get_rdf_size(ldns_rdf_type rdf) +{ + switch(rdf) { + case LDNS_RDF_TYPE_CLASS: + case LDNS_RDF_TYPE_ALG: + case LDNS_RDF_TYPE_INT8: + return 1; + break; + case LDNS_RDF_TYPE_INT16: + case LDNS_RDF_TYPE_TYPE: + case LDNS_RDF_TYPE_CERT_ALG: + return 2; + break; + case LDNS_RDF_TYPE_INT32: + case LDNS_RDF_TYPE_TIME: + case LDNS_RDF_TYPE_A: + case LDNS_RDF_TYPE_PERIOD: + return 4; + break; + case LDNS_RDF_TYPE_TSIGTIME: + return 6; + break; + case LDNS_RDF_TYPE_AAAA: + return 16; + break; + default: + log_assert(false); /* add type above */ + /* only types that appear before a domain * + * name are needed. rest is simply copied. */ + } + return 0; +} + /** calculate the size of one rr */ static int calc_size(ldns_buffer* pkt, uint16_t type, struct rr_parse* rr) @@ -610,51 +652,36 @@ calc_size(ldns_buffer* pkt, uint16_t type, struct rr_parse* rr) int count = (int)desc->_dname_count; int rdf = 0; size_t len; + size_t oldpos; /* skip first part. */ while(count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: /* decompress every domain name */ + oldpos = ldns_buffer_position(pkt); if((len = pkt_dname_len(pkt)) == 0) - return 0; + return 0; /* malformed dname */ + if(ldns_buffer_position(pkt)-oldpos > pkt_len) + return 0; /* dname exceeds rdata */ + pkt_len -= ldns_buffer_position(pkt)-oldpos; rr->size += len; count--; + len = 0; break; case LDNS_RDF_TYPE_STR: + if(pkt_len < 1) + return 0; /* len byte exceeds rdata */ len = ldns_buffer_current(pkt)[0] + 1; - rr->size += len; - ldns_buffer_skip(pkt, (ssize_t)len); - break; - case LDNS_RDF_TYPE_CLASS: - case LDNS_RDF_TYPE_ALG: - case LDNS_RDF_TYPE_INT8: - ldns_buffer_skip(pkt, 1); - rr->size += 1; - break; - case LDNS_RDF_TYPE_INT16: - case LDNS_RDF_TYPE_TYPE: - case LDNS_RDF_TYPE_CERT_ALG: - ldns_buffer_skip(pkt, 2); - rr->size += 2; break; - case LDNS_RDF_TYPE_INT32: - case LDNS_RDF_TYPE_TIME: - case LDNS_RDF_TYPE_A: - case LDNS_RDF_TYPE_PERIOD: - ldns_buffer_skip(pkt, 4); - rr->size += 4; - break; - case LDNS_RDF_TYPE_TSIGTIME: - ldns_buffer_skip(pkt, 6); - rr->size += 6; - break; - case LDNS_RDF_TYPE_AAAA: - ldns_buffer_skip(pkt, 16); - rr->size += 16; default: - log_assert(false); /* add type above */ - /* only types that appear before a domain * - * name are needed. rest is simply copied. */ + len = get_rdf_size(desc->_wireformat[rdf]); + } + if(len) { + if(pkt_len < len) + return 0; /* exceeds rdata */ + pkt_len -= len; + ldns_buffer_skip(pkt, (ssize_t)len); + rr->size += len; } rdf++; } @@ -670,12 +697,109 @@ parse_rr_size(ldns_buffer* pkt, struct rrset_parse* pset, size_t* allocsize) { struct rr_parse* p = pset->rr_first; *allocsize = 0; + /* size of rrs */ while(p) { if(!calc_size(pkt, ntohs(pset->type), p)) return 0; *allocsize += p->size; p = p->next; } + /* TODO calc size of rrsig */ + return 1; +} + +/** 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) +{ + 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))); + if(ldns_buffer_remaining(pkt) < 6) + return 0; + ttl = ldns_buffer_read_u32(pkt); + if(ttl < data->ttl) + data->ttl = ttl; + /* insert decompressed size into memory rdata len */ + pkt_len = htons(rr->size); + memmove(to, &pkt_len, sizeof(uint16_t)); + to += 2; + /* read packet rdata len */ + pkt_len = ldns_buffer_read_u16(pkt); + 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(desc->_dname_count > 0) { + int count = (int)desc->_dname_count; + int rdf = 0; + size_t len; + size_t oldpos; + /* decompress dnames. */ + while(count) { + switch(desc->_wireformat[rdf]) { + case LDNS_RDF_TYPE_DNAME: + oldpos = ldns_buffer_position(pkt); + dname_pkt_copy(pkt, to, + ldns_buffer_current(pkt)); + to += pkt_dname_len(pkt); + pkt_len -= ldns_buffer_position(pkt)-oldpos; + count--; + len = 0; + break; + case LDNS_RDF_TYPE_STR: + len = ldns_buffer_current(pkt)[0] + 1; + break; + default: + len = get_rdf_size(desc->_wireformat[rdf]); + break; + } + if(len) { + memmove(to, ldns_buffer_current(pkt), len); + to += len; + ldns_buffer_skip(pkt, (ssize_t)len); + log_assert(len <= pkt_len); + pkt_len -= len; + } + rdf++; + } + } + /* copy remaining rdata */ + if(pkt_len > 0) + memmove(to, ldns_buffer_current(pkt), pkt_len); + + return 1; +} + +/** copy over the data into packed rrset */ +static int +parse_rr_copy(ldns_buffer* pkt, struct rrset_parse* pset, + struct packed_rrset_data* data) +{ + size_t i; + struct rr_parse* rr = pset->rr_first; + uint8_t* nextrdata; + data->ttl = MAX_TTL; + data->count = pset->rr_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_data = 0; + data->rrsig_len = 0; + for(i=0; icount; 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)) + return 0; + rr = rr->next; + } + /* if rrsig, its rdata is at nextrdata */ return 1; } @@ -693,6 +817,9 @@ parse_create_rrset(ldns_buffer* pkt, struct rrset_parse* pset, (sizeof(size_t)+sizeof(uint8_t*)+sizeof(uint32_t)) + allocsize); if(!*data) return LDNS_RCODE_SERVFAIL; + /* copy & decompress */ + if(!parse_rr_copy(pkt, pset, *data)) + return LDNS_RCODE_SERVFAIL; return 0; } diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index 8291767c7..549a75643 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -115,7 +115,6 @@ struct ub_packed_rrset_key { * o base struct * o rr_len size_t array * o rr_data uint8_t* array - * o rr_ttl uint32_t array * o rr_data rdata wireformats * o rrsig_data rdata wireformat * -- 2.47.2