• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 12595591960

03 Jan 2025 09:27AM UTC coverage: 62.774% (+2.5%) from 60.245%
12595591960

Pull #15008

github

web-flow
Merge c2a2749d3 into 788f396a7
Pull Request #15008: Do not follow CNAME records for ANY or CNAME queries

30393 of 78644 branches covered (38.65%)

Branch coverage included in aggregate %.

105822 of 138350 relevant lines covered (76.49%)

4613078.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.31
/pdns/dnsname.cc
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
 */
22
#include "dnsname.hh"
23
#include <boost/format.hpp>
24
#include <string>
25
#include <cinttypes>
26

27
#include "dnswriter.hh"
28
#include "misc.hh"
29

30
#include <boost/functional/hash.hpp>
31

32
const DNSName g_rootdnsname("."), g_wildcarddnsname("*");
33

34
/* raw storage
35
   in DNS label format, with trailing 0. W/o trailing 0, we are 'empty'
36
   www.powerdns.com = 3www8powerdns3com0
37
*/
38

39
std::ostream & operator<<(std::ostream &os, const DNSName& d)
40
{
2,657✔
41
  return os <<d.toLogString();
2,657✔
42
}
2,657✔
43

44
void DNSName::throwSafeRangeError(const std::string& msg, const char* buf, size_t length)
45
{
27✔
46
  std::string dots;
27✔
47
  if (length > s_maxDNSNameLength) {
27✔
48
    length = s_maxDNSNameLength;
3✔
49
    dots = "...";
3✔
50
  }
3✔
51
  std::string label;
27✔
52
  DNSName::appendEscapedLabel(label, buf, length);
27✔
53
  throw std::range_error(msg + label + dots);
27✔
54
}
27✔
55

56
DNSName::DNSName(const std::string_view sw)
57
{
16,729,576✔
58
  const char* p = sw.data();
16,729,576✔
59
  size_t length = sw.length();
16,729,576✔
60

61
  if(length == 0 || (length == 1 && p[0]=='.')) {
16,754,102✔
62
    d_storage.assign(1, '\0');
322,125✔
63
  } else {
16,407,487✔
64
    if(!std::memchr(p, '\\', length)) {
16,413,846✔
65
      unsigned char lenpos=0;
15,656,403✔
66
      unsigned char labellen=0;
15,656,403✔
67
      const char* const pbegin=p, *pend=p+length;
15,656,403✔
68

69
      d_storage.reserve(length+1);
15,656,403✔
70
      for(auto iter = pbegin; iter != pend; ) {
35,366,512✔
71
        lenpos = d_storage.size();
19,710,109✔
72
        if(*iter=='.')
19,710,109✔
73
          throwSafeRangeError("Found . in wrong position in DNSName: ", p, length);
8✔
74
        d_storage.append(1, '\0');
19,710,109✔
75
        labellen=0;
19,710,109✔
76
        auto begiter=iter;
19,710,109✔
77
        for(; iter != pend && *iter!='.'; ++iter) {
127,712,868✔
78
          labellen++;
108,002,759✔
79
        }
108,002,759✔
80
        d_storage.append(begiter,iter);
19,710,109✔
81
        if(iter != pend)
19,710,109✔
82
          ++iter;
5,897,535✔
83
        if(labellen > 63)
19,710,109✔
84
          throwSafeRangeError("label too long to append: ", p, length);
7✔
85

86
        if(iter-pbegin > static_cast<ptrdiff_t>(s_maxDNSNameLength - 1)) // reserve two bytes, one for length and one for the root label
19,710,109✔
87
          throwSafeRangeError("name too long to append: ", p, length);
9✔
88

89
        d_storage[lenpos]=labellen;
19,710,109✔
90
      }
19,710,109✔
91
      d_storage.append(1, '\0');
15,656,403✔
92
    }
15,656,403✔
93
    else {
4,295,724,737✔
94
      d_storage=segmentDNSNameRaw(p, length);
4,295,724,737✔
95
      if(d_storage.size() > s_maxDNSNameLength) {
4,295,724,737!
96
        throwSafeRangeError("name too long: ", p, length);
×
97
      }
×
98
    }
4,295,724,737✔
99
  }
16,407,451✔
100
}
16,729,576✔
101

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)
103
{
1,761,907✔
104
  if (offset >= len)
1,761,907!
105
    throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
×
106

107
  if(!uncompress) {
1,761,907✔
108
    if(const void * fnd=memchr(pos+offset, 0, len-offset)) {
40,611✔
109
      d_storage.reserve(2+(const char*)fnd-(pos+offset));
40,604✔
110
    }
40,604✔
111
  }
40,602✔
112

113
  packetParser(pos, len, offset, uncompress, qtype, qclass, consumed, 0, minOffset);
1,761,907✔
114
}
1,761,907✔
115

