|
@@ -133,6 +133,12 @@ const char* const unsigned_delegation_nsec3_txt =
|
|
|
"q81r598950igr1eqvc60aedlq66425b5.example.com. 3600 IN NSEC3 1 1 12 "
|
|
|
"aabbccdd 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom NS RRSIG\n";
|
|
|
|
|
|
+// Name of an "empty" zone: used to simulate the case of
|
|
|
+// configured-but-available zone (due to load errors, etc).
|
|
|
+// Each tested data source client is expected to have this zone (SQLite3
|
|
|
+// currently doesn't have this concept so it's skipped)
|
|
|
+const char* const EMPTY_ZONE_NAME = "empty.example.org";
|
|
|
+
|
|
|
// A helper function that generates a textual representation of RRSIG RDATA
|
|
|
// for the given covered type. The resulting RRSIG may not necessarily make
|
|
|
// sense in terms of the DNSSEC protocol, but for our testing purposes it's
|
|
@@ -799,11 +805,14 @@ createDataSrcClientList(DataSrcType type, DataSourceClient& client) {
|
|
|
return (boost::shared_ptr<ClientList>(new SingletonList(client)));
|
|
|
case INMEMORY:
|
|
|
list.reset(new ConfigurableClientList(RRClass::IN()));
|
|
|
+ // Configure one normal zone and one "empty" zone.
|
|
|
list->configure(isc::data::Element::fromJSON(
|
|
|
"[{\"type\": \"MasterFiles\","
|
|
|
" \"cache-enable\": true, "
|
|
|
" \"params\": {\"example.com\": \"" +
|
|
|
- string(TEST_OWN_DATA_BUILDDIR "/example.zone") +
|
|
|
+ string(TEST_OWN_DATA_BUILDDIR "/example.zone\",") +
|
|
|
+ + "\"" + EMPTY_ZONE_NAME + "\": \"" +
|
|
|
+ string(TEST_OWN_DATA_BUILDDIR "/nosuchfile.zone") +
|
|
|
"\"}}]"), true);
|
|
|
return (list);
|
|
|
case SQLITE3:
|
|
@@ -834,39 +843,38 @@ createDataSrcClientList(DataSrcType type, DataSourceClient& client) {
|
|
|
class MockClient : public DataSourceClient {
|
|
|
public:
|
|
|
virtual FindResult findZone(const isc::dns::Name& origin) const {
|
|
|
- const Name r_origin(origin.reverse());
|
|
|
- std::map<Name, ZoneFinderPtr>::const_iterator it =
|
|
|
- zone_finders_.lower_bound(r_origin);
|
|
|
-
|
|
|
- if (it != zone_finders_.end()) {
|
|
|
- const NameComparisonResult result =
|
|
|
- origin.compare((it->first).reverse());
|
|
|
- if (result.getRelation() == NameComparisonResult::EQUAL) {
|
|
|
- return (FindResult(result::SUCCESS, it->second));
|
|
|
- } else if (result.getRelation() == NameComparisonResult::SUBDOMAIN) {
|
|
|
- return (FindResult(result::PARTIALMATCH, it->second));
|
|
|
- }
|
|
|
- }
|
|
|
+ // Identify the next (strictly) larger name than the given 'origin' in
|
|
|
+ // the map. Its predecessor (if any) is the longest matching name
|
|
|
+ // if it's either an exact match or a super domain; otherwise there's
|
|
|
+ // no match in the map. See also datasrc/tests/mock_client.cc.
|
|
|
|
|
|
- // If it is at the beginning of the map, then the name was not
|
|
|
- // found (we have already handled the element the iterator
|
|
|
- // points to).
|
|
|
- if (it == zone_finders_.begin()) {
|
|
|
+ // Eliminate the case of empty map to simply the rest of the code
|
|
|
+ if (zone_finders_.empty()) {
|
|
|
return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
|
|
|
}
|
|
|
|
|
|
- // Check if the previous element is a partial match.
|
|
|
- --it;
|
|
|
- const NameComparisonResult result =
|
|
|
- origin.compare((it->first).reverse());
|
|
|
- if (result.getRelation() == NameComparisonResult::SUBDOMAIN) {
|
|
|
- return (FindResult(result::PARTIALMATCH, it->second));
|
|
|
+ std::map<Name, ZoneFinderPtr>::const_iterator it =
|
|
|
+ zone_finders_.upper_bound(origin);
|
|
|
+ if (it == zone_finders_.begin()) { // no predecessor
|
|
|
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
|
|
|
}
|
|
|
|
|
|
- return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
|
|
|
+ --it; // get the predecessor
|
|
|
+ const result::ResultFlags flags =
|
|
|
+ it->second ? result::FLAGS_DEFAULT : result::ZONE_EMPTY;
|
|
|
+ const NameComparisonResult compar(it->first.compare(origin));
|
|
|
+ switch (compar.getRelation()) {
|
|
|
+ case NameComparisonResult::EQUAL:
|
|
|
+ return (FindResult(result::SUCCESS, it->second, flags));
|
|
|
+ case NameComparisonResult::SUPERDOMAIN:
|
|
|
+ return (FindResult(result::PARTIALMATCH, it->second, flags));
|
|
|
+ default:
|
|
|
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name&, bool, bool) const {
|
|
|
+ virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name&, bool, bool) const
|
|
|
+ {
|
|
|
isc_throw(isc::NotImplemented,
|
|
|
"Updater isn't supported in the MockClient");
|
|
|
}
|
|
@@ -878,18 +886,21 @@ public:
|
|
|
}
|
|
|
|
|
|
result::Result addZone(ZoneFinderPtr finder) {
|
|
|
- // Use the reverse of the name as the key, so we can quickly
|
|
|
- // find partial matches in the map.
|
|
|
- zone_finders_[finder->getOrigin().reverse()] = finder;
|
|
|
+ zone_finders_[finder->getOrigin()] = finder;
|
|
|
+ return (result::SUCCESS);
|
|
|
+ }
|
|
|
+
|
|
|
+ // "configure" a zone with no data. This will cause the ZONE_EMPTY flag
|
|
|
+ // on in finZone().
|
|
|
+ result::Result addEmptyZone(const Name& zone_name) {
|
|
|
+ zone_finders_[zone_name] = ZoneFinderPtr();
|
|
|
return (result::SUCCESS);
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
// Note that because we no longer have the old RBTree, and the new
|
|
|
// in-memory DomainTree is not useful as it returns const nodes, we
|
|
|
- // use a std::map instead. In this map, the key is a name stored in
|
|
|
- // reverse order of labels to aid in finding partial matches
|
|
|
- // quickly.
|
|
|
+ // use a std::map instead.
|
|
|
std::map<Name, ZoneFinderPtr> zone_finders_;
|
|
|
};
|
|
|
|
|
@@ -916,9 +927,10 @@ protected:
|
|
|
|
|
|
response.setRcode(Rcode::NOERROR());
|
|
|
response.setOpcode(Opcode::QUERY());
|
|
|
- // create and add a matching zone.
|
|
|
+ // create and add a matching zone. One is a "broken, empty" zone.
|
|
|
mock_finder = new MockZoneFinder();
|
|
|
mock_client.addZone(ZoneFinderPtr(mock_finder));
|
|
|
+ mock_client.addEmptyZone(Name(EMPTY_ZONE_NAME));
|
|
|
}
|
|
|
|
|
|
virtual void SetUp() {
|
|
@@ -1144,8 +1156,7 @@ TEST_P(QueryTest, noZone) {
|
|
|
// REFUSED.
|
|
|
MockClient empty_mock_client;
|
|
|
SingletonList empty_list(empty_mock_client);
|
|
|
- EXPECT_NO_THROW(query.process(empty_list, qname, qtype,
|
|
|
- response));
|
|
|
+ EXPECT_NO_THROW(query.process(empty_list, qname, qtype, response));
|
|
|
EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
|
|
|
}
|
|
|
|
|
@@ -1400,7 +1411,6 @@ TEST_F(QueryTestForMockOnly, badSecureDelegation) {
|
|
|
qtype, response));
|
|
|
}
|
|
|
|
|
|
-
|
|
|
TEST_P(QueryTest, nxdomain) {
|
|
|
EXPECT_NO_THROW(query.process(*list_,
|
|
|
Name("nxdomain.example.com"), qtype,
|