Kea: name.cc Source File

| Kea 3.2.0-git

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