Coverage Report

Created: 2026-10-17 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/IPv6Layer.h
Line
Count
Source
1
#pragma once
2
3
#include "Layer.h"
4
#include "IPLayer.h"
5
#include "IPv6Extensions.h"
6
#include "IpAddress.h"
7
#include <algorithm>
8
#include <iterator>
9
10
/// @file
11
12
/// @namespace pcpp
13
/// @brief The main namespace for the PcapPlusPlus lib
14
namespace pcpp
15
{
16
17
  /// @struct ip6_hdr
18
  /// Represents IPv6 protocol header
19
#pragma pack(push, 1)
20
  struct ip6_hdr
21
  {
22
#if (BYTE_ORDER == LITTLE_ENDIAN)
23
    /// Traffic class
24
    uint8_t trafficClass : 4,
25
        /// IP version number, has the value of 6 for IPv6
26
        ipVersion : 4;
27
#else
28
    /// IP version number, has the value of 6 for IPv6
29
    uint8_t ipVersion : 4,
30
        /// Traffic class
31
        trafficClass : 4;
32
#endif
33
    /// Flow label
34
    uint8_t flowLabel[3];
35
    /// The size of the payload in octets, including any extension headers
36
    uint16_t payloadLength;
37
    /// Specifies the type of the next header (protocol). Must be one of ::IPProtocolTypes
38
    uint8_t nextHeader;
39
    /// Replaces the time to live field of IPv4
40
    uint8_t hopLimit;
41
    /// Source address
42
    uint8_t ipSrc[16];
43
    /// Destination address
44
    uint8_t ipDst[16];
45
  };
46
#pragma pack(pop)
47
  static_assert(sizeof(ip6_hdr) == 40, "ip6_hdr size is not 40 bytes");
48
49
  /// @class IPv6Layer
50
  /// Represents an IPv6 protocol layer
51
  class IPv6Layer : public Layer, public IPLayer
52
  {
53
  public:
54
    /// A constructor that creates the layer from an existing packet raw data
55
    /// @param[in] data A pointer to the raw data (will be casted to @ref ip6_hdr)
56
    /// @param[in] dataLen Size of the data in bytes
57
    /// @param[in] prevLayer A pointer to the previous layer
58
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
59
    IPv6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
60
61
    /// A constructor that allocates a new IPv6 header with empty fields
62
    IPv6Layer();
63
64
    /// A constructor that allocates a new IPv6 header with source and destination IPv6 addresses
65
    /// @param[in] srcIP Source IPv6 address
66
    /// @param[in] dstIP Destination IPv6 address
67
    IPv6Layer(const IPv6Address& srcIP, const IPv6Address& dstIP);
68
69
    /// A copy constructor that copies the entire header from the other IPv6Layer (including IPv6 extensions)
70
    IPv6Layer(const IPv6Layer& other);
71
72
    /// A destructor for this layer
73
    ~IPv6Layer() override;
74
75
    /// An assignment operator that first delete all data from current layer and then copy the entire header from
76
    /// the other IPv6Layer (including IPv6 extensions)
77
    IPv6Layer& operator=(const IPv6Layer& other);
78
79
    /// Get a pointer to the IPv6 header. Notice this points directly to the data, so every change will change the
80
    /// actual packet data
81
    /// @return A pointer to the @ref ip6_hdr
82
    ip6_hdr* getIPv6Header() const
83
0
    {
84
0
      return reinterpret_cast<ip6_hdr*>(m_Data);
85
0
    }
86
87
    /// Get the source IP address in the form of IPAddress. This method is very similar to getSrcIPv6Address(),
88
    /// but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses
89
    /// @return An IPAddress containing the source address
90
    IPAddress getSrcIPAddress() const override
91
0
    {
92
0
      return getSrcIPv6Address();
93
0
    }
94
95
    /// Get the source IP address in the form of IPv6Address
96
    /// @return An IPv6Address containing the source address
97
    IPv6Address getSrcIPv6Address() const
98
0
    {
99
0
      return getIPv6Header()->ipSrc;
100
0
    }
101
102
    /// Set the source IP address
103
    /// @param[in] ipAddr The IP address to set
104
    void setSrcIPv6Address(const IPv6Address& ipAddr)
105
0
    {
106
0
      ipAddr.copyTo(getIPv6Header()->ipSrc);
107
0
    }
108
109
    /// Set the dest IP address
110
    /// @param[in] ipAddr The IP address to set
111
    void setDstIPv6Address(const IPv6Address& ipAddr)
112
0
    {
113
0
      ipAddr.copyTo(getIPv6Header()->ipDst);
114
0
    }
115
116
    /// Get the destination IP address in the form of IPAddress. This method is very similar to getDstIPv6Address(),
117
    /// but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses
118
    /// @return An IPAddress containing the destination address
119
    IPAddress getDstIPAddress() const override
120
0
    {
121
0
      return getDstIPv6Address();
122
0
    }
123
124
    /// Get the destination IP address in the form of IPv6Address
125
    /// @return An IPv6Address containing the destination address
126
    IPv6Address getDstIPv6Address() const
127
0
    {
128
0
      return getIPv6Header()->ipDst;
129
0
    }
130
131
    /// @return Number of IPv6 extensions in this layer
132
    size_t getExtensionCount() const;
133
134
    /// A templated getter for an IPv6 extension of a type TIPv6Extension. TIPv6Extension has to be one of the
135
    /// supported IPv6 extensions, meaning a class that inherits IPv6Extension. If the requested extension type
136
    /// isn't found nullptr is returned
137
    /// @return A pointer to the extension instance or nullptr if the requested extension type isn't found
138
    template <class TIPv6Extension> TIPv6Extension* getExtensionOfType() const;
139
140
    /// Add a new extension of type TIPv6Extension to the layer. This is a templated method and TIPv6Extension has
141
    /// to be one of the supported IPv6 extensions, meaning a class that inherits IPv6Extension. If the extension is
142
    /// added successfully a pointer to the newly added extension object is returned, otherwise nullptr is returned
143
    /// @param[in] extensionHeader The extension object to add. Notice the object passed here is read-only, meaning
144
    /// its data is copied but the object itself isn't modified
145
    /// @return If the extension is added successfully a pointer to the newly added extension object is returned.
146
    /// Otherwise nullptr is returned
147
    template <class TIPv6Extension> TIPv6Extension* addExtension(const TIPv6Extension& extensionHeader);
148
149
    /// Remove all IPv6 extensions in this layer
150
    void removeAllExtensions();
151
152
    /// @return True if this packet is an IPv6 fragment, meaning if it has an IPv6FragmentationHeader extension
153
    bool isFragment() const;
154
155
    /// The static method makes validation of input data
156
    /// @param[in] data The pointer to the beginning of byte stream of IP packet
157
    /// @param[in] dataLen The length of byte stream
158
    /// @return True if the data is valid and can represent the IPv6 packet
159
    static inline bool isDataValid(const uint8_t* data, size_t dataLen);
160
161
    // implement abstract methods
162
163
    /// Currently identifies the following next layers:
164
    /// - UdpLayer
165
    /// - TcpLayer
166
    /// - IPv4Layer (IP-in-IP)
167
    /// - IPv6Layer (IP-in-IP)
168
    /// - GreLayer
169
    /// - AuthenticationHeaderLayer (IPSec)
170
    /// - ESPLayer (IPSec)
171
    ///
172
    /// Otherwise sets PayloadLayer
173
    void parseNextLayer() override;
174
175
    /// @return Size of @ref ip6_hdr
176
    size_t getHeaderLen() const override
177
0
    {
178
0
      return sizeof(ip6_hdr) + m_ExtensionsLen;
179
0
    }
180
181
    /// Calculate the following fields:
182
    /// - ip6_hdr#payloadLength = size of payload (all data minus header size)
183
    /// - ip6_hdr#ipVersion = 6
184
    /// - ip6_hdr#nextHeader = calculated if next layer is known: ::PACKETPP_IPPROTO_TCP for TCP,
185
    /// ::PACKETPP_IPPROTO_UDP for UDP, ::PACKETPP_IPPROTO_ICMP for ICMP
186
    void computeCalculateFields() override;
187
188
    std::string toString() const override;
189
190
    OsiModelLayer getOsiModelLayer() const override
191
0
    {
192
0
      return OsiModelNetworkLayer;
193
0
    }
194
195
    /// @struct SerializedFields
196
    /// Fields written by IPv6Layer's serializeLayer(), in addition to
197
    /// Layer::SerializedFields.
198
    struct SerializedFields : Layer::SerializedFields
199
    {
200
      /// @return All field descriptors for IPv6Layer
201
      static std::vector<FieldDescriptor> all()
202
0
      {
203
0
        auto result = Layer::SerializedFields::all();
204
0
        std::initializer_list<FieldDescriptor> extra{ SrcIp,      DstIp,      PayloadLength,
205
0
                                                    IsFragment, NextHeader, Extensions };
206
0
        std::copy(extra.begin(), extra.end(), std::back_inserter(result));
207
0
        return result;
208
0
      }
209
210
      /// @struct IPv6ExtensionObject
211
      /// Fields describing one element of the Extensions array
212
      struct IPv6ExtensionObject : ObjectFieldDescriptor<IPv6ExtensionObject>
213
      {
214
        using ObjectFieldDescriptor::ObjectFieldDescriptor;
215
216
        /// @return All field descriptors for one extension header
217
        static std::vector<FieldDescriptor> all()
218
0
        {
219
0
          return { Name, Type };
220
0
        }
221
222
        /// @brief Extension type name (e.g. "Fragment", "Hop-By-Hop")
223
        static const FieldDescriptor Name;
224
225
        /// @brief Raw numeric extension type
226
        static const FieldDescriptor Type;
227
      };
228
229
      /// @brief Source IP address, as a string
230
      static const FieldDescriptor SrcIp;
231
232
      /// @brief Destination IP address, as a string
233
      static const FieldDescriptor DstIp;
234
235
      /// @brief Payload length, in host byte order
236
      static const FieldDescriptor PayloadLength;
237
238
      /// @brief Whether this packet is a fragment
239
      static const FieldDescriptor IsFragment;
240
241
      /// @brief Next Header field (first extension header, or upper-layer protocol if none)
242
      static const FieldDescriptor NextHeader;
243
244
      /// @brief Array of extension headers; elements described by IPv6ExtensionObject
245
      static const FieldDescriptor Extensions;
246
    };
247
248
  protected:
249
    void serializeLayer(ObjectScope& serializer) const override;
250
251
  private:
252
    void initLayer();
253
    void parseExtensions();
254
    void deleteExtensions();
255
256
    IPv6Extension* m_FirstExtension;
257
    IPv6Extension* m_LastExtension;
258
    size_t m_ExtensionsLen;
259
  };
260
261
  template <class TIPv6Extension> TIPv6Extension* IPv6Layer::getExtensionOfType() const
262
0
  {
263
0
    IPv6Extension* curExt = m_FirstExtension;
264
0
    while (curExt != nullptr && dynamic_cast<TIPv6Extension*>(curExt) == nullptr)
265
0
      curExt = curExt->getNextHeader();
266
267
0
    return static_cast<TIPv6Extension*>(curExt);
268
0
  }
269
270
  template <class TIPv6Extension> TIPv6Extension* IPv6Layer::addExtension(const TIPv6Extension& extensionHeader)
271
  {
272
    int offsetToAddHeader = static_cast<int>(getHeaderLen());
273
    if (!extendLayer(offsetToAddHeader, extensionHeader.getExtensionLen()))
274
    {
275
      return nullptr;
276
    }
277
278
    TIPv6Extension* newHeader = new TIPv6Extension(this, static_cast<size_t>(offsetToAddHeader));
279
    (*newHeader) = extensionHeader;
280
281
    if (m_FirstExtension != nullptr)
282
    {
283
      newHeader->getBaseHeader()->nextHeader = m_LastExtension->getBaseHeader()->nextHeader;
284
      m_LastExtension->getBaseHeader()->nextHeader = newHeader->getExtensionType();
285
      m_LastExtension->setNextHeader(newHeader);
286
      m_LastExtension = newHeader;
287
    }
288
    else
289
    {
290
      m_FirstExtension = newHeader;
291
      m_LastExtension = newHeader;
292
      newHeader->getBaseHeader()->nextHeader = getIPv6Header()->nextHeader;
293
      getIPv6Header()->nextHeader = newHeader->getExtensionType();
294
    }
295
296
    m_ExtensionsLen += newHeader->getExtensionLen();
297
298
    return newHeader;
299
  }
300
301
  // implementation of inline methods
302
303
  bool IPv6Layer::isDataValid(const uint8_t* data, size_t dataLen)
304
0
  {
305
0
    auto ip6Header = reinterpret_cast<const ip6_hdr*>(data);
306
0
    return canReinterpretAs<ip6_hdr>(data, dataLen) && ip6Header->ipVersion == 6;
307
0
  }
308
309
}  // namespace pcpp