Coverage Report

Created: 2023-01-17 06:15

/src/PcapPlusPlus/Dist/header/Packet.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef PACKETPP_PACKET
2
#define PACKETPP_PACKET
3
4
#include "RawPacket.h"
5
#include "Layer.h"
6
#include <vector>
7
8
/// @file
9
10
/**
11
 * \namespace pcpp
12
 * \brief The main namespace for the PcapPlusPlus lib
13
 */
14
namespace pcpp
15
{
16
17
  /**
18
   * @class Packet
19
   * This class represents a parsed packet. It contains the raw data (RawPacket instance), and a linked list of layers, each layer is a parsed
20
   * protocol that this packet contains. The layers linked list is ordered where the first layer is the lowest in the packet (currently it's always
21
   * Ethernet protocol as PcapPlusPlus supports only Ethernet packets), the next layer will be L2.5 or L3 (e.g VLAN, IPv4, IPv6, etc.), and so on.
22
   * etc.), etc. The last layer in the linked list will be the highest in the packet.
23
   * For example: for a standard HTTP request packet the layer will look like this: EthLayer -> IPv4Layer -> TcpLayer -> HttpRequestLayer <BR>
24
   * Packet instance isn't read only. The user can add or remove layers, update current layer, etc.
25
   */
26
  class Packet
27
  {
28
    friend class Layer;
29
  private:
30
    RawPacket* m_RawPacket;
31
    Layer* m_FirstLayer;
32
    Layer* m_LastLayer;
33
    uint64_t m_ProtocolTypes;
34
    size_t m_MaxPacketLen;
35
    bool m_FreeRawPacket;
36
    bool m_CanReallocateData;
37
38
  public:
39
40
    /**
41
     * A constructor for creating a new packet (with no layers).
42
     * When using this constructor an empty raw buffer is allocated (with the size of maxPacketLen) and a new RawPacket is created
43
     * @param[in] maxPacketLen The expected packet length in bytes
44
     */
45
    Packet(size_t maxPacketLen = 1);
46
47
    /**
48
     * A constructor for creating a new packet with a buffer that is pre-allocated by the user.
49
     * The packet is created empty (with no layers), which means the constructor doesn't parse the data in the buffer.
50
     * Instead, all of the raw data of this packet it written to this buffer: whenever a layer is added, it's data is written to this buffer.
51
     * The buffer isn't freed and it's content isn't erased when the packet object is deleted.
52
     * This constructor is useful when you already have a memory buffer and you want to create packet data in it.
53
     * @param[in] buffer A pointer to a pre-allocated memory buffer
54
     * @param[in] bufferSize The size of the buffer
55
     */
56
    Packet(uint8_t* buffer, size_t bufferSize);
57
58
    /**
59
     * A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets that came from the network.
60
     * When using this constructor a pointer to the RawPacket is saved (data isn't copied) and the RawPacket is parsed, meaning all layers
61
     * are created and linked to each other in the right order. In this overload of the constructor the user can specify whether to free
62
     * the instance of raw packet when the Packet is free or not
63
     * @param[in] rawPacket A pointer to the raw packet
64
     * @param[in] freeRawPacket Optional parameter. A flag indicating if the destructor should also call the raw packet destructor or not. Default value is false
65
     * @param[in] parseUntil Optional parameter. Parse the packet until you reach a certain protocol (inclusive). Can be useful for cases when you need to parse only up to a
66
     * certain layer and want to avoid the performance impact and memory consumption of parsing the whole packet. Default value is ::UnknownProtocol which means don't take this
67
     * parameter into account
68
     * @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI model (inclusive). Can be useful for cases when you need to
69
     * parse only up to a certain OSI layer (for example transport layer) and want to avoid the performance impact and memory consumption of parsing the whole packet.
70
     * Default value is ::OsiModelLayerUnknown which means don't take this parameter into account
71
     */
72
    explicit Packet(RawPacket* rawPacket, bool freeRawPacket = false, ProtocolType parseUntil = UnknownProtocol, OsiModelLayer parseUntilLayer = OsiModelLayerUnknown);
73
74
    /**
75
     * A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets that came from the network.
76
     * When using this constructor a pointer to the RawPacket is saved (data isn't copied) and the RawPacket is parsed, meaning all layers
77
     * are created and linked to each other in the right order. In this overload of the constructor the user can specify whether to free
78
     * the instance of raw packet when the Packet is free or not. This constructor should be used to parse the packet up to a certain layer
79
     * @param[in] rawPacket A pointer to the raw packet
80
     * @param[in] parseUntil Optional parameter. Parse the packet until you reach a certain protocol (inclusive). Can be useful for cases when you need to parse only up to a
81
     * certain layer and want to avoid the performance impact and memory consumption of parsing the whole packet
82
     */
83
    Packet(RawPacket* rawPacket, ProtocolType parseUntil);
84
85
    /**
86
     * A constructor for creating a packet out of already allocated RawPacket. Very useful when parsing packets that came from the network.
87
     * When using this constructor a pointer to the RawPacket is saved (data isn't copied) and the RawPacket is parsed, meaning all layers
88
     * are created and linked to each other in the right order. In this overload of the constructor the user can specify whether to free
89
     * the instance of raw packet when the Packet is free or not. . This constructor should be used to parse the packet up to a certain layer in the OSI model
90
     * @param[in] rawPacket A pointer to the raw packet
91
     * @param[in] parseUntilLayer Optional parameter. Parse the packet until you reach a certain layer in the OSI model (inclusive). Can be useful for cases when you need to
92
     * parse only up to a certain OSI layer (for example transport layer) and want to avoid the performance impact and memory consumption of parsing the whole packet
93
     */
94
    Packet(RawPacket* rawPacket, OsiModelLayer parseUntilLayer);
95
96
    /**
97
     * A destructor for this class. Frees all layers allocated by this instance (Notice: it doesn't free layers that weren't allocated by this
98
     * class, for example layers that were added by addLayer() or insertLayer() ). In addition it frees the raw packet if it was allocated by
99
     * this instance (meaning if it was allocated by this instance constructor)
100
     */
101
997k
    virtual ~Packet() { destructPacketData(); }
102
103
    /**
104
     * A copy constructor for this class. This copy constructor copies all the raw data and re-create all layers. So when the original Packet
105
     * is being freed, no data will be lost in the copied instance
106
     * @param[in] other The instance to copy from
107
     */
108
0
    Packet(const Packet& other) { copyDataFrom(other); }
109
110
    /**
111
     * Assignment operator overloading. It first frees all layers allocated by this instance (Notice: it doesn't free layers that weren't allocated by this
112
     * class, for example layers that were added by addLayer() or insertLayer() ). In addition it frees the raw packet if it was allocated by
113
     * this instance (meaning if it was allocated by this instance constructor).
114
     * Afterwards it copies the data from the other packet in the same way used in the copy constructor.
115
     * @param[in] other The instance to copy from
116
     */
117
    Packet& operator=(const Packet& other);
118
119
    /**
120
     * Get a pointer to the Packet's RawPacket
121
     * @return A pointer to the Packet's RawPacket
122
     */
123
0
    RawPacket* getRawPacket() const { return m_RawPacket; }
124
125
    /**
126
     * Set a RawPacket and re-construct all packet layers
127
     * @param[in] rawPacket Raw packet to set
128
     * @param[in] freeRawPacket A flag indicating if the destructor should also call the raw packet destructor or not
129
     * @param[in] parseUntil Parse the packet until it reaches this protocol. Can be useful for cases when you need to parse only up to a certain layer and want to avoid the
130
     * performance impact and memory consumption of parsing the whole packet. Default value is ::UnknownProtocol which means don't take this parameter into account
131
     * @param[in] parseUntilLayer Parse the packet until certain layer in OSI model. Can be useful for cases when you need to parse only up to a certain layer and want to avoid the
132
     * performance impact and memory consumption of parsing the whole packet. Default value is ::OsiModelLayerUnknown which means don't take this parameter into account
133
     */
134
    void setRawPacket(RawPacket* rawPacket, bool freeRawPacket, ProtocolType parseUntil = UnknownProtocol, OsiModelLayer parseUntilLayer = OsiModelLayerUnknown);
135
136
    /**
137
     * Get a pointer to the Packet's RawPacket in a read-only manner
138
     * @return A pointer to the Packet's RawPacket
139
     */
140
0
    RawPacket* getRawPacketReadOnly() const { return m_RawPacket; }
141
142
    /**
143
     * Get a pointer to the first (lowest) layer in the packet
144
     * @return A pointer to the first (lowest) layer in the packet
145
     */
146
1.36M
    Layer* getFirstLayer() const { return m_FirstLayer; }
147
148
    /**
149
     * Get a pointer to the last (highest) layer in the packet
150
     * @return A pointer to the last (highest) layer in the packet
151
     */
152
0
    Layer* getLastLayer() const { return m_LastLayer; }
153
154
    /**
155
     * Add a new layer as the last layer in the packet. This method gets a pointer to the new layer as a parameter
156
     * and attaches it to the packet. Notice after calling this method the input layer is attached to the packet so
157
     * every change you make in it affect the packet; Also it cannot be attached to other packets
158
     * @param[in] newLayer A pointer to the new layer to be added to the packet
159
     * @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct.  Default is false.
160
     * @return True if everything went well or false otherwise (an appropriate error log message will be printed in
161
     * such cases)
162
     */
163
    bool addLayer(Layer* newLayer, bool ownInPacket = false) { return insertLayer(m_LastLayer, newLayer, ownInPacket); }
164
165
    /**
166
     * Insert a new layer after an existing layer in the packet. This method gets a pointer to the new layer as a
167
     * parameter and attaches it to the packet. Notice after calling this method the input layer is attached to the
168
     * packet so every change you make in it affect the packet; Also it cannot be attached to other packets
169
     * @param[in] prevLayer A pointer to an existing layer in the packet which the new layer should followed by. If
170
     * this layer isn't attached to a packet and error will be printed to log and false will be returned
171
     * @param[in] newLayer A pointer to the new layer to be added to the packet
172
     * @param[in] ownInPacket If true, Packet fully owns newLayer, including memory deletion upon destruct.  Default is false.
173
     * @return True if everything went well or false otherwise (an appropriate error log message will be printed in
174
     * such cases)
175
     */
176
    bool insertLayer(Layer* prevLayer, Layer* newLayer, bool ownInPacket = false);
177
178
179
    /**
180
     * Remove an existing layer from the packet. The layer to removed is identified by its type (protocol). If the
181
     * packet has multiple layers of the same type in the packet the user may specify the index of the layer to remove
182
     * (the default index is 0 - remove the first layer of this type). If the layer was allocated during packet creation
183
     * it will be deleted and any pointer to it will get invalid. However if the layer was allocated by the user and
184
     * manually added to the packet it will simply get detached from the packet, meaning the pointer to it will stay
185
     * valid and its data (that was removed from the packet) will be copied back to the layer. In that case it's
186
     * the user's responsibility to delete the layer instance
187
     * @param[in] layerType The layer type (protocol) to remove
188
     * @param[in] index If there are multiple layers of the same type, indicate which instance to remove. The default
189
     * value is 0, meaning remove the first layer of this type
190
     * @return True if everything went well or false otherwise (an appropriate error log message will be printed in
191
     * such cases)
192
     */
193
    bool removeLayer(ProtocolType layerType, int index = 0);
194
195
    /**
196
     * Remove the first layer in the packet. The layer will be deleted if it was allocated during packet creation, or detached
197
     * if was allocated outside of the packet. Please refer to removeLayer() to get more info
198
     * @return True if layer removed successfully, or false if removing the layer failed or if there are no layers in the
199
     * packet. In any case of failure an appropriate error log message will be printed
200
     */
201
    bool removeFirstLayer();
202
203
    /**
204
     * Remove the last layer in the packet. The layer will be deleted if it was allocated during packet creation, or detached
205
     * if was allocated outside of the packet. Please refer to removeLayer() to get more info
206
     * @return True if layer removed successfully, or false if removing the layer failed or if there are no layers in the
207
     * packet. In any case of failure an appropriate error log message will be printed
208
     */
209
    bool removeLastLayer();
210
211
    /**
212
     * Remove all layers that come after a certain layer. All layers removed will be deleted if they were allocated during
213
     * packet creation or detached if were allocated outside of the packet, please refer to removeLayer() to get more info
214
     * @param[in] layer A pointer to the layer to begin removing from. Please note this layer will not be removed, only the
215
     * layers that come after it will be removed. Also, if removal of one layer failed, the method will return immediately and
216
     * the following layers won't be deleted
217
     * @return True if all layers were removed successfully, or false if failed to remove at least one layer. In any case of
218
     * failure an appropriate error log message will be printed
219
     */
220
    bool removeAllLayersAfter(Layer* layer);
221
222
    /**
223
     * Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated from the
224
     * packet - e.g it will be removed from the layer chain of the packet and its data will be copied from the packet buffer
225
     * into an internal layer buffer. After a layer is detached, it can be added into another packet (but it's impossible to
226
     * attach a layer to multiple packets in the same time). After layer is detached, it's the user's responsibility to
227
     * delete it when it's not needed anymore
228
     * @param[in] layerType The layer type (protocol) to detach from the packet
229
     * @param[in] index If there are multiple layers of the same type, indicate which instance to detach. The default
230
     * value is 0, meaning detach the first layer of this type
231
     * @return A pointer to the detached layer or NULL if detaching process failed. In any case of failure an
232
     * appropriate error log message will be printed
233
     */
234
    Layer* detachLayer(ProtocolType layerType, int index = 0);
235
236
    /**
237
     * Detach a layer from the packet. Detaching means the layer instance will not be deleted, but rather separated from the
238
     * packet - e.g it will be removed from the layer chain of the packet and its data will be copied from the packet buffer
239
     * into an internal layer buffer. After a layer is detached, it can be added into another packet (but it's impossible to
240
     * attach a layer to multiple packets at the same time). After layer is detached, it's the user's responsibility to
241
     * delete it when it's not needed anymore
242
     * @param[in] layer A pointer to the layer to detach
243
     * @return True if the layer was detached successfully, or false if something went wrong. In any case of failure an
244
     * appropriate error log message will be printed
245
     */
246
0
    bool detachLayer(Layer* layer) { return removeLayer(layer, false); }
247
248
    /**
249
     * Get a pointer to the layer of a certain type (protocol). This method goes through the layers and returns a layer
250
     * that matches the give protocol type
251
     * @param[in] layerType The layer type (protocol) to fetch
252
     * @param[in] index If there are multiple layers of the same type, indicate which instance to fetch. The default
253
     * value is 0, meaning fetch the first layer of this type
254
     * @return A pointer to the layer or NULL if no such layer was found
255
     */
256
    Layer* getLayerOfType(ProtocolType layerType, int index = 0) const;
257
258
    /**
259
     * A templated method to get a layer of a certain type (protocol). If no layer of such type is found, NULL is returned
260
     * @param[in] reverseOrder The optional parameter that indicates that the lookup should run in reverse order, the default value is false
261
     * @return A pointer to the layer of the requested type, NULL if not found
262
     */
263
    template<class TLayer>
264
    TLayer* getLayerOfType(bool reverseOrder = false) const;
265
266
    /**
267
     * A templated method to get the first layer of a certain type (protocol), start searching from a certain layer.
268
     * For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) -> IPv4Layer
269
     * and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(3) will be returned
270
     * If no layer of such type is found, NULL is returned
271
     * @param[in] startLayer A pointer to the layer to start search from
272
     * @return A pointer to the layer of the requested type, NULL if not found
273
     */
274
    template<class TLayer>
275
    TLayer* getNextLayerOfType(Layer* startLayer) const;
276
277
    /**
278
     * A templated method to get the first layer of a certain type (protocol), start searching from a certain layer.
279
     * For example: if a packet looks like: EthLayer -> VlanLayer(1) -> VlanLayer(2) -> VlanLayer(3) -> IPv4Layer
280
     * and the user put VlanLayer(2) as a parameter and wishes to search for a VlanLayer, VlanLayer(1) will be returned
281
     * If no layer of such type is found, NULL is returned
282
     * @param[in] startLayer A pointer to the layer to start search from
283
     * @return A pointer to the layer of the requested type, NULL if not found
284
     */
285
    template<class TLayer>
286
    TLayer* getPrevLayerOfType(Layer* startLayer) const;
287
288
    /**
289
     * Check whether the packet contains a certain protocol
290
     * @param[in] protocolType The protocol type to search
291
     * @return True if the packet contains the protocol, false otherwise
292
     */
293
997k
    bool isPacketOfType(ProtocolType protocolType) const { return m_ProtocolTypes & protocolType; }
294
295
    /**
296
     * Each layer can have fields that can be calculate automatically from other fields using Layer#computeCalculateFields(). This method forces all layers to calculate these
297
     * fields values
298
     */
299
    void computeCalculateFields();
300
301
    /**
302
     * Each layer can print a string representation of the layer most important data using Layer#toString(). This method aggregates this string from all layers and
303
     * print it to a complete string containing all packet's relevant data
304
     * @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set to false
305
     * @return A string containing most relevant data from all layers (looks like the packet description in Wireshark)
306
     */
307
    std::string toString(bool timeAsLocalTime = true) const;
308
309
    /**
310
     * Similar to toString(), but instead of one string it outputs a list of strings, one string for every layer
311
     * @param[out] result A string vector that will contain all strings
312
     * @param[in] timeAsLocalTime Print time as local time or GMT. Default (true value) is local time, for GMT set to false
313
     */
314
    void toStringList(std::vector<std::string>& result, bool timeAsLocalTime = true) const;
315
316
  private:
317
    void copyDataFrom(const Packet& other);
318
319
    void destructPacketData();
320
321
    bool extendLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToExtend);
322
    bool shortenLayer(Layer* layer, int offsetInLayer, size_t numOfBytesToShorten);
323
324
    void reallocateRawData(size_t newSize);
325
326
    bool removeLayer(Layer* layer, bool tryToDelete);
327
328
    std::string printPacketInfo(bool timeAsLocalTime) const;
329
330
    Layer* createFirstLayer(LinkLayerType linkType);
331
  }; // class Packet
