Coverage Report

Created: 2024-02-25 06:29

/src/PcapPlusPlus/Packet++/header/IgmpLayer.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include "Layer.h"
4
#include "IpAddress.h"
5
#include <vector>
6
7
/// @file
8
9
/**
10
 * \namespace pcpp
11
 * \brief The main namespace for the PcapPlusPlus lib
12
 */
13
namespace pcpp
14
{
15
16
/**
17
 * @struct igmp_header
18
 * IGMPv1 and IGMPv2 basic protocol header
19
 */
20
struct igmp_header
21
{
22
  /** Indicates the message type. The enum for message type is pcpp::IgmpType */
23
  uint8_t type;
24
  /** Specifies the time limit for the corresponding report. The field has a resolution of 100 milliseconds */
25
  uint8_t maxResponseTime;
26
  /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */
27
  uint16_t checksum;
28
  /** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query */
29
  uint32_t groupAddress;
30
};
31
32
33
/**
34
 * @struct igmpv3_query_header
35
 * IGMPv3 membership query basic header
36
 */
37
struct igmpv3_query_header
38
{
39
  /** IGMP message type. Should always have value of membership query (::IgmpType_MembershipQuery)  */
40
  uint8_t type;
41
  /** This field specifies the maximum time (in 1/10 second) allowed before sending a responding report */
42
  uint8_t maxResponseTime;
43
  /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */
44
  uint16_t checksum;
45
  /** This is the multicast address being queried when sending a Group-Specific or Group-and-Source-Specific Query */
46
  uint32_t groupAddress;
47
  /** Suppress Router-side Processing Flag + Querier's Robustness Variable */
48
  uint8_t s_qrv;
49
  /** Querier's Query Interval Code */
50
  uint8_t qqic;
51
  /** This field specifies the number of source addresses present in the Query */
52
  uint16_t numOfSources;
53
};
54
55
56
/**
57
 * @struct igmpv3_report_header
58
 * IGMPv3 membership report basic header
59
 */
60
struct igmpv3_report_header
61
{
62
  /** IGMP message type. Should always have value of IGMPv3 membership report (::IgmpType_MembershipReportV3)  */
63
  uint8_t type;
64
  /** Unused byte */
65
  uint8_t reserved1;
66
  /** This is the 16-bit one's complement of the one's complement sum of the entire IGMP message */
67
  uint16_t checksum;
68
  /** Unused bytes */
69
  uint16_t reserved2;
70
  /** This field specifies the number of group records present in the Report */
71
  uint16_t numOfGroupRecords;
72
};
73
74
75
/**
76
 * @struct igmpv3_group_record
77
 * A block of fields containing information pertaining to the sender's membership in a single multicast group on the interface
78
 * from which the Report is sent. Relevant only for IGMPv3 membership report messages
79
 */
80
struct igmpv3_group_record
81
{
82
  /** Group record type */
83
  uint8_t recordType;
84
  /** Contains the length of the Auxiliary Data field in this Group Record. A value other than 0 isn't supported */
85
  uint8_t auxDataLen;
86
  /** Specifies how many source addresses are present in this Group Record */
87
  uint16_t numOfSources;
88
  /** Contains the IP multicast address to which this Group Record pertains */
89
  uint32_t multicastAddress;
90
  /** A vector of n IP unicast addresses, where n is the value in this record's Number of Sources field */
91
  uint8_t sourceAddresses[];
92
93
  /**
94
   * @return The multicast address in igmpv3_group_record#multicastAddress as IPv4Address instance
95
   */
96
0
  IPv4Address getMulticastAddress() const { return multicastAddress; }
97
98
  /**
99
   * @return The number of source addresses in this group record
100
   */
101
  uint16_t getSourceAddressCount() const;
102
103
  /**
104
   * Get the source address at a certain index
105
   * @param[in] index The index of the source address in the group record
106
   * @return The source address in the requested index. If index is negative or higher than the number of source addresses in this
107
   * group record the value if IPv4Address#Zero is returned
108
   */
109
  IPv4Address getSourceAddressAtIndex(int index) const;
110
111
  /**
112
   * @return The total size in bytes of the group record
113
   */
114
  size_t getRecordLen() const;
115
};
116
117
118
/**
119
 * IGMP message types
120
 */
121
enum IgmpType
122
{
123
  /** Unknown message type */
124
  IgmpType_Unknown = 0,
125
  /** IGMP Membership Query */
126
  IgmpType_MembershipQuery = 0x11,
127
  /** IGMPv1 Membership Report */
128
  IgmpType_MembershipReportV1 = 0x12,
129
  /** DVMRP */
130
  IgmpType_DVMRP = 0x13,
131
  /** PIM version 1 */
132
  IgmpType_P1Mv1 = 0x14,
133
  /** Cisco Trace Messages */
134
  IgmpType_CiscoTrace = 0x15,
135
  /** IGMPv2 Membership Report */
136
  IgmpType_MembershipReportV2 = 0x16,
137
  /** IGMPv2 Leave Group */
138
  IgmpType_LeaveGroup = 0x17,
139
  /** Multicast Traceroute Response */
140
  IgmpType_MulticastTracerouteResponse = 0x1e,
141
  /** Multicast Traceroute */
142
  IgmpType_MulticastTraceroute = 0x1f,
143
  /** IGMPv3 Membership Report */
144
  IgmpType_MembershipReportV3 = 0x22,
145
  /** MRD, Multicast Router Advertisement */
146
  IgmpType_MulticastRouterAdvertisement = 0x30,
147
  /** MRD, Multicast Router Solicitation */
148
  IgmpType_MulticastRouterSolicitation = 0x31,
149
  /** MRD, Multicast Router Termination */
150
  IgmpType_MulticastRouterTermination = 0x32,
151
};
152
153
154
/**
155
 * @class IgmpLayer
156
 * A base class for all IGMP (Internet Group Management Protocol) protocol classes. This is an abstract class and cannot be instantiated,
157
 * only its child classes can be instantiated. The inherited classes represent the different versions of the protocol:
158
 * IGMPv1, IGMPv2 and IGMPv3
159
 */
160
class IgmpLayer : public Layer
161
{
162
protected:
163
164
23.8k
  IgmpLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, ProtocolType igmpVer) : Layer(data, dataLen, prevLayer, packet) { m_Protocol = igmpVer; }
165
166
  IgmpLayer(IgmpType type, const IPv4Address& groupAddr, uint8_t maxResponseTime, ProtocolType igmpVer);
167
168
  uint16_t calculateChecksum();
169
170
  size_t getHeaderSizeByVerAndType(ProtocolType igmpVer, IgmpType igmpType) const;
171
public:
172
173
0
  virtual ~IgmpLayer() {}
174
175
  /**
176
   * Get a pointer to the raw IGMPv1/IGMPv2 header. Notice this points directly to the data, so every change will change the actual packet data
177
   * @return A pointer to the @ref igmp_header
178
   */
179
19.1k
  igmp_header* getIgmpHeader() const { return (igmp_header*)m_Data; }
180
181
  /**
182
   * @return The IPv4 multicast address stored igmp_header#groupAddress
183
   */
184
0
  IPv4Address getGroupAddress() const { return getIgmpHeader()->groupAddress; }
185
186
  /**
187
   * Set the IPv4 multicast address
188
   * @param[in] groupAddr The IPv4 address to set
189
   */
190
  void setGroupAddress(const IPv4Address& groupAddr);
191
192
  /**
193
   * @return IGMP type set in igmp_header#type as ::IgmpType enum. Notice that if igmp_header#type contains a value
194
   * that doesn't appear in the ::IgmpType enum, ::IgmpType_Unknown will be returned
195
   */
196
  IgmpType getType() const;
197
198
  /**
199
   * Set IGMP type (will be written to igmp_header#type field)
200
   * @param[in] type The type to set
201
   */
202
  void setType(IgmpType type);
203
204
  /**
205
   * A static method that gets raw IGMP data (byte stream) and returns the IGMP version of this IGMP message
206
   * @param[in] data The IGMP raw data (byte stream)
207
   * @param[in] dataLen Raw data length
208
   * @param[out] isQuery Return true if IGMP message type is ::IgmpType_MembershipQuery and false otherwise
209
   * @return One of the values ::IGMPv1, ::IGMPv2, ::IGMPv3 according to detected IGMP version or ::UnknownProtocol if couldn't detect
210
   * IGMP version
211
   */
212
  static ProtocolType getIGMPVerFromData(uint8_t* data, size_t dataLen, bool& isQuery);
213
214
215
  // implement abstract methods
216
217
  /**
218
   * Does nothing for this layer (IGMP layer is always last)
219
   */
220
23.8k
  void parseNextLayer() {}
221
222
  /**
223
   * @return Size of IGMP header = 8B
224
   */
225
5.37k
  size_t getHeaderLen() const { return sizeof(igmp_header); }
226
227
  std::string toString() const;
228
229
5.47k
  OsiModelLayer getOsiModelLayer() const { return OsiModelNetworkLayer; }
230
};
231
232
233
/**
234
 * @class IgmpV1Layer
235
 * Represents IGMPv1 (Internet Group Management Protocol ver 1) layer. This class represents all the different messages of IGMPv1
236
 */
