]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Fixup for a wildcarded NSEC with empty nonterminal query.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 20 Sep 2007 11:37:15 +0000 (11:37 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 20 Sep 2007 11:37:15 +0000 (11:37 +0000)
git-svn-id: file:///svn/unbound/trunk@624 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
doc/plan
makedist.sh
testdata/val_mal_wc.rpl [new file with mode: 0644]
validator/val_nsec.c
validator/val_nsec.h
validator/validator.c

index 8d0425108b82cb48e58bd736b60a62f1ce2a14bc..bcaf5cca1f7e75e607fe9977ffafbaf993ae2b6e 100644 (file)
@@ -1,3 +1,8 @@
+20 September 2007: Wouter
+       - fixup and test for NSEC wildcard with empty nonterminals. 
+       - makedist.sh fixup for svn info.
+       - acl features request in plan.
+
 19 September 2007: Wouter
        - comments about non-packed usage.
        - plan for overload support in 0.6.
index 7048a7fe1197bd93f27b2afcb04f5560c80a3ffd..77458bfbfb2dec81bd069b8ed902d83736cae9c1 100644 (file)
--- a/doc/plan
+++ b/doc/plan
@@ -179,6 +179,11 @@ Styleguide:
   if phase 1, start servicing, phase is 0 again. Make robust against delays.
   readme: max about 1 second worth of incoming queries, 10k perhaps,
        or 1/number of seconds it takes start up of 10k.
+* features from Jakob's graph.
+       * acl for allowed recursion (RD=1), then drop or refused query.
+       * static answers for queries, option
+       * blacklist (return fixed nxdomain), option
+       * after checking acl, static, blacklist, do iter forwards, recurse.
 
 *** Local zones feature.
 * Build in local zone features. First the total stop for1912.
index e335bac513f736f97f0134f798a07160dc50dbd3..9449c89351fe1896a3b3e15bad37efec162a119e 100755 (executable)
@@ -134,7 +134,7 @@ done
 # Check if SVNROOT is specified.
 if [ -z "$SVNROOT" ]; then
     if test -f .svn/entries; then
-         eval `grep 'url=' .svn/entries | head -1`
+         eval `svn info | grep 'URL:' | sed -e 's/URL: /url=/' | head -1`
          SVNROOT="$url"
     fi
     if test -z "$SVNROOT"; then
diff --git a/testdata/val_mal_wc.rpl b/testdata/val_mal_wc.rpl
new file mode 100644 (file)
index 0000000..5bba1bc
--- /dev/null
@@ -0,0 +1,120 @@
+; config options
+; The island of trust is at example.com
+server:
+       trust-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       val-override-date: "20070916134226"
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with nodata, wildcards and ENT
+
+; 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 qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+
+; response to DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN DNSKEY
+SECTION ANSWER
+example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+example.com.    3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION ANSWER
+SECTION AUTHORITY
+example.com.    86394   IN      SOA     NS.IANA.ORG. NSTLD.IANA.ORG. 2007092000 1800 900 604800 86400
+example.com.    86394   IN      RRSIG   SOA 3 2 86394 20070926135752 20070829135752 2854 example.com. MCwCFFHjDbVjiPywHcXm669wMUJ7dlcoAhRfuauTUoExMSx96lTVYbBHOXtQEw== ;{id = 2854}
+
+; note that b.example.com. is an empty nonterminal
+*.example.com.  3600    IN      NSEC    *.b.example.com. A MX RRSIG NSEC 
+*.example.com.  3600    IN      RRSIG   NSEC 3 2 3600 20070926135752 20070829135752 2854 example.com. MCwCFE9CopvxP6w/1HqnqxNluh1Qbgk0AhRgKrdjk/YoEm4tcYflNX6McDMCgQ== ;{id = 2854}
+
+SECTION ADDITIONAL
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+b.example.com. IN DS
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA AD NOERROR
+SECTION QUESTION
+b.example.com. IN DS
+SECTION ANSWER
+SECTION AUTHORITY
+example.com.    86394   IN      SOA     NS.IANA.ORG. NSTLD.IANA.ORG. 2007092000 1800 900 604800 86400
+SECTION ADDITIONAL
+ENTRY_END
+
+SCENARIO_END
index 74320096a79403485103d022f39b9fbeb9f79a83..eb76fc834e4c7c57e94a02a60162b009c88333bc 100644 (file)
 #include "util/data/msgreply.h"
 #include "util/data/dname.h"
 
+/** get ttl of rrset */
+static uint32_t 
+rrset_get_ttl(struct ub_packed_rrset_key* k)
+{
+       struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
+       return d->ttl;
+}
+
 int
 nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type)
 {
@@ -181,6 +189,8 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
                qinfo->qclass);
        enum sec_status sec;
        size_t i;
