Nicer encoding. fixes.

git-svn-id: file:///svn/unbound/trunk@379 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-06-11 10:12:43 +00:00
parent d43a081730
commit c8b71a8b1e
10 changed files with 87 additions and 30 deletions

View file

@ -503,7 +503,7 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id,
/* locked and ids and ttls are OK. */
if(!reply_info_answer_encode(&mrentry->key, rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns)) {
udpsize, edns, (int)(edns->bits & EDNS_DO) )) {
replyerror_fillbuf(LDNS_RCODE_SERVFAIL, repinfo, id,
flags, &mrentry->key);
}
@ -529,12 +529,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
struct work_query* w;
struct edns_data edns;
verbose(VERB_DETAIL, "worker handle request");
if(error != NETEVENT_NOERROR) {
log_err("called with err=%d", error);
log_err("handle request called with err=%d", error);
return 0;
}
if((ret=worker_check_request(c->buffer)) != 0) {
verbose(VERB_ALGO, "worker check request: bad query.");
if(ret != -1) {
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
@ -546,6 +546,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->stats.num_queries++;
/* see if query is in the cache */
if(!query_info_parse(&qinfo, c->buffer)) {
verbose(VERB_ALGO, "worker parse request: formerror.");
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
@ -553,6 +554,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
h = query_info_hash(&qinfo);
if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
verbose(VERB_ALGO, "worker parse edns: formerror.");
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
return 1;
@ -562,6 +564,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
edns.edns_version = EDNS_ADVERTISED_VERSION;
edns.udp_size = EDNS_ADVERTISED_SIZE;
edns.bits &= EDNS_DO;
verbose(VERB_ALGO, "query with bad edns version.");
replyerror_fillbuf(EDNS_RCODE_BADVERS&0xf, repinfo,
*(uint16_t*)ldns_buffer_begin(c->buffer),
ldns_buffer_read_u16_at(c->buffer, 2), &qinfo);
@ -572,7 +575,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
edns.udp_size = 65535; /* max size for TCP replies */
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */
verbose(VERB_DETAIL, "answer from the cache");
if(answer_from_cache(worker, e,
*(uint16_t*)ldns_buffer_begin(c->buffer),
ldns_buffer_read_u16_at(c->buffer, 2), repinfo,

View file

@ -1,3 +1,13 @@
11 June 2007: Wouter
- replies on TCP queries have the address field set in replyinfo,
for serviced queries, because the initiator does not know that
a TCP fallback has occured.
- omit DNSSEC types from nonDO replies, except if qtype is ANY or
if qtype directly queries for the type (and then only show that
'unknown type' in the answer section).
- fixed message parsing where rrsigs on their own would be put
in the signature list over the rrsig type.
7 June 2007: Wouter
- fixup error in double linked list insertion for subqueries and
for outbound list of serviced queries for iterator module.

View file

@ -163,7 +163,8 @@ iter_handlereply(struct module_qstate* qstate, int id,
qstate->edns.bits &= EDNS_DO;
if(!reply_info_answer_encode(&reply_qinfo, reply_msg, 0,
qstate->query_flags, qstate->buf, 0, 0,
qstate->scratch, us, &qstate->edns))
qstate->scratch, us, &qstate->edns,
(int)(qstate->edns.bits&EDNS_DO)))
return 0;
dns_cache_store_msg(qstate->env, &reply_qinfo, qstate->query_hash,
reply_msg);
@ -344,7 +345,7 @@ iter_encode_respmsg(struct module_qstate* qstate, struct iter_qstate* iq,
edns.bits = qstate->edns.bits & EDNS_DO;
if(!reply_info_answer_encode(&qinf, msg->rep, 0, iq->orig_qflags,
qstate->buf, 0, 1, qstate->scratch, qstate->edns.udp_size,
&edns)) {
&edns, (int)(qstate->edns.bits & EDNS_DO))) {
/* encode servfail */
error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return;

View file

@ -1017,7 +1017,9 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
serviced_tcp_initiate(sq->outnet, sq, c->buffer);
return 0;
}
/* insert address into reply info */
memcpy(&rep->addr, &sq->addr, sq->addrlen);
rep->addrlen = sq->addrlen;
(void)rbtree_delete(sq->outnet->serviced, sq);
serviced_callbacks(sq, error, c, rep);
serviced_delete(sq);

View file

@ -270,7 +270,7 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
} else {
const size_t lim = 512;
ret = reply_info_encode(&qi, rep, id, flags, out, timenow,
region, 65535);
region, 65535, (int)(edns.bits & EDNS_DO) );
unit_assert(ret != 0); /* udp packets should fit */
attach_edns_record(out, &edns);
if(vbmp) printf("inlen %u outlen %u\n",
@ -281,7 +281,8 @@ testpkt(ldns_buffer* pkt, struct alloc_cache* alloc, ldns_buffer* out,
if(ldns_buffer_limit(out) > lim) {
ret = reply_info_encode(&qi, rep, id, flags, out,
timenow, region,
lim - calc_edns_field_size(&edns));
lim - calc_edns_field_size(&edns),
(int)(edns.bits & EDNS_DO));
unit_assert(ret != 0); /* should fit, but with TC */
attach_edns_record(out, &edns);
if( LDNS_QDCOUNT(ldns_buffer_begin(out)) !=

View file

@ -413,17 +413,49 @@ compress_rdata(ldns_buffer* pkt, uint8_t* rdata, size_t todolen,
return RETVAL_OK;
}
/** Returns true if RR type should be included */
static int
rrset_belongs_in_reply(ldns_pkt_section s, uint16_t rrtype, uint16_t qtype,
int dnssec)
{
if(dnssec)
return 1;
/* skip non DNSSEC types, except if directly queried for */
if(s == LDNS_SECTION_ANSWER) {
if(qtype == LDNS_RR_TYPE_ANY || qtype == rrtype)
return 1;
}
/* check DNSSEC-ness */
switch(rrtype) {
case LDNS_RR_TYPE_SIG:
case LDNS_RR_TYPE_KEY:
case LDNS_RR_TYPE_NXT:
case LDNS_RR_TYPE_DS:
case LDNS_RR_TYPE_RRSIG:
case LDNS_RR_TYPE_NSEC:
case LDNS_RR_TYPE_DNSKEY:
/* FIXME: include NSEC3 here. */
return 0;
}
return 1;
}
/** store rrset in buffer in wireformat, return RETVAL_* */
static int
packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt,
uint16_t* num_rrs, uint32_t timenow, region_type* region,
int do_data, int do_sig, struct compress_tree_node** tree)
int do_data, int do_sig, struct compress_tree_node** tree,
ldns_pkt_section s, uint16_t qtype, int dnssec)
{
size_t i, owner_pos;
int r, owner_labs;
uint16_t owner_ptr = 0;
struct packed_rrset_data* data = (struct packed_rrset_data*)
key->entry.data;
/* does this RR type belong in the answer? */
if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec))
return RETVAL_OK;
owner_labs = dname_count_labels(key->rk.dname);
owner_pos = ldns_buffer_position(pkt);
@ -452,7 +484,7 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt,
}
}
/* insert rrsigs */
if(do_sig) {
if(do_sig && dnssec) {
size_t total = data->count+data->rrsig_count;
for(i=data->count; i<total; i++) {
if(owner_ptr && owner_labs != 1) {
@ -481,7 +513,7 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt,
/* change rrnum only after we are sure it fits */
if(do_data)
*num_rrs += data->count;
if(do_sig)
if(do_sig && dnssec)
*num_rrs += data->rrsig_count;
return RETVAL_OK;
@ -491,16 +523,18 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt,
static int
insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
ldns_buffer* pkt, size_t rrsets_before, uint32_t timenow,
region_type* region, int addit, struct compress_tree_node** tree)
region_type* region, struct compress_tree_node** tree,
ldns_pkt_section s, uint16_t qtype, int dnssec)
{
int r;
size_t i, setstart;
*num_rrs = 0;
if(!addit) {
if(s != LDNS_SECTION_ADDITIONAL) {
for(i=0; i<num_rrsets; i++) {
setstart = ldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 1, 1, tree))
pkt, num_rrs, timenow, region, 1, 1, tree,
s, qtype, dnssec))
!= RETVAL_OK) {
/* Bad, but if due to size must set TC bit */
/* trim off the rrset neatly. */
@ -512,28 +546,31 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
for(i=0; i<num_rrsets; i++) {
setstart = ldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 1, 0, tree))
pkt, num_rrs, timenow, region, 1, 0, tree,
s, qtype, dnssec))
!= RETVAL_OK) {
ldns_buffer_set_position(pkt, setstart);
return r;
}
}
for(i=0; i<num_rrsets; i++) {
if(dnssec)
for(i=0; i<num_rrsets; i++) {
setstart = ldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 0, 1, tree))
pkt, num_rrs, timenow, region, 0, 1, tree,
s, qtype, dnssec))
!= RETVAL_OK) {
ldns_buffer_set_position(pkt, setstart);
return r;
}
}
}
}
return RETVAL_OK;
}
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
region_type* region, uint16_t udpsize)
region_type* region, uint16_t udpsize, int dnssec)
{
uint16_t ancount=0, nscount=0, arcount=0;
struct compress_tree_node* tree = 0;
@ -567,7 +604,8 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
/* insert answer section */
if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
0, timenow, region, 0, &tree)) != RETVAL_OK) {
0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
dnssec)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
ldns_buffer_write_u16_at(buffer, 6, ancount);
@ -581,7 +619,8 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
/* insert auth section */
if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
rep->an_numrrsets, timenow, region, 0, &tree)) != RETVAL_OK) {
rep->an_numrrsets, timenow, region, &tree,
LDNS_SECTION_AUTHORITY, qinfo->qtype, dnssec)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
ldns_buffer_write_u16_at(buffer, 8, nscount);
@ -596,7 +635,8 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
/* insert add section */
if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
1, &tree)) != RETVAL_OK) {
&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
dnssec)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* no need to set TC bit, this is the additional */
ldns_buffer_write_u16_at(buffer, 10, arcount);
@ -646,7 +686,7 @@ int
reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow,
int cached, struct region* region, uint16_t udpsize,
struct edns_data* edns)
struct edns_data* edns, int dnssec)
{
uint16_t flags;
@ -662,7 +702,7 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
return 0; /* packet too small to contain edns... */
udpsize -= calc_edns_field_size(edns);
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
udpsize)) {
udpsize, dnssec)) {
log_err("reply encode: out of memory");
return 0;
}