237
class IgmpV1Layer : public IgmpLayer
238
{
239
public:
240
   /** A constructor that creates the layer from an existing packet raw data
241
   * @param[in] data A pointer to the raw data
242
   * @param[in] dataLen Size of the data in bytes
243
   * @param[in] prevLayer A pointer to the previous layer
244
   * @param[in] packet A pointer to the Packet instance where layer will be stored in
245
   */
246
  IgmpV1Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
247
6.76k
    : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv1) {}
248
249
  /**
250
   * A constructor that allocates a new IGMPv1 header
251
   * @param[in] type The message type to set
252
   * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of IPv4Address#Zero
253
   * if not provided
254
   */
255
  explicit IgmpV1Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address())
256
0
    : IgmpLayer(type, groupAddr, 0, IGMPv1) {}
257
258
  /**
259
   * A destructor for this layer (does nothing)
260
   */
261
0
  ~IgmpV1Layer() {}
262
263
264
  // implement abstract methods
265
266
  /**
267
   * Calculate the IGMP checksum and set igmp_header#maxResponseTime to 0 (this field is unused in IGMPv1)
268
   */
269
  void computeCalculateFields();
270
271
};
272
273
274
/**
275
 * @class IgmpV2Layer
276
 * Represents IGMPv2 (Internet Group Management Protocol ver 2) layer. This class represents all the different messages of IGMPv2
277
 */
