/src/PcapPlusPlus/Common++/src/IpAddress.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 12 | { |
65 | 12 | 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 | 12 | } |
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 | 6 | { |
134 | 6 | 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 | 6 | } |
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 | 0 | *arr = new uint8_t[addrLen]; |
145 | 0 | memcpy(*arr, m_Bytes.data(), addrLen); |
146 | 0 | } |
147 | | |
148 | | size_t IPv6Address::copyTo(uint8_t* buffer, size_t size) const |
149 | 0 | { |
150 | 0 | const size_t requiredSize = m_Bytes.size(); |
151 | |
|
152 | 0 | if (buffer == nullptr) |
153 | 0 | { |
154 | 0 | if (size != 0) |
155 | 0 | { |
156 | 0 | throw std::invalid_argument("Buffer is null but size is not zero"); |
157 | 0 | } |
158 | | |
159 | 0 | return requiredSize; |
160 | 0 | } |
161 | | |
162 | 0 | if (size < requiredSize) |
163 | 0 | { |
164 | 0 | return requiredSize; |
165 | 0 | } |
166 | | |
167 | 0 | std::memcpy(buffer, m_Bytes.data(), requiredSize); |
168 | 0 | return requiredSize; |
169 | 0 | } |
170 | | |
171 | | bool IPv6Address::copyToNewBuffer(uint8_t** buffer, size_t& size) const |
172 | 0 | { |
173 | 0 | if (buffer == nullptr) |
174 | 0 | { |
175 | 0 | throw std::invalid_argument("Buffer pointer is null"); |
176 | 0 | } |
177 | | |
178 | 0 | size = copyTo(nullptr, 0); |
179 | 0 | *buffer = new uint8_t[size]; |
180 | 0 | if (copyTo(*buffer, size) != size) |
181 | 0 | { |
182 | 0 | delete[] *buffer; |
183 | 0 | *buffer = nullptr; |
184 | 0 | size = 0; |
185 | 0 | return false; |
186 | 0 | } |
187 | | |
188 | 0 | return true; |
189 | 0 | } |
190 | | |
191 | | bool IPv6Address::matchNetwork(const IPv6Network& network) const |
192 | 0 | { |
193 | 0 | return network.includes(*this); |
194 | 0 | } |
195 | | |
196 | | bool IPv6Address::matchNetwork(const std::string& network) const |
197 | 0 | { |
198 | 0 | try |
199 | 0 | { |
200 | 0 | auto ipv6Network = IPv6Network(network); |
201 | 0 | return ipv6Network.includes(*this); |
202 | 0 | } |
203 | 0 | catch (const std::invalid_argument& e) |
204 | 0 | { |
205 | 0 | (void)e; // Suppress the unreferenced local variable warning when PCPP_LOG_ERROR is disabled |
206 | 0 | PCPP_LOG_ERROR(e.what()); |
207 | 0 | return false; |
208 | 0 | } |
209 | 0 | } |
210 | | |
211 | | bool IPv6Address::isValidIPv6Address(const std::string& addrAsString) |
212 | 0 | { |
213 | 0 | sockaddr_in6 sa_in6{}; |
214 | 0 | return inet_pton(AF_INET6, addrAsString.data(), &(sa_in6.sin6_addr)) > 0; |
215 | 0 | } |
216 | | |
217 | | // ~~~~~~~~~ |
218 | | // IPAddress |
219 | | // ~~~~~~~~~ |
220 | | |
221 | | IPAddress::IPAddress(const std::string& addrAsString) |
222 | 0 | { |
223 | 0 | if (IPv4Address::isValidIPv4Address(addrAsString)) |
224 | 0 | { |
225 | 0 | m_Type = IPv4AddressType; |
226 | 0 | m_IPv4 = IPv4Address(addrAsString); |
227 | 0 | } |
228 | 0 | else if (IPv6Address::isValidIPv6Address(addrAsString)) |
229 | 0 | { |
230 | 0 | m_Type = IPv6AddressType; |
231 | 0 | m_IPv6 = IPv6Address(addrAsString); |
232 | 0 | } |
233 | 0 | else |
234 | 0 | { |
235 | 0 | throw std::invalid_argument("Not a valid IP address: " + addrAsString); |
236 | 0 | } |
237 | 0 | } |
238 | | |
239 | | // ~~~~~~~~~~~ |
240 | | // IPv4Network |
241 | | // ~~~~~~~~~~~ |
242 | | |
243 | | bool IPv4Network::isValidNetmask(const IPv4Address& maskAddress) |
244 | 0 | { |
245 | 0 | if (maskAddress == IPv4Address::Zero) |
246 | 0 | { |
247 | 0 | return true; |
248 | 0 | } |
249 | | |
250 | 0 | const uint32_t maskAsInt = be32toh(maskAddress.toInt()); |
251 | 0 | const std::bitset<32> bitset(maskAsInt); |
252 | 0 | auto bitsetCount = bitset.count(); |
253 | |
|
254 | 0 | if (bitsetCount == 32) |
255 | 0 | { |
256 | 0 | return true; |
257 | 0 | } |
258 | | |
259 | 0 | return maskAsInt << bitsetCount == 0; |
260 | 0 | } |
261 | | |
262 | | void IPv4Network::initFromAddressAndPrefixLength(const IPv4Address& address, uint8_t prefixLen) |
263 | 0 | { |
264 | 0 | m_Mask = be32toh(0xffff'ffff ^ (prefixLen < 32 ? 0xffff'ffff >> prefixLen : 0)); |
265 | 0 | m_NetworkPrefix = address.toInt() & m_Mask; |
266 | 0 | } |
267 | | |
268 | | void IPv4Network::initFromAddressAndNetmask(const IPv4Address& address, const IPv4Address& netmaskAddress) |
269 | 0 | { |
270 | 0 | m_Mask = netmaskAddress.toInt(); |
271 | 0 | m_NetworkPrefix = address.toInt() & m_Mask; |
272 | 0 | } |
273 | | |
274 | | IPv4Network::IPv4Network(const IPv4Address& address, uint8_t prefixLen) |
275 | 0 | { |
276 | 0 | if (prefixLen > 32) |
277 | 0 | { |
278 | 0 | throw std::invalid_argument("prefixLen must be an integer between 0 and 32"); |
279 | 0 | } |
280 | | |
281 | 0 | initFromAddressAndPrefixLength(address, prefixLen); |
282 | 0 | } |
283 | | |
284 | | IPv4Network::IPv4Network(const IPv4Address& address, const std::string& netmask) |
285 | 0 | { |
286 | 0 | IPv4Address netmaskAddr; |
287 | 0 | try |
288 | 0 | { |
289 | 0 | netmaskAddr = IPv4Address(netmask); |
290 | 0 | } |
291 | 0 | catch (const std::exception&) |
292 | 0 | { |
293 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmask); |
294 | 0 | } |
295 | 0 | if (!isValidNetmask(netmaskAddr)) |
296 | 0 | { |
297 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmask); |
298 | 0 | } |
299 | 0 | initFromAddressAndNetmask(address, netmaskAddr); |
300 | 0 | } |
301 | | |
302 | | IPv4Network::IPv4Network(const std::string& addressAndNetmask) |
303 | 0 | { |
304 | 0 | std::stringstream stream(addressAndNetmask); |
305 | 0 | std::string networkPrefixStr; |
306 | 0 | std::string netmaskStr; |
307 | 0 | std::getline(stream, networkPrefixStr, '/'); |
308 | 0 | std::getline(stream, netmaskStr); |
309 | |
|
310 | 0 | if (netmaskStr.empty()) |
311 | 0 | { |
312 | 0 | throw std::invalid_argument( |
313 | 0 | "The input should be in the format of <address>/<netmask> or <address>/<prefixLength>"); |
314 | 0 | } |
315 | | |
316 | 0 | IPv4Address networkPrefix; |
317 | 0 | try |
318 | 0 | { |
319 | 0 | networkPrefix = IPv4Address(networkPrefixStr); |
320 | 0 | } |
321 | 0 | catch (const std::invalid_argument&) |
322 | 0 | { |
323 | 0 | throw std::invalid_argument("The input doesn't contain a valid IPv4 network prefix: " + networkPrefixStr); |
324 | 0 | } |
325 | | |
326 | 0 | if (std::all_of(netmaskStr.begin(), netmaskStr.end(), ::isdigit)) |
327 | 0 | { |
328 | 0 | const uint32_t prefixLen = std::stoi(netmaskStr); |
329 | 0 | if (prefixLen > 32) |
330 | 0 | { |
331 | 0 | throw std::invalid_argument("Prefix length must be an integer between 0 and 32"); |
332 | 0 | } |
333 | | |
334 | 0 | initFromAddressAndPrefixLength(networkPrefix, prefixLen); |
335 | 0 | } |
336 | 0 | else |
337 | 0 | { |
338 | 0 | IPv4Address netmaskAddr; |
339 | 0 | try |
340 | 0 | { |
341 | 0 | netmaskAddr = IPv4Address(netmaskStr); |
342 | 0 | } |
343 | 0 | catch (const std::invalid_argument&) |
344 | 0 | { |
345 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmaskStr); |
346 | 0 | } |
347 | 0 | if (!isValidNetmask(netmaskAddr)) |
348 | 0 | { |
349 | 0 | throw std::invalid_argument("Netmask is not valid IPv4 format: " + netmaskStr); |
350 | 0 | } |
351 | 0 | initFromAddressAndNetmask(networkPrefix, netmaskAddr); |
352 | 0 | } |
353 | 0 | } |
354 | | |
355 | | uint8_t IPv4Network::getPrefixLen() const |
356 | 0 | { |
357 | 0 | const std::bitset<32> bitset(m_Mask); |
358 | 0 | return bitset.count(); |
359 | 0 | } |
360 | | |
361 | | IPv4Address IPv4Network::getLowestAddress() const |
362 | 0 | { |
363 | 0 | const std::bitset<32> bitset(m_Mask); |
364 | 0 | return bitset.count() < 32 ? m_NetworkPrefix + htobe32(1) : m_NetworkPrefix; |
365 | 0 | } |
366 | | |
367 | | IPv4Address IPv4Network::getHighestAddress() const |
368 | 0 | { |
369 | 0 | auto tempAddress = static_cast<uint32_t>(m_NetworkPrefix | ~m_Mask); |
370 | 0 | const std::bitset<32> bitset(m_Mask); |
371 | 0 | return bitset.count() < 32 ? tempAddress - htobe32(1) : tempAddress; |
372 | 0 | } |
373 | | |
374 | | uint64_t IPv4Network::getTotalAddressCount() const |
375 | 0 | { |
376 | 0 | const std::bitset<32> bitset(~static_cast<uint64_t>(m_Mask)); |
377 | 0 | return 1ULL << bitset.count(); |
378 | 0 | } |
379 | | |
380 | | bool IPv4Network::includes(const IPv4Address& address) const |
381 | 0 | { |
382 | 0 | return (address.toInt() & m_Mask) == m_NetworkPrefix; |
383 | 0 | } |
384 | | |
385 | | bool IPv4Network::includes(const IPv4Network& network) const |
386 | 0 | { |
387 | 0 | const uint32_t lowestAddress = network.m_NetworkPrefix; |
388 | 0 | const uint32_t highestAddress = network.m_NetworkPrefix | ~network.m_Mask; |
389 | 0 | return ((lowestAddress & m_Mask) == m_NetworkPrefix && (highestAddress & m_Mask) == m_NetworkPrefix); |
390 | 0 | } |
391 | | |
392 | | std::string IPv4Network::toString() const |
393 | 0 | { |
394 | 0 | std::ostringstream stream; |
395 | 0 | stream << getNetworkPrefix() << "/" << static_cast<int>(getPrefixLen()); |
396 | 0 | return stream.str(); |
397 | 0 | } |
398 | | |
399 | | // ~~~~~~~~~~~ |
400 | | // IPv6Network |
401 | | // ~~~~~~~~~~~ |
402 | | |
403 | 0 | #define IPV6_ADDR_SIZE 16 |
404 | | |
405 | | bool IPv6Network::isValidNetmask(const IPv6Address& netmask) |
406 | 0 | { |
407 | 0 | if (netmask == IPv6Address::Zero) |
408 | 0 | { |
409 | 0 | return true; |
410 | 0 | } |
411 | | |
412 | 0 | const uint8_t* addressAsBytes = netmask.toBytes(); |
413 | 0 | int expectingValue = 1; |
414 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
415 | 0 | { |
416 | 0 | auto curByte = addressAsBytes[byteIndex]; |
417 | 0 | if (expectingValue == 1) |
418 | 0 | { |
419 | 0 | if (curByte == 0xff) |
420 | 0 | { |
421 | 0 | continue; |
422 | 0 | } |
423 | 0 | const std::bitset<8> bitset(curByte); |
424 | 0 | if (((curByte << bitset.count()) & 0xff) != 0) |
425 | 0 | { |
426 | 0 | return false; |
427 | 0 | } |
428 | 0 | expectingValue = 0; |
429 | 0 | } |
430 | 0 | else if (expectingValue == 0 && curByte != 0) |
431 | 0 | { |
432 | 0 | return false; |
433 | 0 | } |
434 | 0 | } |
435 | | |
436 | 0 | return true; |
437 | 0 | } |
438 | | |
439 | | void IPv6Network::initFromAddressAndPrefixLength(const IPv6Address& address, uint8_t prefixLen) |
440 | 0 | { |
441 | 0 | memset(m_Mask, 0, IPV6_ADDR_SIZE); |
442 | 0 | int remainingPrefixLen = prefixLen; |
443 | 0 | for (auto& byte : m_Mask) |
444 | 0 | { |
445 | 0 | if (remainingPrefixLen >= 8) |
446 | 0 | { |
447 | 0 | byte = 0xff; |
448 | 0 | } |
449 | 0 | else if (remainingPrefixLen > 0) |
450 | 0 | { |
451 | 0 | byte = 0xff << (8 - remainingPrefixLen); |
452 | 0 | } |
453 | 0 | else |
454 | 0 | { |
455 | 0 | break; |
456 | 0 | } |
457 | | |
458 | 0 | remainingPrefixLen -= 8; |
459 | 0 | } |
460 | |
|
461 | 0 | address.copyTo(m_NetworkPrefix); |
462 | |
|
463 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
464 | 0 | { |
465 | 0 | m_NetworkPrefix[byteIndex] &= m_Mask[byteIndex]; |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | | void IPv6Network::initFromAddressAndNetmask(const IPv6Address& address, const IPv6Address& netmaskAddr) |
470 | 0 | { |
471 | 0 | netmaskAddr.copyTo(m_Mask); |
472 | |
|
473 | 0 | address.copyTo(m_NetworkPrefix); |
474 | |
|
475 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
476 | 0 | { |
477 | 0 | m_NetworkPrefix[byteIndex] &= m_Mask[byteIndex]; |
478 | 0 | } |
479 | 0 | } |
480 | | |
481 | | IPv6Network::IPv6Network(const IPv6Address& address, uint8_t prefixLen) |
482 | 0 | { |
483 | 0 | if (prefixLen > 128) |
484 | 0 | { |
485 | 0 | throw std::invalid_argument("prefixLen must be an integer between 0 and 128"); |
486 | 0 | } |
487 | | |
488 | 0 | initFromAddressAndPrefixLength(address, prefixLen); |
489 | 0 | } |
490 | | |
491 | | IPv6Network::IPv6Network(const IPv6Address& address, const std::string& netmask) |
492 | 0 | { |
493 | 0 | IPv6Address netmaskAddr; |
494 | 0 | try |
495 | 0 | { |
496 | 0 | netmaskAddr = IPv6Address(netmask); |
497 | 0 | } |
498 | 0 | catch (const std::exception&) |
499 | 0 | { |
500 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmask); |
501 | 0 | } |
502 | 0 | if (!isValidNetmask(netmaskAddr)) |
503 | 0 | { |
504 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmask); |
505 | 0 | } |
506 | 0 | initFromAddressAndNetmask(address, netmaskAddr); |
507 | 0 | } |
508 | | |
509 | | IPv6Network::IPv6Network(const std::string& addressAndNetmask) |
510 | 0 | { |
511 | 0 | std::stringstream stream(addressAndNetmask); |
512 | 0 | std::string networkPrefixStr; |
513 | 0 | std::string netmaskStr; |
514 | 0 | std::getline(stream, networkPrefixStr, '/'); |
515 | 0 | std::getline(stream, netmaskStr); |
516 | |
|
517 | 0 | if (netmaskStr.empty()) |
518 | 0 | { |
519 | 0 | throw std::invalid_argument( |
520 | 0 | "The input should be in the format of <address>/<netmask> or <address>/<prefixLength>"); |
521 | 0 | } |
522 | | |
523 | 0 | IPv6Address networkPrefix; |
524 | 0 | try |
525 | 0 | { |
526 | 0 | networkPrefix = IPv6Address(networkPrefixStr); |
527 | 0 | } |
528 | 0 | catch (const std::invalid_argument&) |
529 | 0 | { |
530 | 0 | throw std::invalid_argument("The input doesn't contain a valid IPv6 network prefix: " + networkPrefixStr); |
531 | 0 | } |
532 | 0 | if (std::all_of(netmaskStr.begin(), netmaskStr.end(), ::isdigit)) |
533 | 0 | { |
534 | 0 | const uint32_t prefixLen = std::stoi(netmaskStr); |
535 | 0 | if (prefixLen > 128) |
536 | 0 | { |
537 | 0 | throw std::invalid_argument("Prefix length must be an integer between 0 and 128"); |
538 | 0 | } |
539 | | |
540 | 0 | initFromAddressAndPrefixLength(networkPrefix, prefixLen); |
541 | 0 | } |
542 | 0 | else |
543 | 0 | { |
544 | 0 | IPv6Address netmaskAddr; |
545 | 0 | try |
546 | 0 | { |
547 | 0 | netmaskAddr = IPv6Address(netmaskStr); |
548 | 0 | } |
549 | 0 | catch (const std::exception&) |
550 | 0 | { |
551 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmaskStr); |
552 | 0 | } |
553 | 0 | if (!isValidNetmask(netmaskAddr)) |
554 | 0 | { |
555 | 0 | throw std::invalid_argument("Netmask is not valid IPv6 format: " + netmaskStr); |
556 | 0 | } |
557 | 0 | initFromAddressAndNetmask(networkPrefix, netmaskAddr); |
558 | 0 | } |
559 | 0 | } |
560 | | |
561 | | uint8_t IPv6Network::getPrefixLen() const |
562 | 0 | { |
563 | 0 | uint8_t result = 0; |
564 | 0 | for (const auto& byte : m_Mask) |
565 | 0 | { |
566 | 0 | const std::bitset<8> bset(byte); |
567 | 0 | result += static_cast<uint8_t>(bset.count()); |
568 | 0 | } |
569 | 0 | return result; |
570 | 0 | } |
571 | | |
572 | | IPv6Address IPv6Network::getLowestAddress() const |
573 | 0 | { |
574 | 0 | if (getPrefixLen() == 128) |
575 | 0 | { |
576 | 0 | return m_NetworkPrefix; |
577 | 0 | } |
578 | | |
579 | 0 | uint8_t lowestAddress[IPV6_ADDR_SIZE]; |
580 | 0 | memcpy(lowestAddress, m_NetworkPrefix, IPV6_ADDR_SIZE); |
581 | 0 | lowestAddress[IPV6_ADDR_SIZE - 1]++; |
582 | 0 | return lowestAddress; |
583 | 0 | } |
584 | | |
585 | | IPv6Address IPv6Network::getHighestAddress() const |
586 | 0 | { |
587 | 0 | uint8_t result[IPV6_ADDR_SIZE]; |
588 | |
|
589 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
590 | 0 | { |
591 | 0 | result[byteIndex] = m_NetworkPrefix[byteIndex] | ~m_Mask[byteIndex]; |
592 | 0 | } |
593 | |
|
594 | 0 | return result; |
595 | 0 | } |
596 | | |
597 | | uint64_t IPv6Network::getTotalAddressCount() const |
598 | 0 | { |
599 | 0 | int numOfBitset = 0; |
600 | 0 | for (const auto& byte : m_Mask) |
601 | 0 | { |
602 | 0 | const std::bitset<8> bitset(static_cast<uint8_t>(~byte)); |
603 | 0 | numOfBitset += static_cast<int>(bitset.count()); |
604 | 0 | } |
605 | |
|
606 | 0 | if (numOfBitset >= 64) |
607 | 0 | { |
608 | 0 | throw std::out_of_range("Number of addresses exceeds uint64_t"); |
609 | 0 | } |
610 | 0 | return 1ULL << numOfBitset; |
611 | 0 | } |
612 | | |
613 | | bool IPv6Network::includes(const IPv6Address& address) const |
614 | 0 | { |
615 | 0 | uint8_t maskedBytes[IPV6_ADDR_SIZE]; |
616 | 0 | address.copyTo(maskedBytes); |
617 | |
|
618 | 0 | for (auto byteIndex = 0; byteIndex < IPV6_ADDR_SIZE; byteIndex++) |
619 | 0 | { |
620 | 0 | maskedBytes[byteIndex] &= m_Mask[byteIndex]; |
621 | 0 | } |
622 | 0 | return memcmp(m_NetworkPrefix, maskedBytes, IPV6_ADDR_SIZE) == 0; |
623 | 0 | } |
624 | | |
625 | | bool IPv6Network::includes(const IPv6Network& network) const |
626 | 0 | { |
627 | 0 | return includes(network.getLowestAddress()) && includes(network.getHighestAddress()); |
628 | 0 | } |
629 | | |
630 | | std::string IPv6Network::toString() const |
631 | 0 | { |
632 | 0 | std::ostringstream stream; |
633 | 0 | stream << getNetworkPrefix() << "/" << static_cast<int>(getPrefixLen()); |
634 | 0 | return stream.str(); |
635 | 0 | } |
636 | | |
637 | | } // namespace pcpp |