Commit e2ff6e8c authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2429] played with max allowable TTL (2^31-1).

parent ea84394f
......@@ -52,6 +52,7 @@ public:
const MasterLoaderCallbacks& callbacks,
const AddRRCallback& add_callback,
MasterLoader::Options options) :
MAX_TTL(0x7fffffff),
lexer_(),
zone_origin_(zone_origin),
zone_class_(zone_class),
......@@ -142,13 +143,38 @@ private:
pushSource(filename);
}
// Upper limit check when recognizing a specific TTL value from the
// zone file ($TTL, the RR's TTL field, or the SOA minimum). RFC2181
// Section 8 limits the range of TTL values to unsigned 32-bit integers,
// and prohibits transmitting a TTL field exceeding this range. We
// guarantee that by limiting the value at the time of zone
// parsing/loading, following what BIND 9 does. Resetting it to 0
// at this point may not be exactly what the RFC states, but the end
// result would be the same. Again, we follow the BIND 9's behavior here.
//
// post_parsing is true iff this method is called after parsing the entire
// RR and the lexer is positioned at the next line. It's just for
// calculating the accurate source line when callback is necessary.
void limitTTL(RRTTL& ttl, bool post_parsing) {
if (ttl > MAX_TTL) {
const size_t src_line = lexer_.getSourceLine() -
(post_parsing ? 1 : 0);
callbacks_.warning(lexer_.getSourceName(), src_line,
"TTL " + ttl.toText() + " > MAXTTL, "
"setting to 0 per RFC2181");
ttl = RRTTL(0);
}
}
// Set/reset the default TTL. Either from $TTL or SOA minimum TTL.
void setDefaultTTL(const RRTTL& ttl) {
// see LimitTTL() for parameter post_parsing.
void setDefaultTTL(const RRTTL& ttl, bool post_parsing) {
if (!default_ttl_) {
default_ttl_.reset(new RRTTL(ttl));
} else {
*default_ttl_ = ttl;
}
limitTTL(*default_ttl_, post_parsing);
}
// Set/reset the TTL currently being used. This can be used the last
......@@ -168,6 +194,7 @@ private:
bool setCurrentTTL(const string& ttl_txt) {
try {
setCurrentTTL(RRTTL(ttl_txt));
limitTTL(*current_ttl_, false);
return (true);
} catch (const InvalidRRTTL&) {
return (false);
......@@ -197,7 +224,7 @@ private:
const uint32_t ttl_val =
dynamic_cast<const rdata::generic::SOA&>(*rdata).
getMinimum();
setDefaultTTL(RRTTL(ttl_val));
setDefaultTTL(RRTTL(ttl_val), true);
setCurrentTTL(*default_ttl_);
} else {
// On catching the exception we'll try to reach EOL again,
......@@ -227,7 +254,7 @@ private:
isc_throw(isc::NotImplemented,
"Origin directive not implemented yet");
} else if (iequals(directive, "TTL")) {
setDefaultTTL(RRTTL(getString()));
setDefaultTTL(RRTTL(getString()), false);
eatUntilEOL(true);
} else {
isc_throw(InternalException, "Unknown directive '" <<
......@@ -265,6 +292,11 @@ private:
}
private:
// RFC2181 Section 8 specifies TTLs are unsigned 32-bit integer,
// effectively limiting the maximum value to 2^32-1. This constant
// represent a TTL of the max value.
const RRTTL MAX_TTL;
MasterLexer lexer_;
const Name zone_origin_;
const RRClass zone_class_;
......
......@@ -419,7 +419,9 @@ TEST_F(MasterLoaderTest, ttlDirective) {
// Extended TTL form is accepted.
zone_stream << "$TTL 1H\nb.example.org. IN A 192.0.2.3\n";
// Matching is case insensitive.
zone_stream << "$tTl 360\nc.example.org. IN A 192.0.2.3\n";
zone_stream << "$tTl 360\nc.example.org. IN A 192.0.2.4\n";
// Maximum allowable TTL
zone_stream << "$TTL 2147483647\nd.example.org. IN A 192.0.2.5\n";
setLoader(zone_stream, Name("example.org."), RRClass::IN(),
MasterLoader::DEFAULT);
......@@ -428,7 +430,8 @@ TEST_F(MasterLoaderTest, ttlDirective) {
checkRR("example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
checkRR("a.example.org", RRType::A(), "192.0.2.2", RRTTL(100));
checkRR("b.example.org", RRType::A(), "192.0.2.3", RRTTL(3600));
checkRR("c.example.org", RRType::A(), "192.0.2.3", RRTTL(360));
checkRR("c.example.org", RRType::A(), "192.0.2.4", RRTTL(360));
checkRR("d.example.org", RRType::A(), "192.0.2.5", RRTTL(2147483647));
}
TEST_F(MasterLoaderTest, ttlFromSOA) {
......@@ -527,6 +530,36 @@ TEST_F(MasterLoaderTest, ttlUnknownAndEOF) {
checkCallbackMessage(*warnings_.rbegin(), "Unexpected end end of file", 1);
}
TEST_F(MasterLoaderTest, ttlOverflow) {
stringstream zone_stream;
zone_stream << "example.org. IN SOA . . 0 0 0 0 2147483648\n";
zone_stream << "$TTL 3600\n"; // reset to an in-range value
zone_stream << "$TTL 2147483649\n" << "a.example.org. IN A 192.0.2.1\n";
zone_stream << "$TTL 3600\n"; // reset to an in-range value
zone_stream << "b.example.org. 2147483650 IN A 192.0.2.2\n";
setLoader(zone_stream, Name("example.org."), RRClass::IN(),
MasterLoader::DEFAULT);
loader_->load();
EXPECT_TRUE(loader_->loadedSucessfully());
EXPECT_EQ(3, rrsets_.size());
checkRR("example.org", RRType::SOA(), ". . 0 0 0 0 2147483648", RRTTL(0));
checkRR("a.example.org", RRType::A(), "192.0.2.1", RRTTL(0));
checkRR("b.example.org", RRType::A(), "192.0.2.2", RRTTL(0));
EXPECT_EQ(4, warnings_.size());
checkCallbackMessage(warnings_.at(1),
"TTL 2147483648 > MAXTTL, setting to 0 per RFC2181",
1);
checkCallbackMessage(warnings_.at(2),
"TTL 2147483649 > MAXTTL, setting to 0 per RFC2181",
3);
checkCallbackMessage(warnings_.at(3),
"TTL 2147483650 > MAXTTL, setting to 0 per RFC2181",
6);
}
// Test the constructor rejects empty add callback.
TEST_F(MasterLoaderTest, emptyCallback) {
EXPECT_THROW(MasterLoader(TEST_DATA_SRCDIR "/example.org",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment