Browse Source

[master] Merge branch 'master' of ssh://git.bind10.isc.org/var/bind10/git/bind10

Naoki Kambe 12 years ago
parent
commit
307a588d6e

+ 8 - 12
src/bin/auth/query.cc

@@ -57,7 +57,7 @@ namespace auth {
 void
 void
 Query::ResponseCreator::addRRset(isc::dns::Message& message,
 Query::ResponseCreator::addRRset(isc::dns::Message& message,
                                  const isc::dns::Message::Section section,
                                  const isc::dns::Message::Section section,
-                                 const ConstRRsetPtr& rrset, const bool dnssec)
+                                 const ConstRRsetPtr& rrset)
 {
 {
     /// Is this RRset already in the list of RRsets added to the message?
     /// Is this RRset already in the list of RRsets added to the message?
     const std::vector<const AbstractRRset*>::const_iterator i =
     const std::vector<const AbstractRRset*>::const_iterator i =
@@ -68,8 +68,7 @@ Query::ResponseCreator::addRRset(isc::dns::Message& message,
         // No - add it to both the message and the list of RRsets processed.
         // No - add it to both the message and the list of RRsets processed.
         // The const-cast is wrong, but the message interface seems to insist.
         // The const-cast is wrong, but the message interface seems to insist.
         message.addRRset(section,
         message.addRRset(section,
-                         boost::const_pointer_cast<AbstractRRset>(rrset),
-                         dnssec);
+                         boost::const_pointer_cast<AbstractRRset>(rrset));
         added_.push_back(rrset.get());
         added_.push_back(rrset.get());
     }
     }
 }
 }
@@ -78,8 +77,7 @@ void
 Query::ResponseCreator::create(Message& response,
 Query::ResponseCreator::create(Message& response,
                                const vector<ConstRRsetPtr>& answers,
                                const vector<ConstRRsetPtr>& answers,
                                const vector<ConstRRsetPtr>& authorities,
                                const vector<ConstRRsetPtr>& authorities,
-                               const vector<ConstRRsetPtr>& additionals,
-                               const bool dnssec)
+                               const vector<ConstRRsetPtr>& additionals)
 {
 {
     // Inserter should be reset each time the query is reset, so should be
     // Inserter should be reset each time the query is reset, so should be
     // empty at this point.
     // empty at this point.
@@ -91,13 +89,13 @@ Query::ResponseCreator::create(Message& response,
     // guarantee that if there are duplicates, the single RRset added will
     // guarantee that if there are duplicates, the single RRset added will
     // appear in the most important section.
     // appear in the most important section.
     BOOST_FOREACH(const ConstRRsetPtr& rrset, answers) {
     BOOST_FOREACH(const ConstRRsetPtr& rrset, answers) {
-        addRRset(response, Message::SECTION_ANSWER, rrset, dnssec);
+        addRRset(response, Message::SECTION_ANSWER, rrset);
     }
     }
     BOOST_FOREACH(const ConstRRsetPtr& rrset, authorities) {
     BOOST_FOREACH(const ConstRRsetPtr& rrset, authorities) {
-        addRRset(response, Message::SECTION_AUTHORITY, rrset, dnssec);
+        addRRset(response, Message::SECTION_AUTHORITY, rrset);
     }
     }
     BOOST_FOREACH(const ConstRRsetPtr& rrset, additionals) {
     BOOST_FOREACH(const ConstRRsetPtr& rrset, additionals) {
-        addRRset(response, Message::SECTION_ADDITIONAL, rrset, dnssec);
+        addRRset(response, Message::SECTION_ADDITIONAL, rrset);
     }
     }
 }
 }
 
 
@@ -533,8 +531,7 @@ Query::process(datasrc::ClientList& client_list,
             break;
             break;
     }
     }
 
 
-    response_creator_.create(*response_, answers_, authorities_, additionals_,
-                             dnssec_);
+    response_creator_.create(*response_, answers_, authorities_, additionals_);
 }
 }
 
 
 void
 void
@@ -592,8 +589,7 @@ Query::processDSAtChild() {
         }
         }
     }
     }
 
 
-    response_creator_.create(*response_, answers_, authorities_, additionals_,
-                             dnssec_);
+    response_creator_.create(*response_, answers_, authorities_, additionals_);
     return (true);
     return (true);
 }
 }
 
 

+ 4 - 8
src/bin/auth/query.h

@@ -441,16 +441,13 @@ public:
         /// authority, and additional sections, and add them to their
         /// authority, and additional sections, and add them to their
         /// corresponding sections in the given message.  The RRsets are
         /// corresponding sections in the given message.  The RRsets are
         /// filtered such that a particular RRset appears only once in the
         /// filtered such that a particular RRset appears only once in the
-        /// message.
-        ///
-        /// If \c dnssec is true, it tells the message to include any RRSIGs
-        /// attached to the RRsets.
+        /// message. Any RRSIGs attached to the RRsets will be included
+        /// when they are rendered.
         void create(
         void create(
             isc::dns::Message& message,
             isc::dns::Message& message,
             const std::vector<isc::dns::ConstRRsetPtr>& answers_,
             const std::vector<isc::dns::ConstRRsetPtr>& answers_,
             const std::vector<isc::dns::ConstRRsetPtr>& authorities_,
             const std::vector<isc::dns::ConstRRsetPtr>& authorities_,
-            const std::vector<isc::dns::ConstRRsetPtr>& additionals_,
-            const bool dnssec);
+            const std::vector<isc::dns::ConstRRsetPtr>& additionals_);
 
 
     private:
     private:
         // \brief RRset comparison functor.
         // \brief RRset comparison functor.
@@ -469,10 +466,9 @@ public:
         /// \param message Message to which the RRset is to be added
         /// \param message Message to which the RRset is to be added
         /// \param section Section of the message in which the RRset is put
         /// \param section Section of the message in which the RRset is put
         /// \param rrset Pointer to RRset to be added to the message
         /// \param rrset Pointer to RRset to be added to the message
-        /// \param dnssec Whether RRSIG records should be added as well
         void addRRset(isc::dns::Message& message,
         void addRRset(isc::dns::Message& message,
                       const isc::dns::Message::Section section,
                       const isc::dns::Message::Section section,
-                      const isc::dns::ConstRRsetPtr& rrset, const bool dnssec);
+                      const isc::dns::ConstRRsetPtr& rrset);
 
 
 
 
     private:
     private:

+ 28 - 32
src/bin/auth/tests/query_unittest.cc

@@ -211,12 +211,18 @@ const char* const nonsec_a_txt =
     "nonsec.example.com. 3600 IN A 192.0.2.0\n";
     "nonsec.example.com. 3600 IN A 192.0.2.0\n";
 
 
 // NSEC3 RRs.  You may also need to add mapping to MockZoneFinder::hash_map_.
 // NSEC3 RRs.  You may also need to add mapping to MockZoneFinder::hash_map_.
-const char* const nsec3_apex_txt =
+const string nsec3_apex_txt =
     "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN NSEC3 1 1 12 "
     "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN NSEC3 1 1 12 "
     "aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA NSEC3PARAM RRSIG\n";
     "aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA NSEC3PARAM RRSIG\n";
-const char* const nsec3_www_txt =
+const string nsec3_apex_rrsig_txt =
+    "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN RRSIG NSEC3 5 3 "
+    "3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE";
+const string nsec3_www_txt =
     "q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN NSEC3 1 1 12 "
     "q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN NSEC3 1 1 12 "
     "aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG\n";
     "aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG\n";
+const string nsec3_www_rrsig_txt =
+    "q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN RRSIG NSEC3 5 3 "
+    "3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE";
 
 
 // NSEC3 for wild.example.com (used in wildcard tests, will be added on
 // NSEC3 for wild.example.com (used in wildcard tests, will be added on
 // demand not to confuse other tests)
 // demand not to confuse other tests)
@@ -479,9 +485,10 @@ protected:
                                        isc::dns::ConstRRsetPtr rrset,
                                        isc::dns::ConstRRsetPtr rrset,
                                        FindResultFlags flags = RESULT_DEFAULT)
                                        FindResultFlags flags = RESULT_DEFAULT)
     {
     {
+        ConstRRsetPtr rp = stripRRsigs(rrset, options);
         return (ZoneFinderContextPtr(
         return (ZoneFinderContextPtr(
                     new Context(*this, options,
                     new Context(*this, options,
-                                ResultContext(code, rrset, flags))));
+                                ResultContext(code, rp, flags))));
     }
     }
 
 
 private:
 private:
