Coverage Report

Created: 2023-01-25 06:41

/src/PcapPlusPlus/Packet++/src/IgmpLayer.cpp
Line
Count
Source (jump to first uncovered line)
1
#define LOG_MODULE PacketLogModuleIgmpLayer
2
3
#include "IgmpLayer.h"
4
#include "PacketUtils.h"
5
#include "Logger.h"
6
#include <string.h>
7
#include "EndianPortable.h"
8
9
namespace pcpp
10
{
11
12
/*************
13
 * IgmpLayer
14
 *************/
15
16
IgmpLayer::IgmpLayer(IgmpType type, const IPv4Address& groupAddr, uint8_t maxResponseTime, ProtocolType igmpVer)
17
0
{
18
0
  m_DataLen = getHeaderSizeByVerAndType(igmpVer, type);
19
0
  m_Data = new uint8_t[m_DataLen];
20
0
  memset(m_Data, 0, m_DataLen);
21
0
  m_Protocol = igmpVer;
22
23
0
  setType(type);
24
0
  if (groupAddr.isValid())
25
0
    setGroupAddress(groupAddr);
26
27
0
  getIgmpHeader()->maxResponseTime = maxResponseTime;
28
0
}
29
30
void IgmpLayer::setGroupAddress(const IPv4Address& groupAddr)
31
0
{
32
0
  igmp_header* hdr = getIgmpHeader();
33
0
  hdr->groupAddress = groupAddr.toInt();
34
0
}
35
36
IgmpType IgmpLayer::getType() const
37
0
{
38
0
  uint8_t type = getIgmpHeader()->type;
39
0
  if (type < (uint8_t)IgmpType_MembershipQuery ||
40
0
      (type > (uint8_t)IgmpType_LeaveGroup && type < (uint8_t)IgmpType_MulticastTracerouteResponse) ||
41
0
      (type > (uint8_t)IgmpType_MulticastTraceroute && type < (uint8_t)IgmpType_MembershipReportV3) ||
42
0
      (type > (uint8_t)IgmpType_MembershipReportV3 && type < (uint8_t)IgmpType_MulticastRouterAdvertisement) ||
43
0
      type > IgmpType_MulticastRouterTermination)
44
0
    return IgmpType_Unknown;
45
46
0
  return (IgmpType)type;
47
0
}
48
49
void IgmpLayer::setType(IgmpType type)
50
0
{
51
0
  if (type == IgmpType_Unknown)
52
0
    return;
53
54
0
  igmp_header* hdr = getIgmpHeader();
55
0
  hdr->type = type;
56
0
}
57
58
ProtocolType IgmpLayer::getIGMPVerFromData(uint8_t* data, size_t dataLen, bool& isQuery)
59
2.80k
{
60
2.80k
  isQuery = false;
61
62
2.80k
  if (dataLen < 8 || data == NULL)
63
232
    return UnknownProtocol;
64
65
2.57k
  switch ((int)data[0])
66
2.57k
  {
67
280
  case IgmpType_MembershipReportV2:
68
422
  case IgmpType_LeaveGroup:
69
422
    return IGMPv2;
70
444
  case IgmpType_MembershipReportV1:
71
444
    return IGMPv1;
72
66
  case IgmpType_MembershipReportV3:
73
66
    return IGMPv3;
74
845
  case IgmpType_MembershipQuery:
75
845
  {
76
845
    isQuery = true;
77
78
845
    if (dataLen >= sizeof(igmpv3_query_header))
79
225
      return IGMPv3;
80
81
620
    if (data[1] == 0)
82
373
      return IGMPv1;
83
247
    else
84
247
      return IGMPv2;
85
620
  }
86
796
  default:
87
796
    return UnknownProtocol;
88
2.57k
  }
89
2.57k
}
90
91
uint16_t IgmpLayer::calculateChecksum()
92
0
{
93
0
  ScalarBuffer<uint16_t> buffer;
94
0
  buffer.buffer = (uint16_t*)getIgmpHeader();
95
0
  buffer.len = getHeaderLen();
96
0
  return computeChecksum(&buffer, 1);
97
0
}
98
99
size_t IgmpLayer::getHeaderSizeByVerAndType(ProtocolType igmpVer, IgmpType igmpType) const
100
0
{
101
0
  if (igmpVer == IGMPv1 || igmpVer == IGMPv2)
102
0
    return sizeof(igmp_header);
103
104
0
  if (igmpVer == IGMPv3)
105
0
  {
106
0
    if (igmpType == IgmpType_MembershipQuery)
107
0
      return sizeof(igmpv3_query_header);
108
0
    else if (igmpType == IgmpType_MembershipReportV3)
109
0
      return sizeof(igmpv3_report_header);
110
0
  }
111
112
0
  return 0;
113
0
}
114
115
std::string IgmpLayer::toString() const
116
0
{
117
0
  std::string igmpVer = "";
118
0
  switch (getProtocol())
119
0
  {
120
0
  case IGMPv1:
121
0
    igmpVer = "1";
122
0
    break;
123
0
  case IGMPv2:
124
0
    igmpVer = "2";
125
0
    break;
126
0
  default:
127
0
    igmpVer = "3";
128
0
  }
129
130
0
  std::string msgType;
131
132
0
  switch (getType())
133
0
  {
134
0
  case IgmpType_MembershipQuery:
135
0
    msgType = "Membership Query";
136
0
    break;
137
0
  case IgmpType_MembershipReportV1:
138
0
    msgType = "Membership Report";
139
0
    break;
140
0
  case IgmpType_DVMRP:
141
0
    msgType = "DVMRP";
142
0
    break;
143
0
  case IgmpType_P1Mv1:
144
0
    msgType = "PIMv1";
145
0
    break;
146
0
  case IgmpType_CiscoTrace:
147
0
    msgType = "Cisco Trace";
148
0
    break;
149
0
  case IgmpType_MembershipReportV2:
150
0
    msgType = "Membership Report";
151
0
    break;
152
0
  case IgmpType_LeaveGroup:
153
0
    msgType = "Leave Group";
154
0
    break;
155
0
  case IgmpType_MulticastTracerouteResponse:
156
0
    msgType = "Multicast Traceroute Response";
157
0
    break;
158
0
  case IgmpType_MulticastTraceroute:
159
0
    msgType = "Multicast Traceroute";
160
0
    break;
161
0
  case IgmpType_MembershipReportV3:
162
0
    msgType = "Membership Report";
163
0
    break;
164
0
  case IgmpType_MulticastRouterAdvertisement:
165
0
    msgType = "Multicast Router Advertisement";
166
0
    break;
167
0
  case IgmpType_MulticastRouterSolicitation:
168
0
    msgType = "Multicast Router Solicitation";
169
0
    break;
170
0
  case IgmpType_MulticastRouterTermination:
171
0
    msgType = "Multicast Router Termination";
172
0
    break;
173
0
  default:
174
0
    msgType = "Unknown";
175
0
    break;
176
0
  }
177
178
0
  std::string result = "IGMPv" + igmpVer + " Layer, " + msgType + " message";
179
0
  return result;
180
0
}
181
182
183
184
185
/*************
186
 * IgmpV1Layer
187
 *************/
188
189
190
void IgmpV1Layer::computeCalculateFields()
191
0
{
192
0
  igmp_header* hdr = getIgmpHeader();
193
0
  hdr->checksum = 0;
194
0
  hdr->checksum = htobe16(calculateChecksum());
195
0
  hdr->maxResponseTime = 0;
196
0
}
197
198
199
200
201
202
/*************
203
 * IgmpV2Layer
204
 *************/
205
206
207
void IgmpV2Layer::computeCalculateFields()
208
0
{
209
0
  igmp_header* hdr = getIgmpHeader();
210
0
  hdr->checksum = 0;
211
0
  hdr->checksum = htobe16(calculateChecksum());
212
0
}
213
214
215
216
217
218
/******************
219
 * IgmpV3QueryLayer
220
 ******************/
221
222
223
IgmpV3QueryLayer::IgmpV3QueryLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) :
224
    IgmpLayer(data, dataLen, prevLayer, packet, IGMPv3)
