Coverage Report

Created: 2026-09-03 08:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/DnsLayer.cpp
Line
Count
Source
1
117k
#define LOG_MODULE PacketLogModuleDnsLayer
2
3
#include "DnsLayer.h"
4
#include "Logger.h"
5
#include <sstream>
6
#include "EndianPortable.h"
7
8
namespace pcpp
9
{
10
11
  // ~~~~~~~~
12
  // DnsLayer
13
  // ~~~~~~~~
14
15
  DnsLayer::DnsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
16
48.7k
      : Layer(data, dataLen, prevLayer, packet)
17
48.7k
  {
18
48.7k
    init(0, true);
19
48.7k
  }
20
21
  DnsLayer::DnsLayer()
22
0
  {
23
0
    initNewLayer(0);
24
0
  }
25
26
11.6k
  DnsLayer::DnsLayer(const DnsLayer& other) : Layer(other)
27
11.6k
  {
28
11.6k
    init(other.m_OffsetAdjustment, true);
29
11.6k
  }
30
31
  DnsLayer::DnsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, size_t offsetAdjustment)
32
13.8k
      : Layer(data, dataLen, prevLayer, packet)
33
13.8k
  {
34
13.8k
    init(offsetAdjustment, true);
35
13.8k
  }
36
37
  DnsLayer::DnsLayer(size_t offsetAdjustment)
38
0
  {
39
0
    initNewLayer(offsetAdjustment);
40
0
  }
41
42
  DnsLayer& DnsLayer::operator=(const DnsLayer& other)
43
11.6k
  {
44
11.6k
    Layer::operator=(other);
45
46
11.6k
    IDnsResource* curResource = m_ResourceList;
47
30.5k
    while (curResource != nullptr)
48
18.8k
    {
49
18.8k
      IDnsResource* temp = curResource->getNextResource();
50
18.8k
      delete curResource;
51
18.8k
      curResource = temp;
52
18.8k
    }
53
54
11.6k
    init(other.m_OffsetAdjustment, true);
55
56
11.6k
    return (*this);
57
11.6k
  }
58
59
  DnsLayer::~DnsLayer()
60
74.2k
  {
61
74.2k
    IDnsResource* curResource = m_ResourceList;
62
171k
    while (curResource != nullptr)
63
96.8k
    {
64
96.8k
      IDnsResource* nextResource = curResource->getNextResource();
65
96.8k
      delete curResource;
66
96.8k
      curResource = nextResource;
67
96.8k
    }
68
74.2k
  }
69
70
  void DnsLayer::init(size_t offsetAdjustment, bool callParseResource)
71
85.8k
  {
72
85.8k
    m_OffsetAdjustment = offsetAdjustment;
73
85.8k
    m_Protocol = DNS;
74
85.8k
    m_ResourceList = nullptr;
75
76
85.8k
    m_FirstQuery = nullptr;
77
85.8k
    m_FirstAnswer = nullptr;
78
85.8k
    m_FirstAuthority = nullptr;
79
85.8k
    m_FirstAdditional = nullptr;
80
81
85.8k
    if (callParseResource)
82
85.8k
      parseResources();
83
85.8k
  }
84
85
  void DnsLayer::initNewLayer(size_t offsetAdjustment)
86
0
  {
87
0
    m_OffsetAdjustment = offsetAdjustment;
88
0
    const size_t headerLen = getBasicHeaderSize();
89
0
    allocData(headerLen);
90
91
0
    init(m_OffsetAdjustment, false);
92
0
  }
93
94
  size_t DnsLayer::getBasicHeaderSize()
95
132k
  {
96
132k
    return sizeof(dnshdr) + m_OffsetAdjustment;
97
132k
  }
98
99
  dnshdr* DnsLayer::getDnsHeader() const
100
736k
  {
101
736k
    uint8_t* ptr = m_Data + m_OffsetAdjustment;
102
736k
    return reinterpret_cast<dnshdr*>(ptr);
103
736k
  }
104
105
  bool DnsLayer::extendLayer(int offsetInLayer, size_t numOfBytesToExtend, IDnsResource* resource)
106
46.4k
  {
107
46.4k
    if (!Layer::extendLayer(offsetInLayer, numOfBytesToExtend))
108
10.7k
      return false;
109
110
35.7k
    IDnsResource* curResource = resource->getNextResource();
111
44.4k
    while (curResource != nullptr)
112
8.70k
    {
113
8.70k
      curResource->m_OffsetInLayer += numOfBytesToExtend;
114
8.70k
      curResource = curResource->getNextResource();
115
8.70k
    }
116
35.7k
    return true;
117
46.4k
  }
118
119
  bool DnsLayer::shortenLayer(int offsetInLayer, size_t numOfBytesToShorten, IDnsResource* resource)
