Coverage Report

Created: 2026-07-16 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/src/DnsLayer.cpp
Line
Count
Source
1
66.2k
#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
46.7k
      : Layer(data, dataLen, prevLayer, packet)
17
46.7k
  {
18
46.7k
    init(0, true);
19
46.7k
  }
20
21
  DnsLayer::DnsLayer()
22
0
  {
23
0
    initNewLayer(0);
24
0
  }
25
26
10.4k
  DnsLayer::DnsLayer(const DnsLayer& other) : Layer(other)
27
10.4k
  {
28
10.4k
    init(other.m_OffsetAdjustment, true);
29
10.4k
  }
30
31
  DnsLayer::DnsLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, size_t offsetAdjustment)
32
4.92k
      : Layer(data, dataLen, prevLayer, packet)
33
4.92k
  {
34
4.92k
    init(offsetAdjustment, true);
35
4.92k
  }
36
37
  DnsLayer::DnsLayer(size_t offsetAdjustment)
38
0
  {
39
0
    initNewLayer(offsetAdjustment);
40
0
  }
41
42
  DnsLayer& DnsLayer::operator=(const DnsLayer& other)
43
10.4k
  {
44
10.4k
    Layer::operator=(other);
45
46
10.4k
    IDnsResource* curResource = m_ResourceList;
47
34.5k
    while (curResource != nullptr)
48
24.1k
    {
49
24.1k
      IDnsResource* temp = curResource->getNextResource();
50
24.1k
      delete curResource;
51
24.1k
      curResource = temp;
52
24.1k
    }
53
54
10.4k
    init(other.m_OffsetAdjustment, true);
55
56
10.4k
    return (*this);
57
10.4k
  }
58
59
  DnsLayer::~DnsLayer()
60
62.1k
  {
61
62.1k
    IDnsResource* curResource = m_ResourceList;
62
206k
    while (curResource != nullptr)
63
144k
    {
64
144k
      IDnsResource* nextResource = curResource->getNextResource();
65
144k
      delete curResource;
66
144k
      curResource = nextResource;
67
144k
    }
68
62.1k
  }
69
70
  void DnsLayer::init(size_t offsetAdjustment, bool callParseResource)
71
72.5k
  {
72
72.5k
    m_OffsetAdjustment = offsetAdjustment;
73
72.5k
    m_Protocol = DNS;
74
72.5k
    m_ResourceList = nullptr;
75
76
72.5k
    m_FirstQuery = nullptr;
77
72.5k
    m_FirstAnswer = nullptr;
78
72.5k
    m_FirstAuthority = nullptr;
79
72.5k
    m_FirstAdditional = nullptr;
80
81
72.5k
    if (callParseResource)
82
72.5k
      parseResources();
83
72.5k
  }
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
114k
  {
96
114k
    return sizeof(dnshdr) + m_OffsetAdjustment;
97
114k
  }
98
99
  dnshdr* DnsLayer::getDnsHeader() const
100
678k
  {
101
678k
    uint8_t* ptr = m_Data + m_OffsetAdjustment;
102
678k
    return reinterpret_cast<dnshdr*>(ptr);
103
678k
  }
104
105
  bool DnsLayer::extendLayer(int offsetInLayer, size_t numOfBytesToExtend, IDnsResource* resource)
106
41.7k
  {
107
41.7k
    if (!Layer::extendLayer(offsetInLayer, numOfBytesToExtend))
108
965
      return false;
109
110
40.8k
    IDnsResource* curResource = resource->getNextResource();
111
52.8k
    while (curResource != nullptr)
112
11.9k
    {
113
11.9k
      curResource->m_OffsetInLayer += numOfBytesToExtend;
114
11.9k
      curResource = curResource->getNextResource();
115
11.9k
    }
116
40.8k
    return true;
117
41.7k
  }
118
119
  bool DnsLayer::shortenLayer(int offsetInLayer, size_t numOfBytesToShorten, IDnsResource* resource)
