]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix some malformed reponses to edns queries get fallback to nonedns.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 18 Apr 2016 11:56:55 +0000 (11:56 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Mon, 18 Apr 2016 11:56:55 +0000 (11:56 +0000)
git-svn-id: file:///svn/unbound/trunk@3701 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
services/outside_network.c

index 3d6ee8b6e27f19598bd2b431e7000052fc232f37..72fbf1afff90e2bf06afd10c65659d5949f0e2dc 100644 (file)
@@ -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.
 
index 398d0da43f054c2432fadc2e9577732af98d9028..e4d1fb1b918bce0fd60064529b32d886617ed7d0 100644 (file)
@@ -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;