120
35.5k
  {
121
35.5k
    if (!Layer::shortenLayer(offsetInLayer, numOfBytesToShorten))
122
0
      return false;
123
124
35.5k
    IDnsResource* curResource = resource->getNextResource();
125
44.2k
    while (curResource != nullptr)
126
8.70k
    {
127
8.70k
      curResource->m_OffsetInLayer -= numOfBytesToShorten;
128
8.70k
      curResource = curResource->getNextResource();
129
8.70k
    }
130
35.5k
    return true;
131
35.5k
  }
132
133
  void DnsLayer::parseResources()
134
85.8k
  {
135
85.8k
    size_t offsetInPacket = getBasicHeaderSize();
136
85.8k
    IDnsResource* curResource = m_ResourceList;
137
138
85.8k
    uint16_t numOfQuestions = be16toh(getDnsHeader()->numberOfQuestions);
139
85.8k
    uint16_t numOfAnswers = be16toh(getDnsHeader()->numberOfAnswers);
140
85.8k
    uint16_t numOfAuthority = be16toh(getDnsHeader()->numberOfAuthority);
141
85.8k
    uint16_t numOfAdditional = be16toh(getDnsHeader()->numberOfAdditional);
142
143
85.8k
    uint32_t numOfOtherResources = numOfQuestions + numOfAnswers + numOfAuthority + numOfAdditional;
144
145
85.8k
    if (numOfOtherResources > 300)
146
19.1k
    {
147
19.1k
      PCPP_LOG_ERROR(
148
19.1k
          "DNS layer contains more than 300 resources, probably a bad packet. Skipping parsing DNS resources");
149
19.1k
      return;
150
19.1k
    }
151
152
182k
    for (uint32_t i = 0; i < numOfOtherResources; i++)
153
135k
    {
154
135k
      DnsResourceType resType;
155
135k
      if (numOfQuestions > 0)
156
85.4k
      {
157
85.4k
        resType = DnsQueryType;
158
85.4k
        numOfQuestions--;
159
85.4k
      }
160
50.3k
      else if (numOfAnswers > 0)
161
16.8k
      {
162
16.8k
        resType = DnsAnswerType;
163
16.8k
        numOfAnswers--;
164
16.8k
      }
165
33.4k
      else if (numOfAuthority > 0)
166
23.0k
      {
167
23.0k
        resType = DnsAuthorityType;
168
23.0k
        numOfAuthority--;
169
23.0k
      }
170
10.3k
      else
171
10.3k
      {
172
10.3k
        resType = DnsAdditionalType;
173
10.3k
        numOfAdditional--;
174
10.3k
      }
175
176
135k
      DnsResource* newResource = nullptr;
177
135k
      DnsQuery* newQuery = nullptr;
178
135k
      IDnsResource* newGenResource = nullptr;
179
135k
      if (resType == DnsQueryType)
180
85.4k
      {
181
85.4k
        newQuery = new DnsQuery(this, offsetInPacket);
182
85.4k
        newGenResource = newQuery;
183
85.4k
        offsetInPacket += newQuery->getSize();
184
85.4k
      }
185
50.3k
      else
186
50.3k
      {
187
50.3k
        newResource = new DnsResource(this, offsetInPacket, resType);
188
50.3k
        newGenResource = newResource;
189
50.3k
        offsetInPacket += newResource->getSize();
190
50.3k
      }
191
192
135k
      if (offsetInPacket > m_DataLen)
193
20.3k
      {
194
        // Parse packet failed, DNS resource is out of bounds. Probably a bad packet
195
20.3k
        delete newGenResource;
196
20.3k
        return;
197
20.3k
      }
198
199
      // this resource is the first resource
200
115k
      if (m_ResourceList == nullptr)
201
60.8k
      {
202
60.8k
        m_ResourceList = newGenResource;
203
60.8k
        curResource = m_ResourceList;
204
60.8k
      }
205
54.5k
      else
206
54.5k
      {
207
54.5k
        curResource->setNextResource(newGenResource);
208
54.5k
        curResource = curResource->getNextResource();
209
54.5k
      }
210
211
115k
      if (resType == DnsQueryType && m_FirstQuery == nullptr)
212
60.2k
        m_FirstQuery = newQuery;
213
55.1k
      else if (resType == DnsAnswerType && m_FirstAnswer == nullptr)
214
5.62k
        m_FirstAnswer = newResource;
215
49.5k
      else if (resType == DnsAuthorityType && m_FirstAuthority == nullptr)
216
8.58k
        m_FirstAuthority = newResource;
217
40.9k
      else if (resType == DnsAdditionalType && m_FirstAdditional == nullptr)
218
4.74k
        m_FirstAdditional = newResource;
219
115k
    }
220
66.7k
  }
221
222
  IDnsResource* DnsLayer::getResourceByName(IDnsResource* startFrom, size_t resourceCount, const std::string& name,
223
                                            bool exactMatch) const
