]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix that the aggressive negative cache does not insert NSEC
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 23 Jul 2026 14:17:59 +0000 (16:17 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 23 Jul 2026 14:17:59 +0000 (16:17 +0200)
  records with overreaching next owner name. Also the result
  is not above the trust anchor's bailiwick. Also RRSIGS are
  not considered valid when an NSEC next owner name is not
  under the signer zone name. Thanks to Qifan Zhang, Palo
  Alto Networks, for the report.

doc/Changelog
iterator/iterator.c
testdata/nsec_cross_zone.rpl [new file with mode: 0644]
testdata/stop_nxdomain_minimised.rpl
validator/val_neg.c
validator/val_sigcrypt.c
validator/val_utils.c
validator/val_utils.h

index 112fc2465ae5d69318aaf41214d2f0cc811f1f4d..fee4ed411fed5fbbd3ca2e8ed1e16addc9648c29 100644 (file)
@@ -6,6 +6,12 @@
          checked to be the same as the signer name. Also RRSIGs are
          not considered valid when an NSEC3 is not b32.signerzone.
          Thanks to Qifan Zhang, Palo Alto Networks, for the report.
+       - Fix that the aggressive negative cache does not insert NSEC
+         records with overreaching next owner name. Also the result
+         is not above the trust anchor's bailiwick. Also RRSIGS are
+         not considered valid when an NSEC next owner name is not
+         under the signer zone name. Thanks to Qifan Zhang, Palo
+         Alto Networks, for the report.
 
 22 July 2026: Wouter
        - Release tag for 1.25.2, with the security commits:
index 25d40f269ada99a14842948de2f4fbbd6ca05518..1f95039c8834f948f5e35bb3b13c381f7c4ce5d0 100644 (file)
@@ -1531,7 +1531,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
                        msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
                                qstate->region, qstate->env->rrset_cache,
                                qstate->env->scratch_buffer, 
-                               *qstate->env->now, 1/*add SOA*/, NULL, 
+                               *qstate->env->now, 1/*add SOA*/, dpname,
                                qstate->env->cfg);
                }
                /* item taken from cache does not match our query name, thus
diff --git a/testdata/nsec_cross_zone.rpl b/testdata/nsec_cross_zone.rpl
new file mode 100644 (file)
index 0000000..8973fae
--- /dev/null
@@ -0,0 +1,216 @@
+; config options
+; The island of trust is at test.
+server:
+       trust-anchor: "test. DS 1444 8 2 8a87d067fd09a5965244fe2e317dd26d182c468e0a7f26ecc4c7b479bf89db9b"
+       val-override-date: "20201020135527"
+       target-fetch-policy: "0 0 0 0 0"
+       qname-minimisation: "no"
+       fake-sha1: yes
+       trust-anchor-signaling: no
+       minimal-responses: no
+       iter-scrub-promiscuous: no
+       aggressive-nsec: yes
+       local-zone: test. nodefault
+       log-servfail: yes
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test overreaching NSEC with aggressive cache
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+test. IN NS
+SECTION AUTHORITY
+test.  IN NS   ns.test.
+SECTION ADDITIONAL
+ns.test. IN A 1.2.3.5
+ENTRY_END
+RANGE_END
+
+; ns.test
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+test. IN NS
+SECTION ANSWER
+test.    IN NS   ns.test
+test.  3600    IN      RRSIG   NS 8 1 3600 20201116135527 20201019135527 1444 test. RGCxIO32TbbLTk6xZmTr+fjYPH50hntBxeOQ2DIj2pDsmjALcHYtVkOfpfk2EhOhHZd+9PLuoJPbJh6a9NqLSFeBvr0XZoCZoQ2g0tCHUNHcH5EVjA2TuYBQem6DVYnPLJ3914aRx0uA1j42b8dC2xsam/XkOo7U+dLbUW2Os1s=
+SECTION ADDITIONAL
+ns.test. IN A 1.2.3.5
+ns.test.       3600    IN      RRSIG   A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.test. IN A
+SECTION ANSWER
+ns.test. IN A 1.2.3.5
+ns.test.       3600    IN      RRSIG   A 8 2 3600 20201116135527 20201019135527 1444 test. GskCc4/k6GjH9V9Jz2V5L2XLiizbOeWkB0feSbf+aN859S3vxVvtuqkvIgwY4LafUO1QAn/pUcv9zA7rcFO++rlg+8t6gvZTo9p3v0bfeIv2uJDsfSBD5jDh0WXlxjekfnrKrQp7zE+GiA93tWwKUWKPvxXDgP+n886e6WcbHJw=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.test. IN AAAA
+SECTION AUTHORITY
+test. 3600 IN SOA ns.test. host.test. 20201 3600 1800 604800 3600
+test.  3600    IN      RRSIG   SOA 8 1 3600 20201116135527 20201019135527 1444 test. IZJIDmEgf0W7A5G7hvvZ2hUqJ9Trbv1/i7ySapDmPbYV9lVCmHHobySxO01yDhI2/Pvpsvxqrm1Tiv3BxH8uzZ4keKgiQjBsSy4htAsFct9I4E7ly2glPj/Fm3oun3PsjJDv5QYhx0KS7w4IQKU7Nc9pfJc92uoUI5bdoC1pRGw=
+ns.test. 3600 IN NSEC nz.test. A RRSIG
+ns.test.       3600    IN      RRSIG   NSEC 8 2 3600 20201116135527 20201019135527 1444 test. PElArVB3KPg8KHAP7lzcNbhFuXNxTsHNTn1dZVncB5qmWRdIaeKpaXDjpH0JSXMaelGFS+/QhuQ6Hmw9+4VyZFRqMzGhw4agUR/2bxABHcDIG4ZpUwyeSP61ATTfHUkQVxaH2wjCWI/tfmesdP2xVE4GXyUvCIBxU914MkZbULU=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+test. IN DNSKEY
+SECTION ANSWER
+test.    3600    IN      DNSKEY  257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b}
+test.  3600    IN      RRSIG   DNSKEY 8 1 3600 20201116135527 20201019135527 1444 test. UmRMS4iG9NBBHZYOtpwFFcJgbEb5SfHSgHd9XRe/8pTWM31WSDayn5ViPOBMqI1T5TXg2amc13dDI574xIM2oKMus3b5cBW72jJLW13jprBtslO6P8BMWb4HNnvLrJtQjwf3ErRirtTxinLmywQtmyr1cdthyG3Gp4N7i90fHSc=
+SECTION ADDITIONAL
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qname qtype
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.test. IN DS
+SECTION ANSWER
+example.test.  3600    IN      DS      55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39
+example.test.  3600    IN      RRSIG   DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.test. IN NS
+SECTION AUTHORITY
+example.test.    IN NS   ns.example.test.
+example.test.  3600    IN      DS      55567 8 2 a2d578906330a10a57d40462257b6ce038bad3f7bf4a45c46c46086e20a94b39
+example.test.  3600    IN      RRSIG   DS 8 2 3600 20201116135527 20201019135527 1444 test. P7+FTYW2qHuJ4I1YbuvseEz5X1lOYAraGEHB3C5y0OOCQFmhmSiFRdquNi2NlpcS6FXLdsE0EU+Bo1+0atTG4EkMWXbpF21lrtbB51BdsnlX4Mzc/o375fvjiOMwmF6wPCUaOUN62jrVrhsE/hedaVyDphDToqL17ETohwgUO2I=
+SECTION ADDITIONAL
+ns.example.test. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.test.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.test. IN NS
+SECTION ANSWER
+example.test.    IN NS   ns.example.test.
+example.test.  3600    IN      RRSIG   NS 8 2 3600 20201116135527 20201019135527 55567 example.test. l1JT0wMlK0YI7/CWHzexf/k0iafUhCgN+BdgjBXIRXmSQNf4HDTiAkbcWL2/15qtnp12nQy9JeiTdSQ3vtPoHAJX4C5uTWaze4ms+Wrrf+n92sLCjacP9x50uuicH3URT6cKb1QCAPwlvlWxIlZjAMYFScSns7+C441NMJT8aE4=
+SECTION ADDITIONAL
+ns.example.test.         IN      A       1.2.3.4
+ns.example.test.       3600    IN      RRSIG   A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.test. IN A
+SECTION ANSWER
+ns.example.test.         IN      A       1.2.3.4
+ns.example.test.       3600    IN      RRSIG   A 8 3 3600 20201116135527 20201019135527 55567 example.test. 2PWaVaccZFQgfPKXNsdEGYUVaashCAj1ZhBo9XRt5eQKUFvZcauBjMnXIuxZFyWeootn1fZGw6GuPI5W48Y0FDx38H6adprkFgQikso2Y64jDdDMWznSo38Z/XqP+U0+kq4vmwonvmEMpm7hKnNEXvhqGKyGzyBwb+CZVJ2L8Eo=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.test. IN AAAA
+SECTION AUTHORITY
+example.test. 3600 IN SOA ns.example.test. host.example.test. 20301 3600 1800 604800 3600
+example.test.  3600    IN      RRSIG   SOA 8 2 3600 20201116135527 20201019135527 55567 example.test. 2UUkScBAN37fJpSrelhE8DotKvmOzj3q9wicaanCIaCv95DE4nQnePih5B+ek3FIRjB/Uv2+z4Ro5Uxy94XAnlK0rCkDLSa0U9U7KP0ytc88sevO0x1SCPAMoZoJO6JqHkv42pdh54WSz+Zb/D8npY0j/tksHe/uX+VQnMymgb8=
+ns.example.test. 3600 IN NSEC nz.example.test. A RRSIG
+example.test.  3600    IN      SOA     ns.example.test. host.example.test. 20301 3600 1800 604800 3600
+ENTRY_END
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.test. IN DNSKEY
+SECTION ANSWER
+example.test.  3600    IN      DNSKEY  257 3 8 AwEAAdug/L739i0mgN2nuK/bhxu3wFn5Ud9nK2+XUmZQlPUEZUC5YZvm1rfMmEWTGBn87fFxEu/kjFZHJ55JLzqsbbpVHLbmKCTT2gYR2FV2WDKROGKuYbVkJIXdKAjJ0ONuK507NinYvlWXIoxHn22KAWOd9wKgSTNHBlmGkX+ts3hh ;{id = 55567 (ksk), size = 1024b}
+example.test.  3600    IN      RRSIG   DNSKEY 8 2 3600 20201116135527 20201019135527 55567 example.test. IbWMC6quOuZFNPAVxQLqCJ9nLhindBo826rnLcg5yMgs9dGUSPOCXAfHTmbgJAUNs9HTFfrJWNvasnETs0UOpmEuifGwWdH1OlME7Gny4RL2QmITUFeMW81Jz1tiVQxFXl6yxT0jxOxvz+bqMHlrz+8IeWQXcO+GZTPu8ueq30g=
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.test. IN NSEC
+SECTION ANSWER
+; normal record has next owner in example.test.
+; example.test. IN NSEC b.example.test. SOA DNSKEY NS RRSIG NSEC
+example.test. IN NSEC b.foo.test. NS SOA RRSIG NSEC DNSKEY
+example.test.  3600    IN      RRSIG   NSEC 8 2 3600 20201116135527 20201019135527 55567 example.test. xxepzzIxsJURk4/eZrwcDm5jhQNHtf1OmnPuu3T/w8y5NWwzlgn/hL17xoI71dIgTJg2GAq97wxEUhp951jtGMCeLH2Dz5lDZXxQI4wf2Wl43u2mTBQFRagDwfAauFc6Z4FYI/biDZyYcylZ3A5Q6j6ifFnsgMTL+cP0UIEZBTQ=
+ENTRY_END
+RANGE_END
+
+; CD=1 query for type NSEC
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD CD DO
+SECTION QUESTION
+example.test. IN NSEC
+ENTRY_END
+
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD CD RA DO NOERROR
+SECTION QUESTION
+example.test. IN NSEC
+SECTION ANSWER
+; The overreaching NSEC is removed by the scrubber.
+ENTRY_END
+
+SCENARIO_END
index 0de22edde6412d73b280ff38d273b471ba67012d..d6e881f59e878da1c62cd0e64f7cfd2a2b8e4769 100644 (file)
@@ -7,6 +7,7 @@ server:
        val-override-date: "20070916134226"
        fake-sha1: yes
        trust-anchor-signaling: no
+       domain-insecure: "anotherexample.local"
 
 stub-zone:
        name: "."
@@ -69,7 +70,7 @@ REPLY QR AA NOERROR
 SECTION QUESTION
 anotherexample.local. IN TXT
 SECTION ANSWER
-anotherexample.local.  86400   IN      TXT     "should not resolve this"
+anotherexample.local.  86400   IN      TXT     "stub works"
 ENTRY_END
 RANGE_END
 
@@ -95,7 +96,7 @@ STEP 20 QUERY
 ENTRY_BEGIN
 REPLY RD
 SECTION QUESTION
-anotherexample.local. IN TXT
+anotherexample2.local. IN TXT
 ENTRY_END
 
 ; query should be answered using NXDOMAIN for local in cache
@@ -104,9 +105,27 @@ ENTRY_BEGIN
 MATCH all
 REPLY QR RD RA NXDOMAIN
 SECTION QUESTION
-anotherexample.local. IN TXT
+anotherexample2.local. IN TXT
 SECTION AUTHORITY
 .      86400   IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2010111601 1800 900 604800 86400
 ENTRY_END
 
+STEP 40 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+anotherexample.local. IN TXT
+ENTRY_END
+
+; The stub stops going higher in the negative cache.
+STEP 50 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+anotherexample.local. IN TXT
+SECTION ANSWER
+anotherexample.local.  86400   IN      TXT     "stub works"
+ENTRY_END
+
 SCENARIO_END
index 5835fcbafdf04547b500372015d2f1e7eacc6155..63f380ad9ecf5a4b7ee50c87e2107972164f7ed6 100644 (file)
@@ -938,6 +938,10 @@ void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep)
                        continue;
                if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, 
                        zone->name)) continue;
+               if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC &&
+                       !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) {
+                       continue; /* nextowner not in zone */
+               }
                /* insert NSEC into this zone's tree */
                neg_insert_data(neg, zone, rep->rrsets[i]);
        }