@@ -594,7 +601,7 @@ MockZoneFinder::findAll(const Name& name, std::vector<ConstRRsetPtr>& target,
                  found_domain->second.begin();
                  found_domain->second.begin();
                  found_rrset != found_domain->second.end(); ++found_rrset) {
                  found_rrset != found_domain->second.end(); ++found_rrset) {
                 // Insert RRs under the domain name into target
                 // Insert RRs under the domain name into target
-                target.push_back(found_rrset->second);
+                target.push_back(stripRRsigs(found_rrset->second, options));
             }
             }
             return (ZoneFinderContextPtr(
             return (ZoneFinderContextPtr(
                         new Context(*this, options,
                         new Context(*this, options,
@@ -701,25 +708,8 @@ MockZoneFinder::find(const Name& name, const RRType& type,
         RRsetStore::const_iterator found_rrset =
         RRsetStore::const_iterator found_rrset =
             found_domain->second.find(type);
             found_domain->second.find(type);
         if (found_rrset != found_domain->second.end()) {
         if (found_rrset != found_domain->second.end()) {
-            ConstRRsetPtr rrset;
-            // Strip whatever signature there is in case DNSSEC is not required
-            // Just to make sure the Query asks for it when it is needed
-            if ((options & ZoneFinder::FIND_DNSSEC) != 0 ||
-                include_rrsig_anyway_ ||
-                !found_rrset->second->getRRsig()) {
-                rrset = found_rrset->second;
-            } else {
-                RRsetPtr noconst(new RRset(found_rrset->second->getName(),
-                                           found_rrset->second->getClass(),
-                                           found_rrset->second->getType(),
-                                           found_rrset->second->getTTL()));
-                for (RdataIteratorPtr
-                     i(found_rrset->second->getRdataIterator());
-                     !i->isLast(); i->next()) {
-                    noconst->addRdata(i->getCurrent());
-                }
-                rrset = noconst;
-            }
+            ConstRRsetPtr rrset = ZoneFinder::stripRRsigs(found_rrset->second,
+                                                          options);
             return (createContext(options, SUCCESS, rrset));
             return (createContext(options, SUCCESS, rrset));
         }
         }
 
 
@@ -1985,14 +1975,16 @@ TEST_F(QueryTest, findNSEC3) {
     // Apex name.  It should have a matching NSEC3
     // Apex name.  It should have a matching NSEC3
     {
     {
         SCOPED_TRACE("apex, non recursive");
         SCOPED_TRACE("apex, non recursive");
-        nsec3Check(true, expected_closest_labels, nsec3_apex_txt,
+        nsec3Check(true, expected_closest_labels,
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt,
                    mock_finder->findNSEC3(Name("example.com"), false));
                    mock_finder->findNSEC3(Name("example.com"), false));
     }
     }
 
 
     // Recursive mode doesn't change the result in this case.
     // Recursive mode doesn't change the result in this case.
     {
     {
         SCOPED_TRACE("apex, recursive");
         SCOPED_TRACE("apex, recursive");
-        nsec3Check(true, expected_closest_labels, nsec3_apex_txt,
+        nsec3Check(true, expected_closest_labels,
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt,
                    mock_finder->findNSEC3(Name("example.com"), true));
                    mock_finder->findNSEC3(Name("example.com"), true));
     }
     }
 
 
@@ -2000,7 +1992,8 @@ TEST_F(QueryTest, findNSEC3) {
     // returned.
     // returned.
     {
     {
         SCOPED_TRACE("nxdomain, non recursive");
         SCOPED_TRACE("nxdomain, non recursive");
-        nsec3Check(false, 4, nsec3_www_txt,
+        nsec3Check(false, 4,
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain.example.com"),
                    mock_finder->findNSEC3(Name("nxdomain.example.com"),
                                           false));
                                           false));
     }
     }
@@ -2010,7 +2003,8 @@ TEST_F(QueryTest, findNSEC3) {
     {
     {
         SCOPED_TRACE("nxdomain, recursive");
         SCOPED_TRACE("nxdomain, recursive");
         nsec3Check(true, expected_closest_labels,
         nsec3Check(true, expected_closest_labels,
-                   string(nsec3_apex_txt) + string(nsec3_www_txt),
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt + "\n" +
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain.example.com"), true));
                    mock_finder->findNSEC3(Name("nxdomain.example.com"), true));
     }
     }
 
 
@@ -2019,7 +2013,8 @@ TEST_F(QueryTest, findNSEC3) {
     {
     {
         SCOPED_TRACE("nxdomain, next closer != qname");
         SCOPED_TRACE("nxdomain, next closer != qname");
         nsec3Check(true, expected_closest_labels,
         nsec3Check(true, expected_closest_labels,
-                   string(nsec3_apex_txt) + string(nsec3_www_txt),
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt + "\n" +
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nx.domain.example.com"),
                    mock_finder->findNSEC3(Name("nx.domain.example.com"),
                                           true));
                                           true));
     }
     }
@@ -2027,13 +2022,15 @@ TEST_F(QueryTest, findNSEC3) {
     // In the rest of test we check hash comparison for wrap around cases.
     // In the rest of test we check hash comparison for wrap around cases.
     {
     {
         SCOPED_TRACE("largest");
         SCOPED_TRACE("largest");
-        nsec3Check(false, 4, nsec3_apex_txt,
+        nsec3Check(false, 4,
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain2.example.com"),
                    mock_finder->findNSEC3(Name("nxdomain2.example.com"),
                                           false));
                                           false));
     }
     }
     {
     {
         SCOPED_TRACE("smallest");
         SCOPED_TRACE("smallest");
-        nsec3Check(false, 4, nsec3_www_txt,
+        nsec3Check(false, 4,
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain3.example.com"),
                    mock_finder->findNSEC3(Name("nxdomain3.example.com"),
                                           false));
                                           false));
     }
     }
@@ -2516,8 +2513,7 @@ TEST_F(QueryTest, DuplicateNameRemoval) {
     EXPECT_EQ(0, message.getRRCount(Message::SECTION_ADDITIONAL));
     EXPECT_EQ(0, message.getRRCount(Message::SECTION_ADDITIONAL));
 
 
     // ... and fill it.
     // ... and fill it.
-    Query::ResponseCreator().create(message, answer, authority, additional,
-                                    false);
+    Query::ResponseCreator().create(message, answer, authority, additional);
 
 
     // Check counts in each section.  Note that these are RR counts,
     // Check counts in each section.  Note that these are RR counts,
     // not RRset counts.
     // not RRset counts.

+ 5 - 8
src/lib/cache/message_entry.cc

@@ -110,8 +110,7 @@ MessageEntry::getRRsetEntries(vector<RRsetEntryPtr>& rrset_entry_vec,
 void
 void
 MessageEntry::addRRset(isc::dns::Message& message,
 MessageEntry::addRRset(isc::dns::Message& message,
                        const vector<RRsetEntryPtr>& rrset_entry_vec,
                        const vector<RRsetEntryPtr>& rrset_entry_vec,
-                       const isc::dns::Message::Section& section,
-                       bool dnssec_need)
+                       const isc::dns::Message::Section& section)
 {
 {
     uint16_t start_index = 0;
     uint16_t start_index = 0;
     uint16_t end_index = answer_count_;
     uint16_t end_index = answer_count_;
@@ -126,8 +125,7 @@ MessageEntry::addRRset(isc::dns::Message& message,
     }
     }
 
 
     for (uint16_t index = start_index; index < end_index; ++index) {
     for (uint16_t index = start_index; index < end_index; ++index) {
-        message.addRRset(section, rrset_entry_vec[index]->getRRset(),
-                         dnssec_need);
+        message.addRRset(section, rrset_entry_vec[index]->getRRset());
     }
     }
 }
 }
 
 
@@ -156,10 +154,9 @@ MessageEntry::genMessage(const time_t& time_now,
         msg.setHeaderFlag(Message::HEADERFLAG_AA, false);
         msg.setHeaderFlag(Message::HEADERFLAG_AA, false);
         msg.setHeaderFlag(Message::HEADERFLAG_TC, headerflag_tc_);
         msg.setHeaderFlag(Message::HEADERFLAG_TC, headerflag_tc_);
 
 
-        bool dnssec_need = msg.getEDNS().get();
-        addRRset(msg, rrset_entry_vec, Message::SECTION_ANSWER, dnssec_need);
-        addRRset(msg, rrset_entry_vec, Message::SECTION_AUTHORITY, dnssec_need);
-        addRRset(msg, rrset_entry_vec, Message::SECTION_ADDITIONAL, dnssec_need);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_ANSWER);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_AUTHORITY);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_ADDITIONAL);
 
 
         return (true);
         return (true);
     }
     }

+ 1 - 3
src/lib/cache/message_entry.h

@@ -154,11 +154,9 @@ protected:
     /// \param rrset_entry_vec vector for rrset entries in
     /// \param rrset_entry_vec vector for rrset entries in
     ///        different sections.
     ///        different sections.
     /// \param section The section to add to
     /// \param section The section to add to
-    /// \param dnssec_need need dnssec records or not.
     void addRRset(isc::dns::Message& message,
     void addRRset(isc::dns::Message& message,
                   const std::vector<RRsetEntryPtr>& rrset_entry_vec,
                   const std::vector<RRsetEntryPtr>& rrset_entry_vec,
-                  const isc::dns::Message::Section& section,
-                  bool dnssec_need);
+                  const isc::dns::Message::Section& section);
 
 
     /// \brief Get the all the rrset entries for the message entry.
     /// \brief Get the all the rrset entries for the message entry.
     ///
     ///

+ 1 - 1
src/lib/datasrc/Makefile.am

@@ -29,7 +29,7 @@ libb10_datasrc_la_SOURCES += cache.h cache.cc
 libb10_datasrc_la_SOURCES += rbnode_rrset.h
 libb10_datasrc_la_SOURCES += rbnode_rrset.h
 libb10_datasrc_la_SOURCES += rbtree.h
 libb10_datasrc_la_SOURCES += rbtree.h
 libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
 libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
-libb10_datasrc_la_SOURCES += zone.h zone_finder_context.cc
+libb10_datasrc_la_SOURCES += zone.h zone_finder.cc zone_finder_context.cc
 libb10_datasrc_la_SOURCES += result.h
 libb10_datasrc_la_SOURCES += result.h
 libb10_datasrc_la_SOURCES += logger.h logger.cc
 libb10_datasrc_la_SOURCES += logger.h logger.cc
 libb10_datasrc_la_SOURCES += client.h iterator.h
 libb10_datasrc_la_SOURCES += client.h iterator.h

+ 2 - 2
src/lib/datasrc/data_source.cc

@@ -564,12 +564,12 @@ addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
         if (rrset->getType() == RRType::RRSIG() ||
         if (rrset->getType() == RRType::RRSIG() ||
             !m.hasRRset(sect, rrset->getName(), rrset->getClass(),
             !m.hasRRset(sect, rrset->getName(), rrset->getClass(),
                         rrset->getType())) {
                         rrset->getType())) {
-            m.addRRset(sect, rrset, false);
+            m.addRRset(sect, rrset);
         }
         }
     } else {
     } else {
         if (!m.hasRRset(sect, rrset->getName(), rrset->getClass(),
         if (!m.hasRRset(sect, rrset->getName(), rrset->getClass(),
                         rrset->getType())) {
                         rrset->getType())) {
-            m.addRRset(sect, rrset, q.wantDnssec());
+            m.addRRset(sect, rrset);
         }
         }
     }
     }
 }
 }

+ 32 - 16
src/lib/datasrc/database.cc

@@ -157,7 +157,7 @@ public:
         const isc::dns::RRType& type_covered =
         const isc::dns::RRType& type_covered =
             static_cast<isc::dns::rdata::generic::RRSIG*>(
             static_cast<isc::dns::rdata::generic::RRSIG*>(
                 sig_rdata.get())->typeCovered();
                 sig_rdata.get())->typeCovered();
-        sigs[type_covered].push_back(sig_rdata);
+        sigs_[type_covered].push_back(sig_rdata);
     }
     }
 
 
     // If the store contains signatures for the type of the given
     // If the store contains signatures for the type of the given
