/src/PcapPlusPlus/Common++/src/IpAddress.cpp
Line | Count | Source |
1 | 0 | #define LOG_MODULE CommonLogModuleIpUtils |
2 | | |
3 | | #include <algorithm> |
4 | | #include <sstream> |
5 | | #include <stdexcept> |
6 | | #include <bitset> |
7 | | #include "Logger.h" |
8 | | #include "IpUtils.h" |
9 | | #include "IpAddress.h" |
10 | | #include "EndianPortable.h" |
11 | | |
12 | | // for AF_INET, AF_INET6 |
13 | | #if !defined(_WIN32) |
14 | | # include <sys/socket.h> |
15 | | #endif |
16 | | |
17 | | namespace pcpp |
18 | | { |
19 | | |
20 | | const IPv4Address IPv4Address::Zero; |
21 | | const IPv6Address IPv6Address::Zero; |
22 | | |
23 | | const IPv4Address IPv4Address::MulticastRangeLowerBound("224.0.0.0"); |
24 | | const IPv4Address IPv4Address::MulticastRangeUpperBound("239.255.255.255"); |
25 | | const IPv6Address IPv6Address::MulticastRangeLowerBound("ff00:0000:0000:0000:0000:0000:0000:0000"); |
26 | | |
27 | | // ~~~~~~~~~~~ |
28 | | // IPv4Address |
29 | | // ~~~~~~~~~~~ |
30 | | |
31 | | std::string IPv4Address::toString() const |
32 | 0 | { |
33 | 0 | char addrBuffer[INET_ADDRSTRLEN]; |
34 | |
|
35 | 0 | if (inet_ntop(AF_INET, toBytes(), addrBuffer, sizeof(addrBuffer)) != nullptr) |
36 | 0 | { |
37 | 0 | return addrBuffer; |
38 | 0 | } |
39 | | |
40 | 0 | return {}; |
41 | 0 | } |
42 | | |
43 | | bool IPv4Address::isMulticast() const |
44 | 0 | { |
45 | 0 | return !operator<(MulticastRangeLowerBound) && |
46 | 0 | (operator<(MulticastRangeUpperBound) || operator==(MulticastRangeUpperBound)); |
47 | 0 | } |
48 | | |
49 | | IPv4Address::IPv4Address(const uint8_t* bytes, size_t size) |
50 | 0 | { |
51 | 0 | if (bytes == nullptr) |
52 | 0 | { |
53 | 0 | throw std::invalid_argument("Buffer pointer is null"); |
54 | 0 | } |
55 | | |
56 | 0 | if (size < 4) |
57 | 0 | { |
58 | 0 | throw std::out_of_range("Buffer size is smaller than IPv4 address size"); |
59 | 0 | } |
60 | 0 | memcpy(m_Bytes.data(), bytes, 4 * sizeof(uint8_t)); |
61 | 0 | } |
62 | | |
63 | | IPv4Address::IPv4Address(const std::string& addrAsString) |
64 | 4 | { |
65 | 4 | if (inet_pton(AF_INET, addrAsString.data(), m_Bytes.data()) <= 0) |
66 | 0 | { |
67 | 0 | throw std::invalid_argument("Not a valid IPv4 address: " + addrAsString); |
68 | 0 | } |
69 | 4 | } |
70 | | |
71 | | bool IPv4Address::matchNetwork(const IPv4Network& network) const |
72 | 0 | { |
73 | 0 | return network.includes(*this); |
74 | 0 | } |
75 | | |
76 | | bool IPv4Address::matchNetwork(const std::string& network) const |
77 | 0 | { |
78 | 0 | try |
79 | 0 | { |
80 | 0 | auto ipv4Network = IPv4Network(network); |
81 | 0 | return ipv4Network.includes(*this); |
82 | 0 | } |
83 | 0 | catch (const std::invalid_argument& e) |
84 | 0 | { |
85 | 0 | (void)e; // Suppress the unreferenced local variable warning when PCPP_LOG_ERROR is disabled |
86 | 0 | PCPP_LOG_ERROR(e.what()); |
87 | 0 | return false; |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | | bool IPv4Address::isValidIPv4Address(const std::string& addrAsString) |
92 | 0 | { |
93 | 0 | sockaddr_in sa_in{}; |
94 | 0 | return inet_pton(AF_INET, addrAsString.data(), &(sa_in.sin_addr)) > 0; |
95 | 0 | } |
96 | | |
97 | | // ~~~~~~~~~~~ |
98 | | // IPv6Address |
99 | | // ~~~~~~~~~~~ |
100 | | |
101 | | std::string IPv6Address::toString() const |
102 | 0 | { |
103 | 0 | char addrBuffer[INET6_ADDRSTRLEN]; |
104 | |
|
105 | 0 | if (inet_ntop(AF_INET6, toBytes(), addrBuffer, sizeof(addrBuffer)) != nullptr) |
106 | 0 | { |
107 | 0 | return addrBuffer; |
108 | 0 | } |
109 | | |
110 | 0 | return {}; |
111 | 0 | } |
112 | | |
113 | | bool IPv6Address::isMulticast() const |
114 | 0 | { |
115 | 0 | return !operator<(MulticastRangeLowerBound); |
116 | 0 | } |
117 | | |
118 | | IPv6Address::IPv6Address(const uint8_t* bytes, size_t size) |
119 | 0 | { |
120 | 0 | if (bytes == nullptr) |
121 | 0 | { |
122 | 0 | throw std::invalid_argument("Buffer pointer is null"); |
123 | 0 | } |
124 | | |
125 | 0 | if (size < 16) |
126 | 0 | { |
127 | 0 | throw std::out_of_range("Buffer size is smaller than IPv6 address size"); |
128 | 0 | } |
129 | 0 | std::memcpy(m_Bytes.data(), bytes, 16 * sizeof(uint8_t)); |
130 | 0 | } |
131 | | |
132 | | IPv6Address::IPv6Address(const std::string& addrAsString) |
133 | 2 | { |
134 | 2 | if (inet_pton(AF_INET6, addrAsString.data(), m_Bytes.data()) <= 0) |
135 | 0 | { |
136 | 0 | throw std::invalid_argument("Not a valid IPv6 address: " + addrAsString); |
137 | 0 | } |
138 | 2 | } |
139 | | |
140 | | void IPv6Address::copyTo(uint8_t** arr, size_t& length) const |
141 | 0 | { |
142 | 0 | const size_t addrLen = m_Bytes.size() * sizeof(uint8_t); |
143 | 0 | length = addrLen; |
144 | | // cppcheck-suppress ctunullpointer |
145 | 0 | *arr = new uint8_t[addrLen]; |
146 | 0 | memcpy(*arr, m_Bytes.data(), addrLen); |
147 | 0 | } |
148 | | |
149 | | size_t IPv6Address::copyTo(uint8_t* buffer, size_t size) const |
150 | 0 | { |
151 | 0 | const size_t requiredSize = m_Bytes.size(); |
152 | |
|
153 | 0 | if (buffer == nullptr) |
154 | 0 | { |
155 | 0 | if (size != 0) |
156 | 0 | { |
157 | 0 | throw std::invalid_argument("Buffer is null but size is not zero"); |
158 | 0 | } |
159 | | |
160 | 0 | return requiredSize; |
161 | 0 | } |
162 | | |
163 | 0 | if (size < requiredSize) |
164 | 0 | { |
165 | 0 | return requiredSize; |
166 | 0 | } |
167 | | |
168 | 0 | std::memcpy(buffer, m_Bytes.data(), requiredSize); |
169 | 0 | return requiredSize; |
170 | 0 | } |
171 | | |
172 | | bool IPv6Address::copyToNewBuffer(uint8_t** buffer, size_t& size) const |
173 | 0 | { |
174 | 0 | if (buffer == nullptr) |
175 | 0 | { |
176 | 0 | throw std::invalid_argument("Buffer pointer is null"); |
177 | 0 | } |
178 | | |
179 | 0 | size = copyTo(nullptr, 0); |
180 | 0 | *buffer = new uint8_t[size]; |
181 | 0 | if (copyTo(*buffer, size) != size) |
182 | 0 | { |
183 | 0 | delete[] *buffer; |
184 | 0 | *buffer = nullptr; |
185 | 0 | size = 0; |
186 | 0 | return false; |
187 | 0 | } |
188 | | |
189 | 0 | return true; |
190 | 0 | } |
191 | | |
192 | | bool IPv6Address::matchNetwork(const IPv6Network& network) const |
193 | 0 | { |
194 | 0 | return network.includes(*this); |
195 | 0 | } |
196 | | |
197 | | bool IPv6Address::matchNetwork(const std::string& network) const |
198 | 0 | { |
199 | 0 | try |
200 | 0 | { |
201 | 0 | auto ipv6Network = IPv6Network(network); |
202 | 0 | return ipv6Network.includes(*this); |
203 | 0 | } |
204 | 0 | catch (const std::invalid_argument& e) |
205 | 0 | { |
206 | 0 | (void)e; // Suppress the unreferenced local variable warning when PCPP_LOG_ERROR is disabled |
207 | 0 | PCPP_LOG_ERROR(e.what()); |
208 | 0 | return false; |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | bool IPv6Address::isValidIPv6Address(const std::string& addrAsString) |
213 | 0 | { |
214 | 0 | sockaddr_in6 sa_in6{}; |
215 | 0 | return inet_pton(AF_INET6, addrAsString.data(), &(sa_in6.sin6_addr)) > 0; |
216 | 0 | } |
217 | | |
218 | | // ~~~~~~~~~ |
219 | | // IPAddress |
220 | | // ~~~~~~~~~ |
221 | | |
222 | | IPAddress::IPAddress(const std::string& addrAsString) |
223 | 0 | { |
224 | 0 | if (IPv4Address::isValidIPv4Address(addrAsString)) |
225 | 0 | { |
226 | 0 | m_Type = IPv4AddressType; |
227 | 0 | m_IPv4 = IPv4Address(addrAsString); |
228 | 0 | } |
229 | 0 | else if (IPv6Address::isValidIPv6Address(addrAsString)) |
230 | 0 | { |
231 | 0 | m_Type = IPv6AddressType; |
232 | 0 | m_IPv6 = IPv6Address(addrAsString); |
233 | 0 | } |
234 | 0 | else |
235 | 0 | { |
236 | 0 | throw std::invalid_argument("Not a valid IP address: " + addrAsString); |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | | // ~~~~~~~~~~~ |
241 | | // IPv4Network |
242 | | // ~~~~~~~~~~~ |
243 | | |
244 | | bool IPv4Network::isValidNetmask(const IPv4Address& maskAddress) |
245 | 0 | { |
246 | 0 | if (maskAddress == IPv4Address::Zero) |
247 | 0 | { |
248 | 0 | return true; |
249 | 0 | } |
250 | | |
251 | 0 | const uint32_t maskAsInt = be32toh(maskAddress.toInt()); |
252 | 0 | const std::bitset<32> bitset(maskAsInt); |
253 | 0 | auto bitsetCount = bitset.count(); |
254 | |
|
255 | 0 | if (bitsetCount == 32) |
256 | 0 | { |
257 | 0 | return true; |
258 | 0 | } |
259 | | |
260 | 0 | return maskAsInt << bitsetCount == 0; |
261 | 0 | } |
262 | | |
263 | | void IPv4Network::initFromAddressAndPrefixLength(const IPv4Address& address, uint8_t prefixLen) |
264 | 0 | { |
265 | 0 | m_Mask = be32toh(0xffff'ffff ^ (prefixLen < 32 ? 0xffff'ffff >> prefixLen : 0)); |
266 | 0 | m_NetworkPrefix = address.toInt() & m_Mask; |
267 | 0 | } |
268 | | |
269 | | void IPv4Network::initFromAddressAndNetmask(const IPv4Address& address, const IPv4Address& netmaskAddress) |
270 | 0 | { |
271 | 0 | m_Mask = netmaskAddress.toInt(); |
272 | 0 | m_NetworkPrefix = address.toInt() & m_Mask; |
273 | 0 | } |
274 | | |
275 | | IPv4Network::IPv4Network(const IPv4Address& address, uint8_t prefixLen) |
276 | 0 | { |
277 | 0 | if (prefixLen > 32) |
278 | 0 | { |
279 | 0 | throw std::invalid_argument("prefixLen must be an integer between 0 and 32"); |
280 | 0 | } |
281 | | |
282 | 0 | initFromAddressAndPrefixLength(address, prefixLen); |
283 | 0 | } |
284 | | |
285 | | IPv4Network::IPv4Network(const IPv4Address& address, const std::string& netmask) |
286 | 0 | { |
287 | 0 | IPv4Address netmaskAddr; |
288 | 0 | try |
289 | 0 | { |
290 | 0 | netmaskAddr = IPv4Address(netmask); |
291 | 0 | } |
292 | 0 | catch (const std::exception&) |
293 | 0 | { |
294 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmask); |
295 | 0 | } |
296 | 0 | if (!isValidNetmask(netmaskAddr)) |
297 | 0 | { |
298 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmask); |
299 | 0 | } |
300 | 0 | initFromAddressAndNetmask(address, netmaskAddr); |
301 | 0 | } |
302 | | |
303 | | IPv4Network::IPv4Network(const std::string& addressAndNetmask) |
304 | 0 | { |
305 | 0 | std::stringstream stream(addressAndNetmask); |
306 | 0 | std::string networkPrefixStr; |
307 | 0 | std::string netmaskStr; |
308 | 0 | std::getline(stream, networkPrefixStr, '/'); |
309 | 0 | std::getline(stream, netmaskStr); |
310 | |
|
311 | 0 | if (netmaskStr.empty()) |
312 | 0 | { |
313 | 0 | throw std::invalid_argument( |
314 | 0 | "The input should be in the format of <address>/<netmask> or <address>/<prefixLength>"); |
315 | 0 | } |
316 | | |
317 | 0 | IPv4Address networkPrefix; |
318 | 0 | try |
319 | 0 | { |
320 | 0 | networkPrefix = IPv4Address(networkPrefixStr); |
321 | 0 | } |
322 | 0 | catch (const std::invalid_argument&) |
323 | 0 | { |
324 | 0 | throw std::invalid_argument("The input doesn't contain a valid IPv4 network prefix: " + networkPrefixStr); |
325 | 0 | } |
326 | | |
327 | 0 | if (std::all_of(netmaskStr.begin(), netmaskStr.end(), ::isdigit)) |
328 | 0 | { |
329 | 0 | const uint32_t prefixLen = std::stoi(netmaskStr); |
330 | 0 | if (prefixLen > 32) |
331 | 0 | { |
332 | 0 | throw std::invalid_argument("Prefix length must be an integer between 0 and 32"); |
333 | 0 | } |
334 | | |
335 | 0 | initFromAddressAndPrefixLength(networkPrefix, prefixLen); |
336 | 0 | } |
337 | 0 | else |
338 | 0 | { |
339 | 0 | IPv4Address netmaskAddr; |
340 | 0 | try |
341 | 0 | { |
342 | 0 | netmaskAddr = IPv4Address(netmaskStr); |
343 | 0 | } |
344 | 0 | catch (const std::invalid_argument&) |
345 | 0 | { |
346 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmaskStr); |
347 | 0 | } |
348 | 0 | if (!isValidNetmask(netmaskAddr)) |
349 | 0 | { |
350 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmaskStr); |
351 | 0 | } |
352 | 0 | initFromAddressAndNetmask(networkPrefix, netmaskAddr); |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | | uint8_t IPv4Network::getPrefixLen() const |
357 | 0 | { |
358 | 0 | const std::bitset<32> bitset(m_Mask); |
359 | 0 | return bitset.count(); |
360 | 0 | } |
361 | | |
362 | | IPv4Address IPv4Network::getLowestAddress() const |
363 | 0 | { |
364 | 0 | const std::bitset<32> bitset(m_Mask); |
365 | 0 | return bitset.count() < 32 ? m_NetworkPrefix + htobe32(1) : m_NetworkPrefix; |
366 | 0 | } |
367 | | |
368 | | IPv4Address IPv4Network::getHighestAddress() const |
369 | 0 | { |
370 | 0 | auto tempAddress = static_cast<uint32_t>(m_NetworkPrefix | ~m_Mask); |
371 | 0 | const std::bitset<32> bitset(m_Mask); |
372 | 0 | return bitset.count() < 32 ? tempAddress - htobe32(1) : tempAddress; |
373 | 0 | } |
374 | | |
375 | | uint64_t IPv4Network::getTotalAddressCount() const |
376 | 0 | { |
377 | 0 | const std::bitset<32> bitset(~static_cast<uint64_t>(m_Mask)); |
378 | 0 | return 1ULL << bitset.count(); |
379 | 0 | } |
380 | | |
381 | | bool IPv4Network::includes(const IPv4Address& address) const |
382 | 0 | { |
383 | 0 | return (address.toInt() & m_Mask) == m_NetworkPrefix; |
384 | 0 | } |
385 | | |
386 | | bool IPv4Network::includes(const IPv4Network& network) const |
387 | 0 | { |
388 | 0 | const uint32_t lowestAddress = network.m_NetworkPrefix; |
389 | 0 | const uint32_t highestAddress = network.m_NetworkPrefix | ~network.m_Mask; |
390 | 0 | return ((lowestAddress & m_Mask) == m_NetworkPrefix && (highestAddress & m_Mask) == m_NetworkPrefix); |
391 | 0 | } |
392 | | |
393 | | std::string IPv4Network::toString() const |
394 | 0 | { |
395 | 0 | std::ostringstream stream; |
396 | 0 | stream << getNetworkPrefix() << "/" << static_cast<int>(getPrefixLen()); |
397 | 0 | return stream.str(); |
398 | 0 | } |
399 | | |
400 | | // ~~~~~~~~~~~ |
401 | | // IPv6Network |
402 | | // ~~~~~~~~~~~ |
403 | | |
404 | 0 | #define IPV6_ADDR_SIZE 16 |
405 | | |
406 | | bool IPv6Network::isValidNetmask(const IPv6Address& netmask) |
407 | 0 | { |
408 | 0 | if (netmask == IPv6Address::Zero) |
409 | 0 | { |
410 | 0 | return true; |
411 | 0 | } |
412 | | |
413 | 0 | const uint8_t* addressAsBytes = netmask.toBytes(); |
414 | 0 | int expectingValue = 1; |
415 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
416 | 0 | { |
417 | 0 | auto curByte = addressAsBytes[byteIndex]; |
418 | 0 | if (expectingValue == 1) |
419 | 0 | { |
420 | 0 | if (curByte == 0xff) |
421 | 0 | { |
422 | 0 | continue; |
423 | 0 | } |
424 | 0 | const std::bitset<8> bitset(curByte); |
425 | 0 | if (((curByte << bitset.count()) & 0xff) != 0) |
426 | 0 | { |
427 | 0 | return false; |
428 | 0 | } |
429 | 0 | expectingValue = 0; |
430 | 0 | } |
431 | 0 | else if (expectingValue == 0 && curByte != 0) |
432 | 0 | { |
433 | 0 | return false; |
434 | 0 | } |
435 | 0 | } |
436 | | |
437 | 0 | return true; |
438 | 0 | } |
439 | | |
440 | | void IPv6Network::initFromAddressAndPrefixLength(const IPv6Address& address, uint8_t prefixLen) |
441 | 0 | { |
442 | 0 | memset(m_Mask, 0, IPV6_ADDR_SIZE); |
443 | 0 | int remainingPrefixLen = prefixLen; |
444 | 0 | for (auto& byte : m_Mask) |
445 | 0 | { |
446 | 0 | if (remainingPrefixLen >= 8) |
447 | 0 | { |
448 | 0 | byte = 0xff; |
449 | 0 | } |
450 | 0 | else if (remainingPrefixLen > 0) |
451 | 0 | { |
452 | 0 | byte = 0xff << (8 - remainingPrefixLen); |
453 | 0 | } |
454 | 0 | else |
455 | 0 | { |
456 | 0 | break; |
457 | 0 | } |
458 | | |
459 | 0 | remainingPrefixLen -= 8; |
460 | 0 | } |
461 | |
|
462 | 0 | address.copyTo(m_NetworkPrefix); |
463 | |
|
464 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
465 | 0 | { |
466 | 0 | m_NetworkPrefix[byteIndex] &= m_Mask[byteIndex]; |
467 | 0 | } |
468 | 0 | } |
469 | | |
470 | | void IPv6Network::initFromAddressAndNetmask(const IPv6Address& address, const IPv6Address& netmaskAddr) |
471 | 0 | { |
472 | 0 | netmaskAddr.copyTo(m_Mask); |
473 | |
|
474 | 0 | address.copyTo(m_NetworkPrefix); |
475 | |
|
476 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
477 | 0 | { |
478 | 0 | m_NetworkPrefix[byteIndex] &= m_Mask[byteIndex]; |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | IPv6Network::IPv6Network(const IPv6Address& address, uint8_t prefixLen) |
483 | 0 | { |
484 | 0 | if (prefixLen > 128) |
485 | 0 | { |
486 | 0 | throw std::invalid_argument("prefixLen must be an integer between 0 and 128"); |
487 | 0 | } |
488 | | |
489 | 0 | initFromAddressAndPrefixLength(address, prefixLen); |
490 | 0 | } |
491 | | |
492 | | IPv6Network::IPv6Network(const IPv6Address& address, const std::string& netmask) |
493 | 0 | { |
494 | 0 | IPv6Address netmaskAddr; |
495 | 0 | try |
496 | 0 | { |
497 | 0 | netmaskAddr = IPv6Address(netmask); |
498 | 0 | } |
499 | 0 | catch (const std::exception&) |
500 | 0 | { |
501 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmask); |
502 | 0 | } |
503 | 0 | if (!isValidNetmask(netmaskAddr)) |
504 | 0 | { |
505 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmask); |
506 | 0 | } |
507 | 0 | initFromAddressAndNetmask(address, netmaskAddr); |
508 | 0 | } |
509 | | |
510 | | IPv6Network::IPv6Network(const std::string& addressAndNetmask) |
511 | 0 | { |
512 | 0 | std::stringstream stream(addressAndNetmask); |
513 | 0 | std::string networkPrefixStr; |
514 | 0 | std::string netmaskStr; |
515 | 0 | std::getline(stream, networkPrefixStr, '/'); |
516 | 0 | std::getline(stream, netmaskStr); |
517 | |
|
518 | 0 | if (netmaskStr.empty()) |
519 | 0 | { |
520 | 0 | throw std::invalid_argument( |
521 | 0 | "The input should be in the format of <address>/<netmask> or <address>/<prefixLength>"); |
522 | 0 | } |
523 | | |
524 | 0 | IPv6Address networkPrefix; |
525 | 0 | try |
526 | 0 | { |
527 | 0 | networkPrefix = IPv6Address(networkPrefixStr); |
528 | 0 | } |
529 | 0 | catch (const std::invalid_argument&) |
530 | 0 | { |
531 | 0 | throw std::invalid_argument("The input doesn't contain a valid IPv6 network prefix: " + networkPrefixStr); |
532 | 0 | } |
533 | 0 | if (std::all_of(netmaskStr.begin(), netmaskStr.end(), ::isdigit)) |
534 | 0 | { |
535 | 0 | const uint32_t prefixLen = std::stoi(netmaskStr); |
536 | 0 | if (prefixLen > 128) |
537 | 0 | { |
538 | 0 | throw std::invalid_argument("Prefix length must be an integer between 0 and 128"); |
539 | 0 | } |
540 | | |
541 | 0 | initFromAddressAndPrefixLength(networkPrefix, prefixLen); |
542 | 0 | } |
543 | 0 | else |
544 | 0 | { |
545 | 0 | IPv6Address netmaskAddr; |
546 | 0 | try |
547 | 0 | { |
548 | 0 | netmaskAddr = IPv6Address(netmaskStr); |
549 | 0 | } |
550 | 0 | catch (const std::exception&) |
551 | 0 | { |
552 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmaskStr); |
553 | 0 | } |
554 | 0 | if (!isValidNetmask(netmaskAddr)) |
555 | 0 | { |
556 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmaskStr); |
557 | 0 | } |
558 | 0 | initFromAddressAndNetmask(networkPrefix, netmaskAddr); |
559 | 0 | } |
560 | 0 | } |
561 | | |
562 | | uint8_t IPv6Network::getPrefixLen() const |
563 | 0 | { |
564 | 0 | uint8_t result = 0; |
565 | 0 | for (const auto& byte : m_Mask) |
566 | 0 | { |
567 | 0 | const std::bitset<8> bset(byte); |
568 | 0 | result += static_cast<uint8_t>(bset.count()); |
569 | 0 | } |
570 | 0 | return result; |
571 | 0 | } |
572 | | |
573 | | IPv6Address IPv6Network::getLowestAddress() const |
574 | 0 | { |
575 | 0 | if (getPrefixLen() == 128) |
576 | 0 | { |
577 | 0 | return m_NetworkPrefix; |
578 | 0 | } |
579 | | |
580 | 0 | uint8_t lowestAddress[IPV6_ADDR_SIZE]; |
581 | 0 | memcpy(lowestAddress, m_NetworkPrefix, IPV6_ADDR_SIZE); |
582 | 0 | lowestAddress[IPV6_ADDR_SIZE - 1]++; |
583 | 0 | return lowestAddress; |
584 | 0 | } |
585 | | |
586 | | IPv6Address IPv6Network::getHighestAddress() const |
587 | 0 | { |
588 | 0 | uint8_t result[IPV6_ADDR_SIZE]; |
589 | |
|
590 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
591 | 0 | { |
592 | 0 | result[byteIndex] = m_NetworkPrefix[byteIndex] | ~m_Mask[byteIndex]; |
593 | 0 | } |
594 | |
|
595 | 0 | return result; |
596 | 0 | } |
597 | | |
598 | | uint64_t IPv6Network::getTotalAddressCount() const |
599 | 0 | { |
600 | 0 | int numOfBitset = 0; |
601 | 0 | for (const auto& byte : m_Mask) |
602 | 0 | { |
603 | 0 | const std::bitset<8> bitset(static_cast<uint8_t>(~byte)); |
604 | 0 | numOfBitset += static_cast<int>(bitset.count()); |
605 | 0 | } |
606 | |
|
607 | 0 | if (numOfBitset >= 64) |
608 | 0 | { |
609 | 0 | throw std::out_of_range("Number of addresses exceeds uint64_t"); |
610 | 0 | } |
611 | 0 | return 1ULL << numOfBitset; |
612 | 0 | } |
613 | | |
614 | | bool IPv6Network::includes(const IPv6Address& address) const |
615 | 0 | { |
616 | 0 | uint8_t maskedBytes[IPV6_ADDR_SIZE]; |
617 | 0 | address.copyTo(maskedBytes); |
618 | |
|
619 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
620 | 0 | { |
621 | 0 | maskedBytes[byteIndex] &= m_Mask[byteIndex]; |
622 | 0 | } |
623 | 0 | return memcmp(m_NetworkPrefix, maskedBytes, IPV6_ADDR_SIZE) == 0; |
624 | 0 | } |
625 | | |
626 | | bool IPv6Network::includes(const IPv6Network& network) const |
627 | 0 | { |
628 | 0 | return includes(network.getLowestAddress()) && includes(network.getHighestAddress()); |
629 | 0 | } |
630 | | |
631 | | std::string IPv6Network::toString() const |
632 | 0 | { |
633 | 0 | std::ostringstream stream; |
634 | 0 | stream << getNetworkPrefix() << "/" << static_cast<int>(getPrefixLen()); |
635 | 0 | return stream.str(); |
636 | 0 | } |
637 | | |
638 | | void IPNetwork::NetworkVariant::swapTo(IPNetwork::NetworkVariant::Type newType) noexcept |
639 | 0 | { |
640 | 0 | if (m_Type == newType) |
641 | 0 | { |
642 | 0 | return; |
643 | 0 | } |
644 | | |
645 | 0 | destroyActiveMem(); |
646 | |
|
647 | 0 | switch (newType) |
648 | 0 | { |
649 | 0 | case Type::IPv4: |
650 | 0 | new (&m_IPv4Net) IPv4Network(IPv4Address::Zero); |
651 | 0 | break; |
652 | 0 | case Type::IPv6: |
653 | 0 | new (&m_IPv6Net) IPv6Network(IPv6Address::Zero); |
654 | 0 | break; |
655 | 0 | } |
656 | 0 | m_Type = newType; |
657 | 0 | } |
658 | | |
659 | | void IPNetwork::NetworkVariant::destroyActiveMem() noexcept |
660 | 0 | { |
661 | 0 | switch (m_Type) |
662 | 0 | { |
663 | 0 | case Type::IPv4: |
664 | 0 | m_IPv4Net.~IPv4Network(); |
665 | 0 | break; |
666 | 0 | case Type::IPv6: |
667 | 0 | m_IPv6Net.~IPv6Network(); |
668 | 0 | break; |
669 | 0 | } |
670 | 0 | } |
671 | | |
672 | | } // namespace pcpp |