@@ -1022,6 +1026,10 @@ void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
                        continue;
                if(!dname_subdomain_c(rep->rrsets[i]->rk.dname, 
                        zone->name)) continue;
+               if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC &&
+                       !nsec_nextowner_subdomain(rep->rrsets[i], zone->name)) {
+                       continue; /* nextowner not in zone */
+               }
                /* insert NSEC into this zone's tree */
                neg_insert_data(neg, zone, rep->rrsets[i]);
        }
@@ -1110,12 +1118,14 @@ grab_nsec(struct rrset_cache* rrset_cache, uint8_t* qname, size_t qname_len,
  * @param rrset_cache: rrset cache
  * @param now: to check ttl against
  * @param region: where to alloc result
+ * @param topname: do not look higher than this name, so that the
+ *   result cannot be taken from a zone above the current trust anchor.
  * @return rrset or NULL
  */
 static struct ub_packed_rrset_key*
 neg_find_nsec(struct val_neg_cache* neg_cache, uint8_t* qname, size_t qname_len,
        uint16_t qclass, struct rrset_cache* rrset_cache, time_t now,
-       struct regional* region)
+       struct regional* region, uint8_t* topname)
 {
        int labs;
        uint32_t flags;
@@ -1133,6 +1143,11 @@ neg_find_nsec(struct val_neg_cache* neg_cache, uint8_t* qname, size_t qname_len,
                lock_basic_unlock(&neg_cache->lock);
                return NULL;
        }
+       if(topname && !dname_subdomain_c(zone->name, topname)) {
+               /* Reject NSEC not within trust anchor's bailiwick */
+               lock_basic_unlock(&neg_cache->lock);
+               return NULL;
+       }
 
        /* NSEC only for now */
        if(zone->nsec3_hash) {
@@ -1430,7 +1445,7 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
 
        /* Get best available NSEC for qname */
        nsec = neg_find_nsec(neg, qinfo->qname, qinfo->qname_len, qinfo->qclass,
-               rrset_cache, now, region);
+               rrset_cache, now, region, topname);
 
        /* Matching NSEC, use to generate No Data answer. Not creating answers
         * yet for No Data proven using wildcard. */
@@ -1510,7 +1525,7 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
                                 * proof */
                                if(!(wcrr = neg_find_nsec(neg, wc_qinfo.qname,
                                        wc_qinfo.qname_len, qinfo->qclass,
-                                       rrset_cache, now, region)))
+                                       rrset_cache, now, region, topname)))
                                        return NULL;
 
                                nodata_wc = NULL;