332
333
334
  // implementation of inline methods
335
336
  template<class TLayer>
337
  TLayer* Packet::getLayerOfType(bool reverse) const
338
683k
  {
339
683k
    if (!reverse)
340
683k
    {
341
683k
      if (dynamic_cast<TLayer*>(getFirstLayer()) != NULL)
342
661k
        return dynamic_cast<TLayer*>(getFirstLayer());
343
344
22.0k
      return getNextLayerOfType<TLayer>(getFirstLayer());
345
683k
    }
346
347
    // lookup in reverse order
348
0
    if (dynamic_cast<TLayer*>(getLastLayer()) != NULL)
349
0
      return dynamic_cast<TLayer*>(getLastLayer());
350
351
0
    return getPrevLayerOfType<TLayer>(getLastLayer());
352
0
  }
353
354
  template<class TLayer>
355
  TLayer* Packet::getNextLayerOfType(Layer* curLayer) const
356
22.0k
  {
357
22.0k
    if (curLayer == NULL)
358
0
      return NULL;
359
360
22.0k
    curLayer = curLayer->getNextLayer();
361
30.4k
    while ((curLayer != NULL) && (dynamic_cast<TLayer*>(curLayer) == NULL))
362
8.38k
    {
363
8.38k
      curLayer = curLayer->getNextLayer();
364
8.38k
    }
365
366
22.0k
    return dynamic_cast<TLayer*>(curLayer);
367
22.0k
  }
368
369
  template<class TLayer>
370
  TLayer* Packet::getPrevLayerOfType(Layer* curLayer) const
371
0
  {
372
0
    if (curLayer == NULL)
373
0
      return NULL;
374
375
0
    curLayer = curLayer->getPrevLayer();
376
0
    while (curLayer != NULL && dynamic_cast<TLayer*>(curLayer) == NULL)
377
0
    {
378
0
      curLayer = curLayer->getPrevLayer();
379
0
    }
380
381
0
    return dynamic_cast<TLayer*>(curLayer);
382
0
  }
383
384
} // namespace pcpp
385
386
inline std::ostream& operator<<(std::ostream& os, const pcpp::Packet& packet)
387
0
{
388
0
  os << packet.toString();
389
0
  return os;
390
0
}
391
392
#endif /* PACKETPP_PACKET */