mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-31 20:09:35 -05:00
RRSIG parsing and outputting.
git-svn-id: file:///svn/unbound/trunk@255 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
2d53f65c92
commit
add942bd40
9 changed files with 724 additions and 117 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
if(!skip_ttl_rdata(pkt))
|
||||
return LDNS_RCODE_FORMERR;
|
||||
ldns_buffer_skip(pkt, 4); /* ttl */
|
||||
rdatalen = ldns_buffer_read_u16(pkt);
|
||||
if(ldns_buffer_remaining(pkt) < rdatalen)
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue