Coverage Report

Created: 2023-01-17 06:15

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