116
static void checkLabelLength(uint8_t length)
117
{
3,666,648✔
118
  if (length == 0) {
3,666,648✔
119
    throw std::range_error("no such thing as an empty label to append");
6✔
120
  }
6✔
121
  if (length > 63) {
3,666,642✔
122
    throw std::range_error("label too long to append");
6✔
123
  }
6✔
124
}
3,666,642✔
125

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)
128
{
2,256,947✔
129
  const size_t initialPos = pos;
2,256,947✔
130
  size_t totalLength = 0;
2,256,947✔
131
  unsigned char labellen = 0;
2,256,947✔
132

133
  do {
5,810,663✔
134
    labellen = view.at(pos);
5,810,663✔
135
    ++pos;
5,810,663✔
136

137
    if (labellen == 0) {
5,810,663✔
138
      --pos;
1,750,780✔
139
      break;
1,750,780✔
140
    }
1,750,780✔
141

142
    if (labellen >= 0xc0) {
4,059,883✔
143
      if (!uncompress) {
510,262✔
144
        throw std::range_error("Found compressed label, instructed not to follow");
6✔
145
      }
6✔
146
      --pos;
510,256✔
147
      break;
510,256✔
148
    }
510,262✔
149

150
    if ((labellen & 0xc0) != 0) {
3,549,621✔
151
      throw std::range_error("Found an invalid label length in qname (only one of the first two bits is set)");
6✔
152
    }
6✔
153
    checkLabelLength(labellen);
3,549,615✔
154
    // reserve one byte for the label length
155
    if (totalLength + labellen > s_maxDNSNameLength - 1) {
3,549,615!
156
      throw std::range_error("name too long to append");
×
157
    }
×
158
    if (pos + labellen >= view.size()) {
3,549,615✔
159
      throw std::range_error("Found an invalid label length in qname");
11✔
160
    }
11✔
161
    pos += labellen;
3,549,604✔
162
    totalLength += 1 + labellen;
3,549,604✔
163
  }
3,549,604✔
164
  while (pos < view.size());
3,549,784✔
165

166
  if (totalLength != 0) {
2,256,924✔
167
    auto existingSize = d_storage.size();
1,779,990✔
168
    if (existingSize > 0) {
1,779,990✔
169
      // remove the last label count, we are about to override it */
170
      --existingSize;
47,506✔
171
    }
47,506✔
172
    d_storage.reserve(existingSize + totalLength + 1);
1,779,990✔
173
    d_storage.resize(existingSize + totalLength);
1,779,990✔
174
    memcpy(&d_storage.at(existingSize), &view.at(initialPos), totalLength);
1,779,990✔
175
    d_storage.append(1, static_cast<char>(0));
1,779,990✔
176
  }
1,779,990✔
177
  return pos;
2,256,924✔
178
}
2,256,947✔
179

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)
182
{
2,270,958✔
183
  if (offset >= len) {
2,270,958!
184
    throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
×
185
  }
×
186

187
  if (offset < static_cast<size_t>(minOffset)) {
2,270,958!
188
    throw std::range_error("Trying to read before the beginning of the buffer ("+std::to_string(offset)+ " < "+std::to_string(minOffset)+")");
×
189
  }
×
190
  unsigned char labellen{0};
2,270,958✔
191

192
  pdns::views::UnsignedCharView view(qpos, len);
2,270,958✔
193
  auto pos = parsePacketUncompressed(view, offset, uncompress);
2,270,958✔
194

195
  labellen = view.at(pos);
2,270,958✔
196
  pos++;
2,270,958✔
197
  if (labellen != 0 && pos < view.size()) {
2,270,958✔
198
    if (labellen < 0xc0) {
511,918!
199
      abort();
×
200
    }
×
201

202
    if (!uncompress) {
511,918!
203
      throw std::range_error("Found compressed label, instructed not to follow");
×
204
    }
×
205

206
    labellen &= (~0xc0);
511,918✔
207
    size_t newpos = (labellen << 8) + view.at(pos);
511,918✔
208

209
    if (newpos >= offset) {
511,918✔
210
      throw std::range_error("Found a forward reference during label decompression");
16✔
211
    }
16✔
212

213
    if (newpos < minOffset) {
511,902!
214
      throw std::range_error("Invalid label position during decompression ("+std::to_string(newpos)+ " < "+std::to_string(minOffset)+")");
×
215
    }
×
216

217
    if (++depth > 100) {
511,902!
218
      throw std::range_error("Abort label decompression after 100 redirects");
×
219
    }
×
220

221
    packetParser(qpos, len, newpos, true, nullptr, nullptr, nullptr, depth, minOffset);
511,902✔
222

223
    pos++;
511,902✔
224
  }
511,902✔
225

226
  if (d_storage.empty()) {
2,270,942✔
227
    d_storage.append(1, static_cast<char>(0)); // we just parsed the root
17,094✔
228
  }
17,094✔
229

230
  if (consumed != nullptr) {
2,270,942✔
231
    *consumed = pos - offset;
1,708,811✔
232
  }
1,708,811✔
233

234
  if (qtype != nullptr) {
2,270,942✔
235
    if (pos + 2 > view.size()) {
40,375!
236
      throw std::range_error("Trying to read qtype past the end of the buffer ("+std::to_string(pos + 2)+ " > "+std::to_string(len)+")");
×
237
    }
×
238
    *qtype = view.at(pos)*256 + view.at(pos+1);
40,375✔
239
  }
40,375✔
240

241
  pos += 2;
2,270,942✔
242
  if (qclass != nullptr) {
2,270,942✔
243
    if (pos + 2 > view.size()) {
32,699✔
244
      throw std::range_error("Trying to read qclass past the end of the buffer ("+std::to_string(pos + 2)+ " > "+std::to_string(len)+")");
6✔
245
    }
6✔
246
    *qclass = view.at(pos)*256 + view.at(pos+1);
32,693✔
247
  }
32,693✔
248
}
2,270,942✔
249

