labelsequence.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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. LabelSequence::LabelSequence(const uint8_t* data,
  22. const uint8_t* offsets,
  23. size_t offsets_size) : data_(data),
  24. offsets_(offsets),
  25. offsets_size_(offsets_size),
  26. first_label_(0),
  27. last_label_(offsets_size_)
  28. {
  29. if (data == NULL || offsets == NULL) {
  30. isc_throw(BadValue, "Null pointer passed to LabelSequence constructor");
  31. }
  32. if (offsets_size == 0) {
  33. isc_throw(BadValue, "Zero offsets to LabelSequence constructor");
  34. }
  35. if (offsets_size > Name::MAX_LABELS) {
  36. isc_throw(BadValue, "MAX_LABELS exceeded");
  37. }
  38. for (size_t cur_offset = 0; cur_offset < offsets_size; ++cur_offset) {
  39. if (offsets[cur_offset] > Name::MAX_LABELLEN) {
  40. isc_throw(BadValue, "MAX_LABEL_LEN exceeded");
  41. }
  42. if (cur_offset > 0 && offsets[cur_offset] <= offsets[cur_offset - 1]) {
  43. isc_throw(BadValue, "Offset smaller than previous offset");
  44. }
  45. }
  46. }
  47. const uint8_t*
  48. LabelSequence::getData(size_t *len) const {
  49. *len = getDataLength();
  50. return (&data_[offsets_[first_label_]]);
  51. }
  52. void
  53. LabelSequence::getOffsetData(size_t* len,
  54. uint8_t placeholder[Name::MAX_LABELS]) const {
  55. *len = last_label_ - first_label_;
  56. for (size_t i = 0; i < *len; i++) {
  57. placeholder[i] = offsets_[first_label_ + i] - offsets_[first_label_];
  58. }
  59. }
  60. size_t
  61. LabelSequence::getDataLength() const {
  62. // If the labelsequence is absolute, the current last_label_ falls
  63. // out of the vector (since it points to the 'label' after the
  64. // root label, which doesn't exist; in that case, return
  65. // the length for the 'previous' label (the root label) plus
  66. // one (for the root label zero octet)
  67. if (isAbsolute()) {
  68. return (offsets_[last_label_ - 1] -
  69. offsets_[first_label_] + 1);
  70. } else {
  71. return (offsets_[last_label_] - offsets_[first_label_]);
  72. }
  73. }
  74. bool
  75. LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
  76. size_t len, other_len;
  77. const uint8_t* data = getData(&len);
  78. const uint8_t* other_data = other.getData(&other_len);
  79. if (len != other_len) {
  80. return (false);
  81. }
  82. if (case_sensitive) {
  83. return (std::memcmp(data, other_data, len) == 0);
  84. }
  85. // As long as the data was originally validated as (part of) a name,
  86. // label length must never be a capital ascii character, so we can
  87. // simply compare them after converting to lower characters.
  88. for (size_t i = 0; i < len; ++i) {
  89. const uint8_t ch = data[i];
  90. const uint8_t other_ch = other_data[i];
  91. if (isc::dns::name::internal::maptolower[ch] !=
  92. isc::dns::name::internal::maptolower[other_ch]) {
  93. return (false);
  94. }
  95. }
  96. return (true);
  97. }
  98. NameComparisonResult
  99. LabelSequence::compare(const LabelSequence& other,
  100. bool case_sensitive) const
  101. {
  102. // Determine the relative ordering under the DNSSEC order relation of
  103. // 'this' and 'other', and also determine the hierarchical relationship
  104. // of the labels.
  105. unsigned int nlabels = 0;
  106. int l1 = last_label_ - first_label_;
  107. int l2 = other.last_label_ - other.first_label_;
  108. const int ldiff = static_cast<int>(l1) - static_cast<int>(l2);
  109. unsigned int l = (ldiff < 0) ? l1 : l2;
  110. while (l > 0) {
  111. --l;
  112. --l1;
  113. --l2;
  114. size_t pos1 = offsets_[l1 + first_label_];
  115. size_t pos2 = other.offsets_[l2 + other.first_label_];
  116. unsigned int count1 = data_[pos1++];
  117. unsigned int count2 = other.data_[pos2++];
  118. // We don't support any extended label types including now-obsolete
  119. // bitstring labels.
  120. assert(count1 <= Name::MAX_LABELLEN && count2 <= Name::MAX_LABELLEN);
  121. const int cdiff = static_cast<int>(count1) - static_cast<int>(count2);
  122. unsigned int count = (cdiff < 0) ? count1 : count2;
  123. while (count > 0) {
  124. const uint8_t label1 = data_[pos1];
  125. const uint8_t label2 = other.data_[pos2];
  126. int chdiff;
  127. if (case_sensitive) {
  128. chdiff = static_cast<int>(label1) - static_cast<int>(label2);
  129. } else {
  130. chdiff = static_cast<int>(
  131. isc::dns::name::internal::maptolower[label1]) -
  132. static_cast<int>(
  133. isc::dns::name::internal::maptolower[label2]);
  134. }
  135. if (chdiff != 0) {
  136. return (NameComparisonResult(
  137. chdiff, nlabels,
  138. nlabels == 0 ? NameComparisonResult::NONE :
  139. NameComparisonResult::COMMONANCESTOR));
  140. }
  141. --count;
  142. ++pos1;
  143. ++pos2;
  144. }
  145. if (cdiff != 0) {
  146. return (NameComparisonResult(
  147. cdiff, nlabels,
  148. nlabels == 0 ? NameComparisonResult::NONE :
  149. NameComparisonResult::COMMONANCESTOR));
  150. }
  151. ++nlabels;
  152. }
  153. if (ldiff < 0) {
  154. return (NameComparisonResult(ldiff, nlabels,
  155. NameComparisonResult::SUPERDOMAIN));
  156. } else if (ldiff > 0) {
  157. return (NameComparisonResult(ldiff, nlabels,
  158. NameComparisonResult::SUBDOMAIN));
  159. }
  160. return (NameComparisonResult(ldiff, nlabels, NameComparisonResult::EQUAL));
  161. }
  162. void
  163. LabelSequence::stripLeft(size_t i) {
  164. if (i >= getLabelCount()) {
  165. isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
  166. " (labelcount: " << getLabelCount() << ")");
  167. }
  168. first_label_ += i;
  169. }
  170. void
  171. LabelSequence::stripRight(size_t i) {
  172. if (i >= getLabelCount()) {
  173. isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
  174. " (labelcount: " << getLabelCount() << ")");
  175. }
  176. last_label_ -= i;
  177. }
  178. bool
  179. LabelSequence::isAbsolute() const {
  180. return (last_label_ == offsets_size_);
  181. }
  182. size_t
  183. LabelSequence::getHash(bool case_sensitive) const {
  184. size_t length;
  185. const uint8_t* s = getData(&length);
  186. if (length > 16) {
  187. length = 16;
  188. }
  189. size_t hash_val = 0;
  190. while (length > 0) {
  191. const uint8_t c = *s++;
  192. boost::hash_combine(hash_val, case_sensitive ? c :
  193. isc::dns::name::internal::maptolower[c]);
  194. --length;
  195. }
  196. return (hash_val);
  197. }
  198. std::string
  199. LabelSequence::toText(bool omit_final_dot) const {
  200. const uint8_t* np = &data_[offsets_[first_label_]];
  201. const uint8_t* np_end = np + getDataLength();
  202. // use for integrity check
  203. unsigned int labels = last_label_ - first_label_;
  204. // init with an impossible value to catch error cases in the end:
  205. unsigned int count = Name::MAX_LABELLEN + 1;
  206. // result string: it will roughly have the same length as the wire format
  207. // label sequence data. reserve that length to minimize reallocation.
  208. std::string result;
  209. result.reserve(getDataLength());
  210. while (np != np_end) {
  211. labels--;
  212. count = *np++;
  213. if (count == 0) {
  214. // We've reached the "final dot". If we've not dumped any
  215. // character, the entire label sequence is the root name.
  216. // In that case we don't omit the final dot.
  217. if (!omit_final_dot || result.empty()) {
  218. result.push_back('.');
  219. }
  220. break;
  221. }
  222. if (count <= Name::MAX_LABELLEN) {
  223. assert(np_end - np >= count);
  224. if (!result.empty()) {
  225. // just after a non-empty label. add a separating dot.
  226. result.push_back('.');
  227. }
  228. while (count-- > 0) {
  229. const uint8_t c = *np++;
  230. switch (c) {
  231. case 0x22: // '"'
  232. case 0x28: // '('
  233. case 0x29: // ')'
  234. case 0x2E: // '.'
  235. case 0x3B: // ';'
  236. case 0x5C: // '\\'
  237. // Special modifiers in zone files.
  238. case 0x40: // '@'
  239. case 0x24: // '$'
  240. result.push_back('\\');
  241. result.push_back(c);
  242. break;
  243. default:
  244. if (c > 0x20 && c < 0x7f) {
  245. // append printable characters intact
  246. result.push_back(c);
  247. } else {
  248. // encode non-printable characters in the form of \DDD
  249. result.push_back(0x5c);
  250. result.push_back(0x30 + ((c / 100) % 10));
  251. result.push_back(0x30 + ((c / 10) % 10));
  252. result.push_back(0x30 + (c % 10));
  253. }
  254. }
  255. }
  256. } else {
  257. isc_throw(BadLabelType, "unknown label type in name data");
  258. }
  259. }
  260. // We should be at the end of the data and have consumed all labels.
  261. assert(np == np_end);
  262. assert(labels == 0);
  263. return (result);
  264. }
  265. std::string
  266. LabelSequence::toText() const {
  267. return (toText(!isAbsolute()));
  268. }
  269. std::ostream&
  270. operator<<(std::ostream& os, const LabelSequence& label_sequence) {
  271. os << label_sequence.toText();
  272. return (os);
  273. }
  274. } // end namespace dns
  275. } // end namespace isc