Browse Source

[1579] adjust codes for the flag in the find function. Using a helper class to
deal with the flag.

haikuo zhang 13 years ago
parent
commit
4eeff0e79d
4 changed files with 397 additions and 181 deletions
  1. 1 1
      INSTALL
  2. 193 95
      src/lib/datasrc/database.cc
  3. 152 40
      src/lib/datasrc/database.h
  4. 51 45
      src/lib/datasrc/tests/database_unittest.cc

+ 1 - 1
INSTALL

@@ -1,4 +1,4 @@
-If using git (not the tarball), build the "configure" file:
+f using git (not the tarball), build the "configure" file:
     autoreconf --install
 
 To then build from source:

+ 193 - 95
src/lib/datasrc/database.cc

@@ -423,17 +423,9 @@ DatabaseClient::Finder::findAll(const isc::dns::Name& name,
                                 std::vector<isc::dns::ConstRRsetPtr>& target,
                                 const FindOptions options)
 {
-    const bool need_nsec3 = (((options & FIND_DNSSEC) != 0) && isNSEC3());
-    if (need_nsec3 && isNSEC()) {
-        isc_throw(DataSourceError, "nsec and nsec3 coexist");
-    }
-    // If the zone is signed with NSEC3, need to add RESULT_NSEC3_SIGNED to the
-    // flags in FindContext when NXRRSET NXDOMAIN or WILDCARD in the DNSSEC
-    // query, no need  NSEC RRset at the same time.
     return (ZoneFinderContextPtr(new Context(*this, options,
                                              findInternal(name, RRType::ANY(),
-                                                          &target, options,
-                                                          need_nsec3),
+                                                          &target, options),
                                              target)));
 }
 
@@ -445,17 +437,9 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
     if (type == RRType::ANY()) {
         isc_throw(isc::Unexpected, "Use findAll to answer ANY");
     }
-    // If the zone is signed with NSEC3, need to add RESULT_NSEC3_SIGNED to the
-    // flags in FindContext when NXRRSET NXDOMAIN or WILDCARD in the DNSSEC
-    // query, no need NSEC RRset at the same time.
-    const bool need_nsec3 = (((options & FIND_DNSSEC) != 0) && isNSEC3());
-    if (need_nsec3 && isNSEC()) {
-        isc_throw(DataSourceError, "nsec and nsec3 coexist");
-    }
     return (ZoneFinderContextPtr(new Context(*this, options,
                                              findInternal(name, type, NULL,
-                                                          options,
-                                                          need_nsec3))));
+                                                          options))));
 }
 
 DatabaseClient::Finder::DelegationSearchResult
@@ -617,15 +601,17 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
 //
 // If none of the above applies in any level, the search fails with NXDOMAIN.
 ZoneFinder::ResultContext
