Coverage Report

Created: 2025-07-11 07:47

/src/PcapPlusPlus/Packet++/header/NdpLayer.h
Line
Count
Source (jump to first uncovered line)
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
30
    explicit NdpOption(uint8_t* optionRawData) : TLVRecord(optionRawData)
38
30
    {}
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
0
    {
57
0
      if (m_Data == nullptr)
58
0
        return 0;
59
60
0
      return static_cast<size_t>(m_Data->recordLen) * 8;
61
0
    }
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
60
    ~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
60
        : IcmpV6Layer(data, dataLen, prevLayer, packet)
141
60
    {}
142
143
  private:
144
    TLVRecordReader<NdpOption> m_OptionReader;
145
146
    virtual size_t getNdpHeaderLen() const = 0;
147
    virtual uint8_t* getNdpOptionsBasePtr() const
148
30
    {
149
30
      return m_Data + getNdpHeaderLen();
150
30
    };
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
60
        : NDPLayerBase(data, dataLen, prevLayer, packet)
178
60
    {}
179
180
    /// A constructor for a new NDPNeighborSolicitationLayer object
181
    /// @param[in] code Code field
182
    /// @param[in] targetIP Target IP address for which the solicitation shall be created
183
    NDPNeighborSolicitationLayer(uint8_t code, const IPv6Address& targetIP);
184
185
    /// A constructor for a new NDPNeighborSolicitationLayer object
186
    /// @param[in] code Code field
187
    /// @param[in] targetIP Target IP address for which the solicitation shall be created
188
    /// @param[in] srcMac Mac address which shall be put in the linklayer option
189
    NDPNeighborSolicitationLayer(uint8_t code, const IPv6Address& targetIP, const MacAddress& srcMac);
190
191
    ~NDPNeighborSolicitationLayer() override = default;
192
193
    /// @return Get the IP address specified as the target IP address in the solicitation message
194
    IPv6Address getTargetIP() const
195
30
    {
196
30
      return IPv6Address(getNdpHeader()->targetIP);
197
30
    };
198
199
    /// Checks if the layer has a link layer address option set
200
    /// @return true if link layer address option is available, false otherwise
201
    bool hasLinkLayerAddress() const;
202
203
    /// Get the Link Layer Address
204
    /// @return Mac address which is specified in the link layer address option
205
    MacAddress getLinkLayerAddress() const;
206
207
    std::string toString() const override;
208
209
  private:
210
    void initLayer(uint8_t code, const IPv6Address& targetIP);
211
    ndpneighborsolicitationhdr* getNdpHeader() const
212
30
    {
213
30
      return reinterpret_cast<ndpneighborsolicitationhdr*>(m_Data);
214
30
    }
215
    size_t getNdpHeaderLen() const override
216
60
    {
217
60
      return sizeof(ndpneighborsolicitationhdr);
218
60
    };
219
  };
220
221
  /// @class NDPNeighborAdvertisementLayer
222
  /// Represents a NDP Neighbor Advertisement protocol layer
223
  class NDPNeighborAdvertisementLayer : public NDPLayerBase
