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

PowerDNS / pdns / 12321902803

13 Dec 2024 07:34PM UTC coverage: 66.359% (+1.6%) from 64.78%
12321902803

Pull #14970

github

web-flow
Merge e3a7df61c into 3dfd8e317
Pull Request #14970: boost > std optional

26084 of 54744 branches covered (47.65%)

Branch coverage included in aggregate %.

14 of 15 new or added lines in 2 files covered. (93.33%)

1863 existing lines in 52 files now uncovered.

85857 of 113946 relevant lines covered (75.35%)

4412729.59 hits per line

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

77.91
/pdns/dnsparser.hh
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
#pragma once
23
#include <atomic>
24
#include <map>
25
#include <sstream>
26
#include <stdexcept>
27
#include <iostream>
28
#include <unordered_set>
29
#include <utility>
30
#include <vector>
31
#include <cerrno>
32
// #include <netinet/in.h>
33
#include "misc.hh"
34

35
#include "dns.hh"
36
#include "dnswriter.hh"
37
#include "dnsname.hh"
38
#include "noinitvector.hh"
39
#include "pdnsexception.hh"
40
#include "iputils.hh"
41
#include "svc-records.hh"
42

43
/** DNS records have three representations:
44
    1) in the packet
45
    2) parsed in a class, ready for use
46
    3) in the zone
47

48
    We should implement bidirectional transitions between 1&2 and 2&3.
49
    Currently we have: 1 -> 2
50
                       2 -> 3
51

52
    We can add:        2 -> 1  easily by reversing the packetwriter
53
    And we might be able to reverse 2 -> 3 as well
54
*/
55

56
#include "namespaces.hh"
57

58
class MOADNSException : public runtime_error
59
{
60
public:
61
  MOADNSException(const string& str) : runtime_error(str)
62
  {}
82✔
63
};
64

65

66
class MOADNSParser;
67

68
class PacketReader
69
{
70
public:
71
  PacketReader(const std::string_view& content, uint16_t initialPos=sizeof(dnsheader))
72
    : d_pos(initialPos), d_startrecordpos(initialPos), d_content(content)
73
  {
1,396,891✔
74
    if(content.size() > std::numeric_limits<uint16_t>::max())
1,396,891!
75
      throw std::out_of_range("packet too large");
×
76

77
    d_recordlen = (uint16_t) content.size();
1,396,891✔
78
    not_used = 0;
1,396,891✔
79
  }
1,396,891✔
80

81
  uint32_t get32BitInt();
82
  uint16_t get16BitInt();
83
  uint8_t get8BitInt();
84

85
  void xfrNodeOrLocatorID(NodeOrLocatorID& val);
86
  void xfr48BitInt(uint64_t& val);
87

88
  void xfr32BitInt(uint32_t& val)
89
  {
3,183,653✔
90
    val=get32BitInt();
3,183,653✔
91
  }
3,183,653✔
92

93
  void xfrIP(uint32_t& val)
94
  {
903,192✔
95
    xfr32BitInt(val);
903,192✔
96
    val=htonl(val);
903,192✔
97
  }
903,192✔
98

99
  void xfrIP6(std::string &val) {
12,458✔
100
    xfrBlob(val, 16);
12,458✔
101
  }
12,458✔
102

103
  void xfrCAWithoutPort(uint8_t version, ComboAddress &val) {
35✔
104
    string blob;
35✔
105
    if (version == 4) xfrBlob(blob, 4);
35✔
106
    else if (version == 6) xfrBlob(blob, 16);
15!
107
    else throw runtime_error("invalid IP protocol");
×
108
    val = makeComboAddressFromRaw(version, blob);
35✔
109
  }
35✔
110

111
  void xfrCAPort(ComboAddress &val) {
×
112
    uint16_t port;
×
113
    xfr16BitInt(port);
×
114
    val.sin4.sin_port = port;
×
115
  }
×
116

117
  void xfrTime(uint32_t& val)
118
  {
1,472,012✔
119
    xfr32BitInt(val);
1,472,012✔
120
  }
1,472,012✔
121

122

123
  void xfr16BitInt(uint16_t& val)
124
  {
1,753,137✔
125
    val=get16BitInt();
1,753,137✔
126
  }
1,753,137✔
127

128
  void xfrType(uint16_t& val)
129
  {
736,006✔
130
    xfr16BitInt(val);
736,006✔
131
  }
736,006✔
132

133

134
  void xfr8BitInt(uint8_t& val)
135
  {
2,515,705✔
136
    val=get8BitInt();
2,515,705✔
137
  }
2,515,705✔
138

139
  void xfrName(DNSName& name, bool /* compress */ = false, bool /* noDot */ = false)
140
  {
915,978✔
141
    name = getName();
915,978✔
142
  }
915,978✔
143

144
  void xfrText(string &text, bool multi=false, bool lenField=true)
145
  {
6,127✔
146
    text=getText(multi, lenField);
6,127✔
147
  }
6,127✔
148

149
  void xfrUnquotedText(string &text, bool lenField){
21✔
150
    text=getUnquotedText(lenField);
21✔
151
  }
21✔
152

153
  void xfrBlob(string& blob);
154
  void xfrBlobNoSpaces(string& blob, int len);
155
  void xfrBlob(string& blob, int length);
156
  void xfrHexBlob(string& blob, bool keepReading=false);
157
  void xfrSvcParamKeyVals(set<SvcParam> &kvs);
158

159
  void getDnsrecordheader(struct dnsrecordheader &ah);
160
  void copyRecord(vector<unsigned char>& dest, uint16_t len);
161
  void copyRecord(unsigned char* dest, uint16_t len);
162

163
  DNSName getName();
164
  string getText(bool multi, bool lenField);
165
  string getUnquotedText(bool lenField);
166

167

168
  bool eof() { return true; };
1,856,544✔
169
  const string getRemaining() const {
×
170
    return "";
×
171
  };
×
172

173
  uint16_t getPosition() const
174
  {
2,212,806✔
175
    return d_pos;
2,212,806✔
176
  }
2,212,806✔
177

178
  void skip(uint16_t n)
UNCOV
179
  {
×
UNCOV
180
    d_pos += n;
×
UNCOV
181
  }
×
182

183
private:
184
  uint16_t d_pos;
185
  uint16_t d_startrecordpos; // needed for getBlob later on
186
  uint16_t d_recordlen;      // ditto
187
  uint16_t not_used; // Aligns the whole class on 8-byte boundaries
188
  const std::string_view d_content;
189
};
190

