zone_finder.cc 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. // Copyright (C) 2012 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 <datasrc/memory/zone_finder.h>
  15. #include <datasrc/memory/domaintree.h>
  16. #include <datasrc/memory/treenode_rrset.h>
  17. #include <datasrc/zone.h>
  18. #include <datasrc/data_source.h>
  19. #include <dns/labelsequence.h>
  20. #include <dns/name.h>
  21. #include <dns/rrset.h>
  22. #include <dns/rrtype.h>
  23. #include <util/buffer.h>
  24. #include <util/encode/base32hex.h>
  25. #include <util/hash/sha1.h>
  26. #include <datasrc/logger.h>
  27. using namespace isc::dns;
  28. using namespace isc::datasrc::memory;
  29. using namespace isc::datasrc;
  30. using namespace isc::util;
  31. using namespace isc::util::encode;
  32. using namespace isc::util::hash;
  33. namespace isc {
  34. namespace datasrc {
  35. namespace memory {
  36. namespace {
  37. /// Creates a TreeNodeRRsetPtr for the given RdataSet at the given Node, for
  38. /// the given RRClass
  39. ///
  40. /// We should probably have some pool so these do not need to be allocated
  41. /// dynamically.
  42. ///
  43. /// \param node The ZoneNode found by the find() calls
  44. /// \param rdataset The RdataSet to create the RRsetPtr for
  45. /// \param rrclass The RRClass as passed by the client
  46. /// \param realname If given, the TreeNodeRRset is created with this name
  47. /// (e.g. for wildcard substitution)
  48. ///
  49. /// Returns an empty TreeNodeRRsetPtr if node is NULL or if rdataset is NULL.
  50. TreeNodeRRsetPtr
  51. createTreeNodeRRset(const ZoneNode* node,
  52. const RdataSet* rdataset,
  53. const RRClass& rrclass,
  54. ZoneFinder::FindOptions options,
  55. const Name* realname = NULL)
  56. {
  57. const bool dnssec = ((options & ZoneFinder::FIND_DNSSEC) != 0);
  58. if (node != NULL && rdataset != NULL) {
  59. if (realname != NULL) {
  60. return (TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass,
  61. node, rdataset,
  62. dnssec)));
  63. } else {
  64. return (TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node, rdataset,
  65. dnssec)));
  66. }
  67. } else {
  68. return (TreeNodeRRsetPtr());
  69. }
  70. }
  71. /// Maintain intermediate data specific to the search context used in
  72. /// \c find().
  73. ///
  74. /// It will be passed to \c cutCallback() (see below) and record a possible
  75. /// zone cut node and related RRset (normally NS or DNAME).
  76. struct FindState {
  77. FindState(bool glue_ok) :
  78. zonecut_node_(NULL),
  79. dname_node_(NULL),
  80. rrset_(NULL),
  81. glue_ok_(glue_ok)
  82. {}
  83. // These will be set to a domain node of the highest delegation point,
  84. // if any. In fact, we could use a single variable instead of both.
  85. // But then we would need to distinquish these two cases by something
  86. // else and it seemed little more confusing when this was written.
  87. const ZoneNode* zonecut_node_;
  88. const ZoneNode* dname_node_;
  89. // Delegation RRset (NS or DNAME), if found.
  90. const RdataSet* rrset_;
  91. // Whether to continue search below a delegation point.
  92. // Set at construction time.
  93. const bool glue_ok_;
  94. };
  95. // A callback called from possible zone cut nodes and nodes with DNAME.
  96. // This will be passed from findNode() to \c RBTree::find().
  97. bool cutCallback(const ZoneNode& node, FindState* state) {
  98. // We need to look for DNAME first, there's allowed case where
  99. // DNAME and NS coexist in the apex. DNAME is the one to notice,
  100. // the NS is authoritative, not delegation (corner case explicitly
  101. // allowed by section 3 of 2672)
  102. const RdataSet* found_dname = RdataSet::find(node.getData(),
  103. RRType::DNAME());
  104. if (found_dname != NULL) {
  105. LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_DNAME_ENCOUNTERED);
  106. state->dname_node_ = &node;
  107. state->rrset_ = found_dname;
  108. return (true);
  109. }
  110. // Look for NS
  111. const RdataSet* found_ns = RdataSet::find(node.getData(), RRType::NS());
  112. if (found_ns != NULL) {
  113. // We perform callback check only for the highest zone cut in the
  114. // rare case of nested zone cuts.
  115. if (state->zonecut_node_ != NULL) {
  116. return (false);
  117. }
  118. LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_NS_ENCOUNTERED);
  119. // BIND 9 checks if this node is not the origin. That's probably
  120. // because it can support multiple versions for dynamic updates
  121. // and IXFR, and it's possible that the callback is called at
  122. // the apex and the DNAME doesn't exist for a particular version.
  123. // It cannot happen for us (at least for now), so we don't do
  124. // that check.
  125. state->zonecut_node_ = &node;
  126. state->rrset_ = found_ns;
  127. // Unless glue is allowed the search stops here, so we return
  128. // false; otherwise return true to continue the search.
  129. return (!state->glue_ok_);
  130. }
  131. // This case should not happen because we enable callback only
  132. // when we add an RR searched for above.
  133. assert(0);
  134. // This is here to avoid warning (therefore compilation error)
  135. // in case assert is turned off. Otherwise we could get "Control
  136. // reached end of non-void function".
  137. return (false);
  138. }
  139. // convenience function to fill in the final details
  140. //
  141. // Set up ZoneFinderResultContext object as a return value of find(),
  142. // taking into account wildcard matches and DNSSEC information. We set
  143. // the NSEC/NSEC3 flag when applicable regardless of the find option; the
  144. // caller would simply ignore these when they didn't request DNSSEC
  145. // related results.
  146. //
  147. // Also performs the conversion of node + RdataSet into a TreeNodeRRsetPtr
  148. //
  149. // if wild is true, the RESULT_WILDCARD flag will be set.
  150. // If qname is not NULL, this is the query name, to be used in wildcard
  151. // substitution instead of the Node's name).
  152. isc::datasrc::memory::ZoneFinderResultContext
  153. createFindResult(const RRClass& rrclass,
  154. const ZoneData& zone_data,
  155. ZoneFinder::Result code,
  156. const RdataSet* rdset,
  157. const ZoneNode* node,
  158. ZoneFinder::FindOptions options,
  159. bool wild = false,
  160. const Name* qname = NULL)
  161. {
  162. ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
  163. const Name* rename = NULL;
  164. if (wild) {
  165. flags = flags | ZoneFinder::RESULT_WILDCARD;
  166. // only use the rename qname if wild is true
  167. rename = qname;
  168. }
  169. if (code == ZoneFinder::NXRRSET || code == ZoneFinder::NXDOMAIN || wild) {
  170. if (zone_data.isNSEC3Signed()) {
  171. flags = flags | ZoneFinder::RESULT_NSEC3_SIGNED;
  172. } else if (zone_data.isSigned()) {
  173. flags = flags | ZoneFinder::RESULT_NSEC_SIGNED;
  174. }
  175. }
  176. return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rdset,
  177. rrclass, options,
  178. rename),
  179. flags, node));
  180. }
  181. // A helper function for NSEC-signed zones. It searches the zone for
  182. // the "closest" NSEC corresponding to the search context stored in
  183. // node_path (it should contain sufficient information to identify the
  184. // previous name of the query name in the zone). In some cases the
  185. // immediate closest name may not have NSEC (when it's under a zone cut
  186. // for glue records, or even when the zone is partly broken), so this
  187. // method continues the search until it finds a name that has NSEC,
  188. // and returns the one found first. Due to the prerequisite (see below),
  189. // it should always succeed.
  190. //
  191. // node_path must store valid search context (in practice, it's expected
  192. // to be set by findNode()); otherwise the underlying RBTree implementation
  193. // throws.
  194. //
  195. // If the zone is not considered NSEC-signed or DNSSEC records were not
  196. // required in the original search context (specified in options), this
  197. // method doesn't bother to find NSEC, and simply returns NULL. So, by
  198. // definition of "NSEC-signed", when it really tries to find an NSEC it
  199. // should succeed; there should be one at least at the zone origin.
  200. const RdataSet*
  201. getClosestNSEC(const ZoneData& zone_data,
  202. ZoneChain& node_path,
  203. const ZoneNode** nsec_node,
  204. ZoneFinder::FindOptions options)
  205. {
  206. if (!zone_data.isSigned() ||
  207. (options & ZoneFinder::FIND_DNSSEC) == 0 ||
  208. zone_data.isNSEC3Signed()) {
  209. return (NULL);
  210. }
  211. const ZoneNode* prev_node;
  212. while ((prev_node = zone_data.getZoneTree().previousNode(node_path))
  213. != NULL) {
  214. if (!prev_node->isEmpty()) {
  215. const RdataSet* found =
  216. RdataSet::find(prev_node->getData(), RRType::NSEC());
  217. if (found != NULL) {
  218. *nsec_node = prev_node;
  219. return (found);
  220. }
  221. }
  222. }
  223. // This must be impossible and should be an internal bug.
  224. // See the description at the method declaration.
  225. assert(false);
  226. // Even though there is an assert here, strict compilers
  227. // will still need some return value.
  228. return (NULL);
  229. }
  230. // A helper function for the NXRRSET case in find(). If the zone is
  231. // NSEC-signed and DNSSEC records are requested, try to find NSEC
  232. // on the given node, and return it if found; return NULL for all other
  233. // cases.
  234. const RdataSet*
  235. getNSECForNXRRSET(const ZoneData& zone_data,
  236. ZoneFinder::FindOptions options,
  237. const ZoneNode* node)
  238. {
  239. if (zone_data.isSigned() &&
  240. !zone_data.isNSEC3Signed() &&
  241. (options & ZoneFinder::FIND_DNSSEC) != 0) {
  242. const RdataSet* found = RdataSet::find(node->getData(),
  243. RRType::NSEC());
  244. if (found != NULL) {
  245. return (found);
  246. }
  247. }
  248. return (NULL);
  249. }
  250. // Structure to hold result data of the findNode() call
  251. class FindNodeResult {
  252. public:
  253. // Bitwise flags to represent supplemental information of the
  254. // search result:
  255. // Search resulted in a wildcard match.
  256. static const unsigned int FIND_WILDCARD = 1;
  257. // Search encountered a zone cut due to NS but continued to look for
  258. // a glue.
  259. static const unsigned int FIND_ZONECUT = 2;
  260. FindNodeResult(ZoneFinder::Result code_param,
  261. const ZoneNode* node_param,
  262. const RdataSet* rrset_param,
  263. unsigned int flags_param = 0) :
  264. code(code_param),
  265. node(node_param),
  266. rrset(rrset_param),
  267. flags(flags_param)
  268. {}
  269. const ZoneFinder::Result code;
  270. const ZoneNode* node;
  271. const RdataSet* rrset;
  272. const unsigned int flags;
  273. };
  274. // Implementation notes: this method identifies an ZoneNode that best matches
  275. // the give name in terms of DNS query handling. In many cases,
  276. // DomainTree::find() will result in EXACTMATCH or PARTIALMATCH (note that
  277. // the given name is generally expected to be contained in the zone, so
  278. // even if it doesn't exist, it should at least match the zone origin).
  279. // If it finds an exact match, that's obviously the best one. The partial
  280. // match case is more complicated.
  281. //
  282. // We first need to consider the case where search hits a delegation point,
  283. // either due to NS or DNAME. They are indicated as either dname_node_ or
  284. // zonecut_node_ being non NULL. Usually at most one of them will be
  285. // something else than NULL (it might happen both are NULL, in which case we
  286. // consider it NOT FOUND). There's one corner case when both might be
  287. // something else than NULL and it is in case there's a DNAME under a zone
  288. // cut and we search in glue OK mode ‒ in that case we don't stop on the
  289. // domain with NS and ignore it for the answer, but it gets set anyway. Then
  290. // we find the DNAME and we need to act by it, therefore we first check for
  291. // DNAME and then for NS. In all other cases it doesn't matter, as at least
  292. // one of them is NULL.
  293. //
  294. // Next, we need to check if the ZoneTree search stopped at a node for a
  295. // subdomain of the search name (so the comparison result that stopped the
  296. // search is "SUPERDOMAIN"), it means the stopping node is an empty
  297. // non-terminal node. In this case the search name is considered to exist
  298. // but no data should be found there.
  299. //
  300. // If none of above is the case, we then consider whether there's a matching
  301. // wildcard. DomainTree::find() records the node if it encounters a
  302. // "wildcarding" node, i.e., the immediate ancestor of a wildcard name
  303. // (e.g., wild.example.com for *.wild.example.com), and returns it if it
  304. // doesn't find any node that better matches the query name. In this case
  305. // we'll check if there's indeed a wildcard below the wildcarding node.
  306. //
  307. // Note, first, that the wildcard is checked after the empty
  308. // non-terminal domain case above, because if that one triggers, it
  309. // means we should not match according to 4.3.3 of RFC 1034 (the query
  310. // name is known to exist).
  311. //
  312. // Before we try to find a wildcard, we should check whether there's
  313. // an existing node that would cancel the wildcard match. If
  314. // DomainTree::find() stopped at a node which has a common ancestor
  315. // with the query name, it might mean we are comparing with a
  316. // non-wildcard node. In that case, we check which part is common. If
  317. // we have something in common that lives below the node we got (the
  318. // one above *), then we should cancel the match according to section
  319. // 4.3.3 of RFC 1034 (as the name between the wildcard domain and the
  320. // query name is known to exist).
  321. //
  322. // If there's no node below the wildcarding node that shares a common ancestor
  323. // of the query name, we can conclude the wildcard is the best match.
  324. // We'll then identify the wildcard node via an incremental search. Note that
  325. // there's no possibility that the query name is at an empty non terminal
  326. // node below the wildcarding node at this stage; that case should have been
  327. // caught above.
  328. //
  329. // If none of the above succeeds, we conclude the name doesn't exist in
  330. // the zone, and throw an OutOfZone exception.
  331. FindNodeResult findNode(const ZoneData& zone_data,
  332. const Name& name,
  333. ZoneChain& node_path,
  334. ZoneFinder::FindOptions options)
  335. {
  336. ZoneNode* node = NULL;
  337. FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
  338. const ZoneTree& tree(zone_data.getZoneTree());
  339. ZoneTree::Result result = tree.find(isc::dns::LabelSequence(name),
  340. &node, node_path, cutCallback,
  341. &state);
  342. const unsigned int zonecut_flag =
  343. (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
  344. if (result == ZoneTree::EXACTMATCH) {
  345. return (FindNodeResult(ZoneFinder::SUCCESS, node, state.rrset_,
  346. zonecut_flag));
  347. } else if (result == ZoneTree::PARTIALMATCH) {
  348. assert(node != NULL);
  349. if (state.dname_node_ != NULL) { // DNAME
  350. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DNAME_FOUND).
  351. arg(state.dname_node_->getName());
  352. return (FindNodeResult(ZoneFinder::DNAME, state.dname_node_,
  353. state.rrset_));
  354. }
  355. if (state.zonecut_node_ != NULL) { // DELEGATION due to NS
  356. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
  357. arg(state.zonecut_node_->getName());
  358. return (FindNodeResult(ZoneFinder::DELEGATION,
  359. state.zonecut_node_,
  360. state.rrset_));
  361. }
  362. if (node_path.getLastComparisonResult().getRelation() ==
  363. NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
  364. LOG_DEBUG(logger, DBG_TRACE_DATA,
  365. DATASRC_MEM_SUPER_STOP).arg(name);
  366. const ZoneNode* nsec_node;
  367. const RdataSet* nsec_rds = getClosestNSEC(zone_data,
  368. node_path,
  369. &nsec_node,
  370. options);
  371. return (FindNodeResult(ZoneFinder::NXRRSET, nsec_node,
  372. nsec_rds));
  373. }
  374. // Nothing really matched.
  375. // May be a wildcard, but check only if not disabled
  376. if (node->getFlag(ZoneData::WILDCARD_NODE) &&
  377. (options & ZoneFinder::NO_WILDCARD) == 0) {
  378. if (node_path.getLastComparisonResult().getRelation() ==
  379. NameComparisonResult::COMMONANCESTOR) {
  380. // This means, e.g., we have *.wild.example and
  381. // bar.foo.wild.example and are looking for
  382. // baz.foo.wild.example. The common ancestor, foo.wild.example,
  383. // should cancel wildcard. Treat it as NXDOMAIN.
  384. LOG_DEBUG(logger, DBG_TRACE_DATA,
  385. DATASRC_MEM_WILDCARD_CANCEL).arg(name);
  386. const ZoneNode* nsec_node;
  387. const RdataSet* nsec_rds = getClosestNSEC(zone_data,
  388. node_path,
  389. &nsec_node,
  390. options);
  391. return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node,
  392. nsec_rds));
  393. }
  394. uint8_t ls_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
  395. // Create the wildcard name (i.e. take "*" and extend it
  396. // with all node labels down to the wildcard node
  397. LabelSequence wildcard_ls(LabelSequence::WILDCARD(), ls_buf);
  398. const ZoneNode* extend_with = node;
  399. while (extend_with != NULL) {
  400. wildcard_ls.extend(extend_with->getLabels(), ls_buf);
  401. extend_with = extend_with->getUpperNode();
  402. }
  403. // Clear the node_path so that we don't keep incorrect (NSEC)
  404. // context
  405. node_path.clear();
  406. ZoneTree::Result result = tree.find(LabelSequence(wildcard_ls),
  407. &node, node_path, cutCallback,
  408. &state);
  409. // Otherwise, why would the domain_flag::WILD be there if
  410. // there was no wildcard under it?
  411. assert(result == ZoneTree::EXACTMATCH);
  412. return (FindNodeResult(ZoneFinder::SUCCESS, node, state.rrset_,
  413. FindNodeResult::FIND_WILDCARD | zonecut_flag));
  414. }
  415. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
  416. const ZoneNode* nsec_node;
  417. const RdataSet* nsec_rds = getClosestNSEC(zone_data, node_path,
  418. &nsec_node, options);
  419. return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node, nsec_rds));
  420. } else {
  421. // If the name is neither an exact or partial match, it is
  422. // out of bailiwick, which is considered an error.
  423. isc_throw(OutOfZone, name.toText() << " not in " <<
  424. zone_data.getOriginNode()->getName());
  425. }
  426. }
  427. } // end anonymous namespace
  428. inline void
  429. iterateSHA1(SHA1Context* ctx, const uint8_t* input, size_t inlength,
  430. const uint8_t* salt, size_t saltlen,
  431. uint8_t output[SHA1_HASHSIZE])
  432. {
  433. SHA1Reset(ctx);
  434. SHA1Input(ctx, input, inlength);
  435. SHA1Input(ctx, salt, saltlen); // this works whether saltlen == or > 0
  436. SHA1Result(ctx, output);
  437. }
  438. std::string
  439. InMemoryZoneFinderNSEC3Calculate(const Name& name,
  440. const uint16_t iterations,
  441. const uint8_t* salt,
  442. size_t salt_len) {
  443. // We first need to normalize the name by converting all upper case
  444. // characters in the labels to lower ones.
  445. OutputBuffer obuf(Name::MAX_WIRE);
  446. Name name_copy(name);
  447. name_copy.downcase();
  448. name_copy.toWire(obuf);
  449. const uint8_t* const salt_buf = (salt_len > 0) ? salt : NULL;
  450. std::vector<uint8_t> digest(SHA1_HASHSIZE);
  451. uint8_t* const digest_buf = &digest[0];
  452. SHA1Context sha1_ctx;
  453. iterateSHA1(&sha1_ctx, static_cast<const uint8_t*>(obuf.getData()),
  454. obuf.getLength(), salt_buf, salt_len, digest_buf);
  455. for (unsigned int n = 0; n < iterations; ++n) {
  456. iterateSHA1(&sha1_ctx, digest_buf, SHA1_HASHSIZE,
  457. salt_buf, salt_len,
  458. digest_buf);
  459. }
  460. return (encodeBase32Hex(digest));
  461. }
  462. /// \brief Specialization of the ZoneFinder::Context for the in-memory finder.
  463. ///
  464. /// \note Right now we don't implement optimization using this specialized
  465. /// version, but assuming we'll do pretty soon we'll keep and use the
  466. /// definition. The note below will apply at that point (and at that point
  467. /// we should remove the other constructor for findAll()).
  468. ///
  469. /// Note that we don't have a specific constructor for the findAll() case.
  470. /// For (successful) type ANY query, found_node points to the
  471. /// corresponding zone node, which is recorded within this specialized
  472. /// context.
  473. class InMemoryZoneFinder::Context : public ZoneFinder::Context {
  474. public:
  475. /// \brief Constructor for normal find().
  476. Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
  477. ZoneFinderResultContext result) :
  478. ZoneFinder::Context(finder, options,
  479. ResultContext(result.code, result.rrset,
  480. result.flags)),
  481. rrset_(result.rrset), found_node_(result.found_node)
  482. {}
  483. /// \brief Constructor for findAll().
  484. Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
  485. ZoneFinderResultContext result,
  486. std::vector<isc::dns::ConstRRsetPtr>& target) :
  487. ZoneFinder::Context(finder, options,
  488. ResultContext(result.code, result.rrset,
  489. result.flags), target),
  490. rrset_(result.rrset), found_node_(result.found_node)
  491. {}
  492. private:
  493. const TreeNodeRRsetPtr rrset_;
  494. const ZoneNode* const found_node_;
  495. };
  496. boost::shared_ptr<ZoneFinder::Context>
  497. InMemoryZoneFinder::find(const isc::dns::Name& name,
  498. const isc::dns::RRType& type,
  499. const FindOptions options)
  500. {
  501. return (ZoneFinderContextPtr(new Context(*this, options,
  502. find_internal(name, type,
  503. NULL, options))));
  504. }
  505. boost::shared_ptr<ZoneFinder::Context>
  506. InMemoryZoneFinder::findAll(const isc::dns::Name& name,
  507. std::vector<isc::dns::ConstRRsetPtr>& target,
  508. const FindOptions options)
  509. {
  510. return (ZoneFinderContextPtr(new Context(*this, options,
  511. find_internal(name,
  512. RRType::ANY(),
  513. &target,
  514. options),
  515. target)));
  516. }
  517. ZoneFinderResultContext
  518. InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
  519. const isc::dns::RRType& type,
  520. std::vector<ConstRRsetPtr>* target,
  521. const FindOptions options)
  522. {
  523. // Get the node. All other cases than an exact match are handled
  524. // in findNode(). We simply construct a result structure and return.
  525. ZoneChain node_path;
  526. const FindNodeResult node_result =
  527. findNode(zone_data_, name, node_path, options);
  528. if (node_result.code != SUCCESS) {
  529. return (createFindResult(rrclass_, zone_data_, node_result.code,
  530. node_result.rrset, node_result.node,
  531. options));
  532. }
  533. const ZoneNode* node = node_result.node;
  534. assert(node != NULL);
  535. // We've found an exact match, may or may not be a result of wildcard.
  536. const bool wild = ((node_result.flags &
  537. FindNodeResult::FIND_WILDCARD) != 0);
  538. // If there is an exact match but the node is empty, it's equivalent
  539. // to NXRRSET.
  540. if (node->isEmpty()) {
  541. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DOMAIN_EMPTY).
  542. arg(name);
  543. const ZoneNode* nsec_node;
  544. const RdataSet* nsec_rds = getClosestNSEC(zone_data_, node_path,
  545. &nsec_node, options);
  546. return (createFindResult(rrclass_, zone_data_, NXRRSET,
  547. nsec_rds, nsec_node, options, wild));
  548. }
  549. const RdataSet* found;
  550. // If the node callback is enabled, this may be a zone cut. If it
  551. // has a NS RR, we should return a delegation, but not in the apex.
  552. // There are two exceptions:
  553. // - the case for DS query, which should always be considered in-zone
  554. // lookup.
  555. // - when we are looking for glue records (FIND_GLUE_OK)
  556. if (node->getFlag(ZoneNode::FLAG_CALLBACK) &&
  557. (options & FIND_GLUE_OK) == 0 &&
  558. node != zone_data_.getOriginNode() && type != RRType::DS()) {
  559. found = RdataSet::find(node->getData(), RRType::NS());
  560. if (found != NULL) {
  561. LOG_DEBUG(logger, DBG_TRACE_DATA,
  562. DATASRC_MEM_EXACT_DELEGATION).arg(name);
  563. return (createFindResult(rrclass_, zone_data_, DELEGATION,
  564. found, node, options, wild, &name));
  565. }
  566. }
  567. // Handle type any query
  568. if (target != NULL && node->getData() != NULL) {
  569. // Empty domain will be handled as NXRRSET by normal processing
  570. const RdataSet* cur_rds = node->getData();
  571. while (cur_rds != NULL) {
  572. target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_,
  573. options, &name));
  574. cur_rds = cur_rds->getNext();
  575. }
  576. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
  577. arg(name);
  578. return (createFindResult(rrclass_, zone_data_, SUCCESS, NULL, node,
  579. options, wild, &name));
  580. }
  581. const RdataSet* currds = node->getData();
  582. while (currds != NULL) {
  583. currds = currds->getNext();
  584. }
  585. found = RdataSet::find(node->getData(), type);
  586. if (found != NULL) {
  587. // Good, it is here
  588. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
  589. arg(type);
  590. return (createFindResult(rrclass_, zone_data_, SUCCESS, found, node,
  591. options, wild, &name));
  592. } else {
  593. // Next, try CNAME.
  594. found = RdataSet::find(node->getData(), RRType::CNAME());
  595. if (found != NULL) {
  596. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
  597. return (createFindResult(rrclass_, zone_data_, CNAME, found, node,
  598. options, wild, &name));
  599. }
  600. }
  601. // No exact match or CNAME. Get NSEC if necessary and return NXRRSET.
  602. return (createFindResult(rrclass_, zone_data_, NXRRSET,
  603. getNSECForNXRRSET(zone_data_, options, node),
  604. node, options, wild, &name));
  605. }
  606. isc::datasrc::ZoneFinder::FindNSEC3Result
  607. InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
  608. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3).arg(name).
  609. arg(recursive ? "recursive" : "non-recursive");
  610. if (!zone_data_.isNSEC3Signed()) {
  611. isc_throw(DataSourceError,
  612. "findNSEC3 attempt for non NSEC3 signed zone: " <<
  613. getOrigin() << "/" << getClass());
  614. }
  615. const NameComparisonResult cmp_result = name.compare(getOrigin());
  616. if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
  617. cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
  618. isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: "
  619. << name << ", zone: " << getOrigin() << "/"
  620. << getClass());
  621. }
  622. // Convenient shortcuts
  623. const ZoneFinder::FindOptions options =
  624. ZoneFinder::FIND_DNSSEC; // NSEC3 implies DNSSEC
  625. const unsigned int olabels = getOrigin().getLabelCount();
  626. const unsigned int qlabels = name.getLabelCount();
  627. const NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
  628. const ZoneNode* covering_node(NULL); // placeholder of the next closer proof
  629. // Examine all names from the query name to the origin name, stripping
  630. // the deepest label one by one, until we find a name that has a matching
  631. // NSEC3 hash.
  632. for (unsigned int labels = qlabels; labels >= olabels; --labels) {
  633. const std::string hlabel = (nsec3_calculate_)
  634. ((labels == qlabels ?
  635. name : name.split(qlabels - labels, labels)),
  636. nsec3_data->iterations,
  637. nsec3_data->getSaltData(),
  638. nsec3_data->getSaltLen());
  639. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3_TRYHASH).
  640. arg(name).arg(labels).arg(hlabel);
  641. const ZoneTree& tree = nsec3_data->getNSEC3Tree();
  642. ZoneNode* node(NULL);
  643. ZoneChain chain;
  644. ZoneTree::Result result =
  645. tree.find(Name(hlabel + "." + getOrigin().toText()), &node, chain);
  646. if (result == ZoneTree::EXACTMATCH) {
  647. // We found an exact match.
  648. RdataSet* set = node->getData();
  649. ConstRRsetPtr closest = createTreeNodeRRset(node, set, getClass(),
  650. options);
  651. ConstRRsetPtr next =
  652. createTreeNodeRRset(covering_node,
  653. (covering_node != NULL ?
  654. covering_node->getData() : NULL),
  655. getClass(), options);
  656. LOG_DEBUG(logger, DBG_TRACE_BASIC,
  657. DATASRC_MEM_FINDNSEC3_MATCH).arg(name).arg(labels).
  658. arg(*closest);
  659. return (FindNSEC3Result(true, labels, closest, next));
  660. } else {
  661. const NameComparisonResult& last_cmp =
  662. chain.getLastComparisonResult();
  663. const ZoneNode* last_node = chain.getLastComparedNode();
  664. assert(last_cmp.getOrder() != 0);
  665. // find() finished in between one of these and last_node:
  666. const ZoneNode* previous_node = last_node->predecessor();
  667. const ZoneNode* next_node = last_node->successor();
  668. // If the given hash is larger than the largest stored hash or
  669. // the first label doesn't match the target, identify the "previous"
  670. // hash value and remember it as the candidate next closer proof.
  671. if (((last_cmp.getOrder() < 0) && (previous_node == NULL)) ||
  672. ((last_cmp.getOrder() > 0) && (next_node == NULL))) {
  673. covering_node = last_node->getLargestInSubTree();
  674. } else {
  675. // Otherwise, H(found_entry-1) < given_hash < H(found_entry).
  676. // The covering proof is the first one (and it's valid
  677. // because found is neither begin nor end)
  678. covering_node = previous_node;
  679. }
  680. if (!recursive) { // in non recursive mode, we are done.
  681. ConstRRsetPtr closest =
  682. createTreeNodeRRset(covering_node,
  683. (covering_node != NULL ?
  684. covering_node->getData() :
  685. NULL),
  686. getClass(), options);
  687. if (closest) {
  688. LOG_DEBUG(logger, DBG_TRACE_BASIC,
  689. DATASRC_MEM_FINDNSEC3_COVER).
  690. arg(name).arg(*closest);
  691. }
  692. return (FindNSEC3Result(false, labels,
  693. closest, ConstRRsetPtr()));
  694. }
  695. }
  696. }
  697. isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely "
  698. "a broken NSEC3 zone: " << getOrigin() << "/"
  699. << getClass());
  700. }
  701. Name
  702. InMemoryZoneFinder::getOrigin() const {
  703. size_t data_len;
  704. const uint8_t* data;
  705. // Normally the label sequence of the origin node should be absolute,
  706. // in which case we can simply generate the origin name from the labels.
  707. const LabelSequence node_labels = zone_data_.getOriginNode()->getLabels();
  708. if (node_labels.isAbsolute()) {
  709. data = node_labels.getData(&data_len);
  710. } else {
  711. // In future we may allow adding out-of-zone names in the zone tree.
  712. // For example, to hold out-of-zone NS names so we can establish a
  713. // shortcut link to them as an optimization. If and when that happens
  714. // the origin node may not have an absolute label (consider the zone
  715. // is example.org and we add ns.noexample.org). In that case
  716. // we first need to construct the absolute label sequence and then
  717. // construct the name.
  718. uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
  719. const LabelSequence name_labels =
  720. zone_data_.getOriginNode()->getAbsoluteLabels(labels_buf);
  721. data = name_labels.getData(&data_len);
  722. }
  723. util::InputBuffer buffer(data, data_len);
  724. return (Name(buffer));
  725. }
  726. } // namespace memory
  727. } // namespace datasrc
  728. } // namespace isc