From e77a3a99414ca4f7b2de7bc7a27a85d235917666 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Mon, 18 Apr 2016 11:56:55 +0000 Subject: [PATCH] - Fix some malformed reponses to edns queries get fallback to nonedns. git-svn-id: file:///svn/unbound/trunk@3701 be551aaa-1e26-0410-a405-d3ace91eadb9 --- doc/Changelog | 3 +++ services/outside_network.c | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/doc/Changelog b/doc/Changelog index 3d6ee8b6e..72fbf1aff 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +18 April 2016: Wouter + - Fix some malformed reponses to edns queries get fallback to nonedns. + 15 April 2016: Wouter - cachedb module event handling design. diff --git a/services/outside_network.c b/services/outside_network.c index 398d0da43..e4d1fb1b9 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -1708,6 +1708,40 @@ serviced_tcp_send(struct serviced_query* sq, sldns_buffer* buff) return sq->pending != NULL; } +/* see if packet is edns malformed; got zeroes at start */ +static int +packet_edns_malformed(struct sldns_buffer* buf, uint16_t qtype) +{ + size_t len; + if(sldns_buffer_limit(buf) < LDNS_HEADER_SIZE) + return 1; /* malformed */ + /* they have NOERROR rcode, 1 answer. */ + if(LDNS_RCODE_WIRE(sldns_buffer_begin(buf)) != LDNS_RCODE_NOERROR) + return 0; + /* one query (to skip) and answer records */ + if(LDNS_QDCOUNT(sldns_buffer_begin(buf)) != 1 || + LDNS_ANCOUNT(sldns_buffer_begin(buf)) == 0) + return 0; + if(qtype == 0) + return 0; /* we asked for type 0 */ + /* skip qname */ + len = dname_valid(sldns_buffer_at(buf, LDNS_HEADER_SIZE), + sldns_buffer_limit(buf)-LDNS_HEADER_SIZE); + if(len == 0) + return 0; + /* and then 4 bytes (type and class of query) */ + if(sldns_buffer_limit(buf) < LDNS_HEADER_SIZE + len + 4 + 3) + return 0; + + /* and start with 11 zeroes as the answer RR */ + /* so check the qtype of the answer record, qname=0, type=0 */ + if(sldns_buffer_at(buf, LDNS_HEADER_SIZE+len+4)[0] == 0 && + sldns_buffer_at(buf, LDNS_HEADER_SIZE+len+4)[1] == 0 && + sldns_buffer_at(buf, LDNS_HEADER_SIZE+len+4)[2] == 0) + return 1; + return 0; +} + int serviced_udp_callback(struct comm_point* c, void* arg, int error, struct comm_reply* rep) @@ -1778,7 +1812,9 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error, ||sq->status == serviced_query_UDP_EDNS_FRAG) && (LDNS_RCODE_WIRE(sldns_buffer_begin(c->buffer)) == LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE( - sldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL)) { + sldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL + || packet_edns_malformed(c->buffer, sq->qtype) + )) { /* try to get an answer by falling back without EDNS */ verbose(VERB_ALGO, "serviced query: attempt without EDNS"); sq->status = serviced_query_UDP_EDNS_fallback;