224
93.0k
  {
225
93.0k
    size_t index = 0;
226
158k
    while (index < resourceCount)
227
118k
    {
228
118k
      if (startFrom == nullptr)
229
17.5k
        return nullptr;
230
231
100k
      std::string resourceName = startFrom->getName();
232
100k
      if (exactMatch && resourceName == name)
233
0
        return startFrom;
234
100k
      else if (!exactMatch && resourceName.find(name) != std::string::npos)
235
35.5k
        return startFrom;
236
237
65.1k
      startFrom = startFrom->getNextResource();
238
239
65.1k
      index++;
240
65.1k
    }
241
242
39.9k
    return nullptr;
243
93.0k
  }
244
245
  DnsQuery* DnsLayer::getQuery(const std::string& name, bool exactMatch) const
246
23.2k
  {
247
23.2k
    uint16_t numOfQueries = be16toh(getDnsHeader()->numberOfQuestions);
248
23.2k
    IDnsResource* res = getResourceByName(m_FirstQuery, numOfQueries, name, exactMatch);
249
23.2k
    if (res != nullptr)
250
8.91k
      return dynamic_cast<DnsQuery*>(res);
251
14.3k
    return nullptr;
252
23.2k
  }
253
254
  DnsQuery* DnsLayer::getFirstQuery() const
255
11.6k
  {
256
11.6k
    return m_FirstQuery;
257
11.6k
  }
258
259
  DnsQuery* DnsLayer::getNextQuery(DnsQuery* query) const
260
9.85k
  {
261
9.85k
    if (query == nullptr || query->getNextResource() == nullptr || query->getType() != DnsQueryType ||
262
4.17k
        query->getNextResource()->getType() != DnsQueryType)
263
8.09k
      return nullptr;
264
265
1.76k
    return (DnsQuery*)(query->getNextResource());
266
9.85k
  }
267
268
  size_t DnsLayer::getQueryCount() const
269
41.1k
  {
270
41.1k
    return be16toh(getDnsHeader()->numberOfQuestions);
271
41.1k
  }
272
273
  DnsResource* DnsLayer::getAnswer(const std::string& name, bool exactMatch) const
274
23.2k
  {
275
23.2k
    uint16_t numOfAnswers = be16toh(getDnsHeader()->numberOfAnswers);
276
23.2k
    IDnsResource* res = getResourceByName(m_FirstAnswer, numOfAnswers, name, exactMatch);
277
23.2k
    if (res != nullptr)
278
8.85k
      return dynamic_cast<DnsResource*>(res);
279
14.4k
    return nullptr;
280
23.2k
  }
281
282
  DnsResource* DnsLayer::getFirstAnswer() const
283
11.6k
  {
284
11.6k
    return m_FirstAnswer;
285
11.6k
  }
286
287
  DnsResource* DnsLayer::getNextAnswer(DnsResource* answer) const
288
1.85k
  {
289
1.85k
    if (answer == nullptr || answer->getNextResource() == nullptr || answer->getType() != DnsAnswerType ||
290
1.07k
        answer->getNextResource()->getType() != DnsAnswerType)
291
848
      return nullptr;
292
293
1.00k
    return (DnsResource*)(answer->getNextResource());
294
1.85k
  }
295
296
  size_t DnsLayer::getAnswerCount() const
297
41.0k
  {
298
41.0k
    return be16toh(getDnsHeader()->numberOfAnswers);
299
41.0k
  }
300
301
  DnsResource* DnsLayer::getAuthority(const std::string& name, bool exactMatch) const
302
23.2k
  {
303
23.2k
    uint16_t numOfAuthorities = be16toh(getDnsHeader()->numberOfAuthority);
304
23.2k
    IDnsResource* res = getResourceByName(m_FirstAuthority, numOfAuthorities, name, exactMatch);
305
23.2k
    if (res != nullptr)
306
8.88k
      return dynamic_cast<DnsResource*>(res);
307
14.3k
    return nullptr;
308
23.2k
  }
309
310
  DnsResource* DnsLayer::getFirstAuthority() const
311
11.6k
  {
312
11.6k
    return m_FirstAuthority;
313
11.6k
  }
314
315
  DnsResource* DnsLayer::getNextAuthority(DnsResource* authority) const
316
2.06k
  {
317
2.06k
    if (authority == nullptr || authority->getNextResource() == nullptr ||
318
1.02k
        authority->getType() != DnsAuthorityType || authority->getNextResource()->getType() != DnsAuthorityType)
319
1.25k
      return nullptr;
320
321
806
    return (DnsResource*)(authority->getNextResource());
322
2.06k
  }
323
324
  size_t DnsLayer::getAuthorityCount() const
325
41.0k
  {
326
41.0k
    return be16toh(getDnsHeader()->numberOfAuthority);
327
41.0k
  }
