From: Wouter Wijngaards Date: Tue, 19 Jun 2007 13:50:43 +0000 (+0000) Subject: fix of flags in errors and very short bufsizes from edns. X-Git-Tag: release-0.4~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f16769aa3b971443a46456887c5702e8a7b8477;p=thirdparty%2Funbound.git fix of flags in errors and very short bufsizes from edns. git-svn-id: file:///svn/unbound/trunk@397 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/worker.c b/daemon/worker.c index 506752bc1..671af29d1 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -157,7 +157,7 @@ replyerror_fillbuf(int r, struct comm_reply* repinfo, uint16_t id, ldns_buffer_clear(buf); ldns_buffer_write(buf, &id, sizeof(uint16_t)); - flags = (uint16_t)(BIT_QR | r); /* QR and retcode*/ + flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/ flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ ldns_buffer_write_u16(buf, flags); flags = 1; @@ -571,6 +571,16 @@ worker_handle_request(struct comm_point* c, void* arg, int error, attach_edns_record(c->buffer, &edns); return 1; } + if(edns.edns_present && edns.udp_size < LDNS_HEADER_SIZE) { + verbose(VERB_ALGO, "worker request: edns is too small."); + LDNS_QR_SET(ldns_buffer_begin(c->buffer)); + LDNS_TC_SET(ldns_buffer_begin(c->buffer)); + LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), + LDNS_RCODE_SERVFAIL); + ldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); + ldns_buffer_flip(c->buffer); + return 1; + } if(c->type != comm_udp) edns.udp_size = 65535; /* max size for TCP replies */ if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) { diff --git a/doc/Changelog b/doc/Changelog index 86744a85d..c14419a94 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -6,6 +6,9 @@ - target-fetch-policy: "3 2 1 0 0" config setting. - fixup queries answered without RD bit (for root prime results). - refuse AXFR and IXFR requests. + - fixup RD flag in error reply from iterator. fixup RA flag from + worker error reply. + - fixup encoding of very short edns buffer sizes, now sets TC bit. 18 June 2007: Wouter - same, move subqueries to slumber list when first has resolved. diff --git a/iterator/iterator.c b/iterator/iterator.c index 6f7e0f305..0ebdf660d 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -255,10 +255,12 @@ error_response(struct module_qstate* qstate, int id, int rcode) verbose(VERB_DETAIL, "return error response %s", ldns_lookup_by_id(ldns_rcodes, rcode)? ldns_lookup_by_id(ldns_rcodes, rcode)->name:"??"); - if(iq && iq->orig_qname) { - /* encode original query */ - qstate->qinfo.qname = iq->orig_qname; - qstate->qinfo.qname_len = iq->orig_qnamelen; + if(iq) { + if(iq->orig_qname) { + /* encode original query */ + qstate->qinfo.qname = iq->orig_qname; + qstate->qinfo.qname_len = iq->orig_qnamelen; + } qstate->query_flags = iq->orig_qflags; } qinfo_query_encode(qstate->buf, &qstate->qinfo); diff --git a/util/data/msgencode.c b/util/data/msgencode.c index fb6a68f78..0add5fd43 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -568,7 +568,26 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, return RETVAL_OK; } -int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, +/** store query section in wireformat buffer, return RETVAL */ +static int +insert_query(struct query_info* qinfo, struct compress_tree_node* tree, + ldns_buffer* buffer, struct region* region) +{ + if(ldns_buffer_remaining(buffer) < + qinfo->qname_len+sizeof(uint16_t)*2) + return RETVAL_TRUNC; /* buffer too small */ + if(!compress_tree_store(&tree, qinfo->qname, + dname_count_labels(qinfo->qname), + ldns_buffer_position(buffer), region, NULL)) + return RETVAL_OUTMEM; + ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len); + ldns_buffer_write_u16(buffer, qinfo->qtype); + ldns_buffer_write_u16(buffer, qinfo->qclass); + 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, int dnssec) { @@ -590,16 +609,17 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, /* insert query section */ if(rep->qdcount) { - if(ldns_buffer_remaining(buffer) < - qinfo->qname_len+sizeof(uint16_t)*2) - return 0; /* buffer too small */ - if(!compress_tree_store(&tree, qinfo->qname, - dname_count_labels(qinfo->qname), - ldns_buffer_position(buffer), region, NULL)) + if((r=insert_query(qinfo, tree, buffer, region)) != + RETVAL_OK) { + if(r == RETVAL_TRUNC) { + /* create truncated message */ + ldns_buffer_write_u16_at(buffer, 4, 0); + LDNS_TC_SET(ldns_buffer_begin(buffer)); + ldns_buffer_flip(buffer); + return 1; + } return 0; - ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len); - ldns_buffer_write_u16(buffer, qinfo->qtype); - ldns_buffer_write_u16(buffer, qinfo->qclass); + } } /* insert answer section */ @@ -689,6 +709,7 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, struct edns_data* edns, int dnssec) { uint16_t flags; + int attach_edns = 1; if(!cached) { /* original flags, copy RD bit from query. */ @@ -698,15 +719,23 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); } log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ - if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) - return 0; /* packet too small to contain edns... */ - udpsize -= calc_edns_field_size(edns); + if(udpsize < LDNS_HEADER_SIZE) + return 0; + if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) { + /* packet too small to contain edns, omit it. */ + attach_edns = 0; + } else { + /* reserve space for edns record */ + udpsize -= calc_edns_field_size(edns); + } + if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region, udpsize, dnssec)) { log_err("reply encode: out of memory"); return 0; } - attach_edns_record(pkt, edns); + if(attach_edns) + attach_edns_record(pkt, edns); return 1; }