191
struct DNSRecord;
192

193
class DNSRecordContent
194
{
195
public:
196
  static std::shared_ptr<DNSRecordContent> make(const DNSRecord& dr, PacketReader& pr);
197
  static std::shared_ptr<DNSRecordContent> make(const DNSRecord& dr, PacketReader& pr, uint16_t opcode);
198
  static std::shared_ptr<DNSRecordContent> make(uint16_t qtype, uint16_t qclass, const string& zone);
199
  static string upgradeContent(const DNSName& qname, const QType& qtype, const string& content);
200

201
  virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
202
  virtual ~DNSRecordContent() = default;
12,791,472✔
203
  virtual void toPacket(DNSPacketWriter& pw) const = 0;
204
  // returns the wire format of the content, possibly including compressed pointers pointing to the owner name (unless canonic or lowerCase are set)
205
  string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) const
206
  {
3,977,144✔
207
    vector<uint8_t> packet;
3,977,144✔
208
    DNSPacketWriter pw(packet, g_rootdnsname, 1);
3,977,144✔
209
    if(canonic)
3,977,144✔
210
      pw.setCanonic(true);
2,554,348✔
211

212
    if(lowerCase)
3,977,144✔
213
      pw.setLowercase(true);
2,432,237✔
214

215
    pw.startRecord(qname, this->getType());
3,977,144✔
216
    this->toPacket(pw);
3,977,144✔
217

218
    string record;
3,977,144✔
219
    pw.getRecordPayload(record); // needs to be called before commit()
3,977,144✔
220
    return record;
3,977,144✔
221
  }
3,977,144✔
222

223
  virtual bool operator==(const DNSRecordContent& rhs) const
224
  {
5,572✔
225
    return typeid(*this)==typeid(rhs) && this->getZoneRepresentation() == rhs.getZoneRepresentation();
5,572!
226
  }
5,572✔
227

228
  // parse the content in wire format, possibly including compressed pointers pointing to the owner name
229
  static shared_ptr<DNSRecordContent> deserialize(const DNSName& qname, uint16_t qtype, const string& serialized, uint16_t qclass=QClass::IN);
230

231
  void doRecordCheck(const struct DNSRecord&){}
953,836✔
232

233
  typedef std::shared_ptr<DNSRecordContent> makerfunc_t(const struct DNSRecord& dr, PacketReader& pr);
