treenode_rrset.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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 <util/buffer.h>
  16. #include <dns/messagerenderer.h>
  17. #include <dns/name.h>
  18. #include <dns/rrclass.h>
  19. #include <dns/rrtype.h>
  20. #include <dns/rrttl.h>
  21. #include <dns/rdata.h>
  22. #include <dns/rrset.h>
  23. #include "treenode_rrset.h"
  24. #include "rdata_serialization.h"
  25. #include <boost/bind.hpp>
  26. #include <cassert>
  27. #include <string>
  28. #include <vector>
  29. using namespace isc::dns;
  30. using namespace isc::dns::rdata;
  31. namespace isc {
  32. namespace datasrc {
  33. namespace memory {
  34. const Name&
  35. TreeNodeRRset::getName() const {
  36. if (realname_ != NULL) {
  37. return (*realname_);
  38. }
  39. if (name_ == NULL) {
  40. uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
  41. const LabelSequence name_labels = getOwnerLabels(labels_buf);
  42. size_t data_len;
  43. const uint8_t* data = name_labels.getData(&data_len);
  44. util::InputBuffer buffer(data, data_len);
  45. name_ = new Name(buffer);
  46. }
  47. return (*name_);
  48. }
  49. const RRTTL&
  50. TreeNodeRRset::getTTL() const {
  51. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  52. }
  53. void
  54. TreeNodeRRset::setName(const Name&) {
  55. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  56. }
  57. void
  58. TreeNodeRRset::setTTL(const RRTTL&) {
  59. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  60. }
  61. std::string
  62. TreeNodeRRset::toText() const {
  63. // Create TTL from internal data
  64. util::InputBuffer ttl_buffer(rdataset_->getTTLData(), sizeof(uint32_t));
  65. const RRTTL ttl(ttl_buffer);
  66. // Dump the main RRset, if not empty
  67. std::string ret;
  68. RRsetPtr tmp_rrset;
  69. for (RdataIteratorPtr rit = getRdataIterator();
  70. !rit->isLast();
  71. rit->next())
  72. {
  73. if (!tmp_rrset) {
  74. tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_, getType(),
  75. ttl));
  76. }
  77. tmp_rrset->addRdata(rit->getCurrent());
  78. }
  79. if (tmp_rrset) {
  80. ret = tmp_rrset->toText();
  81. }
  82. // Dump any RRSIGs
  83. tmp_rrset.reset();
  84. for (RdataIteratorPtr rit = getSigRdataIterator();
  85. !rit->isLast();
  86. rit->next())
  87. {
  88. if (!tmp_rrset) {
  89. tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_,
  90. RRType::RRSIG(), ttl));
  91. }
  92. tmp_rrset->addRdata(rit->getCurrent());
  93. }
  94. if (tmp_rrset) {
  95. ret += tmp_rrset->toText();
  96. }
  97. return (ret);
  98. }
  99. namespace {
  100. void
  101. renderName(const LabelSequence& name_labels, RdataNameAttributes attr,
  102. AbstractMessageRenderer* renderer)
  103. {
  104. renderer->writeName(name_labels, (attr & NAMEATTR_COMPRESSIBLE) != 0);
  105. }
  106. void
  107. renderData(const void* data, size_t data_len,
  108. AbstractMessageRenderer* renderer)
  109. {
  110. renderer->writeData(data, data_len);
  111. }
  112. // Common code logic for rendering a single (either main or RRSIG) RRset.
  113. size_t
  114. writeRRs(AbstractMessageRenderer& renderer, size_t rr_count,
  115. const LabelSequence& name_labels, const RRType& rrtype,
  116. const RRClass& rrclass, const void* ttl_data,
  117. RdataReader& reader, bool (RdataReader::* rdata_iterate_fn)())
  118. {
  119. for (size_t i = 0; i < rr_count; ++i) {
  120. const size_t pos0 = renderer.getLength();
  121. // Name, type, class, TTL
  122. renderer.writeName(name_labels, true);
  123. rrtype.toWire(renderer);
  124. rrclass.toWire(renderer);
  125. renderer.writeData(ttl_data, sizeof(uint32_t));
  126. // RDLEN and RDATA
  127. const size_t pos = renderer.getLength();
  128. renderer.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
  129. const bool rendered = (reader.*rdata_iterate_fn)();
  130. assert(rendered == true);
  131. renderer.writeUint16At(renderer.getLength() - pos - sizeof(uint16_t),
  132. pos);
  133. // Check if truncation would happen
  134. if (renderer.getLength() > renderer.getLengthLimit()) {
  135. renderer.trim(renderer.getLength() - pos0);
  136. renderer.setTruncated();
  137. return (i);
  138. }
  139. }
  140. return (rr_count);
  141. }
  142. }
  143. unsigned int
  144. TreeNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
  145. RdataReader reader(rrclass_, rdataset_->type, rdataset_->getDataBuf(),
  146. rdataset_->getRdataCount(), rrsig_count_,
  147. boost::bind(renderName, _1, _2, &renderer),
  148. boost::bind(renderData, _1, _2, &renderer));
  149. // Get the owner name of the RRset in the form of LabelSequence.
  150. uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
  151. const LabelSequence name_labels = getOwnerLabels(labels_buf);
  152. // Render the main (non RRSIG) RRs
  153. const size_t rendered_rdata_count =
  154. writeRRs(renderer, rdataset_->getRdataCount(), name_labels,
  155. rdataset_->type, rrclass_, rdataset_->getTTLData(), reader,
  156. &RdataReader::iterateRdata);
  157. if (renderer.isTruncated()) {
  158. return (rendered_rdata_count);
  159. }
  160. const bool rendered = reader.iterateRdata();
  161. assert(rendered == false); // we should've reached the end
  162. // Render any RRSIGs, if we supposed to do so
  163. const size_t rendered_rrsig_count = dnssec_ok_ ?
  164. writeRRs(renderer, rrsig_count_, name_labels, RRType::RRSIG(),
  165. rrclass_, rdataset_->getTTLData(), reader,
  166. &RdataReader::iterateSingleSig) : 0;
  167. return (rendered_rdata_count + rendered_rrsig_count);
  168. }
  169. unsigned int
  170. TreeNodeRRset::toWire(isc::util::OutputBuffer&) const {
  171. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  172. }
  173. void
  174. TreeNodeRRset::addRdata(rdata::ConstRdataPtr) {
  175. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  176. }
  177. void
  178. TreeNodeRRset::addRdata(const rdata::Rdata&) {
  179. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  180. }
  181. namespace {
  182. // In this namespace we define a set of helper stuff to implement the
  183. // RdataIterator for the TreeNodeRRset. We should eventually optimize
  184. // the code so that performance sensitive path won't require the iterator,
  185. // so, at the moment, the implementation is straightforward, but less
  186. // efficient one: It builds a vector of Rdata objects on construction,
  187. // and its getCurrent() returns the stored data.
  188. class TreeNodeRdataIterator : public RdataIterator {
  189. public:
  190. TreeNodeRdataIterator(const std::vector<ConstRdataPtr>& rdata_list) :
  191. rdata_list_(rdata_list), rdata_it_(rdata_list_.begin())
  192. {}
  193. virtual void first() { rdata_it_ = rdata_list_.begin(); }
  194. virtual void next() {
  195. ++rdata_it_;
  196. }
  197. virtual const rdata::Rdata& getCurrent() const {
  198. return (**rdata_it_);
  199. }
  200. virtual bool isLast() const { return (rdata_it_ == rdata_list_.end()); }
  201. private:
  202. const std::vector<ConstRdataPtr> rdata_list_;
  203. std::vector<ConstRdataPtr>::const_iterator rdata_it_;
  204. };
  205. void
  206. renderNameToBuffer(const LabelSequence& name_labels, RdataNameAttributes,
  207. util::OutputBuffer* buffer)
  208. {
  209. size_t data_len;
  210. const uint8_t *data = name_labels.getData(&data_len);
  211. buffer->writeData(data, data_len);
  212. }
  213. void
  214. renderDataToBuffer(const void* data, size_t data_len,
  215. util::OutputBuffer* buffer)
  216. {
  217. buffer->writeData(data, data_len);
  218. }
  219. }
  220. RdataIteratorPtr
  221. TreeNodeRRset::getRdataIteratorInternal(bool is_rrsig, size_t count) const {
  222. util::OutputBuffer buffer(0);
  223. RdataReader reader(rrclass_, rdataset_->type, rdataset_->getDataBuf(),
  224. rdataset_->getRdataCount(), rrsig_count_,
  225. boost::bind(renderNameToBuffer, _1, _2, &buffer),
  226. boost::bind(renderDataToBuffer, _1, _2, &buffer));
  227. std::vector<ConstRdataPtr> rdata_list;
  228. for (size_t i = 0; i < count; ++i) {
  229. buffer.clear();
  230. const bool rendered = is_rrsig ? reader.iterateSingleSig() :
  231. reader.iterateRdata();
  232. assert(rendered == true);
  233. util::InputBuffer ib(buffer.getData(), buffer.getLength());
  234. rdata_list.push_back(
  235. createRdata(is_rrsig ? RRType::RRSIG() : rdataset_->type, rrclass_,
  236. ib, ib.getLength()));
  237. }
  238. return (RdataIteratorPtr(new TreeNodeRdataIterator(rdata_list)));
  239. }
  240. RdataIteratorPtr
  241. TreeNodeRRset::getRdataIterator() const {
  242. return (getRdataIteratorInternal(false, rdataset_->getRdataCount()));
  243. }
  244. RdataIteratorPtr
  245. TreeNodeRRset::getSigRdataIterator() const {
  246. return (getRdataIteratorInternal(true, dnssec_ok_ ? rrsig_count_ : 0));
  247. }
  248. RRsetPtr
  249. TreeNodeRRset::getRRsig() const {
  250. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  251. }
  252. void
  253. TreeNodeRRset::addRRsig(const rdata::ConstRdataPtr&) {
  254. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  255. }
  256. void
  257. TreeNodeRRset::addRRsig(const rdata::RdataPtr&) {
  258. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  259. }
  260. void
  261. TreeNodeRRset::addRRsig(const AbstractRRset&) {
  262. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  263. }
  264. void
  265. TreeNodeRRset::addRRsig(const ConstRRsetPtr&) {
  266. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  267. }
  268. void
  269. TreeNodeRRset::addRRsig(const RRsetPtr&) {
  270. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  271. }
  272. void
  273. TreeNodeRRset::removeRRsig() {
  274. isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
  275. }
  276. bool
  277. TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const {
  278. const TreeNodeRRset* other =
  279. dynamic_cast<const TreeNodeRRset*>(&abs_other);
  280. if (other != NULL) {
  281. // If type is different, they are not the same kind
  282. if (rdataset_ != other->rdataset_) {
  283. return (false);
  284. }
  285. // Same for the owner name. Comparing the nodes also detect
  286. // the case where RR classes are different (see the method description
  287. // of the header for details).
  288. if (node_ != other->node_ ) {
  289. return (false);
  290. }
  291. // If one is constructed with a "real name" and the other isn't
  292. // *we consider* them different.
  293. if ((realname_ == NULL && other->realname_ != NULL) ||
  294. (realname_ != NULL && other->realname_ == NULL)) {
  295. return (false);
  296. }
  297. // If both are constructed with a "real name", we compare their names
  298. // (as label sequences) explicitly.
  299. if (realname_ != NULL && other->realname_ != NULL &&
  300. realname_->nequals(*other->realname_)) {
  301. return (false);
  302. }
  303. return (true);
  304. }
  305. return (AbstractRRset::isSameKind(abs_other));
  306. }
  307. } // namespace memory
  308. } // namespace datasrc
  309. } // datasrc isc