Kea  1.9.9-git
name.cc
Go to the documentation of this file.
1 // Copyright (C) 2009-2019 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <cctype>
10 #include <iterator>
11 #include <functional>
12 #include <vector>
13 #include <iostream>
14 #include <algorithm>
15 
16 #include <exceptions/isc_assert.h>
17 #include <util/buffer.h>
18 #include <dns/exceptions.h>
19 #include <dns/name.h>
20 #include <dns/name_internal.h>
21 #include <dns/messagerenderer.h>
22 #include <dns/labelsequence.h>
23 
24 using namespace std;
25 using namespace isc::util;
27 using namespace isc::dns::name::internal;
28 
29 namespace isc {
30 namespace dns {
31 
32 namespace {
51 const signed char digitvalue[256] = {
52  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
53  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
54  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 48
55  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 64
56  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
57  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
58  -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 112
59  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128
60  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
61  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
65  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
66  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
67  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 256
68 };
69 }
70 
71 namespace name {
72 namespace internal {
73 const uint8_t maptolower[] = {
74  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
75  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
76  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
77  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
78  0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
79  0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
80  0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
81  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
82  0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, // ..., 'A' - 'G'
83  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, // 'H' - 'O'
84  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // 'P' - 'W'
85  0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, // 'X' - 'Z', ...
86  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
87  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
88  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
89  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
90  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
91  0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
92  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
93  0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
94  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
95  0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
96  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
97  0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
98  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
99  0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
100  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
101  0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
102  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
103  0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
104  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
105  0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
106 };
107 } // end of internal
108 } // end of name
109 
110 namespace {
114 typedef enum {
115  ft_init = 0, // begin of the name
116  ft_start, // begin of a label
117  ft_ordinary, // parsing an ordinary label
118  ft_initialescape, // just found '\'
119  ft_escape, // begin of handling a '\'-escaped sequence
120  ft_escdecimal // parsing a '\DDD' octet.
121 } ft_state;
122 
123 // The parser of name from a string. It is a template, because
124 // some parameters are used with two different types, while others
125 // are private type aliases.
126 template<class Iterator, class Offsets, class Data>
127 void
128 stringParse(Iterator s, Iterator send, bool downcase, Offsets& offsets,
129  Data& ndata)
130 {
131  const Iterator orig_s(s);
132  //
133  // Initialize things to make the compiler happy; they're not required.
134  //
135  unsigned int digits = 0;
136  unsigned int value = 0;
137  unsigned int count = 0;
138 
139  //
140  // Set up the state machine.
141  //
142  bool done = false;
143  bool is_root = false;
144  const bool empty = s == send;
145  ft_state state = ft_init;
146 
147  // Prepare the output buffers.
148  offsets.reserve(Name::MAX_LABELS);
149  offsets.push_back(0);
150  ndata.reserve(Name::MAX_WIRE);
151 
152  // should we refactor this code using, e.g, the state pattern? Probably
153  // not at this point, as this is based on proved code (derived from BIND9)
154  // and it's less likely that we'll have more variations in the domain name
155  // syntax. If this ever happens next time, we should consider refactor
156  // the code, rather than adding more states and cases below.
157  while (ndata.size() < Name::MAX_WIRE && s != send && !done) {
158  unsigned char c = *s++;
159 
160  switch (state) {
161  case ft_init:
162  //
163  // Is this the root name?
164  //
165  if (c == '.') {
166  if (s != send) {
167  isc_throw(EmptyLabel,
168  "non terminating empty label in " <<
169  string(orig_s, send));
170  }
171  is_root = true;
172  } else if (c == '@' && s == send) {
173  // handle a single '@' as the root name.
174  is_root = true;
175  }
176 
177  if (is_root) {
178  ndata.push_back(0);
179  done = true;
180  break;
181  }
182 
183  // FALLTHROUGH
184  case ft_start:
185  ndata.push_back(0); // placeholder for the label length field
186  count = 0;
187  if (c == '\\') {
188  state = ft_initialescape;
189  break;
190  }
191  state = ft_ordinary;
192  isc_throw_assert(ndata.size() < Name::MAX_WIRE);
193  // FALLTHROUGH
194  case ft_ordinary:
195  if (c == '.') {
196  if (count == 0) {
197  isc_throw(EmptyLabel,
198  "duplicate period in " << string(orig_s, send));
199  }
200  ndata.at(offsets.back()) = count;
201  offsets.push_back(ndata.size());
202  if (s == send) {
203  ndata.push_back(0);
204  done = true;
205  }
206  state = ft_start;
207  } else if (c == '\\') {
208  state = ft_escape;
209  } else {
210  if (++count > Name::MAX_LABELLEN) {
211  isc_throw(TooLongLabel,
212  "label is too long in " << string(orig_s, send));
213  }
214  ndata.push_back(downcase ? maptolower[c] : c);
215  }
216  break;
217  case ft_initialescape:
218  if (c == '[') {
219  // This looks like a bitstring label, which was deprecated.
220  // Intentionally drop it.
221  isc_throw(BadLabelType,
222  "invalid label type in " << string(orig_s, send));
223  }
224  // FALLTHROUGH
225  case ft_escape:
226  if (!isdigit(c & 0xff)) {
227  if (++count > Name::MAX_LABELLEN) {
228  isc_throw(TooLongLabel,
229  "label is too long in " << string(orig_s, send));
230  }
231  ndata.push_back(downcase ? maptolower[c] : c);
232  state = ft_ordinary;
233  break;
234  }
235  digits = 0;
236  value = 0;
237  state = ft_escdecimal;
238  // FALLTHROUGH
239  case ft_escdecimal:
240  if (!isdigit(c & 0xff)) {
241  isc_throw(BadEscape,
242  "mixture of escaped digit and non-digit in "
243  << string(orig_s, send));
244  }
245  value *= 10;
246  value += digitvalue[c];
247  digits++;
248  if (digits == 3) {
249  if (value > 255) {
250  isc_throw(BadEscape,
251  "escaped decimal is too large in "
252  << string(orig_s, send));
253  }
254  if (++count > Name::MAX_LABELLEN) {
255  isc_throw(TooLongLabel,
256  "label is too long in " << string(orig_s, send));
257  }
258  ndata.push_back(downcase ? maptolower[value] : value);
259  state = ft_ordinary;
260  }
261  break;
262  default:
263  // impossible case
264  isc_throw_assert(false);
265  }
266  }
267 
268  if (!done) { // no trailing '.' was found.
269  if (ndata.size() == Name::MAX_WIRE) {
270  isc_throw(TooLongName,
271  "name is too long for termination in " <<
272  string(orig_s, send));
273  }
274  isc_throw_assert(s == send);
275  if (state != ft_ordinary) {
276  isc_throw(IncompleteName,
277  "incomplete textual name in " <<
278  (empty ? "<empty>" : string(orig_s, send)));
279  }
280  if (state == ft_ordinary) {
281  isc_throw_assert(count != 0);
282  ndata.at(offsets.back()) = count;
283 
284  offsets.push_back(ndata.size());
285  // add a trailing \0
286  ndata.push_back('\0');
287  }
288  }
289 }
290 
291 }
292 
293 Name::Name(const std::string &namestring, bool downcase) {
294  // Prepare inputs for the parser
295  const std::string::const_iterator s = namestring.begin();
296  const std::string::const_iterator send = namestring.end();
297 
298  // Prepare outputs
299  NameOffsets offsets;
300  NameString ndata;
301 
302  // To the parsing
303  stringParse(s, send, downcase, offsets, ndata);
304 
305  // And get the output
306  labelcount_ = offsets.size();
307  isc_throw_assert(labelcount_ > 0 && labelcount_ <= Name::MAX_LABELS);
308  ndata_.assign(ndata.data(), ndata.size());
309  length_ = ndata_.size();
310  offsets_.assign(offsets.begin(), offsets.end());
311 }
312 
313 Name::Name(const char* namedata, size_t data_len, const Name* origin,
314  bool downcase)
315 {
316  // Check validity of data
317  if (namedata == NULL || data_len == 0) {
319  "No data provided to Name constructor");
320  }
321  // If the last character is not a dot, it is a relative to origin.
322  // It is safe to check now, we know there's at least one character.
323  const bool absolute = (namedata[data_len - 1] == '.');
324  // If we are not absolute, we need the origin to complete the name.
325  if (!absolute && origin == NULL) {
327  "No origin available and name is relative");
328  }
329  // Prepare inputs for the parser
330  const char* end = namedata + data_len;
331 
332  // Prepare outputs
333  NameOffsets offsets;
334  NameString ndata;
335 
336  // Do the actual parsing
337  stringParse(namedata, end, downcase, offsets, ndata);
338 
339  // Get the output
340  labelcount_ = offsets.size();
341  isc_throw_assert(labelcount_ > 0 && labelcount_ <= Name::MAX_LABELS);
342  ndata_.assign(ndata.data(), ndata.size());
343  length_ = ndata_.size();
344  offsets_.assign(offsets.begin(), offsets.end());
345 
346  if (!absolute) {
347  // Now, extend the data with the ones from origin. But eat the
348  // last label (the empty one).
349 
350  // Drop the last character of the data (the \0) and append a copy of
351  // the origin's data
352  ndata_.erase(ndata_.end() - 1);
353  ndata_.append(origin->ndata_);
354 
355  // Do a similar thing with offsets. However, we need to move them
356  // so they point after the prefix we parsed before.
357  size_t offset = offsets_.back();
358  offsets_.pop_back();
359  size_t offset_count = offsets_.size();
360  offsets_.insert(offsets_.end(), origin->offsets_.begin(),
361  origin->offsets_.end());
362  for (NameOffsets::iterator it(offsets_.begin() + offset_count);
363  it != offsets_.end(); ++it) {
364  *it += offset;
365  }
366 
367  // Adjust sizes.
368  length_ = ndata_.size();
369  labelcount_ = offsets_.size();
370 
371  // And check the sizes are OK.
372  if (labelcount_ > Name::MAX_LABELS || length_ > Name::MAX_WIRE) {
373  isc_throw(TooLongName, "Combined name is too long");
374  }
375  }
376 }
377 
378 namespace {
382 typedef enum {
383  fw_start = 0, // beginning of a label
384  fw_ordinary, // inside an ordinary (non compressed) label
385  fw_newcurrent // beginning of a compression pointer
386 } fw_state;
387 }
388 
389 Name::Name(InputBuffer& buffer, bool downcase) {
390  NameOffsets offsets;
391  offsets.reserve(Name::MAX_LABELS);
392 
393  /*
394  * Initialize things to make the compiler happy; they're not required.
395  */
396  unsigned int n = 0;
397 
398  //
399  // Set up.
400  //
401  bool done = false;
402  unsigned int nused = 0;
403  bool seen_pointer = false;
404  fw_state state = fw_start;
405 
406  unsigned int cused = 0; // Bytes of compressed name data used
407  unsigned int current = buffer.getPosition();
408  unsigned int pos_begin = current;
409  unsigned int biggest_pointer = current;
410 
411  // Make the compiler happy; this is not required.
412  // XXX: bad style in that we initialize it with a dummy value and define
413  // it far from where it's used. But alternatives seemed even worse.
414  unsigned int new_current = 0;
415 
416  //
417  // Note: The following code is not optimized for speed, but
418  // rather for correctness. Speed will be addressed in the future.
419  //
420  while (current < buffer.getLength() && !done) {
421  unsigned int c = buffer.readUint8();
422  current++;
423  if (!seen_pointer) {
424  cused++;
425  }
426 
427  switch (state) {
428  case fw_start:
429  if (c <= MAX_LABELLEN) {
430  offsets.push_back(nused);
431  if (nused + c + 1 > Name::MAX_WIRE) {
432  isc_throw(DNSMessageFORMERR, "wire name is too long: "
433  << nused + c + 1 << " bytes");
434  }
435  nused += c + 1;
436  ndata_.push_back(c);
437  if (c == 0) {
438  done = true;
439  }
440  n = c;
441  state = fw_ordinary;
442  } else if ((c & COMPRESS_POINTER_MARK8) == COMPRESS_POINTER_MARK8) {
443  //
444  // Ordinary 14-bit pointer.
445  //
446  new_current = c & ~COMPRESS_POINTER_MARK8;
447  n = 1;
448  state = fw_newcurrent;
449  } else {
450  // this case includes local compression pointer, which hasn't
451  // been standardized.
452  isc_throw(DNSMessageFORMERR, "unknown label character: " << c);
453  }
454  break;
455  case fw_ordinary:
456  if (downcase) {
457  c = maptolower[c];
458  }
459  ndata_.push_back(c);
460  if (--n == 0) {
461  state = fw_start;
462  }
463  break;
464  case fw_newcurrent:
465  new_current *= 256;
466  new_current += c;
467  if (--n != 0) {
468  break;
469  }
470  if (new_current >= biggest_pointer) {
472  "bad compression pointer (out of range): " <<
473  new_current);
474  }
475  biggest_pointer = new_current;
476  current = new_current;
477  buffer.setPosition(current);
478  seen_pointer = true;
479  state = fw_start;
480  break;
481  default:
482  isc_throw_assert(false);
483  }
484  }
485 
486  if (!done) {
487  isc_throw(DNSMessageFORMERR, "incomplete wire-format name");
488  }
489 
490  labelcount_ = offsets.size();
491  length_ = nused;
492  offsets_.assign(offsets.begin(), offsets.end());
493  buffer.setPosition(pos_begin + cused);
494 }
495 
496 void
497 Name::toWire(OutputBuffer& buffer) const {
498  buffer.writeData(ndata_.data(), ndata_.size());
499 }
500 
501 void
502 Name::toWire(AbstractMessageRenderer& renderer) const {
503  renderer.writeName(*this);
504 }
505 
506 std::string
507 Name::toText(bool omit_final_dot) const {
508  LabelSequence ls(*this);
509  return (ls.toText(omit_final_dot));
510 }
511 
512 std::string
513 Name::toRawText(bool omit_final_dot) const {
514  LabelSequence ls(*this);
515  return (ls.toRawText(omit_final_dot));
516 }
517 
519 Name::compare(const Name& other) const {
520  const LabelSequence ls1(*this);
521  const LabelSequence ls2(other);
522  return (ls1.compare(ls2));
523 }
524 
525 bool
526 Name::equals(const Name& other) const {
527  if (length_ != other.length_ || labelcount_ != other.labelcount_) {
528  return (false);
529  }
530 
531  for (unsigned int l = labelcount_, pos = 0; l > 0; --l) {
532  uint8_t count = ndata_[pos];
533  if (count != other.ndata_[pos]) {
534  return (false);
535  }
536  ++pos;
537 
538  while (count-- > 0) {
539  uint8_t label1 = ndata_[pos];
540  uint8_t label2 = other.ndata_[pos];
541 
542  if (maptolower[label1] != maptolower[label2]) {
543  return (false);
544  }
545  ++pos;
546  }
547  }
548 
549  return (true);
550 }
551 
552 bool
553 Name::leq(const Name& other) const {
554  return (compare(other).getOrder() <= 0);
555 }
556 
557 bool
558 Name::geq(const Name& other) const {
559  return (compare(other).getOrder() >= 0);
560 }
561 
562 bool
563 Name::lthan(const Name& other) const {
564  return (compare(other).getOrder() < 0);
565 }
566 
567 bool
568 Name::gthan(const Name& other) const {
569  return (compare(other).getOrder() > 0);
570 }
571 
572 bool
573 Name::isWildcard() const {
574  return (length_ >= 2 && ndata_[0] == 1 && ndata_[1] == '*');
575 }
576 
577 Name
578 Name::concatenate(const Name& suffix) const {
579  isc_throw_assert(length_ > 0 && suffix.length_ > 0);
580  isc_throw_assert(labelcount_ > 0 && suffix.labelcount_ > 0);
581 
582  unsigned int length = length_ + suffix.length_ - 1;
583  if (length > Name::MAX_WIRE) {
584  isc_throw(TooLongName, "names are too long to concatenate");
585  }
586 
587  Name retname;
588  retname.ndata_.reserve(length);
589  retname.ndata_.assign(ndata_, 0, length_ - 1);
590  retname.ndata_.insert(retname.ndata_.end(),
591  suffix.ndata_.begin(), suffix.ndata_.end());
592  isc_throw_assert(retname.ndata_.size() == length);
593  retname.length_ = length;
594 
595  //
596  // Setup the offsets vector. Copy the offsets of this (prefix) name,
597  // excluding that for the trailing dot, and append the offsets of the
598  // suffix name with the additional offset of the length of the prefix.
599  //
600  unsigned int labels = labelcount_ + suffix.labelcount_ - 1;
601  isc_throw_assert(labels <= Name::MAX_LABELS);
602  retname.offsets_.reserve(labels);
603  retname.offsets_.assign(&offsets_[0], &offsets_[0] + labelcount_ - 1);
604  transform(suffix.offsets_.begin(), suffix.offsets_.end(),
605  back_inserter(retname.offsets_),
606  [this] (char x) { return (x + length_ - 1); });
607  isc_throw_assert(retname.offsets_.size() == labels);
608  retname.labelcount_ = labels;
609 
610  return (retname);
611 }
612 
613 Name
614 Name::reverse() const {
615  Name retname;
616  //
617  // Set up offsets: The size of the string and number of labels will
618  // be the same in as in the original.
619  //
620  retname.offsets_.reserve(labelcount_);
621  retname.ndata_.reserve(length_);
622 
623  // Copy the original name, label by label, from tail to head.
624  NameOffsets::const_reverse_iterator rit0 = offsets_.rbegin();
625  NameOffsets::const_reverse_iterator rit1 = rit0 + 1;
626  NameString::const_iterator n0 = ndata_.begin();
627  retname.offsets_.push_back(0);
628  while (rit1 != offsets_.rend()) {
629  retname.ndata_.append(n0 + *rit1, n0 + *rit0);
630  retname.offsets_.push_back(retname.ndata_.size());
631  ++rit0;
632  ++rit1;
633  }
634  retname.ndata_.push_back(0);
635 
636  retname.labelcount_ = labelcount_;
637  retname.length_ = length_;
638 
639  return (retname);
640 }
641 
642 Name
643 Name::split(const unsigned int first, const unsigned int n) const {
644  if (n == 0 || n > labelcount_ || first > labelcount_ - n) {
645  isc_throw(OutOfRange, "Name::split: invalid split range");
646  }
647 
648  Name retname;
649  // If the specified range doesn't include the trailing dot, we need one
650  // more label for that.
651  unsigned int newlabels = (first + n == labelcount_) ? n : n + 1;
652 
653  //
654  // Set up offsets: copy the corresponding range of the original offsets
655  // with subtracting an offset of the prefix length.
656  //
657  retname.offsets_.reserve(newlabels);
658  transform(offsets_.begin() + first, offsets_.begin() + first + newlabels,
659  back_inserter(retname.offsets_),
660  [&](char x) { return (x - offsets_[first]); });
661 
662  //
663  // Set up the new name. At this point the tail of the new offsets specifies
664  // the position of the trailing dot, which should be equal to the length of
665  // the extracted portion excluding the dot. First copy that part from the
666  // original name, and append the trailing dot explicitly.
667  //
668  retname.ndata_.reserve(retname.offsets_.back() + 1);
669  retname.ndata_.assign(ndata_, offsets_[first], retname.offsets_.back());
670  retname.ndata_.push_back(0);
671 
672  retname.length_ = retname.ndata_.size();
673  retname.labelcount_ = retname.offsets_.size();
674  isc_throw_assert(retname.labelcount_ == newlabels);
675 
676  return (retname);
677 }
678 
679 Name
680 Name::split(const unsigned int level) const {
681  if (level >= getLabelCount()) {
682  isc_throw(OutOfRange, "invalid level for name split (" << level
683  << ") for name " << *this);
684  }
685 
686  return (split(level, getLabelCount() - level));
687 }
688 
689 Name&
690 Name::downcase() {
691  unsigned int nlen = length_;
692  unsigned int labels = labelcount_;
693  unsigned int pos = 0;
694 
695  while (labels > 0 && nlen > 0) {
696  --labels;
697  --nlen;
698 
699  // we assume a valid name, and do abort() if the assumption fails
700  // rather than throwing an exception.
701  unsigned int count = ndata_.at(pos++);
702  isc_throw_assert(count <= MAX_LABELLEN);
703  isc_throw_assert(nlen >= count);
704 
705  while (count > 0) {
706  ndata_.at(pos) =
707  maptolower[ndata_.at(pos)];
708  ++pos;
709  --nlen;
710  --count;
711  }
712  }
713 
714  return (*this);
715 }
716 
717 std::ostream&
718 operator<<(std::ostream& os, const Name& name) {
719  os << name.toText();
720  return (os);
721 }
722 
723 }
724 }
The Name class encapsulates DNS names.
Definition: name.h:223
size_t getLength() const
Return the length of the data stored in the buffer.
Definition: buffer.h:100
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
Definition: isc_assert.h:18
Thrown when origin is NULL and is needed.
Definition: name.h:96
virtual void writeName(const Name &name, bool compress=true)=0
Write a Name object into the internal buffer in wire format, with or without name compression...
void setPosition(size_t position)
Set the read position of the buffer to the given value.
Definition: buffer.h:115
std::string toText() const
Convert the LabelSequence to a string.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
std::string toRawText(bool omit_final_dot) const
Convert the LabelSequence to a string without escape sequences.
std::string toText(bool omit_final_dot=false) const
Convert the Name to a string.
Definition: name.cc:507
uint8_t at(size_t pos) const
Provides one-byte name data in wire format at the specified position.
Definition: name.h:346
STL namespace.
This is a supplemental class used only as a return value of Name::compare() and LabelSequence::compar...
Definition: name.h:117
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: edns.h:19
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
std::ostream & operator<<(std::ostream &os, const Name &name)
Insert the name as a string into stream.
Definition: name.cc:718
A standard DNS module exception that is thrown if the name parser encounters too long a name...
Definition: name.h:40
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
Defines the logger used by the top-level component of kea-dhcp-ddns.
size_t getPosition() const
Return the current read position.
Definition: buffer.h:102
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
uint8_t readUint8()
Read an unsigned 8-bit integer from the buffer and return it.
Definition: buffer.h:130
NameComparisonResult compare(const LabelSequence &other, bool case_sensitive=false) const
Compares two label sequences.
Light-weight Accessor to Name data.
Definition: labelsequence.h:35
const uint8_t maptolower[]
Definition: name.cc:73