Coverage Report

Created: 2026-10-17 07:09

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