@@ -165,21 +165,26 @@ public:
     void appendSignatures(isc::dns::RRsetPtr& rrset) const {
     void appendSignatures(isc::dns::RRsetPtr& rrset) const {
         std::map<isc::dns::RRType,
         std::map<isc::dns::RRType,
                  std::vector<isc::dns::rdata::RdataPtr> >::const_iterator
                  std::vector<isc::dns::rdata::RdataPtr> >::const_iterator
-            found = sigs.find(rrset->getType());
-        if (found != sigs.end()) {
+            found = sigs_.find(rrset->getType());
+        if (found != sigs_.end()) {
             BOOST_FOREACH(isc::dns::rdata::RdataPtr sig, found->second) {
             BOOST_FOREACH(isc::dns::rdata::RdataPtr sig, found->second) {
                 rrset->addRRsig(sig);
                 rrset->addRRsig(sig);
             }
             }
         }
         }
     }
     }
 
 
+    bool empty() const {
+        return (sigs_.empty());
+    }
+
 private:
 private:
-    std::map<isc::dns::RRType, std::vector<isc::dns::rdata::RdataPtr> > sigs;
+    std::map<isc::dns::RRType, std::vector<isc::dns::rdata::RdataPtr> > sigs_;
 };
 };
 }
 }
 
 
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
+                                  bool sigs,
                                   const string* construct_name, bool any,
                                   const string* construct_name, bool any,
                                   DatabaseAccessor::IteratorContextPtr context)
                                   DatabaseAccessor::IteratorContextPtr context)
 {
 {
@@ -213,7 +218,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
         try {
         try {
             const RRType cur_type(columns[DatabaseAccessor::TYPE_COLUMN]);
             const RRType cur_type(columns[DatabaseAccessor::TYPE_COLUMN]);
 
 
-            if (cur_type == RRType::RRSIG()) {
+            if (sigs && (cur_type == RRType::RRSIG())) {
                 // If we get signatures before we get the actual data, we
                 // If we get signatures before we get the actual data, we
                 // can't know which ones to keep and which to drop...
                 // can't know which ones to keep and which to drop...
                 // So we keep a separate store of any signature that may be
                 // So we keep a separate store of any signature that may be
@@ -228,7 +233,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
             if (types.find(cur_type) != types.end() || any) {
             if (types.find(cur_type) != types.end() || any) {
                 // This type is requested, so put it into result
                 // This type is requested, so put it into result
                 const RRTTL cur_ttl(columns[DatabaseAccessor::TTL_COLUMN]);
                 const RRTTL cur_ttl(columns[DatabaseAccessor::TTL_COLUMN]);
-                // Ths sigtype column was an optimization for finding the
+                // The sigtype column was an optimization for finding the
                 // relevant RRSIG RRs for a lookup. Currently this column is
                 // relevant RRSIG RRs for a lookup. Currently this column is
                 // not used in this revised datasource implementation. We
                 // not used in this revised datasource implementation. We
                 // should either start using it again, or remove it from use
                 // should either start using it again, or remove it from use
@@ -276,10 +281,12 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
         isc_throw(DataSourceError, "CNAME shares domain " << name <<
         isc_throw(DataSourceError, "CNAME shares domain " << name <<
                   " with something else");
                   " with something else");
     }
     }
-    // Add signatures to all found RRsets
-    for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
-         i != result.end(); ++ i) {
-        sig_store.appendSignatures(i->second);
+    if (!sig_store.empty()) {
+        // Add signatures to all found RRsets
+        for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
+             i != result.end(); ++ i) {
+            sig_store.appendSignatures(i->second);
+        }
     }
     }
     if (records_found && any) {
     if (records_found && any) {
         result[RRType::ANY()] = RRsetPtr();
         result[RRType::ANY()] = RRsetPtr();
@@ -448,7 +455,9 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
         // Look if there's NS or DNAME at this point of the tree, but ignore
         // Look if there's NS or DNAME at this point of the tree, but ignore
         // the NS RRs at the apex of the zone.
         // the NS RRs at the apex of the zone.
         const FoundRRsets found = getRRsets(superdomain.toText(),
         const FoundRRsets found = getRRsets(superdomain.toText(),
-                                            DELEGATION_TYPES());
+                                            DELEGATION_TYPES(),
+                                            ((options & FIND_DNSSEC) ==
+                                             FIND_DNSSEC));
         if (found.first) {
         if (found.first) {
             // This node contains either NS or DNAME RRs so it does exist.
             // This node contains either NS or DNAME RRs so it does exist.
             const FoundIterator nsi(found.second.find(RRType::NS()));
             const FoundIterator nsi(found.second.find(RRType::NS()));
@@ -581,6 +590,8 @@ DatabaseClient::Finder::findWildcardMatch(
         // RFC 4592 section 4.4).
         // RFC 4592 section 4.4).
         // Search for a match.  The types are the same as with original query.
         // Search for a match.  The types are the same as with original query.
         const FoundRRsets found = getRRsets(wildcard, final_types,
         const FoundRRsets found = getRRsets(wildcard, final_types,
+                                            ((options & FIND_DNSSEC) ==
+                                             FIND_DNSSEC),
                                             &construct_name,
                                             &construct_name,
                                             type == RRType::ANY());
                                             type == RRType::ANY());
         if (found.first) {
         if (found.first) {
@@ -685,7 +696,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // such cases).
             // such cases).
             const string origin = finder_.getOrigin().toText();
             const string origin = finder_.getOrigin().toText();
             const FoundRRsets nsec3_found =
             const FoundRRsets nsec3_found =
-                finder_.getRRsets(origin, NSEC3PARAM_TYPES());
+                finder_.getRRsets(origin, NSEC3PARAM_TYPES(), true);
             const FoundIterator nfi=
             const FoundIterator nfi=
                 nsec3_found.second.find(RRType::NSEC3PARAM());
                 nsec3_found.second.find(RRType::NSEC3PARAM());
             is_nsec3_ = (nfi != nsec3_found.second.end());
             is_nsec3_ = (nfi != nsec3_found.second.end());
@@ -696,7 +707,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // described in Section 10.4 of RFC 5155.
             // described in Section 10.4 of RFC 5155.
             if (!is_nsec3_) {
             if (!is_nsec3_) {
                 const FoundRRsets nsec_found =
                 const FoundRRsets nsec_found =
-                    finder_.getRRsets(origin, NSEC_TYPES());
+                    finder_.getRRsets(origin, NSEC_TYPES(), true);
                 const FoundIterator nfi =
                 const FoundIterator nfi =
                     nsec_found.second.find(RRType::NSEC());
                     nsec_found.second.find(RRType::NSEC());
                 is_nsec_ = (nfi != nsec_found.second.end());
                 is_nsec_ = (nfi != nsec_found.second.end());
@@ -749,7 +760,7 @@ DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(const Name &name,
         const Name& nsec_name =
         const Name& nsec_name =
             covering ? finder_.findPreviousName(name) : name;
             covering ? finder_.findPreviousName(name) : name;
         const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
         const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
-                                                    NSEC_TYPES());
+                                                    NSEC_TYPES(), true);
         const FoundIterator nci = found.second.find(RRType::NSEC());
         const FoundIterator nci = found.second.find(RRType::NSEC());
         if (nci != found.second.end()) {
         if (nci != found.second.end()) {
             return (nci->second);
             return (nci->second);
@@ -976,6 +987,8 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
     WantedTypes final_types(FINAL_TYPES());
     WantedTypes final_types(FINAL_TYPES());
     final_types.insert(type);
     final_types.insert(type);
     const FoundRRsets found = getRRsets(name.toText(), final_types,
     const FoundRRsets found = getRRsets(name.toText(), final_types,
+                                        ((options & FIND_DNSSEC) ==
+                                         FIND_DNSSEC),
                                         NULL, type == RRType::ANY());
                                         NULL, type == RRType::ANY());
     FindDNSSECContext dnssec_ctx(*this, options);
     FindDNSSECContext dnssec_ctx(*this, options);
     if (found.first) {
     if (found.first) {
@@ -1009,7 +1022,8 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
     // Now, we need to get the NSEC3 params from the apex and create the hash
     // Now, we need to get the NSEC3 params from the apex and create the hash
     // creator for it.
     // creator for it.
     const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
     const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
-                                           NSEC3PARAM_TYPES()));
+                                           NSEC3PARAM_TYPES(),
+                                           true));
     const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
     const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
     if (!nsec3param.first || param == nsec3param.second.end()) {
     if (!nsec3param.first || param == nsec3param.second.end()) {
         // No NSEC3 params? :-(
         // No NSEC3 params? :-(
@@ -1049,6 +1063,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
         }
         }
 
 
         const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
         const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
+                                          true,
                                           NULL, false, context));
                                           NULL, false, context));
 
 
         if (nsec3.first) {
         if (nsec3.first) {
@@ -1074,7 +1089,8 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
                 arg(labels).arg(prevHash);
                 arg(labels).arg(prevHash);
             context = accessor_->getNSEC3Records(prevHash, zone_id_);
             context = accessor_->getNSEC3Records(prevHash, zone_id_);
             const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
             const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
-                                                   NSEC3_TYPES(), NULL, false,
+                                                   NSEC3_TYPES(), true,
+                                                   NULL, false,
                                                    context));
                                                    context));
 
 
             if (!prev_nsec3.first) {
             if (!prev_nsec3.first) {

+ 3 - 0
src/lib/datasrc/database.h

@@ -963,6 +963,8 @@ public:
         ///
         ///
         /// \param name Which domain name should be scanned.
         /// \param name Which domain name should be scanned.
         /// \param types List of types the caller is interested in.
         /// \param types List of types the caller is interested in.
+        /// \param sigs Return RRSIGs if true is passed. Otherwise, no
+        ///     associated RRSIGs are set on the returned RRsets.
         /// \param construct_name If this is NULL, the resulting RRsets have
         /// \param construct_name If this is NULL, the resulting RRsets have
         ///     their name set to name. If it is not NULL, it overrides the
         ///     their name set to name. If it is not NULL, it overrides the
         ///     name and uses this one (this can be used for wildcard
         ///     name and uses this one (this can be used for wildcard
@@ -984,6 +986,7 @@ public:
         ///     database or the database contains bad data.
         ///     database or the database contains bad data.
         FoundRRsets getRRsets(const std::string& name,
         FoundRRsets getRRsets(const std::string& name,
                               const WantedTypes& types,
                               const WantedTypes& types,
+                              bool sigs,
                               const std::string* construct_name = NULL,
                               const std::string* construct_name = NULL,
                               bool any = false,
                               bool any = false,
                               DatabaseAccessor::IteratorContextPtr srcContext =
                               DatabaseAccessor::IteratorContextPtr srcContext =

+ 26 - 6
src/lib/datasrc/memory_datasrc.cc

@@ -738,7 +738,24 @@ prepareRRset(const Name& name, const ConstRBNodeRRsetPtr& rrset, bool rename,
         rrset->copyAdditionalNodes(*result);
         rrset->copyAdditionalNodes(*result);
         return (result);
         return (result);
     } else {
     } else {
-        return (rrset);
+        ConstRRsetPtr sig_rrset = rrset->getRRsig();
+        if (sig_rrset &&
+            ((options & ZoneFinder::FIND_DNSSEC) == 0)) {
+            RRsetPtr result_base(new RRset(name, rrset->getClass(),
+                                           rrset->getType(),
+                                           rrset->getTTL()));
+            for (RdataIteratorPtr i(rrset->getRdataIterator());
+                 !i->isLast();
+                 i->next()) {
+                result_base->addRdata(i->getCurrent());
+            }
+
+            RBNodeRRsetPtr result(new RBNodeRRset(result_base));
+            rrset->copyAdditionalNodes(*result);
+            return (result);
+        } else {
+            return (rrset);
+        }
     }
     }
 }
 }
 
 
@@ -795,10 +812,10 @@ protected:
             }
             }
             BOOST_FOREACH(const DomainPair& dom_it, *found_node_->getData()) {
             BOOST_FOREACH(const DomainPair& dom_it, *found_node_->getData()) {
                 getAdditionalForRRset(*dom_it.second, requested_types,
                 getAdditionalForRRset(*dom_it.second, requested_types,
-                                      result);
+                                      result, options_);
             }
             }
         } else {
         } else {
-            getAdditionalForRRset(*rrset_, requested_types, result);
+            getAdditionalForRRset(*rrset_, requested_types, result, options_);
         }
         }
     }
     }
 
 
@@ -809,7 +826,8 @@ private:
     // type for each node.
     // type for each node.
     static void getAdditionalForRRset(const RBNodeRRset& rrset,
     static void getAdditionalForRRset(const RBNodeRRset& rrset,
                                       const vector<RRType>& requested_types,
                                       const vector<RRType>& requested_types,
-                                      vector<ConstRRsetPtr>& result)
+                                      vector<ConstRRsetPtr>& result,
+                                      ZoneFinder::FindOptions options)
     {
     {
         const vector<AdditionalNodeInfo>* additionals_ =
         const vector<AdditionalNodeInfo>* additionals_ =
             rrset.getAdditionalNodes();
             rrset.getAdditionalNodes();
@@ -836,11 +854,13 @@ private:
                     // in case the caller has the same RRset but as a result
                     // in case the caller has the same RRset but as a result
                     // of normal find() and needs to know they are of the same
                     // of normal find() and needs to know they are of the same
                     // kind; otherwise we simply use the stored RBNodeRRset.
                     // kind; otherwise we simply use the stored RBNodeRRset.
+                    ConstRRsetPtr rp;
                     if (wild_expanded) {
                     if (wild_expanded) {
-                        result.push_back(found->second->getUnderlyingRRset());
+                        rp = found->second->getUnderlyingRRset();
                     } else {
                     } else {
-                        result.push_back(found->second);
+                        rp = found->second;
                     }
                     }
+                    result.push_back(ZoneFinder::stripRRsigs(rp, options));
                 }
                 }
             }
             }
         }
         }

