zone_data_updater.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <datasrc/memory/zone_data_updater.h>
  15. #include <datasrc/memory/logger.h>
  16. #include <datasrc/zone.h>
  17. #include <dns/rdataclass.h>
  18. using namespace isc::dns;
  19. using namespace isc::dns::rdata;
  20. namespace isc {
  21. namespace datasrc {
  22. namespace memory {
  23. void
  24. ZoneDataUpdater::addWildcards(const Name& name) {
  25. Name wname(name);
  26. const unsigned int labels(wname.getLabelCount());
  27. const unsigned int origin_labels(zone_name_.getLabelCount());
  28. for (unsigned int l = labels;
  29. l > origin_labels;
  30. --l, wname = wname.split(1))
  31. {
  32. if (wname.isWildcard()) {
  33. LOG_DEBUG(logger, DBG_TRACE_DATA,
  34. DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
  35. // Ensure a separate level exists for the "wildcarding"
  36. // name, and mark the node as "wild".
  37. ZoneNode* node;
  38. zone_data_.insertName(mem_sgmt_, wname.split(1), &node);
  39. node->setFlag(ZoneData::WILDCARD_NODE);
  40. // Ensure a separate level exists for the wildcard name.
  41. // Note: for 'name' itself we do this later anyway, but the
  42. // overhead should be marginal because wildcard names should
  43. // be rare.
  44. zone_data_.insertName(mem_sgmt_, wname, &node);
  45. }
  46. }
  47. }
  48. void
  49. ZoneDataUpdater::contextCheck(const AbstractRRset& rrset,
  50. const RdataSet* rdataset) const
  51. {
  52. // Ensure CNAME and other type of RR don't coexist for the same
  53. // owner name except with NSEC, which is the only RR that can
  54. // coexist with CNAME (and also RRSIG, which is handled separately)
  55. if (rrset.getType() == RRType::CNAME()) {
  56. for (const RdataSet* sp = rdataset; sp != NULL; sp = sp->getNext()) {
  57. if (sp->type != RRType::NSEC()) {
  58. LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
  59. arg(rrset.getName());
  60. isc_throw(AddError,
  61. "CNAME can't be added with " << sp->type
  62. << " RRType for " << rrset.getName());
  63. }
  64. }
  65. } else if ((rrset.getType() != RRType::NSEC()) &&
  66. (RdataSet::find(rdataset, RRType::CNAME()) != NULL))
  67. {
  68. LOG_ERROR(logger,
  69. DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
  70. isc_throw(AddError,
  71. "CNAME and " << rrset.getType() <<
  72. " can't coexist for " << rrset.getName());
  73. }
  74. // Similar with DNAME, but it must not coexist only with NS and only
  75. // in non-apex domains. RFC 2672 section 3 mentions that it is
  76. // implied from it and RFC 2181.
  77. if (rrset.getName() != zone_name_ &&
  78. // Adding DNAME, NS already there
  79. ((rrset.getType() == RRType::DNAME() &&
  80. RdataSet::find(rdataset, RRType::NS()) != NULL) ||
  81. // Adding NS, DNAME already there
  82. (rrset.getType() == RRType::NS() &&
  83. RdataSet::find(rdataset, RRType::DNAME()) != NULL)))
  84. {
  85. LOG_ERROR(logger, DATASRC_MEMORY_MEM_DNAME_NS).arg(rrset.getName());
  86. isc_throw(AddError, "DNAME can't coexist with NS in non-apex domain: "
  87. << rrset.getName());
  88. }
  89. }
  90. void
  91. ZoneDataUpdater::validate(const isc::dns::ConstRRsetPtr rrset) const {
  92. if (!rrset) {
  93. isc_throw(NullRRset, "The rrset provided is NULL");
  94. }
  95. if (rrset->getRdataCount() == 0) {
  96. isc_throw(AddError,
  97. "The rrset provided is empty: "
  98. << rrset->getName() << "/" << rrset->getType());
  99. }
  100. // Check for singleton RRs. It should probably handled at a different
  101. // layer in future.
  102. if ((rrset->getType() == RRType::CNAME() ||
  103. rrset->getType() == RRType::DNAME()) &&
  104. rrset->getRdataCount() > 1)
  105. {
  106. // XXX: this is not only for CNAME or DNAME. We should
  107. // generalize this code for all other "singleton RR types" (such
  108. // as SOA) in a separate task.
  109. LOG_ERROR(logger,
  110. DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
  111. arg(rrset->getType());
  112. isc_throw(AddError, "multiple RRs of singleton type for "
  113. << rrset->getName());
  114. }
  115. // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
  116. // implementation requests it be so at the moment.
  117. if ((rrset->getType() == RRType::NSEC3() ||
  118. rrset->getType() == RRType::NSEC3PARAM()) &&
  119. (rrset->getRdataCount() > 1))
  120. {
  121. isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
  122. << rrset->getName() << " which isn't supported");
  123. }
  124. // For RRSIGs, check consistency of the type covered. We know the
  125. // RRset isn't empty, so the following check is safe.
  126. if (rrset->getType() == RRType::RRSIG()) {
  127. RdataIteratorPtr rit = rrset->getRdataIterator();
  128. const RRType covered = dynamic_cast<const generic::RRSIG&>(
  129. rit->getCurrent()).typeCovered();
  130. for (rit->next(); !rit->isLast(); rit->next()) {
  131. if (dynamic_cast<const generic::RRSIG&>(
  132. rit->getCurrent()).typeCovered() != covered)
  133. {
  134. isc_throw(AddError, "RRSIG contains mixed covered types: "
  135. << rrset->toText());
  136. }
  137. }
  138. }
  139. const NameComparisonResult compare = zone_name_.compare(rrset->getName());
  140. if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
  141. compare.getRelation() != NameComparisonResult::EQUAL)
  142. {
  143. LOG_ERROR(logger,
  144. DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
  145. arg(zone_name_);
  146. isc_throw(OutOfZone,
  147. "The name " << rrset->getName() <<
  148. " is not contained in zone " << zone_name_);
  149. }
  150. // Some RR types do not really work well with a wildcard. Even
  151. // though the protocol specifically doesn't completely ban such
  152. // usage, we refuse to load a zone containing such RR in order to
  153. // keep the lookup logic simpler and more predictable. See RFC4592
  154. // and (for DNAME) RFC6672 for more technical background. Note also
  155. // that BIND 9 refuses NS at a wildcard, so in that sense we simply
  156. // provide compatible behavior.
  157. if (rrset->getName().isWildcard()) {
  158. if (rrset->getType() == RRType::NS()) {
  159. LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_NS).
  160. arg(rrset->getName());
  161. isc_throw(AddError, "Invalid NS owner name (wildcard): "
  162. << rrset->getName());
  163. }
  164. if (rrset->getType() == RRType::DNAME()) {
  165. LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_DNAME).
  166. arg(rrset->getName());
  167. isc_throw(AddError, "Invalid DNAME owner name (wildcard): "
  168. << rrset->getName());
  169. }
  170. }
  171. // Owner names of NSEC3 have special format as defined in RFC5155,
  172. // and cannot be a wildcard name or must be one label longer than
  173. // the zone origin. While the RFC doesn't prohibit other forms of
  174. // names, no sane zone would have such names for NSEC3. BIND 9 also
  175. // refuses NSEC3 at wildcard.
  176. if (rrset->getType() == RRType::NSEC3() &&
  177. (rrset->getName().isWildcard() ||
  178. rrset->getName().getLabelCount() != zone_name_.getLabelCount() + 1))
  179. {
  180. LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).arg(rrset->getName());
  181. isc_throw(AddError, "Invalid NSEC3 owner name: " <<
  182. rrset->getName() << "; zone: " << zone_name_);
  183. }
  184. }
  185. const NSEC3Hash*
  186. ZoneDataUpdater::getNSEC3Hash() {
  187. if (hash_ == NULL) {
  188. NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
  189. // This should never be NULL in this codepath.
  190. assert(nsec3_data != NULL);
  191. hash_ = NSEC3Hash::create(nsec3_data->hashalg,
  192. nsec3_data->iterations,
  193. nsec3_data->getSaltData(),
  194. nsec3_data->getSaltLen());
  195. }
  196. return (hash_);
  197. }
  198. template <typename T>
  199. void
  200. ZoneDataUpdater::setupNSEC3(const ConstRRsetPtr rrset) {
  201. // We know rrset has exactly one RDATA
  202. const T& nsec3_rdata =
  203. dynamic_cast<const T&>(
  204. rrset->getRdataIterator()->getCurrent());
  205. NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
  206. if (nsec3_data == NULL) {
  207. nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
  208. zone_data_.setNSEC3Data(nsec3_data);
  209. zone_data_.setSigned(true);
  210. } else {
  211. const NSEC3Hash* hash = getNSEC3Hash();
  212. if (!hash->match(nsec3_rdata)) {
  213. isc_throw(AddError,
  214. rrset->getType() << " with inconsistent parameters: "
  215. << rrset->toText());
  216. }
  217. }
  218. }
  219. void
  220. ZoneDataUpdater::addNSEC3(const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
  221. {
  222. setupNSEC3<generic::NSEC3>(rrset);
  223. NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
  224. ZoneNode* node;
  225. nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
  226. RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig);
  227. RdataSet* old_rdataset = node->setData(rdataset);
  228. if (old_rdataset != NULL) {
  229. RdataSet::destroy(mem_sgmt_, rrclass_, old_rdataset);
  230. }
  231. }
  232. void
  233. ZoneDataUpdater::addRdataSet(const ConstRRsetPtr rrset,
  234. const ConstRRsetPtr rrsig)
  235. {
  236. if (rrset->getType() == RRType::NSEC3()) {
  237. addNSEC3(rrset, rrsig);
  238. } else {
  239. ZoneNode* node;
  240. zone_data_.insertName(mem_sgmt_, rrset->getName(), &node);
  241. RdataSet* rdataset_head = node->getData();
  242. // Checks related to the surrounding data. Note: when the check
  243. // fails and the exception is thrown, it may break strong
  244. // exception guarantee. At the moment we prefer code simplicity
  245. // and don't bother to introduce complicated recovery code.
  246. contextCheck(*rrset, rdataset_head);
  247. if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
  248. isc_throw(AddError,
  249. "RRset of the type already exists: "
  250. << rrset->getName() << " (type: "
  251. << rrset->getType() << ")");
  252. }
  253. RdataSet* rdataset_new = RdataSet::create(mem_sgmt_, encoder_,
  254. rrset, rrsig);
  255. rdataset_new->next = rdataset_head;
  256. node->setData(rdataset_new);
  257. // Ok, we just put it in.
  258. // If this RRset creates a zone cut at this node, mark the node
  259. // indicating the need for callback in find().
  260. if (rrset->getType() == RRType::NS() &&
  261. rrset->getName() != zone_name_) {
  262. node->setFlag(ZoneNode::FLAG_CALLBACK);
  263. // If it is DNAME, we have a callback as well here
  264. } else if (rrset->getType() == RRType::DNAME()) {
  265. node->setFlag(ZoneNode::FLAG_CALLBACK);
  266. }
  267. // If we've added NSEC3PARAM at zone origin, set up NSEC3
  268. // specific data or check consistency with already set up
  269. // parameters.
  270. if (rrset->getType() == RRType::NSEC3PARAM() &&
  271. rrset->getName() == zone_name_) {
  272. setupNSEC3<generic::NSEC3PARAM>(rrset);
  273. } else if (rrset->getType() == RRType::NSEC()) {
  274. // If it is NSEC signed zone, we mark the zone as signed
  275. // (conceptually "signed" is a broader notion but our
  276. // current zone finder implementation regards "signed" as
  277. // "NSEC signed")
  278. zone_data_.setSigned(true);
  279. }
  280. }
  281. }
  282. void
  283. ZoneDataUpdater::add(const ConstRRsetPtr& rrset,
  284. const ConstRRsetPtr& sig_rrset)
  285. {
  286. // Validate input. This will cause an exception to be thrown if the
  287. // input RRset is empty.
  288. validate(rrset);
  289. if (sig_rrset) {
  290. validate(sig_rrset);
  291. }
  292. // OK, can add the RRset.
  293. LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
  294. arg(rrset->getName()).arg(rrset->getType()).arg(zone_name_);
  295. // Add wildcards possibly contained in the owner name to the domain
  296. // tree. This can only happen for the normal (non-NSEC3) tree.
  297. // Note: this can throw an exception, breaking strong exception
  298. // guarantee. (see also the note for the call to contextCheck()
  299. // above).
  300. if (rrset->getType() != RRType::NSEC3()) {
  301. addWildcards(rrset->getName());
  302. }
  303. addRdataSet(rrset, sig_rrset);
  304. }
  305. } // namespace memory
  306. } // namespace datasrc
  307. } // namespace isc