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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#ifndef PACKETPP_IPV6_LAYER
#define PACKETPP_IPV6_LAYER
#include "Layer.h"
#include "IPLayer.h"
#include "IPv6Extensions.h"
#include "IpAddress.h"
/// @file
/**
* \namespace pcpp
* \brief The main namespace for the PcapPlusPlus lib
*/
namespace pcpp
{
/**
* @struct ip6_hdr
* Represents IPv6 protocol header
*/
#pragma pack(push, 1)
struct ip6_hdr
{
#if (BYTE_ORDER == LITTLE_ENDIAN)
/** Traffic class */
uint8_t trafficClass:4,
/** IP version number, has the value of 6 for IPv6 */
ipVersion:4;
#else
/** IP version number, has the value of 6 for IPv6 */
uint8_t ipVersion:4,
/** Traffic class */
trafficClass:4;
#endif
/** Flow label */
uint8_t flowLabel[3];
/** The size of the payload in octets, including any extension headers */
uint16_t payloadLength;
/** Specifies the type of the next header (protocol). Must be one of ::IPProtocolTypes */
uint8_t nextHeader;
/** Replaces the time to live field of IPv4 */
uint8_t hopLimit;
/** Source address */
uint8_t ipSrc[16];
/** Destination address */
uint8_t ipDst[16];
};
#pragma pack(pop)
/**
* @class IPv6Layer
* Represents an IPv6 protocol layer
*/
class IPv6Layer : public Layer, public IPLayer
{
public:
/**
* A constructor that creates the layer from an existing packet raw data
* @param[in] data A pointer to the raw data (will be casted to @ref ip6_hdr)
* @param[in] dataLen Size of the data in bytes
* @param[in] prevLayer A pointer to the previous layer
* @param[in] packet A pointer to the Packet instance where layer will be stored in
*/
IPv6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
/**
* A constructor that allocates a new IPv6 header with empty fields
*/
IPv6Layer();
/**
* A constructor that allocates a new IPv6 header with source and destination IPv6 addresses
* @param[in] srcIP Source IPv6 address
* @param[in] dstIP Destination IPv6 address
*/
IPv6Layer(const IPv6Address& srcIP, const IPv6Address& dstIP);
/**
* A copy constructor that copies the entire header from the other IPv6Layer (including IPv6 extensions)
*/
IPv6Layer(const IPv6Layer& other);
/**
* A destructor for this layer
*/
~IPv6Layer();
/**
* An assignment operator that first delete all data from current layer and then copy the entire header from the other IPv6Layer (including IPv6 extensions)
*/
IPv6Layer& operator=(const IPv6Layer& other);
/**
* Get a pointer to the IPv6 header. Notice this points directly to the data, so every change will change the actual packet data
* @return A pointer to the @ref ip6_hdr
*/
ip6_hdr* getIPv6Header() const { return (ip6_hdr*)m_Data; }
/**
* Get the source IP address in the form of IPAddress. This method is very similar to getSrcIPv6Address(),
* but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses
* @return An IPAddress containing the source address
*/
IPAddress getSrcIPAddress() const { return getSrcIPv6Address(); }
/**
* Get the source IP address in the form of IPv6Address
* @return An IPv6Address containing the source address
*/
IPv6Address getSrcIPv6Address() const { return getIPv6Header()->ipSrc; }
/**
* Set the source IP address
* @param[in] ipAddr The IP address to set
*/
void setSrcIPv6Address(const IPv6Address& ipAddr) { ipAddr.copyTo(getIPv6Header()->ipSrc); }
/**
* Set the dest IP address
* @param[in] ipAddr The IP address to set
*/
void setDstIPv6Address(const IPv6Address& ipAddr) { ipAddr.copyTo(getIPv6Header()->ipDst); }
/**
* Get the destination IP address in the form of IPAddress. This method is very similar to getDstIPv6Address(),
* but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses
* @return An IPAddress containing the destination address
*/
IPAddress getDstIPAddress() const { return getDstIPv6Address(); }
/**
* Get the destination IP address in the form of IPv6Address
* @return An IPv6Address containing the destination address
*/
IPv6Address getDstIPv6Address() const { return getIPv6Header()->ipDst; }
/**
* @return Number of IPv6 extensions in this layer
*/
size_t getExtensionCount() const;
/**
* A templated getter for an IPv6 extension of a type TIPv6Extension. TIPv6Extension has to be one of the supported IPv6 extensions,
* meaning a class that inherits IPv6Extension. If the requested extension type isn't found NULL is returned
* @return A pointer to the extension instance or NULL if the requested extension type isn't found
*/
template<class TIPv6Extension>
TIPv6Extension* getExtensionOfType() const;
/**
* Add a new extension of type TIPv6Extension to the layer. This is a templated method and TIPv6Extension has to be one of
* the supported IPv6 extensions, meaning a class that inherits IPv6Extension. If the extension is added successfully a pointer
* to the newly added extension object is returned, otherwise NULL is returned
* @param[in] extensionHeader The extension object to add. Notice the object passed here is read-only, meaning its data is copied
* but the object itself isn't modified
* @return If the extension is added successfully a pointer to the newly added extension object is returned. Otherwise NULL is
* returned
*/
template<class TIPv6Extension>
TIPv6Extension* addExtension(const TIPv6Extension& extensionHeader);
/**
* Remove all IPv6 extensions in this layer
*/
void removeAllExtensions();
/**
* @return True if this packet is an IPv6 fragment, meaning if it has an IPv6FragmentationHeader extension
*/
bool isFragment() const;
/**
* The static method makes validation of input data
* @param[in] data The pointer to the beginning of byte stream of IP packet
* @param[in] dataLen The length of byte stream
* @return True if the data is valid and can represent the IPv6 packet
*/
static inline bool isDataValid(const uint8_t* data, size_t dataLen);
// implement abstract methods
/**
* Currently identifies the following next layers:
* - UdpLayer
* - TcpLayer
* - IPv4Layer (IP-in-IP)
* - IPv6Layer (IP-in-IP)
* - GreLayer
* - AuthenticationHeaderLayer (IPSec)
* - ESPLayer (IPSec)
*
* Otherwise sets PayloadLayer
*/
void parseNextLayer();
/**
* @return Size of @ref ip6_hdr
*/
size_t getHeaderLen() const { return sizeof(ip6_hdr) + m_ExtensionsLen; }
/**
* Calculate the following fields:
* - ip6_hdr#payloadLength = size of payload (all data minus header size)
* - ip6_hdr#ipVersion = 6
* - ip6_hdr#nextHeader = calculated if next layer is known: ::PACKETPP_IPPROTO_TCP for TCP, ::PACKETPP_IPPROTO_UDP for UDP, ::PACKETPP_IPPROTO_ICMP for ICMP
*/
void computeCalculateFields();
std::string toString() const;
OsiModelLayer getOsiModelLayer() const { return OsiModelNetworkLayer; }
private:
void initLayer();
void parseExtensions();
void deleteExtensions();
IPv6Extension* m_FirstExtension;
IPv6Extension* m_LastExtension;
size_t m_ExtensionsLen;
};
template<class TIPv6Extension>
TIPv6Extension* IPv6Layer::getExtensionOfType() const
{
IPv6Extension* curExt = m_FirstExtension;
while (curExt != NULL && dynamic_cast<TIPv6Extension*>(curExt) == NULL)
curExt = curExt->getNextHeader();
return (TIPv6Extension*)curExt;
}
template<class TIPv6Extension>
TIPv6Extension* IPv6Layer::addExtension(const TIPv6Extension& extensionHeader)
{
int offsetToAddHeader = (int)getHeaderLen();
if (!extendLayer(offsetToAddHeader, extensionHeader.getExtensionLen()))
{
return NULL;
}
TIPv6Extension* newHeader = new TIPv6Extension(this, (size_t)offsetToAddHeader);
(*newHeader) = extensionHeader;
if (m_FirstExtension != NULL)
{
newHeader->getBaseHeader()->nextHeader = m_LastExtension->getBaseHeader()->nextHeader;
m_LastExtension->getBaseHeader()->nextHeader = newHeader->getExtensionType();
m_LastExtension->setNextHeader(newHeader);
m_LastExtension = newHeader;
}
else
{
m_FirstExtension = newHeader;
m_LastExtension = newHeader;
newHeader->getBaseHeader()->nextHeader = getIPv6Header()->nextHeader;
getIPv6Header()->nextHeader = newHeader->getExtensionType();
}
m_ExtensionsLen += newHeader->getExtensionLen();
return newHeader;
}
// implementation of inline methods
bool IPv6Layer::isDataValid(const uint8_t* data, size_t dataLen)
{
return data && dataLen >= sizeof(ip6_hdr);
}
} // namespace pcpp
#endif /* PACKETPP_IPV6_LAYER */