+ 18 - 6
src/lib/datasrc/tests/Makefile.am

@@ -46,17 +46,21 @@ common_ldadd += $(GTEST_LDADD) $(SQLITE_LIBS)
 
 
 # The general tests
 # The general tests
 run_unittests_SOURCES = $(common_sources)
 run_unittests_SOURCES = $(common_sources)
-run_unittests_SOURCES += datasrc_unittest.cc
-run_unittests_SOURCES += static_unittest.cc
-run_unittests_SOURCES += query_unittest.cc
-run_unittests_SOURCES += cache_unittest.cc
+
+# Commented out by ticket #2165. If you re-enable these, please modify
+# EXTRA_DIST at the bottom of this file.
+#run_unittests_SOURCES += datasrc_unittest.cc
+#run_unittests_SOURCES += static_unittest.cc
+#run_unittests_SOURCES += query_unittest.cc
+#run_unittests_SOURCES += cache_unittest.cc
+#run_unittests_SOURCES += sqlite3_unittest.cc
+#run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
+
 run_unittests_SOURCES += test_client.h test_client.cc
 run_unittests_SOURCES += test_client.h test_client.cc
-run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
 run_unittests_SOURCES += rbtree_unittest.cc
 run_unittests_SOURCES += rbtree_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
 run_unittests_SOURCES += client_unittest.cc
 run_unittests_SOURCES += client_unittest.cc
 run_unittests_SOURCES += database_unittest.cc
 run_unittests_SOURCES += database_unittest.cc
-run_unittests_SOURCES += sqlite3_unittest.cc
 run_unittests_SOURCES += sqlite3_accessor_unittest.cc
 run_unittests_SOURCES += sqlite3_accessor_unittest.cc
 run_unittests_SOURCES += memory_datasrc_unittest.cc
 run_unittests_SOURCES += memory_datasrc_unittest.cc
 run_unittests_SOURCES += rbnode_rrset_unittest.cc
 run_unittests_SOURCES += rbnode_rrset_unittest.cc
@@ -118,3 +122,11 @@ EXTRA_DIST += testdata/new_minor_schema.sqlite3
 EXTRA_DIST += testdata/newschema.sqlite3
 EXTRA_DIST += testdata/newschema.sqlite3
 EXTRA_DIST += testdata/oldschema.sqlite3
 EXTRA_DIST += testdata/oldschema.sqlite3
 EXTRA_DIST += testdata/static.zone
 EXTRA_DIST += testdata/static.zone
+
+# Added by ticket #2165
+EXTRA_DIST += datasrc_unittest.cc
+EXTRA_DIST += static_unittest.cc
+EXTRA_DIST += query_unittest.cc
+EXTRA_DIST += cache_unittest.cc
+EXTRA_DIST += sqlite3_unittest.cc
+EXTRA_DIST += test_datasrc.h test_datasrc.cc

+ 48 - 12
src/lib/datasrc/tests/database_unittest.cc

@@ -1711,17 +1711,22 @@ doFindTest(ZoneFinder& finder,
         checkRRset(result->rrset, expected_name != Name(".") ? expected_name :
         checkRRset(result->rrset, expected_name != Name(".") ? expected_name :
                    name, finder.getClass(), expected_type, expected_ttl,
                    name, finder.getClass(), expected_type, expected_ttl,
                    expected_rdatas);
                    expected_rdatas);
-
-        if (!expected_sig_rdatas.empty() && result->rrset->getRRsig()) {
-            checkRRset(result->rrset->getRRsig(), expected_name != Name(".") ?
-                       expected_name : name, finder.getClass(),
-                       isc::dns::RRType::RRSIG(), expected_ttl,
-                       expected_sig_rdatas);
-        } else if (expected_sig_rdatas.empty()) {
+        if ((options & ZoneFinder::FIND_DNSSEC) == ZoneFinder::FIND_DNSSEC) {
+            if (!expected_sig_rdatas.empty() && result->rrset->getRRsig()) {
+                checkRRset(result->rrset->getRRsig(),
+                           expected_name != Name(".") ? expected_name : name,
+                           finder.getClass(),
+                           isc::dns::RRType::RRSIG(), expected_ttl,
+                           expected_sig_rdatas);
+            } else if (expected_sig_rdatas.empty()) {
+                EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
+                    "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
+            } else {
+                ADD_FAILURE() << "Missing RRSIG";
+            }
+        } else if (result->rrset->getRRsig()) {
             EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
             EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
                 "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
                 "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
-        } else {
-            ADD_FAILURE() << "Missing RRSIG";
         }
         }
     } else if (expected_rdatas.empty()) {
     } else if (expected_rdatas.empty()) {
         EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset) <<
         EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset) <<
@@ -2842,6 +2847,35 @@ TYPED_TEST(DatabaseClientTest, anyFromFind) {
                                          RRType::ANY()), isc::Unexpected);
                                          RRType::ANY()), isc::Unexpected);
 }
 }
 
 
