Coverage Report

Created: 2025-12-14 07:46

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