/src/PcapPlusPlus/Packet++/header/IPv6Layer.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include "Layer.h" |
4 | | #include "IPLayer.h" |
5 | | #include "IPv6Extensions.h" |
6 | | #include "IpAddress.h" |
7 | | #include <algorithm> |
8 | | #include <iterator> |
9 | | |
10 | | /// @file |
11 | | |
12 | | /// @namespace pcpp |
13 | | /// @brief The main namespace for the PcapPlusPlus lib |
14 | | namespace pcpp |
15 | | { |
16 | | |
17 | | /// @struct ip6_hdr |
18 | | /// Represents IPv6 protocol header |
19 | | #pragma pack(push, 1) |
20 | | struct ip6_hdr |
21 | | { |
22 | | #if (BYTE_ORDER == LITTLE_ENDIAN) |
23 | | /// Traffic class |
24 | | uint8_t trafficClass : 4, |
25 | | /// IP version number, has the value of 6 for IPv6 |
26 | | ipVersion : 4; |
27 | | #else |
28 | | /// IP version number, has the value of 6 for IPv6 |
29 | | uint8_t ipVersion : 4, |
30 | | /// Traffic class |
31 | | trafficClass : 4; |
32 | | #endif |
33 | | /// Flow label |
34 | | uint8_t flowLabel[3]; |
35 | | /// The size of the payload in octets, including any extension headers |
36 | | uint16_t payloadLength; |
37 | | /// Specifies the type of the next header (protocol). Must be one of ::IPProtocolTypes |
38 | | uint8_t nextHeader; |
39 | | /// Replaces the time to live field of IPv4 |
40 | | uint8_t hopLimit; |
41 | | /// Source address |
42 | | uint8_t ipSrc[16]; |
43 | | /// Destination address |
44 | | uint8_t ipDst[16]; |
45 | | }; |
46 | | #pragma pack(pop) |
47 | | static_assert(sizeof(ip6_hdr) == 40, "ip6_hdr size is not 40 bytes"); |
48 | | |
49 | | /// @class IPv6Layer |
50 | | /// Represents an IPv6 protocol layer |
51 | | class IPv6Layer : public Layer, public IPLayer |
52 | | { |
53 | | public: |
54 | | /// A constructor that creates the layer from an existing packet raw data |
55 | | /// @param[in] data A pointer to the raw data (will be casted to @ref ip6_hdr) |
56 | | /// @param[in] dataLen Size of the data in bytes |
57 | | /// @param[in] prevLayer A pointer to the previous layer |
58 | | /// @param[in] packet A pointer to the Packet instance where layer will be stored in |
59 | | IPv6Layer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet); |
60 | | |
61 | | /// A constructor that allocates a new IPv6 header with empty fields |
62 | | IPv6Layer(); |
63 | | |
64 | | /// A constructor that allocates a new IPv6 header with source and destination IPv6 addresses |
65 | | /// @param[in] srcIP Source IPv6 address |
66 | | /// @param[in] dstIP Destination IPv6 address |
67 | | IPv6Layer(const IPv6Address& srcIP, const IPv6Address& dstIP); |
68 | | |
69 | | /// A copy constructor that copies the entire header from the other IPv6Layer (including IPv6 extensions) |
70 | | IPv6Layer(const IPv6Layer& other); |
71 | | |
72 | | /// A destructor for this layer |
73 | | ~IPv6Layer() override; |
74 | | |
75 | | /// An assignment operator that first delete all data from current layer and then copy the entire header from |
76 | | /// the other IPv6Layer (including IPv6 extensions) |
77 | | IPv6Layer& operator=(const IPv6Layer& other); |
78 | | |
79 | | /// Get a pointer to the IPv6 header. Notice this points directly to the data, so every change will change the |
80 | | /// actual packet data |
81 | | /// @return A pointer to the @ref ip6_hdr |
82 | | ip6_hdr* getIPv6Header() const |
83 | 0 | { |
84 | 0 | return reinterpret_cast<ip6_hdr*>(m_Data); |
85 | 0 | } |
86 | | |
87 | | /// Get the source IP address in the form of IPAddress. This method is very similar to getSrcIPv6Address(), |
88 | | /// but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses |
89 | | /// @return An IPAddress containing the source address |
90 | | IPAddress getSrcIPAddress() const override |
91 | 0 | { |
92 | 0 | return getSrcIPv6Address(); |
93 | 0 | } |
94 | | |
95 | | /// Get the source IP address in the form of IPv6Address |
96 | | /// @return An IPv6Address containing the source address |
97 | | IPv6Address getSrcIPv6Address() const |
98 | 0 | { |
99 | 0 | return getIPv6Header()->ipSrc; |
100 | 0 | } |
101 | | |
102 | | /// Set the source IP address |
103 | | /// @param[in] ipAddr The IP address to set |
104 | | void setSrcIPv6Address(const IPv6Address& ipAddr) |
105 | 0 | { |
106 | 0 | ipAddr.copyTo(getIPv6Header()->ipSrc); |
107 | 0 | } |
108 | | |
109 | | /// Set the dest IP address |
110 | | /// @param[in] ipAddr The IP address to set |
111 | | void setDstIPv6Address(const IPv6Address& ipAddr) |
112 | 0 | { |
113 | 0 | ipAddr.copyTo(getIPv6Header()->ipDst); |
114 | 0 | } |
115 | | |
116 | | /// Get the destination IP address in the form of IPAddress. This method is very similar to getDstIPv6Address(), |
117 | | /// but adds a level of abstraction because IPAddress can be used for both IPv4 and IPv6 addresses |
118 | | /// @return An IPAddress containing the destination address |
119 | | IPAddress getDstIPAddress() const override |
120 | 0 | { |
121 | 0 | return getDstIPv6Address(); |
122 | 0 | } |
123 | | |
124 | | /// Get the destination IP address in the form of IPv6Address |
125 | | /// @return An IPv6Address containing the destination address |
126 | | IPv6Address getDstIPv6Address() const |
127 | 0 | { |
128 | 0 | return getIPv6Header()->ipDst; |
129 | 0 | } |
130 | | |
131 | | /// @return Number of IPv6 extensions in this layer |
132 | | size_t getExtensionCount() const; |
133 | | |
134 | | /// A templated getter for an IPv6 extension of a type TIPv6Extension. TIPv6Extension has to be one of the |
135 | | /// supported IPv6 extensions, meaning a class that inherits IPv6Extension. If the requested extension type |
136 | | /// isn't found nullptr is returned |
137 | | /// @return A pointer to the extension instance or nullptr if the requested extension type isn't found |
138 | | template <class TIPv6Extension> TIPv6Extension* getExtensionOfType() const; |
139 | | |
140 | | /// Add a new extension of type TIPv6Extension to the layer. This is a templated method and TIPv6Extension has |
141 | | /// to be one of the supported IPv6 extensions, meaning a class that inherits IPv6Extension. If the extension is |
142 | | /// added successfully a pointer to the newly added extension object is returned, otherwise nullptr is returned |
143 | | /// @param[in] extensionHeader The extension object to add. Notice the object passed here is read-only, meaning |
144 | | /// its data is copied but the object itself isn't modified |
145 | | /// @return If the extension is added successfully a pointer to the newly added extension object is returned. |
146 | | /// Otherwise nullptr is returned |
147 | | template <class TIPv6Extension> TIPv6Extension* addExtension(const TIPv6Extension& extensionHeader); |
148 | | |
149 | | /// Remove all IPv6 extensions in this layer |
150 | | void removeAllExtensions(); |
151 | | |
152 | | /// @return True if this packet is an IPv6 fragment, meaning if it has an IPv6FragmentationHeader extension |
153 | | bool isFragment() const; |
154 | | |
155 | | /// The static method makes validation of input data |
156 | | /// @param[in] data The pointer to the beginning of byte stream of IP packet |
157 | | /// @param[in] dataLen The length of byte stream |
158 | | /// @return True if the data is valid and can represent the IPv6 packet |
159 | | static inline bool isDataValid(const uint8_t* data, size_t dataLen); |
160 | | |
161 | | // implement abstract methods |
162 | | |
163 | | /// Currently identifies the following next layers: |
164 | | /// - UdpLayer |
165 | | /// - TcpLayer |
166 | | /// - IPv4Layer (IP-in-IP) |
167 | | /// - IPv6Layer (IP-in-IP) |
168 | | /// - GreLayer |
169 | | /// - AuthenticationHeaderLayer (IPSec) |
170 | | /// - ESPLayer (IPSec) |
171 | | /// |
172 | | /// Otherwise sets PayloadLayer |
173 | | void parseNextLayer() override; |
174 | | |
175 | | /// @return Size of @ref ip6_hdr |
176 | | size_t getHeaderLen() const override |
177 | 0 | { |
178 | 0 | return sizeof(ip6_hdr) + m_ExtensionsLen; |
179 | 0 | } |
180 | | |
181 | | /// Calculate the following fields: |
182 | | /// - ip6_hdr#payloadLength = size of payload (all data minus header size) |
183 | | /// - ip6_hdr#ipVersion = 6 |
184 | | /// - ip6_hdr#nextHeader = calculated if next layer is known: ::PACKETPP_IPPROTO_TCP for TCP, |
185 | | /// ::PACKETPP_IPPROTO_UDP for UDP, ::PACKETPP_IPPROTO_ICMP for ICMP |
186 | | void computeCalculateFields() override; |
187 | | |
188 | | std::string toString() const override; |
189 | | |
190 | | OsiModelLayer getOsiModelLayer() const override |
191 | 0 | { |
192 | 0 | return OsiModelNetworkLayer; |
193 | 0 | } |
194 | | |
195 | | /// @struct SerializedFields |
196 | | /// Fields written by IPv6Layer's serializeLayer(), in addition to |
197 | | /// Layer::SerializedFields. |
198 | | struct SerializedFields : Layer::SerializedFields |
199 | | { |
200 | | /// @return All field descriptors for IPv6Layer |
201 | | static std::vector<FieldDescriptor> all() |
202 | 0 | { |
203 | 0 | auto result = Layer::SerializedFields::all(); |
204 | 0 | std::initializer_list<FieldDescriptor> extra{ SrcIp, DstIp, PayloadLength, |
205 | 0 | IsFragment, NextHeader, Extensions }; |
206 | 0 | std::copy(extra.begin(), extra.end(), std::back_inserter(result)); |
207 | 0 | return result; |
208 | 0 | } |
209 | | |
210 | | /// @struct IPv6ExtensionObject |
211 | | /// Fields describing one element of the Extensions array |
212 | | struct IPv6ExtensionObject : ObjectFieldDescriptor<IPv6ExtensionObject> |
213 | | { |
214 | | using ObjectFieldDescriptor::ObjectFieldDescriptor; |
215 | | |
216 | | /// @return All field descriptors for one extension header |
217 | | static std::vector<FieldDescriptor> all() |
218 | 0 | { |
219 | 0 | return { Name, Type }; |
220 | 0 | } |
221 | | |
222 | | /// @brief Extension type name (e.g. "Fragment", "Hop-By-Hop") |
223 | | static const FieldDescriptor Name; |
224 | | |
225 | | /// @brief Raw numeric extension type |
226 | | static const FieldDescriptor Type; |
227 | | }; |
228 | | |
229 | | /// @brief Source IP address, as a string |
230 | | static const FieldDescriptor SrcIp; |
231 | | |
232 | | /// @brief Destination IP address, as a string |
233 | | static const FieldDescriptor DstIp; |
234 | | |
235 | | /// @brief Payload length, in host byte order |
236 | | static const FieldDescriptor PayloadLength; |
237 | | |
238 | | /// @brief Whether this packet is a fragment |
239 | | static const FieldDescriptor IsFragment; |
240 | | |
241 | | /// @brief Next Header field (first extension header, or upper-layer protocol if none) |
242 | | static const FieldDescriptor NextHeader; |
243 | | |
244 | | /// @brief Array of extension headers; elements described by IPv6ExtensionObject |
245 | | static const FieldDescriptor Extensions; |
246 | | }; |
247 | | |
248 | | protected: |
249 | | void serializeLayer(ObjectScope& serializer) const override; |
250 | | |
251 | | private: |
252 | | void initLayer(); |
253 | | void parseExtensions(); |
254 | | void deleteExtensions(); |
255 | | |
256 | | IPv6Extension* m_FirstExtension; |
257 | | IPv6Extension* m_LastExtension; |
258 | | size_t m_ExtensionsLen; |
259 | | }; |
260 | | |
261 | | template <class TIPv6Extension> TIPv6Extension* IPv6Layer::getExtensionOfType() const |
262 | 0 | { |
263 | 0 | IPv6Extension* curExt = m_FirstExtension; |
264 | 0 | while (curExt != nullptr && dynamic_cast<TIPv6Extension*>(curExt) == nullptr) |
265 | 0 | curExt = curExt->getNextHeader(); |
266 | |
|
267 | 0 | return static_cast<TIPv6Extension*>(curExt); |
268 | 0 | } |
269 | | |
270 | | template <class TIPv6Extension> TIPv6Extension* IPv6Layer::addExtension(const TIPv6Extension& extensionHeader) |
271 | | { |
272 | | int offsetToAddHeader = static_cast<int>(getHeaderLen()); |
273 | | if (!extendLayer(offsetToAddHeader, extensionHeader.getExtensionLen())) |
274 | | { |
275 | | return nullptr; |
276 | | } |
277 | | |
278 | | TIPv6Extension* newHeader = new TIPv6Extension(this, static_cast<size_t>(offsetToAddHeader)); |
279 | | (*newHeader) = extensionHeader; |
280 | | |
281 | | if (m_FirstExtension != nullptr) |
282 | | { |
283 | | newHeader->getBaseHeader()->nextHeader = m_LastExtension->getBaseHeader()->nextHeader; |
284 | | m_LastExtension->getBaseHeader()->nextHeader = newHeader->getExtensionType(); |
285 | | m_LastExtension->setNextHeader(newHeader); |
286 | | m_LastExtension = newHeader; |
287 | | } |
288 | | else |
289 | | { |
290 | | m_FirstExtension = newHeader; |
291 | | m_LastExtension = newHeader; |
292 | | newHeader->getBaseHeader()->nextHeader = getIPv6Header()->nextHeader; |
293 | | getIPv6Header()->nextHeader = newHeader->getExtensionType(); |
294 | | } |
295 | | |
296 | | m_ExtensionsLen += newHeader->getExtensionLen(); |
297 | | |
298 | | return newHeader; |
299 | | } |
300 | | |
301 | | // implementation of inline methods |
302 | | |
303 | | bool IPv6Layer::isDataValid(const uint8_t* data, size_t dataLen) |
304 | 0 | { |
305 | 0 | auto ip6Header = reinterpret_cast<const ip6_hdr*>(data); |
306 | 0 | return canReinterpretAs<ip6_hdr>(data, dataLen) && ip6Header->ipVersion == 6; |
307 | 0 | } |
308 | | |
309 | | } // namespace pcpp |