Browse Source

[2309] supported use_minttl part of findAtOrigin.

JINMEI Tatuya 12 years ago
parent
commit
6317823834

+ 106 - 4
src/lib/datasrc/tests/database_unittest.cc

@@ -1813,6 +1813,7 @@ doFindAtOriginTest(ZoneFinder& finder,
                    ZoneFinder::Result expected_result,
                    ZoneFinder::Result expected_result,
                    const std::vector<std::string>& expected_rdatas,
                    const std::vector<std::string>& expected_rdatas,
                    const std::vector<std::string>& expected_sig_rdatas,
                    const std::vector<std::string>& expected_sig_rdatas,
+                   bool use_minttl = false,
                    ZoneFinder::FindResultFlags expected_flags =
                    ZoneFinder::FindResultFlags expected_flags =
                    ZoneFinder::RESULT_DEFAULT,
                    ZoneFinder::RESULT_DEFAULT,
                    const isc::dns::Name& expected_name =
                    const isc::dns::Name& expected_name =
@@ -1822,7 +1823,7 @@ doFindAtOriginTest(ZoneFinder& finder,
 {
 {
     SCOPED_TRACE("doFindOriginTest " + origin.toText() + " " + type.toText());
     SCOPED_TRACE("doFindOriginTest " + origin.toText() + " " + type.toText());
     ConstZoneFinderContextPtr result =
     ConstZoneFinderContextPtr result =
-        finder.findAtOrigin(type, false, options);
+        finder.findAtOrigin(type, use_minttl, options);
     findTestCommon(finder, origin, type, result, expected_type, expected_ttl,
     findTestCommon(finder, origin, type, result, expected_type, expected_ttl,
                    expected_result, expected_rdatas, expected_sig_rdatas,
                    expected_result, expected_rdatas, expected_sig_rdatas,
                    expected_flags, expected_name, options);
                    expected_flags, expected_name, options);
@@ -2182,7 +2183,7 @@ TYPED_TEST(DatabaseClientTest, findAtOrigin) {
     doFindAtOriginTest(*finder, this->zname_, RRType::NS(), RRType::NS(),
     doFindAtOriginTest(*finder, this->zname_, RRType::NS(), RRType::NS(),
                        this->rrttl_, ZoneFinder::SUCCESS,
                        this->rrttl_, ZoneFinder::SUCCESS,
                        this->expected_rdatas_, this->expected_sig_rdatas_,
                        this->expected_rdatas_, this->expected_sig_rdatas_,
-                       ZoneFinder::RESULT_DEFAULT, this->zname_,
+                       false, ZoneFinder::RESULT_DEFAULT, this->zname_,
                        ZoneFinder::FIND_DNSSEC);
                        ZoneFinder::FIND_DNSSEC);
 
 
     // Specified type of RR doesn't exist, no DNSSEC
     // Specified type of RR doesn't exist, no DNSSEC
@@ -2203,7 +2204,7 @@ TYPED_TEST(DatabaseClientTest, findAtOrigin) {
     doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::NSEC(),
     doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::NSEC(),
                        this->rrttl_, ZoneFinder::NXRRSET,
                        this->rrttl_, ZoneFinder::NXRRSET,
                        this->expected_rdatas_, this->expected_sig_rdatas_,
                        this->expected_rdatas_, this->expected_sig_rdatas_,
-                       ZoneFinder::RESULT_NSEC_SIGNED,
+                       false, ZoneFinder::RESULT_NSEC_SIGNED,
                        this->zname_, ZoneFinder::FIND_DNSSEC);
                        this->zname_, ZoneFinder::FIND_DNSSEC);
 
 
     // Specified type of RR doesn't exist, with DNSSEC, enabling NSEC3
     // Specified type of RR doesn't exist, with DNSSEC, enabling NSEC3
@@ -2213,10 +2214,111 @@ TYPED_TEST(DatabaseClientTest, findAtOrigin) {
     doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::TXT(),
     doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::TXT(),
                        this->rrttl_, ZoneFinder::NXRRSET,
                        this->rrttl_, ZoneFinder::NXRRSET,
                        this->expected_rdatas_, this->expected_sig_rdatas_,
                        this->expected_rdatas_, this->expected_sig_rdatas_,
-                       ZoneFinder::RESULT_NSEC3_SIGNED,
+                       false, ZoneFinder::RESULT_NSEC3_SIGNED,
                        this->zname_, ZoneFinder::FIND_DNSSEC);
                        this->zname_, ZoneFinder::FIND_DNSSEC);
 }
 }
 
 
+TYPED_TEST(DatabaseClientTest, findAtOriginWithMinTTL) {
+    // First, replace the SOA of the test zone so that its RR TTL is larger
+    // than MINTTL (the original data are used in many places, so replacing
+    // them just for this doesn't make sense).
+    RRsetPtr old_soa(new RRset(this->zname_, this->qclass_, RRType::SOA(),
+                               this->rrttl_));
+    old_soa->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+                                         "ns1.example.org. admin.example.org. "
+                                         "1234 3600 1800 2419200 7200"));
+
+    const string new_soa_rdata = "ns1.example.org. admin.example.org. "
+        "1234 3600 1800 2419200 1200";
+    RRsetPtr new_soa(new RRset(this->zname_, this->qclass_, RRType::SOA(),
+                               this->rrttl_));
+    new_soa->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+                                         new_soa_rdata));
+
+    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    this->updater_->deleteRRset(*old_soa);
+    this->updater_->addRRset(*new_soa);
+    this->updater_->commit();
+
+    ZoneFinderPtr finder = this->getFinder();
+
+    // Specify the use of min TTL, then the resulting TTL should be drived
+    // from the SOA MINTTL (which is smaller).
+    this->expected_rdatas_.push_back(new_soa_rdata);
+    doFindAtOriginTest(*finder, this->zname_, RRType::SOA(), RRType::SOA(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true);
+
+    // If DNSSEC is requested, TTL of the RRSIG should also be the min.
+    this->expected_sig_rdatas_.push_back(
+        "SOA 5 3 3600 20000101000000 "
+        "20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, this->zname_, RRType::SOA(), RRType::SOA(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true, ZoneFinder::RESULT_DEFAULT, this->zname_,
+                       ZoneFinder::FIND_DNSSEC);
+
+    // Not really intended usage, but specify the use of min TTL for non SOA.
+    // It should still work as specified.
+    this->expected_rdatas_.clear();
+    this->expected_sig_rdatas_.clear();
+    this->expected_rdatas_.push_back("ns.example.com.");
+    doFindAtOriginTest(*finder, this->zname_, RRType::NS(), RRType::NS(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true);
+
+    // If we don't request the use of min TTL, the original TTL will be used.
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back(new_soa_rdata);
+    doFindAtOriginTest(*finder, this->zname_, RRType::SOA(), RRType::SOA(),
+                       this->rrttl_, ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_);
+
+    // If no RRset is returned, use_minttl doesn't matter (it shouldn't cause
+    // disruption)
+    this->expected_rdatas_.clear();
+    doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), this->qtype_,
+                       this->rrttl_, ZoneFinder::NXRRSET,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true);
+
+    // If it results in NXRRSET with NSEC, and if we specify the use of min
+    // TTL, the NSEC and RRSIG should have the min TTL (again, though, this
+    // use case is not really the intended one)
+    this->expected_rdatas_.push_back(
+        "acnamesig1.example.org. A NS RRSIG NSEC");
+    this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                         "20000201000000 12345 example.org. "
+                                         "FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::NSEC(),
+                       RRTTL(1200), ZoneFinder::NXRRSET,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true, ZoneFinder::RESULT_NSEC_SIGNED,
+                       this->zname_, ZoneFinder::FIND_DNSSEC);
+}
+
+TYPED_TEST(DatabaseClientTest, findAtOriginWithMinTTLBroken) {
+    // Similar to the previous case, but we intentionally remove the SOA
+    // (assuming the underlying data source doesn't complain about it).
+    // This will cause exception in subsequent findAtOrigin() with use_minttl
+    // being true.
+    RRsetPtr old_soa(new RRset(this->zname_, this->qclass_, RRType::SOA(),
+                               this->rrttl_));
+    old_soa->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+                                         "ns1.example.org. admin.example.org. "
+                                         "1234 3600 1800 2419200 7200"));
+    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    this->updater_->deleteRRset(*old_soa);
+    this->updater_->commit();
+
+    EXPECT_THROW(this->getFinder()->findAtOrigin(RRType::NS(), true,
+                                                 ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+}
+
 TYPED_TEST(DatabaseClientTest, findOutOfZone) {
 TYPED_TEST(DatabaseClientTest, findOutOfZone) {
     // If the query name is out-of-zone it should result in an exception
     // If the query name is out-of-zone it should result in an exception
     boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
     boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());

+ 88 - 4
src/lib/datasrc/zone_finder.cc

@@ -12,13 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <datasrc/zone_finder.h>
+#include <datasrc/data_source.h>
+
 #include <dns/rdata.h>
 #include <dns/rdata.h>
 #include <dns/rrset.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 #include <dns/rdataclass.h>
 
 
-#include <datasrc/zone_finder.h>
-
 using namespace std;
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::dns::rdata;
@@ -26,11 +27,94 @@ using namespace isc::dns::rdata;
 namespace isc {
 namespace isc {
 namespace datasrc {
 namespace datasrc {
 
 
+namespace {
+// Identify zone's SOA and return its MINTTL in the form of RRTTL.
+RRTTL
+getMinTTL(ZoneFinder& finder, ConstRRsetPtr rrset) {
+    ConstRRsetPtr soa_rrset;
+    if (rrset->getType() == RRType::SOA()) {
+        // Shortcut: if we are looking at SOA itself (which should be the
+        // case in the expected scenario), we can simply use its RDATA.
+        soa_rrset = rrset;
+    } else {
+        soa_rrset =
+            finder.findAtOrigin(RRType::SOA(), false,
+                                ZoneFinder::FIND_DEFAULT)->rrset;
+    }
+
+    // In a valid zone there is one and only one SOA RR at the origin.
+    // Otherwise either zone data or the data source implementation is broken.
+    if (!soa_rrset || soa_rrset->getRdataCount() != 1) {
+        isc_throw(DataSourceError, "Zone " << rrset->getName().toText(true)
+                  << "/" << rrset->getClass().toText() << " is broken: "
+                  << (!soa_rrset ? "no SOA" : "empty SOA"));
+    }
+
+    return (RRTTL(dynamic_cast<const generic::SOA&>(
+                      soa_rrset->getRdataIterator()->getCurrent()).
+                  getMinimum()));
+}
+
+// Make a fresh copy of given RRset, just replacing RRTTL with the given one.
+RRsetPtr
+copyRRset(const AbstractRRset& rrset, const RRTTL& ttl) {
+    RRsetPtr rrset_copy(new RRset(rrset.getName(), rrset.getClass(),
+                                  rrset.getType(), ttl));
+    for (RdataIteratorPtr rit = rrset.getRdataIterator();
+         !rit->isLast();
+         rit->next()) {
+        rrset_copy->addRdata(rit->getCurrent());
+    }
+
+    ConstRRsetPtr rrsig = rrset.getRRsig();
+    if (rrsig) {
+        RRsetPtr rrsig_copy(new RRset(rrset.getName(), rrset.getClass(),
+                                      RRType::RRSIG(), ttl));
+        for (RdataIteratorPtr rit = rrsig->getRdataIterator();
+             !rit->isLast();
+             rit->next()) {
+            rrsig_copy->addRdata(rit->getCurrent());
+        }
+        rrset_copy->addRRsig(rrsig_copy);
+    }
+
+    return (rrset_copy);
+}
+}
+
 ZoneFinderContextPtr
 ZoneFinderContextPtr
-ZoneFinder::findAtOrigin(const dns::RRType& type, bool /*use_minmtu*/,
+ZoneFinder::findAtOrigin(const dns::RRType& type, bool use_minttl,
                          FindOptions options)
                          FindOptions options)
 {
 {
-    return (find(getOrigin(), type, options));
+    ZoneFinderContextPtr context = find(getOrigin(), type, options);
+
+    // If we are requested to use the min TTL and the RRset's RR TTL is larger
+    // than that, we need to make a copy of the RRset, replacing the TTL,
+    // and return a newly created context copying other parameters.
+    if (use_minttl && context->rrset) {
+        const AbstractRRset& rrset = *context->rrset;
+        const RRTTL min_ttl = getMinTTL(*this, context->rrset);
+        if (min_ttl < rrset.getTTL()) {
+            FindResultFlags flags_copy = RESULT_DEFAULT;
+            if (context->isWildcard()) {
+                flags_copy = flags_copy | RESULT_WILDCARD;
+            }
+            if (context->isNSECSigned()) {
+                flags_copy = flags_copy | RESULT_NSEC_SIGNED;
+            } else if (context->isNSEC3Signed()) {
+                flags_copy = flags_copy | RESULT_NSEC3_SIGNED;
+            }
+            
+            return (ZoneFinderContextPtr(
+                        new GenericContext(*this, options,
+                                           ResultContext(context->code,
+                                                         copyRRset(rrset,
+                                                                   min_ttl),
+                                                         flags_copy))));
+        }
+    }
+
+    return (context);
 }
 }
 
 
 isc::dns::ConstRRsetPtr
 isc::dns::ConstRRsetPtr

+ 1 - 1
src/lib/datasrc/zone_finder.h

@@ -584,7 +584,7 @@ public:
     /// This is an equivalent of a call to \c find() where the \c name
     /// This is an equivalent of a call to \c find() where the \c name
     /// parameter is the zone origin.
     /// parameter is the zone origin.
     virtual boost::shared_ptr<Context> findAtOrigin(
     virtual boost::shared_ptr<Context> findAtOrigin(
-        const isc::dns::RRType& type, bool use_minmtu,
+        const isc::dns::RRType& type, bool use_minttl,
         FindOptions options);
         FindOptions options);
 
 
     ///
     ///