250
std::string DNSName::toString(const std::string& separator, const bool trailing) const
251
{
980,411✔
252
  std::string ret;
980,411✔
253
  toString(ret, separator, trailing);
980,411✔
254
  return ret;
980,411✔
255
}
980,411✔
256

257
void DNSName::toString(std::string& output, const std::string& separator, const bool trailing) const
258
{
980,591✔
259
  if (empty()) {
980,591✔
260
    throw std::out_of_range("Attempt to print an unset dnsname");
6✔
261
  }
6✔
262

263
  if (isRoot()) {
980,585✔
264
    output += (trailing ? separator : "");
1,805!
265
    return;
1,805✔
266
  }
1,805✔
267

268
  if (output.capacity() < (output.size() + d_storage.size())) {
978,780✔
269
    output.reserve(output.size() + d_storage.size());
120,194✔
270
  }
120,194✔
271

272
  {
978,780✔
273
    // iterate over the raw labels
274
    const char* p = d_storage.c_str();
978,780✔
275
    const char* end = p + d_storage.size();
978,780✔
276

277
    while (p < end && *p) {
3,030,917✔
278
      appendEscapedLabel(output, p + 1, static_cast<size_t>(*p));
2,052,136✔
279
      output += separator;
2,052,136✔
280
      p += *p + 1;
2,052,136✔
281
    }
2,052,136✔
282
  }
978,780✔
283

284
  if (!trailing) {
978,784✔
285
    output.resize(output.size() - separator.size());
128,098✔
286
  }
128,098✔
287
}
978,780✔
288

289
std::string DNSName::toLogString() const
290
{
147,415✔
291
  if (empty()) {
147,415✔
292
    return "(empty)";
195✔
293
  }
195✔
294

295
  return toStringRootDot();
147,220✔
296
}
147,415✔
297

298
std::string DNSName::toDNSString() const
299
{
1,031,681✔
300
  if (empty()) {
1,031,681✔
301
    throw std::out_of_range("Attempt to DNSString an unset dnsname");
3✔
302
  }
3✔
303

304
  return std::string(d_storage.c_str(), d_storage.length());
1,031,678✔
305
}
1,031,681✔
306

307
std::string DNSName::toDNSStringLC() const
308
{
1,031,461✔
309
  auto result = toDNSString();
1,031,461✔
310
  toLowerInPlace(result); // label lengths are always < 'A'
1,031,461✔
311
  return result;
1,031,461✔
312
}
1,031,461✔
313

314
/**
315
 * Get the length of the DNSName on the wire
316
 *
317
 * @return the total wirelength of the DNSName
318
 */
319
size_t DNSName::wirelength() const {
8,401,917✔
320
  return d_storage.length();
8,401,917✔
321
}
8,401,917✔
322