225
225
{
226
225
}
227
228
IgmpV3QueryLayer::IgmpV3QueryLayer(const IPv4Address& multicastAddr, uint8_t maxResponseTime, uint8_t s_qrv) :
229
    IgmpLayer(IgmpType_MembershipQuery, multicastAddr, maxResponseTime, IGMPv3)
230
0
{
231
0
  getIgmpV3QueryHeader()->s_qrv = s_qrv;
232
0
}
233
234
uint16_t IgmpV3QueryLayer::getSourceAddressCount() const
235
0
{
236
0
  return be16toh(getIgmpV3QueryHeader()->numOfSources);
237
0
}
238
239
IPv4Address IgmpV3QueryLayer::getSourceAddressAtIndex(int index) const
240
0
{
241
0
  uint16_t numOfSources = getSourceAddressCount();
242
0
  if (index < 0 || index >= numOfSources)
243
0
    return IPv4Address();
244
245
  // verify numOfRecords is a reasonable number that points to data within the packet
246
0
  int ptrOffset = index * sizeof(uint32_t) + sizeof(igmpv3_query_header);
247
0
  if (ptrOffset + sizeof(uint32_t) > getDataLen())
248
0
    return IPv4Address();
249
250
0
  uint8_t* ptr = m_Data + ptrOffset;
251
0
  return IPv4Address(*(uint32_t*)ptr);
252
0
}
253
254
size_t IgmpV3QueryLayer::getHeaderLen() const
255
0
{
256
0
  uint16_t numOfSources = getSourceAddressCount();
257
258
0
  int headerLen = numOfSources * sizeof(uint32_t) + sizeof(igmpv3_query_header);
259
260
  // verify numOfRecords is a reasonable number that points to data within the packet
261
0
  if ((size_t)headerLen > getDataLen())
262
0
    return getDataLen();
263
264
0
  return (size_t)headerLen;
265
0
}
266
267
void IgmpV3QueryLayer::computeCalculateFields()
268
0
{
269
0
  igmpv3_query_header* hdr = getIgmpV3QueryHeader();
270
0
  hdr->checksum = 0;
271
0
  hdr->checksum = htobe16(calculateChecksum());
272
0
}
273
274
bool IgmpV3QueryLayer::addSourceAddress(const IPv4Address& addr)
275
0
{
276
0
  return addSourceAddressAtIndex(addr, getSourceAddressCount());
277
0
}
278
279
bool IgmpV3QueryLayer::addSourceAddressAtIndex(const IPv4Address& addr, int index)
280
0
{
281
0
  uint16_t sourceAddrCount = getSourceAddressCount();
282
283
0
  if (index < 0 || index > (int)sourceAddrCount)
284
0
  {
285
0
    PCPP_LOG_ERROR("Cannot add source address at index " << index << ", index is out of bounds");
286
0
    return false;
287
0
  }
288
289
0
  size_t offset = sizeof(igmpv3_query_header) + index * sizeof(uint32_t);
290
0
  if (offset > getHeaderLen())
291
0
  {
292
0
    PCPP_LOG_ERROR("Cannot add source address at index " << index << ", index is out of packet bounds");
293
0
    return false;
294
0
  }
295
296
0
  if (!extendLayer(offset, sizeof(uint32_t)))
297
0
  {
298
0
    PCPP_LOG_ERROR("Cannot add source address at index " << index << ", didn't manage to extend layer");
299
0
    return false;
300
0
  }
301
302
0
  memcpy(m_Data + offset, addr.toBytes(), sizeof(uint32_t));
303
304
0
  getIgmpV3QueryHeader()->numOfSources = htobe16(sourceAddrCount+1);
305
306
0
  return true;
307
0
}
308
309
bool IgmpV3QueryLayer::removeSourceAddressAtIndex(int index)
310
0
{
311
0
  uint16_t sourceAddrCount = getSourceAddressCount();
312
313
0
  if (index < 0 || index > (int)sourceAddrCount-1)
314
0
  {
315
0
    PCPP_LOG_ERROR("Cannot remove source address at index " << index << ", index is out of bounds");
316
0
    return false;
317
0
  }
318
319
0
  size_t offset = sizeof(igmpv3_query_header) + index * sizeof(uint32_t);
320
0
  if (offset >= getHeaderLen())
321
0
  {
322
0
    PCPP_LOG_ERROR("Cannot remove source address at index " << index << ", index is out of packet bounds");
323
0
    return false;
324
0
  }
325
326
0
  if (!shortenLayer(offset, sizeof(uint32_t)))
327
0
  {
328
0
    PCPP_LOG_ERROR("Cannot remove source address at index " << index << ", didn't manage to shorten layer");
329
0
    return false;
330
0
  }
331
332
0
  getIgmpV3QueryHeader()->numOfSources = htobe16(sourceAddrCount-1);
333
334
0
  return true;
335
0
}
336
337
bool IgmpV3QueryLayer::removeAllSourceAddresses()
338
0
{
339
0
  size_t offset = sizeof(igmpv3_query_header);
340
0
  size_t numOfBytesToShorted = getHeaderLen() - offset;
341
342
0
  if (!shortenLayer(offset, numOfBytesToShorted))
343
0
  {
344
0
    PCPP_LOG_ERROR("Cannot remove all source addresses, didn't manage to shorten layer");
345
0
    return false;
346
0
  }
347
348
0
  getIgmpV3QueryHeader()->numOfSources = 0;
349
350
0
  return true;
351
0
}
352
353
354
355
356
357
/*******************
358
 * IgmpV3ReportLayer
359
 *******************/