328
329
  DnsResource* DnsLayer::getAdditionalRecord(const std::string& name, bool exactMatch) const
330
23.2k
  {
331
23.2k
    uint16_t numOfAdditionalRecords = be16toh(getDnsHeader()->numberOfAdditional);
332
23.2k
    IDnsResource* res = getResourceByName(m_FirstAdditional, numOfAdditionalRecords, name, exactMatch);
333
23.2k
    if (res != nullptr)
334
8.88k
      return dynamic_cast<DnsResource*>(res);
335
14.3k
    return nullptr;
336
23.2k
  }
337
338
  DnsResource* DnsLayer::getFirstAdditionalRecord() const
339
11.6k
  {
340
11.6k
    return m_FirstAdditional;
341
11.6k
  }
342
343
  DnsResource* DnsLayer::getNextAdditionalRecord(DnsResource* additionalRecord) const
344
1.24k
  {
345
1.24k
    if (additionalRecord == nullptr || additionalRecord->getNextResource() == nullptr ||
346
514
        additionalRecord->getType() != DnsAdditionalType ||
347
514
        additionalRecord->getNextResource()->getType() != DnsAdditionalType)
348
733
      return nullptr;
349
350
514
    return (DnsResource*)(additionalRecord->getNextResource());
351
1.24k
  }
352
353
  size_t DnsLayer::getAdditionalRecordCount() const
354
41.0k
  {
355
41.0k
    return be16toh(getDnsHeader()->numberOfAdditional);
356
41.0k
  }
357
358
  std::string DnsLayer::toString() const
359
23.2k
  {
360
23.2k
    std::ostringstream tidAsString;
361
23.2k
    tidAsString << be16toh(getDnsHeader()->transactionID);
362
363
23.2k
    std::ostringstream queryCount;
364
23.2k
    queryCount << getQueryCount();
365
366
23.2k
    std::ostringstream answerCount;
367
23.2k
    answerCount << getAnswerCount();
368
369
23.2k
    std::ostringstream authorityCount;
370
23.2k
    authorityCount << getAuthorityCount();
371
372
23.2k
    std::ostringstream additionalCount;
373
23.2k
    additionalCount << getAdditionalRecordCount();
374
375
23.2k
    if (getDnsHeader()->queryOrResponse == 1)
376
5.48k
    {
377
5.48k
      return "DNS query response, ID: " + tidAsString.str() + ";" + " queries: " + queryCount.str() +
378
5.48k
             ", answers: " + answerCount.str() + ", authorities: " + authorityCount.str() +
379
5.48k
             ", additional record: " + additionalCount.str();
380
5.48k
    }
381
17.7k
    else if (getDnsHeader()->queryOrResponse == 0)
382
17.7k
    {
383
17.7k
      return "DNS query, ID: " + tidAsString.str() + ";" + " queries: " + queryCount.str() +
384
17.7k
             ", answers: " + answerCount.str() + ", authorities: " + authorityCount.str() +
385
17.7k
             ", additional record: " + additionalCount.str();
386
17.7k
    }
387
0
    else  // not likely - a DNS with no answers and no queries
388
0
    {
389
0
      return "DNS record without queries and answers, ID: " + tidAsString.str() + ";" +
390
0
             " queries: " + queryCount.str() + ", answers: " + answerCount.str() +
391
0
             ", authorities: " + authorityCount.str() + ", additional record: " + additionalCount.str();
392
0
    }
393
23.2k
  }
394
395
  IDnsResource* DnsLayer::getFirstResource(DnsResourceType resType) const
396
35.5k
  {
397
35.5k
    switch (resType)
398
35.5k
    {
399
8.91k
    case DnsQueryType:
400
8.91k
    {
401
8.91k
      return m_FirstQuery;
402
0
    }
403
8.85k
    case DnsAnswerType:
404
8.85k
    {
405
8.85k
      return m_FirstAnswer;
406
0
    }
407
8.88k
    case DnsAuthorityType:
408
8.88k
    {
409
8.88k
      return m_FirstAuthority;
410
0
    }
411
8.88k
    case DnsAdditionalType:
412
8.88k
    {
413
8.88k
      return m_FirstAdditional;
414
0
    }
415
0
    default:
416
0
      return nullptr;
417
35.5k
    }
418
35.5k
  }
419
420
  void DnsLayer::setFirstResource(DnsResourceType resType, IDnsResource* resource)
