Coverage Report

Created: 2026-10-17 07:09

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