360
361
362
uint16_t IgmpV3ReportLayer::getGroupRecordCount() const
363
0
{
364
0
  return be16toh(getReportHeader()->numOfGroupRecords);
365
0
}
366
367
igmpv3_group_record* IgmpV3ReportLayer::getFirstGroupRecord() const
368
0
{
369
  // check if there are group records at all
370
0
  if (getHeaderLen() <= sizeof(igmpv3_report_header))
371
0
    return NULL;
372
373
0
  uint8_t* curGroupPtr = m_Data + sizeof(igmpv3_report_header);
374
0
  return (igmpv3_group_record*)curGroupPtr;
375
0
}
376
377
igmpv3_group_record* IgmpV3ReportLayer::getNextGroupRecord(igmpv3_group_record* groupRecord) const
378
0
{
379
0
  if (groupRecord == NULL)
380
0
    return NULL;
381
382
  // prev group was the last group
383
0
  if ((uint8_t*)groupRecord + groupRecord->getRecordLen() - m_Data >= (int)getHeaderLen())
384
0
    return NULL;
385
386
0
  igmpv3_group_record* nextGroup = (igmpv3_group_record*)((uint8_t*)groupRecord + groupRecord->getRecordLen());
387
388
0
  return nextGroup;
389
0
}
390
391
void IgmpV3ReportLayer::computeCalculateFields()
392
0
{
393
0
  igmpv3_report_header* hdr = getReportHeader();
394
0
  hdr->checksum = 0;
395
0
  hdr->checksum = htobe16(calculateChecksum());
396
0
}
397
398
igmpv3_group_record* IgmpV3ReportLayer::addGroupRecordAt(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int offset)
399
0
{
400
0
  if (offset > (int)getHeaderLen())
401
0
  {
402
0
    PCPP_LOG_ERROR("Cannot add group record, offset is out of layer bounds");
403
0
    return NULL;
404
0
  }
405
406
0
  size_t groupRecordSize = sizeof(igmpv3_group_record) + sizeof(uint32_t)*sourceAddresses.size();
407
408
0
  if (!extendLayer(offset, groupRecordSize))
409
0
  {
410
0
    PCPP_LOG_ERROR("Cannot add group record, cannot extend layer");
411
0
    return NULL;
412
0
  }
413
414
0
  uint8_t* groupRecordBuffer = new uint8_t[groupRecordSize];
415
0
  memset(groupRecordBuffer, 0, groupRecordSize);
416
0
  igmpv3_group_record* newGroupRecord = (igmpv3_group_record*)groupRecordBuffer;
417
0
  newGroupRecord->multicastAddress = multicastAddress.toInt();
418
0
  newGroupRecord->recordType = recordType;
419
0
  newGroupRecord->auxDataLen = 0;
420
0
  newGroupRecord->numOfSources = htobe16(sourceAddresses.size());
421
422
0
  int srcAddrOffset = 0;
423
0
  for (std::vector<IPv4Address>::const_iterator iter = sourceAddresses.begin(); iter != sourceAddresses.end(); iter++)
424
0
  {
425
0
    memcpy(newGroupRecord->sourceAddresses + srcAddrOffset, iter->toBytes(), sizeof(uint32_t));
426
0
    srcAddrOffset += sizeof(uint32_t);
427
0
  }
428
429
0
  memcpy(m_Data + offset, groupRecordBuffer, groupRecordSize);
430
431
0
  delete[] groupRecordBuffer;
432
433
0
  getReportHeader()->numOfGroupRecords = htobe16(getGroupRecordCount() + 1);
434
435
0
  return (igmpv3_group_record*)(m_Data + offset);
436
0
}
437
438
igmpv3_group_record* IgmpV3ReportLayer::addGroupRecord(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses)
439
0
{
440
0
  return addGroupRecordAt(recordType, multicastAddress, sourceAddresses, (int)getHeaderLen());
441
0
}
442
443
igmpv3_group_record* IgmpV3ReportLayer::addGroupRecordAtIndex(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int index)
444
0
{
445
0
  int groupCnt = (int)getGroupRecordCount();
446
447
0
  if (index < 0 || index > groupCnt)
448
0
  {
449
0
    PCPP_LOG_ERROR("Cannot add group record, index " << index << " out of bounds");
450
0
    return NULL;
451
0
  }
452
453
0
  size_t offset = sizeof(igmpv3_report_header);
454
455
0
  igmpv3_group_record* curRecord = getFirstGroupRecord();
456
0
  for (int i = 0; i < index; i++)
457
0
  {
458
0
    if (curRecord == NULL)
459
0
    {
460
0
      PCPP_LOG_ERROR("Cannot add group record, cannot find group record at index " << i);
461
0
      return NULL;
462
0
    }
463
464
0
    offset += curRecord->getRecordLen();
465
0
    curRecord = getNextGroupRecord(curRecord);
466
0
  }
467
468
0
  return addGroupRecordAt(recordType, multicastAddress, sourceAddresses, (int)offset);
469
0
}
470
471
bool IgmpV3ReportLayer::removeGroupRecordAtIndex(int index)
472
0
{
473
0
  int groupCnt = (int)getGroupRecordCount();
474
475
0
  if (index < 0 || index >= groupCnt)
476
0
  {
477
0
    PCPP_LOG_ERROR("Cannot remove group record, index " << index << " is out of bounds");
478
0
    return false;
479
0
  }
480
481
0
  size_t offset = sizeof(igmpv3_report_header);
482
483
0
  igmpv3_group_record* curRecord = getFirstGroupRecord();
484
0
  for (int i = 0; i < index; i++)
485
0
  {
486
0
    if (curRecord == NULL)
487
0
    {
488
0
      PCPP_LOG_ERROR("Cannot remove group record at index " << index << ", cannot find group record at index " << i);
489
0
      return false;
490
0
    }
491
492
0
    offset += curRecord->getRecordLen();
493
0
    curRecord = getNextGroupRecord(curRecord);
494
0
  }
495
496
0
  if (!shortenLayer((int)offset, curRecord->getRecordLen()))
497
0
  {
498
0
    PCPP_LOG_ERROR("Cannot remove group record at index " << index << ", cannot shorted layer");
499
0
    return false;
500
0
  }
501
502
0
  getReportHeader()->numOfGroupRecords = htobe16(groupCnt-1);
503
504
0
  return true;
505
0
}
506
507
bool IgmpV3ReportLayer::removeAllGroupRecords()
508
0
{
509
0
  int offset = (int)sizeof(igmpv3_report_header);
510
511
0
  if (!shortenLayer(offset, getHeaderLen()-offset))
512
0
  {
513
0
    PCPP_LOG_ERROR("Cannot remove all group records, cannot shorted layer");
514
0
    return false;
515
0
  }
516
517
0
  getReportHeader()->numOfGroupRecords = 0;
518
0
  return true;
519
0
}
520
521
522
523
524
525
526
/*********************
527
 * igmpv3_group_record
528
 *********************/
529
530
uint16_t igmpv3_group_record::getSourceAddressCount() const
531
0
{
532
0
  return be16toh(numOfSources);
533
0
}
534
535
IPv4Address igmpv3_group_record::getSourceAddressAtIndex(int index) const
536
0
{
537
0
  uint16_t numOfRecords = getSourceAddressCount();
538
0
  if (index < 0 || index >= numOfRecords)
539
0
    return IPv4Address();
540
541
0
  int offset = index * sizeof(uint32_t);
542
0
  const uint8_t* ptr = sourceAddresses + offset;
543
0
  return IPv4Address(*(uint32_t*)ptr);
544
0
}
545
546
size_t igmpv3_group_record::getRecordLen() const
547
0
{
548
0
  uint16_t numOfRecords = getSourceAddressCount();
549
550
0
  int headerLen = numOfRecords * sizeof(uint32_t) + sizeof(igmpv3_group_record);
551
0
  return (size_t)headerLen;
552
0
}
553
554
}