memory_client.cc 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070
  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. ConstRRsetPtr last_rrset_;
  96. // Common process for zone load.
  97. // rrset_installer is a functor that takes another functor as an argument,
  98. // and expected to call the latter for each RRset of the zone. How the
  99. // sequence of the RRsets is generated depends on the internal
  100. // details of the loader: either from a textual master file or from
  101. // another data source.
  102. // filename is the file name of the master file or empty if the zone is
  103. // loaded from another data source.
  104. result::Result load(const Name& zone_name, const string& filename,
  105. boost::function<void(LoadCallback)> rrset_installer);
  106. // Add the necessary magic for any wildcard contained in 'name'
  107. // (including itself) to be found in the zone.
  108. //
  109. // In order for wildcard matching to work correctly in the zone finder,
  110. // we must ensure that a node for the wildcarding level exists in the
  111. // backend RBTree.
  112. // E.g. if the wildcard name is "*.sub.example." then we must ensure
  113. // that "sub.example." exists and is marked as a wildcard level.
  114. // Note: the "wildcarding level" is for the parent name of the wildcard
  115. // name (such as "sub.example.").
  116. //
  117. // We also perform the same trick for empty wild card names possibly
  118. // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
  119. void addWildcards(const Name& zone_name, ZoneData& zone_data,
  120. const Name& name)
  121. {
  122. Name wname(name);
  123. const unsigned int labels(wname.getLabelCount());
  124. const unsigned int origin_labels(zone_name.getLabelCount());
  125. for (unsigned int l = labels;
  126. l > origin_labels;
  127. --l, wname = wname.split(1)) {
  128. if (wname.isWildcard()) {
  129. LOG_DEBUG(logger, DBG_TRACE_DATA,
  130. DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
  131. // Ensure a separate level exists for the "wildcarding" name,
  132. // and mark the node as "wild".
  133. ZoneNode* node;
  134. zone_data.insertName(mem_sgmt_, wname.split(1), &node);
  135. node->setFlag(ZoneData::WILDCARD_NODE);
  136. // Ensure a separate level exists for the wildcard name.
  137. // Note: for 'name' itself we do this later anyway, but the
  138. // overhead should be marginal because wildcard names should
  139. // be rare.
  140. zone_data.insertName(mem_sgmt_, wname, &node);
  141. }
  142. }
  143. }
  144. /*
  145. * Does some checks in context of the data that are already in the zone.
  146. * Currently checks for forbidden combinations of RRsets in the same
  147. * domain (CNAME+anything, DNAME+NS).
  148. *
  149. * If such condition is found, it throws AddError.
  150. */
  151. void contextCheck(const Name& zone_name, const AbstractRRset& rrset,
  152. const RdataSet* set) const {
  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) draft-ietf-dnsext-rfc2672bis-dname
  255. // for more technical background. Note also that BIND 9 refuses
  256. // NS at a wildcard, so in that sense we simply provide compatible
  257. // behavior.
  258. if (rrset->getName().isWildcard()) {
  259. if (rrset->getType() == RRType::NS()) {
  260. LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_NS).
  261. arg(rrset->getName());
  262. isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
  263. rrset->getName());
  264. }
  265. if (rrset->getType() == RRType::DNAME()) {
  266. LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_DNAME).
  267. arg(rrset->getName());
  268. isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
  269. rrset->getName());
  270. }
  271. }
  272. // Owner names of NSEC3 have special format as defined in RFC5155,
  273. // and cannot be a wildcard name or must be one label longer than
  274. // the zone origin. While the RFC doesn't prohibit other forms of
  275. // names, no sane zone would have such names for NSEC3.
  276. // BIND 9 also refuses NSEC3 at wildcard.
  277. if (rrset->getType() == RRType::NSEC3() &&
  278. (rrset->getName().isWildcard() ||
  279. rrset->getName().getLabelCount() !=
  280. zone_name.getLabelCount() + 1)) {
  281. LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).
  282. arg(rrset->getName());
  283. isc_throw(AddError, "Invalid NSEC3 owner name: " <<
  284. rrset->getName());
  285. }
  286. }
  287. void addNSEC3(const ConstRRsetPtr rrset,
  288. const ConstRRsetPtr rrsig,
  289. ZoneData& zone_data) {
  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. // Only one of these can be passed at a time.
  328. assert(!(rrset && rrsig));
  329. // If rrsig is passed, validate it against the last-saved rrset.
  330. if (rrsig) {
  331. // The covered RRset should have been saved by now.
  332. if (!last_rrset_) {
  333. isc_throw(AddError,
  334. "RRSIG is being added, "
  335. "but doesn't follow its covered RR: "
  336. << rrsig->getName());
  337. }
  338. if (rrsig->getName() != last_rrset_->getName()) {
  339. isc_throw(AddError,
  340. "RRSIG is being added, "
  341. "but doesn't match the last RR's name: "
  342. << last_rrset_->getName() << " vs. "
  343. << rrsig->getName());
  344. }
  345. // Consistency of other types in rrsig are checked in addRRsig().
  346. RdataIteratorPtr rit = rrsig->getRdataIterator();
  347. const RRType covered = dynamic_cast<const generic::RRSIG&>(
  348. rit->getCurrent()).typeCovered();
  349. if (covered != last_rrset_->getType()) {
  350. isc_throw(AddError,
  351. "RRSIG is being added, "
  352. "but doesn't match the last RR's type: "
  353. << last_rrset_->getType() << " vs. "
  354. << covered);
  355. }
  356. }
  357. if (!last_rrset_) {
  358. last_rrset_ = rrset;
  359. return;
  360. }
  361. if (last_rrset_->getType() == RRType::NSEC3()) {
  362. addNSEC3(last_rrset_, rrsig, zone_data);
  363. } else {
  364. ZoneNode* node;
  365. zone_data.insertName(mem_sgmt_, last_rrset_->getName(), &node);
  366. RdataSet* set = node->getData();
  367. // Checks related to the surrounding data.
  368. // Note: when the check fails and the exception is thrown,
  369. // it may break strong exception guarantee. At the moment
  370. // we prefer code simplicity and don't bother to introduce
  371. // complicated recovery code.
  372. contextCheck(zone_name, *last_rrset_, set);
  373. if (RdataSet::find(set, last_rrset_->getType()) != NULL) {
  374. isc_throw(AddError,
  375. "RRset of the type already exists: "
  376. << last_rrset_->getName() << " (type: "
  377. << last_rrset_->getType() << ")");
  378. }
  379. RdataEncoder encoder;
  380. RdataSet *new_set = RdataSet::create(mem_sgmt_, encoder,
  381. last_rrset_, rrsig);
  382. new_set->next = set;
  383. node->setData(new_set);
  384. // Ok, we just put it in
  385. // If this RRset creates a zone cut at this node, mark the
  386. // node indicating the need for callback in find().
  387. if (last_rrset_->getType() == RRType::NS() &&
  388. last_rrset_->getName() != zone_name) {
  389. node->setFlag(ZoneNode::FLAG_CALLBACK);
  390. // If it is DNAME, we have a callback as well here
  391. } else if (last_rrset_->getType() == RRType::DNAME()) {
  392. node->setFlag(ZoneNode::FLAG_CALLBACK);
  393. }
  394. // If we've added NSEC3PARAM at zone origin, set up NSEC3
  395. // specific data or check consistency with already set up
  396. // parameters.
  397. if (last_rrset_->getType() == RRType::NSEC3PARAM() &&
  398. last_rrset_->getName() == zone_name) {
  399. // We know rrset has exactly one RDATA
  400. const generic::NSEC3PARAM& param =
  401. dynamic_cast<const generic::NSEC3PARAM&>
  402. (last_rrset_->getRdataIterator()->getCurrent());
  403. NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
  404. if (nsec3_data == NULL) {
  405. nsec3_data = NSEC3Data::create(mem_sgmt_, param);
  406. zone_data.setNSEC3Data(nsec3_data);
  407. } else {
  408. size_t salt_len = nsec3_data->getSaltLen();
  409. const uint8_t* salt_data = nsec3_data->getSaltData();
  410. const vector<uint8_t>& salt_data_2 = param.getSalt();
  411. if ((param.getHashalg() != nsec3_data->hashalg) ||
  412. (param.getIterations() != nsec3_data->iterations) ||
  413. (salt_data_2.size() != salt_len) ||
  414. (std::memcmp(&salt_data_2[0],
  415. salt_data, salt_len) != 0)) {
  416. isc_throw(AddError,
  417. "NSEC3PARAM with inconsistent parameters: "
  418. << last_rrset_->toText());
  419. }
  420. }
  421. } else if (last_rrset_->getType() == RRType::NSEC()) {
  422. // If it is NSEC signed zone, so we put a flag there
  423. // (flag is enough)
  424. zone_data.setSigned(true);
  425. }
  426. }
  427. last_rrset_ = rrset;
  428. }
  429. void addRdataSet2(const Name& zone_name, ZoneData& zone_data,
  430. const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
  431. {
  432. if (rrset->getType() == RRType::NSEC3()) {
  433. addNSEC3(rrset, rrsig, zone_data);
  434. } else {
  435. ZoneNode* node;
  436. zone_data.insertName(mem_sgmt_, rrset->getName(), &node);
  437. RdataSet* rdataset_head = node->getData();
  438. // Checks related to the surrounding data.
  439. // Note: when the check fails and the exception is thrown,
  440. // it may break strong exception guarantee. At the moment
  441. // we prefer code simplicity and don't bother to introduce
  442. // complicated recovery code.
  443. contextCheck(zone_name, *rrset, rdataset_head);
  444. if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
  445. isc_throw(AddError,
  446. "RRset of the type already exists: "
  447. << rrset->getName() << " (type: "
  448. << rrset->getType() << ")");
  449. }
  450. RdataEncoder encoder;
  451. RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder, rrset,
  452. rrsig);
  453. rdataset->next = rdataset_head;
  454. node->setData(rdataset);
  455. // Ok, we just put it in
  456. // If this RRset creates a zone cut at this node, mark the
  457. // node indicating the need for callback in find().
  458. if (rrset->getType() == RRType::NS() &&
  459. rrset->getName() != zone_name) {
  460. node->setFlag(ZoneNode::FLAG_CALLBACK);
  461. // If it is DNAME, we have a callback as well here
  462. } else if (rrset->getType() == RRType::DNAME()) {
  463. node->setFlag(ZoneNode::FLAG_CALLBACK);
  464. }
  465. // If we've added NSEC3PARAM at zone origin, set up NSEC3
  466. // specific data or check consistency with already set up
  467. // parameters.
  468. if (rrset->getType() == RRType::NSEC3PARAM() &&
  469. rrset->getName() == zone_name) {
  470. // We know rrset has exactly one RDATA
  471. const generic::NSEC3PARAM& param =
  472. dynamic_cast<const generic::NSEC3PARAM&>
  473. (rrset->getRdataIterator()->getCurrent());
  474. NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
  475. if (nsec3_data == NULL) {
  476. nsec3_data = NSEC3Data::create(mem_sgmt_, param);
  477. zone_data.setNSEC3Data(nsec3_data);
  478. } else {
  479. size_t salt_len = nsec3_data->getSaltLen();
  480. const uint8_t* salt_data = nsec3_data->getSaltData();
  481. const vector<uint8_t>& salt_data_2 = param.getSalt();
  482. if ((param.getHashalg() != nsec3_data->hashalg) ||
  483. (param.getIterations() != nsec3_data->iterations) ||
  484. (salt_data_2.size() != salt_len) ||
  485. (std::memcmp(&salt_data_2[0],
  486. salt_data, salt_len) != 0)) {
  487. isc_throw(AddError,
  488. "NSEC3PARAM with inconsistent parameters: "
  489. << rrset->toText());
  490. }
  491. }
  492. } else if (rrset->getType() == RRType::NSEC()) {
  493. // If it is NSEC signed zone, so we put a flag there
  494. // (flag is enough)
  495. zone_data.setSigned(true);
  496. }
  497. }
  498. }
  499. result::Result addRRsig(const ConstRRsetPtr sig_rrset,
  500. const Name& zone_name, ZoneData& zone_data)
  501. {
  502. // Check consistency of the type covered.
  503. // We know the RRset isn't empty, so the following check is safe.
  504. RdataIteratorPtr rit = sig_rrset->getRdataIterator();
  505. const RRType covered = dynamic_cast<const generic::RRSIG&>(
  506. rit->getCurrent()).typeCovered();
  507. for (rit->next(); !rit->isLast(); rit->next()) {
  508. if (dynamic_cast<const generic::RRSIG&>(
  509. rit->getCurrent()).typeCovered() != covered) {
  510. isc_throw(AddError, "RRSIG contains mixed covered types: "
  511. << sig_rrset->toText());
  512. }
  513. }
  514. addRdataSet(zone_name, zone_data, ConstRRsetPtr(), sig_rrset);
  515. return (result::SUCCESS);
  516. }
  517. /*
  518. * Implementation of longer methods. We put them here, because the
  519. * access is without the impl_-> and it will get inlined anyway.
  520. */
  521. // Implementation of InMemoryClient::add()
  522. result::Result add(const ConstRRsetPtr& rrset,
  523. const Name& zone_name, ZoneData& zone_data)
  524. {
  525. // Sanitize input. This will cause an exception to be thrown
  526. // if the input RRset is empty.
  527. addValidation(zone_name, rrset);
  528. // OK, can add the RRset.
  529. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
  530. arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
  531. if (rrset->getType() == RRType::NSEC3()) {
  532. addRdataSet(zone_name, zone_data, rrset, ConstRRsetPtr());
  533. return (result::SUCCESS);
  534. }
  535. // RRSIGs are special in various points, so we handle it in a
  536. // separate dedicated method.
  537. if (rrset->getType() == RRType::RRSIG()) {
  538. return (addRRsig(rrset, zone_name, zone_data));
  539. }
  540. // Add wildcards possibly contained in the owner name to the domain
  541. // tree.
  542. // Note: this can throw an exception, breaking strong exception
  543. // guarantee. (see also the note for contextCheck() below).
  544. addWildcards(zone_name, zone_data, rrset->getName());
  545. addRdataSet(zone_name, zone_data, rrset, ConstRRsetPtr());
  546. return (result::SUCCESS);
  547. }
  548. result::Result add(const ConstRRsetPtr& rrset,
  549. const ConstRRsetPtr& sig_rrset,
  550. const Name& zone_name, ZoneData& zone_data)
  551. {
  552. // Sanitize input. This will cause an exception to be thrown
  553. // if the input RRset is empty.
  554. addValidation(zone_name, rrset);
  555. if (sig_rrset) {
  556. addValidation(zone_name, sig_rrset);
  557. }
  558. // OK, can add the RRset.
  559. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
  560. arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
  561. if (rrset->getType() == RRType::NSEC3()) {
  562. addRdataSet2(zone_name, zone_data, rrset, sig_rrset);
  563. return (result::SUCCESS);
  564. }
  565. // Add wildcards possibly contained in the owner name to the domain
  566. // tree.
  567. // Note: this can throw an exception, breaking strong exception
  568. // guarantee. (see also the note for contextCheck() below).
  569. addWildcards(zone_name, zone_data, rrset->getName());
  570. addRdataSet2(zone_name, zone_data, rrset, sig_rrset);
  571. return (result::SUCCESS);
  572. }
  573. };
  574. // A helper internal class for load(). make it non-copyable to avoid
  575. // accidental copy.
  576. //
  577. // The current internal implementation expects that both a normal
  578. // (non RRSIG) RRset and (when signed) its RRSIG are added at once.
  579. // Also in the current implementation, the input sequence of RRsets
  580. // are grouped with their owner name (so if the owner name is changed
  581. // no subsequent RRset has the previous owner name), but the ordering
  582. // in the same group is not fixed. So we hold all RRsets of the same
  583. // owner name in node_rrsets_ and node_rrsets_, and add the matching
  584. // pairs of RRsets to the zone when we see a new owner name.
  585. //
  586. // The caller is responsible for adding the RRsets of the last group
  587. // in the input sequence by explicitly calling flushNodeRRsets() at the
  588. // end. It's cleaner and more robust if we let the destructor of this class,
  589. // but since we cannot guarantee the adding operation is exception free,
  590. // we don't choose that option to maintain the common expectation for
  591. // destructors.
  592. class InMemoryClient::Loader : boost::noncopyable {
  593. typedef std::map<RRType, ConstRRsetPtr> NodeRRsets;
  594. typedef NodeRRsets::value_type NodeRRsetsVal;
  595. public:
  596. Loader(InMemoryClientImpl* client_impl) : client_impl_(client_impl) {}
  597. void addFromLoad(const ConstRRsetPtr& rrset,
  598. const Name& zone_name, ZoneData* zone_data)
  599. {
  600. if ((!node_rrsets_.empty() || !node_rrsigsets_.empty()) &&
  601. getCurrentName() != rrset->getName()) {
  602. flushNodeRRsets(zone_name, zone_data);
  603. }
  604. if (rrset->getType() == RRType::RRSIG()) {
  605. node_rrsigsets_.insert(NodeRRsetsVal(getCoveredType(rrset),
  606. rrset));
  607. } else {
  608. if (!node_rrsets_.insert(NodeRRsetsVal(rrset->getType(),
  609. rrset)).second) {
  610. isc_throw(AddError,
  611. "Duplicate add of the same type of RRset: "
  612. << rrset->getName() << "/" << rrset->getType());
  613. }
  614. }
  615. }
  616. void flushNodeRRsets(const Name& zone_name, ZoneData* zone_data) {
  617. BOOST_FOREACH(NodeRRsetsVal val, node_rrsets_) {
  618. ConstRRsetPtr sig_rrset;
  619. NodeRRsets::const_iterator sig_it =
  620. node_rrsigsets_.find(val.first);
  621. if (sig_it != node_rrsigsets_.end()) {
  622. sig_rrset = sig_it->second;
  623. }
  624. const result::Result result =
  625. client_impl_->add(val.second, sig_rrset, zone_name,
  626. *zone_data);
  627. assert(result == result::SUCCESS);
  628. }
  629. node_rrsets_.clear();
  630. node_rrsigsets_.clear();
  631. }
  632. private:
  633. static RRType getCoveredType(const ConstRRsetPtr& sig_rrset) {
  634. RdataIteratorPtr it = sig_rrset->getRdataIterator();
  635. // TBD: empty case
  636. return (dynamic_cast<const generic::RRSIG&>(it->getCurrent()).
  637. typeCovered());
  638. }
  639. const Name& getCurrentName() const {
  640. if (!node_rrsets_.empty()) {
  641. return (node_rrsets_.begin()->second->getName());
  642. }
  643. assert(!node_rrsigsets_.empty());
  644. return (node_rrsigsets_.begin()->second->getName());
  645. }
  646. private:
  647. InMemoryClientImpl* client_impl_;
  648. NodeRRsets node_rrsets_;
  649. NodeRRsets node_rrsigsets_;
  650. };
  651. result::Result
  652. InMemoryClient::InMemoryClientImpl::load(
  653. const Name& zone_name,
  654. const string& filename,
  655. boost::function<void(LoadCallback)> rrset_installer)
  656. {
  657. SegmentObjectHolder<ZoneData, RRClass> holder(
  658. mem_sgmt_, ZoneData::create(mem_sgmt_, zone_name), rrclass_);
  659. assert(!last_rrset_);
  660. try {
  661. Loader loader(this);
  662. rrset_installer(boost::bind(&Loader::addFromLoad, &loader,
  663. _1, zone_name, holder.get()));
  664. // Add any last RRsets that were left
  665. loader.flushNodeRRsets(zone_name, holder.get());
  666. } catch (...) {
  667. last_rrset_ = ConstRRsetPtr();
  668. throw;
  669. }
  670. assert(!last_rrset_);
  671. const ZoneNode* origin_node = holder.get()->getOriginNode();
  672. const RdataSet* set = origin_node->getData();
  673. // If the zone is NSEC3-signed, check if it has NSEC3PARAM
  674. if (holder.get()->isNSEC3Signed()) {
  675. // Note: origin_data_ is set on creation of ZoneData, and the load
  676. // process only adds new nodes (and their data), so this assertion
  677. // should hold.
  678. if (RdataSet::find(set, RRType::NSEC3PARAM()) == NULL) {
  679. LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
  680. arg(zone_name).arg(rrclass_);
  681. }
  682. }
  683. // When an empty zone file is loaded, the origin doesn't even have
  684. // an SOA RR. This condition should be avoided, and hence load()
  685. // should throw when an empty zone is loaded.
  686. if (RdataSet::find(set, RRType::SOA()) == NULL) {
  687. isc_throw(EmptyZone,
  688. "Won't create an empty zone for: " << zone_name);
  689. }
  690. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
  691. arg(zone_name).arg(rrclass_.toText());
  692. // Set the filename in file_name_tree_ now, so that getFileName()
  693. // can use it (during zone reloading).
  694. FileNameNode* node(NULL);
  695. switch (file_name_tree_->insert(mem_sgmt_, zone_name, &node)) {
  696. case FileNameTree::SUCCESS:
  697. case FileNameTree::ALREADYEXISTS:
  698. // These are OK
  699. break;
  700. default:
  701. // Can Not Happen
  702. assert(false);
  703. }
  704. // node must point to a valid node now
  705. assert(node != NULL);
  706. std::string* tstr = node->setData(new std::string(filename));
  707. delete tstr;
  708. ZoneTable::AddResult result(zone_table_->addZone(mem_sgmt_, rrclass_,
  709. zone_name));
  710. if (result.code == result::SUCCESS) {
  711. // Only increment the zone count if the zone doesn't already
  712. // exist.
  713. ++zone_count_;
  714. }
  715. ZoneTable::FindResult fr(zone_table_->setZoneData(zone_name,
  716. holder.release()));
  717. assert(fr.code == result::SUCCESS);
  718. if (fr.zone_data != NULL) {
  719. ZoneData::destroy(mem_sgmt_, fr.zone_data, rrclass_);
  720. }
  721. return (result.code);
  722. }
  723. namespace {
  724. // A wrapper for dns::masterLoad used by load() below. Essentially it
  725. // converts the two callback types. Note the mostly redundant wrapper of
  726. // boost::bind. It converts function<void(ConstRRsetPtr)> to
  727. // function<void(RRsetPtr)> (masterLoad() expects the latter). SunStudio
  728. // doesn't seem to do this conversion if we just pass 'callback'.
  729. void
  730. masterLoadWrapper(const char* const filename, const Name& origin,
  731. const RRClass& zone_class, LoadCallback callback)
  732. {
  733. masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
  734. }
  735. // The installer called from Impl::load() for the iterator version of load().
  736. void
  737. generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
  738. ConstRRsetPtr rrset;
  739. while ((rrset = iterator->getNextRRset()) != NULL) {
  740. callback(rrset);
  741. }
  742. }
  743. }
  744. InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
  745. RRClass rrclass) :
  746. impl_(new InMemoryClientImpl(mem_sgmt, rrclass))
  747. {}
  748. InMemoryClient::~InMemoryClient() {
  749. delete impl_;
  750. }
  751. RRClass
  752. InMemoryClient::getClass() const {
  753. return (impl_->rrclass_);
  754. }
  755. unsigned int
  756. InMemoryClient::getZoneCount() const {
  757. return (impl_->zone_count_);
  758. }
  759. isc::datasrc::memory::ZoneTable::FindResult
  760. InMemoryClient::findZone2(const isc::dns::Name& zone_name) const {
  761. LOG_DEBUG(logger, DBG_TRACE_DATA,
  762. DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
  763. ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
  764. return (result);
  765. }
  766. isc::datasrc::DataSourceClient::FindResult
  767. InMemoryClient::findZone(const isc::dns::Name&) const {
  768. // This variant of findZone() is not implemented and should be
  769. // removed eventually. It currently throws an exception. It is
  770. // required right now to derive from DataSourceClient.
  771. isc_throw(isc::NotImplemented,
  772. "This variant of findZone() is not implemented.");
  773. }
  774. result::Result
  775. InMemoryClient::load(const isc::dns::Name& zone_name,
  776. const std::string& filename) {
  777. LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
  778. arg(filename);
  779. return (impl_->load(zone_name, filename,
  780. boost::bind(masterLoadWrapper, filename.c_str(),
  781. zone_name, getClass(), _1)));
  782. }
  783. result::Result
  784. InMemoryClient::load(const isc::dns::Name& zone_name,
  785. ZoneIterator& iterator) {
  786. return (impl_->load(zone_name, string(),
  787. boost::bind(generateRRsetFromIterator,
  788. &iterator, _1)));
  789. }
  790. const std::string
  791. InMemoryClient::getFileName(const isc::dns::Name& zone_name) const {
  792. FileNameNode* node(NULL);
  793. FileNameTree::Result result = impl_->file_name_tree_->find(zone_name,
  794. &node);
  795. if (result == FileNameTree::EXACTMATCH) {
  796. return (*node->getData());
  797. } else {
  798. return (std::string());
  799. }
  800. }
  801. result::Result
  802. InMemoryClient::add(const isc::dns::Name& zone_name,
  803. const ConstRRsetPtr& rrset)
  804. {
  805. assert(!impl_->last_rrset_);
  806. const ZoneTable::FindResult result =
  807. impl_->zone_table_->findZone(zone_name);
  808. if (result.code != result::SUCCESS) {
  809. isc_throw(DataSourceError, "No such zone: " + zone_name.toText());
  810. }
  811. const ConstRRsetPtr sig_rrset =
  812. rrset ? rrset->getRRsig() : ConstRRsetPtr();
  813. const result::Result ret(impl_->add(rrset, sig_rrset,
  814. zone_name, *result.zone_data));
  815. assert(!impl_->last_rrset_);
  816. return (ret);
  817. }
  818. namespace {
  819. class MemoryIterator : public ZoneIterator {
  820. private:
  821. ZoneChain chain_;
  822. const RdataSet* set_node_;
  823. const RRClass rrclass_;
  824. const ZoneTree& tree_;
  825. const ZoneNode* node_;
  826. // Only used when separate_rrs_ is true
  827. ConstRRsetPtr rrset_;
  828. RdataIteratorPtr rdata_iterator_;
  829. bool separate_rrs_;
  830. bool ready_;
  831. public:
  832. MemoryIterator(const RRClass rrclass,
  833. const ZoneTree& tree, const Name& origin,
  834. bool separate_rrs) :
  835. rrclass_(rrclass),
  836. tree_(tree),
  837. separate_rrs_(separate_rrs),
  838. ready_(true)
  839. {
  840. // Find the first node (origin) and preserve the node chain for future
  841. // searches
  842. ZoneTree::Result result(tree_.find(origin, &node_, chain_));
  843. // It can't happen that the origin is not in there
  844. if (result != ZoneTree::EXACTMATCH) {
  845. isc_throw(Unexpected,
  846. "In-memory zone corrupted, missing origin node");
  847. }
  848. // Initialize the iterator if there's somewhere to point to
  849. if (node_ != NULL && node_->getData() != NULL) {
  850. set_node_ = node_->getData();
  851. if (separate_rrs_ && set_node_ != NULL) {
  852. rrset_.reset(new TreeNodeRRset(rrclass_,
  853. node_, set_node_, true));
  854. rdata_iterator_ = rrset_->getRdataIterator();
  855. }
  856. }
  857. }
  858. virtual ConstRRsetPtr getNextRRset() {
  859. if (!ready_) {
  860. isc_throw(Unexpected, "Iterating past the zone end");
  861. }
  862. /*
  863. * This cycle finds the first nonempty node with yet unused
  864. * RdataSset. If it is NULL, we run out of nodes. If it is
  865. * empty, it doesn't contain any RdataSets. If we are at the
  866. * end, just get to next one.
  867. */
  868. while (node_ != NULL &&
  869. (node_->getData() == NULL || set_node_ == NULL)) {
  870. node_ = tree_.nextNode(chain_);
  871. // If there's a node, initialize the iterator and check next time
  872. // if the map is empty or not
  873. if (node_ != NULL && node_->getData() != NULL) {
  874. set_node_ = node_->getData();
  875. // New RRset, so get a new rdata iterator
  876. if (separate_rrs_ && set_node_ != NULL) {
  877. rrset_.reset(new TreeNodeRRset(rrclass_,
  878. node_, set_node_, true));
  879. rdata_iterator_ = rrset_->getRdataIterator();
  880. }
  881. }
  882. }
  883. if (node_ == NULL) {
  884. // That's all, folks
  885. ready_ = false;
  886. return (ConstRRsetPtr());
  887. }
  888. if (separate_rrs_) {
  889. // For separate rrs, reconstruct a new RRset with just the
  890. // 'current' rdata
  891. RRsetPtr result(new RRset(rrset_->getName(),
  892. rrset_->getClass(),
  893. rrset_->getType(),
  894. rrset_->getTTL()));
  895. result->addRdata(rdata_iterator_->getCurrent());
  896. rdata_iterator_->next();
  897. if (rdata_iterator_->isLast()) {
  898. // all used up, next.
  899. set_node_ = set_node_->getNext();
  900. // New RRset, so get a new rdata iterator, but only if this
  901. // was not the final RRset in the chain
  902. if (set_node_ != NULL) {
  903. rrset_.reset(new TreeNodeRRset(rrclass_,
  904. node_, set_node_, true));
  905. rdata_iterator_ = rrset_->getRdataIterator();
  906. }
  907. }
  908. return (result);
  909. } else {
  910. ConstRRsetPtr result(new TreeNodeRRset(rrclass_,
  911. node_, set_node_, true));
  912. // This one is used, move it to the next time for next call
  913. set_node_ = set_node_->getNext();
  914. return (result);
  915. }
  916. }
  917. virtual ConstRRsetPtr getSOA() const {
  918. isc_throw(NotImplemented, "Not implemented");
  919. }
  920. };
  921. } // End of anonymous namespace
  922. ZoneIteratorPtr
  923. InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
  924. ZoneTable::FindResult result(impl_->zone_table_->findZone(name));
  925. if (result.code != result::SUCCESS) {
  926. isc_throw(DataSourceError, "No such zone: " + name.toText());
  927. }
  928. return (ZoneIteratorPtr(new MemoryIterator(
  929. getClass(),
  930. result.zone_data->getZoneTree(), name,
  931. separate_rrs)));
  932. }
  933. ZoneUpdaterPtr
  934. InMemoryClient::getUpdater(const isc::dns::Name&, bool, bool) const {
  935. isc_throw(isc::NotImplemented, "Update attempt on in memory data source");
  936. }
  937. pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
  938. InMemoryClient::getJournalReader(const isc::dns::Name&, uint32_t,
  939. uint32_t) const
  940. {
  941. isc_throw(isc::NotImplemented, "Journaling isn't supported for "
  942. "in memory data source");
  943. }
  944. } // end of namespace memory
  945. } // end of namespace datasrc
  946. } // end of namespace isc