index 55e7f1266599a0f9711ace39602b111dc74350e5..4139cc1fe0ceb6c2ca2f449e316822eebbca1718 100644 (file)
@@ -1641,6 +1641,16 @@ dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf,
                        return sec_status_bogus; /* NSEC3 owner not b32.signer */
                }
        }
+       /* NSEC, a next owner that is not under the signer is not allowed.*/
+       if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NSEC &&
+               !nsec_nextowner_subdomain(rrset, signer)) {
+               verbose(VERB_QUERY, "verify: NSEC next owner overreaches signer name");
+               *reason = "NSEC next owner overreaches signer name";
+               if(reason_bogus)
+                       *reason_bogus = LDNS_EDE_DNSSEC_BOGUS;
+               return sec_status_bogus; /* nextowner overreaching */
+       }
+
        sigblock = (unsigned char*)signer+signer_len;
        if(siglen < 2+18+signer_len+1) {
                verbose(VERB_QUERY, "verify: too short, no signature data");
index 9ff1c224d092b45b21ab112011cdcf9bbf8187d0..e77f93f5ae8e1f86626b2e46a3e1f16f11a5f585 100644 (file)
@@ -1384,3 +1384,20 @@ int derive_cname_from_dname(struct ub_packed_rrset_key* cname,
        memmove(out+prefix_len, dname_target, dname_target_len);
        return 1;
 }
+
+int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name)
+{
+       struct packed_rrset_data* d;
+       uint8_t* next;
+       size_t nextlen;
+       if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_NSEC)
+               return 0;
+       d = (struct packed_rrset_data*)rrset->entry.data;
+       if(!d || d->count == 0)
+               return 0;
+       next = d->rr_data[0]+2;
+       nextlen = dname_valid(next, d->rr_len[0]-2);
+       if(nextlen == 0)
+               return 0; /* malformed */
+       return dname_subdomain_c(next, name);
+}
index b44915a2ab5445b15021337471b0414ce0cf64a8..43386edbf35197260bf969dce7bc350d0ebe0931 100644 (file)
@@ -452,4 +452,7 @@ int derive_cname_from_dname(struct ub_packed_rrset_key* cname,
 void rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname,
        size_t* slen);
 
+/** See if the NSEC nextowner name is a subdomain of the name. */
+int nsec_nextowner_subdomain(struct ub_packed_rrset_key* rrset, uint8_t* name);
+
 #endif /* VALIDATOR_VAL_UTILS_H */