278
class IgmpV2Layer : public IgmpLayer
279
{
280
public:
281
   /** A constructor that creates the layer from an existing packet raw data
282
   * @param[in] data A pointer to the raw data
283
   * @param[in] dataLen Size of the data in bytes
284
   * @param[in] prevLayer A pointer to the previous layer
285
   * @param[in] packet A pointer to the Packet instance where layer will be stored in
286
   */
287
  IgmpV2Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
288
5.99k
    : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv2) {}
289
290
  /**
291
   * A constructor that allocates a new IGMPv2 header
292
   * @param[in] type The message type to set
293
   * @param[in] groupAddr The multicast address to set. This is an optional parameter and has a default value of unspecified/zero IPv4 address
294
   * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default value of 0 if not provided
295
   */
296
  explicit IgmpV2Layer(IgmpType type, const IPv4Address& groupAddr = IPv4Address(), uint8_t maxResponseTime = 0)
297
0
    : IgmpLayer(type, groupAddr, maxResponseTime, IGMPv2) {}
298
299
  /**
300
   * A destructor for this layer (does nothing)
301
   */
302
0
  ~IgmpV2Layer() {}
303
304
305
  // implement abstract methods
306
307
  /**
308
   * Calculate the IGMP checksum
309
   */
310
  void computeCalculateFields();
311
};
312
313
314
/**
315
 * @class IgmpV3QueryLayer
316
 * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership query message
317
 */