120
40.4k
  {
121
40.4k
    if (!Layer::shortenLayer(offsetInLayer, numOfBytesToShorten))
122
0
      return false;
123
124
40.4k
    IDnsResource* curResource = resource->getNextResource();
125
55.5k
    while (curResource != nullptr)
126
15.1k
    {
127
15.1k
      curResource->m_OffsetInLayer -= numOfBytesToShorten;
128
15.1k
      curResource = curResource->getNextResource();
129
15.1k
    }
130
40.4k
    return true;
131
40.4k
  }
132
133
  void DnsLayer::parseResources()
134
72.5k
  {
135
72.5k
    size_t offsetInPacket = getBasicHeaderSize();
136
72.5k
    IDnsResource* curResource = m_ResourceList;
137
138
72.5k
    uint16_t numOfQuestions = be16toh(getDnsHeader()->numberOfQuestions);
139
72.5k
    uint16_t numOfAnswers = be16toh(getDnsHeader()->numberOfAnswers);
140
72.5k
    uint16_t numOfAuthority = be16toh(getDnsHeader()->numberOfAuthority);
141
72.5k
    uint16_t numOfAdditional = be16toh(getDnsHeader()->numberOfAdditional);
142
143
72.5k
    uint32_t numOfOtherResources = numOfQuestions + numOfAnswers + numOfAuthority + numOfAdditional;
144
145
72.5k
    if (numOfOtherResources > 300)
146
10.5k
    {
147
10.5k
      PCPP_LOG_ERROR(
148
10.5k
          "DNS layer contains more than 300 resources, probably a bad packet. Skipping parsing DNS resources");
149
10.5k
      return;
150
10.5k
    }
151
152
229k
    for (uint32_t i = 0; i < numOfOtherResources; i++)
153
190k
    {
154
190k
      DnsResourceType resType;
155
190k
      if (numOfQuestions > 0)
156
106k
      {
157
106k
        resType = DnsQueryType;
158
106k
        numOfQuestions--;
159
106k
      }
160
84.0k
      else if (numOfAnswers > 0)
161
49.6k
      {
162
49.6k
        resType = DnsAnswerType;
163
49.6k
        numOfAnswers--;
164
49.6k
      }
165
34.3k
      else if (numOfAuthority > 0)
166
5.02k
      {
167
5.02k
        resType = DnsAuthorityType;
168
5.02k
        numOfAuthority--;
169
5.02k
      }
170
29.3k
      else
171
29.3k
      {
172
29.3k
        resType = DnsAdditionalType;
173
29.3k
        numOfAdditional--;
174
29.3k
      }
175
176
190k
      DnsResource* newResource = nullptr;
177
190k
      DnsQuery* newQuery = nullptr;
178
190k
      IDnsResource* newGenResource = nullptr;
179
190k
      if (resType == DnsQueryType)
180
106k
      {
181
106k
        newQuery = new DnsQuery(this, offsetInPacket);
182
106k
        newGenResource = newQuery;
183
106k
        offsetInPacket += newQuery->getSize();
184
106k
      }
185
84.0k
      else
186
84.0k
      {
187
84.0k
        newResource = new DnsResource(this, offsetInPacket, resType);
188
84.0k
        newGenResource = newResource;
189
84.0k
        offsetInPacket += newResource->getSize();
190
84.0k
      }
191
192
190k
      if (offsetInPacket > m_DataLen)
193
22.3k
      {
194
        // Parse packet failed, DNS resource is out of bounds. Probably a bad packet
195
22.3k
        delete newGenResource;
196
22.3k
        return;
197
22.3k
      }
198
199
      // this resource is the first resource
200
167k
      if (m_ResourceList == nullptr)
201
57.8k
      {
202
57.8k
        m_ResourceList = newGenResource;
203
57.8k
        curResource = m_ResourceList;
204
57.8k
      }
205
110k
      else
206
110k
      {
207
110k
        curResource->setNextResource(newGenResource);
208
110k
        curResource = curResource->getNextResource();
209
110k
      }
210
211
167k
      if (resType == DnsQueryType && m_FirstQuery == nullptr)
212
57.0k
        m_FirstQuery = newQuery;
213
110k
      else if (resType == DnsAnswerType && m_FirstAnswer == nullptr)
214
12.6k
        m_FirstAnswer = newResource;
215
98.3k
      else if (resType == DnsAuthorityType && m_FirstAuthority == nullptr)
216
2.25k
        m_FirstAuthority = newResource;
217
96.0k
      else if (resType == DnsAdditionalType && m_FirstAdditional == nullptr)
218
7.02k
        m_FirstAdditional = newResource;
219
167k
    }
220
61.9k
  }