234
  typedef std::shared_ptr<DNSRecordContent> zmakerfunc_t(const string& str);
235

236
  static void regist(uint16_t cl, uint16_t ty, makerfunc_t* f, zmakerfunc_t* z, const char* name)
237
  {
3,170,648✔
238
    assert(!d_locked.load()); // NOLINT: it's the API
3,170,648✔
239
    if(f)
3,170,648✔
240
      getTypemap()[pair(cl,ty)]=f;
3,085,703✔
241
    if(z)
3,170,648✔
242
      getZmakermap()[pair(cl,ty)]=z;
3,085,703✔
243

244
    getT2Namemap().emplace(pair(cl, ty), name);
3,170,648✔
245
    getN2Typemap().emplace(name, pair(cl, ty));
3,170,648✔
246
  }
3,170,648✔
247

248
  static bool isUnknownType(const string& name)
249
  {
23,924✔
250
    return boost::starts_with(name, "TYPE") || boost::starts_with(name, "type");
23,924✔
251
  }
23,924✔
252

253
  static uint16_t TypeToNumber(const string& name)
254
  {
5,342,951✔
255
    n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name));
5,342,951✔
256
    if(iter != getN2Typemap().end())
5,342,951✔
257
      return iter->second.second;
5,342,104✔
258

259
    if (isUnknownType(name)) {
847✔
260
      return pdns::checked_stoi<uint16_t>(name.substr(4));
844✔
261
    }
844✔
262

263
    throw runtime_error("Unknown DNS type '"+name+"'");
3✔
264
  }
847✔
265

266
  static const string NumberToType(uint16_t num, uint16_t classnum = QClass::IN)
267
  {
2,265,812✔
268
    auto iter = getT2Namemap().find(pair(classnum, num));
2,265,812✔
269
    if(iter == getT2Namemap().end())
2,265,812✔
270
      return "TYPE" + std::to_string(num);
393,691✔
271
      //      throw runtime_error("Unknown DNS type with numerical id "+std::to_string(num));
272
    return iter->second;
1,872,121✔
273
  }
2,265,812✔
274

275
  /**
276
   * \brief Return whether we have implemented a content representation for this type
277
   */
278
  static bool isRegisteredType(uint16_t rtype, uint16_t rclass = QClass::IN);
279

280
  virtual uint16_t getType() const = 0;
281

282
  static void lock()
283
  {
28,315✔
284
    d_locked.store(true);
28,315✔
285
  }
28,315✔
286

287
protected:
288
  typedef std::map<std::pair<uint16_t, uint16_t>, makerfunc_t* > typemap_t;
289
  typedef std::map<std::pair<uint16_t, uint16_t>, zmakerfunc_t* > zmakermap_t;
290
  typedef std::map<std::pair<uint16_t, uint16_t>, string > t2namemap_t;
291
  typedef std::map<string, std::pair<uint16_t, uint16_t> > n2typemap_t;
292
  static typemap_t& getTypemap();
293
  static t2namemap_t& getT2Namemap();
294
  static n2typemap_t& getN2Typemap();
295
  static zmakermap_t& getZmakermap();
296
  static std::atomic<bool> d_locked;
297
};
298