318
class IgmpV3QueryLayer : public IgmpLayer
319
{
320
public:
321
322
   /** A constructor that creates the layer from an existing packet raw data
323
   * @param[in] data A pointer to the raw data
324
   * @param[in] dataLen Size of the data in bytes
325
   * @param[in] prevLayer A pointer to the previous layer
326
   * @param[in] packet A pointer to the Packet instance where layer will be stored in
327
   */
328
  IgmpV3QueryLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
329
330
  /**
331
   * A constructor that allocates a new IGMPv3 membership query
332
   * @param[in] multicastAddr The multicast address to set. This is an optional parameter and has a default value of unspecified/zero IPv4 address
333
   * if not provided
334
   * @param[in] maxResponseTime The max response time to set. This is an optional parameter and has a default value of 0 if not provided
335
   * @param[in] s_qrv A 1-byte value representing the value in Suppress Router-side Processing Flag + Querier's Robustness Variable
336
   * (igmpv3_query_header#s_qrv field). This is an optional parameter and has a default value of 0 if not provided
337
   */
338
  explicit IgmpV3QueryLayer(const IPv4Address& multicastAddr = IPv4Address(), uint8_t maxResponseTime = 0, uint8_t s_qrv = 0);
339
340
  /**
341
   * Get a pointer to the raw IGMPv3 membership query header. Notice this points directly to the data, so every change will change the
342
   * actual packet data
343
   * @return A pointer to the @ref igmpv3_query_header
344
   */
345
2.25k
  igmpv3_query_header* getIgmpV3QueryHeader() const { return (igmpv3_query_header*)m_Data; }
346
347
  /**
348
   * @return The number of source addresses in this message (as extracted from the igmpv3_query_header#numOfSources field)
349
   */
350
  uint16_t getSourceAddressCount() const;
351
352
  /**
353
   * Get the IPV4 source address in a certain index
354
   * @param[in] index The requested index of the source address
355
   * @return The IPv4 source address, or IPv4Address#Zero if index is out of bounds (of the message or of the layer)
356
   */
357
  IPv4Address getSourceAddressAtIndex(int index) const;
358
359
  /**
360
   * Add a new source address at the end of the source address list. The igmpv3_query_header#numOfSources field will be incremented accordingly
361
   * @param[in] addr The IPv4 source address to add
362
   * @return True if source address was added successfully or false otherwise. If false is returned an appropriate error message
363
   * will be printed to log
364
   */
365
  bool addSourceAddress(const IPv4Address& addr);
366
367
  /**
368
   * Add a new source address at a certain index of the source address list. The igmpv3_query_header#numOfSources field will be incremented accordingly
369
   * @param[in] addr The IPv4 source address to add
370
   * @param[in] index The index to add the new source address at
371
   * @return True if source address was added successfully or false otherwise. If false is returned an appropriate error message
372
   * will be printed to log
373
   */
374
  bool addSourceAddressAtIndex(const IPv4Address& addr, int index);
375
376
  /**
377
   * Remove a source address at a certain index. The igmpv3_query_header#numOfSources field will be decremented accordingly
378
   * @param[in] index The index of the source address to be removed
379
   * @return True if source address was removed successfully or false otherwise. If false is returned an appropriate error message
380
   * will be printed to log
381
   */
382
  bool removeSourceAddressAtIndex(int index);
383
384
  /**
385
   * Remove all source addresses in the message. The igmpv3_query_header#numOfSources field will be set to 0
386
   * @return True if all source addresses were cleared successfully or false otherwise. If false is returned an appropriate error message
387
   * will be printed to log
388
   */
389
  bool removeAllSourceAddresses();
390
391
  // implement abstract methods
392
393
  /**
394
   * Calculate the IGMP checksum
395
   */
396
  void computeCalculateFields();
397
398
  /**
399
   * @return The message size in bytes which include the size of the basic header + the size of the source address list
400
   */
401
  size_t getHeaderLen() const;
402
};
403
404
405
/**
406
 * @class IgmpV3ReportLayer
407
 * Represents an IGMPv3 (Internet Group Management Protocol ver 3) membership report message
408
 */