+       uint8_t* wc = NULL, *ce = NULL;
+       int valid_nsec = 0;
 
        /* If we have a NSEC at the same name, it must prove one 
         * of two things
@@ -223,23 +233,55 @@ val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
                                "did not verify.");
                        return sec_status_bogus;
                }
-               if(nsec_proves_nodata(rep->rrsets[i], qinfo)) {
+               if(nsec_proves_nodata(rep->rrsets[i], qinfo, &wc)) {
                        verbose(VERB_ALGO, "NSEC for empty non-terminal "
                                "proved no DS.");
-                       return sec_status_secure;
+                       *proof_ttl = rrset_get_ttl(rep->rrsets[i]);
+                       valid_nsec = 1;
+               }
+               if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) {
+                       ce = nsec_closest_encloser(qinfo->qname, 
+                               rep->rrsets[i]);
                }
        }
+       if(wc && !ce)
+               valid_nsec = 0;
+       else if(wc && ce) {
+               /* ce and wc must match */
+               if(query_dname_compare(wc, ce) != 0) 
+                       valid_nsec = 0;
+       }
+       if(valid_nsec) {
+               return sec_status_secure;
+       }
 
        /* NSEC proof did not conlusively point to DS or no DS */
        return sec_status_unchecked;
 }
 
 int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, 
-       struct query_info* qinfo)
+       struct query_info* qinfo, uint8_t** wc)
 {
+       log_assert(wc);
        if(query_dname_compare(nsec->rk.dname, qinfo->qname) != 0) {
                uint8_t* nm;
                size_t ln;
+
+               /* empty-non-terminal checking. 
+                * Done before wildcard, because this is an exact match,
+                * and would prevent a wildcard from matching. */
+
+               /* If the nsec is proving that qname is an ENT, the nsec owner 
+                * will be less than qname, and the next name will be a child 
+                * domain of the qname. */
+               if(!nsec_get_next(nsec, &nm, &ln))
+                       return 0; /* bad nsec */
+               if(dname_strict_subdomain_c(nm, qinfo->qname) &&
+                       dname_canonical_compare(nsec->rk.dname, 
+                               qinfo->qname) < 0) {
+                       return 1; /* proves ENT */
+               }
+
                /* wildcard checking. */
 
                /* If this is a wildcard NSEC, make sure that a) it was 
@@ -254,7 +296,8 @@ int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
                        dname_remove_label(&ce, &ce_len);
 
                        /* The qname must be a strict subdomain of the 
-                        * closest encloser, for the wildcard to apply */
+                        * closest encloser, for the wildcard to apply 
+                        */
                        if(dname_strict_subdomain_c(qinfo->qname, ce)) {
                                /* here we have a matching NSEC for the qname,
                                 * perform matching NSEC checks */
@@ -270,24 +313,13 @@ int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
                                if(nsec_has_type(nsec, qinfo->qtype)) {
                                        return 0;
                                }
+                               *wc = ce;
                                return 1;
                        }
                }
 
-               /* empty-non-terminal checking. */
-
-               /* If the nsec is proving that qname is an ENT, the nsec owner 
-                * will be less than qname, and the next name will be a child 
-                * domain of the qname. */
-               if(!nsec_get_next(nsec, &nm, &ln))
-                       return 0; /* bad nsec */
-               if(dname_strict_subdomain_c(nm, qinfo->qname) &&
-                       dname_canonical_compare(nsec->rk.dname, 
-                               qinfo->qname) < 0) {
-                       return 1; /* proves ENT */
-               }
-               /* Otherwise, this NSEC does not prove ENT, so it does not 
-                * prove NODATA. */
+               /* Otherwise, this NSEC does not prove ENT and is not a 
+                * wildcard, so it does not prove NODATA. */
                return 0;
        }
 