299
struct DNSRecord
300
{
301
  DNSRecord() :
302
    d_class(QClass::IN)
303
  {}
4,792,135✔
304
  explicit DNSRecord(const DNSResourceRecord& rr);
305
  DNSRecord(const std::string& name,
306
            std::shared_ptr<DNSRecordContent> content,
307
            const uint16_t type,
308
            const uint16_t qclass = QClass::IN,
309
            const uint32_t ttl = 86400,
310
            const uint16_t clen = 0,
311
            const DNSResourceRecord::Place place = DNSResourceRecord::ANSWER) :
312
    d_name(DNSName(name)),
313
    d_content(std::move(content)),
314
    d_type(type),
315
    d_class(qclass),
316
    d_ttl(ttl),
317
    d_clen(clen),
318
    d_place(place) {}
296✔
319

320
  DNSName d_name;
321
private:
322
  std::shared_ptr<const DNSRecordContent> d_content;
323
public:
324
  uint16_t d_type{};
325
  uint16_t d_class{};
326
  uint32_t d_ttl{};
327
  uint16_t d_clen{};
328
  DNSResourceRecord::Place d_place{DNSResourceRecord::ANSWER};
329

330
  [[nodiscard]] std::string print(const std::string& indent = "") const
331
  {
536✔
332
    std::stringstream s;
536✔
333
    s << indent << "Content = " << d_content->getZoneRepresentation() << std::endl;
536✔
334
    s << indent << "Type = " << d_type << std::endl;
536✔
335
    s << indent << "Class = " << d_class << std::endl;
536✔
336
    s << indent << "TTL = " << d_ttl << std::endl;
536✔
337
    s << indent << "clen = " << d_clen << std::endl;
536✔
338
    s << indent << "Place = " << std::to_string(d_place) << std::endl;
536✔
339
    return s.str();
536✔
340
  }
536✔
341

342
  [[nodiscard]] std::string toString() const
343
  {
826✔
344
    std::string ret(d_name.toLogString());
826✔
345
    ret += '|';
826✔
346
    ret += QType(d_type).toString();
826✔
347
    ret += '|';
826✔
348
    ret += getContent()->getZoneRepresentation();
826✔
349
    return ret;
826✔
350
  }
826✔
351

352
  void setContent(const std::shared_ptr<const DNSRecordContent>& content)
353
  {
712,501✔
354
    d_content = content;
712,501✔
355
  }
712,501✔
356

357
  void setContent(std::shared_ptr<const DNSRecordContent>&& content)
358
  {
3,924,235✔
359
    d_content = std::move(content);
3,924,235✔
360
  }
3,924,235✔
361

362
  [[nodiscard]] const std::shared_ptr<const DNSRecordContent>& getContent() const
363
  {
7,889,807✔
364
    return d_content;
7,889,807✔
365
  }
7,889,807✔
366

367
  bool operator<(const DNSRecord& rhs) const
368
  {
×
369
    if(std::tie(d_name, d_type, d_class, d_ttl) < std::tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl))
×
370
      return true;
×
371

×
372
    if(std::tie(d_name, d_type, d_class, d_ttl) != std::tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl))
×
373
      return false;
×
374

×
375
    string lzrp, rzrp;
×
376
    if(d_content)
×
377
      lzrp=toLower(d_content->getZoneRepresentation());
×
378
    if(rhs.d_content)
×
379
      rzrp=toLower(rhs.d_content->getZoneRepresentation());
×
380

×
381
    return lzrp < rzrp;
×
382
  }
×
383

384
  // this orders in canonical order and keeps the SOA record on top
385
  static bool prettyCompare(const DNSRecord& a, const DNSRecord& b)
386
  {
×
387
    auto aType = (a.d_type == QType::SOA) ? 0 : a.d_type;
×
388
    auto bType = (b.d_type == QType::SOA) ? 0 : b.d_type;
×
389

×
390
    if(a.d_name.canonCompare(b.d_name))
×
391
      return true;
×
392
    if(b.d_name.canonCompare(a.d_name))
×
393
      return false;
×
394

×
395
    if(std::tie(aType, a.d_class, a.d_ttl) < std::tie(bType, b.d_class, b.d_ttl))
×
396
      return true;
×
397

×
398
    if(std::tie(aType, a.d_class, a.d_ttl) != std::tie(bType, b.d_class, b.d_ttl))
×
399
      return false;
×
400

×
401
    string lzrp, rzrp;
×
402
    if(a.d_content)
×
403
      lzrp = a.d_content->getZoneRepresentation();
×
404
    if(b.d_content)
×
405
      rzrp = b.d_content->getZoneRepresentation();
×
406

×
407
    switch (a.d_type) {
×
408
    case QType::TXT:
×
409
    case QType::SPF:
×
410
#if !defined(RECURSOR)
×
411
    case QType::LUA:
×
412
#endif
×
413
      return lzrp < rzrp;
×
414
    default:
×
415
      return toLower(lzrp) < toLower(rzrp);
×
416
    }
×
417
  }
×
418

419
  bool operator==(const DNSRecord& rhs) const
420
  {
15,170✔
421
    if (d_type != rhs.d_type || d_class != rhs.d_class || d_name != rhs.d_name) {
15,170!
422
      return false;
9,234✔
423
    }
9,234✔
424

425
    return *d_content == *rhs.d_content;
5,936✔
426
  }
15,170✔
427
};
428

429
struct DNSZoneRecord
430
{
431
  int domain_id{-1};
432
  uint8_t scopeMask{0};
433
  int signttl{0};
434
  DNSName wildcardname;
435
  bool auth{true};
436
  bool disabled{false};
437
  DNSRecord dr;
438
};
439