409
class IgmpV3ReportLayer : public IgmpLayer
410
{
411
private:
412
  igmpv3_group_record* addGroupRecordAt(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int offset);
413
414
public:
415
416
   /** A constructor that creates the layer from an existing packet raw data
417
   * @param[in] data A pointer to the raw data
418
   * @param[in] dataLen Size of the data in bytes
419
   * @param[in] prevLayer A pointer to the previous layer
420
   * @param[in] packet A pointer to the Packet instance where layer will be stored in
421
   */
422
  IgmpV3ReportLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
423
8.37k
    : IgmpLayer(data, dataLen, prevLayer, packet, IGMPv3) {}
424
425
  /**
426
   * A constructor that allocates a new IGMPv3 membership report with 0 group addresses
427
   */
428
0
  IgmpV3ReportLayer() : IgmpLayer(IgmpType_MembershipReportV3, IPv4Address(), 0, IGMPv3) {}
429
430
  /**
431
   * Get a pointer to the raw IGMPv3 membership report header. Notice this points directly to the data, so every change will change the
432
   * actual packet data
433
   * @return A pointer to the @ref igmpv3_report_header
434
   */
435
2.04k
  igmpv3_report_header* getReportHeader() const { return (igmpv3_report_header*)m_Data; }
436
437
  /**
438
   * @return The number of group records in this message (as extracted from the igmpv3_report_header#numOfGroupRecords field)
439
   */
440
  uint16_t getGroupRecordCount() const;
441
442
  /**
443
   * @return A pointer to the first group record or NULL if no group records exist. Notice the return value is a pointer to the real data,
444
   * so changes in the return value will affect the packet data
445
   */
446
  igmpv3_group_record* getFirstGroupRecord() const;
447
448
  /**
449
   * Get the group record that comes next to a given group record. If "groupRecord" is NULL then NULL will be returned.
450
   * If "groupRecord" is the last group record or if it is out of layer bounds NULL will be returned also. Notice the return value is a
451
   * pointer to the real data casted to igmpv3_group_record type (as opposed to a copy of the option data). So changes in the return
452
   * value will affect the packet data
453
   * @param[in] groupRecord The group record to start searching from
454
   * @return The next group record or NULL if "groupRecord" is NULL, last or out of layer bounds
455
   */
456
  igmpv3_group_record* getNextGroupRecord(igmpv3_group_record* groupRecord) const;
457
458
  /**
459
   * Add a new group record at a the end of the group record list. The igmpv3_report_header#numOfGroupRecords field will be
460
   * incremented accordingly
461
   * @param[in] recordType The type of the new group record
462
   * @param[in] multicastAddress The multicast address of the new group record
463
   * @param[in] sourceAddresses A vector containing all the source addresses of the new group record
464
   * @return The method constructs a new group record, adds it to the end of the group record list of IGMPv3 report message and
465
   * returns a pointer to the new message. If something went wrong in creating or adding the new group record a NULL value is returned
466
   * and an appropriate error message is printed to log
467
   */
468
  igmpv3_group_record* addGroupRecord(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses);
469
470
  /**
471
   * Add a new group record at a certain index of the group record list. The igmpv3_report_header#numOfGroupRecords field will be
472
   * incremented accordingly
473
   * @param[in] recordType The type of the new group record
474
   * @param[in] multicastAddress The multicast address of the new group record
475
   * @param[in] sourceAddresses A vector containing all the source addresses of the new group record
476
   * @param[in] index The index to add the new group address at
477
   * @return The method constructs a new group record, adds it to the IGMPv3 report message and returns a pointer to the new message.
478
   * If something went wrong in creating or adding the new group record a NULL value is returned and an appropriate error message is
479
   * printed to log
480
   */
481
  igmpv3_group_record* addGroupRecordAtIndex(uint8_t recordType, const IPv4Address& multicastAddress, const std::vector<IPv4Address>& sourceAddresses, int index);
482
483
  /**
484
   * Remove a group record at a certain index. The igmpv3_report_header#numOfGroupRecords field will be decremented accordingly
485
   * @param[in] index The index of the group record to be removed
486
   * @return True if group record was removed successfully or false otherwise. If false is returned an appropriate error message
487
   * will be printed to log
488
   */
489
  bool removeGroupRecordAtIndex(int index);
490
491
  /**
492
   * Remove all group records in the message. The igmpv3_report_header#numOfGroupRecords field will be set to 0
493
   * @return True if all group records were cleared successfully or false otherwise. If false is returned an appropriate error message
494
   * will be printed to log
495
   */
496
  bool removeAllGroupRecords();
497
498
  // implement abstract methods
499
500
  /**
501
   * Calculate the IGMP checksum
502
   */
503
  void computeCalculateFields();
504
505
  /**
506
   * @return The message size in bytes which include the size of the basic header + the size of the group record list
507
   */
508
4.08k
  size_t getHeaderLen() const { return m_DataLen; }
509
};
510
511
}