-DatabaseClient::Finder::findWildcardMatch(
-    const isc::dns::Name& name, const isc::dns::RRType& type,
-    const FindOptions options, const DelegationSearchResult& dresult,
-    std::vector<isc::dns::ConstRRsetPtr>* target, const bool need_nsec3)
+DatabaseClient::Finder::findWildcardMatch(const isc::dns::Name& name,
+                                          const isc::dns::RRType& type,
+                                          const DelegationSearchResult& dresult,
+                                          std::vector<isc::dns::ConstRRsetPtr>*
+                                          target, FindDNSSECContext& dnssec_ctx)
 {
     // Note that during the search we are going to search not only for the
     // requested type, but also for types that indicate a delegation -
     // NS and DNAME.
-    WantedTypes final_types(need_nsec3 ? FINAL_TYPES_NO_NSEC() : FINAL_TYPES());
+    WantedTypes final_types(dnssec_ctx.isNSEC3() ? FINAL_TYPES_NO_NSEC() :
+        FINAL_TYPES());
     final_types.insert(type);
 
     const size_t remove_labels = name.getLabelCount() - dresult.last_known;
@@ -647,7 +633,7 @@ DatabaseClient::Finder::findWildcardMatch(
             if (dresult.first_ns) {
                 // About to use first_ns.  The only way this can be set is if
                 // we are searching for glue, so do a sanity check.
-                if ((options & FIND_GLUE_OK) == 0) {
+                if ((dnssec_ctx.getOptions() & FIND_GLUE_OK) == 0) {
                     isc_throw(Unexpected, "Inconsistent conditions during "
                               "cancel of wilcard search for " <<
                               name.toText() << ": find_ns non-null when not "
@@ -663,8 +649,8 @@ DatabaseClient::Finder::findWildcardMatch(
             } else if (!hasSubdomains(name.split(i - 1).toText())) {
                 // The wildcard match is the best one, find the final result
                 // at it.  Note that wildcard should never be the zone origin.
-                return (findOnNameResult(name, type, options, false,
-                                         found, &wildcard, target, need_nsec3));
+                return (findOnNameResult(name, type, found, &wildcard,
+                                         target, dnssec_ctx));
             } else {
 
                 // more specified match found, cancel wildcard match
@@ -680,17 +666,15 @@ DatabaseClient::Finder::findWildcardMatch(
             LOG_DEBUG(logger, DBG_TRACE_DETAILED,
                       DATASRC_DATABASE_WILDCARD_EMPTY).
                 arg(accessor_->getDBName()).arg(wildcard).arg(name);
-            if (((options & FIND_DNSSEC) != 0) && !need_nsec3) {
+            FindResultFlags flags = (RESULT_WILDCARD |
+                dnssec_ctx.getResultFlags());
+            if (dnssec_ctx.isNSEC()) {
                 ConstRRsetPtr nsec = findNSECCover(Name(wildcard));
                 if (nsec) {
-                    return (ResultContext(NXRRSET, nsec,
-                                          RESULT_WILDCARD |
-                                          RESULT_NSEC_SIGNED));
+                    return (ResultContext(NXRRSET, nsec, flags));
                 }
             }
-            return (ResultContext(NXRRSET, ConstRRsetPtr(), need_nsec3 ?
-                        (RESULT_WILDCARD | RESULT_NSEC3_SIGNED) :
-                                  RESULT_WILDCARD));
+            return (ResultContext(NXRRSET, ConstRRsetPtr(), flags));
         }
     }
 
@@ -728,23 +712,157 @@ DatabaseClient::Finder::logAndCreateResult(
     return (ResultContext(code, rrset, flags));
 }
 
+DatabaseClient::Finder::FindDNSSECContext::FindDNSSECContext(
+    DatabaseClient::Finder* finderp,
+    const isc::datasrc::ZoneFinder::FindOptions options,
+    const Name& origin) :
+    finderp_(finderp),
+    options_(options),
+    origin_(origin),
+    initialized_(false)
+{}
+
+ZoneFinder::FindOptions
+DatabaseClient::Finder::FindDNSSECContext::getOptions() const
+{
+    return options_;
+}
+
+void
+DatabaseClient::Finder::FindDNSSECContext::init()
+{
+    if (finderp_ == NULL) {
+        isc_throw(DataSourceError, "no Finder to query");
+    }
+    if (!initialized_) {
+        initialized_ = true;
+        // If NSEC3PARAM rrset exists, the zone looks like signed with NSEC3
+        is_nsec3_ = ((options_ & FIND_DNSSEC) == 0) ? false :
+            finderp_->isNSEC3();
+        if (is_nsec3_) {
+            // If the zone is signed with NSEC3, no need to check NSEC. If NSEC
+            // and NSEC3 coexist, according to RFC 5155 10-4, it should return
+            // result as NSEC3.
+            is_nsec_ = false;
+        } else {
+            // If no NSEC3PARAM and it is DNSSEC query, check whether NSEC
+            // exist in apex of zone
+            is_nsec_ = ((options_ & FIND_DNSSEC) == 0) ? false :
+                finderp_->isNSEC();
+        }
+    }
+}
+
+bool
+DatabaseClient::Finder::FindDNSSECContext::isInited()
+{
+    return initialized_;
+}
+
+bool
+DatabaseClient::Finder::FindDNSSECContext::isNSEC3()
+{
+    if (isInited()) {
+        return is_nsec3_;
+    } else {
+        init();
+        return is_nsec3_;
+    }
+}
+
+bool
+DatabaseClient::Finder::FindDNSSECContext::isNSEC()
+{
+    if (isInited()) {
+        return is_nsec_;
+    } else {
+        init();
+        return is_nsec_;
+    }
+}
+
+isc::dns::ConstRRsetPtr
+DatabaseClient::Finder::FindDNSSECContext::getNSECRRset(
+        const FoundRRsets& found_set) const
+{
+    const FoundIterator nci = found_set.second.find(RRType::NSEC());
+    if (nci != found_set.second.end()) {
+        return nci->second;
+    } else {
+        return ConstRRsetPtr();
+    }
+}
+
+isc::dns::ConstRRsetPtr
+DatabaseClient::Finder::FindDNSSECContext::getNSECRRset(const Name &name) const
+{
+    if (finderp_ == NULL) {
+        isc_throw(DataSourceError, "no Finder to query");
+    }
+    const FoundRRsets wfound = finderp_->getRRsets(name.toText(), NSEC_TYPES(),
+                                                   true);
+    const FoundIterator nci = wfound.second.find(RRType::NSEC());
+    if (nci != wfound.second.end()) {
+        return nci->second;
+    } else {
+        return ConstRRsetPtr();
+    }
+}
+
+DatabaseClient::Finder::FoundRRsets
+DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(const Name& name,
+                                                          const RRType& type)
+{
+    if (finderp_ == NULL) {
+        isc_throw(DataSourceError, "no Finder to query");
+    }
+    const bool is_origin = isOrigin(name);
+    bool is_nsec = isNSEC();
+    WantedTypes final_types(is_nsec ? FINAL_TYPES() : FINAL_TYPES_NO_NSEC());
+    final_types.insert(type);
+    return (finderp_->getRRsets(name.toText(), final_types, !is_origin, NULL,
+            type == RRType::ANY()));
+}
+
+bool
+DatabaseClient::Finder::FindDNSSECContext::isOrigin(const Name &name) const
+{
+    return (name == origin_);
+}
+
+ZoneFinder::FindResultFlags
+DatabaseClient::Finder::FindDNSSECContext::getResultFlags()
+{
+    // If it is not DNSSEC query, it should return RESULT_DEFAULT
+    if ((options_ & FIND_DNSSEC) == 0) {
+        return RESULT_DEFAULT;
+    }
+    // If it is a DNSSEC query and the zone is signed with NSEC3, it should
+    // return RESULT_NSEC3_SIGNED
+    if (isNSEC3()) {
+        return RESULT_NSEC3_SIGNED;
+    } else {
+        // If it is a DNSSEC query and the zone is signed with NSEC, it should
+        // return RESULT_NSEC_SIGNED, other else, return RESULT_DEFAULT
+        return (isNSEC() ? RESULT_NSEC_SIGNED : RESULT_DEFAULT);
+    }
+}
+
 ZoneFinder::ResultContext
 DatabaseClient::Finder::findOnNameResult(const Name& name,
                                          const RRType& type,
-                                         const FindOptions options,
-                                         const bool is_origin,
                                          const FoundRRsets& found,
                                          const string* wildname,
                                          std::vector<isc::dns::ConstRRsetPtr>*
-                                         target, const bool need_nsec3)
+                                         target, FindDNSSECContext& dnssec_ctx)
 {
     const bool wild = (wildname != NULL);
-    FindResultFlags flags;
-    if (need_nsec3) {
-        flags = wild ? (RESULT_WILDCARD | RESULT_NSEC3_SIGNED) :
-            RESULT_DEFAULT;
-    } else {
-        flags = wild ? RESULT_WILDCARD : RESULT_DEFAULT;
+    FindResultFlags flags = wild ? RESULT_WILDCARD : RESULT_DEFAULT;
+    // If the zone file is signed with NSEC3, need to set RESULT_NSEC3_SIGNED
+    // flag in the flags. It is good for upper caller to deal with the query
+    // response message.
+    if (wild & dnssec_ctx.isNSEC3()) {
+        flags = (flags | RESULT_NSEC3_SIGNED);
     }
     // Get iterators for the different types of records we are interested in -
     // CNAME, NS and Wanted types.
@@ -754,15 +872,13 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
     // For wildcard case with DNSSEC required, the caller would need to know
     // whether it's NSEC or NSEC3 signed.  So we need to do an additional
     // search here, even though the NSEC RR may not be returned.
-    // TODO: this part should be revised when we support NSEC3; ideally we
-    // should use more effective and efficient way to identify (whether and)
-    // in which way the zone is signed.
-    if (wild && (options & FIND_DNSSEC) != 0 && !need_nsec3 &&
+    if (wild && dnssec_ctx.isNSEC() &&
         found.second.find(RRType::NSEC()) != found.second.end()) {
-        flags = flags | RESULT_NSEC_SIGNED;
+        flags = (flags | RESULT_NSEC_SIGNED);
     }
 
-    if (!is_origin && ((options & FIND_GLUE_OK) == 0) &&
+    if (!dnssec_ctx.isOrigin(name) &&
+        ((dnssec_ctx.getOptions() & FIND_GLUE_OK) == 0) &&
         nsi != found.second.end()) {
         // A NS RRset was found at the domain we were searching for.  As it is
         // not at the origin of the zone, it is a delegation and indicates that
@@ -821,66 +937,54 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
     // NSEC records in the name of the wildcard, not the substituted one,
     // so we need to search the tree again.
     ConstRRsetPtr nsec_rrset;   // possibly used with DNSSEC, otherwise NULL
-    if ((options & FIND_DNSSEC) != 0 && !need_nsec3) {
-        if (wild) {
-            const FoundRRsets wfound = getRRsets(*wildname, NSEC_TYPES(),
-                                                 true);
-            const FoundIterator nci = wfound.second.find(RRType::NSEC());
-            if (nci != wfound.second.end()) {
-                nsec_rrset = nci->second;
-            }
-        } else {
-            const FoundIterator nci = found.second.find(RRType::NSEC());
-            if (nci != found.second.end()) {
-                nsec_rrset = nci->second;
-            }
-        }
+    if (dnssec_ctx.isNSEC()) {
+        nsec_rrset = wild ? dnssec_ctx.getNSECRRset(Name(*wildname)) :
+            dnssec_ctx.getNSECRRset(found);
     }
     if (nsec_rrset) {
         // This log message covers both normal and wildcard cases, so we pass
         // NULL for 'wildname'.
         return (logAndCreateResult(name, NULL, type, NXRRSET, nsec_rrset,
                                    DATASRC_DATABASE_FOUND_NXRRSET_NSEC,
-                                   flags | RESULT_NSEC_SIGNED));
+                                   (flags | RESULT_NSEC_SIGNED)));
     }
     return (logAndCreateResult(name, wildname, type, NXRRSET, nsec_rrset,
                                wild ? DATASRC_DATABASE_WILDCARD_NXRRSET :
-                               DATASRC_DATABASE_FOUND_NXRRSET, need_nsec3 ?
-                               (flags | RESULT_NSEC3_SIGNED) : flags));
+                               DATASRC_DATABASE_FOUND_NXRRSET,
+                               (flags | dnssec_ctx.getResultFlags())));
 }
 
 ZoneFinder::ResultContext
 DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
-                                         FindOptions options,
                                          const DelegationSearchResult& dresult,
                                          std::vector<isc::dns::ConstRRsetPtr>*
-                                         target, const bool need_nsec3)
+                                         target, FindDNSSECContext& dnssec_ctx)
 {
-    const bool dnssec_data = ((options & FIND_DNSSEC) != 0);
-    const bool need_nsec = (dnssec_data && !need_nsec3);
     // On entry to this method, we know that the database doesn't have any
     // entry for this name.  Before returning NXDOMAIN, we need to check
     // for special cases.
 
     if (hasSubdomains(name.toText())) {
-        // Does the domain have a subdomain (i.e. it is an empty non-terminal)?
+        // Does the domain have a subdomain (i.e. it is an empty non-terminal)
         // If so, return NXRRSET instead of NXDOMAIN (as although the name does
         // not exist in the database, it does exist in the DNS tree).
         LOG_DEBUG(logger, DBG_TRACE_DETAILED,
                   DATASRC_DATABASE_FOUND_EMPTY_NONTERMINAL).
             arg(accessor_->getDBName()).arg(name);
-        const ConstRRsetPtr nsec = need_nsec ? findNSECCover(name) :
+        const ConstRRsetPtr nsec = dnssec_ctx.isNSEC() ? findNSECCover(name) :
             ConstRRsetPtr();
-        return (ResultContext(NXRRSET, nsec, nsec ? RESULT_NSEC_SIGNED :
-            (need_nsec3 ? RESULT_NSEC3_SIGNED : RESULT_DEFAULT)));
-    } else if ((options & NO_WILDCARD) == 0) {
+        if(dnssec_ctx.isNSEC() && (!nsec)){
+            isc_throw(DataSourceError,
+                      "no NSEC RR covers in the NSEC signed zone");
+        }
+        return (ResultContext(NXRRSET, nsec, dnssec_ctx.getResultFlags()));
+    } else if ((dnssec_ctx.getOptions() & NO_WILDCARD) == 0) {
         // It's not an empty non-terminal and wildcard matching is not
         // disabled, so check for wildcards. If there is a wildcard match
         // (i.e. all results except NXDOMAIN) return it; otherwise fall
         // through to the NXDOMAIN case below.
         const ResultContext wcontext =
-            findWildcardMatch(name, type, options, dresult, target,
-                              need_nsec3);
+            findWildcardMatch(name, type, dresult, target, dnssec_ctx);
         if (wcontext.code != NXDOMAIN) {
             return (wcontext);
         }
@@ -890,11 +994,12 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
     // NSEC records if requested).
     LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_NO_MATCH).
               arg(accessor_->getDBName()).arg(name).arg(type).arg(getClass());
-    const ConstRRsetPtr nsec = need_nsec ? findNSECCover(name) :
+    const ConstRRsetPtr nsec = dnssec_ctx.isNSEC() ? findNSECCover(name) :
         ConstRRsetPtr();
-    return (ResultContext(NXDOMAIN, nsec,
-                          nsec ? RESULT_NSEC_SIGNED : (need_nsec3 ?
-                          RESULT_NSEC3_SIGNED : RESULT_DEFAULT)));
+    if(dnssec_ctx.isNSEC() && (!nsec)){
+        isc_throw(DataSourceError, "no NSEC RR covers in the NSEC signed zone");
+    }
+    return (ResultContext(NXDOMAIN, nsec, dnssec_ctx.getResultFlags()));
 }
 
 bool
@@ -910,9 +1015,9 @@ DatabaseClient::Finder::isNSEC3() {
 
 bool
 DatabaseClient::Finder::isNSEC() {
-    // If an NSEC RRsets exists at the zone apex, it's quite likely that
-    // the zone is signed with NSEC. (If not the zone is more or less broken,
-    // but it's caller's responsibility how to handle such cases)
+    // If an NSEC RR exists at the zone apex, it's quite likely that
+    // the zone is signed with NSEC.  (If not the zone is more or less broken,
+    // but it's caller's responsibility how to handle such cases).
     const FoundRRsets nsec_found = getRRsets(origin_.toText(),
                                              NSEC_TYPES(), false);
     const FoundIterator nfi(nsec_found.second.find(RRType::NSEC()));
@@ -922,8 +1027,7 @@ DatabaseClient::Finder::isNSEC() {
 ZoneFinder::ResultContext
 DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
                                      std::vector<ConstRRsetPtr>* target,
-                                     const FindOptions options,
-                                     const bool is_nsec3)
+                                     const FindOptions options)
 {
     LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
               .arg(accessor_->getDBName()).arg(name).arg(type).arg(getClass());
@@ -961,22 +1065,16 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
     // - Requested name is a delegation point (NS only but not at the zone
     //   apex - DNAME is ignored here as it redirects DNS names subordinate to
     //   the owner name - the owner name itself is not redirected.)
-    const bool is_origin = (name == getOrigin());
-    WantedTypes final_types(is_nsec3 ? FINAL_TYPES_NO_NSEC() : FINAL_TYPES());
-    final_types.insert(type);
-    const FoundRRsets found = getRRsets(name.toText(), final_types,
-                                        !is_origin, NULL,
-                                        type == RRType::ANY());
+    FindDNSSECContext dnssec_ctx(this, options, getOrigin());
+    const FoundRRsets found = dnssec_ctx.getDNSSECRRset(name, type);
     if (found.first) {
         // Something found at the domain name.  Look into it further to get
         // the final result.
-        return (findOnNameResult(name, type, options, is_origin, found,
-                                 NULL, target, is_nsec3));
+        return (findOnNameResult(name, type, found, NULL, target, dnssec_ctx));
     } else {
         // Did not find anything at all at the domain name, so check for
         // subdomains or wildcards.
-        return (findNoNameResult(name, type, options, dresult, target,
-                                 is_nsec3));
+        return (findNoNameResult(name, type, dresult, target, dnssec_ctx));
     }
 }
 

+ 152 - 40
src/lib/datasrc/database.h

@@ -673,6 +673,7 @@ public:
     DatabaseClient(isc::dns::RRClass rrclass,
                    boost::shared_ptr<DatabaseAccessor> accessor);
 
+
     /// \brief Corresponding ZoneFinder implementation
     ///
     /// The zone finder implementation for database data sources. Similarly
@@ -687,7 +688,126 @@ public:
     ///
     /// Methods directly corresponds to the ones in ZoneFinder.
     class Finder : public ZoneFinder {
-    public:
+
+        /// \brief Helper to the findInterval.
+        ///
+        /// Get the ResultFlags for findInterval. If the zone is signed with
+        /// NSEC3, it will return RESULT_NSEC3_SIGNED. If it is signed with
+        /// NSEC, it wll return RESULT_NSEC_SIGNED. Other else it will return
+        /// RESULT_DEFAULT. It wraps getRRsets function to do some special
+        /// search, like searching NSEC RRset by getNSECRRset function,
+        /// searching DNSSEC related RRset and RRsig by getNSECRRset.
+        class FindDNSSECContext{
+            public:
+
+                /// \brief Constructor for FindDNSSECContext class.
+                ///
+                /// It initalize a helper for findInterval function.
+                ///
+                /// \param finderp The Finder piont for search.
+                /// \param options Search options.
+                /// \param origin The origin name for this finder.
+                FindDNSSECContext(Finder* finderp, const FindOptions options,
+                                  const isc::dns::Name& origin);
+
+                /// \brief Get result flags of this query.
+                /// \return ResultFlags for this query. If the zone file is
+                /// signed with NSEC, is will return RESULT_NSEC_SIGNED with
+                /// dnssec query. If the zone file is signed with NSEC3, it
+                /// will return RESULT_NSEC3_SIGNED with dnssec query, others
+                /// it should return RESULT_DEFAULT.
+                ZoneFinder::FindResultFlags getResultFlags();
+
+                typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
+                    FoundRRsets;
+                /// \brief Get DNSSEC RRset for the queried name.
+                ///
+                /// It should return the RRsets and RRsigs for the queried
+                /// name with designated type.
+                ///
+                /// \param name The queried name.
+                /// \param type The queried type.
+                /// \return RRsets and RRsigs that are matched.
+                FoundRRsets getDNSSECRRset(const isc::dns::Name& name,
+                                           const isc::dns::RRType& type);
+
+                /// \brief Get the needed NSEC RRset.
+                ///
+                /// It should return the needed NSEC RRset.
+                ///
+                /// \param name The name which the NSEC RRset belong to.
+                /// \return the needed NSEC RRsets.
+                isc::dns::ConstRRsetPtr getNSECRRset(const isc::dns::Name&
+                                                     name) const;
+
+                /// \brief Get the needed NSEC RRset.
+                ///
+                /// It should return the needed NSEC RRset.
+                ///
+                /// \param found_set The RRset which contain the NSEC an other
+                /// type RRs.
+                /// \return the needed NSEC RRsets.
+                isc::dns::ConstRRsetPtr getNSECRRset(const FoundRRsets&
+                                                     found_set) const;
+
+                /// \brief Check whether the zone file is signed with NSECi3.
+                ///
+                /// It checks whether the zone file is signed with NSEC3. If
+                /// yes, return true, other else return false.
+                ///
+                /// \return True for NSEC3, false for other else.
+                bool isNSEC3();
+
+                /// \brief Check whether the zone file is signed with NSEC.
+                ///
+                /// It checks whether the zone file is signed with NSEC, If
+                /// yes, return true, other else return false.
+                ///
+                /// \return True for NSEC, false for other else.
+                bool isNSEC();
+
+                /// \brief Check whether the name is origin name of the zone.
+                ///
+                /// It checks whether the name is origin name of the zone. Yes
+                /// for the origin name, false for not.
+                ///
+                /// \param name The queried name.
+                /// \return True for origin name, false for not.
+                bool isOrigin(const isc::dns::Name& name) const;
+
+                /// \brief get the options of queried.
+                ///
+                /// It return the queried options.
+                ///
+                /// \return It return the queried options.
+                ZoneFinder::FindOptions getOptions() const;
+            private:
+
+                /// \brief Init the attributes in this entity.
+                ///
+                /// It should init the attributes of this entity. Check whether
+                /// it is the NSEC or NSEC3 zone file if it is a dnssec query.
+                ///
+                /// \note If the entity is initalized, no need to init it again.
+                void init();
+
+                /// \brief Check whether the entity is initalized.
+                ///
+                /// It should return true if the entity is inited, else return
+                /// false.
+                ///
+                /// \return True for inited, else return false.
+                bool isInited();
+                DatabaseClient::Finder* finderp_;
+                ZoneFinder::ZoneFinder::FindOptions options_;
+                FindResultFlags flags_;
+                isc::dns::Name origin_;
+                bool is_nsec3_;
+                bool is_nsec_;
+                bool initialized_;
+        };
+
+        public:
         /// \brief Constructor
         ///
         /// \param database The database (shared with DatabaseClient) to
@@ -706,19 +826,6 @@ public:
         virtual isc::dns::Name getOrigin() const;
         virtual isc::dns::RRClass getClass() const;
 
-
-        /// \brief check whether zone is signed with nsec3
-        ///
-        /// searches the NSEC3PARAM RRset in the zone apex, if it exists, the 
-        /// zone looks signed with nsec3
-        bool isNSEC3();
-
-        /// \brief check whether zone is signed with nsec
-        ///
-        /// searches the NSEC RRset in the zone apex, if it exists, the
-        /// zone looks signed with nsec
-        bool isNSEC();
-
         /// \brief Find an RRset in the datasource
         ///
         /// Searches the datasource for an RRset of the given name and
@@ -791,10 +898,22 @@ public:
             return (*accessor_);
         }
 
+        /// \brief check whether zone is signed with nsec
+        ///
+        /// searches the NSEC3PARAM RRset in the zone apex, if it exists, the
+        /// zone looks signed with nsec
+        bool isNSEC();
+        /// \brief check whether zone is signed with nsec3
+        ///
+        /// searches the NSEC3PARAM RRset in the zone apex, if it exists, the
+        /// zone looks signed with nsec3
+        bool isNSEC3();
+
     private:
         boost::shared_ptr<DatabaseAccessor> accessor_;
         const int zone_id_;
         const isc::dns::Name origin_;
+
         /// \brief Shortcut name for the result of getRRsets
         typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
             FoundRRsets;
@@ -814,9 +933,8 @@ public:
                                    const isc::dns::RRType& type,
                                    std::vector<isc::dns::ConstRRsetPtr>*
                                    target,
-                                   const FindOptions options = FIND_DEFAULT,
-                                   const bool need_nsec3 = false);
-
+                                   const FindOptions options = FIND_DEFAULT);
+    public:
         /// \brief Searches database for RRsets of one domain.
         ///
         /// This method scans RRs of single domain specified by name and
@@ -851,6 +969,7 @@ public:
                               const std::string* construct_name = NULL,
                               bool any = false);
 
+    private:
         /// \brief Search result of \c findDelegationPoint().
         ///
         /// This is a tuple combining the result of the search - a status code
@@ -946,15 +1065,13 @@ public:
         ///
         /// \param name The name to find
         /// \param type The RRType to find
-        /// \param options Options about how to search. See the documentation
-        ///        for ZoneFinder::FindOptions.
         /// \param dresult Result of the search through the zone for a
         ///        delegation.
         /// \param target If the type happens to be ANY, it will insert all
         ///        the RRsets of the found name (if any is found) here instead
         ///        of being returned by the result.
-        /// \param need_nsec3 When zone is signed with nsec3, no need to find 
-        ///        nsec rrset
+        /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
+        ///        find function.
         /// \return Tuple holding the result of the search - the RRset of the
         ///         wildcard records matching the name, together with a status
         ///         indicating the match type (e.g. CNAME at the wildcard
@@ -962,13 +1079,11 @@ public:
         ///         success due to an exact match).  Also returned if there
         ///         is no match is an indication as to whether there was an
         ///         NXDOMAIN or an NXRRSET.
-        ResultContext findWildcardMatch(
-            const isc::dns::Name& name,
-            const isc::dns::RRType& type,
-            const FindOptions options,
-            const DelegationSearchResult& dresult,
-            std::vector<isc::dns::ConstRRsetPtr>* target,
-            const bool need_nsec3);
+        ResultContext findWildcardMatch(const isc::dns::Name& name,
+                                        const isc::dns::RRType& type,
+                                        const DelegationSearchResult& dresult,
+                                        std::vector<isc::dns::ConstRRsetPtr>*
+                                        target, FindDNSSECContext& dnssec_ctx);
 
         /// \brief Handle matching results for name
         ///
@@ -989,9 +1104,6 @@ public:
         ///
         /// \param name The name to find
         /// \param type The RRType to find
-        /// \param options Options about how to search. See the documentation
-        ///        for ZoneFinder::FindOptions.
-        /// \param is_origin If name is the zone's origin name.
         /// \param found A set of found RRsets in the search for the name
         ///        and type.  It could contain one or more of the requested
         ///        type, CNAME, NS, and NSEC RRsets of the name.
@@ -1001,8 +1113,9 @@ public:
         ///                 it's NULL in the case of non wildcard match.
         /// \param target When the query is any, this must be set to a vector
         ///    where the result will be stored.
-        /// \param need_nsec3 When zone is signed with nsec3, no need to find 
-        ///    nsec rrset
+        /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
+        ///        find function.
+
         /// \return Tuple holding the result of the search - the RRset of the
         ///         wildcard records matching the name, together with a status
         ///         indicating the match type (corresponding to the each of
@@ -1011,12 +1124,10 @@ public:
         ///         method.
         ResultContext findOnNameResult(const isc::dns::Name& name,
                                        const isc::dns::RRType& type,
-                                       const FindOptions options,
-                                       const bool is_origin,
                                        const FoundRRsets& found,
                                        const std::string* wildname,
                                        std::vector<isc::dns::ConstRRsetPtr>*
-                                       target, const bool need_nsec3);
+                                       target, FindDNSSECContext& dnssec_ctx);
 
         /// \brief Handle no match for name
         ///
@@ -1041,8 +1152,8 @@ public:
         /// \param target If the query is for type ANY, the successfull result,
         ///        if there happens to be one, will be returned through the
         ///        parameter, as it doesn't fit into the result.
-        /// \param need_nsec3 When zone is signed with nsec3, no need to find
-        ///        nsec rrset
+        /// \param dnssec_ctx The dnssec context, it is a DNSSEC wrapper for
+        ///        find function.
         /// \return Tuple holding the result of the search - the RRset of the
         ///         wildcard records matching the name, together with a status
         ///         indicating the match type (e.g. CNAME at the wildcard
@@ -1050,10 +1161,9 @@ public:
         ///         success due to an exact match).
         ResultContext findNoNameResult(const isc::dns::Name& name,
                                        const isc::dns::RRType& type,
-                                       FindOptions options,
                                        const DelegationSearchResult& dresult,
                                        std::vector<isc::dns::ConstRRsetPtr>*
-                                       targeti, const bool need_nsec3);
+                                       target, FindDNSSECContext& dnssec_ctx);
 
         /// Logs condition and creates result
         ///
@@ -1106,6 +1216,8 @@ public:
         /// To find stuff in the result of getRRsets.
         typedef std::map<dns::RRType, dns::RRsetPtr>::const_iterator
             FoundIterator;
+
+
     };
 
     /// \brief Find a zone in the database