+TYPED_TEST(DatabaseClientTest, findRRSIGsWithoutDNSSEC) {
+    // Trying to find RRSIG records directly should work even if
+    // FIND_DNSSEC flag is not specified.
+
+    boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+    ConstZoneFinderContextPtr result =
+        finder->find(isc::dns::Name("signed1.example.org."), RRType::RRSIG());
+
+    EXPECT_EQ(ZoneFinder::SUCCESS, result->code);
+
+    std::vector<std::string> expected_rdata;
+    expected_rdata.push_back(TEST_RECORDS[10][4]);
+    expected_rdata.push_back(TEST_RECORDS[11][4]);
+    expected_rdata.push_back(TEST_RECORDS[14][4]);
+
+    RdataIteratorPtr it(result->rrset->getRdataIterator());
+    std::vector<std::string> rdata;
+    while (!it->isLast()) {
+        rdata.push_back(it->getCurrent().toText());
+        it->next();
+    }
+    std::sort(rdata.begin(), rdata.end());
+    std::sort(expected_rdata.begin(), expected_rdata.end());
+    ASSERT_EQ(expected_rdata.size(), rdata.size());
+    for (size_t i(0); i < expected_rdata.size(); ++ i) {
+        EXPECT_EQ(expected_rdata[i], rdata[i]);
+    }
+}
+
 // Test the findAll method.
 // Test the findAll method.
 TYPED_TEST(DatabaseClientTest, getAll) {
 TYPED_TEST(DatabaseClientTest, getAll) {
     // The domain doesn't exist, so we must get the right NSEC
     // The domain doesn't exist, so we must get the right NSEC
@@ -3636,9 +3670,11 @@ TYPED_TEST(DatabaseClientTest, compoundUpdate) {
 TYPED_TEST(DatabaseClientTest, invalidRdata) {
 TYPED_TEST(DatabaseClientTest, invalidRdata) {
     boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
     boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
 
 
-    EXPECT_THROW(finder->find(Name("invalidrdata.example.org."), RRType::A()),
+    EXPECT_THROW(finder->find(Name("invalidrdata.example.org."),
+                              RRType::A()),
                  DataSourceError);
                  DataSourceError);
-    EXPECT_THROW(finder->find(Name("invalidrdata2.example.org."), RRType::A()),
+    EXPECT_THROW(finder->find(Name("invalidrdata2.example.org."),
+                              RRType::A(), ZoneFinder::FIND_DNSSEC),
                  DataSourceError);
                  DataSourceError);
 }
 }
 
 
@@ -4053,7 +4089,7 @@ TYPED_TEST(DatabaseClientTest, findNSEC3) {
     this->current_accessor_->enableNSEC3();
     this->current_accessor_->enableNSEC3();
 
 
     // The rest is in the function, it is shared with in-memory tests
     // The rest is in the function, it is shared with in-memory tests
-    performNSEC3Test(*finder);
+    performNSEC3Test(*finder, true);
 }
 }
 
 
 }
 }

+ 22 - 13
src/lib/datasrc/tests/faked_nsec3.cc

@@ -34,6 +34,11 @@ const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
     "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
     "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
 const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
 const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
+const char* const nsec3_rrsig_common2 = " 300 IN RRSIG NSEC3 5 4 7200 "
+    "20100410172647 20100311172647 63192 example.org. gNIVj4T8t51fEU6k"
+    "OPpvK7HOGBFZGbalN5ZKmInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/Lis2M6yUWH"
+    "yXbNbj/QqwqgadG5dhxTArfuR02xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o8g"
+    "HSY5vYTtothcZQa4BMKhmGQEk=";
 const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
 const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
 const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
 const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
 const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
 const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
@@ -93,8 +98,7 @@ void
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
                const string& expected_closest,
                const string& expected_closest,
                const string& expected_next,
                const string& expected_next,
-               const ZoneFinder::FindNSEC3Result& result,
-               bool expected_sig)
+               const ZoneFinder::FindNSEC3Result& result)
 {
 {
     EXPECT_EQ(expected_matched, result.matched);
     EXPECT_EQ(expected_matched, result.matched);
     // Convert to int so the error messages would be more readable:
     // Convert to int so the error messages would be more readable:
@@ -104,9 +108,6 @@ findNSEC3Check(bool expected_matched, uint8_t expected_labels,
     vector<ConstRRsetPtr> actual_rrsets;
     vector<ConstRRsetPtr> actual_rrsets;
     ASSERT_TRUE(result.closest_proof);
     ASSERT_TRUE(result.closest_proof);
     actual_rrsets.push_back(result.closest_proof);
     actual_rrsets.push_back(result.closest_proof);
-    if (expected_sig) {
-        actual_rrsets.push_back(result.closest_proof->getRRsig());
-    }
     rrsetsCheck(expected_closest, actual_rrsets.begin(),
     rrsetsCheck(expected_closest, actual_rrsets.begin(),
                 actual_rrsets.end());
                 actual_rrsets.end());
 
 
@@ -116,30 +117,38 @@ findNSEC3Check(bool expected_matched, uint8_t expected_labels,
     } else {
     } else {
         ASSERT_TRUE(result.next_proof);
         ASSERT_TRUE(result.next_proof);
         actual_rrsets.push_back(result.next_proof);
         actual_rrsets.push_back(result.next_proof);
-        if (expected_sig) {
-            actual_rrsets.push_back(result.next_proof->getRRsig());
-        }
         rrsetsCheck(expected_next, actual_rrsets.begin(),
         rrsetsCheck(expected_next, actual_rrsets.begin(),
                     actual_rrsets.end());
                     actual_rrsets.end());
     }
     }
 }
 }
 
 
 void
 void
-performNSEC3Test(ZoneFinder &finder) {
+performNSEC3Test(ZoneFinder &finder, bool rrsigs_exist) {
     // Parameter validation: the query name must be in or below the zone
     // Parameter validation: the query name must be in or below the zone
     EXPECT_THROW(finder.findNSEC3(Name("example.com"), false), OutOfZone);
     EXPECT_THROW(finder.findNSEC3(Name("example.com"), false), OutOfZone);
     EXPECT_THROW(finder.findNSEC3(Name("org"), true), OutOfZone);
     EXPECT_THROW(finder.findNSEC3(Name("org"), true), OutOfZone);
 
 
     const Name origin("example.org");
     const Name origin("example.org");
-    const string apex_nsec3_text = string(apex_hash) + ".example.org." +
+    string apex_nsec3_text = string(apex_hash) + ".example.org." +
         string(nsec3_common);
         string(nsec3_common);
-    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+    string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
         string(nsec3_common);
         string(nsec3_common);
-    const string w_nsec3_text = string(w_hash) + ".example.org." +
+    string w_nsec3_text = string(w_hash) + ".example.org." +
         string(nsec3_common);
         string(nsec3_common);
-    const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
+    string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
         string(nsec3_common);
         string(nsec3_common);
 
 
+    if (rrsigs_exist) {
+        apex_nsec3_text += "\n" + string(apex_hash) + ".example.org." +
+            string(nsec3_rrsig_common2);
+        ns1_nsec3_text += "\n" + string(ns1_hash) + ".example.org." +
+            string(nsec3_rrsig_common2);
+        w_nsec3_text += "\n" + string(w_hash) + ".example.org." +
+            string(nsec3_rrsig_common2);
+        zzz_nsec3_text += "\n" + string(zzz_hash) + ".example.org." +
+            string(nsec3_rrsig_common2);
+    }
+
     // Apex name.  It should have a matching NSEC3.
     // Apex name.  It should have a matching NSEC3.
     {
     {
         SCOPED_TRACE("apex, non recursive mode");
         SCOPED_TRACE("apex, non recursive mode");

+ 2 - 3
src/lib/datasrc/tests/faked_nsec3.h

@@ -69,13 +69,12 @@ void
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
                const std::string& expected_closest,
                const std::string& expected_closest,
                const std::string& expected_next,
                const std::string& expected_next,
-               const isc::datasrc::ZoneFinder::FindNSEC3Result& result,
-               bool expected_sig = false);
+               const isc::datasrc::ZoneFinder::FindNSEC3Result& result);
 
 
 // Perform the shared part of NSEC3 test (shared between in-memory and database
 // Perform the shared part of NSEC3 test (shared between in-memory and database
 // tests).
 // tests).
 void
 void
-performNSEC3Test(ZoneFinder &finder);
+performNSEC3Test(ZoneFinder &finder, bool rrsigs_exist = false);
 
 
 }
 }
 }
 }

+ 5 - 3
src/lib/datasrc/tests/memory_datasrc_unittest.cc

@@ -1263,12 +1263,14 @@ TEST_F(InMemoryZoneFinderTest, loadFromIterator) {
     RRsetPtr expected_answer = textToRRset(soa_txt, RRClass::IN(), origin_);
     RRsetPtr expected_answer = textToRRset(soa_txt, RRClass::IN(), origin_);
     expected_answer->addRRsig(textToRRset(soa_sig_txt));
     expected_answer->addRRsig(textToRRset(soa_sig_txt));
     findTest(origin_, RRType::SOA(), ZoneFinder::SUCCESS, true,
     findTest(origin_, RRType::SOA(), ZoneFinder::SUCCESS, true,
-             expected_answer);
+             expected_answer, ZoneFinder::RESULT_DEFAULT, NULL,
+             ZoneFinder::FIND_DNSSEC);
 
 
     expected_answer = textToRRset(a_txt);
     expected_answer = textToRRset(a_txt);
     expected_answer->addRRsig(textToRRset(a_sig_txt));
     expected_answer->addRRsig(textToRRset(a_sig_txt));
     findTest(Name("ns1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
     findTest(Name("ns1.example.org"), RRType::A(), ZoneFinder::SUCCESS, true,
-             expected_answer);
+             expected_answer, ZoneFinder::RESULT_DEFAULT, NULL,
+             ZoneFinder::FIND_DNSSEC);
 
 
     // File name should be (re)set to empty.
     // File name should be (re)set to empty.
     EXPECT_TRUE(zone_finder_.getFileName().empty());
     EXPECT_TRUE(zone_finder_.getFileName().empty());
@@ -2065,7 +2067,7 @@ TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
     // Then look for it.  The NSEC3 should have the RRSIG that was just added.
     // Then look for it.  The NSEC3 should have the RRSIG that was just added.
     findNSEC3Check(true, origin_.getLabelCount(),
     findNSEC3Check(true, origin_.getLabelCount(),
                    nsec3_text + "\n" + nsec3_rrsig_text, "",
                    nsec3_text + "\n" + nsec3_rrsig_text, "",
-                   zone_finder_.findNSEC3(Name("example.org"), false), true);
+                   zone_finder_.findNSEC3(Name("example.org"), false));
 
 
     // Duplicate add of RRSIG for the same NSEC3 is prohibited.
     // Duplicate add of RRSIG for the same NSEC3 is prohibited.
     EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),
     EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),