221
222
  IDnsResource* DnsLayer::getResourceByName(IDnsResource* startFrom, size_t resourceCount, const std::string& name,
223
                                            bool exactMatch) const
224
83.5k
  {
225
83.5k
    size_t index = 0;
226
168k
    while (index < resourceCount)
227
133k
    {
228
133k
      if (startFrom == nullptr)
229
8.29k
        return nullptr;
230
231
124k
      std::string resourceName = startFrom->getName();
232
124k
      if (exactMatch && resourceName == name)
233
26
        return startFrom;
234
124k
      else if (!exactMatch && resourceName.find(name) != std::string::npos)
235
40.3k
        return startFrom;
236
237
84.4k
      startFrom = startFrom->getNextResource();
238
239
84.4k
      index++;
240
84.4k
    }
241
242
34.8k
    return nullptr;
243
83.5k
  }
244
245
  DnsQuery* DnsLayer::getQuery(const std::string& name, bool exactMatch) const
246
20.8k
  {
247
20.8k
    uint16_t numOfQueries = be16toh(getDnsHeader()->numberOfQuestions);
248
20.8k
    IDnsResource* res = getResourceByName(m_FirstQuery, numOfQueries, name, exactMatch);
249
20.8k
    if (res != nullptr)
250
10.2k
      return dynamic_cast<DnsQuery*>(res);
251
10.6k
    return nullptr;
252
20.8k
  }
253
254
  DnsQuery* DnsLayer::getFirstQuery() const
255
10.4k
  {
256
10.4k
    return m_FirstQuery;
257
10.4k
  }
258
259
  DnsQuery* DnsLayer::getNextQuery(DnsQuery* query) const
260
14.8k
  {
261
14.8k
    if (query == nullptr || query->getNextResource() == nullptr || query->getType() != DnsQueryType ||
262
9.20k
        query->getNextResource()->getType() != DnsQueryType)
263
8.13k
      return nullptr;
264
265
6.71k
    return (DnsQuery*)(query->getNextResource());
266
14.8k
  }
267
268
  size_t DnsLayer::getQueryCount() const
269
41.2k
  {
270
41.2k
    return be16toh(getDnsHeader()->numberOfQuestions);
271
41.2k
  }
272
273
  DnsResource* DnsLayer::getAnswer(const std::string& name, bool exactMatch) const
274
20.8k
  {
275
20.8k
    uint16_t numOfAnswers = be16toh(getDnsHeader()->numberOfAnswers);
276
20.8k
    IDnsResource* res = getResourceByName(m_FirstAnswer, numOfAnswers, name, exactMatch);
277
20.8k
    if (res != nullptr)
278
9.94k
      return dynamic_cast<DnsResource*>(res);
279
10.9k
    return nullptr;
280
20.8k
  }
281
282
  DnsResource* DnsLayer::getFirstAnswer() const
283
10.4k
  {
284
10.4k
    return m_FirstAnswer;
285
10.4k
  }
286
287
  DnsResource* DnsLayer::getNextAnswer(DnsResource* answer) const
288
7.20k
  {
289
7.20k
    if (answer == nullptr || answer->getNextResource() == nullptr || answer->getType() != DnsAnswerType ||
290
5.52k
        answer->getNextResource()->getType() != DnsAnswerType)
291
2.06k
      return nullptr;
292
293
5.13k
    return (DnsResource*)(answer->getNextResource());
294
7.20k
  }
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
20.8k
  {
303
20.8k
    uint16_t numOfAuthorities = be16toh(getDnsHeader()->numberOfAuthority);
304
20.8k
    IDnsResource* res = getResourceByName(m_FirstAuthority, numOfAuthorities, name, exactMatch);
305
20.8k
    if (res != nullptr)
306
10.1k
      return dynamic_cast<DnsResource*>(res);
307
10.7k
    return nullptr;
308
20.8k
  }
