Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/IPv6Extensions.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <vector>
4
#include "IpAddress.h"
5
#include "Layer.h"
6
#include "TLVData.h"
7
8
/// @file
9
10
/// @namespace pcpp
11
/// @brief The main namespace for the PcapPlusPlus lib
12
namespace pcpp
13
{
14
  /// @class IPv6Extension
15
  /// A base class for all supported IPv6 extensions. This class is abstract, meaning it cannot be instantiated or
16
  /// copied (has private c'tor and copy c'tor)
17
  class IPv6Extension
18
  {
19
    friend class IPv6Layer;
20
21
  public:
22
    /// An enum representing all supported IPv6 extension types
23
    enum IPv6ExtensionType
24
    {
25
      /// Hop-By-Hop extension type
26
      IPv6HopByHop = 0,
27
      /// Routing extension type
28
      IPv6Routing = 43,
29
      /// IPv6 fragmentation extension type
30
      IPv6Fragmentation = 44,
31
      /// Authentication Header extension type
32
      IPv6AuthenticationHdr = 51,
33
      /// Destination extension type
34
      IPv6Destination = 60,
35
      /// Unknown or unsupported extension type
36
      IPv6ExtensionUnknown = 255
37
    };
38
39
    /// @return The size of extension in bytes, meaning (for most extensions): 8 * ([headerLen field] + 1)
40
    virtual size_t getExtensionLen() const
41
15.4k
    {
42
15.4k
      return 8 * (getBaseHeader()->headerLen + 1);
43
15.4k
    }
44
45
    /// @return The type of the extension
46
    IPv6ExtensionType getExtensionType() const
47
7.83k
    {
48
7.83k
      return m_ExtType;
49
7.83k
    }
50
51
    /// A destructor for this class
52
    virtual ~IPv6Extension();
53
54
    /// @return A pointer to the next header or nullptr if the extension is the last one
55
    IPv6Extension* getNextHeader() const
56
15.0k
    {
57
15.0k
      return m_NextHeader;
58
15.0k
    }
59
60
  protected:
61
    struct ipv6_ext_base_header
62
    {
63
      uint8_t nextHeader;
64
      uint8_t headerLen;
65
    };
66
67
    // protected c'tor
68
    IPv6Extension(IDataContainer* dataContainer, size_t offset)
69
8.21k
        : m_NextHeader(nullptr), m_ExtType(IPv6ExtensionUnknown), m_DataContainer(dataContainer), m_Offset(offset),
70
8.21k
          m_ShadowData(nullptr)
71
8.21k
    {}
72
73
    // protected empty c'tor
74
    IPv6Extension()
75
0
        : m_NextHeader(nullptr), m_ExtType(IPv6ExtensionUnknown), m_DataContainer(nullptr), m_Offset(0),
76
0
          m_ShadowData(nullptr)
77
0
    {}
78
79
    // protected assignment operator
80
    IPv6Extension& operator=(const IPv6Extension& other);
81
82
    uint8_t* getDataPtr() const;
83
84
    void initShadowPtr(size_t size);
85
86
    ipv6_ext_base_header* getBaseHeader() const
87
29.2k
    {
88
29.2k
      return (ipv6_ext_base_header*)getDataPtr();
89
29.2k
    }
90
91
    void setNextHeader(IPv6Extension* nextHeader)
92
3.34k
    {
93
3.34k
      m_NextHeader = nextHeader;
94
3.34k
    }
95
96
    IPv6Extension* m_NextHeader;
97
    IPv6ExtensionType m_ExtType;
98
99
  private:
100
    IDataContainer* m_DataContainer;
101
    size_t m_Offset;
102
    uint8_t* m_ShadowData;
103
  };
104
105
  /// @class IPv6FragmentationHeader
106
  /// Represents an IPv6 fragmentation extension header and allows easy access to all fragmentation parameters
107
  class IPv6FragmentationHeader : public IPv6Extension
108
  {
109
    friend class IPv6Layer;
110
111
  public:
112
    /// @struct ipv6_frag_header
113
    /// A struct representing IPv6 fragmentation header
114
    struct ipv6_frag_header
115
    {
116
      /// Next header type
117
      uint8_t nextHeader;
118
      /// Fragmentation header size is fixed 8 bytes, so len is always zero
119
      uint8_t headerLen;
120
      /// Offset, in 8-octet units, relative to the start of the fragmentable part of the original packet
121
      /// plus 1-bit indicating if more fragments will follow
122
      uint16_t fragOffsetAndFlags;
123
      /// packet identification value. Needed for reassembly of the original packet
124
      uint32_t id;
125
    };
126
127
    /// A c'tor for creating a new IPv6 fragmentation extension object not bounded to a packet. Useful for adding
128
    /// new extensions to an IPv6 layer with IPv6Layer#addExtension()
129
    /// @param[in] fragId Fragmentation ID
130
    /// @param[in] fragOffset Fragmentation offset
131
    /// @param[in] lastFragment Indicates whether this fragment is the last one
132
    IPv6FragmentationHeader(uint32_t fragId, uint16_t fragOffset, bool lastFragment);
133
134
    /// Get a pointer to the fragmentation header. Notice the returned pointer points directly to the data, so every
135
    /// change will modify the actual packet data
136
    /// @return A pointer to the @ref ipv6_frag_header
137
    ipv6_frag_header* getFragHeader() const
138
0
    {
139
0
      return (ipv6_frag_header*)getDataPtr();
140
0
    }
141
142
    /// @return True if this is the first fragment (which usually contains the L4 header), false otherwise
143
    bool isFirstFragment() const;
144
145
    /// @return True if this is the last fragment, false otherwise
146
    bool isLastFragment() const;
147
148
    /// @return True if the "more fragments" bit is set, meaning more fragments are expected to follow this fragment
149
    bool isMoreFragments() const;
150
151
    /// @return The fragment offset
152
    uint16_t getFragmentOffset() const;
153
154
  private:
155
0
    IPv6FragmentationHeader(IDataContainer* dataContainer, size_t offset) : IPv6Extension(dataContainer, offset)
156
0
    {
157
0
      m_ExtType = IPv6Fragmentation;
158
0
    }
159
  };
160
161
  /// An abstract base class for Hop-By-Hop and Destination IPv6 extensions which their structure contains
162
  /// Type-Length-Value (TLV) options. This class provides access to these options and their data as well as methods
163
  /// to create new options. Notice this class is abstract and cannot be instantiated
164
  class IPv6TLVOptionHeader : public IPv6Extension
165
  {
166
    friend class IPv6Layer;
167
168
  public:
169
    /// @class IPv6Option
170
    /// A class representing a Type-Length-Value (TLV) options that are used inside Hop-By-Hop and Destinations IPv6
171
    /// extensions. This class does not create or modify IPv6 option records, but rather serves as a wrapper and
172
    /// provides useful methods for retrieving data from them
173
    class IPv6Option : public TLVRecord<uint8_t, uint8_t>
174
    {
175
    public:
176
      static const uint8_t Pad0OptionType = 0;
177
      static const uint8_t PadNOptionType = 1;
178
179
      /// A c'tor for this class that gets a pointer to the option raw data (byte array)
180
      /// @param[in] optionRawData A pointer to the attribute raw data
181
0
      explicit IPv6Option(uint8_t* optionRawData) : TLVRecord(optionRawData)
182
0
      {}
183
184
      /// A d'tor for this class, currently does nothing
185
      ~IPv6Option()
186
0
      {}
187
188
      /// Check if a pointer can be assigned to the TLV record data
189
      /// @param[in] recordRawData A pointer to the TLV record raw data
190
      /// @param[in] tlvDataLen The size of the TLV record raw data
191
      /// @return True if data is valid and can be assigned
192
      static bool canAssign(const uint8_t* recordRawData, size_t tlvDataLen)
193
0
      {
194
0
        auto data = (TLVRawData*)recordRawData;
195
0
        if (data == nullptr)
196
0
          return false;
197
198
0
        if (tlvDataLen < sizeof(TLVRawData::recordType))
199
0
          return false;
200
201
0
        if (data->recordType == Pad0OptionType)
202
0
          return true;
203
204
0
        return TLVRecord<uint8_t, uint8_t>::canAssign(recordRawData, tlvDataLen);
205
0
      }
206
207
      // implement abstract methods
208
209
      size_t getTotalSize() const
210
0
      {
211
0
        if (m_Data == nullptr)
212
0
          return 0;
213
214
0
        if (m_Data->recordType == Pad0OptionType)
215
0
          return sizeof(uint8_t);
216
217
0
        return (size_t)(m_Data->recordLen + sizeof(uint16_t));
218
0
      }
219
220
      size_t getDataSize() const
221
0
      {
222
0
        if (m_Data == nullptr || m_Data->recordType == Pad0OptionType)
223
0
          return 0;
224
225
0
        return (size_t)m_Data->recordLen;
226
0
      }
227
    };
228
229
    /// @class IPv6TLVOptionBuilder
230
    /// A class for building IPv6 Type-Length-Value (TLV) options. This builder receives the option parameters in
231
    /// its c'tor, builds the option raw buffer and provides a method to build a IPv6Option object out of it
232
    class IPv6TLVOptionBuilder : public TLVRecordBuilder
233
    {
234
    public:
235
      /// A c'tor for building IPv6 TLV options which their value is a byte array. The IPv6Option object can later
236
      /// be retrieved by calling build()
237
      /// @param[in] optType IPv6 option type
238
      /// @param[in] optValue A buffer containing the option value. This buffer is read-only and isn't modified in
239
      /// any way
240
      /// @param[in] optValueLen Option value length in bytes
241
      IPv6TLVOptionBuilder(uint8_t optType, const uint8_t* optValue, uint8_t optValueLen)
242
          : TLVRecordBuilder(optType, optValue, optValueLen)
243
0
      {}
244
245
      /// A c'tor for building IPv6 TLV options which have a 1-byte value. The IPv6Option object can later be
246
      /// retrieved by calling build()
247
      /// @param[in] optType IPv6 option type
248
      /// @param[in] optValue A 1-byte option value
249
      IPv6TLVOptionBuilder(uint8_t optType, uint8_t optValue) : TLVRecordBuilder(optType, optValue)
250
0
      {}
251
252
      /// A c'tor for building IPv6 TLV options which have a 2-byte value. The IPv6Option object can later be
253
      /// retrieved by calling build()
254
      /// @param[in] optType IPv6 option type
255
      /// @param[in] optValue A 2-byte option value
256
      IPv6TLVOptionBuilder(uint8_t optType, uint16_t optValue) : TLVRecordBuilder(optType, optValue)
257
0
      {}
258
259
      /// A copy c'tor that creates an instance of this class out of another instance and copies all the data from
260
      /// it
261
      /// @param[in] other The instance to copy data from
262
      IPv6TLVOptionBuilder(const IPv6TLVOptionBuilder& other) : TLVRecordBuilder(other)
263
0
      {}
264
265
      /// Assignment operator that copies all data from another instance of IPv6TLVOptionBuilder
266
      /// @param[in] other The instance to assign from
267
      IPv6TLVOptionBuilder& operator=(const IPv6TLVOptionBuilder& other)
268
0
      {
269
0
        TLVRecordBuilder::operator=(other);
270
0
        return *this;
271
0
      }
272
273
      /// Build the IPv6Option object out of the parameters defined in the c'tor
274
      /// @return The IPv6Option object
275
      IPv6Option build() const;
276
    };
277
278
    /// Retrieve an option by its type
279
    /// @param[in] optionType Option type
280
    /// @return An IPv6Option object that wraps the option data. If option isn't found a logical null is returned
281
    /// (IPv6Option#isNull() == true)
282
    IPv6Option getOption(uint8_t optionType) const;
283
284
    /// @return An IPv6Option that wraps the first option data or logical null (IPv6Option#isNull() == true) if no
285
    /// options exist
286
    IPv6Option getFirstOption() const;
287
288
    /// Returns a pointer to the option that comes after the option given as the parameter
289
    /// @param[in] option A pointer to an option instance
290
    /// @return An IPv6Option object that wraps the option data. In the following cases logical null
291
    /// (IPv6Option#isNull() == true) is returned: (1) input parameter is out-of-bounds for this extension or (2)
292
    /// the next option doesn't exist or (3) the input option is nullptr
293
    IPv6Option getNextOption(IPv6Option& option) const;
294
295
    /// @returns The number of options this IPv6 extension contains
296
    size_t getOptionCount() const;
297
298
  protected:
299
    /// A private c'tor to keep this object from being constructed
300
    explicit IPv6TLVOptionHeader(const std::vector<IPv6TLVOptionBuilder>& options);
301
302
    IPv6TLVOptionHeader(IDataContainer* dataContainer, size_t offset);
303
304
  private:
305
    TLVRecordReader<IPv6Option> m_OptionReader;
306
  };
307
308
  /// @class IPv6HopByHopHeader
309
  /// Represents IPv6 Hop-By-Hop extension header and allows easy access to all of its data including the TLV options
310
  /// stored
311
  class IPv6HopByHopHeader : public IPv6TLVOptionHeader
312
  {
313
    friend class IPv6Layer;
314
315
  public:
316
    /// A c'tor for creating a new IPv6 Hop-By-Hop extension object not bounded to a packet. Useful for adding new
317
    /// extensions to an IPv6 layer with IPv6Layer#addExtension()
318
    /// @param[in] options A vector of IPv6TLVOptionHeader#TLVOptionBuilder instances which define the options that
319
    /// will be stored in the extension data. Notice this vector is read-only and its content won't be modified
320
    explicit IPv6HopByHopHeader(const std::vector<IPv6TLVOptionBuilder>& options) : IPv6TLVOptionHeader(options)
321
0
    {
322
0
      m_ExtType = IPv6HopByHop;
323
0
    }
324
325
  private:
326
7.46k
    IPv6HopByHopHeader(IDataContainer* dataContainer, size_t offset) : IPv6TLVOptionHeader(dataContainer, offset)
327
7.46k
    {
328
7.46k
      m_ExtType = IPv6HopByHop;
329
7.46k
    }
330
  };
331
332
  /// @class IPv6DestinationHeader
333
  /// Represents IPv6 destination extension header and allows easy access to all of its data including the TLV options
334
  /// stored in it
335
  class IPv6DestinationHeader : public IPv6TLVOptionHeader
336
  {
337
    friend class IPv6Layer;
338
339
  public:
340
    /// A c'tor for creating a new IPv6 destination extension object not bounded to a packet. Useful for adding new
341
    /// extensions to an IPv6 layer with IPv6Layer#addExtension()
342
    /// @param[in] options A vector of IPv6TLVOptionHeader#TLVOptionBuilder instances which define the options that
343
    /// will be stored in the extension data. Notice this vector is read-only and its content won't be modified
344
    explicit IPv6DestinationHeader(const std::vector<IPv6TLVOptionBuilder>& options) : IPv6TLVOptionHeader(options)
345
0
    {
346
0
      m_ExtType = IPv6Destination;
347
0
    }
348
349
  private:
350
0
    IPv6DestinationHeader(IDataContainer* dataContainer, size_t offset) : IPv6TLVOptionHeader(dataContainer, offset)
351
0
    {
352
0
      m_ExtType = IPv6Destination;
353
0
    }
354
  };
355
356
  /// @class IPv6RoutingHeader
357
  /// Represents IPv6 routing extension header and allows easy access to all of its data
358
  class IPv6RoutingHeader : public IPv6Extension
359
  {
360
    friend class IPv6Layer;
361
362
  public:
363
    /// @struct ipv6_routing_header
364
    /// A struct representing the fixed part of the IPv6 routing extension header
365
    struct ipv6_routing_header
366
    {
367
      /// Next header type
368
      uint8_t nextHeader;
369
      /// The length of this header, in multiples of 8 octets, not including the first 8 octets
370
      uint8_t headerLen;
371
      /// A value representing the routing type
372
      uint8_t routingType;
373
      /// Number of nodes this packet still has to visit before reaching its final destination
374
      uint8_t segmentsLeft;
375
    };
376
377
    /// A c'tor for creating a new IPv6 routing extension object not bounded to a packet. Useful for adding new
378
    /// extensions to an IPv6 layer with IPv6Layer#addExtension()
379
    /// @param[in] routingType Routing type value (will be written to ipv6_routing_header#routingType field)
380
    /// @param[in] segmentsLeft Segments left value (will be written to ipv6_routing_header#segmentsLeft field)
381
    /// @param[in] additionalRoutingData A pointer to a buffer containing the additional routing data for this
382
    /// extension. Notice this buffer is read-only and its content isn't modified
383
    /// @param[in] additionalRoutingDataLen The length of the additional routing data buffer
384
    IPv6RoutingHeader(uint8_t routingType, uint8_t segmentsLeft, const uint8_t* additionalRoutingData,
385
                      size_t additionalRoutingDataLen);
386
387
    /// Get a pointer to the fixed part of the routing header. Notice the return pointer points directly to the
388
    /// data, so every change will modify the actual packet data
389
    /// @return A pointer to the @ref ipv6_routing_header
390
    ipv6_routing_header* getRoutingHeader() const
391
0
    {
392
0
      return (ipv6_routing_header*)getDataPtr();
393
0
    }
394
395
    /// @return A pointer to the buffer containing the additional routing data for this extension. Notice that any
396
    /// change in this buffer will lead to a change in the extension data
397
    uint8_t* getRoutingAdditionalData() const;
398
399
    /// @return The length of the additional routing parameters buffer
400
    size_t getRoutingAdditionalDataLength() const;
401
402
    /// In many cases the additional routing data is actually IPv6 address(es). This method converts the raw buffer
403
    /// data into an IPv6 address
404
    /// @param[in] offset An offset in the additional routing buffer pointing to where the IPv6 address begins. In
405
    /// some cases there are multiple IPv6 addresses in the additional routing data buffer so this offset points to
406
    /// where the request IPv6 address begins. Also, even if there is only one IPv6 address in this buffer,
407
    /// sometimes it isn't written in the beginning of the buffer, so the offset points to where the IPv6 address
408
    /// begins. This is an optional parameter and the default offset is 0
409
    /// @return The IPv6 address stored in the additional routing data buffer from the offset defined by the user.
410
    /// If offset is out-of-bounds of the extension of doesn't have 16 bytes (== the length of IPv6 address) until
411
    /// the end of the buffer - IPv6Address#Zero is returned
412
    IPv6Address getRoutingAdditionalDataAsIPv6Address(size_t offset = 0) const;
413
414
  private:
415
252
    IPv6RoutingHeader(IDataContainer* dataContainer, size_t offset) : IPv6Extension(dataContainer, offset)
416
252
    {
417
252
      m_ExtType = IPv6Routing;
418
252
    }
419
  };
420
421
  /// @class IPv6AuthenticationHeader
422
  /// Represents IPv6 authentication header extension (used in IPSec protocol) and allows easy access to all of its
423
  /// data
424
  class IPv6AuthenticationHeader : public IPv6Extension
425
  {
426
    friend class IPv6Layer;
427
428
  public:
429
    /// @struct ipv6_authentication_header
430
    /// A struct representing the fixed part of the IPv6 authentication header extension
431
    struct ipv6_authentication_header
432
    {
433
      /// Next header type
434
      uint8_t nextHeader;
435
      /// The length of this Authentication Header in 4-octet units, minus 2. For example, an AH value of 4
436
      /// equals: [ 3×(32-bit fixed-length AH fields) + 3×(32-bit ICV fields) − 2 ] and thus an AH value of 4
437
      /// means 24 octets
438
      uint8_t headerLen;
439
      /// Reserved bytes, all zeros
440
      uint16_t reserved;
441
      /// Arbitrary value which is used (together with the destination IP address) to identify the security
442
      /// association of the receiving party
443
      uint32_t securityParametersIndex;
444
      /// A monotonic strictly increasing sequence number (incremented by 1 for every packet sent)
445
      uint32_t sequenceNumber;
446
    };
447
448
    /// A c'tor for creating a new IPv6 authentication header extension object not bounded to a packet. Useful for
449
    /// adding new extensions to an IPv6 layer with IPv6Layer#addExtension()
450
    /// @param[in] securityParametersIndex Security Parameters Index (SPI) value (will be written to
451
    /// ipv6_authentication_header#securityParametersIndex field)
452
    /// @param[in] sequenceNumber Sequence number value (will be written to
453
    /// ipv6_authentication_header#sequenceNumber field)
454
    /// @param[in] integrityCheckValue A pointer to a buffer containing the integrity check value (ICV) data for
455
    /// this extension. Notice this pointer is read-only and its content isn't modified in any way
456
    /// @param[in] integrityCheckValueLen The length of the integrity check value (ICV) buffer
457
    IPv6AuthenticationHeader(uint32_t securityParametersIndex, uint32_t sequenceNumber,
458
                             const uint8_t* integrityCheckValue, size_t integrityCheckValueLen);
459
460
    /// Get a pointer to the fixed part of the authentication header. Notice the return pointer points directly to
461
    /// the data, so every change will modify the actual packet data
462
    /// @return A pointer to the @ref ipv6_authentication_header
463
    ipv6_authentication_header* getAuthHeader() const
464
0
    {
465
0
      return (ipv6_authentication_header*)getDataPtr();
466
0
    }
467
468
    /// @return A pointer to the buffer containing the integrity check value (ICV) for this extension. Notice that
469
    /// any change in this buffer will lead to a change in the extension data
470
    uint8_t* getIntegrityCheckValue() const;
471
472
    /// @return The length of the integrity check value (ICV) buffer
473
    size_t getIntegrityCheckValueLength() const;
474
475
    // overridden methods
476
477
    /// In the authentication header the extension length is calculated in a different way than other extensions.
478
    /// The calculation is: [ 4 * (ipv6_authentication_header#headerLen + 2) ]
479
    /// @return The length of this extension
480
    size_t getExtensionLen() const override
481
984
    {
482
984
      return 4 * (getBaseHeader()->headerLen + 2);
483
984
    }
484
485
  private:
486
492
    IPv6AuthenticationHeader(IDataContainer* dataContainer, size_t offset) : IPv6Extension(dataContainer, offset)
487
492
    {
488
492
      m_ExtType = IPv6AuthenticationHdr;
489
492
    }
490
  };
491
492
}  // namespace pcpp