440
class UnknownRecordContent : public DNSRecordContent
441
{
442
public:
443
  UnknownRecordContent(const DNSRecord& dr, PacketReader& pr)
444
    : d_dr(dr)
445
  {
3,991✔
446
    pr.copyRecord(d_record, dr.d_clen);
3,991✔
447
  }
3,991✔
448

449
  UnknownRecordContent(const string& zone);
450

451
  string getZoneRepresentation(bool noDot) const override;
452
  void toPacket(DNSPacketWriter& pw) const override;
453
  uint16_t getType() const override
454
  {
909✔
455
    return d_dr.d_type;
909✔
456
  }
909✔
457

458
  const vector<uint8_t>& getRawContent() const
UNCOV
459
  {
×
UNCOV
460
    return d_record;
×
UNCOV
461
  }
×
462

463
private:
464
  DNSRecord d_dr;
465
  vector<uint8_t> d_record;
466
};
467

468
//! This class can be used to parse incoming packets, and is copyable
469
class MOADNSParser : public boost::noncopyable
470
{
471
public:
472
  //! Parse from a string
473
  MOADNSParser(bool query, const string& buffer): d_tsigPos(0)
474
  {
1,338,704✔
475
    init(query, buffer);
1,338,704✔
476
  }
1,338,704✔
477

478
  //! Parse from a pointer and length
479
  MOADNSParser(bool query, const char *packet, unsigned int len) : d_tsigPos(0)
480
  {
28,613✔
481
    init(query, std::string_view(packet, len));
28,613✔
482
  }
28,613✔
483

484
  DNSName d_qname;
485
  uint16_t d_qclass, d_qtype;
486
  dnsheader d_header;
487

488
  using answers_t = vector<DNSRecord>;
489

490
  //! All answers contained in this packet (everything *but* the question section)
491
  answers_t d_answers;
492

493
  uint16_t getTSIGPos() const
494
  {
1,298,380✔
495
    return d_tsigPos;
1,298,380✔
496
  }
1,298,380✔
497

498
  bool hasEDNS() const;
499

500
private:
501
  void init(bool query, const std::string_view& packet);
502
  uint16_t d_tsigPos;
503
};
504

505
string simpleCompress(const string& label, const string& root="");
506
void ageDNSPacket(char* packet, size_t length, uint32_t seconds, const dnsheader_aligned&);
507
void ageDNSPacket(std::string& packet, uint32_t seconds, const dnsheader_aligned&);
508
void editDNSPacketTTL(char* packet, size_t length, const std::function<uint32_t(uint8_t, uint16_t, uint16_t, uint32_t)>& visitor);
509
void clearDNSPacketRecordTypes(vector<uint8_t>& packet, const std::unordered_set<QType>& qtypes);
510
void clearDNSPacketRecordTypes(PacketBuffer& packet, const std::unordered_set<QType>& qtypes);
511
void clearDNSPacketRecordTypes(char* packet, size_t& length, const std::unordered_set<QType>& qtypes);
512
uint32_t getDNSPacketMinTTL(const char* packet, size_t length, bool* seenAuthSOA=nullptr);
513
uint32_t getDNSPacketLength(const char* packet, size_t length);
514
uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type);
515
bool getEDNSUDPPayloadSizeAndZ(const char* packet, size_t length, uint16_t* payloadSize, uint16_t* z);
516
/* call the visitor for every records in the answer, authority and additional sections, passing the section, class, type, ttl, rdatalength and rdata
517
   to the visitor. Stops whenever the visitor returns false or at the end of the packet */
518
bool visitDNSPacket(const std::string_view& packet, const std::function<bool(uint8_t, uint16_t, uint16_t, uint32_t, uint16_t, const char*)>& visitor);
519

520
template<typename T>
521
std::shared_ptr<const T> getRR(const DNSRecord& dr)
522
{
1,451,603✔
523
  return std::dynamic_pointer_cast<const T>(dr.getContent());
1,451,603✔
524
}
1,451,603✔
525

526
/** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs
527
 *  If you survive that, feel free to read from the pointer */
