labelsequence.cc 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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 <dns/labelsequence.h>
  15. #include <dns/name_internal.h>
  16. #include <exceptions/exceptions.h>
  17. #include <boost/functional/hash.hpp>
  18. #include <cstring>
  19. namespace isc {
  20. namespace dns {
  21. const uint8_t*
  22. LabelSequence::getData(size_t *len) const {
  23. *len = getDataLength();
  24. return (&name_.ndata_[name_.offsets_[first_label_]]);
  25. }
  26. size_t
  27. LabelSequence::getDataLength() const {
  28. // If the labelsequence is absolute, the current last_label_ falls
  29. // out of the vector (since it points to the 'label' after the
  30. // root label, which doesn't exist; in that case, return
  31. // the length for the 'previous' label (the root label) plus
  32. // one (for the root label zero octet)
  33. if (isAbsolute()) {
  34. return (name_.offsets_[last_label_ - 1] -
  35. name_.offsets_[first_label_] + 1);
  36. } else {
  37. return (name_.offsets_[last_label_] - name_.offsets_[first_label_]);
  38. }
  39. }
  40. bool
  41. LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
  42. size_t len, other_len;
  43. const uint8_t* data = getData(&len);
  44. const uint8_t* other_data = other.getData(&other_len);
  45. if (len != other_len) {
  46. return (false);
  47. }
  48. if (case_sensitive) {
  49. return (std::memcmp(data, other_data, len) == 0);
  50. }
  51. // As long as the data was originally validated as (part of) a name,
  52. // label length must never be a capital ascii character, so we can
  53. // simply compare them after converting to lower characters.
  54. for (size_t i = 0; i < len; ++i) {
  55. const uint8_t ch = data[i];
  56. const uint8_t other_ch = other_data[i];
  57. if (isc::dns::name::internal::maptolower[ch] !=
  58. isc::dns::name::internal::maptolower[other_ch]) {
  59. return (false);
  60. }
  61. }
  62. return (true);
  63. }
  64. void
  65. LabelSequence::stripLeft(size_t i) {
  66. if (i >= getLabelCount()) {
  67. isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
  68. " (labelcount: " << getLabelCount() << ")");
  69. }
  70. first_label_ += i;
  71. }
  72. void
  73. LabelSequence::stripRight(size_t i) {
  74. if (i >= getLabelCount()) {
  75. isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
  76. " (labelcount: " << getLabelCount() << ")");
  77. }
  78. last_label_ -= i;
  79. }
  80. bool
  81. LabelSequence::isAbsolute() const {
  82. return (last_label_ == name_.offsets_.size());
  83. }
  84. size_t
  85. LabelSequence::getHash(bool case_sensitive) const {
  86. size_t length;
  87. const uint8_t* s = getData(&length);
  88. if (length > 16) {
  89. length = 16;
  90. }
  91. size_t hash_val = 0;
  92. while (length > 0) {
  93. const uint8_t c = *s++;
  94. boost::hash_combine(hash_val, case_sensitive ? c :
  95. isc::dns::name::internal::maptolower[c]);
  96. --length;
  97. }
  98. return (hash_val);
  99. }
  100. std::string
  101. LabelSequence::toText(bool omit_final_dot) const {
  102. Name::NameString::const_iterator np = name_.ndata_.begin() +
  103. name_.offsets_[first_label_];
  104. const Name::NameString::const_iterator np_end = np + getDataLength();
  105. // use for integrity check
  106. unsigned int labels = last_label_ - first_label_;
  107. // init with an impossible value to catch error cases in the end:
  108. unsigned int count = Name::MAX_LABELLEN + 1;
  109. // result string: it will roughly have the same length as the wire format
  110. // label sequence data. reserve that length to minimize reallocation.
  111. std::string result;
  112. result.reserve(getDataLength());
  113. while (np != np_end) {
  114. labels--;
  115. count = *np++;
  116. if (count == 0) {
  117. // We've reached the "final dot". If we've not dumped any
  118. // character, the entire label sequence is the root name.
  119. // In that case we don't omit the final dot.
  120. if (!omit_final_dot || result.empty()) {
  121. result.push_back('.');
  122. }
  123. break;
  124. }
  125. if (count <= Name::MAX_LABELLEN) {
  126. assert(np_end - np >= count);
  127. if (!result.empty()) {
  128. // just after a non-empty label. add a separating dot.
  129. result.push_back('.');
  130. }
  131. while (count-- > 0) {
  132. const uint8_t c = *np++;
  133. switch (c) {
  134. case 0x22: // '"'
  135. case 0x28: // '('
  136. case 0x29: // ')'
  137. case 0x2E: // '.'
  138. case 0x3B: // ';'
  139. case 0x5C: // '\\'
  140. // Special modifiers in zone files.
  141. case 0x40: // '@'
  142. case 0x24: // '$'
  143. result.push_back('\\');
  144. result.push_back(c);
  145. break;
  146. default:
  147. if (c > 0x20 && c < 0x7f) {
  148. // append printable characters intact
  149. result.push_back(c);
  150. } else {
  151. // encode non-printable characters in the form of \DDD
  152. result.push_back(0x5c);
  153. result.push_back(0x30 + ((c / 100) % 10));
  154. result.push_back(0x30 + ((c / 10) % 10));
  155. result.push_back(0x30 + (c % 10));
  156. }
  157. }
  158. }
  159. } else {
  160. isc_throw(BadLabelType, "unknown label type in name data");
  161. }
  162. }
  163. // We should be at the end of the data and have consumed all labels.
  164. assert(np == np_end);
  165. assert(labels == 0);
  166. return (result);
  167. }
  168. std::string
  169. LabelSequence::toText() const {
  170. return (toText(!isAbsolute()));
  171. }
  172. std::ostream&
  173. operator<<(std::ostream& os, const LabelSequence& label_sequence) {
  174. os << label_sequence.toText();
  175. return (os);
  176. }
  177. } // end namespace dns
  178. } // end namespace isc