Coverage Report

Created: 2024-02-25 06:29

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