memory_client.cc 34 KB

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