query.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <dns/message.h>
  15. #include <dns/rcode.h>
  16. #include <dns/rrtype.h>
  17. #include <dns/rrset.h>
  18. #include <dns/rdataclass.h>
  19. #include <datasrc/client.h>
  20. #include <datasrc/client_list.h>
  21. #include <auth/query.h>
  22. #include <boost/foreach.hpp>
  23. #include <boost/bind.hpp>
  24. #include <boost/function.hpp>
  25. #include <cassert>
  26. #include <algorithm> // for std::max
  27. #include <functional>
  28. #include <vector>
  29. using namespace std;
  30. using namespace isc::dns;
  31. using namespace isc::datasrc;
  32. using namespace isc::dns::rdata;
  33. // This is a "constant" vector storing desired RR types for the additional
  34. // section. The vector is filled first time it's used.
  35. namespace {
  36. const vector<RRType>&
  37. A_AND_AAAA() {
  38. static vector<RRType> needed_types;
  39. if (needed_types.empty()) {
  40. needed_types.push_back(RRType::A());
  41. needed_types.push_back(RRType::AAAA());
  42. }
  43. return (needed_types);
  44. }
  45. }
  46. namespace isc {
  47. namespace auth {
  48. void
  49. Query::ResponseCreator::addRRset(isc::dns::Message& message,
  50. const isc::dns::Message::Section section,
  51. const ConstRRsetPtr& rrset)
  52. {
  53. /// Is this RRset already in the list of RRsets added to the message?
  54. const std::vector<const AbstractRRset*>::const_iterator i =
  55. std::find_if(added_.begin(), added_.end(),
  56. std::bind1st(Query::ResponseCreator::IsSameKind(),
  57. rrset.get()));
  58. if (i == added_.end()) {
  59. // No - add it to both the message and the list of RRsets processed.
  60. // The const-cast is wrong, but the message interface seems to insist.
  61. message.addRRset(section,
  62. boost::const_pointer_cast<AbstractRRset>(rrset));
  63. added_.push_back(rrset.get());
  64. }
  65. }
  66. void
  67. Query::ResponseCreator::create(Message& response,
  68. const vector<ConstRRsetPtr>& answers,
  69. const vector<ConstRRsetPtr>& authorities,
  70. const vector<ConstRRsetPtr>& additionals)
  71. {
  72. // Inserter should be reset each time the query is reset, so should be
  73. // empty at this point.
  74. assert(added_.empty());
  75. // Add the RRsets to the message. The order of sections is important,
  76. // as the ResponseCreator remembers RRsets added and will not add
  77. // duplicates. Adding in the order answer, authory, additional will
  78. // guarantee that if there are duplicates, the single RRset added will
  79. // appear in the most important section.
  80. BOOST_FOREACH(const ConstRRsetPtr& rrset, answers) {
  81. addRRset(response, Message::SECTION_ANSWER, rrset);
  82. }
  83. BOOST_FOREACH(const ConstRRsetPtr& rrset, authorities) {
  84. addRRset(response, Message::SECTION_AUTHORITY, rrset);
  85. }
  86. BOOST_FOREACH(const ConstRRsetPtr& rrset, additionals) {
  87. addRRset(response, Message::SECTION_ADDITIONAL, rrset);
  88. }
  89. }
  90. void
  91. Query::addSOA(ZoneFinder& finder) {
  92. // This method is always called in finding SOA for a negative response,
  93. // so we specify the use of min(RRTTL, SOA MINTTL) as specified in
  94. // Section 3 of RFC2308.
  95. ZoneFinderContextPtr soa_ctx = finder.findAtOrigin(RRType::SOA(), true,
  96. dnssec_opt_);
  97. if (soa_ctx->code != ZoneFinder::SUCCESS) {
  98. isc_throw(NoSOA, "There's no SOA record in zone " <<
  99. finder.getOrigin().toText());
  100. } else {
  101. authorities_.push_back(soa_ctx->rrset);
  102. }
  103. }
  104. // Note: unless the data source client implementation or the zone content
  105. // is broken, 'nsec' should be a valid NSEC RR. Likewise, the call to
  106. // find() in this method should result in NXDOMAIN and an NSEC RR that proves
  107. // the non existent of matching wildcard. If these assumptions aren't met
  108. // due to a buggy data source implementation or a broken zone, we'll let
  109. // underlying libdns++ modules throw an exception, which would result in
  110. // either an SERVFAIL response or just ignoring the query. We at least prevent
  111. // a complete crash due to such broken behavior.
  112. void
  113. Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
  114. if (nsec->getRdataCount() == 0) {
  115. isc_throw(BadNSEC, "NSEC for NXDOMAIN is empty");
  116. }
  117. // Add the NSEC proving NXDOMAIN to the authority section.
  118. authorities_.push_back(nsec);
  119. // Next, identify the best possible wildcard name that would match
  120. // the query name. It's the longer common suffix with the qname
  121. // between the owner or the next domain of the NSEC that proves NXDOMAIN,
  122. // prefixed by the wildcard label, "*". For example, for query name
  123. // a.b.example.com, if the NXDOMAIN NSEC is
  124. // b.example.com. NSEC c.example.com., the longer suffix is b.example.com.,
  125. // and the best possible wildcard is *.b.example.com. If the NXDOMAIN
  126. // NSEC is a.example.com. NSEC c.b.example.com., the longer suffix
  127. // is the next domain of the NSEC, and we get the same wildcard name.
  128. const int qlabels = qname_->getLabelCount();
  129. const int olabels = qname_->compare(nsec->getName()).getCommonLabels();
  130. const int nlabels = qname_->compare(
  131. dynamic_cast<const generic::NSEC&>(nsec->getRdataIterator()->
  132. getCurrent()).
  133. getNextName()).getCommonLabels();
  134. const int common_labels = std::max(olabels, nlabels);
  135. const Name wildname(Name("*").concatenate(qname_->split(qlabels -
  136. common_labels)));
  137. // Confirm the wildcard doesn't exist (this should result in NXDOMAIN;
  138. // otherwise we shouldn't have got NXDOMAIN for the original query in
  139. // the first place).
  140. ConstZoneFinderContextPtr fcontext =
  141. finder.find(wildname, RRType::NSEC(), dnssec_opt_);
  142. if (fcontext->code != ZoneFinder::NXDOMAIN || !fcontext->rrset ||
  143. fcontext->rrset->getRdataCount() == 0) {
  144. isc_throw(BadNSEC, "Unexpected result for wildcard NXDOMAIN proof");
  145. }
  146. // Add the (no-) wildcard proof. This can be the same NSEC we already
  147. // added, but we'd add it here anyway; duplicate checks will take place
  148. // later in a unified manner.
  149. authorities_.push_back(fcontext->rrset);
  150. }
  151. uint8_t
  152. Query::addClosestEncloserProof(ZoneFinder& finder, const Name& name,
  153. bool exact_ok, bool add_closest)
  154. {
  155. const ZoneFinder::FindNSEC3Result result = finder.findNSEC3(name, true);
  156. // Validity check (see the method description). Note that a completely
  157. // broken findNSEC3 implementation could even return NULL RRset in
  158. // closest_proof. We don't explicitly check such case; addRRset() will
  159. // throw an exception, and it will be converted to SERVFAIL at the caller.
  160. if (!exact_ok && !result.next_proof) {
  161. isc_throw(BadNSEC3, "Matching NSEC3 found for a non existent name: "
  162. << qname_);
  163. }
  164. if (add_closest) {
  165. authorities_.push_back(result.closest_proof);
  166. }
  167. if (result.next_proof) {
  168. authorities_.push_back(result.next_proof);
  169. }
  170. return (result.closest_labels);
  171. }
  172. void
  173. Query::addNSEC3ForName(ZoneFinder& finder, const Name& name, bool match) {
  174. const ZoneFinder::FindNSEC3Result result = finder.findNSEC3(name, false);
  175. // See the comment for addClosestEncloserProof(). We don't check a
  176. // totally bogus case where closest_proof is NULL here.
  177. if (match != result.matched) {
  178. isc_throw(BadNSEC3, "Unexpected "
  179. << (result.matched ? "matching" : "covering")
  180. << " NSEC3 found for " << name);
  181. }
  182. authorities_.push_back(result.closest_proof);
  183. }
  184. void
  185. Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
  186. // Firstly get the NSEC3 proves for Closest Encloser Proof
  187. // See Section 7.2.1 of RFC 5155.
  188. const uint8_t closest_labels =
  189. addClosestEncloserProof(finder, *qname_, false);
  190. // Next, construct the wildcard name at the closest encloser, i.e.,
  191. // '*' followed by the closest encloser, and add NSEC3 for it.
  192. const Name wildname(Name("*").concatenate(
  193. qname_->split(qname_->getLabelCount() - closest_labels)));
  194. addNSEC3ForName(finder, wildname, false);
  195. }
  196. void
  197. Query::addWildcardProof(ZoneFinder& finder,
  198. const ZoneFinder::Context& db_context)
  199. {
  200. if (db_context.isNSECSigned()) {
  201. // Case for RFC4035 Section 3.1.3.3.
  202. //
  203. // The query name shouldn't exist in the zone if there were no wildcard
  204. // substitution. Confirm that by specifying NO_WILDCARD. It should
  205. // result in NXDOMAIN and an NSEC RR that proves it should be returned.
  206. ConstZoneFinderContextPtr fcontext =
  207. finder.find(*qname_, RRType::NSEC(),
  208. dnssec_opt_ | ZoneFinder::NO_WILDCARD);
  209. if (fcontext->code != ZoneFinder::NXDOMAIN || !fcontext->rrset ||
  210. fcontext->rrset->getRdataCount() == 0) {
  211. isc_throw(BadNSEC,
  212. "Unexpected NSEC result for wildcard proof");
  213. }
  214. authorities_.push_back(fcontext->rrset);
  215. } else if (db_context.isNSEC3Signed()) {
  216. // Case for RFC 5155 Section 7.2.6.
  217. //
  218. // Note that the closest encloser must be the immediate ancestor
  219. // of the matching wildcard, so NSEC3 for its next closer (and only
  220. // that NSEC3) is what we are expected to provided per the RFC (if
  221. // this assumption isn't met the zone is broken anyway).
  222. addClosestEncloserProof(finder, *qname_, false, false);
  223. }
  224. }
  225. void
  226. Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
  227. // There should be one NSEC RR which was found in the zone to prove
  228. // that there is not matched <QNAME,QTYPE> via wildcard expansion.
  229. if (nsec->getRdataCount() == 0) {
  230. isc_throw(BadNSEC, "NSEC for WILDCARD_NXRRSET is empty");
  231. }
  232. ConstZoneFinderContextPtr fcontext =
  233. finder.find(*qname_, RRType::NSEC(),
  234. dnssec_opt_ | ZoneFinder::NO_WILDCARD);
  235. if (fcontext->code != ZoneFinder::NXDOMAIN || !fcontext->rrset ||
  236. fcontext->rrset->getRdataCount() == 0) {
  237. isc_throw(BadNSEC, "Unexpected result for no match QNAME proof");
  238. }
  239. authorities_.push_back(fcontext->rrset);
  240. }
  241. void
  242. Query::addDS(ZoneFinder& finder, const Name& dname) {
  243. ConstZoneFinderContextPtr ds_context =
  244. finder.find(dname, RRType::DS(), dnssec_opt_);
  245. if (ds_context->code == ZoneFinder::SUCCESS) {
  246. authorities_.push_back(ds_context->rrset);
  247. } else if (ds_context->code == ZoneFinder::NXRRSET &&
  248. ds_context->isNSECSigned()) {
  249. addNXRRsetProof(finder, *ds_context);
  250. } else if (ds_context->code == ZoneFinder::NXRRSET &&
  251. ds_context->isNSEC3Signed()) {
  252. // Add no DS proof with NSEC3 as specified in RFC 5155 Section 7.2.7.
  253. addClosestEncloserProof(finder, dname, true);
  254. } else if (ds_context->code != ZoneFinder::NXRRSET) {
  255. // We know this domain should exist, so the result must be NXRRSET.
  256. // If not, the zone is broken, so we'll return SERVFAIL by triggering
  257. // an exception.
  258. isc_throw(BadDS, "Unexpected result for DS lookup for delegation");
  259. }
  260. }
  261. void
  262. Query::addNXRRsetProof(ZoneFinder& finder,
  263. const ZoneFinder::Context& db_context)
  264. {
  265. if (db_context.isNSECSigned() && db_context.rrset) {
  266. authorities_.push_back(db_context.rrset);
  267. if (db_context.isWildcard()) {
  268. addWildcardNXRRSETProof(finder, db_context.rrset);
  269. }
  270. } else if (db_context.isNSEC3Signed() && !db_context.isWildcard()) {
  271. if (*qtype_ == RRType::DS()) {
  272. // RFC 5155, Section 7.2.4. Add either NSEC3 for the qname or
  273. // closest (provable) encloser proof in case of optout.
  274. addClosestEncloserProof(finder, *qname_, true);
  275. } else {
  276. // RFC 5155, Section 7.2.3. Just add NSEC3 for the qname.
  277. addNSEC3ForName(finder, *qname_, true);
  278. }
  279. } else if (db_context.isNSEC3Signed() && db_context.isWildcard()) {
  280. // Case for RFC 5155 Section 7.2.5: add closest encloser proof for the
  281. // qname, construct the matched wildcard name and add NSEC3 for it.
  282. const uint8_t closest_labels =
  283. addClosestEncloserProof(finder, *qname_, false);
  284. const Name wname = Name("*").concatenate(
  285. qname_->split(qname_->getLabelCount() - closest_labels));
  286. addNSEC3ForName(finder, wname, true);
  287. }
  288. }
  289. void
  290. Query::addAuthAdditional(ZoneFinder& finder,
  291. vector<ConstRRsetPtr>& additionals)
  292. {
  293. // Fill in authority and addtional sections.
  294. ConstZoneFinderContextPtr ns_context =
  295. finder.findAtOrigin(RRType::NS(), false, dnssec_opt_);
  296. // zone origin name should have NS records
  297. if (ns_context->code != ZoneFinder::SUCCESS) {
  298. isc_throw(NoApexNS, "There's no apex NS records in zone " <<
  299. finder.getOrigin().toText());
  300. }
  301. authorities_.push_back(ns_context->rrset);
  302. ns_context->getAdditional(A_AND_AAAA(), additionals);
  303. }
  304. namespace {
  305. // A simple wrapper for DataSourceClient::findZone(). Normally we can simply
  306. // check the closest zone to the qname, but for type DS query we need to
  307. // look into the parent zone. Nevertheless, if there is no "parent" (i.e.,
  308. // the qname consists of a single label, which also means it's the root name),
  309. // we should search the deepest zone we have (which should be the root zone;
  310. // otherwise it's a query error).
  311. ClientList::FindResult
  312. findZone(const ClientList& list, const Name& qname, RRType qtype) {
  313. if (qtype != RRType::DS() || qname.getLabelCount() == 1) {
  314. return (list.find(qname));
  315. }
  316. return (list.find(qname.split(1)));
  317. }
  318. }
  319. void
  320. Query::process(datasrc::ClientList& client_list,
  321. const isc::dns::Name& qname, const isc::dns::RRType& qtype,
  322. isc::dns::Message& response, bool dnssec)
  323. {
  324. // Set up the cleaner object so internal pointers and vectors are
  325. // always reset after scope leaves this method
  326. QueryCleaner cleaner(*this);
  327. // Set up query parameters for the rest of the (internal) methods
  328. initialize(client_list, qname, qtype, response, dnssec);
  329. // Found a zone which is the nearest ancestor to QNAME
  330. const ClientList::FindResult result = findZone(*client_list_, *qname_,
  331. *qtype_);
  332. // If we have no matching authoritative zone for the query name, return
  333. // REFUSED. In short, this is to be compatible with BIND 9, but the
  334. // background discussion is not that simple. See the relevant topic
  335. // at the BIND 10 developers's ML:
  336. // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
  337. if (result.dsrc_client_ == NULL) {
  338. // If we tried to find a "parent zone" for a DS query and failed,
  339. // we may still have authority at the child side. If we do, the query
  340. // has to be handled there.
  341. if (*qtype_ == RRType::DS() && qname_->getLabelCount() > 1 &&
  342. processDSAtChild()) {
  343. return;
  344. }
  345. response_->setHeaderFlag(Message::HEADERFLAG_AA, false);
  346. response_->setRcode(Rcode::REFUSED());
  347. return;
  348. }
  349. ZoneFinder& zfinder = *result.finder_;
  350. // We have authority for a zone that contain the query name (possibly
  351. // indirectly via delegation). Look into the zone.
  352. response_->setHeaderFlag(Message::HEADERFLAG_AA);
  353. response_->setRcode(Rcode::NOERROR());
  354. boost::function0<ZoneFinderContextPtr> find;
  355. const bool qtype_is_any = (*qtype_ == RRType::ANY());
  356. if (qtype_is_any) {
  357. find = boost::bind(&ZoneFinder::findAll, &zfinder, *qname_,
  358. boost::ref(answers_), dnssec_opt_);
  359. } else {
  360. find = boost::bind(&ZoneFinder::find, &zfinder, *qname_, *qtype_,
  361. dnssec_opt_);
  362. }
  363. ZoneFinderContextPtr db_context(find());
  364. switch (db_context->code) {
  365. case ZoneFinder::DNAME: {
  366. // First, put the dname into the answer
  367. answers_.push_back(db_context->rrset);
  368. /*
  369. * Empty DNAME should never get in, as it is impossible to
  370. * create one in master file.
  371. *
  372. * FIXME: Other way to prevent this should be done
  373. */
  374. assert(db_context->rrset->getRdataCount() > 0);
  375. // Get the data of DNAME
  376. RdataIteratorPtr rit = db_context->rrset->getRdataIterator();
  377. const rdata::generic::DNAME& dname(
  378. dynamic_cast<const rdata::generic::DNAME&>(rit->getCurrent()));
  379. // The yet unmatched prefix dname
  380. const Name prefix(qname_->split(0, qname_->getLabelCount() -
  381. db_context->rrset->getName().getLabelCount()));
  382. // If we put it together, will it be too long?
  383. // (The prefix contains trailing ., which will be removed
  384. if (prefix.getLength() - Name::ROOT_NAME().getLength() +
  385. dname.getDname().getLength() > Name::MAX_WIRE) {
  386. /*
  387. * In case the synthesized name is too long, section 4.1
  388. * of RFC 2672 mandates we return YXDOMAIN.
  389. */
  390. response_->setRcode(Rcode::YXDOMAIN());
  391. break;
  392. }
  393. // The new CNAME we are creating (it will be unsigned even
  394. // with DNSSEC, the DNAME is signed and it can be validated
  395. // by that)
  396. RRsetPtr cname(new RRset(*qname_, db_context->rrset->getClass(),
  397. RRType::CNAME(), db_context->rrset->getTTL()));
  398. // Construct the new target by replacing the end
  399. cname->addRdata(rdata::generic::CNAME(qname_->split(0,
  400. qname_->getLabelCount() -
  401. db_context->rrset->getName().getLabelCount()).
  402. concatenate(dname.getDname())));
  403. answers_.push_back(cname);
  404. break;
  405. }
  406. case ZoneFinder::CNAME:
  407. /*
  408. * We don't do chaining yet. Therefore handling a CNAME is
  409. * mostly the same as handling SUCCESS, but we didn't get
  410. * what we expected. It means no exceptions in ANY or NS
  411. * on the origin (though CNAME in origin is probably
  412. * forbidden anyway).
  413. *
  414. * So, just put it there.
  415. */
  416. answers_.push_back(db_context->rrset);
  417. // If the answer is a result of wildcard substitution,
  418. // add a proof that there's no closer name.
  419. if (dnssec_ && db_context->isWildcard()) {
  420. addWildcardProof(*result.finder_, *db_context);
  421. }
  422. break;
  423. case ZoneFinder::SUCCESS:
  424. // If query type is ANY, the rrs have already been added
  425. if (!qtype_is_any) {
  426. answers_.push_back(db_context->rrset);
  427. }
  428. // Retrieve additional records for the answer
  429. db_context->getAdditional(A_AND_AAAA(), additionals_);
  430. // If apex NS records haven't been provided in the answer
  431. // section, insert apex NS records into the authority section
  432. // and AAAA/A RRS of each of the NS RDATA into the additional
  433. // section.
  434. // Checking the findZone() is a lightweight check to see if
  435. // qname is the zone origin.
  436. if (!result.exact_match_ ||
  437. db_context->code != ZoneFinder::SUCCESS ||
  438. (*qtype_ != RRType::NS() && !qtype_is_any))
  439. {
  440. addAuthAdditional(*result.finder_, additionals_);
  441. }
  442. // If the answer is a result of wildcard substitution,
  443. // add a proof that there's no closer name.
  444. if (dnssec_ && db_context->isWildcard()) {
  445. addWildcardProof(*result.finder_, *db_context);
  446. }
  447. break;
  448. case ZoneFinder::DELEGATION:
  449. // If a DS query resulted in delegation, we also need to check
  450. // if we are an authority of the child, too. If so, we need to
  451. // complete the process in the child as specified in Section
  452. // 2.2.1.2. of RFC3658.
  453. if (*qtype_ == RRType::DS() && processDSAtChild()) {
  454. return;
  455. }
  456. response_->setHeaderFlag(Message::HEADERFLAG_AA, false);
  457. authorities_.push_back(db_context->rrset);
  458. // Retrieve additional records for the name servers
  459. db_context->getAdditional(A_AND_AAAA(), additionals_);
  460. // If DNSSEC is requested, see whether there is a DS
  461. // record for this delegation.
  462. if (dnssec_) {
  463. addDS(*result.finder_, db_context->rrset->getName());
  464. }
  465. break;
  466. case ZoneFinder::NXDOMAIN:
  467. response_->setRcode(Rcode::NXDOMAIN());
  468. addSOA(*result.finder_);
  469. if (dnssec_) {
  470. if (db_context->isNSECSigned() && db_context->rrset) {
  471. addNXDOMAINProofByNSEC(zfinder, db_context->rrset);
  472. } else if (db_context->isNSEC3Signed()) {
  473. addNXDOMAINProofByNSEC3(zfinder);
  474. }
  475. }
  476. break;
  477. case ZoneFinder::NXRRSET:
  478. addSOA(*result.finder_);
  479. if (dnssec_) {
  480. addNXRRsetProof(zfinder, *db_context);
  481. }
  482. break;
  483. default:
  484. // This is basically a bug of the data source implementation,
  485. // but could also happen in the middle of development where
  486. // we try to add a new result code.
  487. isc_throw(isc::NotImplemented, "Unknown result code");
  488. break;
  489. }
  490. response_creator_.create(*response_, answers_, authorities_, additionals_);
  491. }
  492. void
  493. Query::initialize(datasrc::ClientList& client_list,
  494. const isc::dns::Name& qname, const isc::dns::RRType& qtype,
  495. isc::dns::Message& response, bool dnssec)
  496. {
  497. client_list_ = &client_list;
  498. qname_ = &qname;
  499. qtype_ = &qtype;
  500. response_ = &response;
  501. dnssec_ = dnssec;
  502. dnssec_opt_ = (dnssec ? isc::datasrc::ZoneFinder::FIND_DNSSEC :
  503. isc::datasrc::ZoneFinder::FIND_DEFAULT);
  504. }
  505. void
  506. Query::reset() {
  507. client_list_ = NULL;
  508. qname_ = NULL;
  509. qtype_ = NULL;
  510. response_ = NULL;
  511. answers_.clear();
  512. authorities_.clear();
  513. additionals_.clear();
  514. response_creator_.clear();
  515. }
  516. bool
  517. Query::processDSAtChild() {
  518. const ClientList::FindResult zresult = client_list_->find(*qname_, true);
  519. if (zresult.dsrc_client_ == NULL) {
  520. return (false);
  521. }
  522. // We are receiving a DS query at the child side of the owner name,
  523. // where the DS isn't supposed to belong. We should return a "no data"
  524. // response as described in Section 3.1.4.1 of RFC4035 and Section
  525. // 2.2.1.1 of RFC 3658. find(DS) should result in NXRRSET, in which
  526. // case (and if DNSSEC is required) we also add the proof for that,
  527. // but even if find() returns an unexpected result, we don't bother.
  528. // The important point in this case is to return SOA so that the resolver
  529. // that happens to contact us can hunt for the appropriate parent zone
  530. // by seeing the SOA.
  531. response_->setHeaderFlag(Message::HEADERFLAG_AA);
  532. response_->setRcode(Rcode::NOERROR());
  533. addSOA(*zresult.finder_);
  534. ConstZoneFinderContextPtr ds_context =
  535. zresult.finder_->find(*qname_, RRType::DS(), dnssec_opt_);
  536. if (ds_context->code == ZoneFinder::NXRRSET) {
  537. if (dnssec_) {
  538. addNXRRsetProof(*zresult.finder_, *ds_context);
  539. }
  540. }
  541. response_creator_.create(*response_, answers_, authorities_, additionals_);
  542. return (true);
  543. }
  544. }
  545. }