421
50.3k
  {
422
50.3k
    switch (resType)
423
50.3k
    {
424
1.59k
    case DnsQueryType:
425
1.59k
    {
426
1.59k
      m_FirstQuery = dynamic_cast<DnsQuery*>(resource);
427
1.59k
      break;
428
0
    }
429
16.3k
    case DnsAnswerType:
430
16.3k
    {
431
16.3k
      m_FirstAnswer = dynamic_cast<DnsResource*>(resource);
432
16.3k
      break;
433
0
    }
434
15.8k
    case DnsAuthorityType:
435
15.8k
    {
436
15.8k
      m_FirstAuthority = dynamic_cast<DnsResource*>(resource);
437
15.8k
      break;
438
0
    }
439
16.5k
    case DnsAdditionalType:
440
16.5k
    {
441
16.5k
      m_FirstAdditional = dynamic_cast<DnsResource*>(resource);
442
16.5k
      break;
443
0
    }
444
0
    default:
445
0
      return;
446
50.3k
    }
447
50.3k
  }
448
449
  DnsResource* DnsLayer::addResource(DnsResourceType resType, const std::string& name, DnsType dnsType,
450
                                     DnsClass dnsClass, uint32_t ttl, IDnsResourceData* data)
451
34.8k
  {
452
    // create new query on temporary buffer
453
34.8k
    uint8_t newResourceRawData[4096];
454
34.8k
    memset(newResourceRawData, 0, sizeof(newResourceRawData));
455
456
34.8k
    DnsResource* newResource = new DnsResource(newResourceRawData, resType);
457
458
34.8k
    newResource->setDnsClass(dnsClass);
459
460
34.8k
    newResource->setDnsType(dnsType);
461
462
    // cannot return false since layer shouldn't be extended or shortened in this stage
463
34.8k
    newResource->setName(name);
464
465
34.8k
    newResource->setTTL(ttl);
466
467
34.8k
    if (!newResource->setData(data))
468
0
    {
469
0
      delete newResource;
470
0
      PCPP_LOG_ERROR("Couldn't set new resource data");
471
0
      return nullptr;
472
0
    }
473
474
34.8k
    size_t newResourceOffsetInLayer = getBasicHeaderSize();
475
34.8k
    IDnsResource* curResource = m_ResourceList;
476
50.5k
    while (curResource != nullptr && curResource->getType() <= resType)
477
40.2k
    {
478
40.2k
      newResourceOffsetInLayer += curResource->getSize();
479
480
40.2k
      if (newResourceOffsetInLayer > m_DataLen)
481
18
      {
482
        // This possibly means that the DNS layer has been created from a malformed packet.
483
18
        PCPP_LOG_ERROR("Couldn't add resource! DNS Layer is malformed and contains out of bounds resources.");
484
18
        delete newResource;
485
18
        return nullptr;
486
18
      }
487
488
40.2k
      IDnsResource* nextResource = curResource->getNextResource();
489
40.2k
      if (nextResource == nullptr || nextResource->getType() > resType)
490
24.5k
        break;
491
15.7k
      curResource = nextResource;
492
15.7k
    }
493
494
    // set next resource for new resource. This must happen here for extendLayer to succeed
495
34.8k
    if (curResource != nullptr)
496
24.5k
    {
497
24.5k
      if (curResource->getType() > newResource->getType())
498
62
        newResource->setNextResource(m_ResourceList);
499
24.5k
      else
500
24.5k
        newResource->setNextResource(curResource->getNextResource());
501
24.5k
    }
502
10.2k
    else
503
10.2k
    {
504
      // curResource != nullptr
505
10.2k
      newResource->setNextResource(m_ResourceList);
506
10.2k
    }
507
508
    // extend layer to make room for the new resource
509
34.8k
    if (!extendLayer(newResourceOffsetInLayer, newResource->getSize(), newResource))
510
8.02k
    {
511
8.02k
      PCPP_LOG_ERROR("Couldn't extend DNS layer, addResource failed");
512
8.02k
      delete newResource;
513
8.02k
      return nullptr;
514
8.02k
    }
515
516
    // connect the new resource to layer
517
26.8k
    newResource->setDnsLayer(this, newResourceOffsetInLayer);
518
519
    // connect the new resource to the layer's resource list
520
26.8k
    if (curResource != nullptr)
521
22.1k
    {
522
22.1k
      curResource->setNextResource(newResource);
523
      // this means the new resource is the first of it's type
524
22.1k
      if (curResource->getType() < newResource->getType())
525
19.8k
      {
526
19.8k
        setFirstResource(resType, newResource);
527
19.8k
      }
528
      // this means the new resource should be the first resource in the packet
529
2.36k
      else if (curResource->getType() > newResource->getType())
530
0
      {
531
0
        m_ResourceList = newResource;
532
533
0
        setFirstResource(resType, newResource);
534
0
      }
535
22.1k
    }
536
4.65k
    else  // curResource != nullptr, meaning this is the first resource in layer
537
4.65k
    {
538
4.65k
      m_ResourceList = newResource;
539
540
4.65k
      setFirstResource(resType, newResource);
541
4.65k
    }
542
543
26.8k
    return newResource;
544
34.8k
  }