+ 4 - 0
src/lib/datasrc/tests/zone_finder_context_unittest.cc

@@ -326,7 +326,11 @@ TEST_P(ZoneFinderContextTest, getAdditionalWithSIG) {
 
 
     ctx->getAdditional(REQUESTED_BOTH, result_sets_);
     ctx->getAdditional(REQUESTED_BOTH, result_sets_);
     rrsetsCheck("ns1.example.org. 3600 IN A 192.0.2.1\n"
     rrsetsCheck("ns1.example.org. 3600 IN A 192.0.2.1\n"
+                "ns1.example.org. 3600 IN RRSIG	A 7 3 3600 20150420235959 "
+                "20051021000000 40430 example.org. FAKEFAKE\n"
                 "ns1.example.org. 3600 IN AAAA 2001:db8::1\n"
                 "ns1.example.org. 3600 IN AAAA 2001:db8::1\n"
+                "ns1.example.org. 3600 IN RRSIG	AAAA 7 3 3600 20150420235959 "
+                "20051021000000 40430 example.org. FAKEFAKEFAKE\n"
                 "ns2.example.org. 3600 IN A 192.0.2.2\n",
                 "ns2.example.org. 3600 IN A 192.0.2.2\n",
                 result_sets_.begin(), result_sets_.end());
                 result_sets_.begin(), result_sets_.end());
 
 

+ 7 - 0
src/lib/datasrc/zone.h

@@ -134,6 +134,11 @@ protected:
     };
     };
 
 
 public:
 public:
+    /// \brief A helper function to strip RRSIGs when FIND_DNSSEC is not
+    /// requested.
+    static isc::dns::ConstRRsetPtr
+    stripRRsigs(isc::dns::ConstRRsetPtr rp, const FindOptions options);
+
     /// \brief Context of the result of a find() call.
     /// \brief Context of the result of a find() call.
     ///
     ///
     /// This class encapsulates results and (possibly) associated context
     /// This class encapsulates results and (possibly) associated context
@@ -299,7 +304,9 @@ public:
     private:
     private:
         ZoneFinder& finder_;
         ZoneFinder& finder_;
         const FindResultFlags flags_;
         const FindResultFlags flags_;
+    protected:
         const FindOptions options_;
         const FindOptions options_;
+    private:
         std::vector<isc::dns::ConstRRsetPtr> all_set_;
         std::vector<isc::dns::ConstRRsetPtr> all_set_;
     };
     };
 
 

+ 55 - 0
src/lib/datasrc/zone_finder.cc

@@ -0,0 +1,55 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/rdata.h>
+#include <dns/rrset.h>
+#include <dns/rrtype.h>
+#include <dns/rdataclass.h>
+
+#include <datasrc/zone.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace datasrc {
+
+isc::dns::ConstRRsetPtr
+ZoneFinder::stripRRsigs(isc::dns::ConstRRsetPtr rp,
+                        const FindOptions options) {
+    if (rp) {
+        isc::dns::ConstRRsetPtr sig_rrset = rp->getRRsig();
+        if (sig_rrset &&
+            ((options & ZoneFinder::FIND_DNSSEC) == 0)) {
+            isc::dns::RRsetPtr result_base
+                (new isc::dns::RRset(rp->getName(),
+                                     rp->getClass(),
+                                     rp->getType(),
+                                     rp->getTTL()));
+            for (isc::dns::RdataIteratorPtr i(rp->getRdataIterator());
+                 !i->isLast();
+                 i->next()) {
+                result_base->addRdata(i->getCurrent());
+            }
+
+            return (result_base);
+        }
+    }
+
+    return (rp);
+}
+
+} // namespace datasrc
+} // datasrc isc

+ 3 - 7
src/lib/dns/message.cc

@@ -493,7 +493,7 @@ Message::getRRCount(const Section section) const {
 }
 }
 
 
 void
 void