323
// Are WE part of parent
324
bool DNSName::isPartOf(const DNSName& parent) const
325
{
1,101,340✔
326
  if(parent.empty() || empty()) {
1,101,352✔
327
    throw std::out_of_range("empty dnsnames aren't part of anything");
6✔
328
  }
6✔
329

330
  if(parent.d_storage.size() > d_storage.size()) {
1,101,334✔
331
    return false;
15,118✔
332
  }
15,118✔
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
335
  for(auto us=d_storage.cbegin(); us<d_storage.cend(); us+=*us+1) {
2,900,955✔
336
    auto distance = std::distance(us,d_storage.cend());
2,900,947✔
337
    if (distance < 0 || static_cast<size_t>(distance) < parent.d_storage.size()) {
2,900,978✔
338
      break;
26,242✔
339
    }
26,242✔
340
    if (static_cast<size_t>(distance) == parent.d_storage.size()) {
2,874,705✔
341
      auto p = parent.d_storage.cbegin();
1,059,985✔
342
      for(; us != d_storage.cend(); ++us, ++p) {
4,901,154✔
343
        if(dns_tolower(*p) != dns_tolower(*us))
3,862,741✔
344
          return false;
21,572✔
345
      }
3,862,741✔
346
      return true;
1,038,413✔
347
    }
1,059,985✔
348
    if (static_cast<uint8_t>(*us) > 63) {
1,814,720!
349
      throw std::out_of_range("illegal label length in dnsname");
×
350
    }
×
351
  }
1,814,720✔
352
  return false;
26,231✔
353
}
1,086,216✔
354

355
DNSName DNSName::makeRelative(const DNSName& zone) const
356
{
2,264✔
357
  DNSName ret(*this);
2,264✔
358
  ret.makeUsRelative(zone);
2,264✔
359
  return ret;
2,264✔
360
}
2,264✔
361

362
void DNSName::makeUsRelative(const DNSName& zone)
363
{
2,410✔
364
  if (isPartOf(zone)) {
2,410!
365
    d_storage.erase(d_storage.size()-zone.d_storage.size());
2,410✔
366
    d_storage.append(1, static_cast<char>(0)); // put back the trailing 0
2,410✔
367
  }
2,410✔
368
  else {
×
369
    clear();
×
370
  }
×
371
}
2,410✔
372

373
DNSName DNSName::getCommonLabels(const DNSName& other) const
374
{
206✔
375
  if (empty() || other.empty()) {
206✔
376
    return DNSName();
6✔
377
  }
6✔
378

379
  DNSName result(g_rootdnsname);
200✔
380

381
  const std::vector<std::string> ours = getRawLabels();
200✔
382
  const std::vector<std::string> others = other.getRawLabels();
200✔
383

384
  for (size_t pos = 0; ours.size() > pos && others.size() > pos; pos++) {
644✔
385
    const std::string& ourLabel = ours.at(ours.size() - pos - 1);
625✔
386
    const std::string& otherLabel = others.at(others.size() - pos - 1);
625✔
387

388
    if (!pdns_iequals(ourLabel, otherLabel)) {
625✔
389
      break;
181✔
390
    }
181✔
391

392
    result.prependRawLabel(ourLabel);
444✔
393
  }
444✔
394

395
  return result;
200✔
396
}
206✔
397

398
DNSName DNSName::labelReverse() const
399
{
6✔
400
  DNSName ret;
6✔
401

402
  if (isRoot()) {
6!
403
    return *this; // we don't create the root automatically below
×
404
  }
×
405

406
  if (!empty()) {
6!
407
    vector<string> l=getRawLabels();
6✔
408
    while(!l.empty()) {
27✔
409
      ret.appendRawLabel(l.back());
21✔
410
      l.pop_back();
21✔
411
    }
21✔
412
  }
6✔
413
  return ret;
6✔
414
}
6✔
415

416
void DNSName::appendRawLabel(const std::string& label)
417
{
17,961✔
418
  appendRawLabel(label.c_str(), label.length());
17,961✔
419
}
17,961✔
420