545
546
  DnsQuery* DnsLayer::addQuery(const std::string& name, DnsType dnsType, DnsClass dnsClass)
547
11.6k
  {
548
    // create new query on temporary buffer
549
11.6k
    uint8_t newQueryRawData[256];
550
11.6k
    DnsQuery* newQuery = new DnsQuery(newQueryRawData);
551
552
11.6k
    newQuery->setDnsClass(dnsClass);
553
11.6k
    newQuery->setDnsType(dnsType);
554
555
    // cannot return false since layer shouldn't be extended or shortened in this stage
556
11.6k
    newQuery->setName(name);
557
558
    // find the offset in the layer to insert the new query
559
11.6k
    size_t newQueryOffsetInLayer = getBasicHeaderSize();
560
11.6k
    DnsQuery* curQuery = getFirstQuery();
561
13.3k
    while (curQuery != nullptr)
562
9.85k
    {
563
9.85k
      newQueryOffsetInLayer += curQuery->getSize();
564
9.85k
      DnsQuery* nextQuery = getNextQuery(curQuery);
565
9.85k
      if (nextQuery == nullptr)
566
8.09k
        break;
567
1.76k
      curQuery = nextQuery;
568
1.76k
    }
569
570
    // set next resource for new query. This must happen here for extendLayer to succeed
571
11.6k
    if (curQuery != nullptr)
572
8.09k
      newQuery->setNextResource(curQuery->getNextResource());
573
3.53k
    else
574
3.53k
      newQuery->setNextResource(m_ResourceList);
575
576
    // extend layer to make room for the new query
577
11.6k
    if (!extendLayer(newQueryOffsetInLayer, newQuery->getSize(), newQuery))
578
2.68k
    {
579
2.68k
      PCPP_LOG_ERROR("Couldn't extend DNS layer, addQuery failed");
580
2.68k
      delete newQuery;
581
2.68k
      return nullptr;
582
2.68k
    }
583
584
    // connect the new query to layer
585
8.94k
    newQuery->setDnsLayer(this, newQueryOffsetInLayer);
586
587
    // connect the new query to the layer's resource list
588
8.94k
    if (curQuery != nullptr)
589
7.31k
      curQuery->setNextResource(newQuery);
590
1.62k
    else  // curQuery == nullptr, meaning this is the first query
591
1.62k
    {
592
1.62k
      m_ResourceList = newQuery;
593
1.62k
      m_FirstQuery = newQuery;
594
1.62k
    }
595
596
    // increase number of queries
597
8.94k
    getDnsHeader()->numberOfQuestions = htobe16(getQueryCount() + 1);
598
599
8.94k
    return newQuery;
600
11.6k
  }
601
602
  DnsQuery* DnsLayer::addQuery(DnsQuery* const copyQuery)
603
0
  {
604
0
    if (copyQuery == nullptr)
605
0
      return nullptr;
606
607
0
    return addQuery(copyQuery->getName(), copyQuery->getDnsType(), copyQuery->getDnsClass());
608
0
  }
609
610
  bool DnsLayer::removeQuery(const std::string& queryNameToRemove, bool exactMatch)
611
23.2k
  {
612
23.2k
    DnsQuery* queryToRemove = getQuery(queryNameToRemove, exactMatch);
613
23.2k
    if (queryToRemove == nullptr)
614
14.3k
    {
615
14.3k
      PCPP_LOG_DEBUG("Query not found");
616
14.3k
      return false;
617
14.3k
    }
618
619
8.91k
    return removeQuery(queryToRemove);
620
23.2k
  }
621
622
  bool DnsLayer::removeQuery(DnsQuery* queryToRemove)
623
8.91k
  {
624
8.91k
    bool res = removeResource(queryToRemove);
625
8.91k
    if (res)
626
8.91k
    {
627
      // decrease number of query records
628
8.91k
      getDnsHeader()->numberOfQuestions = htobe16(getQueryCount() - 1);
629
8.91k
    }
630
631
8.91k
    return res;
632
8.91k
  }
633
634
  DnsResource* DnsLayer::addAnswer(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl,
635
                                   IDnsResourceData* data)
636
11.6k
  {
637
11.6k
    DnsResource* res = addResource(DnsAnswerType, name, dnsType, dnsClass, ttl, data);
638
11.6k
    if (res != nullptr)
639
8.94k
    {
640
      // increase number of answer records
641
8.94k
      getDnsHeader()->numberOfAnswers = htobe16(getAnswerCount() + 1);
642
8.94k
    }
643
644
11.6k
    return res;
645
11.6k
  }
646
647
  DnsResource* DnsLayer::addAnswer(DnsResource* const copyAnswer)