309
310
  DnsResource* DnsLayer::getFirstAuthority() const
311
10.4k
  {
312
10.4k
    return m_FirstAuthority;
313
10.4k
  }
314
315
  DnsResource* DnsLayer::getNextAuthority(DnsResource* authority) const
316
587
  {
317
587
    if (authority == nullptr || authority->getNextResource() == nullptr ||
318
472
        authority->getType() != DnsAuthorityType || authority->getNextResource()->getType() != DnsAuthorityType)
319
332
      return nullptr;
320
321
255
    return (DnsResource*)(authority->getNextResource());
322
587
  }
323
324
  size_t DnsLayer::getAuthorityCount() const
325
41.2k
  {
326
41.2k
    return be16toh(getDnsHeader()->numberOfAuthority);
327
41.2k
  }
328
329
  DnsResource* DnsLayer::getAdditionalRecord(const std::string& name, bool exactMatch) const
330
20.8k
  {
331
20.8k
    uint16_t numOfAdditionalRecords = be16toh(getDnsHeader()->numberOfAdditional);
332
20.8k
    IDnsResource* res = getResourceByName(m_FirstAdditional, numOfAdditionalRecords, name, exactMatch);
333
20.8k
    if (res != nullptr)
334
10.1k
      return dynamic_cast<DnsResource*>(res);
335
10.7k
    return nullptr;
336
20.8k
  }
337
338
  DnsResource* DnsLayer::getFirstAdditionalRecord() const
339
10.4k
  {
340
10.4k
    return m_FirstAdditional;
341
10.4k
  }
342
343
  DnsResource* DnsLayer::getNextAdditionalRecord(DnsResource* additionalRecord) const
344
1.42k
  {
345
1.42k
    if (additionalRecord == nullptr || additionalRecord->getNextResource() == nullptr ||
346
349
        additionalRecord->getType() != DnsAdditionalType ||
347
349
        additionalRecord->getNextResource()->getType() != DnsAdditionalType)
348
1.07k
      return nullptr;
349
350
349
    return (DnsResource*)(additionalRecord->getNextResource());
351
1.42k
  }
352
353
  size_t DnsLayer::getAdditionalRecordCount() const
354
41.2k
  {
355
41.2k
    return be16toh(getDnsHeader()->numberOfAdditional);
356
41.2k
  }
357
358
  std::string DnsLayer::toString() const
