query.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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 <algorithm> // for std::max
  15. #include <vector>
  16. #include <boost/foreach.hpp>
  17. #include <boost/bind.hpp>
  18. #include <boost/function.hpp>
  19. #include <dns/message.h>
  20. #include <dns/rcode.h>
  21. #include <dns/rdataclass.h>
  22. #include <datasrc/client.h>
  23. #include <auth/query.h>
  24. using namespace isc::dns;
  25. using namespace isc::datasrc;
  26. using namespace isc::dns::rdata;
  27. namespace isc {
  28. namespace auth {
  29. void
  30. Query::addAdditional(ZoneFinder& zone, const AbstractRRset& rrset) {
  31. RdataIteratorPtr rdata_iterator(rrset.getRdataIterator());
  32. for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
  33. const Rdata& rdata(rdata_iterator->getCurrent());
  34. if (rrset.getType() == RRType::NS()) {
  35. // Need to perform the search in the "GLUE OK" mode.
  36. const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
  37. addAdditionalAddrs(zone, ns.getNSName(), ZoneFinder::FIND_GLUE_OK);
  38. } else if (rrset.getType() == RRType::MX()) {
  39. const generic::MX& mx(dynamic_cast<const generic::MX&>(rdata));
  40. addAdditionalAddrs(zone, mx.getMXName());
  41. }
  42. }
  43. }
  44. void
  45. Query::addAdditionalAddrs(ZoneFinder& zone, const Name& qname,
  46. const ZoneFinder::FindOptions options)
  47. {
  48. // Out of zone name
  49. NameComparisonResult result = zone.getOrigin().compare(qname);
  50. if ((result.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
  51. (result.getRelation() != NameComparisonResult::EQUAL))
  52. return;
  53. // Omit additional data which has already been provided in the answer
  54. // section from the additional.
  55. //
  56. // All the address rrset with the owner name of qname have been inserted
  57. // into ANSWER section.
  58. if (qname_ == qname && qtype_ == RRType::ANY())
  59. return;
  60. // Find A rrset
  61. if (qname_ != qname || qtype_ != RRType::A()) {
  62. ZoneFinder::FindResult a_result = zone.find(qname, RRType::A(),
  63. options | dnssec_opt_);
  64. if (a_result.code == ZoneFinder::SUCCESS) {
  65. response_.addRRset(Message::SECTION_ADDITIONAL,
  66. boost::const_pointer_cast<AbstractRRset>(a_result.rrset), dnssec_);
  67. }
  68. }
  69. // Find AAAA rrset
  70. if (qname_ != qname || qtype_ != RRType::AAAA()) {
  71. ZoneFinder::FindResult aaaa_result = zone.find(qname, RRType::AAAA(),
  72. options | dnssec_opt_);
  73. if (aaaa_result.code == ZoneFinder::SUCCESS) {
  74. response_.addRRset(Message::SECTION_ADDITIONAL,
  75. boost::const_pointer_cast<AbstractRRset>(aaaa_result.rrset),
  76. dnssec_);
  77. }
  78. }
  79. }
  80. void
  81. Query::addSOA(ZoneFinder& finder) {
  82. ZoneFinder::FindResult soa_result = finder.find(finder.getOrigin(),
  83. RRType::SOA(),
  84. dnssec_opt_);
  85. if (soa_result.code != ZoneFinder::SUCCESS) {
  86. isc_throw(NoSOA, "There's no SOA record in zone " <<
  87. finder.getOrigin().toText());
  88. } else {
  89. /*
  90. * FIXME:
  91. * The const-cast is wrong, but the Message interface seems
  92. * to insist.
  93. */
  94. response_.addRRset(Message::SECTION_AUTHORITY,
  95. boost::const_pointer_cast<AbstractRRset>(soa_result.rrset), dnssec_);
  96. }
  97. }
  98. // Note: unless the data source client implementation or the zone content
  99. // is broken, 'nsec' should be a valid NSEC RR. Likewise, the call to
  100. // find() in this method should result in NXDOMAIN and an NSEC RR that proves
  101. // the non existent of matching wildcard. If these assumptions aren't met
  102. // due to a buggy data source implementation or a broken zone, we'll let
  103. // underlying libdns++ modules throw an exception, which would result in
  104. // either an SERVFAIL response or just ignoring the query. We at least prevent
  105. // a complete crash due to such broken behavior.
  106. void
  107. Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
  108. if (nsec->getRdataCount() == 0) {
  109. isc_throw(BadNSEC, "NSEC for NXDOMAIN is empty");
  110. }
  111. // Add the NSEC proving NXDOMAIN to the authority section.
  112. response_.addRRset(Message::SECTION_AUTHORITY,
  113. boost::const_pointer_cast<AbstractRRset>(nsec), dnssec_);
  114. // Next, identify the best possible wildcard name that would match
  115. // the query name. It's the longer common suffix with the qname
  116. // between the owner or the next domain of the NSEC that proves NXDOMAIN,
  117. // prefixed by the wildcard label, "*". For example, for query name
  118. // a.b.example.com, if the NXDOMAIN NSEC is
  119. // b.example.com. NSEC c.example.com., the longer suffix is b.example.com.,
  120. // and the best possible wildcard is *.b.example.com. If the NXDOMAIN
  121. // NSEC is a.example.com. NSEC c.b.example.com., the longer suffix
  122. // is the next domain of the NSEC, and we get the same wildcard name.
  123. const int qlabels = qname_.getLabelCount();
  124. const int olabels = qname_.compare(nsec->getName()).getCommonLabels();
  125. const int nlabels = qname_.compare(
  126. dynamic_cast<const generic::NSEC&>(nsec->getRdataIterator()->
  127. getCurrent()).
  128. getNextName()).getCommonLabels();
  129. const int common_labels = std::max(olabels, nlabels);
  130. const Name wildname(Name("*").concatenate(qname_.split(qlabels -
  131. common_labels)));
  132. // Confirm the wildcard doesn't exist (this should result in NXDOMAIN;
  133. // otherwise we shouldn't have got NXDOMAIN for the original query in
  134. // the first place).
  135. const ZoneFinder::FindResult fresult =
  136. finder.find(wildname, RRType::NSEC(), dnssec_opt_);
  137. if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
  138. fresult.rrset->getRdataCount() == 0) {
  139. isc_throw(BadNSEC, "Unexpected result for wildcard NXDOMAIN proof");
  140. }
  141. // Add the (no-) wildcard proof only when it's different from the NSEC
  142. // that proves NXDOMAIN; sometimes they can be the same.
  143. // Note: name comparison is relatively expensive. When we are at the
  144. // stage of performance optimization, we should consider optimizing this
  145. // for some optimized data source implementations.
  146. if (nsec->getName() != fresult.rrset->getName()) {
  147. response_.addRRset(Message::SECTION_AUTHORITY,
  148. boost::const_pointer_cast<AbstractRRset>(fresult.rrset),
  149. dnssec_);
  150. }
  151. }
  152. void
  153. Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
  154. // Firstly get the NSEC3 proves for Closest Encloser Proof
  155. // See section 7.2.1 of RFC 5155.
  156. // Since this is a Name Error case both closest and next proofs should
  157. // be available (see addNXRRsetProof).
  158. const ZoneFinder::FindNSEC3Result fresult1 = finder.findNSEC3(qname_,
  159. true);
  160. response_.addRRset(Message::SECTION_AUTHORITY,
  161. boost::const_pointer_cast<AbstractRRset>(
  162. fresult1.closest_proof),
  163. dnssec_);
  164. response_.addRRset(Message::SECTION_AUTHORITY,
  165. boost::const_pointer_cast<AbstractRRset>(
  166. fresult1.next_proof),
  167. dnssec_);
  168. // Next, construct the wildcard name at the closest encloser, i.e.,
  169. // '*' followed by the closest encloser, and add NSEC3 for it.
  170. const Name wildname(Name("*").concatenate(
  171. qname_.split(qname_.getLabelCount() -
  172. fresult1.closest_labels)));
  173. const ZoneFinder::FindNSEC3Result fresult2 =
  174. finder.findNSEC3(wildname, false);
  175. if (fresult2.matched) {
  176. isc_throw(BadNSEC3, "Matching NSEC3 found for nonexistent domain "
  177. << wildname);
  178. }
  179. response_.addRRset(Message::SECTION_AUTHORITY,
  180. boost::const_pointer_cast<AbstractRRset>(
  181. fresult2.closest_proof),
  182. dnssec_);
  183. }
  184. void
  185. Query::addWildcardProof(ZoneFinder& finder,
  186. const ZoneFinder::FindResult& db_result)
  187. {
  188. if (db_result.isNSECSigned()) {
  189. // Case for RFC4035 Section 3.1.3.3.
  190. //
  191. // The query name shouldn't exist in the zone if there were no wildcard
  192. // substitution. Confirm that by specifying NO_WILDCARD. It should
  193. // result in NXDOMAIN and an NSEC RR that proves it should be returned.
  194. const ZoneFinder::FindResult fresult =
  195. finder.find(qname_, RRType::NSEC(),
  196. dnssec_opt_ | ZoneFinder::NO_WILDCARD);
  197. if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
  198. fresult.rrset->getRdataCount() == 0) {
  199. isc_throw(BadNSEC,
  200. "Unexpected NSEC result for wildcard proof");
  201. }
  202. response_.addRRset(Message::SECTION_AUTHORITY,
  203. boost::const_pointer_cast<AbstractRRset>(
  204. fresult.rrset),
  205. dnssec_);
  206. } else if (db_result.isNSEC3Signed()) {
  207. // Case for RFC5155 Section 7.2.6.
  208. //
  209. // Note that the closest encloser must be the immediate ancestor
  210. // of the matching wildcard, so NSEC3 for its next closer is what
  211. // we are expected to provided per the RFC (if this assumption isn't
  212. // met the zone is broken anyway).
  213. const ZoneFinder::FindNSEC3Result NSEC3Result(
  214. finder.findNSEC3(qname_, true));
  215. // Note that at this point next_proof must not be NULL unless it's
  216. // a run time collision (or zone/findNSEC3() is broken). The
  217. // unexpected case will be caught in addRRset() and result in SERVFAIL.
  218. response_.addRRset(Message::SECTION_AUTHORITY,
  219. boost::const_pointer_cast<AbstractRRset>(
  220. NSEC3Result.next_proof), dnssec_);
  221. }
  222. }
  223. void
  224. Query::addWildcardNXRRSETProof(ZoneFinder& finder, ConstRRsetPtr nsec) {
  225. // There should be one NSEC RR which was found in the zone to prove
  226. // that there is not matched <QNAME,QTYPE> via wildcard expansion.
  227. if (nsec->getRdataCount() == 0) {
  228. isc_throw(BadNSEC, "NSEC for WILDCARD_NXRRSET is empty");
  229. }
  230. const ZoneFinder::FindResult fresult =
  231. finder.find(qname_, RRType::NSEC(),
  232. dnssec_opt_ | ZoneFinder::NO_WILDCARD);
  233. if (fresult.code != ZoneFinder::NXDOMAIN || !fresult.rrset ||
  234. fresult.rrset->getRdataCount() == 0) {
  235. isc_throw(BadNSEC, "Unexpected result for no match QNAME proof");
  236. }
  237. if (nsec->getName() != fresult.rrset->getName()) {
  238. // one NSEC RR proves wildcard_nxrrset that no matched QNAME.
  239. response_.addRRset(Message::SECTION_AUTHORITY,
  240. boost::const_pointer_cast<AbstractRRset>(fresult.rrset),
  241. dnssec_);
  242. }
  243. }
  244. void
  245. Query::addDS(ZoneFinder& finder, const Name& dname) {
  246. ZoneFinder::FindResult ds_result =
  247. finder.find(dname, RRType::DS(), dnssec_opt_);
  248. if (ds_result.code == ZoneFinder::SUCCESS) {
  249. response_.addRRset(Message::SECTION_AUTHORITY,
  250. boost::const_pointer_cast<AbstractRRset>(
  251. ds_result.rrset),
  252. dnssec_);
  253. } else if (ds_result.code == ZoneFinder::NXRRSET &&
  254. ds_result.isNSECSigned()) {
  255. addNXRRsetProof(finder, ds_result);
  256. } else if (ds_result.code == ZoneFinder::NXRRSET &&
  257. ds_result.isNSEC3Signed()) {
  258. // Add no DS proof with NSEC3 as specified in RFC5155 Section 7.2.7.
  259. // Depending on whether the zone is optout or not, findNSEC3() may
  260. // return non-NULL or NULL next_proof (respectively). The Opt-Out flag
  261. // must be set or cleared accordingly, but we don't check that
  262. // in this level (as long as the zone signed validly and findNSEC3()
  263. // is valid, the condition should be met; otherwise we'd let the
  264. // validator detect the error).
  265. const ZoneFinder::FindNSEC3Result nsec3_result =
  266. finder.findNSEC3(dname, true);
  267. response_.addRRset(Message::SECTION_AUTHORITY,
  268. boost::const_pointer_cast<AbstractRRset>(
  269. nsec3_result.closest_proof), dnssec_);
  270. if (nsec3_result.next_proof) {
  271. response_.addRRset(Message::SECTION_AUTHORITY,
  272. boost::const_pointer_cast<AbstractRRset>(
  273. nsec3_result.next_proof), dnssec_);
  274. }
  275. } else {
  276. // Any other case should be an error
  277. isc_throw(BadDS, "Unexpected result for DS lookup for delegation");
  278. }
  279. }
  280. void
  281. Query::addNXRRsetProof(ZoneFinder& finder,
  282. const ZoneFinder::FindResult& db_result)
  283. {
  284. if (db_result.isNSECSigned() && db_result.rrset) {
  285. response_.addRRset(Message::SECTION_AUTHORITY,
  286. boost::const_pointer_cast<AbstractRRset>(
  287. db_result.rrset),
  288. dnssec_);
  289. if (db_result.isWildcard()) {
  290. addWildcardNXRRSETProof(finder, db_result.rrset);
  291. }
  292. } else if (db_result.isNSEC3Signed() && !db_result.isWildcard()) {
  293. // Handling depends on whether query type is DS or not
  294. // (see RFC5155, 7.2.3 and 7.2.4): If qtype == DS, do
  295. // recursive search (and add next_proof, if necessary),
  296. // otherwise, do non-recursive search
  297. const bool qtype_ds = (qtype_ == RRType::DS());
  298. ZoneFinder::FindNSEC3Result result(finder.findNSEC3(qname_, qtype_ds));
  299. if (result.matched) {
  300. response_.addRRset(Message::SECTION_AUTHORITY,
  301. boost::const_pointer_cast<AbstractRRset>(
  302. result.closest_proof), dnssec_);
  303. // For qtype == DS, next_proof could be set
  304. // (We could check for opt-out here, but that's really the
  305. // responsibility of the datasource)
  306. if (qtype_ds && result.next_proof != ConstRRsetPtr()) {
  307. response_.addRRset(Message::SECTION_AUTHORITY,
  308. boost::const_pointer_cast<AbstractRRset>(
  309. result.next_proof), dnssec_);
  310. }
  311. } else {
  312. isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain "
  313. << qname_);
  314. }
  315. } else if (db_result.isNSEC3Signed() && db_result.isWildcard()) {
  316. // Case for RFC5155 Section 7.2.5
  317. const ZoneFinder::FindNSEC3Result result(finder.findNSEC3(qname_,
  318. true));
  319. // We know there's no exact match for the qname, so findNSEC3() should
  320. // return both closest and next proofs. If the latter is NULL, it
  321. // means a run time collision (or the zone is broken in other way).
  322. // In that case addRRset() will throw, and it will be converted to
  323. // SERVFAIL.
  324. response_.addRRset(Message::SECTION_AUTHORITY,
  325. boost::const_pointer_cast<AbstractRRset>(
  326. result.closest_proof), dnssec_);
  327. response_.addRRset(Message::SECTION_AUTHORITY,
  328. boost::const_pointer_cast<AbstractRRset>(
  329. result.next_proof), dnssec_);
  330. // Construct the matched wildcard name and add NSEC3 for it.
  331. const Name wname = Name("*").concatenate(
  332. qname_.split(qname_.getLabelCount() - result.closest_labels));
  333. const ZoneFinder::FindNSEC3Result wresult(finder.findNSEC3(wname,
  334. false));
  335. if (wresult.matched) {
  336. response_.addRRset(Message::SECTION_AUTHORITY,
  337. boost::const_pointer_cast<AbstractRRset>(
  338. wresult.closest_proof), dnssec_);
  339. } else {
  340. isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain "
  341. << wname);
  342. }
  343. }
  344. }
  345. void
  346. Query::addAuthAdditional(ZoneFinder& finder) {
  347. // Fill in authority and addtional sections.
  348. ZoneFinder::FindResult ns_result =
  349. finder.find(finder.getOrigin(), RRType::NS(), dnssec_opt_);
  350. // zone origin name should have NS records
  351. if (ns_result.code != ZoneFinder::SUCCESS) {
  352. isc_throw(NoApexNS, "There's no apex NS records in zone " <<
  353. finder.getOrigin().toText());
  354. } else {
  355. response_.addRRset(Message::SECTION_AUTHORITY,
  356. boost::const_pointer_cast<AbstractRRset>(ns_result.rrset), dnssec_);
  357. // Handle additional for authority section
  358. addAdditional(finder, *ns_result.rrset);
  359. }
  360. }
  361. namespace {
  362. // A simple wrapper for DataSourceClient::findZone(). Normally we can simply
  363. // check the closest zone to the qname, but for type DS query we need to
  364. // look into the parent zone. Nevertheless, if there is no "parent" (i.e.,
  365. // the qname consists of a single label, which also means it's the root name),
  366. // we should search the deepest zone we have (which should be the root zone;
  367. // otherwise it's a query error).
  368. DataSourceClient::FindResult
  369. findZone(const DataSourceClient& client, const Name& qname, RRType qtype) {
  370. if (qtype != RRType::DS() || qname.getLabelCount() == 1) {
  371. return (client.findZone(qname));
  372. }
  373. return (client.findZone(qname.split(1)));
  374. }
  375. }
  376. void
  377. Query::process() {
  378. // Found a zone which is the nearest ancestor to QNAME
  379. const DataSourceClient::FindResult result = findZone(datasrc_client_,
  380. qname_, qtype_);
  381. // If we have no matching authoritative zone for the query name, return
  382. // REFUSED. In short, this is to be compatible with BIND 9, but the
  383. // background discussion is not that simple. See the relevant topic
  384. // at the BIND 10 developers's ML:
  385. // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
  386. if (result.code != result::SUCCESS &&
  387. result.code != result::PARTIALMATCH) {
  388. // If we tried to find a "parent zone" for a DS query and failed,
  389. // we may still have authority at the child side. If we do, the query
  390. // has to be handled there.
  391. if (qtype_ == RRType::DS() && qname_.getLabelCount() > 1 &&
  392. processDSAtChild()) {
  393. return;
  394. }
  395. response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
  396. response_.setRcode(Rcode::REFUSED());
  397. return;
  398. }
  399. ZoneFinder& zfinder = *result.zone_finder;
  400. // We have authority for a zone that contain the query name (possibly
  401. // indirectly via delegation). Look into the zone.
  402. response_.setHeaderFlag(Message::HEADERFLAG_AA);
  403. response_.setRcode(Rcode::NOERROR());
  404. std::vector<ConstRRsetPtr> target;
  405. boost::function0<ZoneFinder::FindResult> find;
  406. const bool qtype_is_any = (qtype_ == RRType::ANY());
  407. if (qtype_is_any) {
  408. find = boost::bind(&ZoneFinder::findAll, &zfinder, qname_,
  409. boost::ref(target), dnssec_opt_);
  410. } else {
  411. find = boost::bind(&ZoneFinder::find, &zfinder, qname_, qtype_,
  412. dnssec_opt_);
  413. }
  414. ZoneFinder::FindResult db_result(find());
  415. switch (db_result.code) {
  416. case ZoneFinder::DNAME: {
  417. // First, put the dname into the answer
  418. response_.addRRset(Message::SECTION_ANSWER,
  419. boost::const_pointer_cast<AbstractRRset>(db_result.rrset),
  420. dnssec_);
  421. /*
  422. * Empty DNAME should never get in, as it is impossible to
  423. * create one in master file.
  424. *
  425. * FIXME: Other way to prevent this should be done
  426. */
  427. assert(db_result.rrset->getRdataCount() > 0);
  428. // Get the data of DNAME
  429. const rdata::generic::DNAME& dname(
  430. dynamic_cast<const rdata::generic::DNAME&>(
  431. db_result.rrset->getRdataIterator()->getCurrent()));
  432. // The yet unmatched prefix dname
  433. const Name prefix(qname_.split(0, qname_.getLabelCount() -
  434. db_result.rrset->getName().getLabelCount()));
  435. // If we put it together, will it be too long?
  436. // (The prefix contains trailing ., which will be removed
  437. if (prefix.getLength() - Name::ROOT_NAME().getLength() +
  438. dname.getDname().getLength() > Name::MAX_WIRE) {
  439. /*
  440. * In case the synthesized name is too long, section 4.1
  441. * of RFC 2672 mandates we return YXDOMAIN.
  442. */
  443. response_.setRcode(Rcode::YXDOMAIN());
  444. return;
  445. }
  446. // The new CNAME we are creating (it will be unsigned even
  447. // with DNSSEC, the DNAME is signed and it can be validated
  448. // by that)
  449. RRsetPtr cname(new RRset(qname_, db_result.rrset->getClass(),
  450. RRType::CNAME(), db_result.rrset->getTTL()));
  451. // Construct the new target by replacing the end
  452. cname->addRdata(rdata::generic::CNAME(qname_.split(0,
  453. qname_.getLabelCount() -
  454. db_result.rrset->getName().getLabelCount()).
  455. concatenate(dname.getDname())));
  456. response_.addRRset(Message::SECTION_ANSWER, cname, dnssec_);
  457. break;
  458. }
  459. case ZoneFinder::CNAME:
  460. /*
  461. * We don't do chaining yet. Therefore handling a CNAME is
  462. * mostly the same as handling SUCCESS, but we didn't get
  463. * what we expected. It means no exceptions in ANY or NS
  464. * on the origin (though CNAME in origin is probably
  465. * forbidden anyway).
  466. *
  467. * So, just put it there.
  468. */
  469. response_.addRRset(Message::SECTION_ANSWER,
  470. boost::const_pointer_cast<AbstractRRset>(db_result.rrset),
  471. dnssec_);
  472. // If the answer is a result of wildcard substitution,
  473. // add a proof that there's no closer name.
  474. if (dnssec_ && db_result.isWildcard()) {
  475. addWildcardProof(*result.zone_finder,db_result);
  476. }
  477. break;
  478. case ZoneFinder::SUCCESS:
  479. if (qtype_is_any) {
  480. // If quety type is ANY, insert all RRs under the domain
  481. // into answer section.
  482. BOOST_FOREACH(ConstRRsetPtr rrset, target) {
  483. response_.addRRset(Message::SECTION_ANSWER,
  484. boost::const_pointer_cast<AbstractRRset>(rrset), dnssec_);
  485. // Handle additional for answer section
  486. addAdditional(*result.zone_finder, *rrset.get());
  487. }
  488. } else {
  489. response_.addRRset(Message::SECTION_ANSWER,
  490. boost::const_pointer_cast<AbstractRRset>(db_result.rrset),
  491. dnssec_);
  492. // Handle additional for answer section
  493. addAdditional(*result.zone_finder, *db_result.rrset);
  494. }
  495. // If apex NS records haven't been provided in the answer
  496. // section, insert apex NS records into the authority section
  497. // and AAAA/A RRS of each of the NS RDATA into the additional
  498. // section.
  499. if (qname_ != result.zone_finder->getOrigin() ||
  500. db_result.code != ZoneFinder::SUCCESS ||
  501. (qtype_ != RRType::NS() && !qtype_is_any))
  502. {
  503. addAuthAdditional(*result.zone_finder);
  504. }
  505. // If the answer is a result of wildcard substitution,
  506. // add a proof that there's no closer name.
  507. if (dnssec_ && db_result.isWildcard()) {
  508. addWildcardProof(*result.zone_finder,db_result);
  509. }
  510. break;
  511. case ZoneFinder::DELEGATION:
  512. // If a DS query resulted in delegation, we also need to check
  513. // if we are an authority of the child, too. If so, we need to
  514. // complete the process in the child as specified in Section
  515. // 2.2.1.2. of RFC3658.
  516. if (qtype_ == RRType::DS() && processDSAtChild()) {
  517. return;
  518. }
  519. response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
  520. response_.addRRset(Message::SECTION_AUTHORITY,
  521. boost::const_pointer_cast<AbstractRRset>(db_result.rrset),
  522. dnssec_);
  523. // If DNSSEC is requested, see whether there is a DS
  524. // record for this delegation.
  525. if (dnssec_) {
  526. addDS(*result.zone_finder, db_result.rrset->getName());
  527. }
  528. addAdditional(*result.zone_finder, *db_result.rrset);
  529. break;
  530. case ZoneFinder::NXDOMAIN:
  531. response_.setRcode(Rcode::NXDOMAIN());
  532. addSOA(*result.zone_finder);
  533. if (dnssec_) {
  534. if (db_result.isNSECSigned() && db_result.rrset) {
  535. addNXDOMAINProofByNSEC(zfinder, db_result.rrset);
  536. } else if (db_result.isNSEC3Signed()) {
  537. addNXDOMAINProofByNSEC3(zfinder);
  538. }
  539. }
  540. break;
  541. case ZoneFinder::NXRRSET:
  542. addSOA(*result.zone_finder);
  543. if (dnssec_) {
  544. addNXRRsetProof(zfinder, db_result);
  545. }
  546. break;
  547. default:
  548. // This is basically a bug of the data source implementation,
  549. // but could also happen in the middle of development where
  550. // we try to add a new result code.
  551. isc_throw(isc::NotImplemented, "Unknown result code");
  552. break;
  553. }
  554. }
  555. bool
  556. Query::processDSAtChild() {
  557. const DataSourceClient::FindResult zresult =
  558. datasrc_client_.findZone(qname_);
  559. if (zresult.code != result::SUCCESS) {
  560. return (false);
  561. }
  562. // We are receiving a DS query at the child side of the owner name,
  563. // where the DS isn't supposed to belong. We should return a "no data"
  564. // response as described in Section 3.1.4.1 of RFC4035 and Section
  565. // 2.2.1.1 of RFC 3658. find(DS) should result in NXRRSET, in which
  566. // case (and if DNSSEC is required) we also add the proof for that,
  567. // but even if find() returns an unexpected result, we don't bother.
  568. // The important point in this case is to return SOA so that the resolver
  569. // that happens to contact us can hunt for the appropriate parent zone
  570. // by seeing the SOA.
  571. response_.setHeaderFlag(Message::HEADERFLAG_AA);
  572. response_.setRcode(Rcode::NOERROR());
  573. addSOA(*zresult.zone_finder);
  574. const ZoneFinder::FindResult ds_result =
  575. zresult.zone_finder->find(qname_, RRType::DS(), dnssec_opt_);
  576. if (ds_result.code == ZoneFinder::NXRRSET) {
  577. if (dnssec_) {
  578. addNXRRsetProof(*zresult.zone_finder, ds_result);
  579. }
  580. }
  581. return (true);
  582. }
  583. }
  584. }