From c8b71a8b1e9e84d318b7f4625173dcb868129d58 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 11 Jun 2007 10:12:43 +0000 Subject: [PATCH] Nicer encoding. fixes. git-svn-id: file:///svn/unbound/trunk@379 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/worker.c | 10 +++--- doc/Changelog | 10 ++++++ iterator/iterator.c | 5 +-- services/outside_network.c | 4 ++- testcode/unitmsgparse.c | 5 +-- util/data/msgencode.c | 72 +++++++++++++++++++++++++++++--------- util/data/msgencode.h | 6 ++-- util/data/msgparse.c | 2 +- util/data/msgreply.c | 2 +- util/netevent.c | 1 - 10 files changed, 87 insertions(+), 30 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index d75190f5c..b414db09c 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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, diff --git a/doc/Changelog b/doc/Changelog index f9a78af93..f0d1faa1f 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/iterator/iterator.c b/iterator/iterator.c index bb520721e..8e22fb097 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -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; diff --git a/services/outside_network.c b/services/outside_network.c index 67c2d2949..b1a2c5a88 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -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); diff --git a/testcode/unitmsgparse.c b/testcode/unitmsgparse.c index 4060c1ea6..c26391cde 100644 --- a/testcode/unitmsgparse.c +++ b/testcode/unitmsgparse.c @@ -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)) != diff --git a/util/data/msgencode.c b/util/data/msgencode.c index ce1802ffb..fb6a68f78 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -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; icount; - 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; irrsets[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; irrsets[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; irrsets[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; } diff --git a/util/data/msgencode.h b/util/data/msgencode.h index de49404f5..203929dc8 100644 --- a/util/data/msgencode.h +++ b/util/data/msgencode.h @@ -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. diff --git a/util/data/msgparse.c b/util/data/msgparse.c index ac01bddcc..61c320740 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -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; diff --git a/util/data/msgreply.c b/util/data/msgreply.c index fc9b7661b..859788363 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -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; diff --git a/util/netevent.c b/util/netevent.c index ff09ffda7..b07913056 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -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); -- 2.47.2