648
0
  {
649
0
    if (copyAnswer == nullptr)
650
0
      return nullptr;
651
652
0
    return addAnswer(copyAnswer->getName(), copyAnswer->getDnsType(), copyAnswer->getDnsClass(),
653
0
                     copyAnswer->getTTL(), copyAnswer->getData().get());
654
0
  }
655
656
  bool DnsLayer::removeAnswer(const std::string& answerNameToRemove, bool exactMatch)
657
23.2k
  {
658
23.2k
    DnsResource* answerToRemove = getAnswer(answerNameToRemove, exactMatch);
659
23.2k
    if (answerToRemove == nullptr)
660
14.4k
    {
661
14.4k
      PCPP_LOG_DEBUG("Answer record not found");
662
14.4k
      return false;
663
14.4k
    }
664
665
8.85k
    return removeAnswer(answerToRemove);
666
23.2k
  }
667
668
  bool DnsLayer::removeAnswer(DnsResource* answerToRemove)
669
8.85k
  {
670
8.85k
    bool res = removeResource(answerToRemove);
671
8.85k
    if (res)
672
8.85k
    {
673
      // decrease number of answer records
674
8.85k
      getDnsHeader()->numberOfAnswers = htobe16(getAnswerCount() - 1);
675
8.85k
    }
676
677
8.85k
    return res;
678
8.85k
  }
679
680
  DnsResource* DnsLayer::addAuthority(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl,
681
                                      IDnsResourceData* data)
682
11.6k
  {
683
11.6k
    DnsResource* res = addResource(DnsAuthorityType, name, dnsType, dnsClass, ttl, data);
684
11.6k
    if (res != nullptr)
685
8.94k
    {
686
      // increase number of authority records
687
8.94k
      getDnsHeader()->numberOfAuthority = htobe16(getAuthorityCount() + 1);
688
8.94k
    }
689
690
11.6k
    return res;
691
11.6k
  }
692
693
  DnsResource* DnsLayer::addAuthority(DnsResource* const copyAuthority)
694
0
  {
695
0
    if (copyAuthority == nullptr)
696
0
      return nullptr;
697
698
0
    return addAuthority(copyAuthority->getName(), copyAuthority->getDnsType(), copyAuthority->getDnsClass(),
699
0
                        copyAuthority->getTTL(), copyAuthority->getData().get());
700
0
  }
701
702
  bool DnsLayer::removeAuthority(const std::string& authorityNameToRemove, bool exactMatch)
703
23.2k
  {
704
23.2k
    DnsResource* authorityToRemove = getAuthority(authorityNameToRemove, exactMatch);
705
23.2k
    if (authorityToRemove == nullptr)
706
14.3k
    {
707
14.3k
      PCPP_LOG_DEBUG("Authority not found");
708
14.3k
      return false;
709
14.3k
    }
710
711
8.88k
    return removeAuthority(authorityToRemove);
712
23.2k
  }
713
714
  bool DnsLayer::removeAuthority(DnsResource* authorityToRemove)
715
8.88k
  {
716
8.88k
    bool res = removeResource(authorityToRemove);
717
8.88k
    if (res)
718
8.88k
    {
719
      // decrease number of authority records
720
8.88k
      getDnsHeader()->numberOfAuthority = htobe16(getAuthorityCount() - 1);
721
8.88k
    }
722
723
8.88k
    return res;
724
8.88k
  }
725
726
  DnsResource* DnsLayer::addAdditionalRecord(const std::string& name, DnsType dnsType, DnsClass dnsClass,
727
                                             uint32_t ttl, IDnsResourceData* data)
728
11.6k
  {
729
11.6k
    DnsResource* res = addResource(DnsAdditionalType, name, dnsType, dnsClass, ttl, data);
730
11.6k
    if (res != nullptr)
731
8.94k
    {
732
      // increase number of authority records
733
8.94k
      getDnsHeader()->numberOfAdditional = htobe16(getAdditionalRecordCount() + 1);
734
8.94k
    }
735
736
11.6k
    return res;
737
11.6k
  }
738
739
  DnsResource* DnsLayer::addAdditionalRecord(const std::string& name, DnsType dnsType, uint16_t customData1,
740
                                             uint32_t customData2, IDnsResourceData* data)
741
11.6k
  {
742
11.6k
    DnsResource* res = addAdditionalRecord(name, dnsType, DNS_CLASS_ANY, customData2, data);
743
11.6k
    if (res != nullptr)
744
8.94k
    {
745
8.94k
      res->setCustomDnsClass(customData1);
746
8.94k
    }
747
748
11.6k
    return res;
749
11.6k
  }
750
751
  DnsResource* DnsLayer::addAdditionalRecord(DnsResource* const copyAdditionalRecord)