359
20.8k
  {
360
20.8k
    std::ostringstream tidAsString;
361
20.8k
    tidAsString << be16toh(getDnsHeader()->transactionID);
362
363
20.8k
    std::ostringstream queryCount;
364
20.8k
    queryCount << getQueryCount();
365
366
20.8k
    std::ostringstream answerCount;
367
20.8k
    answerCount << getAnswerCount();
368
369
20.8k
    std::ostringstream authorityCount;
370
20.8k
    authorityCount << getAuthorityCount();
371
372
20.8k
    std::ostringstream additionalCount;
373
20.8k
    additionalCount << getAdditionalRecordCount();
374
375
20.8k
    if (getDnsHeader()->queryOrResponse == 1)
376
4.17k
    {
377
4.17k
      return "DNS query response, ID: " + tidAsString.str() + ";" + " queries: " + queryCount.str() +
378
4.17k
             ", answers: " + answerCount.str() + ", authorities: " + authorityCount.str() +
379
4.17k
             ", additional record: " + additionalCount.str();
380
4.17k
    }
381
16.7k
    else if (getDnsHeader()->queryOrResponse == 0)
382
16.7k
    {
383
16.7k
      return "DNS query, ID: " + tidAsString.str() + ";" + " queries: " + queryCount.str() +
384
16.7k
             ", answers: " + answerCount.str() + ", authorities: " + authorityCount.str() +
385
16.7k
             ", additional record: " + additionalCount.str();
386
16.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
20.8k
  }
394
395
  IDnsResource* DnsLayer::getFirstResource(DnsResourceType resType) const
396
40.4k
  {
397
40.4k
    switch (resType)
398
40.4k
    {
399
10.2k
    case DnsQueryType:
400
10.2k
    {
401
10.2k
      return m_FirstQuery;
402
0
    }
403
9.94k
    case DnsAnswerType:
404
9.94k
    {
405
9.94k
      return m_FirstAnswer;
406
0
    }
407
10.1k
    case DnsAuthorityType:
408
10.1k
    {
409
10.1k
      return m_FirstAuthority;
410
0
    }
411
10.1k
    case DnsAdditionalType:
412
10.1k
    {
413
10.1k
      return m_FirstAdditional;
414
0
    }
415
0
    default:
416
0
      return nullptr;
417
40.4k
    }
418
40.4k
  }
419
420
  void DnsLayer::setFirstResource(DnsResourceType resType, IDnsResource* resource)
421
56.9k
  {
422
56.9k
    switch (resType)
423
56.9k
    {
424
2.11k
    case DnsQueryType:
425
2.11k
    {
426
2.11k
      m_FirstQuery = dynamic_cast<DnsQuery*>(resource);
427
2.11k
      break;
428
0
    }
429
16.5k
    case DnsAnswerType:
430
16.5k
    {
431
16.5k
      m_FirstAnswer = dynamic_cast<DnsResource*>(resource);
432
16.5k
      break;
433
0
    }
434
19.9k
    case DnsAuthorityType:
435
19.9k
    {
436
19.9k
      m_FirstAuthority = dynamic_cast<DnsResource*>(resource);
437
19.9k
      break;
438
0
    }
439
18.3k
    case DnsAdditionalType:
440
18.3k
    {
441
18.3k
      m_FirstAdditional = dynamic_cast<DnsResource*>(resource);
442
18.3k
      break;
443
0
    }
444
0
    default:
445
0
      return;
446
56.9k
    }
447
56.9k
  }
448
449
  DnsResource* DnsLayer::addResource(DnsResourceType resType, const std::string& name, DnsType dnsType,
450
                                     DnsClass dnsClass, uint32_t ttl, IDnsResourceData* data)
451
31.3k
  {
452
    // create new query on temporary buffer
453
31.3k
    uint8_t newResourceRawData[4096];
454
31.3k
    memset(newResourceRawData, 0, sizeof(newResourceRawData));
455
456
31.3k
    DnsResource* newResource = new DnsResource(newResourceRawData, resType);
457
458
31.3k
    newResource->setDnsClass(dnsClass);
459
460
31.3k
    newResource->setDnsType(dnsType);
461
462
    // cannot return false since layer shouldn't be extended or shortened in this stage
463
31.3k
    newResource->setName(name);
464
465
31.3k
    newResource->setTTL(ttl);
466
467
31.3k
    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
31.3k
    size_t newResourceOffsetInLayer = getBasicHeaderSize();
475
31.3k
    IDnsResource* curResource = m_ResourceList;
476
74.5k
    while (curResource != nullptr && curResource->getType() <= resType)
477
68.3k
    {
478
68.3k
      newResourceOffsetInLayer += curResource->getSize();
479
480
68.3k
      if (newResourceOffsetInLayer > m_DataLen)
481
0
      {
482
        // This possibly means that the DNS layer has been created from a malformed packet.
483
0
        PCPP_LOG_ERROR("Couldn't add resource! DNS Layer is malformed and contains out of bounds resources.");
484
0
        delete newResource;
485
0
        return nullptr;
486
0
      }
487
488
68.3k
      IDnsResource* nextResource = curResource->getNextResource();
489
68.3k
      if (nextResource == nullptr || nextResource->getType() > resType)
490
25.1k
        break;
491
43.1k
      curResource = nextResource;
492
43.1k
    }
493
494
    // set next resource for new resource. This must happen here for extendLayer to succeed
495
31.3k
    if (curResource != nullptr)
496
25.1k
    {
497
25.1k
      if (curResource->getType() > newResource->getType())
498
7
        newResource->setNextResource(m_ResourceList);
499
25.1k
      else
500
25.1k
        newResource->setNextResource(curResource->getNextResource());
501
25.1k
    }
502
6.17k
    else
503
6.17k
    {
504
      // curResource != nullptr
505
6.17k
      newResource->setNextResource(m_ResourceList);
506
6.17k
    }
507
508
    // extend layer to make room for the new resource
509
31.3k
    if (!extendLayer(newResourceOffsetInLayer, newResource->getSize(), newResource))
510
723
    {
511
723
      PCPP_LOG_ERROR("Couldn't extend DNS layer, addResource failed");
512
723
      delete newResource;
513
723
      return nullptr;
514
723
    }
515
516
    // connect the new resource to layer
517
30.6k
    newResource->setDnsLayer(this, newResourceOffsetInLayer);
518
519
    // connect the new resource to the layer's resource list
520
30.6k
    if (curResource != nullptr)
521
25.0k
    {
522
25.0k
      curResource->setNextResource(newResource);
523
      // this means the new resource is the first of it's type
524
25.0k
      if (curResource->getType() < newResource->getType())
525
22.0k
      {
526
22.0k
        setFirstResource(resType, newResource);
527
22.0k
      }
528
      // this means the new resource should be the first resource in the packet
529
3.04k
      else if (curResource->getType() > newResource->getType())
530
0
      {
531
0
        m_ResourceList = newResource;
532
533
0
        setFirstResource(resType, newResource);
534
0
      }
535
25.0k
    }
536
5.52k
    else  // curResource != nullptr, meaning this is the first resource in layer
537
5.52k
    {
538
5.52k
      m_ResourceList = newResource;
539
540
5.52k
      setFirstResource(resType, newResource);
541
5.52k
    }
542
543
30.6k
    return newResource;
544
31.3k
  }
545
546
  DnsQuery* DnsLayer::addQuery(const std::string& name, DnsType dnsType, DnsClass dnsClass)
547
10.4k
  {
548
    // create new query on temporary buffer
549
10.4k
    uint8_t newQueryRawData[256];
550
10.4k
    DnsQuery* newQuery = new DnsQuery(newQueryRawData);
551
552
10.4k
    newQuery->setDnsClass(dnsClass);
553
10.4k
    newQuery->setDnsType(dnsType);
554
555
    // cannot return false since layer shouldn't be extended or shortened in this stage
556
10.4k
    newQuery->setName(name);
557
558
    // find the offset in the layer to insert the new query
559
10.4k
    size_t newQueryOffsetInLayer = getBasicHeaderSize();
560
10.4k
    DnsQuery* curQuery = getFirstQuery();
561
17.1k
    while (curQuery != nullptr)
562
14.8k
    {
563
14.8k
      newQueryOffsetInLayer += curQuery->getSize();
564
14.8k
      DnsQuery* nextQuery = getNextQuery(curQuery);
565
14.8k
      if (nextQuery == nullptr)
566
8.13k
        break;
567
6.71k
      curQuery = nextQuery;
568
6.71k
    }
569
570
    // set next resource for new query. This must happen here for extendLayer to succeed
571
10.4k
    if (curQuery != nullptr)
572
8.13k
      newQuery->setNextResource(curQuery->getNextResource());
573
2.30k
    else
574
2.30k
      newQuery->setNextResource(m_ResourceList);
575
576
    // extend layer to make room for the new query
577
10.4k
    if (!extendLayer(newQueryOffsetInLayer, newQuery->getSize(), newQuery))
578
242
    {
579
242
      PCPP_LOG_ERROR("Couldn't extend DNS layer, addQuery failed");
580
242
      delete newQuery;
581
242
      return nullptr;
582
242
    }
583
584
    // connect the new query to layer
585
10.2k
    newQuery->setDnsLayer(this, newQueryOffsetInLayer);
586
587
    // connect the new query to the layer's resource list
588
10.2k
    if (curQuery != nullptr)
589
8.12k
      curQuery->setNextResource(newQuery);
590
2.08k
    else  // curQuery == nullptr, meaning this is the first query
591
2.08k
    {
592
2.08k
      m_ResourceList = newQuery;
593
2.08k
      m_FirstQuery = newQuery;
594
2.08k
    }
595
596
    // increase number of queries
597
10.2k
    getDnsHeader()->numberOfQuestions = htobe16(getQueryCount() + 1);
598
599
10.2k
    return newQuery;
600
10.4k
  }
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
20.8k
  {
612
20.8k
    DnsQuery* queryToRemove = getQuery(queryNameToRemove, exactMatch);
613
20.8k
    if (queryToRemove == nullptr)
614
10.6k
    {
615
10.6k
      PCPP_LOG_DEBUG("Query not found");
616
10.6k
      return false;
617
10.6k
    }
618
619
10.2k
    return removeQuery(queryToRemove);
620
20.8k
  }
621
622
  bool DnsLayer::removeQuery(DnsQuery* queryToRemove)
623
10.2k
  {
624
10.2k
    bool res = removeResource(queryToRemove);
625
10.2k
    if (res)
626
10.2k
    {
627
      // decrease number of query records
628
10.2k
      getDnsHeader()->numberOfQuestions = htobe16(getQueryCount() - 1);
629
10.2k
    }
630
631
10.2k
    return res;
632
10.2k
  }
633
634
  DnsResource* DnsLayer::addAnswer(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl,
635
                                   IDnsResourceData* data)
636
10.4k
  {
637
10.4k
    DnsResource* res = addResource(DnsAnswerType, name, dnsType, dnsClass, ttl, data);
638
10.4k
    if (res != nullptr)
639
10.2k
    {
640
      // increase number of answer records
641
10.2k
      getDnsHeader()->numberOfAnswers = htobe16(getAnswerCount() + 1);
642
10.2k
    }
643
644
10.4k
    return res;
645
10.4k
  }
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
20.8k
  {
658
20.8k
    DnsResource* answerToRemove = getAnswer(answerNameToRemove, exactMatch);
659
20.8k
    if (answerToRemove == nullptr)
660
10.9k
    {
661
10.9k
      PCPP_LOG_DEBUG("Answer record not found");
662
10.9k
      return false;
663
10.9k
    }
664
665
9.94k
    return removeAnswer(answerToRemove);
666
20.8k
  }
667
668
  bool DnsLayer::removeAnswer(DnsResource* answerToRemove)
669
9.94k
  {
670
9.94k
    bool res = removeResource(answerToRemove);
671
9.94k
    if (res)
672
9.94k
    {
673
      // decrease number of answer records
674
9.94k
      getDnsHeader()->numberOfAnswers = htobe16(getAnswerCount() - 1);
675
9.94k
    }
676
677
9.94k
    return res;
678
9.94k
  }
679
680
  DnsResource* DnsLayer::addAuthority(const std::string& name, DnsType dnsType, DnsClass dnsClass, uint32_t ttl,
681
                                      IDnsResourceData* data)
682
10.4k
  {
683
10.4k
    DnsResource* res = addResource(DnsAuthorityType, name, dnsType, dnsClass, ttl, data);
684
10.4k
    if (res != nullptr)
685
10.2k
    {
686
      // increase number of authority records
687
10.2k
      getDnsHeader()->numberOfAuthority = htobe16(getAuthorityCount() + 1);
688
10.2k
    }
689
690
10.4k
    return res;
691
10.4k
  }
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
20.8k
  {
704
20.8k
    DnsResource* authorityToRemove = getAuthority(authorityNameToRemove, exactMatch);
705
20.8k
    if (authorityToRemove == nullptr)
706
10.7k
    {
707
10.7k
      PCPP_LOG_DEBUG("Authority not found");
708
10.7k
      return false;
709
10.7k
    }
710
711
10.1k
    return removeAuthority(authorityToRemove);
712
20.8k
  }
713
714
  bool DnsLayer::removeAuthority(DnsResource* authorityToRemove)
715
10.1k
  {
716
10.1k
    bool res = removeResource(authorityToRemove);
717
10.1k
    if (res)
718
10.1k
    {
719
      // decrease number of authority records
720
10.1k
      getDnsHeader()->numberOfAuthority = htobe16(getAuthorityCount() - 1);
721
10.1k
    }
722
723
10.1k
    return res;
724
10.1k
  }
725
726
  DnsResource* DnsLayer::addAdditionalRecord(const std::string& name, DnsType dnsType, DnsClass dnsClass,
727
                                             uint32_t ttl, IDnsResourceData* data)
728
10.4k
  {
729
10.4k
    DnsResource* res = addResource(DnsAdditionalType, name, dnsType, dnsClass, ttl, data);
730
10.4k
    if (res != nullptr)
731
10.2k
    {
732
      // increase number of authority records
733
10.2k
      getDnsHeader()->numberOfAdditional = htobe16(getAdditionalRecordCount() + 1);
734
10.2k
    }
735
736
10.4k
    return res;
737
10.4k
  }
738
739
  DnsResource* DnsLayer::addAdditionalRecord(const std::string& name, DnsType dnsType, uint16_t customData1,
740
                                             uint32_t customData2, IDnsResourceData* data)
741
10.4k
  {
742
10.4k
    DnsResource* res = addAdditionalRecord(name, dnsType, DNS_CLASS_ANY, customData2, data);
743
10.4k
    if (res != nullptr)
744
10.2k
    {
745
10.2k
      res->setCustomDnsClass(customData1);
746
10.2k
    }
747
748
10.4k
    return res;
749
10.4k
  }
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
20.8k
  {
763
20.8k
    DnsResource* additionalRecordToRemove = getAdditionalRecord(additionalRecordNameToRemove, exactMatch);
764
20.8k
    if (additionalRecordToRemove == nullptr)
765
10.7k
    {
766
10.7k
      PCPP_LOG_DEBUG("Additional record not found");
767
10.7k
      return false;
768
10.7k
    }
769
770
10.1k
    return removeAdditionalRecord(additionalRecordToRemove);
771
20.8k
  }
772
773
  bool DnsLayer::removeAdditionalRecord(DnsResource* additionalRecordToRemove)
774
10.1k
  {
775
10.1k
    bool res = removeResource(additionalRecordToRemove);
776
10.1k
    if (res)
777
10.1k
    {
778
      // decrease number of additional records
779
10.1k
      getDnsHeader()->numberOfAdditional = htobe16(getAdditionalRecordCount() - 1);
780
10.1k
    }
781
782
10.1k
    return res;
783
10.1k
  }
784
785
  bool DnsLayer::removeResource(IDnsResource* resourceToRemove)
786
40.4k
  {
787
40.4k
    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
40.4k
    IDnsResource* prevResource = m_ResourceList;
795
796
40.4k
    if (m_ResourceList != resourceToRemove)
797
33.0k
    {
798
79.8k
      while (prevResource != nullptr)
799
79.8k
      {
800
79.8k
        IDnsResource* temp = prevResource->getNextResource();
801
79.8k
        if (temp == resourceToRemove)
802
33.0k
          break;
803
804
46.7k
        prevResource = temp;
805
46.7k
      }
806
33.0k
    }
807
808
40.4k
    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
40.4k
    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
40.4k
    if (m_ResourceList != resourceToRemove)
823
33.0k
    {
824
33.0k
      prevResource->setNextResource(resourceToRemove->getNextResource());
825
33.0k
    }
826
7.31k
    else
827
7.31k
    {
828
7.31k
      m_ResourceList = resourceToRemove->getNextResource();
829
7.31k
    }
830
831
    // check whether resourceToRemove was the first of its type
832
40.4k
    if (getFirstResource(resourceToRemove->getType()) == resourceToRemove)
833
29.3k
    {
834
29.3k
      IDnsResource* nextResource = resourceToRemove->getNextResource();
835
29.3k
      if (nextResource != nullptr && nextResource->getType() == resourceToRemove->getType())
836
163
        setFirstResource(resourceToRemove->getType(), nextResource);
837
29.2k
      else
838
29.2k
        setFirstResource(resourceToRemove->getType(), nullptr);
839
29.3k
    }
840
841
    // free resourceToRemove memory
842
40.4k
    delete resourceToRemove;
843
844
40.4k
    return true;
845
40.4k
  }
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
982
  {
858
982
    ((uint16_t*)m_Data)[0] = htobe16(value);
859
982
  }
860
861
  void DnsOverTcpLayer::computeCalculateFields()
862
982
  {
863
982
    setTcpMessageLength(m_DataLen - sizeof(uint16_t));
864
982
  }
865
866
}  // namespace pcpp