1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#ifndef PACKETPP_LAYER
#define PACKETPP_LAYER
#include <stdint.h>
#include <stdio.h>
#include "ProtocolType.h"
#include <string>
/// @file
/**
* \namespace pcpp
* \brief The main namespace for the PcapPlusPlus lib
*/
namespace pcpp
{
/**
* @class IDataContainer
* An interface (virtual abstract class) that indicates an object that holds a pointer to a buffer data. The Layer class is an example
* of such object, hence it inherits this interface
*/
class IDataContainer
{
public:
/**
* Get a pointer to the data
* @param[in] offset Get a pointer in a certain offset. Default is 0 - get a pointer to start of data
* @return A pointer to the data
*/
virtual uint8_t* getDataPtr(size_t offset = 0) const = 0;
virtual ~IDataContainer() {}
};
class Packet;
/**
* @class Layer
* Layer is the base class for all protocol layers. Each protocol supported in PcapPlusPlus has a class that inherits Layer.
* The protocol layer class expose all properties and methods relevant for viewing and editing protocol fields.
* For example: a pointer to a structured header (e.g tcphdr, iphdr, etc.), protocol header size, payload size, compute
* fields that can be automatically computed, print protocol data to string, etc.
* Each protocol instance is obviously part of a protocol stack (which construct a packet). This protocol stack is represented
* in PcapPlusPlus in a linked list, and each layer is an element in this list. That's why each layer has properties to the next and previous
* layer in the protocol stack
* The Layer class, as a base class, is abstract and the user can't create an instance of it (it has a private constructor)
* Each layer holds a pointer to the relevant place in the packet. The layer sees all the data from this pointer forward until the
* end of the packet. Here is an example packet showing this concept:
*
@verbatim
====================================================
|Eth |IPv4 |TCP |Packet |
|Header |Header |Header |Payload |
====================================================
|--------------------------------------------------|
EthLayer data
|---------------------------------------|
IPv4Layer data
|---------------------------|
TcpLayer data
|----------------|
PayloadLayer data
@endverbatim
*
*/
class Layer : public IDataContainer
{
friend class Packet;
public:
/**
* A destructor for this class. Frees the data if it was allocated by the layer constructor (see isAllocatedToPacket() for more info)
*/
virtual ~Layer();
/**
* @return A pointer to the next layer in the protocol stack or NULL if the layer is the last one
*/
Layer* getNextLayer() const { return m_NextLayer; }
/**
* @return A pointer to the previous layer in the protocol stack or NULL if the layer is the first one
*/
Layer* getPrevLayer() const { return m_PrevLayer; }
/**
* @return The protocol enum
*/
ProtocolType getProtocol() const { return m_Protocol; }
/**
* @return A pointer to the layer raw data. In most cases it'll be a pointer to the first byte of the header
*/
uint8_t* getData() const { return m_Data; }
/**
* @return The length in bytes of the data from the first byte of the header until the end of the packet
*/
size_t getDataLen() const { return m_DataLen; }
/**
* @return A pointer for the layer payload, meaning the first byte after the header
*/
uint8_t* getLayerPayload() const { return m_Data + getHeaderLen(); }
/**
* @return The size in bytes of the payload
*/
size_t getLayerPayloadSize() const { return m_DataLen - getHeaderLen(); }
/**
* Raw data in layers can come from one of sources:
* 1. from an existing packet - this is the case when parsing packets received from files or the network. In this case the data was
* already allocated by someone else, and layer only holds the pointer to the relevant place inside this data
* 2. when creating packets, data is allocated when layer is created. In this case the layer is responsible for freeing it as well
*
* @return Returns true if the data was allocated by an external source (a packet) or false if it was allocated by the layer itself
*/
bool isAllocatedToPacket() const { return m_Packet != NULL; }
/**
* Copy the raw data of this layer to another array
* @param[out] toArr The destination byte array
*/
void copyData(uint8_t* toArr) const;
// implement abstract methods
uint8_t* getDataPtr(size_t offset = 0) const { return (uint8_t*)(m_Data + offset); }
// abstract methods
/**
* Each layer is responsible for parsing the next layer
*/
virtual void parseNextLayer() = 0;
/**
* @return The header length in bytes
*/
virtual size_t getHeaderLen() const = 0;
/**
* Each layer can compute field values automatically using this method. This is an abstract method
*/
virtual void computeCalculateFields() = 0;
/**
* @return A string representation of the layer most important data (should look like the layer description in Wireshark)
*/
virtual std::string toString() const = 0;
/**
* @return The OSI Model layer this protocol belongs to
*/
virtual OsiModelLayer getOsiModelLayer() const = 0;
protected:
uint8_t* m_Data;
size_t m_DataLen;
Packet* m_Packet;
ProtocolType m_Protocol;
Layer* m_NextLayer;
Layer* m_PrevLayer;
bool m_IsAllocatedInPacket;
Layer() : m_Data(NULL), m_DataLen(0), m_Packet(NULL), m_Protocol(UnknownProtocol), m_NextLayer(NULL), m_PrevLayer(NULL), m_IsAllocatedInPacket(false) { }
Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet) :
m_Data(data), m_DataLen(dataLen),
m_Packet(packet), m_Protocol(UnknownProtocol),
m_NextLayer(NULL), m_PrevLayer(prevLayer), m_IsAllocatedInPacket(false) {}
// Copy c'tor
Layer(const Layer& other);
Layer& operator=(const Layer& other);
void setNextLayer(Layer* nextLayer) { m_NextLayer = nextLayer; }
void setPrevLayer(Layer* prevLayer) { m_PrevLayer = prevLayer; }
virtual bool extendLayer(int offsetInLayer, size_t numOfBytesToExtend);
virtual bool shortenLayer(int offsetInLayer, size_t numOfBytesToShorten);
};
} // namespace pcpp
inline std::ostream& operator<<(std::ostream& os, const pcpp::Layer &layer)
{
os << layer.toString();
return os;
}
#endif /* PACKETPP_LAYER */