messagerenderer.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. // Copyright (C) 2009 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. // $Id$
  15. #include <cctype>
  16. #include <cassert>
  17. #include <set>
  18. #include <dns/buffer.h>
  19. #include <dns/name.h>
  20. #include <dns/messagerenderer.h>
  21. namespace isc {
  22. namespace dns {
  23. namespace { // hide internal-only names from the public namespaces
  24. ///
  25. /// \brief The \c NameCompressNode class represents a pointer to a name
  26. /// rendered in the internal buffer for the \c MessageRendererImpl object.
  27. ///
  28. /// A \c MessageRendererImpl object maintains a set of the \c NameCompressNode
  29. /// objects, and searches the set for the position of the longest match
  30. /// (ancestor) name against each new name to be rendered into the buffer.
  31. struct NameCompressNode {
  32. NameCompressNode(const MessageRenderer& renderer,
  33. const OutputBuffer& buffer, const size_t pos,
  34. const size_t len) :
  35. renderer_(renderer), buffer_(buffer), pos_(pos), len_(len) {}
  36. /// The renderer that performs name compression using the node.
  37. /// This is kept in each node to detect the compression mode
  38. /// (case-sensitive or not) in the comparison functor (\c NameCompare).
  39. const MessageRenderer& renderer_;
  40. /// The buffer in which the corresponding name is rendered.
  41. const OutputBuffer& buffer_;
  42. /// The position (offset from the beginning) in the buffer where the
  43. /// name starts.
  44. uint16_t pos_;
  45. /// The length of the corresponding name.
  46. uint16_t len_;
  47. };
  48. ///
  49. /// \brief The \c NameCompare class is a functor that gives ordering among
  50. /// \c NameCompressNode objects stored in \c MessageRendererImpl::nodeset_.
  51. ///
  52. /// Its only public method as a functor, \c operator(), gives the ordering
  53. /// between two \c NameCompressNode objects in terms of equivalence, that is,
  54. /// returns whether one is "less than" the other.
  55. /// For our purpose we only need to distinguish two different names, so the
  56. /// ordering is different from the canonical DNS name order used in DNSSEC;
  57. /// basically, it gives the case-insensitive ordering of the two names as their
  58. /// textual representation.
  59. struct NameCompare : public std::binary_function<NameCompressNode,
  60. NameCompressNode,
  61. bool> {
  62. ///
  63. /// Returns true if n1 < n2 as a result of case-insensitive comparison;
  64. /// otherwise return false.
  65. ///
  66. /// The name corresponding to \c n1 or \c n2 may be compressed, in which
  67. /// case we must follow the compression pointer in the associated buffer.
  68. /// The helper private method \c nextPosition() gives the position in the
  69. /// buffer for the next character, taking into account compression.
  70. ///
  71. bool operator()(const NameCompressNode& n1,
  72. const NameCompressNode& n2) const
  73. {
  74. if (n1.len_ < n2.len_) {
  75. return (true);
  76. } else if (n1.len_ > n2.len_) {
  77. return (false);
  78. }
  79. const bool case_sensitive =
  80. (n1.renderer_.getCompressMode() == MessageRenderer::CASE_SENSITIVE);
  81. uint16_t pos1 = n1.pos_;
  82. uint16_t pos2 = n2.pos_;
  83. uint16_t l1 = 0;
  84. uint16_t l2 = 0;
  85. for (uint16_t i = 0; i < n1.len_; i++, pos1++, pos2++) {
  86. pos1 = nextPosition(n1.buffer_, pos1, l1);
  87. pos2 = nextPosition(n2.buffer_, pos2, l2);
  88. if (case_sensitive) {
  89. if (n1.buffer_[pos1] < n2.buffer_[pos2]) {
  90. return (true);
  91. } else if (n1.buffer_[pos1] > n2.buffer_[pos2]) {
  92. return (false);
  93. }
  94. } else {
  95. if (tolower(n1.buffer_[pos1]) < tolower(n2.buffer_[pos2])) {
  96. return (true);
  97. } else if (tolower(n1.buffer_[pos1]) >
  98. tolower(n2.buffer_[pos2])) {
  99. return (false);
  100. }
  101. }
  102. }
  103. return (false);
  104. }
  105. private:
  106. uint16_t nextPosition(const OutputBuffer& buffer,
  107. uint16_t pos, uint16_t& llen) const
  108. {
  109. if (llen == 0) {
  110. int i = 0;
  111. while ((buffer[pos] & Name::COMPRESS_POINTER_MARK8) ==
  112. Name::COMPRESS_POINTER_MARK8) {
  113. pos = (buffer[pos] & ~Name::COMPRESS_POINTER_MARK8) *
  114. 256 + buffer[pos + 1];
  115. // This loop should stop as long as the buffer has been
  116. // constructed validly and the search/insert argument is based
  117. // on a valid name, which is an assumption for this class.
  118. // But we'll abort if a bug could cause an infinite loop.
  119. i += 2;
  120. assert(i < Name::MAX_WIRE);
  121. }
  122. llen = buffer[pos];
  123. } else {
  124. --llen;
  125. }
  126. return (pos);
  127. }
  128. };
  129. }
  130. ///
  131. /// \brief The \c MessageRendererImpl class is the actual implementation of
  132. /// \c MessageRenderer.
  133. ///
  134. /// The implementation is hidden from applications. We can refer to specific
  135. /// members of this class only within the implementation source file.
  136. ///
  137. struct MessageRenderer::MessageRendererImpl {
  138. /// \brief Constructor from an output buffer.
  139. ///
  140. /// \param buffer An \c OutputBuffer object to which wire format data is
  141. /// written.
  142. MessageRendererImpl(OutputBuffer& buffer) :
  143. buffer_(buffer), nbuffer_(Name::MAX_WIRE), msglength_limit_(512),
  144. truncated_(false), compress_mode_(MessageRenderer::CASE_INSENSITIVE)
  145. {}
  146. /// The buffer that holds the entire DNS message.
  147. OutputBuffer& buffer_;
  148. /// A local working buffer to convert each given name into wire format.
  149. /// This could be a local variable of the \c writeName() method, but
  150. /// we keep it in the class so that we can reuse it and avoid construction
  151. /// overhead.
  152. OutputBuffer nbuffer_;
  153. /// A set of compression pointers.
  154. std::set<NameCompressNode, NameCompare> nodeset_;
  155. /// The maximum length of rendered data that can fit without
  156. /// truncation.
  157. uint16_t msglength_limit_;
  158. /// A boolean flag that indicates truncation has occurred while rendering
  159. /// the data.
  160. bool truncated_;
  161. /// The name compression mode.
  162. CompressMode compress_mode_;
  163. };
  164. MessageRenderer::MessageRenderer(OutputBuffer& buffer) :
  165. impl_(new MessageRendererImpl(buffer))
  166. {}
  167. MessageRenderer::~MessageRenderer() {
  168. delete impl_;
  169. }
  170. void
  171. MessageRenderer::skip(const size_t len) {
  172. impl_->buffer_.skip(len);
  173. }
  174. void
  175. MessageRenderer::trim(const size_t len) {
  176. impl_->buffer_.trim(len);
  177. }
  178. void
  179. MessageRenderer::clear() {
  180. impl_->buffer_.clear();
  181. impl_->nbuffer_.clear();
  182. impl_->nodeset_.clear();
  183. impl_->msglength_limit_ = 512;
  184. impl_->truncated_ = false;
  185. impl_->compress_mode_ = CASE_INSENSITIVE;
  186. }
  187. void
  188. MessageRenderer::writeUint8(const uint8_t data) {
  189. impl_->buffer_.writeUint8(data);
  190. }
  191. void
  192. MessageRenderer::writeUint16(const uint16_t data) {
  193. impl_->buffer_.writeUint16(data);
  194. }
  195. void
  196. MessageRenderer::writeUint16At(const uint16_t data, const size_t pos) {
  197. impl_->buffer_.writeUint16At(data, pos);
  198. }
  199. void
  200. MessageRenderer::writeUint32(const uint32_t data) {
  201. impl_->buffer_.writeUint32(data);
  202. }
  203. void
  204. MessageRenderer::writeData(const void* const data, const size_t len) {
  205. impl_->buffer_.writeData(data, len);
  206. }
  207. const void*
  208. MessageRenderer::getData() const {
  209. return (impl_->buffer_.getData());
  210. }
  211. size_t
  212. MessageRenderer::getLength() const {
  213. return (impl_->buffer_.getLength());
  214. }
  215. size_t
  216. MessageRenderer::getLengthLimit() const {
  217. return (impl_->msglength_limit_);
  218. }
  219. void
  220. MessageRenderer::setLengthLimit(const size_t len) {
  221. impl_->msglength_limit_ = len;
  222. }
  223. bool
  224. MessageRenderer::isTruncated() const {
  225. return (impl_->truncated_);
  226. }
  227. void
  228. MessageRenderer::setTruncated() {
  229. impl_->truncated_ = true;
  230. }
  231. MessageRenderer::CompressMode
  232. MessageRenderer::getCompressMode() const {
  233. return (impl_->compress_mode_);
  234. }
  235. void
  236. MessageRenderer::setCompressMode(const CompressMode mode) {
  237. impl_->compress_mode_ = mode;
  238. }
  239. void
  240. MessageRenderer::writeName(const Name& name, const bool compress) {
  241. impl_->nbuffer_.clear();
  242. name.toWire(impl_->nbuffer_);
  243. unsigned int i;
  244. std::set<NameCompressNode>::const_iterator notfound = impl_->nodeset_.end();
  245. std::set<NameCompressNode>::const_iterator n = notfound;
  246. // Find the longest ancestor name in the rendered set that matches the
  247. // given name.
  248. for (i = 0; i < impl_->nbuffer_.getLength(); i += impl_->nbuffer_[i] + 1) {
  249. // skip the trailing null label
  250. if (impl_->nbuffer_[i] == 0) {
  251. continue;
  252. }
  253. n = impl_->nodeset_.find(NameCompressNode(*this, impl_->nbuffer_, i,
  254. impl_->nbuffer_.getLength() -
  255. i));
  256. if (n != notfound) {
  257. break;
  258. }
  259. }
  260. // Record the current offset before extending the buffer.
  261. const size_t offset = impl_->buffer_.getLength();
  262. // Write uncompress part...
  263. impl_->buffer_.writeData(impl_->nbuffer_.getData(),
  264. compress ? i : impl_->nbuffer_.getLength());
  265. if (compress && n != notfound) {
  266. // ...and compression pointer if available.
  267. uint16_t pointer = (*n).pos_;
  268. pointer |= Name::COMPRESS_POINTER_MARK16;
  269. impl_->buffer_.writeUint16(pointer);
  270. }
  271. // Finally, add to the set the newly rendered name and its ancestors that
  272. // have not been in the set.
  273. for (unsigned int j = 0; j < i; j += impl_->nbuffer_[j] + 1) {
  274. if (impl_->nbuffer_[j] == 0) {
  275. continue;
  276. }
  277. if (offset + j > Name::MAX_COMPRESS_POINTER) {
  278. break;
  279. }
  280. impl_->nodeset_.insert(NameCompressNode(*this, impl_->buffer_,
  281. offset + j,
  282. impl_->nbuffer_.getLength() -
  283. j));
  284. }
  285. }
  286. }
  287. }