]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix for iterator RCODE handling of YXDOMAIN. This fixes
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 21 Apr 2026 08:09:02 +0000 (10:09 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 21 Apr 2026 08:09:02 +0000 (10:09 +0200)
  that the server only accepts YXDOMAIN answers that contain
  a DNAME record. This stops bad answers, and checks that
  the authoritative server gives correct replies.
  Thanks to Qifan Zhang, Palo Alto Networks for the report.

doc/Changelog
iterator/iterator.c
testdata/iter_scrub_promiscuous.rpl

index 430ccd9a6cf0b7030a24fb4163024864d707fcf1..a96f08a119362485ebdf865481083709a514ca23 100644 (file)
          the server does not echo extended rcode values after class
          chaos queries. Thanks to Qifan Zhang, Palo Alto Networks
          for the report.
+       - Fix for iterator RCODE handling of YXDOMAIN. This fixes
+         that the server only accepts YXDOMAIN answers that contain
+         a DNAME record. This stops bad answers, and checks that
+         the authoritative server gives correct replies.
+         Thanks to Qifan Zhang, Palo Alto Networks for the report.
 
 20 April 2026: Wouter
        - Fix compile warnings for thread setname routine, and test compile.
index b8bfc432725eecfddbde3bbc6f340e169050b34b..cc38348b39dad95a2175cd1a41c915ece21f3029 100644 (file)
@@ -3224,8 +3224,19 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
        } else iter_scrub_ds(iq->response, NULL, NULL);
        if(type == RESPONSE_TYPE_THROWAWAY &&
                FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) {
-               /* YXDOMAIN is a permanent error, no need to retry */
-               type = RESPONSE_TYPE_ANSWER;
+               /* YXDOMAIN is a permanent error for DNAME expansion overflow
+                * (RFC 6672 Section 2.2). Only accept if the response
+                * contains a DNAME record in the answer section; otherwise
+                * treat as invalid, to make sure the authoritative answer
+                * make sense. */
+               size_t i;
+               for(i=0; i<iq->response->rep->an_numrrsets; i++) {
+                       if(ntohs(iq->response->rep->rrsets[i]->rk.type)
+                               == LDNS_RR_TYPE_DNAME) {
+                               type = RESPONSE_TYPE_ANSWER;
+                               break;
+                       }
+               }
        }
        if(type == RESPONSE_TYPE_CNAME)
                origtypecname = 1;
index febbee81ce4ed9e7d6f81a20b244a198dd398325..e380277fd4f5ea3dbf31630e4fb5eabf708fc409 100644 (file)
@@ -204,6 +204,25 @@ RANGE_END
 ; ns.pollute4.mesa
 RANGE_BEGIN 0 400
        ADDRESS 1.2.4.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.pollute4.mesa. IN A
+SECTION ANSWER
+ns.pollute4.mesa. IN A 1.2.4.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.pollute4.mesa. IN AAAA
+SECTION AUTHORITY
+pollute4.mesa. IN SOA ns.pollute4.mesa. host.pollute4.mesa 20701 3600 3600 604800 3600
+ENTRY_END
 
 ; This is the spoofed answer that is returned.
 ENTRY_BEGIN
@@ -423,14 +442,18 @@ ENTRY_END
 STEP 130 CHECK_ANSWER
 ENTRY_BEGIN
 MATCH all
-REPLY QR RD RA YXDOMAIN
+REPLY QR RD RA SERVFAIL
 SECTION QUESTION
 test4.atkr.pollute4.mesa. IN A
-SECTION ANSWER
-test4.atkr.pollute4.mesa. 86400 IN A 1.2.3.4
-SECTION AUTHORITY
-; removed record
-;pollute4.mesa.       0       IN      NS      ns.attacker.mesa.
+; Since the reply does not contain a DNAME, it is rejected as YXDOMAIN answer.
+;REPLY QR RD RA YXDOMAIN
+;SECTION QUESTION
+;test4.atkr.pollute4.mesa. IN A
+;SECTION ANSWER
+;test4.atkr.pollute4.mesa. 86400 IN A 1.2.3.4
+;SECTION AUTHORITY
+;; removed record
+;;pollute4.mesa.       0       IN      NS      ns.attacker.mesa.
 ENTRY_END
 
 ; Check the cache contents, for query 4.