-Message::addRRset(const Section section, RRsetPtr rrset, const bool sign) {
+Message::addRRset(const Section section, RRsetPtr rrset) {
     if (!rrset) {
     if (!rrset) {
         isc_throw(InvalidParameter,
         isc_throw(InvalidParameter,
                   "NULL RRset is given to Message::addRRset");
                   "NULL RRset is given to Message::addRRset");
@@ -508,12 +508,7 @@ Message::addRRset(const Section section, RRsetPtr rrset, const bool sign) {
 
 
     impl_->rrsets_[section].push_back(rrset);
     impl_->rrsets_[section].push_back(rrset);
     impl_->counts_[section] += rrset->getRdataCount();
     impl_->counts_[section] += rrset->getRdataCount();
-
-    RRsetPtr sp = rrset->getRRsig();
-    if (sign && sp != NULL) {
-        impl_->rrsets_[section].push_back(sp);
-        impl_->counts_[section] += sp->getRdataCount();
-    }
+    impl_->counts_[section] += rrset->getRRsigDataCount();
 }
 }
 
 
 bool
 bool
@@ -555,6 +550,7 @@ Message::removeRRset(const Section section, RRsetIterator& iterator) {
 
 
             // Found the matching RRset so remove it & ignore rest
             // Found the matching RRset so remove it & ignore rest
             impl_->counts_[section] -= (*iterator)->getRdataCount();
             impl_->counts_[section] -= (*iterator)->getRdataCount();
+            impl_->counts_[section] -= (*iterator)->getRRsigDataCount();
             impl_->rrsets_[section].erase(i);
             impl_->rrsets_[section].erase(i);
             removed = true;
             removed = true;
             break;
             break;

+ 1 - 6
src/lib/dns/message.h

@@ -459,9 +459,6 @@ public:
     /// \brief Add a (pointer like object of) RRset to the given section
     /// \brief Add a (pointer like object of) RRset to the given section
     /// of the message.
     /// of the message.
     ///
     ///
-    /// This interface takes into account the RRSIG possibly attached to
-    /// \c rrset.  This interface design needs to be revisited later.
-    ///
     /// Note that \c addRRset() does not currently check for duplicate
     /// Note that \c addRRset() does not currently check for duplicate
     /// data before inserting RRsets.  The caller is responsible for
     /// data before inserting RRsets.  The caller is responsible for
     /// checking for these (see \c hasRRset() below).
     /// checking for these (see \c hasRRset() below).
@@ -473,9 +470,7 @@ public:
     ///
     ///
     /// \param section The message section to which the rrset is to be added
     /// \param section The message section to which the rrset is to be added
     /// \param rrset The rrset to be added.  Must not be NULL.
     /// \param rrset The rrset to be added.  Must not be NULL.
-    /// \param sign If true, and if \c rrset has associated RRSIGs, the
-    /// RRSIGs will also be added to the same section of the message.
-    void addRRset(const Section section, RRsetPtr rrset, bool sign = false);
+    void addRRset(const Section section, RRsetPtr rrset);
 
 
     /// \brief Determine whether the given section already has an RRset
     /// \brief Determine whether the given section already has an RRset
     /// matching the given name, RR class and RR type.
     /// matching the given name, RR class and RR type.

+ 3 - 7
src/lib/dns/python/message_python.cc

@@ -143,9 +143,7 @@ PyMethodDef Message_methods[] = {
     { "add_rrset", reinterpret_cast<PyCFunction>(Message_addRRset), METH_VARARGS,
     { "add_rrset", reinterpret_cast<PyCFunction>(Message_addRRset), METH_VARARGS,
       "Add an RRset to the given section of the message.\n"
       "Add an RRset to the given section of the message.\n"
       "The first argument is of type Section\n"
       "The first argument is of type Section\n"
-      "The second is of type RRset\n"
-      "The third argument is an optional Boolean specifying whether "
-      "the RRset is signed"},
+      "The second is of type RRset"},
     { "clear", reinterpret_cast<PyCFunction>(Message_clear), METH_VARARGS,
     { "clear", reinterpret_cast<PyCFunction>(Message_clear), METH_VARARGS,
       "Clears the message content (if any) and reinitialize the "
       "Clears the message content (if any) and reinitialize the "
       "message in the given mode\n"
       "message in the given mode\n"
@@ -571,17 +569,15 @@ Message_addQuestion(s_Message* self, PyObject* args) {
 
 
 PyObject*
 PyObject*
 Message_addRRset(s_Message* self, PyObject* args) {
 Message_addRRset(s_Message* self, PyObject* args) {
-    PyObject *sign = Py_False;
     int section;
     int section;
     PyObject* rrset;
     PyObject* rrset;
-    if (!PyArg_ParseTuple(args, "iO!|O!", &section, &rrset_type, &rrset,
-                          &PyBool_Type, &sign)) {
+    if (!PyArg_ParseTuple(args, "iO!", &section, &rrset_type, &rrset)) {
         return (NULL);
         return (NULL);
     }
     }
 
 
     try {
     try {
         self->cppobj->addRRset(static_cast<Message::Section>(section),
         self->cppobj->addRRset(static_cast<Message::Section>(section),
-                               PyRRset_ToRRsetPtr(rrset), sign == Py_True);
+                               PyRRset_ToRRsetPtr(rrset));
         Py_RETURN_NONE;
         Py_RETURN_NONE;
     } catch (const InvalidMessageOperation& imo) {
     } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         PyErr_SetString(po_InvalidMessageOperation, imo.what());

+ 41 - 0
src/lib/dns/rrset.cc

@@ -258,6 +258,47 @@ RRset::getRRsigDataCount() const {
     }
     }
 }
 }
 
 
+unsigned int
+RRset::toWire(OutputBuffer& buffer) const {
+    unsigned int rrs_written;
+
+    rrs_written = rrsetToWire<OutputBuffer>(*this, buffer, 0);
+    if (getRdataCount() > rrs_written) {
+        return (rrs_written);
+    }
+
+    if (rrsig_) {
+        rrs_written += rrsetToWire<OutputBuffer>(*(rrsig_.get()), buffer, 0);
+    }
+
+    return (rrs_written);
+}
+
+unsigned int
+RRset::toWire(AbstractMessageRenderer& renderer) const {
+    unsigned int rrs_written;
+
+    rrs_written =
+        rrsetToWire<AbstractMessageRenderer>(*this, renderer,
+                                             renderer.getLengthLimit());
+    if (getRdataCount() > rrs_written) {
+        renderer.setTruncated();
+        return (rrs_written);
+    }
+
+    if (rrsig_) {
+        rrs_written +=
+            rrsetToWire<AbstractMessageRenderer>(*(rrsig_.get()), renderer,
+                                                 renderer.getLengthLimit());
+    }
+
+    if (getRdataCount() + getRRsigDataCount() > rrs_written) {
+        renderer.setTruncated();
+    }
+
+    return (rrs_written);
+}
+
 namespace {
 namespace {
 class BasicRdataIterator : public RdataIterator {
 class BasicRdataIterator : public RdataIterator {
 private:
 private:

+ 11 - 0
src/lib/dns/rrset.h

@@ -828,6 +828,17 @@ public:
 
 
     virtual ~RRset();
     virtual ~RRset();
 
 
+    /// \brief Render the RRset in the wire format with name compression and
+    /// truncation handling.
+    ///
+    /// See \c AbstractRRset::toWire(MessageRenderer&)const.
+    virtual unsigned int toWire(AbstractMessageRenderer& renderer) const;
+
+    /// \brief Render the RRset in the wire format without any compression.
+    ///
+    /// See \c AbstractRRset::toWire(OutputBuffer&)const.
+    virtual unsigned int toWire(isc::util::OutputBuffer& buffer) const;
+
     /// \brief Updates the owner name of the \c RRset, including RRSIGs if any
     /// \brief Updates the owner name of the \c RRset, including RRSIGs if any
     virtual void setName(const Name& n) {
     virtual void setName(const Name& n) {
         BasicRRset::setName(n);
         BasicRRset::setName(n);

+ 58 - 24
src/lib/dns/tests/message_unittest.cc

@@ -289,32 +289,22 @@ TEST_F(MessageTest, getRRCount) {
 }
 }
 
 
 TEST_F(MessageTest, addRRset) {
 TEST_F(MessageTest, addRRset) {
-    // default case
+    // initially, we have 0
+    EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ANSWER));
+
+    // add two A RRs (unsigned)
     message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
     message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
     EXPECT_EQ(rrset_a,
     EXPECT_EQ(rrset_a,
               *message_render.beginSection(Message::SECTION_ANSWER));
               *message_render.beginSection(Message::SECTION_ANSWER));
     EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
     EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
 
 
-    // signed RRset, default case
     message_render.clear(Message::RENDER);
     message_render.clear(Message::RENDER);
-    message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
-    EXPECT_EQ(rrset_aaaa,
-              *message_render.beginSection(Message::SECTION_ANSWER));
-    EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_ANSWER));
 
 
-    // signed RRset, add with the RRSIG.  getRRCount() should return 2
-    message_render.clear(Message::RENDER);
-    message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa, true);
+    // add one AAAA RR (signed)
+    message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
     EXPECT_EQ(rrset_aaaa,
     EXPECT_EQ(rrset_aaaa,
               *message_render.beginSection(Message::SECTION_ANSWER));
               *message_render.beginSection(Message::SECTION_ANSWER));
     EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
     EXPECT_EQ(2, message_render.getRRCount(Message::SECTION_ANSWER));
-
-    // signed RRset, add explicitly without RRSIG.
-    message_render.clear(Message::RENDER);
-    message_render.addRRset(Message::SECTION_ANSWER, rrset_aaaa, false);
-    EXPECT_EQ(rrset_aaaa,
-              *message_render.beginSection(Message::SECTION_ANSWER));
-    EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_ANSWER));
 }
 }
 
 
 TEST_F(MessageTest, badAddRRset) {
 TEST_F(MessageTest, badAddRRset) {
@@ -381,9 +371,9 @@ TEST_F(MessageTest, removeRRset) {
         RRClass::IN(), RRType::A()));
         RRClass::IN(), RRType::A()));
     EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
     EXPECT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
         RRClass::IN(), RRType::AAAA()));
         RRClass::IN(), RRType::AAAA()));
-    EXPECT_EQ(3, message_render.getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(4, message_render.getRRCount(Message::SECTION_ANSWER));
 
 
-    // Locate the AAAA RRset and remove it; this has one RR in it.
+    // Locate the AAAA RRset and remove it and any associated RRSIGs
     RRsetIterator i = message_render.beginSection(Message::SECTION_ANSWER);
     RRsetIterator i = message_render.beginSection(Message::SECTION_ANSWER);
     if ((*i)->getType() == RRType::A()) {
     if ((*i)->getType() == RRType::A()) {
         ++i;
         ++i;
@@ -420,7 +410,7 @@ TEST_F(MessageTest, clearAnswerSection) {
         RRClass::IN(), RRType::A()));
         RRClass::IN(), RRType::A()));
     ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
     ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
         RRClass::IN(), RRType::AAAA()));
         RRClass::IN(), RRType::AAAA()));
-    ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ANSWER));
+    ASSERT_EQ(4, message_render.getRRCount(Message::SECTION_ANSWER));
 
 
     message_render.clearSection(Message::SECTION_ANSWER);
     message_render.clearSection(Message::SECTION_ANSWER);
     EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
     EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ANSWER, test_name,
@@ -439,7 +429,7 @@ TEST_F(MessageTest, clearAuthoritySection) {
         RRClass::IN(), RRType::A()));
         RRClass::IN(), RRType::A()));
     ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
     ASSERT_TRUE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
         RRClass::IN(), RRType::AAAA()));
         RRClass::IN(), RRType::AAAA()));
-    ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_AUTHORITY));
+    ASSERT_EQ(4, message_render.getRRCount(Message::SECTION_AUTHORITY));
 
 
     message_render.clearSection(Message::SECTION_AUTHORITY);
     message_render.clearSection(Message::SECTION_AUTHORITY);
     EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
     EXPECT_FALSE(message_render.hasRRset(Message::SECTION_AUTHORITY, test_name,
@@ -458,7 +448,7 @@ TEST_F(MessageTest, clearAdditionalSection) {
         RRClass::IN(), RRType::A()));
         RRClass::IN(), RRType::A()));
     ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
     ASSERT_TRUE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
         RRClass::IN(), RRType::AAAA()));
         RRClass::IN(), RRType::AAAA()));
-    ASSERT_EQ(3, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+    ASSERT_EQ(4, message_render.getRRCount(Message::SECTION_ADDITIONAL));
 
 
     message_render.clearSection(Message::SECTION_ADDITIONAL);
     message_render.clearSection(Message::SECTION_ADDITIONAL);
     EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
     EXPECT_FALSE(message_render.hasRRset(Message::SECTION_ADDITIONAL, test_name,
@@ -529,7 +519,7 @@ TEST_F(MessageTest, appendSection) {
         RRClass::IN(), RRType::A()));
         RRClass::IN(), RRType::A()));
 
 
     target.appendSection(Message::SECTION_ADDITIONAL, message_render);
     target.appendSection(Message::SECTION_ADDITIONAL, message_render);
-    EXPECT_EQ(3, target.getRRCount(Message::SECTION_ADDITIONAL));
+    EXPECT_EQ(4, target.getRRCount(Message::SECTION_ADDITIONAL));
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
         RRClass::IN(), RRType::A()));
         RRClass::IN(), RRType::A()));
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ADDITIONAL, test_name,
@@ -539,7 +529,7 @@ TEST_F(MessageTest, appendSection) {
     Message source2(Message::RENDER);
     Message source2(Message::RENDER);
     source2.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
     source2.addRRset(Message::SECTION_ANSWER, rrset_aaaa);
     target.appendSection(Message::SECTION_ANSWER, source2);
     target.appendSection(Message::SECTION_ANSWER, source2);
-    EXPECT_EQ(3, target.getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(4, target.getRRCount(Message::SECTION_ANSWER));
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
         RRClass::IN(), RRType::A()));
         RRClass::IN(), RRType::A()));
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
     EXPECT_TRUE(target.hasRRset(Message::SECTION_ANSWER, test_name,
@@ -766,7 +756,7 @@ TEST_F(MessageTest, toWireSigned) {
     rrset_a->addRRsig(rrset_rrsig);
     rrset_a->addRRsig(rrset_rrsig);
     EXPECT_EQ(2, rrset_a->getRRsigDataCount());
     EXPECT_EQ(2, rrset_a->getRRsigDataCount());
 
 
-    message_render.addRRset(Message::SECTION_ANSWER, rrset_a, true);
+    message_render.addRRset(Message::SECTION_ANSWER, rrset_a);
 
 
     EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
     EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
     EXPECT_EQ(4, message_render.getRRCount(Message::SECTION_ANSWER));
     EXPECT_EQ(4, message_render.getRRCount(Message::SECTION_ANSWER));
@@ -780,6 +770,50 @@ TEST_F(MessageTest, toWireSigned) {
                         renderer.getLength(), &data[0], data.size());
                         renderer.getLength(), &data[0], data.size());
 }
 }
 
 