421
void DNSName::appendRawLabel(const char* start, unsigned int length)
422
{
17,961✔
423
  checkLabelLength(length);
17,961✔
424

425
  // reserve one byte for the label length
426
  if (d_storage.size() + length > s_maxDNSNameLength - 1) {
17,961✔
427
    throw std::range_error("name too long to append");
3✔
428
  }
3✔
429

430
  if (d_storage.empty()) {
17,958✔
431
    d_storage.reserve(1 + length + 1);
4,371✔
432
    d_storage.append(1, static_cast<char>(length));
4,371✔
433
  }
4,371✔
434
  else {
13,587✔
435
    d_storage.reserve(d_storage.size() + length + 1);
13,587✔
436
    *d_storage.rbegin() = static_cast<char>(length);
13,587✔
437
  }
13,587✔
438
  d_storage.append(start, length);
17,958✔
439
  d_storage.append(1, static_cast<char>(0));
17,958✔
440
}
17,958✔
441

442
void DNSName::prependRawLabel(const std::string& label)
443
{
111,680✔
444
  checkLabelLength(label.size());
111,680✔
445

446
  // reserve one byte for the label length
447
  if (d_storage.size() + label.size() > s_maxDNSNameLength - 1) {
111,680✔
448
    throw std::range_error("name too long to prepend");
3✔
449
  }
3✔
450

451
  if (d_storage.empty()) {
111,677!
452
    d_storage.reserve(1 + label.size() + 1);
×
453
    d_storage.append(1, static_cast<char>(0));
×
454
  }
×
455
  else {
111,677✔
456
    d_storage.reserve(d_storage.size() + 1 + label.size());
111,677✔
457
  }
111,677✔
458

459
  string_t prep(1, static_cast<char>(label.size()));
111,677✔
460
  prep.append(label.c_str(), label.size());
111,677✔
461
  d_storage = prep+d_storage;
111,677✔
462
}
111,677✔
463

464
bool DNSName::slowCanonCompare(const DNSName& rhs) const
465
{
×
466
  auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels();
×
467
  return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare());
×
468
}
×
469

470
vector<std::string> DNSName::getRawLabels() const
471
{
56,683✔
472
  vector<std::string> ret;
56,683✔
473
  ret.reserve(countLabels());
56,683✔
474
  // 3www4ds9a2nl0
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) {
204,245✔
476
    ret.push_back({(const char*)p+1, (size_t)*p}); // XXX FIXME
147,561✔
477
  }
147,561✔
478
  return ret;
56,683✔
479
}
56,683✔
480

481
std::string DNSName::getRawLabel(unsigned int pos) const
482
{
52,104✔
483
  unsigned int currentPos = 0;
52,104✔
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++) {
59,038✔
485
    if (currentPos == pos) {
59,035✔
486
      return std::string((const char*)p+1, (size_t)*p);
52,102✔
487
    }
52,102✔
488
  }
59,035✔
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");
2,147,483,650✔
491
}
52,104✔
492

493
DNSName DNSName::getLastLabel() const
494
{
22,257✔
495
  DNSName ret(*this);
22,257✔
496
  ret.trimToLabels(1);
22,257✔
497
  return ret;
22,257✔
498
}
22,257✔
499

500
bool DNSName::chopOff()
501
{
465,187✔
502
  if (d_storage.empty() || d_storage[0]==0) {
465,190✔
503
    return false;
102,907✔
504
  }
102,907✔
505
  d_storage.erase(0, (unsigned int)d_storage[0]+1);
362,280✔
506
  return true;
362,280✔
507
}
465,187✔
508

509
bool DNSName::isWildcard() const
510
{
19,732✔
511
  if (d_storage.size() < 2) {
19,732✔
512
    return false;
373✔
513
  }
373✔
514
  auto p = d_storage.begin();
19,359✔
515
  return (*p == 0x01 && *++p == '*');
19,359✔
516
}
19,732✔
517

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
 */
522
bool DNSName::isHostname() const
523
{
26✔
524
  static Regex hostNameRegex = Regex("^(([A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)\\.)+$");
26✔
525
  return hostNameRegex.match(this->toString());
26✔
526
}
26✔
527

528
unsigned int DNSName::countLabels() const
529
{
224,871✔
530
  unsigned int count=0;
224,871✔
531
  const unsigned char* p = reinterpret_cast<const unsigned char*>(d_storage.c_str());
224,871✔
532
  const unsigned char* end = reinterpret_cast<const unsigned char*>(p + d_storage.size());
224,871✔
533

534
  while (p < end && *p) {
726,409✔
535
    ++count;
501,537✔
536
    p += *p + 1;
501,537✔
537
  }
501,537✔
538
  return count;
224,871✔
539
}
224,871✔
540

541
void DNSName::trimToLabels(unsigned int to)
542
{
22,260✔
543
  while(countLabels() > to && chopOff()) {
56,670✔
544
    ;
34,410✔
545
  }
34,410✔
546
}
22,260✔
547