224
  {
225
  public:
226
    /// @struct ndpneighboradvertisementhdr
227
    /// Represents neighbor advertisement message format
228
#pragma pack(push, 1)
229
    struct ndpneighboradvertisementhdr : icmpv6hdr
230
    {
231
#if (BYTE_ORDER == LITTLE_ENDIAN)
232
      uint32_t
233
          /// Unused field
234
          reserved : 5,
235
          /// Flag indicating that this entry should override the old one
236
          override : 1,
237
          /// Flag indicating that the advertisement was sent in response to a Neighbor Solicitation from the
238
          /// Destination address
239
          solicited : 1,
240
          /// Flag indicating that the advertisement is sent by a router
241
          router : 1,
242
          /// Unused field
243
          reserved2 : 24;
244
#else
245
      uint32_t
246
          /// Flag indicating that the advertisement is sent by a router
247
          router : 1,
248
          /// Flag indicating that the advertisement was sent in response to a Neighbor Solicitation from the
249
          /// Destination address
250
          solicited : 1,
251
          /// Flag indicating that this entry should override the old one
252
          override : 1,
253
          /// Unused field
254
          reserved : 29;
255
#endif
256
      /// Target address - Either source address of advertisement or address for requested MAC
257
      uint8_t targetIP[16];
258
    };
259
#pragma pack(pop)
260
261
    /// A constructor that creates the layer from an existing packet raw data
262
    /// @param[in] data A pointer to the raw data
263
    /// @param[in] dataLen Size of the data in bytes
264
    /// @param[in] prevLayer A pointer to the previous layer
265
    /// @param[in] packet A pointer to the Packet instance where layer will be stored in
266
    NDPNeighborAdvertisementLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet)
267
0
        : NDPLayerBase(data, dataLen, prevLayer, packet)
268
0
    {}
269
270
    /// A constructor that allocates a new NDP Advertisement Layer with target link-layer address option
271
    /// @param[in] code Code field
272
    /// @param[in] targetIP The target IP address from the Neighbor Solicitation message (solicited advertisements)
273
    /// or the address whose link-layer address has changed (unsolicited advertisement)
274
    /// @param[in] targetMac Adds the target link-layer address into the option field of the layer
275
    /// @param[in] routerFlag The router flag
276
    /// @param[in] unicastFlag The solicited flag
277
    /// @param[in] overrideFlag The override flag
278
    NDPNeighborAdvertisementLayer(uint8_t code, const IPv6Address& targetIP, const MacAddress& targetMac,
279
                                  bool routerFlag, bool unicastFlag, bool overrideFlag);
280
281
    /// A constructor that allocates a new NDP Advertisement Layer
282
    /// @param code Code field
283
    /// @param targetIP The target IP address from the Neighbor Solicitation message (solicited advertisements) or
284
    /// the address whose link-layer address has changed (unsolicited advertisement)
285
    /// @param routerFlag The router flag
286
    /// @param unicastFlag The solicited flag
287
    /// @param overrideFlag The override flag
288
    NDPNeighborAdvertisementLayer(uint8_t code, const IPv6Address& targetIP, bool routerFlag, bool unicastFlag,
289
                                  bool overrideFlag);
290
291
    ~NDPNeighborAdvertisementLayer() override = default;
292
293
    /// @return Get the target MAC address
294
    MacAddress getTargetMac() const;
295
296
    /// @return Get the target IP address
297
    IPv6Address getTargetIP() const
298
0
    {
299
0
      return IPv6Address(getNdpHeader()->targetIP);
300
0
    }
301
302
    /// @return Get information if the target link-layer address was added in the option field of the header
303
    bool hasTargetMacInfo() const;
304
305
    /// @return Get the router flag
306
    bool getRouterFlag() const
307
0
    {
308
0
      return getNdpHeader()->router;
309
0
    }
310
311
    /// @return Get the unicast flag
312
    bool getUnicastFlag() const
313
0
    {
314
0
      return getNdpHeader()->solicited;
315
0
    }
316
317
    /// @return Get the override flag
318
    bool getOverrideFlag() const
319
0
    {
320
0
      return getNdpHeader()->override;
321
0
    }
322
323
    std::string toString() const override;
324
325
  private:
326
    void initLayer(uint8_t code, const IPv6Address& targetIP, bool routerFlag, bool unicastFlag, bool overrideFlag);
327
    ndpneighboradvertisementhdr* getNdpHeader() const
328
0
    {
329
0
      return reinterpret_cast<ndpneighboradvertisementhdr*>(m_Data);
330
0
    }
331
    size_t getNdpHeaderLen() const override
332
0
    {
333
0
      return sizeof(ndpneighboradvertisementhdr);
334
0
    };
335
  };
336
337
}  // namespace pcpp