Coverage Report

Created: 2026-08-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/NdpLayer.h
Line
Count
Source
1
#pragma once
2
3
#include "IcmpV6Layer.h"
4
#include "IpAddress.h"
5
#include "Layer.h"
6
#include "MacAddress.h"
7
#include "TLVData.h"
8
9
#include <vector>
10
11
/// @file
12
13
/// @namespace pcpp
14
/// @brief The main namespace for the PcapPlusPlus lib
15
namespace pcpp
16
{
17
18
  /// An enum representing the available option types for Neighbor Discovery in IPv6 (see RFC 4861)
19
  enum class NDPNeighborOptionTypes : int
20
  {
21
    NDP_OPTION_SOURCE_LINK_LAYER = 1,
22
    NDP_OPTION_TARGET_LINK_LAYER = 2,
23
    NDP_OPTION_PREFIX_INFORMATION = 3,
24
    NDP_OPTION_REDIRECTED_HEADER = 4,
25
    NDP_OPTION_MTU = 5,
26
    NDP_OPTION_UNKNOWN = 255
27
  };
28
29
  /// @class NdpOption
30
  /// A wrapper class for NDP options. This class does not create or modify NDP option records, but rather
31
  /// serves as a wrapper and provides useful methods for retrieving data from them
32
  class NdpOption : public TLVRecord<uint8_t, uint8_t>
33
  {
34
  public:
35
    /// A c'tor for this class that gets a pointer to the option raw data (byte array)
36
    /// @param[in] optionRawData A pointer to the NDP option raw data
37
1.99k
    explicit NdpOption(uint8_t* optionRawData) : TLVRecord(optionRawData)
38
1.99k
    {}
39
40
    /// A d'tor for this class, currently does nothing
41
    ~NdpOption() override = default;
42
43
    /// @return NDP option type casted as pcpp::NDPNeighborOptionTypes enum. If the data is null a value
44
    /// of NDP_OPTION_UNKNOWN is returned
45
    NDPNeighborOptionTypes getNdpOptionType() const
46
0
    {
47
0
      if (m_Data == nullptr)
48
0
        return NDPNeighborOptionTypes::NDP_OPTION_UNKNOWN;
49
0
50
0
      return static_cast<NDPNeighborOptionTypes>(m_Data->recordType);
51
0
    }
52
53
    // implement abstract methods
54
55
    size_t getTotalSize() const override
56
4.15k
    {
57
4.15k
      if (m_Data == nullptr)
58
0
        return 0;
59
60
4.15k
      return static_cast<size_t>(m_Data->recordLen) * 8;
61
4.15k
    }
62
63
    size_t getDataSize() const override
64
0
    {
65
0
      if (m_Data == nullptr)
66
0
      {
67
0
        return 0;
68
0
      }
69
70
      // length value is stored in units of 8 octets
71
0
      return static_cast<size_t>(m_Data->recordLen) * 8 - (2 * sizeof(uint8_t));
72
0
    }
73
  };
74
75
  /// @class NdpOptionBuilder
76
  /// A class for building NDP option records. This builder receives the NDP option parameters in its c'tor,
77
  /// builds the NDP option raw buffer and provides a build() method to get a NdpOption object out of it
78
  class NdpOptionBuilder : public TLVRecordBuilder
79
  {
80
  public:
81
    /// A c'tor for building NDP options which their value is a byte array. The NdpOption object can be later
82
    /// retrieved by calling build(). Each option is padded to have a 64-bit boundary.
83
    /// @param[in] optionType NDP option type
84
    /// @param[in] optionValue A buffer containing the option value. This buffer is read-only and isn't modified in
85
    /// any way.
86
    /// @param[in] optionValueLen Option value length in bytes
87
    NdpOptionBuilder(NDPNeighborOptionTypes optionType, const uint8_t* optionValue, uint8_t optionValueLen)
88
0
        : TLVRecordBuilder((uint8_t)optionType, optionValue, optionValueLen)
89
0
    {}
90
91
    /// Build the NdpOption object out of the parameters defined in the c'tor. Padding bytes are added to the
92
    /// option for option length with 64-bit boundaries.
93
    /// @return The NdpOption object
94
    NdpOption build() const;
95
  };
96
97
  /// @class NDPLayerBase
98
  /// Represents a base for NDP packet types
99
  class NDPLayerBase : public IcmpV6Layer
100
  {
101
  public:
102
2.55k
    ~NDPLayerBase() override = default;
103
104
    /// @return The number of NDP options in this layer
105
    size_t getNdpOptionCount() const;
106
107
    /// Get a NDP option by type.
108
    /// @param[in] option NDP option type
109
    /// @return An NdpOption object that contains the first option that matches this type, or logical null
110
    /// (NdpOption#isNull() == true) if no such option found
111
    NdpOption getNdpOption(NDPNeighborOptionTypes option) const;
112
113
    /// @return The first NDP option in the packet. If the current layer contains no options the returned value will
114
    /// contain a logical null (NdpOption#isNull() == true)
115
    NdpOption getFirstNdpOption() const;
116
117
    /// Get the NDP option that comes after a given option. If the given option was the last one, the
118
    /// returned value will contain a logical null (IdpOption#isNull() == true)
119
    /// @param[in] option An NDP option object that exists in the current layer
120
    /// @return A NdpOption object that contains the NDP option data that comes next, or logical null if the given
121
    /// NDP option: (1) was the last one; or (2) contains a logical null; or (3) doesn't belong to this packet
122
    NdpOption getNextNdpOption(NdpOption& option) const;
123
124
    /// Add a new NDP option at the end of the layer (after the last NDP option)
125
    /// @param[in] optionBuilder An NdpOptionBuilder object that contains the NDP option data to be added
126
    /// @return A NdpOption object that contains the newly added NDP option data or logical null
127
    /// (NdpOption#isNull() == true) if addition failed. In case of a failure a corresponding error message will be
128
    /// printed to log
129
    NdpOption addNdpOption(const NdpOptionBuilder& optionBuilder);
130
131
    /// Remove all NDP options from the layer
132
    /// @return True if options removed successfully or false if some error occurred (an appropriate error message
133
    /// will be printed to log)
134
    bool removeAllNdpOptions();
135
136
  protected:
137
0
    NDPLayerBase() = default;
138
139
    NDPLayerBase(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
140
2.55k
        : IcmpV6Layer(data, dataLen, prevLayer, packet)
141
2.55k
    {}
142
143
  private:
144
    TLVRecordReader<NdpOption> m_OptionReader;
145
146
    virtual size_t getNdpHeaderLen() const = 0;
147
    virtual uint8_t* getNdpOptionsBasePtr() const
148
1.80k
    {
149
1.80k
      return m_Data + getNdpHeaderLen();
150
1.80k
    };
151
    NdpOption addNdpOptionAt(const NdpOptionBuilder& optionBuilder, int offset);
152
  };
153
154
  /// @class NDPNeighborSolicitationLayer
155
  /// Represents a NDP Neighbor Solicitation protocol layer
156
  class NDPNeighborSolicitationLayer : public NDPLayerBase
157
  {
158
  public:
159
    /// @struct ndpneighborsolicitationhdr
160
    /// Represents neighbor solicitation message format
161
#pragma pack(push, 1)
162
    struct ndpneighborsolicitationhdr : icmpv6hdr
163
    {
164
      /// Reserved
165
      uint32_t reserved;
166
      /// Target address - Target address of solicitation message
167
      uint8_t targetIP[16];
168
    };
169
#pragma pack(pop)
170
171
    /// A constructor that creates the layer from an existing packet raw data
172
    /// @param[in] data A pointer to the raw data
173
    /// @param[in] dataLen Size of the data in bytes
174
    /// @param[in] prevLayer A pointer to the previous layer
175
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
176
    NDPNeighborSolicitationLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
177
2.20k
        : NDPLayerBase(data, dataLen, prevLayer, packet)
178
2.20k
    {}
179
180
    /// Checks whether the data is large enough to be parsed as a neighbor solicitation message
181
    /// @param[in] data A pointer to the raw data
182
    /// @param[in] dataLen Size of the data in bytes
183
    /// @return True if the data is at least the size of the neighbor solicitation header
184
    static bool isDataValid(const uint8_t* data, size_t dataLen)
185
2.20k
    {
186
2.20k
      return data != nullptr && dataLen >= sizeof(ndpneighborsolicitationhdr);
187
2.20k
    }
188
189
    /// A constructor for a new NDPNeighborSolicitationLayer object
190
    /// @param[in] code Code field
191
    /// @param[in] targetIP Target IP address for which the solicitation shall be created
192
    NDPNeighborSolicitationLayer(uint8_t code, const IPv6Address& targetIP);
193
194
    /// A constructor for a new NDPNeighborSolicitationLayer object
195
    /// @param[in] code Code field
196
    /// @param[in] targetIP Target IP address for which the solicitation shall be created
197
    /// @param[in] srcMac Mac address which shall be put in the linklayer option
198
    NDPNeighborSolicitationLayer(uint8_t code, const IPv6Address& targetIP, const MacAddress& srcMac);
199
200
    ~NDPNeighborSolicitationLayer() override = default;
201
202
    /// @return Get the IP address specified as the target IP address in the solicitation message
203
    IPv6Address getTargetIP() const
204
1.07k
    {
205
1.07k
      return IPv6Address(getNdpHeader()->targetIP);
206
1.07k
    };
207
208
    /// Checks if the layer has a link layer address option set
209
    /// @return true if link layer address option is available, false otherwise
210
    bool hasLinkLayerAddress() const;
211
212
    /// Get the Link Layer Address
213
    /// @return Mac address which is specified in the link layer address option
214
    MacAddress getLinkLayerAddress() const;
215
216
    std::string toString() const override;
217
218
  private:
219
    void initLayer(uint8_t code, const IPv6Address& targetIP);
220
    ndpneighborsolicitationhdr* getNdpHeader() const
221
1.07k
    {
222
1.07k
      return reinterpret_cast<ndpneighborsolicitationhdr*>(m_Data);
223
1.07k
    }
224
    size_t getNdpHeaderLen() const override
225
2.91k
    {
226
2.91k
      return sizeof(ndpneighborsolicitationhdr);
227
2.91k
    };
228
  };
229
230
  /// @class NDPNeighborAdvertisementLayer
231
  /// Represents a NDP Neighbor Advertisement protocol layer
232
  class NDPNeighborAdvertisementLayer : public NDPLayerBase
233
  {
234
  public:
235
    /// @struct ndpneighboradvertisementhdr
236
    /// Represents neighbor advertisement message format
237
#pragma pack(push, 1)
238
    struct ndpneighboradvertisementhdr : icmpv6hdr
239
    {
240
#if (BYTE_ORDER == LITTLE_ENDIAN)
241
      uint32_t
242
          /// Unused field
243
          reserved : 5,
244
          /// Flag indicating that this entry should override the old one
245
          override : 1,
246
          /// Flag indicating that the advertisement was sent in response to a Neighbor Solicitation from the
247
          /// Destination address
248
          solicited : 1,
249
          /// Flag indicating that the advertisement is sent by a router
250
          router : 1,
251
          /// Unused field
252
          reserved2 : 24;
253
#else
254
      uint32_t
255
          /// Flag indicating that the advertisement is sent by a router
256
          router : 1,
257
          /// Flag indicating that the advertisement was sent in response to a Neighbor Solicitation from the
258
          /// Destination address
259
          solicited : 1,
260
          /// Flag indicating that this entry should override the old one
261
          override : 1,
262
          /// Unused field
263
          reserved : 29;
264
#endif
265
      /// Target address - Either source address of advertisement or address for requested MAC
266
      uint8_t targetIP[16];
267
    };
268
#pragma pack(pop)
269
270
    /// A constructor that creates the layer from an existing packet raw data
271
    /// @param[in] data A pointer to the raw data
272
    /// @param[in] dataLen Size of the data in bytes
273
    /// @param[in] prevLayer A pointer to the previous layer
274
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
275
    NDPNeighborAdvertisementLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
276
358
        : NDPLayerBase(data, dataLen, prevLayer, packet)
277
358
    {}
278
279
    /// Checks whether the data is large enough to be parsed as a neighbor advertisement message
280
    /// @param[in] data A pointer to the raw data
281
    /// @param[in] dataLen Size of the data in bytes
282
    /// @return True if the data is at least the size of the neighbor advertisement header
283
    static bool isDataValid(const uint8_t* data, size_t dataLen)
284
358
    {
285
358
      return data != nullptr && dataLen >= sizeof(ndpneighboradvertisementhdr);
286
358
    }
287
288
    /// A constructor that allocates a new NDP Advertisement Layer with target link-layer address option
289
    /// @param[in] code Code field
290
    /// @param[in] targetIP The target IP address from the Neighbor Solicitation message (solicited advertisements)
291
    /// or the address whose link-layer address has changed (unsolicited advertisement)
292
    /// @param[in] targetMac Adds the target link-layer address into the option field of the layer
293
    /// @param[in] routerFlag The router flag
294
    /// @param[in] unicastFlag The solicited flag
295
    /// @param[in] overrideFlag The override flag
296
    NDPNeighborAdvertisementLayer(uint8_t code, const IPv6Address& targetIP, const MacAddress& targetMac,
297
                                  bool routerFlag, bool unicastFlag, bool overrideFlag);
298
299
    /// A constructor that allocates a new NDP Advertisement Layer
300
    /// @param code Code field
301
    /// @param targetIP The target IP address from the Neighbor Solicitation message (solicited advertisements) or
302
    /// the address whose link-layer address has changed (unsolicited advertisement)
303
    /// @param routerFlag The router flag
304
    /// @param unicastFlag The solicited flag
305
    /// @param overrideFlag The override flag
306
    NDPNeighborAdvertisementLayer(uint8_t code, const IPv6Address& targetIP, bool routerFlag, bool unicastFlag,
307
                                  bool overrideFlag);
308
309
    ~NDPNeighborAdvertisementLayer() override = default;
310
311
    /// @return Get the target MAC address
312
    MacAddress getTargetMac() const;
313
314
    /// @return Get the target IP address
315
    IPv6Address getTargetIP() const
316
178
    {
317
178
      return IPv6Address(getNdpHeader()->targetIP);
318
178
    }
319
320
    /// @return Get information if the target link-layer address was added in the option field of the header
321
    bool hasTargetMacInfo() const;
322
323
    /// @return Get the router flag
324
    bool getRouterFlag() const
325
0
    {
326
0
      return getNdpHeader()->router;
327
0
    }
328
329
    /// @return Get the unicast flag
330
    bool getUnicastFlag() const
331
0
    {
332
0
      return getNdpHeader()->solicited;
333
0
    }
334
335
    /// @return Get the override flag
336
    bool getOverrideFlag() const
337
0
    {
338
0
      return getNdpHeader()->override;
339
0
    }
340
341
    std::string toString() const override;
342
343
  private:
344
    void initLayer(uint8_t code, const IPv6Address& targetIP, bool routerFlag, bool unicastFlag, bool overrideFlag);
345
    ndpneighboradvertisementhdr* getNdpHeader() const
346
178
    {
347
178
      return reinterpret_cast<ndpneighboradvertisementhdr*>(m_Data);
348
178
    }
349
    size_t getNdpHeaderLen() const override
350
684
    {
351
684
      return sizeof(ndpneighboradvertisementhdr);
352
684
    };
353
  };
354
355
}  // namespace pcpp