528
class DNSPacketMangler
529
{
530
public:
531
  explicit DNSPacketMangler(std::string& packet)
532
    : d_packet(packet.data()), d_length(packet.length()), d_notyouroffset(12), d_offset(d_notyouroffset)
533
  {}
×
534
  DNSPacketMangler(char* packet, size_t length)
535
    : d_packet(packet), d_length(length), d_notyouroffset(12), d_offset(d_notyouroffset)
536
  {}
2,439✔
537

538
  /*! Advances past a wire-format domain name
539
   * The name is not checked for adherence to length restrictions.
540
   * Compression pointers are not followed.
541
   */
542
  void skipDomainName()
543
  {
10,942✔
544
    uint8_t len;
10,942✔
545
    while((len=get8BitInt())) {
17,728✔
546
      if(len >= 0xc0) { // extended label
15,129✔
547
        get8BitInt();
8,343✔
548
        return;
8,343✔
549
      }
8,343✔
550
      skipBytes(len);
6,786✔
551
    }
6,786✔
552
  }
10,942✔
553

554
  void skipBytes(uint16_t bytes)
555
  {
17,923✔
556
    moveOffset(bytes);
17,923✔
557
  }
17,923✔
558
  void rewindBytes(uint16_t by)
559
  {
1✔
560
    rewindOffset(by);
1✔
561
  }
1✔
562
  uint32_t get32BitInt()
563
  {
28✔
564
    const char* p = d_packet + d_offset;
28✔
565
    moveOffset(4);
28✔
566
    uint32_t ret;
28✔
567
    memcpy(&ret, p, sizeof(ret));
28✔
568
    return ntohl(ret);
28✔
569
  }
28✔
570
  uint16_t get16BitInt()
571
  {
16,910✔
572
    const char* p = d_packet + d_offset;
16,910✔
573
    moveOffset(2);
16,910✔
574
    uint16_t ret;
16,910✔
575
    memcpy(&ret, p, sizeof(ret));
16,910✔
576
    return ntohs(ret);
16,910✔
577
  }
16,910✔
578

579
  uint8_t get8BitInt()
580
  {
25,854✔
581
    const char* p = d_packet + d_offset;
25,854✔
582
    moveOffset(1);
25,854✔
583
    return *p;
25,854✔
584
  }
25,854✔
585

586
  void skipRData()
587
  {
8,484✔
588
    int toskip = get16BitInt();
8,484✔
589
    moveOffset(toskip);
8,484✔
590
  }
8,484✔
591

592
  void decreaseAndSkip32BitInt(uint32_t decrease)
593
  {
8,210✔
594
    const char *p = d_packet + d_offset;
8,210✔
595
    moveOffset(4);
8,210✔
596

597
    uint32_t tmp;
8,210✔
598
    memcpy(&tmp, p, sizeof(tmp));
8,210✔
599
    tmp = ntohl(tmp);
8,210✔
600
    if (tmp > decrease) {
8,211✔
601
      tmp -= decrease;
8,193✔
602
    } else {
2,147,483,971✔
603
      tmp = 0;
2,147,483,649✔
604
    }
2,147,483,649✔
605
    tmp = htonl(tmp);
8,210✔
606
    memcpy(d_packet + d_offset-4, (const char*)&tmp, sizeof(tmp));
8,210✔
607
  }
8,210✔
608

609
  void setAndSkip32BitInt(uint32_t value)
610
  {
1✔
611
    moveOffset(4);
1✔
612

613
    value = htonl(value);
1✔
614
    memcpy(d_packet + d_offset-4, (const char*)&value, sizeof(value));
1✔
615
  }
1✔
616

617
  uint32_t getOffset() const
618
  {
3✔
619
    return d_offset;
3✔
620
  }
3✔
621

622
private:
623
  void moveOffset(uint16_t by)
624
  {
75,983✔
625
    d_notyouroffset += by;
75,983✔
626
    if(d_notyouroffset > d_length)
75,983✔
627
      throw std::out_of_range("dns packet out of range: "+std::to_string(d_notyouroffset) +" > "
4✔
628
      + std::to_string(d_length) );
4✔
629
  }
75,983✔
630

631
  void rewindOffset(uint16_t by)
632
  {
1✔
633
    if(d_notyouroffset < by)
1!
634
      throw std::out_of_range("Rewinding dns packet out of range: "+std::to_string(d_notyouroffset) +" < "
×
635
                              + std::to_string(by));
×
636
    d_notyouroffset -= by;
1✔
637
    if(d_notyouroffset < 12)
1!
638
      throw std::out_of_range("Rewinding dns packet out of range: "+std::to_string(d_notyouroffset) +" < "
×
639
                              + std::to_string(12));
×
640
  }
1✔
641

642
  char* d_packet;
643
  size_t d_length;
644

645
  uint32_t d_notyouroffset;  // only 'moveOffset' can touch this
646
  const uint32_t&  d_offset; // look.. but don't touch
647
};
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