752
0
  {
753
0
    if (copyAdditionalRecord == nullptr)
754
0
      return nullptr;
755
756
0
    return addAdditionalRecord(copyAdditionalRecord->getName(), copyAdditionalRecord->getDnsType(),
757
0
                               copyAdditionalRecord->getCustomDnsClass(), copyAdditionalRecord->getTTL(),
758
0
                               copyAdditionalRecord->getData().get());
759
0
  }
760
761
  bool DnsLayer::removeAdditionalRecord(const std::string& additionalRecordNameToRemove, bool exactMatch)
762
23.2k
  {
763
23.2k
    DnsResource* additionalRecordToRemove = getAdditionalRecord(additionalRecordNameToRemove, exactMatch);
764
23.2k
    if (additionalRecordToRemove == nullptr)
765
14.3k
    {
766
14.3k
      PCPP_LOG_DEBUG("Additional record not found");
767
14.3k
      return false;
768
14.3k
    }
769
770
8.88k
    return removeAdditionalRecord(additionalRecordToRemove);
771
23.2k
  }
772
773
  bool DnsLayer::removeAdditionalRecord(DnsResource* additionalRecordToRemove)
774
8.88k
  {
775
8.88k
    bool res = removeResource(additionalRecordToRemove);
776
8.88k
    if (res)
777
8.88k
    {
778
      // decrease number of additional records
779
8.88k
      getDnsHeader()->numberOfAdditional = htobe16(getAdditionalRecordCount() - 1);
780
8.88k
    }
781
782
8.88k
    return res;
783
8.88k
  }
784
785
  bool DnsLayer::removeResource(IDnsResource* resourceToRemove)
786
35.5k
  {
787
35.5k
    if (resourceToRemove == nullptr)
788
0
    {
789
0
      PCPP_LOG_DEBUG("resourceToRemove cannot be nullptr");
790
0
      return false;
791
0
    }
792
793
    // find the resource preceding resourceToRemove
794
35.5k
    IDnsResource* prevResource = m_ResourceList;
795
796
35.5k
    if (m_ResourceList != resourceToRemove)
797
29.3k
    {
798
42.0k
      while (prevResource != nullptr)
799
42.0k
      {
800
42.0k
        IDnsResource* temp = prevResource->getNextResource();
801
42.0k
        if (temp == resourceToRemove)
802
29.3k
          break;
803
804
12.7k
        prevResource = temp;
805
12.7k
      }
806
29.3k
    }
807
808
35.5k
    if (prevResource == nullptr)
809
0
    {
810
0
      PCPP_LOG_DEBUG("Resource not found");
811
0
      return false;
812
0
    }
813
814
    // shorten the layer and fix offset in layer for all next DNS resources in the packet
815
35.5k
    if (!shortenLayer(resourceToRemove->m_OffsetInLayer, resourceToRemove->getSize(), resourceToRemove))
816
0
    {
817
0
      PCPP_LOG_ERROR("Couldn't shorten the DNS layer, resource cannot be removed");
818
0
      return false;
819
0
    }
820
821
    // remove resourceToRemove from the resources linked list
822
35.5k
    if (m_ResourceList != resourceToRemove)
823
29.3k
    {
824
29.3k
      prevResource->setNextResource(resourceToRemove->getNextResource());
825
29.3k
    }
826
6.16k
    else
827
6.16k
    {
828
6.16k
      m_ResourceList = resourceToRemove->getNextResource();
829
6.16k
    }
830
831
    // check whether resourceToRemove was the first of its type
832
35.5k
    if (getFirstResource(resourceToRemove->getType()) == resourceToRemove)
833
25.8k
    {
834
25.8k
      IDnsResource* nextResource = resourceToRemove->getNextResource();
835
25.8k
      if (nextResource != nullptr && nextResource->getType() == resourceToRemove->getType())
836
0
        setFirstResource(resourceToRemove->getType(), nextResource);
837
25.8k
      else
838
25.8k
        setFirstResource(resourceToRemove->getType(), nullptr);
839
25.8k
    }
840
841
    // free resourceToRemove memory
842
35.5k
    delete resourceToRemove;
843
844
35.5k
    return true;
845
35.5k
  }
846
847
  // ~~~~~~~~~~~~~~~
848
  // DnsOverTcpLayer
849
  // ~~~~~~~~~~~~~~~
850
851
  uint16_t DnsOverTcpLayer::getTcpMessageLength()
852
0
  {
853
0
    return be16toh(*(uint16_t*)m_Data);
854
0
  }
855
856
  void DnsOverTcpLayer::setTcpMessageLength(uint16_t value)
857
2.63k
  {
858
2.63k
    ((uint16_t*)m_Data)[0] = htobe16(value);
859
2.63k
  }
860
861
  void DnsOverTcpLayer::computeCalculateFields()
862
2.63k
  {
863
2.63k
    setTcpMessageLength(m_DataLen - sizeof(uint16_t));
864
2.63k
  }
865
866
}  // namespace pcpp