Coverage Report

Created: 2023-01-17 06:15

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