+TEST_F(MessageTest, toWireSignedAndTruncated) {
+    message_render.setQid(0x75c1);
+    message_render.setOpcode(Opcode::QUERY());
+    message_render.setRcode(Rcode::NOERROR());
+    message_render.setHeaderFlag(Message::HEADERFLAG_QR, true);
+    message_render.setHeaderFlag(Message::HEADERFLAG_RD, true);
+    message_render.setHeaderFlag(Message::HEADERFLAG_AA, true);
+    message_render.addQuestion(Question(Name("test.example.com"), RRClass::IN(),
+                                        RRType::TXT()));
+
+    RRsetPtr rrset_txt = RRsetPtr(new RRset(test_name, RRClass::IN(),
+                                            RRType::TXT(), RRTTL(3600)));
+    rrset_txt->addRdata(generic::TXT(string(255, 'a')));
+    rrset_txt->addRdata(generic::TXT(string(255, 'b')));
+    rrset_txt->addRdata(generic::TXT(string(255, 'c')));
+    rrset_txt->addRdata(generic::TXT(string(255, 'd')));
+    rrset_txt->addRdata(generic::TXT(string(255, 'e')));
+    rrset_txt->addRdata(generic::TXT(string(255, 'f')));
+    rrset_txt->addRdata(generic::TXT(string(255, 'g')));
+    rrset_txt->addRdata(generic::TXT(string(255, 'h')));
+
+    rrset_rrsig = RRsetPtr(new RRset(test_name, RRClass::IN(),
+                                     RRType::RRSIG(), RRTTL(3600)));
+    // one signature algorithm (5 = RSA/SHA-1)
+    rrset_rrsig->addRdata(generic::RRSIG("TXT 5 3 3600 "
+                                         "20000101000000 20000201000000 "
+                                         "12345 example.com. FAKEFAKEFAKE"));
+    rrset_txt->addRRsig(rrset_rrsig);
+    EXPECT_EQ(1, rrset_txt->getRRsigDataCount());
+
+    message_render.addRRset(Message::SECTION_ANSWER, rrset_txt);
+
+    EXPECT_EQ(1, message_render.getRRCount(Message::SECTION_QUESTION));
+    EXPECT_EQ(9, message_render.getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_AUTHORITY));
+    EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
+
+    message_render.toWire(renderer);
+    vector<unsigned char> data;
+    UnitTestUtil::readWireData("message_toWire7", data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
+}
+
 TEST_F(MessageTest, toWireInParseMode) {
 TEST_F(MessageTest, toWireInParseMode) {
     // toWire() isn't allowed in the parse mode.
     // toWire() isn't allowed in the parse mode.
     EXPECT_THROW(message_parse.toWire(renderer), InvalidMessageOperation);
     EXPECT_THROW(message_parse.toWire(renderer), InvalidMessageOperation);

+ 1 - 1
src/lib/dns/tests/testdata/Makefile.am

@@ -87,7 +87,7 @@ EXTRA_DIST += message_fromWire19.spec message_fromWire20.spec
 EXTRA_DIST += message_fromWire21.spec message_fromWire22.spec
 EXTRA_DIST += message_fromWire21.spec message_fromWire22.spec
 EXTRA_DIST += message_toWire1 message_toWire2.spec message_toWire3.spec
 EXTRA_DIST += message_toWire1 message_toWire2.spec message_toWire3.spec
 EXTRA_DIST += message_toWire4.spec message_toWire5.spec
 EXTRA_DIST += message_toWire4.spec message_toWire5.spec
-EXTRA_DIST += message_toWire6
+EXTRA_DIST += message_toWire6 message_toWire7
 EXTRA_DIST += message_toText1.txt message_toText1.spec
 EXTRA_DIST += message_toText1.txt message_toText1.spec
 EXTRA_DIST += message_toText2.txt message_toText2.spec
 EXTRA_DIST += message_toText2.txt message_toText2.spec
 EXTRA_DIST += message_toText3.txt message_toText3.spec
 EXTRA_DIST += message_toText3.txt message_toText3.spec

+ 1 - 1
src/lib/dns/tests/testdata/message_toWire6

@@ -2,7 +2,7 @@
 # A simple DNS query message (with a signed response)
 # A simple DNS query message (with a signed response)
 # ID = 0x75c1
 # ID = 0x75c1
 # QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
 # QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
-# QDCOUNT=1, ANCOUNT=2, other COUNTS=0
+# QDCOUNT=1, ANCOUNT=4, other COUNTS=0
 # Question: test.example.com. IN A
 # Question: test.example.com. IN A
 # Answer:
 # Answer:
 #  test.example.com. 3600 IN A 192.0.2.1
 #  test.example.com. 3600 IN A 192.0.2.1

+ 35 - 0
src/lib/dns/tests/testdata/message_toWire7

@@ -0,0 +1,35 @@
+#
+# A simple DNS query message (with a signed response)
+# ID = 0x75c1
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=1, ADCOUNT=0
+# Question: test.example.com. IN TXT
+# Answer:
+#  test.example.com. 3600 IN TXT aaaaa...
+#
+75c1 8700
+0001 0001 0000 0000
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+0010 0001
+# same name, fully compressed
+c0 0c
+# TTL=3600, TXT, IN, RDLENGTH=256, RDATA
+0010 0001 00000e10 0100 ff
+# 'a' repeated 255 times
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61

+ 2 - 14
src/lib/python/isc/datasrc/tests/datasrc_test.py

@@ -482,15 +482,9 @@ class DataSrcUpdater(unittest.TestCase):
                          rrset.to_text())
                          rrset.to_text())
 
 
         rrset_to_delete = rrset;
         rrset_to_delete = rrset;
-
-        # can't delete rrset with associated sig. Abuse that to force an
-        # exception first, then remove the sig, then delete the record
-        updater = dsc.get_updater(isc.dns.Name("example.com"), True)
-        self.assertRaises(isc.datasrc.Error, updater.delete_rrset,
-                          rrset_to_delete)
-
         rrset_to_delete.remove_rrsig()
         rrset_to_delete.remove_rrsig()
 
 
+        updater = dsc.get_updater(isc.dns.Name("example.com"), True)
         updater.delete_rrset(rrset_to_delete)
         updater.delete_rrset(rrset_to_delete)
 
 
         # The record should be gone in the updater, but not in the original
         # The record should be gone in the updater, but not in the original
@@ -582,15 +576,9 @@ class DataSrcUpdater(unittest.TestCase):
                          rrset.to_text())
                          rrset.to_text())
 
 
         rrset_to_delete = rrset;
         rrset_to_delete = rrset;
-
-        # can't delete rrset with associated sig. Abuse that to force an
-        # exception first, then remove the sig, then delete the record
-        updater = dsc.get_updater(isc.dns.Name("example.com"), True)
-        self.assertRaises(isc.datasrc.Error, updater.delete_rrset,
-                          rrset_to_delete)
-
         rrset_to_delete.remove_rrsig()
         rrset_to_delete.remove_rrsig()
 
 
+        updater = dsc.get_updater(isc.dns.Name("example.com"), True)
         updater.delete_rrset(rrset_to_delete)
         updater.delete_rrset(rrset_to_delete)
 
 
         # The record should be gone in the updater, but not in the original
         # The record should be gone in the updater, but not in the original

+ 1 - 1
src/lib/resolve/resolve.cc

@@ -26,7 +26,7 @@ namespace {
             message_(message), section_(sect)
             message_(message), section_(sect)
         {}
         {}
         void operator()(const RRsetPtr rrset) {
         void operator()(const RRsetPtr rrset) {
-            message_->addRRset(section_, rrset, true);
+            message_->addRRset(section_, rrset);
         }
         }
         MessagePtr message_;
         MessagePtr message_;
         const Message::Section section_;
         const Message::Section section_;

+ 16 - 0
src/lib/testutils/dnsmessage_test.h

@@ -168,6 +168,10 @@ public:
     {}
     {}
     void operator()(isc::dns::ConstRRsetPtr rrset) {
     void operator()(isc::dns::ConstRRsetPtr rrset) {
         output_ += "  " + rrset->toText();
         output_ += "  " + rrset->toText();
+
+        if (rrset->getRRsig()) {
+            output_ += "  " + rrset->getRRsig()->toText();
+        }
     }
     }
 private:
 private:
     std::string& output_;
     std::string& output_;
@@ -256,6 +260,7 @@ rrsetsCheck(EXPECTED_ITERATOR expected_begin, EXPECTED_ITERATOR expected_end,
         if (found_rrset_it != expected_end) {
         if (found_rrset_it != expected_end) {
             rrsetCheck(*found_rrset_it, *it);
             rrsetCheck(*found_rrset_it, *it);
             ++rrset_matched;
             ++rrset_matched;
+            rrset_matched += (*it)->getRRsigDataCount();
         }
         }
     }
     }
 
 
@@ -265,9 +270,20 @@ rrsetsCheck(EXPECTED_ITERATOR expected_begin, EXPECTED_ITERATOR expected_end,
                      "Expected:\n" + expected_text);
                      "Expected:\n" + expected_text);
         // make sure all expected RRsets are in actual sets
         // make sure all expected RRsets are in actual sets
         EXPECT_EQ(std::distance(expected_begin, expected_end), rrset_matched);
         EXPECT_EQ(std::distance(expected_begin, expected_end), rrset_matched);
+
+#if (0)
+        // TODO: see bug #2223. The following code was
+        // disabled by #2165. The RRSIG RRsets are no longer directly
+        // stored in the Message's rrsets, so the iterator will not find
+        // them. The expected text used in many tests are flattened,
+        // where the RRSIGs are inline. In other words, RRSIGs may occur
+        // between (expected_begin, expected_end) but not between
+        // (actual_begin, actual_end).
+
         // make sure rrsets only contains expected RRsets
         // make sure rrsets only contains expected RRsets
         EXPECT_EQ(std::distance(expected_begin, expected_end),
         EXPECT_EQ(std::distance(expected_begin, expected_end),
                   std::distance(actual_begin, actual_end));
                   std::distance(actual_begin, actual_end));
+#endif
     }
     }
 }
 }