+ 51 - 45
src/lib/datasrc/tests/database_unittest.cc

@@ -2292,11 +2292,18 @@ TYPED_TEST(DatabaseClientTest, wildcardNXRRSET_NSEC) {
                Name("*.wild.example.org"), ZoneFinder::FIND_DNSSEC);
 }
 
-TYPED_TEST(DatabaseClientTest, dbNegativeCaseFind) {
-    // ZoneFinder::find() for negative cases should show whether the zone is
-    // signed with NSEC or NSEC3, that is good for upper layer caller.
+TYPED_TEST(DatabaseClientTest, nsec3FlagFindDB) {
+    // ZoneFinder::find() for negative cases and wildcard cases should check
+    // whether the zone is signed with NSEC or NSEC3. If it is signed with
+    // NSEC3, RESULT_NSEC3_SIGNED flag should be returned. That is good for
+    // upper layer caller.
 
-    // First off, everything should be okay if no NSEC3PARAM rrset
+    // First off, everything should be okay if no NSEC3PARAM rrset. If
+    // NSEC3PARAM RRset doesn't exist and NSEC RRset exist at apex, it looks
+    // like signed with NSEC, and the RESULT_NSEC_SIGNED flag should be return.
+
+    // Check NXDOMAIN case in NSEC signed zone, and RESULT_NSEC_SIGNED flag
+    // should be returned to upper layer caller.
     this->expected_rdatas_.clear();
     this->expected_sig_rdatas_.clear();
     this->expected_rdatas_.push_back("www2.example.org. A AAAA NSEC RRSIG");
@@ -2309,6 +2316,9 @@ TYPED_TEST(DatabaseClientTest, dbNegativeCaseFind) {
                ZoneFinder::NXDOMAIN, this->expected_rdatas_,
                this->expected_sig_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
                Name("www.example.org."), ZoneFinder::FIND_DNSSEC);
+
+    // Check NXRRSET case in NSEC signed zone, and RESULT_NSEC_SIGNED flag
+    // should be return.
     this->expected_rdatas_.clear();
     this->expected_sig_rdatas_.clear();
     this->expected_rdatas_.push_back("www2.example.org. A AAAA NSEC RRSIG");
@@ -2316,11 +2326,12 @@ TYPED_TEST(DatabaseClientTest, dbNegativeCaseFind) {
                                          "20000201000000 12345 example.org. "
                                          "FAKEFAKEFAKE");
     doFindTest(*finder, isc::dns::Name("www.example.org."),
-               isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(),
-               this->rrttl_, ZoneFinder::NXRRSET,
-               this->expected_rdatas_, this->expected_sig_rdatas_,
-               ZoneFinder::RESULT_NSEC_SIGNED, isc::dns::Name::ROOT_NAME(),
-               ZoneFinder::FIND_DNSSEC);
+               isc::dns::RRType::TXT(), isc::dns::RRType::NSEC(), this->rrttl_,
+               ZoneFinder::NXRRSET, this->expected_rdatas_,
+               this->expected_sig_rdatas_, ZoneFinder::RESULT_NSEC_SIGNED,
+               isc::dns::Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
+
+    // Check wildcase cases, and the RESULT_NSEC_SIGNED should be return.
     this->expected_rdatas_.clear();
     this->expected_sig_rdatas_.clear();
     this->expected_rdatas_.push_back("192.0.2.5");
@@ -2346,26 +2357,10 @@ TYPED_TEST(DatabaseClientTest, dbNegativeCaseFind) {
                this->expected_sig_rdatas_,
                (ZoneFinder::RESULT_WILDCARD | ZoneFinder::RESULT_NSEC_SIGNED),
                Name("*.wild.example.org"), ZoneFinder::FIND_DNSSEC);
-    this->updater_ = this->client_->getUpdater(this->zname_, false);
-    this->rrset_.reset(new RRset(this->zname_, this->qclass_,
-                       isc::dns::RRType::NSEC3PARAM(), this->rrttl_));
-    this->rrset_->addRdata(rdata::createRdata(isc::dns::RRType::NSEC3PARAM(), 
-                           this->rrset_->getClass(), "1 0 12 aabbccdd"));
-    this->updater_->addRRset(*this->rrset_);
-    this->updater_->commit();
-    try {
-        this->expected_rdatas_.clear();
-        this->expected_sig_rdatas_.clear();
-        doFindTest(this->updater_->getFinder(), Name("www1.example.org."),
-                   this->qtype_, this->qtype_, this->rrttl_,
-                   ZoneFinder::NXDOMAIN, this->expected_rdatas_,
-                   this->expected_sig_rdatas_, ZoneFinder::RESULT_NSEC3_SIGNED,
-                   Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
-    } catch (const DataSourceError&) {}
-    // The following test should be tested in zone which is signed by NSEC3
-#if 0
-    // Then, if NSEC3PARAM exists at the origin, the flags of result should
+
+    // Then, if NSEC3PARAM exists at the apex, the flags of result should
     // contain RESULT_NSEC3_SIGNED flag when NXDOMAIN NXRRSET or wildcard
+    // cases.
 
     // Add NSEC3PARAM RRSET at the apex of the zone. It looks weird if the
     // zone only has NSEC3PARM RRset (but no NSEC3s), but it is okay for unit
@@ -2377,23 +2372,27 @@ TYPED_TEST(DatabaseClientTest, dbNegativeCaseFind) {
                                               this->rrset_->getClass(),
                                               "1 0 12 aabbccdd"));
     this->updater_->addRRset(*this->rrset_);
-    // check NXDOMAIN
+
+    // check NXDOMAIN, it should set RESULT_NSEC3_SIGNED in the flags.
     this->expected_rdatas_.clear();
     this->expected_sig_rdatas_.clear();
-    doFindTest(this->updater_->getFinder(),
-            isc::dns::Name("www1.example.org."), this->qtype_, this->qtype_, 
-            this->rrttl_, ZoneFinder::NXDOMAIN, this->expected_rdatas_,
-            this->expected_sig_rdatas_, ZoneFinder::RESULT_NSEC3_SIGNED,
-            isc::dns::Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
-    // check NXRRSET
+    doFindTest(this->updater_->getFinder(), Name("www1.example.org."),
+            this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
+            this->expected_rdatas_, this->expected_sig_rdatas_,
+            ZoneFinder::RESULT_NSEC3_SIGNED,Name::ROOT_NAME(),
+            ZoneFinder::FIND_DNSSEC);
+
+    // check NXRRSET, it should set RESULT_NSEC3_SIGNED in the flags.
     this->expected_rdatas_.clear();
     this->expected_sig_rdatas_.clear();
     doFindTest(this->updater_->getFinder(), Name("www.example.org."),
                RRType::TXT(), RRType::TXT(), this->rrttl_,
                ZoneFinder::NXRRSET, this->expected_rdatas_,
                this->expected_sig_rdatas_, ZoneFinder::RESULT_NSEC3_SIGNED,
-               isc::dns::Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
-    // check flags if wildcard matches
+               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
+
+    // check flags if wildcard matches, it should set RESULT_NSEC3_SIGNED in
+    // the flags.
     this->expected_rdatas_.push_back("192.0.2.5");
     this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 "
                                          "20000201000000 12345 example.org. "
@@ -2403,16 +2402,17 @@ TYPED_TEST(DatabaseClientTest, dbNegativeCaseFind) {
                this->expected_rdatas_, this->expected_sig_rdatas_,
                ZoneFinder::RESULT_WILDCARD | ZoneFinder::RESULT_NSEC3_SIGNED,
                Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
-    // check flags if NXRRSET in wildcard case
+
+    // check flags if NXRRSET in wildcard case, it should set
+    // RESULT_NSEC3_SIGNED in the flags.
     this->expected_rdatas_.clear();
     this->expected_sig_rdatas_.clear();
     doFindTest(this->updater_->getFinder(), Name("b.a.wild.example.org"),
                RRType::TXT(), RRType::TXT(), this->rrttl_,
                ZoneFinder::NXRRSET, this->expected_rdatas_,
                this->empty_rdatas_, (ZoneFinder::RESULT_WILDCARD |
-                                     ZoneFinder::RESULT_NSEC3_SIGNED),
-               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC);
-#endif
+               ZoneFinder::RESULT_NSEC3_SIGNED), Name::ROOT_NAME(),
+               ZoneFinder::FIND_DNSSEC);
 }
 
 TYPED_TEST(DatabaseClientTest, NXDOMAIN_NSEC) {
@@ -2444,14 +2444,17 @@ TYPED_TEST(DatabaseClientTest, NXDOMAIN_NSEC) {
     if (!this->is_mock_) {
         return; // We don't make the real DB to throw
     }
-    EXPECT_NO_THROW(doFindTest(*finder,
+    // If the zone is signed with NSEC, find function should throw an error
+    // when no NSEC RRset for NXDOMAIN case.
+    EXPECT_THROW(doFindTest(*finder,
                                isc::dns::Name("notimplnsec.example.org."),
                                isc::dns::RRType::TXT(),
                                isc::dns::RRType::NSEC(), this->rrttl_,
                                ZoneFinder::NXDOMAIN, this->empty_rdatas_,
                                this->empty_rdatas_,
                                ZoneFinder::RESULT_DEFAULT,
-                               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
+                               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC),
+                 DataSourceError);
 }
 
 TYPED_TEST(DatabaseClientTest, emptyNonterminalNSEC) {
@@ -2471,14 +2474,17 @@ TYPED_TEST(DatabaseClientTest, emptyNonterminalNSEC) {
     if (!this->is_mock_) {
         return; // We don't make the real DB to throw
     }
-    EXPECT_NO_THROW(doFindTest(*finder,
+    // If the zone is signed with NSEC, find function should throw an error
+    // when no NSEC RRset for NXRRset case
+    EXPECT_THROW(doFindTest(*finder,
                                isc::dns::Name("here.wild.example.org."),
                                isc::dns::RRType::TXT(),
                                isc::dns::RRType::NSEC(),
                                this->rrttl_, ZoneFinder::NXRRSET,
                                this->empty_rdatas_, this->empty_rdatas_,
                                ZoneFinder::RESULT_DEFAULT,
-                               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
+                               Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC),
+                 DataSourceError);
 }
 
 TYPED_TEST(DatabaseClientTest, anyFromFind) {