memory_client.cc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  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 <exceptions/exceptions.h>
  15. #include <datasrc/memory/memory_client.h>
  16. #include <datasrc/memory/logger.h>
  17. #include <datasrc/memory/zone_data.h>
  18. #include <datasrc/memory/rdata_serialization.h>
  19. #include <datasrc/memory/rdataset.h>
  20. #include <datasrc/memory/domaintree.h>
  21. #include <datasrc/memory/segment_object_holder.h>
  22. #include <datasrc/memory/treenode_rrset.h>
  23. #include <util/memory_segment_local.h>
  24. #include <datasrc/data_source.h>
  25. #include <datasrc/factory.h>
  26. #include <datasrc/result.h>
  27. #include <dns/name.h>
  28. #include <dns/nsec3hash.h>
  29. #include <dns/rdataclass.h>
  30. #include <dns/rrclass.h>
  31. #include <dns/rrsetlist.h>
  32. #include <dns/masterload.h>
  33. #include <boost/function.hpp>
  34. #include <boost/shared_ptr.hpp>
  35. #include <boost/scoped_ptr.hpp>
  36. #include <boost/bind.hpp>
  37. #include <boost/foreach.hpp>
  38. #include <boost/noncopyable.hpp>
  39. #include <algorithm>
  40. #include <map>
  41. #include <utility>
  42. #include <cctype>
  43. #include <cassert>
  44. using namespace std;
  45. using namespace isc::dns;
  46. using namespace isc::dns::rdata;
  47. using namespace isc::datasrc::memory;
  48. using boost::scoped_ptr;
  49. namespace isc {
  50. namespace datasrc {
  51. namespace memory {
  52. using detail::SegmentObjectHolder;
  53. namespace {
  54. // Some type aliases
  55. typedef DomainTree<std::string> FileNameTree;
  56. typedef DomainTreeNode<std::string> FileNameNode;
  57. // A functor type used for loading.
  58. typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
  59. } // end of anonymous namespace
  60. /// Implementation details for \c InMemoryClient hidden from the public
  61. /// interface.
  62. ///
  63. /// For now, \c InMemoryClient only contains a \c ZoneTable object, which
  64. /// consists of (pointers to) \c InMemoryZoneFinder objects, we may add more
  65. /// member variables later for new features.
  66. class InMemoryClient::InMemoryClientImpl {
  67. private:
  68. // The deleter for the filenames stored in the tree.
  69. struct FileNameDeleter {
  70. FileNameDeleter() {}
  71. void operator()(std::string* filename) const {
  72. delete filename;
  73. }
  74. };
  75. public:
  76. InMemoryClientImpl(util::MemorySegment& mem_sgmt, RRClass rrclass) :
  77. mem_sgmt_(mem_sgmt),
  78. rrclass_(rrclass),
  79. zone_count_(0),
  80. zone_table_(ZoneTable::create(mem_sgmt_, rrclass)),
  81. file_name_tree_(FileNameTree::create(mem_sgmt_, false))
  82. {}
  83. ~InMemoryClientImpl() {
  84. FileNameDeleter deleter;
  85. FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
  86. ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
  87. // see above for the assert().
  88. assert(mem_sgmt_.allMemoryDeallocated());
  89. }
  90. util::MemorySegment& mem_sgmt_;
  91. const RRClass rrclass_;
  92. unsigned int zone_count_;
  93. ZoneTable* zone_table_;
  94. FileNameTree* file_name_tree_;
  95. // Common process for zone load.
  96. // rrset_installer is a functor that takes another functor as an argument,
  97. // and expected to call the latter for each RRset of the zone. How the
  98. // sequence of the RRsets is generated depends on the internal
  99. // details of the loader: either from a textual master file or from
  100. // another data source.
  101. // filename is the file name of the master file or empty if the zone is
  102. // loaded from another data source.
  103. result::Result load(const Name& zone_name, const string& filename,
  104. boost::function<void(LoadCallback)> rrset_installer);
  105. // Add the necessary magic for any wildcard contained in 'name'
  106. // (including itself) to be found in the zone.
  107. //
  108. // In order for wildcard matching to work correctly in the zone finder,
  109. // we must ensure that a node for the wildcarding level exists in the
  110. // backend RBTree.
  111. // E.g. if the wildcard name is "*.sub.example." then we must ensure
  112. // that "sub.example." exists and is marked as a wildcard level.
  113. // Note: the "wildcarding level" is for the parent name of the wildcard
  114. // name (such as "sub.example.").
  115. //
  116. // We also perform the same trick for empty wild card names possibly
  117. // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
  118. void addWildcards(const Name& zone_name, ZoneData& zone_data,
  119. const Name& name)
  120. {
  121. Name wname(name);
  122. const unsigned int labels(wname.getLabelCount());
  123. const unsigned int origin_labels(zone_name.getLabelCount());
  124. for (unsigned int l = labels;
  125. l > origin_labels;
  126. --l, wname = wname.split(1)) {
  127. if (wname.isWildcard()) {
  128. LOG_DEBUG(logger, DBG_TRACE_DATA,
  129. DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
  130. // Ensure a separate level exists for the "wildcarding" name,
  131. // and mark the node as "wild".
  132. ZoneNode* node;
  133. zone_data.insertName(mem_sgmt_, wname.split(1), &node);
  134. node->setFlag(ZoneData::WILDCARD_NODE);
  135. // Ensure a separate level exists for the wildcard name.
  136. // Note: for 'name' itself we do this later anyway, but the
  137. // overhead should be marginal because wildcard names should
  138. // be rare.
  139. zone_data.insertName(mem_sgmt_, wname, &node);
  140. }
  141. }
  142. }
  143. /*
  144. * Does some checks in context of the data that are already in the zone.
  145. * Currently checks for forbidden combinations of RRsets in the same
  146. * domain (CNAME+anything, DNAME+NS).
  147. *
  148. * If such condition is found, it throws AddError.
  149. */
  150. void contextCheck(const Name& zone_name, const AbstractRRset& rrset,
  151. const RdataSet* set) const
  152. {
  153. // Ensure CNAME and other type of RR don't coexist for the same
  154. // owner name except with NSEC, which is the only RR that can coexist
  155. // with CNAME (and also RRSIG, which is handled separately)
  156. if (rrset.getType() == RRType::CNAME()) {
  157. for (const RdataSet* sp = set; sp != NULL; sp = sp->getNext()) {
  158. if (sp->type != RRType::NSEC()) {
  159. LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
  160. arg(rrset.getName());
  161. isc_throw(AddError, "CNAME can't be added with "
  162. << sp->type << " RRType for "
  163. << rrset.getName());
  164. }
  165. }
  166. } else if ((rrset.getType() != RRType::NSEC()) &&
  167. (RdataSet::find(set, RRType::CNAME()) != NULL)) {
  168. LOG_ERROR(logger,
  169. DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
  170. isc_throw(AddError, "CNAME and " << rrset.getType() <<
  171. " can't coexist for " << rrset.getName());
  172. }
  173. /*
  174. * Similar with DNAME, but it must not coexist only with NS and only in
  175. * non-apex domains.
  176. * RFC 2672 section 3 mentions that it is implied from it and RFC 2181
  177. */
  178. if (rrset.getName() != zone_name &&
  179. // Adding DNAME, NS already there
  180. ((rrset.getType() == RRType::DNAME() &&
  181. RdataSet::find(set, RRType::NS()) != NULL) ||
  182. // Adding NS, DNAME already there
  183. (rrset.getType() == RRType::NS() &&
  184. RdataSet::find(set, RRType::DNAME()) != NULL)))
  185. {
  186. LOG_ERROR(logger, DATASRC_MEMORY_MEM_DNAME_NS).arg(rrset.getName());
  187. isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
  188. "domain " << rrset.getName());
  189. }
  190. }
  191. // Validate rrset before adding it to the zone. If something is wrong
  192. // it throws an exception. It doesn't modify the zone, and provides
  193. // the strong exception guarantee.
  194. void addValidation(const Name& zone_name, const ConstRRsetPtr rrset) {
  195. if (!rrset) {
  196. isc_throw(NullRRset, "The rrset provided is NULL");
  197. }
  198. if (rrset->getRdataCount() == 0) {
  199. isc_throw(AddError, "The rrset provided is empty: " <<
  200. rrset->getName() << "/" << rrset->getType());
  201. }
  202. // Check for singleton RRs. It should probably handled at a different
  203. // layer in future.
  204. if ((rrset->getType() == RRType::CNAME() ||
  205. rrset->getType() == RRType::DNAME()) &&
  206. rrset->getRdataCount() > 1)
  207. {
  208. // XXX: this is not only for CNAME or DNAME. We should generalize
  209. // this code for all other "singleton RR types" (such as SOA) in a
  210. // separate task.
  211. LOG_ERROR(logger,
  212. DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
  213. arg(rrset->getType());
  214. isc_throw(AddError, "multiple RRs of singleton type for "
  215. << rrset->getName());
  216. }
  217. // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
  218. // implementation requests it be so at the moment.
  219. if ((rrset->getType() == RRType::NSEC3() ||
  220. rrset->getType() == RRType::NSEC3PARAM()) &&
  221. rrset->getRdataCount() > 1) {
  222. isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
  223. << rrset->getName() << " which isn't supported");
  224. }
  225. // For RRSIGs, check consistency of the type covered.
  226. // We know the RRset isn't empty, so the following check is safe.
  227. if (rrset->getType() == RRType::RRSIG()) {
  228. RdataIteratorPtr rit = rrset->getRdataIterator();
  229. const RRType covered = dynamic_cast<const generic::RRSIG&>(
  230. rit->getCurrent()).typeCovered();
  231. for (rit->next(); !rit->isLast(); rit->next()) {
  232. if (dynamic_cast<const generic::RRSIG&>(
  233. rit->getCurrent()).typeCovered() != covered) {
  234. isc_throw(AddError, "RRSIG contains mixed covered types: "
  235. << rrset->toText());
  236. }
  237. }
  238. }
  239. const NameComparisonResult compare =
  240. zone_name.compare(rrset->getName());
  241. if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
  242. compare.getRelation() != NameComparisonResult::EQUAL)
  243. {
  244. LOG_ERROR(logger,
  245. DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
  246. arg(zone_name);
  247. isc_throw(OutOfZone, "The name " << rrset->getName() <<
  248. " is not contained in zone " << zone_name);
  249. }
  250. // Some RR types do not really work well with a wildcard.
  251. // Even though the protocol specifically doesn't completely ban such
  252. // usage, we refuse to load a zone containing such RR in order to
  253. // keep the lookup logic simpler and more predictable.
  254. // See RFC4592 and (for DNAME) RFC6672 for more technical background.
  255. // Note also that BIND 9 refuses NS at a wildcard, so in that sense
  256. // we simply provide compatible behavior.
  257. if (rrset->getName().isWildcard()) {
  258. if (rrset->getType() == RRType::NS()) {
  259. LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_NS).
  260. arg(rrset->getName());
  261. isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
  262. rrset->getName());
  263. }
  264. if (rrset->getType() == RRType::DNAME()) {
  265. LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_DNAME).
  266. arg(rrset->getName());
  267. isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
  268. rrset->getName());
  269. }
  270. }
  271. // Owner names of NSEC3 have special format as defined in RFC5155,
  272. // and cannot be a wildcard name or must be one label longer than
  273. // the zone origin. While the RFC doesn't prohibit other forms of
  274. // names, no sane zone would have such names for NSEC3.
  275. // BIND 9 also refuses NSEC3 at wildcard.
  276. if (rrset->getType() == RRType::NSEC3() &&
  277. (rrset->getName().isWildcard() ||
  278. rrset->getName().getLabelCount() !=
  279. zone_name.getLabelCount() + 1)) {
  280. LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).
  281. arg(rrset->getName());
  282. isc_throw(AddError, "Invalid NSEC3 owner name: " <<
  283. rrset->getName());
  284. }
  285. }
  286. void addNSEC3(const ConstRRsetPtr rrset,
  287. const ConstRRsetPtr rrsig,
  288. ZoneData& zone_data)
  289. {
  290. // We know rrset has exactly one RDATA
  291. const generic::NSEC3& nsec3_rdata =
  292. dynamic_cast<const generic::NSEC3&>(
  293. rrset->getRdataIterator()->getCurrent());
  294. NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
  295. if (nsec3_data == NULL) {
  296. nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
  297. zone_data.setNSEC3Data(nsec3_data);
  298. } else {
  299. size_t salt_len = nsec3_data->getSaltLen();
  300. const uint8_t* salt_data = nsec3_data->getSaltData();
  301. const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
  302. if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
  303. (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
  304. (salt_data_2.size() != salt_len) ||
  305. (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
  306. isc_throw(AddError,
  307. "NSEC3 with inconsistent parameters: " <<
  308. rrset->toText());
  309. }
  310. }
  311. string fst_label = rrset->getName().split(0, 1).toText(true);
  312. transform(fst_label.begin(), fst_label.end(), fst_label.begin(),
  313. ::toupper);
  314. ZoneNode* node;
  315. nsec3_data->insertName(mem_sgmt_, Name(fst_label), &node);
  316. RdataEncoder encoder;
  317. // We assume that rrsig has already been checked to match rrset
  318. // by the caller.
  319. RdataSet* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
  320. RdataSet* old_set = node->setData(set);
  321. if (old_set != NULL) {
  322. RdataSet::destroy(mem_sgmt_, rrclass_, old_set);
  323. }
  324. }
  325. void addRdataSet(const Name& zone_name, ZoneData& zone_data,
  326. const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
  327. {
  328. if (rrset->getType() == RRType::NSEC3()) {
  329. addNSEC3(rrset, rrsig, zone_data);
  330. } else {
  331. ZoneNode* node;
  332. zone_data.insertName(mem_sgmt_, rrset->getName(), &node);
  333. RdataSet* rdataset_head = node->getData();
  334. // Checks related to the surrounding data.
  335. // Note: when the check fails and the exception is thrown,
  336. // it may break strong exception guarantee. At the moment
  337. // we prefer code simplicity and don't bother to introduce
  338. // complicated recovery code.
  339. contextCheck(zone_name, *rrset, rdataset_head);
  340. if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
  341. isc_throw(AddError,
  342. "RRset of the type already exists: "
  343. << rrset->getName() << " (type: "
  344. << rrset->getType() << ")");
  345. }
  346. RdataEncoder encoder;
  347. RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder, rrset,
  348. rrsig);
  349. rdataset->next = rdataset_head;
  350. node->setData(rdataset);
  351. // Ok, we just put it in
  352. // If this RRset creates a zone cut at this node, mark the
  353. // node indicating the need for callback in find().
  354. if (rrset->getType() == RRType::NS() &&
  355. rrset->getName() != zone_name) {
  356. node->setFlag(ZoneNode::FLAG_CALLBACK);
  357. // If it is DNAME, we have a callback as well here
  358. } else if (rrset->getType() == RRType::DNAME()) {
  359. node->setFlag(ZoneNode::FLAG_CALLBACK);
  360. }
  361. // If we've added NSEC3PARAM at zone origin, set up NSEC3
  362. // specific data or check consistency with already set up
  363. // parameters.
  364. if (rrset->getType() == RRType::NSEC3PARAM() &&
  365. rrset->getName() == zone_name) {
  366. // We know rrset has exactly one RDATA
  367. const generic::NSEC3PARAM& param =
  368. dynamic_cast<const generic::NSEC3PARAM&>
  369. (rrset->getRdataIterator()->getCurrent());
  370. NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
  371. if (nsec3_data == NULL) {
  372. nsec3_data = NSEC3Data::create(mem_sgmt_, param);
  373. zone_data.setNSEC3Data(nsec3_data);
  374. } else {
  375. size_t salt_len = nsec3_data->getSaltLen();
  376. const uint8_t* salt_data = nsec3_data->getSaltData();
  377. const vector<uint8_t>& salt_data_2 = param.getSalt();
  378. if ((param.getHashalg() != nsec3_data->hashalg) ||
  379. (param.getIterations() != nsec3_data->iterations) ||
  380. (salt_data_2.size() != salt_len) ||
  381. (std::memcmp(&salt_data_2[0],
  382. salt_data, salt_len) != 0)) {
  383. isc_throw(AddError,
  384. "NSEC3PARAM with inconsistent parameters: "
  385. << rrset->toText());
  386. }
  387. }
  388. } else if (rrset->getType() == RRType::NSEC()) {
  389. // If it is NSEC signed zone, we mark the zone as signed
  390. // (conceptually "signed" is a broader notion but our current
  391. // zone finder implementation regards "signed" as "NSEC
  392. // signed")
  393. zone_data.setSigned(true);
  394. }
  395. }
  396. }
  397. // Implementation of InMemoryClient::add()
  398. void add(const ConstRRsetPtr& rrset, const ConstRRsetPtr& sig_rrset,
  399. const Name& zone_name, ZoneData& zone_data)
  400. {
  401. // Sanitize input. This will cause an exception to be thrown
  402. // if the input RRset is empty.
  403. addValidation(zone_name, rrset);
  404. if (sig_rrset) {
  405. addValidation(zone_name, sig_rrset);
  406. }
  407. // OK, can add the RRset.
  408. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
  409. arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
  410. // Add wildcards possibly contained in the owner name to the domain
  411. // tree. This can only happen for the normal (non-NSEC3) tree.
  412. // Note: this can throw an exception, breaking strong exception
  413. // guarantee. (see also the note for the call to contextCheck()
  414. // above).
  415. if (rrset->getType() != RRType::NSEC3()) {
  416. addWildcards(zone_name, zone_data, rrset->getName());
  417. }
  418. addRdataSet(zone_name, zone_data, rrset, sig_rrset);
  419. return;
  420. }
  421. };
  422. // A helper internal class for load(). make it non-copyable to avoid
  423. // accidental copy.
  424. //
  425. // The current internal implementation expects that both a normal
  426. // (non RRSIG) RRset and (when signed) its RRSIG are added at once.
  427. // Also in the current implementation, the input sequence of RRsets
  428. // are grouped with their owner name (so once a new owner name is encountered,
  429. // no subsequent RRset has the previous owner name), but the ordering
  430. // in the same group is not fixed. So we hold all RRsets of the same
  431. // owner name in node_rrsets_ and node_rrsigsets_, and add the matching
  432. // pairs of RRsets to the zone when we see a new owner name.
  433. //
  434. // The caller is responsible for adding the RRsets of the last group
  435. // in the input sequence by explicitly calling flushNodeRRsets() at the
  436. // end. It's cleaner and more robust if we let the destructor of this class
  437. // do it, but since we cannot guarantee the adding operation is exception free,
  438. // we don't choose that option to maintain the common expectation for
  439. // destructors.
  440. class InMemoryClient::Loader : boost::noncopyable {
  441. typedef std::map<RRType, ConstRRsetPtr> NodeRRsets;
  442. typedef NodeRRsets::value_type NodeRRsetsVal;
  443. public:
  444. Loader(InMemoryClientImpl* client_impl, const Name& zone_name,
  445. ZoneData& zone_data) :
  446. client_impl_(client_impl), zone_name_(zone_name), zone_data_(zone_data)
  447. {}
  448. void addFromLoad(const ConstRRsetPtr& rrset) {
  449. // If we see a new name, flush the temporary holders, adding the
  450. // pairs of RRsets and RRSIGs of the previous name to the zone.
  451. if ((!node_rrsets_.empty() || !node_rrsigsets_.empty()) &&
  452. getCurrentName() != rrset->getName()) {
  453. flushNodeRRsets();
  454. }
  455. // Store this RRset until it can be added to the zone. The current
  456. // implementation requires RRs of the same RRset should be added at
  457. // once, so we check the "duplicate" here.
  458. const bool is_rrsig = rrset->getType() == RRType::RRSIG();
  459. NodeRRsets& node_rrsets = is_rrsig ? node_rrsigsets_ : node_rrsets_;
  460. const RRType& rrtype = is_rrsig ?
  461. getCoveredType(rrset) : rrset->getType();
  462. if (!node_rrsets.insert(NodeRRsetsVal(rrtype, rrset)).second) {
  463. isc_throw(AddError,
  464. "Duplicate add of the same type of"
  465. << (is_rrsig ? " RRSIG" : "") << " RRset: "
  466. << rrset->getName() << "/" << rrtype);
  467. }
  468. }
  469. void flushNodeRRsets() {
  470. BOOST_FOREACH(NodeRRsetsVal val, node_rrsets_) {
  471. // Identify the corresponding RRSIG for the RRset, if any.
  472. // If found add both the RRset and its RRSIG at once.
  473. ConstRRsetPtr sig_rrset;
  474. NodeRRsets::iterator sig_it =
  475. node_rrsigsets_.find(val.first);
  476. if (sig_it != node_rrsigsets_.end()) {
  477. sig_rrset = sig_it->second;
  478. node_rrsigsets_.erase(sig_it);
  479. }
  480. client_impl_->add(val.second, sig_rrset, zone_name_, zone_data_);
  481. }
  482. // Right now, we don't accept RRSIG without covered RRsets (this
  483. // should eventually allowed, but to do so we'll need to update the
  484. // finder).
  485. if (!node_rrsigsets_.empty()) {
  486. isc_throw(AddError, "RRSIG is added without covered RRset for "
  487. << getCurrentName());
  488. }
  489. node_rrsets_.clear();
  490. node_rrsigsets_.clear();
  491. }
  492. private:
  493. // A helper to identify the covered type of an RRSIG.
  494. static RRType getCoveredType(const ConstRRsetPtr& sig_rrset) {
  495. RdataIteratorPtr it = sig_rrset->getRdataIterator();
  496. // Empty RRSIG shouldn't be passed either via a master file or another
  497. // data source iterator, but it could still happen if the iterator
  498. // has a bug. We catch and reject such cases.
  499. if (it->isLast()) {
  500. isc_throw(isc::Unexpected,
  501. "Empty RRset is passed in-memory loader, name: "
  502. << sig_rrset->getName());
  503. }
  504. return (dynamic_cast<const generic::RRSIG&>(it->getCurrent()).
  505. typeCovered());
  506. }
  507. const Name& getCurrentName() const {
  508. if (!node_rrsets_.empty()) {
  509. return (node_rrsets_.begin()->second->getName());
  510. }
  511. assert(!node_rrsigsets_.empty());
  512. return (node_rrsigsets_.begin()->second->getName());
  513. }
  514. private:
  515. InMemoryClientImpl* client_impl_;
  516. const Name& zone_name_;
  517. ZoneData& zone_data_;
  518. NodeRRsets node_rrsets_;
  519. NodeRRsets node_rrsigsets_;
  520. };
  521. result::Result
  522. InMemoryClient::InMemoryClientImpl::load(
  523. const Name& zone_name,
  524. const string& filename,
  525. boost::function<void(LoadCallback)> rrset_installer)
  526. {
  527. SegmentObjectHolder<ZoneData, RRClass> holder(
  528. mem_sgmt_, ZoneData::create(mem_sgmt_, zone_name), rrclass_);
  529. Loader loader(this, zone_name, *holder.get());
  530. rrset_installer(boost::bind(&Loader::addFromLoad, &loader, _1));
  531. // Add any last RRsets that were left
  532. loader.flushNodeRRsets();
  533. const ZoneNode* origin_node = holder.get()->getOriginNode();
  534. const RdataSet* set = origin_node->getData();
  535. // If the zone is NSEC3-signed, check if it has NSEC3PARAM
  536. if (holder.get()->isNSEC3Signed()) {
  537. if (RdataSet::find(set, RRType::NSEC3PARAM()) == NULL) {
  538. LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
  539. arg(zone_name).arg(rrclass_);
  540. }
  541. }
  542. // When an empty zone file is loaded, the origin doesn't even have
  543. // an SOA RR. This condition should be avoided, and hence load()
  544. // should throw when an empty zone is loaded.
  545. if (RdataSet::find(set, RRType::SOA()) == NULL) {
  546. isc_throw(EmptyZone,
  547. "Won't create an empty zone for: " << zone_name);
  548. }
  549. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
  550. arg(zone_name).arg(rrclass_.toText());
  551. // Set the filename in file_name_tree_ now, so that getFileName()
  552. // can use it (during zone reloading).
  553. FileNameNode* node(NULL);
  554. switch (file_name_tree_->insert(mem_sgmt_, zone_name, &node)) {
  555. case FileNameTree::SUCCESS:
  556. case FileNameTree::ALREADYEXISTS:
  557. // These are OK
  558. break;
  559. default:
  560. // Can Not Happen
  561. assert(false);
  562. }
  563. // node must point to a valid node now
  564. assert(node != NULL);
  565. std::string* tstr = node->setData(new std::string(filename));
  566. delete tstr;
  567. ZoneTable::AddResult result(zone_table_->addZone(mem_sgmt_, rrclass_,
  568. zone_name));
  569. if (result.code == result::SUCCESS) {
  570. // Only increment the zone count if the zone doesn't already
  571. // exist.
  572. ++zone_count_;
  573. }
  574. ZoneTable::FindResult fr(zone_table_->setZoneData(zone_name,
  575. holder.release()));
  576. assert(fr.code == result::SUCCESS);
  577. if (fr.zone_data != NULL) {
  578. ZoneData::destroy(mem_sgmt_, fr.zone_data, rrclass_);
  579. }
  580. return (result.code);
  581. }
  582. namespace {
  583. // A wrapper for dns::masterLoad used by load() below. Essentially it
  584. // converts the two callback types. Note the mostly redundant wrapper of
  585. // boost::bind. It converts function<void(ConstRRsetPtr)> to
  586. // function<void(RRsetPtr)> (masterLoad() expects the latter). SunStudio
  587. // doesn't seem to do this conversion if we just pass 'callback'.
  588. void
  589. masterLoadWrapper(const char* const filename, const Name& origin,
  590. const RRClass& zone_class, LoadCallback callback)
  591. {
  592. masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
  593. }
  594. // The installer called from Impl::load() for the iterator version of load().
  595. void
  596. generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
  597. ConstRRsetPtr rrset;
  598. while ((rrset = iterator->getNextRRset()) != NULL) {
  599. callback(rrset);
  600. }
  601. }
  602. }
  603. InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
  604. RRClass rrclass) :
  605. impl_(new InMemoryClientImpl(mem_sgmt, rrclass))
  606. {}
  607. InMemoryClient::~InMemoryClient() {
  608. delete impl_;
  609. }
  610. RRClass
  611. InMemoryClient::getClass() const {
  612. return (impl_->rrclass_);
  613. }
  614. unsigned int
  615. InMemoryClient::getZoneCount() const {
  616. return (impl_->zone_count_);
  617. }
  618. isc::datasrc::memory::ZoneTable::FindResult
  619. InMemoryClient::findZone2(const isc::dns::Name& zone_name) const {
  620. LOG_DEBUG(logger, DBG_TRACE_DATA,
  621. DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
  622. ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
  623. return (result);
  624. }
  625. isc::datasrc::DataSourceClient::FindResult
  626. InMemoryClient::findZone(const isc::dns::Name&) const {
  627. // This variant of findZone() is not implemented and should be
  628. // removed eventually. It currently throws an exception. It is
  629. // required right now to derive from DataSourceClient.
  630. isc_throw(isc::NotImplemented,
  631. "This variant of findZone() is not implemented.");
  632. }
  633. result::Result
  634. InMemoryClient::load(const isc::dns::Name& zone_name,
  635. const std::string& filename) {
  636. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
  637. arg(filename);
  638. return (impl_->load(zone_name, filename,
  639. boost::bind(masterLoadWrapper, filename.c_str(),
  640. zone_name, getClass(), _1)));
  641. }
  642. result::Result
  643. InMemoryClient::load(const isc::dns::Name& zone_name,
  644. ZoneIterator& iterator) {
  645. return (impl_->load(zone_name, string(),
  646. boost::bind(generateRRsetFromIterator,
  647. &iterator, _1)));
  648. }
  649. const std::string
  650. InMemoryClient::getFileName(const isc::dns::Name& zone_name) const {
  651. FileNameNode* node(NULL);
  652. FileNameTree::Result result = impl_->file_name_tree_->find(zone_name,
  653. &node);
  654. if (result == FileNameTree::EXACTMATCH) {
  655. return (*node->getData());
  656. } else {
  657. return (std::string());
  658. }
  659. }
  660. result::Result
  661. InMemoryClient::add(const isc::dns::Name& zone_name,
  662. const ConstRRsetPtr& rrset)
  663. {
  664. const ZoneTable::FindResult result =
  665. impl_->zone_table_->findZone(zone_name);
  666. if (result.code != result::SUCCESS) {
  667. isc_throw(DataSourceError, "No such zone: " + zone_name.toText());
  668. }
  669. const ConstRRsetPtr sig_rrset =
  670. rrset ? rrset->getRRsig() : ConstRRsetPtr();
  671. impl_->add(rrset, sig_rrset, zone_name, *result.zone_data);
  672. // add() doesn't allow duplicate add, so we always return SUCCESS.
  673. return (result::SUCCESS);
  674. }
  675. namespace {
  676. class MemoryIterator : public ZoneIterator {
  677. private:
  678. ZoneChain chain_;
  679. const RdataSet* set_node_;
  680. const RRClass rrclass_;
  681. const ZoneTree& tree_;
  682. const ZoneNode* node_;
  683. // Only used when separate_rrs_ is true
  684. ConstRRsetPtr rrset_;
  685. RdataIteratorPtr rdata_iterator_;
  686. bool separate_rrs_;
  687. bool ready_;
  688. public:
  689. MemoryIterator(const RRClass rrclass,
  690. const ZoneTree& tree, const Name& origin,
  691. bool separate_rrs) :
  692. rrclass_(rrclass),
  693. tree_(tree),
  694. separate_rrs_(separate_rrs),
  695. ready_(true)
  696. {
  697. // Find the first node (origin) and preserve the node chain for future
  698. // searches
  699. ZoneTree::Result result(tree_.find(origin, &node_, chain_));
  700. // It can't happen that the origin is not in there
  701. if (result != ZoneTree::EXACTMATCH) {
  702. isc_throw(Unexpected,
  703. "In-memory zone corrupted, missing origin node");
  704. }
  705. // Initialize the iterator if there's somewhere to point to
  706. if (node_ != NULL && node_->getData() != NULL) {
  707. set_node_ = node_->getData();
  708. if (separate_rrs_ && set_node_ != NULL) {
  709. rrset_.reset(new TreeNodeRRset(rrclass_,
  710. node_, set_node_, true));
  711. rdata_iterator_ = rrset_->getRdataIterator();
  712. }
  713. }
  714. }
  715. virtual ConstRRsetPtr getNextRRset() {
  716. if (!ready_) {
  717. isc_throw(Unexpected, "Iterating past the zone end");
  718. }
  719. /*
  720. * This cycle finds the first nonempty node with yet unused
  721. * RdataSset. If it is NULL, we run out of nodes. If it is
  722. * empty, it doesn't contain any RdataSets. If we are at the
  723. * end, just get to next one.
  724. */
  725. while (node_ != NULL &&
  726. (node_->getData() == NULL || set_node_ == NULL)) {
  727. node_ = tree_.nextNode(chain_);
  728. // If there's a node, initialize the iterator and check next time
  729. // if the map is empty or not
  730. if (node_ != NULL && node_->getData() != NULL) {
  731. set_node_ = node_->getData();
  732. // New RRset, so get a new rdata iterator
  733. if (separate_rrs_ && set_node_ != NULL) {
  734. rrset_.reset(new TreeNodeRRset(rrclass_,
  735. node_, set_node_, true));
  736. rdata_iterator_ = rrset_->getRdataIterator();
  737. }
  738. }
  739. }
  740. if (node_ == NULL) {
  741. // That's all, folks
  742. ready_ = false;
  743. return (ConstRRsetPtr());
  744. }
  745. if (separate_rrs_) {
  746. // For separate rrs, reconstruct a new RRset with just the
  747. // 'current' rdata
  748. RRsetPtr result(new RRset(rrset_->getName(),
  749. rrset_->getClass(),
  750. rrset_->getType(),
  751. rrset_->getTTL()));
  752. result->addRdata(rdata_iterator_->getCurrent());
  753. rdata_iterator_->next();
  754. if (rdata_iterator_->isLast()) {
  755. // all used up, next.
  756. set_node_ = set_node_->getNext();
  757. // New RRset, so get a new rdata iterator, but only if this
  758. // was not the final RRset in the chain
  759. if (set_node_ != NULL) {
  760. rrset_.reset(new TreeNodeRRset(rrclass_,
  761. node_, set_node_, true));
  762. rdata_iterator_ = rrset_->getRdataIterator();
  763. }
  764. }
  765. return (result);
  766. } else {
  767. ConstRRsetPtr result(new TreeNodeRRset(rrclass_,
  768. node_, set_node_, true));
  769. // This one is used, move it to the next time for next call
  770. set_node_ = set_node_->getNext();
  771. return (result);
  772. }
  773. }
  774. virtual ConstRRsetPtr getSOA() const {
  775. isc_throw(NotImplemented, "Not implemented");
  776. }
  777. };
  778. } // End of anonymous namespace
  779. ZoneIteratorPtr
  780. InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
  781. ZoneTable::FindResult result(impl_->zone_table_->findZone(name));
  782. if (result.code != result::SUCCESS) {
  783. isc_throw(DataSourceError, "No such zone: " + name.toText());
  784. }
  785. return (ZoneIteratorPtr(new MemoryIterator(
  786. getClass(),
  787. result.zone_data->getZoneTree(), name,
  788. separate_rrs)));
  789. }
  790. ZoneUpdaterPtr
  791. InMemoryClient::getUpdater(const isc::dns::Name&, bool, bool) const {
  792. isc_throw(isc::NotImplemented, "Update attempt on in memory data source");
  793. }
  794. pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
  795. InMemoryClient::getJournalReader(const isc::dns::Name&, uint32_t,
  796. uint32_t) const
  797. {
  798. isc_throw(isc::NotImplemented, "Journaling isn't supported for "
  799. "in memory data source");
  800. }
  801. } // end of namespace memory
  802. } // end of namespace datasrc
  803. } // end of namespace isc