Coverage Report

Created: 2024-02-25 06:29

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