index 43f39a0aa118b429f3491dfd2add946086083c98..cd2c3c1397af2305a344dfd81a8dbb7b63845b12 100644 (file)
@@ -93,10 +93,14 @@ int nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type);
  *
  * @param nsec: the nsec record to check against.
  * @param qinfo: the query info.
+ * @param wc: if the nodata is proven for a wildcard match, the wildcard
+ *     closest encloser is returned, else NULL (wc is unchanged).
+ *     This closest encloser must then match the nameerror given for the
+ *     nextcloser of qname.
  * @return true if NSEC proves this.
  */
 int nsec_proves_nodata(struct ub_packed_rrset_key* nsec, 
-       struct query_info* qinfo);
+       struct query_info* qinfo, uint8_t** wc);
 
 /**
  * Determine if the given NSEC proves a NameError (NXDOMAIN) for a given
index 398c82b921f4a35da81efe4c45a7dfb2cf0cda62..14f57078bd7dcbc651b5ffdebd46410a84631086 100644 (file)
@@ -571,14 +571,9 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
                 * NODATA.
                 * This needs to handle the ENT NODATA case. */
                if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
-                       if(nsec_proves_nodata(s, qchase)) {
+                       if(nsec_proves_nodata(s, qchase, &wc)) {
                                has_valid_nsec = 1;
-                               /* set wc only if wildcard applicable, which
-                                * is a *.name, and qname sub of .name */
-                               if(dname_is_wild(s->rk.dname) &&
-                                       dname_strict_subdomain_c(
-                                       qchase->qname, s->rk.dname+2))
-                                       wc = s->rk.dname;
+                               /* sets wc-encloser if wildcard applicable */
                        } 
                        if(val_nsec_proves_name_error(s, qchase->qname)) {
                                ce = nsec_closest_encloser(qchase->qname, s);
@@ -596,9 +591,7 @@ validate_nodata_response(struct module_env* env, struct val_env* ve,
        if(wc && !ce)
                has_valid_nsec = 0;
        else if(wc && ce) {
-               log_assert(dname_is_wild(wc));
-               /* first label wc is \001*, so remove and compare to ce */
-               if(query_dname_compare(wc+2, ce) != 0) {
+               if(query_dname_compare(wc, ce) != 0) {
                        has_valid_nsec = 0;
                }
        }
@@ -912,14 +905,9 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
                 * NODATA. This needs to handle the ENT NODATA case. 
                 * Also try to prove NAMEERROR, and absence of a wildcard */
                if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
-                       if(nsec_proves_nodata(s, qchase)) {
+                       if(nsec_proves_nodata(s, qchase, &wc)) {
                                nodata_valid_nsec = 1;
-                               /* set wc only if wildcard applicable, which
-                                * is a *.name, and qname sub of .name */
-                               if(dname_is_wild(s->rk.dname) &&
-                                       dname_strict_subdomain_c(
-                                       qchase->qname, s->rk.dname+2))
-                                       wc = s->rk.dname;
+                               /* set wc encloser if wildcard applicable */
                        } 
                        if(val_nsec_proves_name_error(s, qchase->qname)) {
                                ce = nsec_closest_encloser(qchase->qname, s);
@@ -941,9 +929,7 @@ validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
        if(wc && !ce)
                nodata_valid_nsec = 0;
        else if(wc && ce) {
-               log_assert(dname_is_wild(wc));
-               /* first label wc is \001*, so remove and compare to ce */
-               if(query_dname_compare(wc+2, ce) != 0) {
+               if(query_dname_compare(wc, ce) != 0) {
                        nodata_valid_nsec = 0;
                }
        }