View file

@ -61,12 +61,13 @@ struct edns_data;
* @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
* @param edns: EDNS data included in the answer, NULL for none.
* or if edns_present = 0, it is not included.
* @param dnssec: if 0 DNSSEC records are omitted from the answer.
* @return: 0 on error (server failure).
*/
int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, ldns_buffer* dest, uint32_t timenow,
int cached, struct region* region, uint16_t udpsize,
struct edns_data* edns);
struct edns_data* edns, int dnssec);
/**
* Regenerate the wireformat from the stored msg reply.
@ -81,12 +82,13 @@ int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
* @param timenow: time now, to adjust ttl values.
* @param region: to store temporary data in.
* @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
* @param dnssec: if 0 DNSSEC records are omitted from the answer.
* @return: nonzero is success, or
* 0 on error: malloc failure (no log_err has been done).
*/
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
struct region* region, uint16_t udpsize);
struct region* region, uint16_t udpsize, int dnssec);
/**
* Encode query packet. Assumes the buffer is large enough.

View file

@ -720,7 +720,7 @@ add_rr_to_rrset(struct rrset_parse* rrset, ldns_buffer* pkt,
return LDNS_RCODE_SERVFAIL;
rr->ttl_data = ldns_buffer_current(pkt);
rr->next = 0;
if(type == LDNS_RR_TYPE_RRSIG) {
if(type == LDNS_RR_TYPE_RRSIG && rrset->type != LDNS_RR_TYPE_RRSIG) {
if(rrset->rrsig_last)
rrset->rrsig_last->next = rr;
else rrset->rrsig_first = rr;

View file

@ -659,7 +659,7 @@ log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
ldns_buffer* buf = ldns_buffer_new(65535);
struct region* region = region_create(malloc, free);
if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0,
region, 65535)) {
region, 65535, 1)) {
log_info("%s: log_dns_msg: out of memory", str);
} else {
ldns_status s;

View file

@ -231,7 +231,6 @@ comm_point_udp_callback(int fd, short event, void* arg)
rep.c = (struct comm_point*)arg;
log_assert(rep.c->type == comm_udp);
verbose(VERB_ALGO, "callback udp");
if(!(event&EV_READ))
return;
log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);