]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsname.cc
rec: mention rust compiler in compiling docs
[thirdparty/pdns.git] / pdns / dnsname.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
3c115e0f 22#include "dnsname.hh"
23#include <boost/format.hpp>
24#include <string>
27b19e8b 25#include <cinttypes>
6d8bc3c6 26
3c115e0f 27#include "dnswriter.hh"
5e1031cd
PD
28#include "misc.hh"
29
30#include <boost/functional/hash.hpp>
3c115e0f 31
c21484df 32const DNSName g_rootdnsname("."), g_wildcarddnsname("*");
33
97e5c6bc 34/* raw storage
ae14c1f3 35 in DNS label format, with trailing 0. W/o trailing 0, we are 'empty'
36 www.powerdns.com = 3www8powerdns3com0
97e5c6bc 37*/
38
8171ab83 39std::ostream & operator<<(std::ostream &os, const DNSName& d)
40{
39b3e0b2 41 return os <<d.toLogString();
8171ab83 42}
43
10ae7b37
OM
44void DNSName::throwSafeRangeError(const std::string& msg, const char* buf, size_t length)
45{
46 std::string dots;
9ec4c239
OM
47 if (length > s_maxDNSNameLength) {
48 length = s_maxDNSNameLength;
10ae7b37
OM
49 dots = "...";
50 }
51 std::string label;
52 DNSName::appendEscapedLabel(label, buf, length);
53 throw std::range_error(msg + label + dots);
54}
55
a9c27e3a 56DNSName::DNSName(const std::string_view sw)
3c115e0f 57{
72a7ae39
AV
58 const char* p = sw.data();
59 size_t length = sw.length();
60
e5465a97 61 if(length == 0 || (length == 1 && p[0]=='.')) {
30351b0c 62 d_storage.assign(1, '\0');
ae14c1f3 63 } else {
c4da11fc 64 if(!std::memchr(p, '\\', length)) {
bae1b0a2 65 unsigned char lenpos=0;
66 unsigned char labellen=0;
d298da97
AV
67 const char* const pbegin=p, *pend=p+length;
68
69 d_storage.reserve(length+1);
bae1b0a2 70 for(auto iter = pbegin; iter != pend; ) {
71 lenpos = d_storage.size();
72 if(*iter=='.')
10ae7b37 73 throwSafeRangeError("Found . in wrong position in DNSName: ", p, length);
30351b0c 74 d_storage.append(1, '\0');
bae1b0a2 75 labellen=0;
76 auto begiter=iter;
77 for(; iter != pend && *iter!='.'; ++iter) {
78 labellen++;
79 }
80 d_storage.append(begiter,iter);
81 if(iter != pend)
82 ++iter;
83 if(labellen > 63)
10ae7b37 84 throwSafeRangeError("label too long to append: ", p, length);
bae1b0a2 85
9ec4c239 86 if(iter-pbegin > static_cast<ptrdiff_t>(s_maxDNSNameLength - 1)) // reserve two bytes, one for length and one for the root label
10ae7b37 87 throwSafeRangeError("name too long to append: ", p, length);
bae1b0a2 88
89 d_storage[lenpos]=labellen;
90 }
30351b0c 91 d_storage.append(1, '\0');
bae1b0a2 92 }
d0a4a4bc 93 else {
beb9fad5 94 d_storage=segmentDNSNameRaw(p, length);
9ec4c239 95 if(d_storage.size() > s_maxDNSNameLength) {
10ae7b37 96 throwSafeRangeError("name too long: ", p, length);
d0a4a4bc
RG
97 }
98 }
ae14c1f3 99 }
3c115e0f 100}
101
cce0983c 102DNSName::DNSName(const char* pos, size_t len, size_t offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, uint16_t minOffset)
3c115e0f 103{
adbace93 104 if (offset >= len)
e415d842 105 throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
adbace93 106
e14febcf 107 if(!uncompress) {
108 if(const void * fnd=memchr(pos+offset, 0, len-offset)) {
109 d_storage.reserve(2+(const char*)fnd-(pos+offset));
110 }
111 }
112
83fc9d8a 113 packetParser(pos, len, offset, uncompress, qtype, qclass, consumed, 0, minOffset);
ac7921b0 114}
115
4dee9e77
RG
116static void checkLabelLength(uint8_t length)
117{
118 if (length == 0) {
119 throw std::range_error("no such thing as an empty label to append");
120 }
121 if (length > 63) {
122 throw std::range_error("label too long to append");
123 }
124}
125
126// this parses a DNS name until a compression pointer is found
2a3c2b44 127size_t DNSName::parsePacketUncompressed(const pdns::views::UnsignedCharView& view, size_t pos, bool uncompress)
4dee9e77 128{
2e163d91 129 const size_t initialPos = pos;
4dee9e77
RG
130 size_t totalLength = 0;
131 unsigned char labellen = 0;
132
133 do {
2e163d91 134 labellen = view.at(pos);
4dee9e77 135 ++pos;
2e163d91 136
4dee9e77
RG
137 if (labellen == 0) {
138 --pos;
139 break;
140 }
2e163d91 141
4dee9e77
RG
142 if (labellen >= 0xc0) {
143 if (!uncompress) {
144 throw std::range_error("Found compressed label, instructed not to follow");
145 }
146 --pos;
147 break;
148 }
2e163d91
RG
149
150 if ((labellen & 0xc0) != 0) {
4dee9e77
RG
151 throw std::range_error("Found an invalid label length in qname (only one of the first two bits is set)");
152 }
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");
157 }
2e163d91 158 if (pos + labellen >= view.size()) {
4dee9e77
RG
159 throw std::range_error("Found an invalid label length in qname");
160 }
161 pos += labellen;
162 totalLength += 1 + labellen;
163 }
28fc8199 164 while (pos < view.size());
4dee9e77
RG
165
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 */
170 --existingSize;
4dee9e77
RG
171 }
172 d_storage.reserve(existingSize + totalLength + 1);
173 d_storage.resize(existingSize + totalLength);
2e163d91 174 memcpy(&d_storage.at(existingSize), &view.at(initialPos), totalLength);
4dee9e77
RG
175 d_storage.append(1, static_cast<char>(0));
176 }
177 return pos;
178}
179
ac7921b0 180// this should be the __only__ dns name parser in PowerDNS.
cce0983c 181void 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)
ac7921b0 182{
05fe7452 183 if (offset >= len) {
e415d842 184 throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
05fe7452 185 }
4dee9e77 186
05fe7452 187 if (offset < static_cast<size_t>(minOffset)) {
83fc9d8a 188 throw std::range_error("Trying to read before the beginning of the buffer ("+std::to_string(offset)+ " < "+std::to_string(minOffset)+")");
05fe7452 189 }
2e163d91 190 unsigned char labellen{0};
3bf1f0b0 191
2a3c2b44 192 pdns::views::UnsignedCharView view(qpos, len);
2e163d91 193 auto pos = parsePacketUncompressed(view, offset, uncompress);
b5b1018e 194
2e163d91
RG
195 labellen = view.at(pos);
196 pos++;
197 if (labellen != 0 && pos < view.size()) {
4dee9e77
RG
198 if (labellen < 0xc0) {
199 abort();
b5b1018e 200 }
4dee9e77
RG
201
202 if (!uncompress) {
203 throw std::range_error("Found compressed label, instructed not to follow");
ac7921b0 204 }
4dee9e77
RG
205
206 labellen &= (~0xc0);
2e163d91 207 size_t newpos = (labellen << 8) + view.at(pos);
4dee9e77
RG
208
209 if (newpos >= offset) {
210 throw std::range_error("Found a forward reference during label decompression");
05fe7452 211 }
4dee9e77
RG
212
213 if (newpos < minOffset) {
214 throw std::range_error("Invalid label position during decompression ("+std::to_string(newpos)+ " < "+std::to_string(minOffset)+")");
215 }
216
217 if (++depth > 100) {
218 throw std::range_error("Abort label decompression after 100 redirects");
219 }
220
2e163d91 221 packetParser(qpos, len, newpos, true, nullptr, nullptr, nullptr, depth, minOffset);
4dee9e77
RG
222
223 pos++;
3c115e0f 224 }
4dee9e77 225
7cd99b08 226 if (d_storage.empty()) {
2e163d91 227 d_storage.append(1, static_cast<char>(0)); // we just parsed the root
05fe7452 228 }
4dee9e77 229
7cd99b08 230 if (consumed != nullptr) {
2e163d91 231 *consumed = pos - offset;
05fe7452 232 }
4dee9e77 233
7cd99b08 234 if (qtype != nullptr) {
2e163d91
RG
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)+")");
bd910269 237 }
2e163d91 238 *qtype = view.at(pos)*256 + view.at(pos+1);
bd910269 239 }
2e163d91 240
4dee9e77
RG
241 pos += 2;
242 if (qclass != nullptr) {
2e163d91
RG
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)+")");
bd910269 245 }
2e163d91 246 *qclass = view.at(pos)*256 + view.at(pos+1);
bd910269 247 }
3c115e0f 248}
249
a61e8e59 250std::string DNSName::toString(const std::string& separator, const bool trailing) const
a44a8d66
OM
251{
252 std::string ret;
253 toString(ret, separator, trailing);
254 return ret;
255}
256
257void DNSName::toString(std::string& output, const std::string& separator, const bool trailing) const
3c115e0f 258{
e1a9ab9f 259 if (empty()) {
ae14c1f3 260 throw std::out_of_range("Attempt to print an unset dnsname");
e1a9ab9f 261 }
ae14c1f3 262
a44a8d66
OM
263 if (isRoot()) {
264 output += (trailing ? separator : "");
265 return;
266 }
07338ade 267
a44a8d66
OM
268 if (output.capacity() < (output.size() + d_storage.size())) {
269 output.reserve(output.size() + d_storage.size());
270 }
19164b93
CHB
271
272 {
273 // iterate over the raw labels
274 const char* p = d_storage.c_str();
275 const char* end = p + d_storage.size();
276
277 while (p < end && *p) {
a44a8d66
OM
278 appendEscapedLabel(output, p + 1, static_cast<size_t>(*p));
279 output += separator;
19164b93
CHB
280 p += *p + 1;
281 }
3c115e0f 282 }
a44a8d66 283
f0da87e0 284 if (!trailing) {
a44a8d66 285 output.resize(output.size() - separator.size());
f0da87e0 286 }
3c115e0f 287}
288
9ab84270
PD
289std::string DNSName::toLogString() const
290{
291 if (empty()) {
292 return "(empty)";
293 }
294
a724f955 295 return toStringRootDot();
9ab84270
PD
296}
297
3c115e0f 298std::string DNSName::toDNSString() const
299{
05fe7452 300 if (empty()) {
ae14c1f3 301 throw std::out_of_range("Attempt to DNSString an unset dnsname");
05fe7452 302 }
ae14c1f3 303
0ba4e1ee 304 return std::string(d_storage.c_str(), d_storage.length());
305}
306
307std::string DNSName::toDNSStringLC() const
308{
5f2286f1
RG
309 auto result = toDNSString();
310 toLowerInPlace(result); // label lengths are always < 'A'
311 return result;
3c115e0f 312}
313
3155c04a
PL
314/**
315 * Get the length of the DNSName on the wire
316 *
317 * @return the total wirelength of the DNSName
318 */
319size_t DNSName::wirelength() const {
ae14c1f3 320 return d_storage.length();
3155c04a
PL
321}
322
ae14c1f3 323// Are WE part of parent
3c115e0f 324bool DNSName::isPartOf(const DNSName& parent) const
325{
05fe7452 326 if(parent.empty() || empty()) {
ae14c1f3 327 throw std::out_of_range("empty dnsnames aren't part of anything");
05fe7452 328 }
ae14c1f3 329
05fe7452 330 if(parent.d_storage.size() > d_storage.size()) {
3bd38afa 331 return false;
05fe7452 332 }
3bd38afa 333
334 // this is slightly complicated since we can't start from the end, since we can't see where a label begins/ends then
d8ec8f44
RG
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()) {
338 break;
339 }
340 if (static_cast<size_t>(distance) == parent.d_storage.size()) {
3bd38afa 341 auto p = parent.d_storage.cbegin();
9e98d926 342 for(; us != d_storage.cend(); ++us, ++p) {
2b62292d 343 if(dns_tolower(*p) != dns_tolower(*us))
9e98d926 344 return false;
3bd38afa 345 }
9e98d926 346 return true;
3bd38afa 347 }
abb8aeb0
OM
348 if (static_cast<uint8_t>(*us) > 63) {
349 throw std::out_of_range("illegal label length in dnsname");
c9742dfb 350 }
3c115e0f 351 }
3bd38afa 352 return false;
3c115e0f 353}
354
a61e8e59
KM
355DNSName DNSName::makeRelative(const DNSName& zone) const
356{
357 DNSName ret(*this);
8ca15224 358 ret.makeUsRelative(zone);
32f19b60 359 return ret;
a61e8e59 360}
32f19b60 361
4dee9e77 362void DNSName::makeUsRelative(const DNSName& zone)
8ca15224 363{
364 if (isPartOf(zone)) {
365 d_storage.erase(d_storage.size()-zone.d_storage.size());
eb6b96f3 366 d_storage.append(1, static_cast<char>(0)); // put back the trailing 0
4dee9e77 367 }
05fe7452 368 else {
8ca15224 369 clear();
05fe7452 370 }
8ca15224 371}
a61e8e59 372
9b061cf5
RG
373DNSName DNSName::getCommonLabels(const DNSName& other) const
374{
385a2208
KM
375 if (empty() || other.empty()) {
376 return DNSName();
377 }
378
379 DNSName result(g_rootdnsname);
9b061cf5
RG
380
381 const std::vector<std::string> ours = getRawLabels();
382 const std::vector<std::string> others = other.getRawLabels();
383
384 for (size_t pos = 0; ours.size() > pos && others.size() > pos; pos++) {
097f8a42
RG
385 const std::string& ourLabel = ours.at(ours.size() - pos - 1);
386 const std::string& otherLabel = others.at(others.size() - pos - 1);
387
388 if (!pdns_iequals(ourLabel, otherLabel)) {
9b061cf5
RG
389 break;
390 }
391
097f8a42 392 result.prependRawLabel(ourLabel);
9b061cf5
RG
393 }
394
395 return result;
396}
397
a61e8e59
KM
398DNSName DNSName::labelReverse() const
399{
400 DNSName ret;
c2b55ab9 401
05fe7452 402 if (isRoot()) {
e1a9ab9f 403 return *this; // we don't create the root automatically below
05fe7452 404 }
c2b55ab9 405
d44e4e09 406 if (!empty()) {
a61e8e59
KM
407 vector<string> l=getRawLabels();
408 while(!l.empty()) {
409 ret.appendRawLabel(l.back());
410 l.pop_back();
411 }
412 }
413 return ret;
414}
415
3c115e0f 416void DNSName::appendRawLabel(const std::string& label)
417{
e14febcf 418 appendRawLabel(label.c_str(), label.length());
419}
420
421void DNSName::appendRawLabel(const char* start, unsigned int length)
422{
4dee9e77
RG
423 checkLabelLength(length);
424
425 // reserve one byte for the label length
426 if (d_storage.size() + length > s_maxDNSNameLength - 1) {
e11dc8c8 427 throw std::range_error("name too long to append");
05fe7452 428 }
ac7921b0 429
05fe7452 430 if (d_storage.empty()) {
4dee9e77 431 d_storage.reserve(1 + length + 1);
eb6b96f3 432 d_storage.append(1, static_cast<char>(length));
ae14c1f3 433 }
434 else {
4dee9e77 435 d_storage.reserve(d_storage.size() + length + 1);
eb6b96f3 436 *d_storage.rbegin() = static_cast<char>(length);
ae14c1f3 437 }
e14febcf 438 d_storage.append(start, length);
eb6b96f3 439 d_storage.append(1, static_cast<char>(0));
3c115e0f 440}
441
442void DNSName::prependRawLabel(const std::string& label)
443{
4dee9e77
RG
444 checkLabelLength(label.size());
445
446 // reserve one byte for the label length
447 if (d_storage.size() + label.size() > s_maxDNSNameLength - 1) {
e11dc8c8 448 throw std::range_error("name too long to prepend");
05fe7452 449 }
be6fbc68 450
05fe7452 451 if (d_storage.empty()) {
4dee9e77 452 d_storage.reserve(1 + label.size() + 1);
eb6b96f3 453 d_storage.append(1, static_cast<char>(0));
05fe7452 454 }
4dee9e77
RG
455 else {
456 d_storage.reserve(d_storage.size() + 1 + label.size());
457 }
ae14c1f3 458
eb6b96f3 459 string_t prep(1, static_cast<char>(label.size()));
d8b778ff 460 prep.append(label.c_str(), label.size());
97e5c6bc 461 d_storage = prep+d_storage;
3c115e0f 462}
463
4dee9e77 464bool DNSName::slowCanonCompare(const DNSName& rhs) const
ddb7e6c6 465{
466 auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels();
467 return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare());
468}
469
19164b93 470vector<std::string> DNSName::getRawLabels() const
3c115e0f 471{
19164b93 472 vector<std::string> ret;
ec3f33c6 473 ret.reserve(countLabels());
ae14c1f3 474 // 3www4ds9a2nl0
e358efcb
RG
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
477 }
97e5c6bc 478 return ret;
3c115e0f 479}
480
39c9bef5
RG
481std::string DNSName::getRawLabel(unsigned int pos) const
482{
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);
487 }
488 }
489
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");
491}
6d8bc3c6 492
41e01592
PL
493DNSName DNSName::getLastLabel() const
494{
495 DNSName ret(*this);
496 ret.trimToLabels(1);
497 return ret;
498}
499
21a3792f 500bool DNSName::chopOff()
3c115e0f 501{
05fe7452 502 if (d_storage.empty() || d_storage[0]==0) {
3c115e0f 503 return false;
05fe7452 504 }
ec3f33c6 505 d_storage.erase(0, (unsigned int)d_storage[0]+1);
3c115e0f 506 return true;
507}
508
8aa5a28c
KM
509bool DNSName::isWildcard() const
510{
05fe7452 511 if (d_storage.size() < 2) {
8aa5a28c 512 return false;
05fe7452 513 }
8aa5a28c
KM
514 auto p = d_storage.begin();
515 return (*p == 0x01 && *++p == '*');
516}
517
32cd4eb1
PL
518/*
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.
521 */
522bool DNSName::isHostname() const
523{
524 static Regex hostNameRegex = Regex("^(([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)\\.)+$");
525 return hostNameRegex.match(this->toString());
526}
527
97e5c6bc 528unsigned int DNSName::countLabels() const
529{
530 unsigned int count=0;
19164b93
CHB
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());
533
534 while (p < end && *p) {
97e5c6bc 535 ++count;
19164b93
CHB
536 p += *p + 1;
537 }
97e5c6bc 538 return count;
539}
540
c9262563 541void DNSName::trimToLabels(unsigned int to)
542{
05fe7452 543 while(countLabels() > to && chopOff()) {
c9262563 544 ;
05fe7452 545 }
c9262563 546}
547
3c115e0f 548
5e1031cd
PD
549size_t hash_value(DNSName const& d)
550{
76cca09f 551 return d.hash();
5e1031cd
PD
552}
553
2430e53c 554void DNSName::appendEscapedLabel(std::string& appendTo, const char* orig, size_t len)
3c115e0f 555{
19164b93
CHB
556 size_t pos = 0;
557
19164b93
CHB
558 while (pos < len) {
559 auto p = static_cast<uint8_t>(orig[pos]);
05fe7452 560 if (p=='.') {
2430e53c 561 appendTo+="\\.";
05fe7452
CHB
562 }
563 else if (p=='\\') {
2430e53c 564 appendTo+="\\\\";
05fe7452
CHB
565 }
566 else if (p > 0x20 && p < 0x7f) {
eb6b96f3 567 appendTo.append(1, static_cast<char>(p));
05fe7452 568 }
3c115e0f 569 else {
2430e53c
RG
570 char buf[] = "000";
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));
574 }
575 appendTo.append(1, '\\');
576 appendTo += buf;
3c115e0f 577 }
19164b93 578 ++pos;
3c115e0f 579 }
3c115e0f 580}
bf7ef5b4
RG
581
582bool DNSName::has8bitBytes() const
583{
584 const auto& s = d_storage;
585 string::size_type pos = 0;
586 uint8_t length = s.at(pos);
587 while (length > 0) {
588 for (size_t idx = 0; idx < length; idx++) {
589 ++pos;
590 char c = s.at(pos);
05fe7452
CHB
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==':')) {
bf7ef5b4 595 return true;
05fe7452 596 }
bf7ef5b4
RG
597 }
598 ++pos;
599 length = s.at(pos);
600 }
601
602 return false;
603}
ad021b69
OM
604
605// clang-format off
606const 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
639};
640
641const 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
674};
fba50923
RG
675
676DNSName::RawLabelsVisitor::RawLabelsVisitor(const DNSName::string_t& storage): d_storage(storage)
677{
678 size_t position = 0;
679 while (position < storage.size()) {
91092e26 680 auto labelLength = static_cast<uint8_t>(storage.at(position));
fba50923
RG
681 if (labelLength == 0) {
682 break;
683 }
684 d_labelPositions.at(d_position) = position;
685 d_position++;
686 position += labelLength + 1;
687 }
688}
689
690DNSName::RawLabelsVisitor DNSName::getRawLabelsVisitor() const
691{
692 return DNSName::RawLabelsVisitor(getStorage());
693}
694
695std::string_view DNSName::RawLabelsVisitor::front() const
696{
697 if (d_position == 0) {
698 throw std::out_of_range("trying to access the front of an empty DNSName::RawLabelsVisitor");
699 }
700 uint8_t length = d_storage.at(0);
701 if (length == 0) {
702 return std::string_view();
703 }
704 return std::string_view(&d_storage.at(1), length);
705}
706
707std::string_view DNSName::RawLabelsVisitor::back() const
708{
709 if (d_position == 0) {
710 throw std::out_of_range("trying to access the back of an empty DNSName::RawLabelsVisitor");
711 }
712 size_t offset = d_labelPositions.at(d_position-1);
713 uint8_t length = d_storage.at(offset);
714 if (length == 0) {
715 return std::string_view();
716 }
717 return std::string_view(&d_storage.at(offset + 1), length);
718}
719
720bool DNSName::RawLabelsVisitor::pop_back()
721{
722 if (d_position > 0) {
723 d_position--;
724 return true;
725 }
726 return false;
727}
728
729bool DNSName::RawLabelsVisitor::empty() const
730{
731 return d_position == 0;
732}