548

549
size_t hash_value(DNSName const& d)
550
{
5,197,400✔
551
  return d.hash();
5,197,400✔
552
}
5,197,400✔
553

554
void DNSName::appendEscapedLabel(std::string& appendTo, const char* orig, size_t len)
555
{
2,052,167✔
556
  size_t pos = 0;
2,052,167✔
557

558
  while (pos < len) {
13,507,337✔
559
    auto p = static_cast<uint8_t>(orig[pos]);
11,455,170✔
560
    if (p=='.') {
11,455,170✔
561
      appendTo+="\\.";
130✔
562
    }
130✔
563
    else if (p=='\\') {
11,455,040✔
564
      appendTo+="\\\\";
3✔
565
    }
3✔
566
    else if (p > 0x20 && p < 0x7f) {
11,455,049✔
567
      appendTo.append(1, static_cast<char>(p));
10,652,761✔
568
    }
10,652,761✔
569
    else {
2,148,285,933✔
570
      char buf[] = "000";
2,148,285,933✔
571
      auto got = snprintf(buf, sizeof(buf), "%03" PRIu8, p);
2,148,285,933✔
572
      if (got < 0 || static_cast<size_t>(got) >= sizeof(buf)) {
2,148,285,933!
573
        throw std::runtime_error("Error, snprintf returned " + std::to_string(got) + " while escaping label " + std::string(orig, len));
×
574
      }
×
575
      appendTo.append(1, '\\');
2,148,285,933✔
576
      appendTo += buf;
2,148,285,933✔
577
    }
2,148,285,933✔
578
    ++pos;
11,455,170✔
579
  }
11,455,170✔
580
}
2,052,167✔
581

582
bool 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);
×
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==':')) {
×
595
        return true;
×
596
      }
×
597
    }
×
598
    ++pos;
×
599
    length = s.at(pos);
×
600
  }
×
601

602
  return false;
×
603
}
×
604

605
// clang-format off
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
639
};
640

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
674
};
675

676
DNSName::RawLabelsVisitor::RawLabelsVisitor(const DNSName::string_t& storage): d_storage(storage)
677
{
56,392✔
678
  size_t position = 0;
56,392✔
679
  while (position < storage.size()) {
197,267✔
680
    auto labelLength = static_cast<uint8_t>(storage.at(position));
197,266✔
681
    if (labelLength == 0) {
197,266✔
682
      break;
56,392✔
683
    }
56,392✔
684
    d_labelPositions.at(d_position) = position;
140,874✔
685
    d_position++;
140,874✔
686
    position += labelLength + 1;
140,874✔
687
  }
140,874✔
688
}
56,392✔
689

690
DNSName::RawLabelsVisitor DNSName::getRawLabelsVisitor() const
691
{
56,393✔
692
  return DNSName::RawLabelsVisitor(getStorage());
56,393✔
693
}
56,393✔
694

695
std::string_view DNSName::RawLabelsVisitor::front() const
696
{
6✔
697
  if (d_position == 0) {
6✔
698
    throw std::out_of_range("trying to access the front of an empty DNSName::RawLabelsVisitor");
3✔
699
  }
3✔
700
  uint8_t length = d_storage.at(0);
3✔
701
  if (length == 0) {
3!
702
    return std::string_view();
×
703
  }
×
704
  return std::string_view(&d_storage.at(1), length);
3✔
705
}
3✔
706

707
std::string_view DNSName::RawLabelsVisitor::back() const
708
{
125,124✔
709
  if (d_position == 0) {
125,124✔
710
    throw std::out_of_range("trying to access the back of an empty DNSName::RawLabelsVisitor");
3✔
711
  }
3✔
712
  size_t offset = d_labelPositions.at(d_position-1);
125,121✔
713
  uint8_t length = d_storage.at(offset);
125,121✔
714
  if (length == 0) {
125,121!
715
    return std::string_view();
×
716
  }
×
717
  return std::string_view(&d_storage.at(offset + 1), length);
125,121✔
718
}
125,121✔
719

720
bool DNSName::RawLabelsVisitor::pop_back()
721
{
111,825✔
722
  if (d_position > 0) {
111,825✔
723
    d_position--;
111,822✔
724
    return true;
111,822✔
725
  }
111,822✔
726
  return false;
3✔
727
}
111,825✔
728

729
bool DNSName::RawLabelsVisitor::empty() const
730
{
168,205✔
731
  return d_position == 0;
168,205✔
732
}
168,205✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc