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