Commit a47f01b6 authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

Merge #1483

parents b0d0bf39 87a72f00
......@@ -15,6 +15,8 @@
#include <algorithm> // for std::max
#include <vector>
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <dns/message.h>
#include <dns/rcode.h>
......@@ -67,7 +69,7 @@ Query::addAdditionalAddrs(ZoneFinder& zone, const Name& qname,
// Find A rrset
if (qname_ != qname || qtype_ != RRType::A()) {
ZoneFinder::FindResult a_result = zone.find(qname, RRType::A(), NULL,
ZoneFinder::FindResult a_result = zone.find(qname, RRType::A(),
options | dnssec_opt_);
if (a_result.code == ZoneFinder::SUCCESS) {
response_.addRRset(Message::SECTION_ADDITIONAL,
......@@ -78,7 +80,7 @@ Query::addAdditionalAddrs(ZoneFinder& zone, const Name& qname,
// Find AAAA rrset
if (qname_ != qname || qtype_ != RRType::AAAA()) {
ZoneFinder::FindResult aaaa_result =
zone.find(qname, RRType::AAAA(), NULL, options | dnssec_opt_);
zone.find(qname, RRType::AAAA(), options | dnssec_opt_);
if (aaaa_result.code == ZoneFinder::SUCCESS) {
response_.addRRset(Message::SECTION_ADDITIONAL,
boost::const_pointer_cast<RRset>(aaaa_result.rrset),
......@@ -90,7 +92,7 @@ Query::addAdditionalAddrs(ZoneFinder& zone, const Name& qname,
void
Query::addSOA(ZoneFinder& finder) {
ZoneFinder::FindResult soa_result(finder.find(finder.getOrigin(),
RRType::SOA(), NULL, dnssec_opt_));
RRType::SOA(), dnssec_opt_));
if (soa_result.code != ZoneFinder::SUCCESS) {
isc_throw(NoSOA, "There's no SOA record in zone " <<
finder.getOrigin().toText());
......@@ -146,7 +148,7 @@ Query::addNXDOMAINProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
// otherwise we shouldn't have got NXDOMAIN for the original query in
// the first place).
const ZoneFinder::FindResult fresult = finder.find(wildname,
RRType::NSEC(), NULL,
RRType::NSEC(),
dnssec_opt_);
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
......@@ -171,7 +173,7 @@ Query::addWildcardProof(ZoneFinder& finder) {
// substitution. Confirm that by specifying NO_WILDCARD. It should result
// in NXDOMAIN and an NSEC RR that proves it should be returned.
const ZoneFinder::FindResult fresult =
finder.find(qname_, RRType::NSEC(), NULL,
finder.find(qname_, RRType::NSEC(),
dnssec_opt_ | ZoneFinder::NO_WILDCARD);
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
......@@ -194,7 +196,7 @@ Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
boost::const_pointer_cast<RRset>(nsec), dnssec_);
const ZoneFinder::FindResult fresult =
finder.find(qname_, RRType::NSEC(), NULL,
finder.find(qname_, RRType::NSEC(),
dnssec_opt_ | ZoneFinder::NO_WILDCARD);
if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
fresult.rrset->getRdataCount() == 0) {
......@@ -213,8 +215,7 @@ void
Query::addAuthAdditional(ZoneFinder& finder) {
// Fill in authority and addtional sections.
ZoneFinder::FindResult ns_result = finder.find(finder.getOrigin(),
RRType::NS(), NULL,
dnssec_opt_);
RRType::NS(), dnssec_opt_);
// zone origin name should have NS records
if (ns_result.code != ZoneFinder::SUCCESS) {
isc_throw(NoApexNS, "There's no apex NS records in zone " <<
......@@ -229,7 +230,6 @@ Query::addAuthAdditional(ZoneFinder& finder) {
void
Query::process() {
bool keep_doing = true;
const bool qtype_is_any = (qtype_ == RRType::ANY());
response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
......@@ -251,147 +251,151 @@ Query::process() {
// Found a zone which is the nearest ancestor to QNAME, set the AA bit
response_.setHeaderFlag(Message::HEADERFLAG_AA);
response_.setRcode(Rcode::NOERROR());
while (keep_doing) {
keep_doing = false;
std::auto_ptr<RRsetList> target(qtype_is_any ? new RRsetList : NULL);
const ZoneFinder::FindResult db_result(
zfinder.find(qname_, qtype_, target.get(), dnssec_opt_));
switch (db_result.code) {
case ZoneFinder::DNAME: {
// First, put the dname into the answer
response_.addRRset(Message::SECTION_ANSWER,
boost::const_pointer_cast<RRset>(db_result.rrset),
dnssec_);
std::vector<ConstRRsetPtr> target;
boost::function0<ZoneFinder::FindResult> find;
if (qtype_is_any) {
find = boost::bind(&ZoneFinder::findAll, &zfinder, qname_,
boost::ref(target), dnssec_opt_);
} else {
find = boost::bind(&ZoneFinder::find, &zfinder, qname_, qtype_,
dnssec_opt_);
}
ZoneFinder::FindResult db_result(find());
switch (db_result.code) {
case ZoneFinder::DNAME: {
// First, put the dname into the answer
response_.addRRset(Message::SECTION_ANSWER,
boost::const_pointer_cast<RRset>(db_result.rrset),
dnssec_);
/*
* Empty DNAME should never get in, as it is impossible to
* create one in master file.
*
* FIXME: Other way to prevent this should be done
*/
assert(db_result.rrset->getRdataCount() > 0);
// Get the data of DNAME
const rdata::generic::DNAME& dname(
dynamic_cast<const rdata::generic::DNAME&>(
db_result.rrset->getRdataIterator()->getCurrent()));
// The yet unmatched prefix dname
const Name prefix(qname_.split(0, qname_.getLabelCount() -
db_result.rrset->getName().getLabelCount()));
// If we put it together, will it be too long?
// (The prefix contains trailing ., which will be removed
if (prefix.getLength() - Name::ROOT_NAME().getLength() +
dname.getDname().getLength() > Name::MAX_WIRE) {
/*
* Empty DNAME should never get in, as it is impossible to
* create one in master file.
*
* FIXME: Other way to prevent this should be done
* In case the synthesized name is too long, section 4.1
* of RFC 2672 mandates we return YXDOMAIN.
*/
assert(db_result.rrset->getRdataCount() > 0);
// Get the data of DNAME
const rdata::generic::DNAME& dname(
dynamic_cast<const rdata::generic::DNAME&>(
db_result.rrset->getRdataIterator()->getCurrent()));
// The yet unmatched prefix dname
const Name prefix(qname_.split(0, qname_.getLabelCount() -
db_result.rrset->getName().getLabelCount()));
// If we put it together, will it be too long?
// (The prefix contains trailing ., which will be removed
if (prefix.getLength() - Name::ROOT_NAME().getLength() +
dname.getDname().getLength() > Name::MAX_WIRE) {
/*
* In case the synthesized name is too long, section 4.1
* of RFC 2672 mandates we return YXDOMAIN.
*/
response_.setRcode(Rcode::YXDOMAIN());
return;
}
// The new CNAME we are creating (it will be unsigned even
// with DNSSEC, the DNAME is signed and it can be validated
// by that)
RRsetPtr cname(new RRset(qname_, db_result.rrset->getClass(),
RRType::CNAME(), db_result.rrset->getTTL()));
// Construct the new target by replacing the end
cname->addRdata(rdata::generic::CNAME(qname_.split(0,
qname_.getLabelCount() -
db_result.rrset->getName().getLabelCount()).
concatenate(dname.getDname())));
response_.addRRset(Message::SECTION_ANSWER, cname, dnssec_);
break;
response_.setRcode(Rcode::YXDOMAIN());
return;
}
case ZoneFinder::CNAME:
case ZoneFinder::WILDCARD_CNAME:
/*
* We don't do chaining yet. Therefore handling a CNAME is
* mostly the same as handling SUCCESS, but we didn't get
* what we expected. It means no exceptions in ANY or NS
* on the origin (though CNAME in origin is probably
* forbidden anyway).
*
* So, just put it there.
*/
response_.addRRset(Message::SECTION_ANSWER,
boost::const_pointer_cast<RRset>(db_result.rrset),
dnssec_);
// The new CNAME we are creating (it will be unsigned even
// with DNSSEC, the DNAME is signed and it can be validated
// by that)
RRsetPtr cname(new RRset(qname_, db_result.rrset->getClass(),
RRType::CNAME(), db_result.rrset->getTTL()));
// Construct the new target by replacing the end
cname->addRdata(rdata::generic::CNAME(qname_.split(0,
qname_.getLabelCount() -
db_result.rrset->getName().getLabelCount()).
concatenate(dname.getDname())));
response_.addRRset(Message::SECTION_ANSWER, cname, dnssec_);
break;
}
case ZoneFinder::CNAME:
case ZoneFinder::WILDCARD_CNAME:
/*
* We don't do chaining yet. Therefore handling a CNAME is
* mostly the same as handling SUCCESS, but we didn't get
* what we expected. It means no exceptions in ANY or NS
* on the origin (though CNAME in origin is probably
* forbidden anyway).
*
* So, just put it there.
*/
response_.addRRset(Message::SECTION_ANSWER,
boost::const_pointer_cast<RRset>(db_result.rrset),
dnssec_);
// If the answer is a result of wildcard substitution,
// add a proof that there's no closer name.
if (dnssec_ && db_result.code == ZoneFinder::WILDCARD_CNAME) {
addWildcardProof(*result.zone_finder);
}
break;
case ZoneFinder::SUCCESS:
case ZoneFinder::WILDCARD:
if (qtype_is_any) {
// If quety type is ANY, insert all RRs under the domain
// into answer section.
BOOST_FOREACH(RRsetPtr rrset, *target) {
response_.addRRset(Message::SECTION_ANSWER, rrset,
dnssec_);
// Handle additional for answer section
addAdditional(*result.zone_finder, *rrset.get());
}
} else {
// If the answer is a result of wildcard substitution,
// add a proof that there's no closer name.
if (dnssec_ && db_result.code == ZoneFinder::WILDCARD_CNAME) {
addWildcardProof(*result.zone_finder);
}
break;
case ZoneFinder::SUCCESS:
case ZoneFinder::WILDCARD:
if (qtype_is_any) {
// If quety type is ANY, insert all RRs under the domain
// into answer section.
BOOST_FOREACH(ConstRRsetPtr rrset, target) {
response_.addRRset(Message::SECTION_ANSWER,
boost::const_pointer_cast<RRset>(db_result.rrset),
dnssec_);
boost::const_pointer_cast<RRset>(rrset), dnssec_);
// Handle additional for answer section
addAdditional(*result.zone_finder, *db_result.rrset);
addAdditional(*result.zone_finder, *rrset.get());
}
// If apex NS records haven't been provided in the answer
// section, insert apex NS records into the authority section
// and AAAA/A RRS of each of the NS RDATA into the additional
// section.
if (qname_ != result.zone_finder->getOrigin() ||
db_result.code != ZoneFinder::SUCCESS ||
(qtype_ != RRType::NS() && !qtype_is_any))
{
addAuthAdditional(*result.zone_finder);
}
// If the answer is a result of wildcard substitution,
// add a proof that there's no closer name.
if (dnssec_ && db_result.code == ZoneFinder::WILDCARD) {
addWildcardProof(*result.zone_finder);
}
break;
case ZoneFinder::DELEGATION:
response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
response_.addRRset(Message::SECTION_AUTHORITY,
} else {
response_.addRRset(Message::SECTION_ANSWER,
boost::const_pointer_cast<RRset>(db_result.rrset),
dnssec_);
// Handle additional for answer section
addAdditional(*result.zone_finder, *db_result.rrset);
break;
case ZoneFinder::NXDOMAIN:
response_.setRcode(Rcode::NXDOMAIN());
addSOA(*result.zone_finder);
if (dnssec_ && db_result.rrset) {
addNXDOMAINProof(zfinder, db_result.rrset);
}
break;
case ZoneFinder::NXRRSET:
addSOA(*result.zone_finder);
if (dnssec_ && db_result.rrset) {
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<RRset>(
db_result.rrset),
dnssec_);
}
break;
case ZoneFinder::WILDCARD_NXRRSET:
addSOA(*result.zone_finder);
if (dnssec_ && db_result.rrset) {
addWildcardNXRRSETProof(zfinder, db_result.rrset);
}
break;
default:
// This is basically a bug of the data source implementation,
// but could also happen in the middle of development where
// we try to add a new result code.
isc_throw(isc::NotImplemented, "Unknown result code");
break;
}
}
// If apex NS records haven't been provided in the answer
// section, insert apex NS records into the authority section
// and AAAA/A RRS of each of the NS RDATA into the additional
// section.
if (qname_ != result.zone_finder->getOrigin() ||
db_result.code != ZoneFinder::SUCCESS ||
(qtype_ != RRType::NS() && !qtype_is_any))
{
addAuthAdditional(*result.zone_finder);
}
// If the answer is a result of wildcard substitution,
// add a proof that there's no closer name.
if (dnssec_ && db_result.code == ZoneFinder::WILDCARD) {
addWildcardProof(*result.zone_finder);
}
break;
case ZoneFinder::DELEGATION:
response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<RRset>(db_result.rrset),
dnssec_);
addAdditional(*result.zone_finder, *db_result.rrset);
break;
case ZoneFinder::NXDOMAIN:
response_.setRcode(Rcode::NXDOMAIN());
addSOA(*result.zone_finder);
if (dnssec_ && db_result.rrset) {
addNXDOMAINProof(zfinder, db_result.rrset);
}
break;
case ZoneFinder::NXRRSET:
addSOA(*result.zone_finder);
if (dnssec_ && db_result.rrset) {
response_.addRRset(Message::SECTION_AUTHORITY,
boost::const_pointer_cast<RRset>(
db_result.rrset),
dnssec_);
}
break;
case ZoneFinder::WILDCARD_NXRRSET:
addSOA(*result.zone_finder);
if (dnssec_ && db_result.rrset) {
addWildcardNXRRSETProof(zfinder, db_result.rrset);
}
break;
default:
// This is basically a bug of the data source implementation,
// but could also happen in the middle of development where
// we try to add a new result code.
isc_throw(isc::NotImplemented, "Unknown result code");
break;
}
}
......
......@@ -211,8 +211,10 @@ public:
virtual isc::dns::RRClass getClass() const { return (rrclass_); }
virtual FindResult find(const isc::dns::Name& name,
const isc::dns::RRType& type,
RRsetList* target = NULL,
const FindOptions options = FIND_DEFAULT);
virtual FindResult findAll(const isc::dns::Name& name,
std::vector<ConstRRsetPtr>& target,
const FindOptions options = FIND_DEFAULT);
// If false is passed, it makes the zone broken as if it didn't have the
// SOA.
......@@ -304,9 +306,30 @@ substituteWild(const RRset& wild_rrset, const Name& real_name) {
return (rrset);
}
ZoneFinder::FindResult
MockZoneFinder::findAll(const Name& name, std::vector<ConstRRsetPtr>& target,
const FindOptions options)
{
ZoneFinder::FindResult result(find(name, RRType::ANY(), options));
if (result.code == NXRRSET) {
const Domains::const_iterator found_domain = domains_.find(name);
if (!found_domain->second.empty()) {
for (RRsetStore::const_iterator found_rrset =
found_domain->second.begin();
found_rrset != found_domain->second.end(); ++found_rrset) {
// Insert RRs under the domain name into target
target.push_back(found_rrset->second);
}
return (FindResult(SUCCESS, RRsetPtr()));
}
}
return (result);
}
ZoneFinder::FindResult
MockZoneFinder::find(const Name& name, const RRType& type,
RRsetList* target, const FindOptions options)
const FindOptions options)
{
// Emulating a broken zone: mandatory apex RRs are missing if specifically
// configured so (which are rare cases).
......@@ -358,17 +381,6 @@ MockZoneFinder::find(const Name& name, const RRType& type,
return (FindResult(SUCCESS, rrset));
}
// If not found but we have a target, fill it with all RRsets here
if (!found_domain->second.empty() && target != NULL) {
for (found_rrset = found_domain->second.begin();
found_rrset != found_domain->second.end(); ++found_rrset) {
// Insert RRs under the domain name into target
target->addRRset(
boost::const_pointer_cast<RRset>(found_rrset->second));
}
return (FindResult(SUCCESS, found_domain->second.begin()->second));
}
// Otherwise, if this domain name has CNAME, return it.
found_rrset = found_domain->second.find(RRType::CNAME());
if (found_rrset != found_domain->second.end()) {
......
......@@ -176,7 +176,8 @@ private:
DatabaseClient::Finder::FoundRRsets
DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
bool check_ns, const string* construct_name)
bool check_ns, const string* construct_name,
bool any)
{
RRsigStore sig_store;
bool records_found = false;
......@@ -221,7 +222,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
columns[DatabaseAccessor::RDATA_COLUMN]));
}
if (types.find(cur_type) != types.end()) {
if (types.find(cur_type) != types.end() || any) {
// This type is requested, so put it into result
const RRTTL cur_ttl(columns[DatabaseAccessor::TTL_COLUMN]);
// Ths sigtype column was an optimization for finding the
......@@ -286,6 +287,12 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
sig_store.appendSignatures(i->second);
}
if (records_found && any) {
result[RRType::ANY()] = RRsetPtr();
// These will be sitting on the other RRsets.
result.erase(RRType::RRSIG());
}
return (FoundRRsets(records_found, result));
}
......@@ -389,6 +396,25 @@ DatabaseClient::Finder::findNSECCover(const Name& name) {
return (ConstRRsetPtr());
}
ZoneFinder::FindResult
DatabaseClient::Finder::findAll(const isc::dns::Name& name,
std::vector<isc::dns::ConstRRsetPtr>& target,
const FindOptions options)
{
return (findInternal(name, RRType::ANY(), &target, options));
}
ZoneFinder::FindResult
DatabaseClient::Finder::find(const isc::dns::Name& name,
const isc::dns::RRType& type,
const FindOptions options)
{
if (type == RRType::ANY()) {
isc_throw(isc::Unexpected, "Use findAll to answer ANY");
}
return (findInternal(name, type, NULL, options));
}
DatabaseClient::Finder::DelegationSearchResult
DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
const FindOptions options)
......@@ -550,7 +576,8 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
ZoneFinder::FindResult
DatabaseClient::Finder::findWildcardMatch(
const isc::dns::Name& name, const isc::dns::RRType& type,
const FindOptions options, const DelegationSearchResult& dresult)
const FindOptions options, const DelegationSearchResult& dresult,
std::vector<isc::dns::ConstRRsetPtr>* target)
{
// Note that during the search we are going to search not only for the
// requested type, but also for types that indicate a delegation -
......@@ -569,7 +596,7 @@ DatabaseClient::Finder::findWildcardMatch(
// RFC 4592 section 4.4).
// Search for a match. The types are the same as with original query.
FoundRRsets found = getRRsets(wildcard, final_types, true,
&construct_name);
&construct_name, type == RRType::ANY());
if (found.first) {
// Found something - but what?
......@@ -594,7 +621,7 @@ DatabaseClient::Finder::findWildcardMatch(
// The wildcard match is the best one, find the final result
// at it. Note that wildcard should never be the zone origin.
return (findOnNameResult(name, type, options, false,
found, &wildcard));
found, &wildcard, target));
} else {
// more specified match found, cancel wildcard match
......@@ -660,7 +687,9 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
const FindOptions options,
const bool is_origin,
const FoundRRsets& found,
const string* wildname)
const string* wildname,
std::vector<isc::dns::ConstRRsetPtr>*
target)
{
const bool wild = (wildname != NULL);
......@@ -698,14 +727,29 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
DATASRC_DATABASE_FOUND_CNAME));
} else if (wti != found.second.end()) {
bool any(type == RRType::ANY());
isc::log::MessageID lid(wild ? DATASRC_DATABASE_WILDCARD_MATCH :
DATASRC_DATABASE_FOUND_RRSET);
if (any) {
// An ANY query, copy everything to the target instead of returning
// directly.
for (FoundIterator it(found.second.begin());
it != found.second.end(); ++it) {
if (it->second) {
// Skip over the empty ANY
target->push_back(it->second);
}
}
lid = wild ? DATASRC_DATABASE_WILDCARD_ANY :
DATASRC_DATABASE_FOUND_ANY;
}
// Found an RR matching the query, so return it. (Note that this
// includes the case where we were explicitly querying for a CNAME and
// found it. It also includes the case where we were querying for an
// NS RRset and found it at the apex of the zone.)
return (logAndCreateResult(name, wildname, type,
wild ? WILDCARD : SUCCESS, wti->second,
wild ? DATASRC_DATABASE_WILDCARD_MATCH :
DATASRC_DATABASE_FOUND_RRSET));
lid));
}
// If we get here, we have found something at the requested name but not
......@@ -747,7 +791,9 @@ DatabaseClient::Finder::findOnNameResult(const Name& name,
ZoneFinder::FindResult
DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
FindOptions options,
const DelegationSearchResult& dresult)
const DelegationSearchResult& dresult,
std::vector<isc::dns::ConstRRsetPtr>*
target)
{
const bool dnssec_data = ((options & FIND_DNSSEC) != 0);
......@@ -771,7 +817,7 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
// (i.e. all results except NXDOMAIN) return it; otherwise fall
// through to the NXDOMAIN case below.
const ZoneFinder::FindResult wresult =
findWildcardMatch(name, type, options, dresult);
findWildcardMatch(name, type, options, dresult, target);
if (wresult.code != NXDOMAIN) {
return (FindResult(wresult.code, wresult.rrset));
}
......@@ -786,9 +832,9 @@ DatabaseClient::Finder::findNoNameResult(const Name& name, const RRType& type,
}
ZoneFinder::FindResult
DatabaseClient::Finder::find(const isc::dns::Name& name,
DatabaseClient::Finder::findInternal(const isc::dns::Name& name,
const isc::dns::RRType& type,
isc::dns::RRsetList*,
std::vector<isc::dns::ConstRRsetPtr>* target,
const FindOptions options)
{
LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
......@@ -820,16 +866,18 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
WantedTypes final_types(FINAL_TYPES());
final_types.insert(type);
const FoundRRsets found = getRRsets(name.toText(), final_types,
!is_origin);
!is_origin, NULL,
type == RRType::ANY());
if (found.first) {
// Something found at the domain name. Look into it further to get
// the final result.
return (findOnNameResult(name, type, options, is_origin, found, NULL));
return (findOnNameResult(name, type, options, is_origin, found, NULL,
target));
} else {
// Did not find anything at all at the domain name, so check for
// subdomains or wildcards.
return (findNoNameResult(name, type, options, dresult));
return (findNoNameResult(name, type, options, dresult, target));
}
}
......@@ -897,7 +945,7 @@ public:
// Find the SOA of the zone (may or may not succeed). Note that
// this must be done before starting the iteration context.
soa_ = DatabaseClient::Finder(accessor_, zone.second, zone_name).
find(zone_name, RRType::SOA(), NULL).rrset;
find(zone_name, RRType::SOA()).rrset;
// Request the context
context_ = accessor_->getAllRecords(zone.second);
......