Browse Source

[2431] Support flexible order of TTL, type and class

Mukund Sivaraman 12 years ago
parent
commit
48a559472a
2 changed files with 67 additions and 7 deletions
  1. 33 7
      src/lib/dns/master_loader.cc
  2. 34 0
      src/lib/dns/tests/master_loader_unittest.cc

+ 33 - 7
src/lib/dns/master_loader.cc

@@ -382,12 +382,26 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
 
 
             const Name name(name_string.beg, name_string.len,
             const Name name(name_string.beg, name_string.len,
                             &zone_origin_);
                             &zone_origin_);
-            // TODO: Some more flexibility. We don't allow omitting
-            // anything yet
+
+            // Find TTL, class and type.  Both TTL and class are
+            // optional and may occur in any order if they exist. TTL
+            // and class come before type which must exist.
+            //
+            // [<TTL>] [<class>] <type> <RDATA>
+            // [<class>] [<TTL>] <type> <RDATA>
 
 
             // The parameters
             // The parameters
             MasterToken rrparam_token = lexer_.getNextToken();
             MasterToken rrparam_token = lexer_.getNextToken();
 
 
+            boost::scoped_ptr<RRClass> rrclass;
+            try {
+                rrclass.reset(new RRClass(rrparam_token.getString()));
+                rrparam_token = lexer_.getNextToken();
+            } catch (InvalidRRClass& e) {
+                // If it's not an rrclass here, continue and try again
+                // after the TTL below.
+            }
+
             bool explicit_ttl = false;
             bool explicit_ttl = false;
             if (rrparam_token.getType() == MasterToken::STRING) {
             if (rrparam_token.getType() == MasterToken::STRING) {
                 // Try TTL
                 // Try TTL
@@ -397,19 +411,31 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
                 }
                 }
             }
             }
 
 
-            const RRClass rrclass(rrparam_token.getString());
+            if (!rrclass) {
+                try {
+                    rrclass.reset(new RRClass(rrparam_token.getString()));
+                    rrparam_token = lexer_.getNextToken();
+                } catch (InvalidRRClass& e) {
+                    // If it's not an rrclass here, use the zone's class.
+                    rrclass.reset(new RRClass(zone_class_));
+                }
+            }
+
+            // Return the last token
+            lexer_.ungetToken();
+
             const RRType rrtype(getString());
             const RRType rrtype(getString());
 
 
             // TODO: Some more validation?
             // TODO: Some more validation?
-            if (rrclass != zone_class_) {
+            if (*rrclass != zone_class_) {
                 // It doesn't really matter much what type of exception
                 // It doesn't really matter much what type of exception
                 // we throw, we catch it just below.
                 // we throw, we catch it just below.
-                isc_throw(isc::BadValue, "Class mismatch: " << rrclass <<
+                isc_throw(isc::BadValue, "Class mismatch: " << *rrclass <<
                           "vs. " << zone_class_);
                           "vs. " << zone_class_);
             }
             }
             // TODO: Check if it is SOA, it should be at the origin.
             // TODO: Check if it is SOA, it should be at the origin.
 
 
-            const rdata::RdataPtr rdata(rdata::createRdata(rrtype, rrclass,
+            const rdata::RdataPtr rdata(rdata::createRdata(rrtype, *rrclass,
                                                            lexer_,
                                                            lexer_,
                                                            &zone_origin_,
                                                            &zone_origin_,
                                                            options_,
                                                            options_,
@@ -419,7 +445,7 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
             // callbacks_ already. We need to decide if we want to continue
             // callbacks_ already. We need to decide if we want to continue
             // or not.
             // or not.
             if (rdata) {
             if (rdata) {
-                add_callback_(name, rrclass, rrtype,
+                add_callback_(name, *rrclass, rrtype,
                               getCurrentTTL(explicit_ttl, rrtype, rdata),
                               getCurrentTTL(explicit_ttl, rrtype, rdata),
                               rdata);
                               rdata);
 
 

+ 34 - 0
src/lib/dns/tests/master_loader_unittest.cc

@@ -471,6 +471,40 @@ TEST_F(MasterLoaderTest, ttlFromPrevious) {
     checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
     checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
 }
 }
 
 
+TEST_F(MasterLoaderTest, ttlClassTypeOrder) {
+    // We test the order and lack of TTL, class and type.  Both TTL and
+    // class are optional and may occur in any order if they exist. TTL
+    // and class come before type which must exist.
+    //
+    // [<TTL>] [<class>] <type> <RDATA>
+    // [<class>] [<TTL>] <type> <RDATA>
+
+    stringstream zone_stream;
+    // <TTL> <class> <type> <RDATA>
+    zone_stream << "a.example.org. 1800 IN A 192.0.2.1\n";
+    // <type> <RDATA>
+    zone_stream << "b.example.org. A 192.0.2.2\n";
+    // <class> <TTL> <type> <RDATA>
+    zone_stream << "c.example.org. IN 3600 A 192.0.2.3\n";
+    // <TTL> <type> <RDATA>
+    zone_stream << "d.example.org. 7200 A 192.0.2.4\n";
+    // <class> <type> <RDATA>
+    zone_stream << "e.example.org. IN A 192.0.2.5\n";
+
+    setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+              MasterLoader::DEFAULT);
+    loader_->load();
+    EXPECT_TRUE(loader_->loadedSucessfully());
+    checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
+    checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(1800));
+    checkRR("c.example.org", RRType::A(), "192.0.2.3", RRTTL(3600));
+    checkRR("d.example.org", RRType::A(), "192.0.2.4", RRTTL(7200));
+    checkRR("e.example.org", RRType::A(), "192.0.2.5", RRTTL(7200));
+
+    EXPECT_EQ(1, warnings_.size());
+    checkCallbackMessage(warnings_.at(0), "using RFC1035 TTL semantics", 2);
+}
+
 TEST_F(MasterLoaderTest, ttlFromPreviousSOA) {
 TEST_F(MasterLoaderTest, ttlFromPreviousSOA) {
     // Mixture of the previous two cases: SOA has explicit TTL, followed by
     // Mixture of the previous two cases: SOA has explicit TTL, followed by
     // an RR without an explicit TTL.  In this case the minimum TTL won't be
     // an RR without an explicit TTL.  In this case the minimum TTL won't be