Coverage Report

Created: 2025-11-09 07:08

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