]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsname.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <boost/format.hpp>
27 #include "dnswriter.hh"
30 #include <boost/functional/hash.hpp>
32 const DNSName
g_rootdnsname("."), g_wildcarddnsname("*");
35 in DNS label format, with trailing 0. W/o trailing 0, we are 'empty'
36 www.powerdns.com = 3www8powerdns3com0
39 std::ostream
& operator<<(std::ostream
&os
, const DNSName
& d
)
41 return os
<<d
.toLogString();
44 void DNSName::throwSafeRangeError(const std::string
& msg
, const char* buf
, size_t length
)
47 if (length
> s_maxDNSNameLength
) {
48 length
= s_maxDNSNameLength
;
52 DNSName::appendEscapedLabel(label
, buf
, length
);
53 throw std::range_error(msg
+ label
+ dots
);
56 DNSName::DNSName(const std::string_view sw
)
58 const char* p
= sw
.data();
59 size_t length
= sw
.length();
61 if(length
== 0 || (length
== 1 && p
[0]=='.')) {
62 d_storage
.assign(1, '\0');
64 if(!std::memchr(p
, '\\', length
)) {
65 unsigned char lenpos
=0;
66 unsigned char labellen
=0;
67 const char* const pbegin
=p
, *pend
=p
+length
;
69 d_storage
.reserve(length
+1);
70 for(auto iter
= pbegin
; iter
!= pend
; ) {
71 lenpos
= d_storage
.size();
73 throwSafeRangeError("Found . in wrong position in DNSName: ", p
, length
);
74 d_storage
.append(1, '\0');
77 for(; iter
!= pend
&& *iter
!='.'; ++iter
) {
80 d_storage
.append(begiter
,iter
);
84 throwSafeRangeError("label too long to append: ", p
, length
);
86 if(iter
-pbegin
> static_cast<ptrdiff_t>(s_maxDNSNameLength
- 1)) // reserve two bytes, one for length and one for the root label
87 throwSafeRangeError("name too long to append: ", p
, length
);
89 d_storage
[lenpos
]=labellen
;
91 d_storage
.append(1, '\0');
94 d_storage
=segmentDNSNameRaw(p
, length
);
95 if(d_storage
.size() > s_maxDNSNameLength
) {
96 throwSafeRangeError("name too long: ", p
, length
);
102 DNSName::DNSName(const char* pos
, size_t len
, size_t offset
, bool uncompress
, uint16_t* qtype
, uint16_t* qclass
, unsigned int* consumed
, uint16_t minOffset
)
105 throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset
)+ " >= "+std::to_string(len
)+")");
108 if(const void * fnd
=memchr(pos
+offset
, 0, len
-offset
)) {
109 d_storage
.reserve(2+(const char*)fnd
-(pos
+offset
));
113 packetParser(pos
, len
, offset
, uncompress
, qtype
, qclass
, consumed
, 0, minOffset
);
116 static void checkLabelLength(uint8_t length
)
119 throw std::range_error("no such thing as an empty label to append");
122 throw std::range_error("label too long to append");
126 // this parses a DNS name until a compression pointer is found
127 size_t DNSName::parsePacketUncompressed(const pdns::views::UnsignedCharView
& view
, size_t pos
, bool uncompress
)
129 const size_t initialPos
= pos
;
130 size_t totalLength
= 0;
131 unsigned char labellen
= 0;
134 labellen
= view
.at(pos
);
142 if (labellen
>= 0xc0) {
144 throw std::range_error("Found compressed label, instructed not to follow");
150 if ((labellen
& 0xc0) != 0) {
151 throw std::range_error("Found an invalid label length in qname (only one of the first two bits is set)");
153 checkLabelLength(labellen
);
154 // reserve one byte for the label length
155 if (totalLength
+ labellen
> s_maxDNSNameLength
- 1) {
156 throw std::range_error("name too long to append");
158 if (pos
+ labellen
>= view
.size()) {
159 throw std::range_error("Found an invalid label length in qname");
162 totalLength
+= 1 + labellen
;
164 while (pos
< view
.size());
166 if (totalLength
!= 0) {
167 auto existingSize
= d_storage
.size();
168 if (existingSize
> 0) {
169 // remove the last label count, we are about to override it */
172 d_storage
.reserve(existingSize
+ totalLength
+ 1);
173 d_storage
.resize(existingSize
+ totalLength
);
174 memcpy(&d_storage
.at(existingSize
), &view
.at(initialPos
), totalLength
);
175 d_storage
.append(1, static_cast<char>(0));
180 // this should be the __only__ dns name parser in PowerDNS.
181 void DNSName::packetParser(const char* qpos
, size_t len
, size_t offset
, bool uncompress
, uint16_t* qtype
, uint16_t* qclass
, unsigned int* consumed
, int depth
, uint16_t minOffset
)
184 throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset
)+ " >= "+std::to_string(len
)+")");
187 if (offset
< static_cast<size_t>(minOffset
)) {
188 throw std::range_error("Trying to read before the beginning of the buffer ("+std::to_string(offset
)+ " < "+std::to_string(minOffset
)+")");
190 unsigned char labellen
{0};
192 pdns::views::UnsignedCharView
view(qpos
, len
);
193 auto pos
= parsePacketUncompressed(view
, offset
, uncompress
);
195 labellen
= view
.at(pos
);
197 if (labellen
!= 0 && pos
< view
.size()) {
198 if (labellen
< 0xc0) {
203 throw std::range_error("Found compressed label, instructed not to follow");
207 size_t newpos
= (labellen
<< 8) + view
.at(pos
);
209 if (newpos
>= offset
) {
210 throw std::range_error("Found a forward reference during label decompression");
213 if (newpos
< minOffset
) {
214 throw std::range_error("Invalid label position during decompression ("+std::to_string(newpos
)+ " < "+std::to_string(minOffset
)+")");
218 throw std::range_error("Abort label decompression after 100 redirects");
221 packetParser(qpos
, len
, newpos
, true, nullptr, nullptr, nullptr, depth
, minOffset
);
226 if (d_storage
.empty()) {
227 d_storage
.append(1, static_cast<char>(0)); // we just parsed the root
230 if (consumed
!= nullptr) {
231 *consumed
= pos
- offset
;
234 if (qtype
!= nullptr) {
235 if (pos
+ 2 > view
.size()) {
236 throw std::range_error("Trying to read qtype past the end of the buffer ("+std::to_string(pos
+ 2)+ " > "+std::to_string(len
)+")");
238 *qtype
= view
.at(pos
)*256 + view
.at(pos
+1);
242 if (qclass
!= nullptr) {
243 if (pos
+ 2 > view
.size()) {
244 throw std::range_error("Trying to read qclass past the end of the buffer ("+std::to_string(pos
+ 2)+ " > "+std::to_string(len
)+")");
246 *qclass
= view
.at(pos
)*256 + view
.at(pos
+1);
250 std::string
DNSName::toString(const std::string
& separator
, const bool trailing
) const
253 toString(ret
, separator
, trailing
);
257 void DNSName::toString(std::string
& output
, const std::string
& separator
, const bool trailing
) const
260 throw std::out_of_range("Attempt to print an unset dnsname");
264 output
+= (trailing
? separator
: "");
268 if (output
.capacity() < (output
.size() + d_storage
.size())) {
269 output
.reserve(output
.size() + d_storage
.size());
273 // iterate over the raw labels
274 const char* p
= d_storage
.c_str();
275 const char* end
= p
+ d_storage
.size();
277 while (p
< end
&& *p
) {
278 appendEscapedLabel(output
, p
+ 1, static_cast<size_t>(*p
));
285 output
.resize(output
.size() - separator
.size());
289 std::string
DNSName::toLogString() const
295 return toStringRootDot();
298 std::string
DNSName::toDNSString() const
301 throw std::out_of_range("Attempt to DNSString an unset dnsname");
304 return std::string(d_storage
.c_str(), d_storage
.length());
307 std::string
DNSName::toDNSStringLC() const
309 auto result
= toDNSString();
310 toLowerInPlace(result
); // label lengths are always < 'A'
315 * Get the length of the DNSName on the wire
317 * @return the total wirelength of the DNSName
319 size_t DNSName::wirelength() const {
320 return d_storage
.length();
323 // Are WE part of parent
324 bool DNSName::isPartOf(const DNSName
& parent
) const
326 if(parent
.empty() || empty()) {
327 throw std::out_of_range("empty dnsnames aren't part of anything");
330 if(parent
.d_storage
.size() > d_storage
.size()) {
334 // this is slightly complicated since we can't start from the end, since we can't see where a label begins/ends then
335 for(auto us
=d_storage
.cbegin(); us
<d_storage
.cend(); us
+=*us
+1) {
336 auto distance
= std::distance(us
,d_storage
.cend());
337 if (distance
< 0 || static_cast<size_t>(distance
) < parent
.d_storage
.size()) {
340 if (static_cast<size_t>(distance
) == parent
.d_storage
.size()) {
341 auto p
= parent
.d_storage
.cbegin();
342 for(; us
!= d_storage
.cend(); ++us
, ++p
) {
343 if(dns_tolower(*p
) != dns_tolower(*us
))
348 if (static_cast<uint8_t>(*us
) > 63) {
349 throw std::out_of_range("illegal label length in dnsname");
355 DNSName
DNSName::makeRelative(const DNSName
& zone
) const
358 ret
.makeUsRelative(zone
);
362 void DNSName::makeUsRelative(const DNSName
& zone
)
364 if (isPartOf(zone
)) {
365 d_storage
.erase(d_storage
.size()-zone
.d_storage
.size());
366 d_storage
.append(1, static_cast<char>(0)); // put back the trailing 0
373 DNSName
DNSName::getCommonLabels(const DNSName
& other
) const
375 if (empty() || other
.empty()) {
379 DNSName
result(g_rootdnsname
);
381 const std::vector
<std::string
> ours
= getRawLabels();
382 const std::vector
<std::string
> others
= other
.getRawLabels();
384 for (size_t pos
= 0; ours
.size() > pos
&& others
.size() > pos
; pos
++) {
385 const std::string
& ourLabel
= ours
.at(ours
.size() - pos
- 1);
386 const std::string
& otherLabel
= others
.at(others
.size() - pos
- 1);
388 if (!pdns_iequals(ourLabel
, otherLabel
)) {
392 result
.prependRawLabel(ourLabel
);
398 DNSName
DNSName::labelReverse() const
403 return *this; // we don't create the root automatically below
407 vector
<string
> l
=getRawLabels();
409 ret
.appendRawLabel(l
.back());
416 void DNSName::appendRawLabel(const std::string
& label
)
418 appendRawLabel(label
.c_str(), label
.length());
421 void DNSName::appendRawLabel(const char* start
, unsigned int length
)
423 checkLabelLength(length
);
425 // reserve one byte for the label length
426 if (d_storage
.size() + length
> s_maxDNSNameLength
- 1) {
427 throw std::range_error("name too long to append");
430 if (d_storage
.empty()) {
431 d_storage
.reserve(1 + length
+ 1);
432 d_storage
.append(1, static_cast<char>(length
));
435 d_storage
.reserve(d_storage
.size() + length
+ 1);
436 *d_storage
.rbegin() = static_cast<char>(length
);
438 d_storage
.append(start
, length
);
439 d_storage
.append(1, static_cast<char>(0));
442 void DNSName::prependRawLabel(const std::string
& label
)
444 checkLabelLength(label
.size());
446 // reserve one byte for the label length
447 if (d_storage
.size() + label
.size() > s_maxDNSNameLength
- 1) {
448 throw std::range_error("name too long to prepend");
451 if (d_storage
.empty()) {
452 d_storage
.reserve(1 + label
.size() + 1);
453 d_storage
.append(1, static_cast<char>(0));
456 d_storage
.reserve(d_storage
.size() + 1 + label
.size());
459 string_t
prep(1, static_cast<char>(label
.size()));
460 prep
.append(label
.c_str(), label
.size());
461 d_storage
= prep
+d_storage
;
464 bool DNSName::slowCanonCompare(const DNSName
& rhs
) const
466 auto ours
=getRawLabels(), rhsLabels
= rhs
.getRawLabels();
467 return std::lexicographical_compare(ours
.rbegin(), ours
.rend(), rhsLabels
.rbegin(), rhsLabels
.rend(), CIStringCompare());
470 vector
<std::string
> DNSName::getRawLabels() const
472 vector
<std::string
> ret
;
473 ret
.reserve(countLabels());
475 for(const unsigned char* p
= (const unsigned char*) d_storage
.c_str(); p
< ((const unsigned char*) d_storage
.c_str()) + d_storage
.size() && *p
; p
+=*p
+1) {
476 ret
.push_back({(const char*)p
+1, (size_t)*p
}); // XXX FIXME
481 std::string
DNSName::getRawLabel(unsigned int pos
) const
483 unsigned int currentPos
= 0;
484 for(const unsigned char* p
= (const unsigned char*) d_storage
.c_str(); p
< ((const unsigned char*) d_storage
.c_str()) + d_storage
.size() && *p
; p
+=*p
+1, currentPos
++) {
485 if (currentPos
== pos
) {
486 return std::string((const char*)p
+1, (size_t)*p
);
490 throw std::out_of_range("trying to get label at position "+std::to_string(pos
)+" of a DNSName that only has "+std::to_string(currentPos
)+" labels");
493 DNSName
DNSName::getLastLabel() const
500 bool DNSName::chopOff()
502 if (d_storage
.empty() || d_storage
[0]==0) {
505 d_storage
.erase(0, (unsigned int)d_storage
[0]+1);
509 bool DNSName::isWildcard() const
511 if (d_storage
.size() < 2) {
514 auto p
= d_storage
.begin();
515 return (*p
== 0x01 && *++p
== '*');
519 * Returns true if the DNSName is a valid RFC 1123 hostname, this function uses
520 * a regex on the string, so it is probably best not used when speed is essential.
522 bool DNSName::isHostname() const
524 static Regex hostNameRegex
= Regex("^(([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)\\.)+$");
525 return hostNameRegex
.match(this->toString());
528 unsigned int DNSName::countLabels() const
530 unsigned int count
=0;
531 const unsigned char* p
= reinterpret_cast<const unsigned char*>(d_storage
.c_str());
532 const unsigned char* end
= reinterpret_cast<const unsigned char*>(p
+ d_storage
.size());
534 while (p
< end
&& *p
) {
541 void DNSName::trimToLabels(unsigned int to
)
543 while(countLabels() > to
&& chopOff()) {
549 size_t hash_value(DNSName
const& d
)
554 void DNSName::appendEscapedLabel(std::string
& appendTo
, const char* orig
, size_t len
)
559 auto p
= static_cast<uint8_t>(orig
[pos
]);
566 else if (p
> 0x20 && p
< 0x7f) {
567 appendTo
.append(1, static_cast<char>(p
));
571 auto got
= snprintf(buf
, sizeof(buf
), "%03" PRIu8
, p
);
572 if (got
< 0 || static_cast<size_t>(got
) >= sizeof(buf
)) {
573 throw std::runtime_error("Error, snprintf returned " + std::to_string(got
) + " while escaping label " + std::string(orig
, len
));
575 appendTo
.append(1, '\\');
582 bool DNSName::has8bitBytes() const
584 const auto& s
= d_storage
;
585 string::size_type pos
= 0;
586 uint8_t length
= s
.at(pos
);
588 for (size_t idx
= 0; idx
< length
; idx
++) {
591 if (!((c
>= 'a' && c
<= 'z') ||
592 (c
>= 'A' && c
<= 'Z') ||
593 (c
>= '0' && c
<= '9') ||
594 c
=='-' || c
== '_' || c
=='*' || c
=='.' || c
=='/' || c
=='@' || c
==' ' || c
=='\\' || c
==':')) {
606 const unsigned char dns_toupper_table
[256] = {
607 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
608 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
609 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
610 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
611 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
612 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
613 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
614 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
615 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
616 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
617 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
618 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
619 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
620 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
621 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
622 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
623 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
624 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
625 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
626 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
627 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
628 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
629 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
630 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
631 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
632 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
633 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
634 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
635 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
636 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
637 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
638 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
641 const unsigned char dns_tolower_table
[256] = {
642 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
643 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
644 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
645 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
646 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
647 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
648 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
649 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
650 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
651 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
652 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
653 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
654 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
655 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
656 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
657 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
658 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
659 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
660 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
661 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
662 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
663 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
664 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
665 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
666 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
667 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
668 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
669 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
670 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
671 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
672 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
673 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
676 DNSName::RawLabelsVisitor::RawLabelsVisitor(const DNSName::string_t
& storage
): d_storage(storage
)
679 while (position
< storage
.size()) {
680 auto labelLength
= static_cast<uint8_t>(storage
.at(position
));
681 if (labelLength
== 0) {
684 d_labelPositions
.at(d_position
) = position
;
686 position
+= labelLength
+ 1;
690 DNSName::RawLabelsVisitor
DNSName::getRawLabelsVisitor() const
692 return DNSName::RawLabelsVisitor(getStorage());
695 std::string_view
DNSName::RawLabelsVisitor::front() const
697 if (d_position
== 0) {
698 throw std::out_of_range("trying to access the front of an empty DNSName::RawLabelsVisitor");
700 uint8_t length
= d_storage
.at(0);
702 return std::string_view();
704 return std::string_view(&d_storage
.at(1), length
);
707 std::string_view
DNSName::RawLabelsVisitor::back() const
709 if (d_position
== 0) {
710 throw std::out_of_range("trying to access the back of an empty DNSName::RawLabelsVisitor");
712 size_t offset
= d_labelPositions
.at(d_position
-1);
713 uint8_t length
= d_storage
.at(offset
);
715 return std::string_view();
717 return std::string_view(&d_storage
.at(offset
+ 1), length
);
720 bool DNSName::RawLabelsVisitor::pop_back()
722 if (d_position
> 0) {
729 bool DNSName::RawLabelsVisitor::empty() const
731 return d_position
== 0;