Coverage Report

Created: 2025-07-18 06:14

/src/PcapPlusPlus/Common++/header/IpAddress.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <cstdint>
4
#include <cstring>
5
#include <string>
6
#include <algorithm>
7
#include <ostream>
8
#include <array>
9
#include <memory>
10
11
#include "DeprecationUtils.h"
12
13
/// @file
14
15
/// @namespace pcpp
16
/// @brief The main namespace for the PcapPlusPlus lib
17
namespace pcpp
18
{
19
20
  // forward declarations
21
  class IPv4Network;
22
  class IPv6Network;
23
24
  // The implementation of the classes is based on document N4771 "Working Draft, C++ Extensions for Networking"
25
  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4771.pdf
26
27
  /// @class IPv4Address
28
  /// Represents an IPv4 address (of type XXX.XXX.XXX.XXX)
29
  class IPv4Address
30
  {
31
  public:
32
    /// A default constructor that creates an instance of the class with the zero-initialized address
33
0
    IPv4Address() = default;
34
35
    /// A constructor that creates an instance of the class out of 4-byte integer value.
36
    /// @param[in] addrAsInt The address as 4-byte integer in network byte order
37
    IPv4Address(const uint32_t addrAsInt)
38
0
    {
39
0
      memcpy(m_Bytes.data(), &addrAsInt, sizeof(addrAsInt));
40
0
    }
41
42
    /// A constructor that creates an instance of the class out of 4-byte array.
43
    /// @param[in] bytes The address as 4-byte array in network byte order
44
    /// @remarks This constructor assumes that the provided array is exactly 4 bytes long.
45
    /// Prefer using the constructor with size parameter if the array length is not guaranteed to be 4 bytes.
46
    IPv4Address(const uint8_t bytes[4]) : IPv4Address(bytes, 4)
47
0
    {}
48
49
    /// A constructor that creates an instance of the class out of a 4-byte array.
50
    /// @param[in] bytes The address as 4-byte array in network byte order
51
    /// @param[in] size The size of the array in bytes
52
    /// @throws std::invalid_argument If the provided bytes pointer is null.
53
    /// @throws std::out_of_range If the provided size is smaller than 4 bytes.
54
    IPv4Address(const uint8_t* bytes, size_t size);
55
56
    /// A constructor that creates an instance of the class out of a 4-byte standard array.
57
    /// @param[in] bytes The address as 4-byte standard array in network byte order
58
    IPv4Address(const std::array<uint8_t, 4>& bytes) : m_Bytes(bytes)
59
0
    {}
60
61
    /// A constructor that creates an instance of the class out of std::string value.
62
    /// @param[in] addrAsString The std::string representation of the address
63
    /// @throws std::invalid_argument The provided string does not represent a valid IPv4 address.
64
    IPv4Address(const std::string& addrAsString);
65
66
    /// @return A 4-byte integer in network byte order representing the IPv4 address
67
    inline uint32_t toInt() const;
68
69
    /// @return A non-owning pointer to 4-byte C-style array representing the IPv4 address
70
    const uint8_t* toBytes() const
71
0
    {
72
0
      return m_Bytes.data();
73
0
    }
74
75
    /// @return A reference to a 4-byte standard array representing the IPv4 address
76
    const std::array<uint8_t, 4>& toByteArray() const
77
0
    {
78
0
      return m_Bytes;
79
0
    }
80
81
    /// @return A string representation of the address
82
    std::string toString() const;
83
84
    /// @return True if an address is multicast, false otherwise.
85
    bool isMulticast() const;
86
87
    /// Overload of the equal-to operator
88
    /// @param[in] rhs The object to compare with
89
    /// @return True if the addresses are equal, false otherwise
90
    bool operator==(const IPv4Address& rhs) const
91
0
    {
92
0
      return toInt() == rhs.toInt();
93
0
    }
94
95
    /// Overload of the less-than operator
96
    /// @param[in] rhs The object to compare with
97
    /// @return True if the address value is lower than the other address value, false otherwise
98
    bool operator<(const IPv4Address& rhs) const
99
0
    {
100
0
      uint32_t intVal = toInt();
101
0
      std::reverse(reinterpret_cast<uint8_t*>(&intVal), reinterpret_cast<uint8_t*>(&intVal) + sizeof(intVal));
102
103
0
      uint32_t rhsIntVal = rhs.toInt();
104
0
      std::reverse(reinterpret_cast<uint8_t*>(&rhsIntVal),
105
0
                   reinterpret_cast<uint8_t*>(&rhsIntVal) + sizeof(rhsIntVal));
106
107
0
      return intVal < rhsIntVal;
108
0
    }
109
110
    /// Overload of the not-equal-to operator
111
    /// @param[in] rhs The object to compare with
112
    /// @return True if the addresses are not equal, false otherwise
113
    bool operator!=(const IPv4Address& rhs) const
114
0
    {
115
0
      return !(*this == rhs);
116
0
    }
117
118
    /// Checks whether the address matches a network.
119
    /// @param network An IPv4Network network
120
    /// @return True if the address matches the network or false otherwise
121
    bool matchNetwork(const IPv4Network& network) const;
122
123
    /// Checks whether the address matches a network.
124
    /// For example: this method will return true for address 10.1.1.9 and network which is one of:
125
    /// 10.1.1.1/24, 10.1.1.1/255.255.255.0
126
    /// Another example: this method will return false for address 11.1.1.9 and network which is one of:
127
    /// 10.1.1.1/16, 10.1.1.1/255.255.0.0
128
    /// @param[in] network A string in one of these formats:
129
    ///  - X.X.X.X/Y where X.X.X.X is a valid IP address and Y is a number between 0 and 32
130
    ///  - X.X.X.X/Y.Y.Y.Y where X.X.X.X is a valid IP address and Y.Y.Y.Y is a valid netmask
131
    /// @return True if the address matches the network or false if it doesn't or if the network is invalid
132
    bool matchNetwork(const std::string& network) const;
133
134
    /// A static method that checks whether a string represents a valid IPv4 address
135
    /// @param[in] addrAsString The std::string representation of the address
136
    /// @return True if the address is valid, false otherwise
137
    static bool isValidIPv4Address(const std::string& addrAsString);
138
139
    /// A static value representing a zero value of IPv4 address, meaning address of value "0.0.0.0".
140
    static const IPv4Address Zero;
141
142
    /// A static values representing the lower and upper bound of IPv4 multicast ranges. The bounds are inclusive.
143
    /// MulticastRangeLowerBound is initialized to "224.0.0.0".
144
    /// MulticastRangeUpperBound is initialized to "239.255.255.255".
145
    /// In order to check whether the address is a multicast address the isMulticast method can be used.
146
    static const IPv4Address MulticastRangeLowerBound;
147
    static const IPv4Address MulticastRangeUpperBound;
148
149
  private:
150
    std::array<uint8_t, 4> m_Bytes = { 0 };
151
  };  // class IPv4Address
152
153
  // Implementation of inline methods
154
155
  uint32_t IPv4Address::toInt() const
156
0
  {
157
0
    uint32_t addr = 0;
158
0
    memcpy(&addr, m_Bytes.data(), m_Bytes.size() * sizeof(uint8_t));
159
0
    return addr;
160
0
  }
161
162
  /// @class IPv6Address
163
  /// Represents an IPv6 address (of type xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx).
164
  class IPv6Address
165
  {
166
  public:
167
    /// A default constructor that creates an instance of the class with the zero-initialized address.
168
0
    IPv6Address() = default;
169
170
    /// A constructor that creates an instance of the class out of 16-byte array.
171
    /// @param[in] bytes The address as 16-byte array in network byte order
172
    /// @remarks This constructor assumes that the provided array is exactly 16 bytes long.
173
    /// Prefer using the constructor with size parameter if the array length is not guaranteed to be 16 bytes.
174
0
    IPv6Address(const uint8_t bytes[16]) : IPv6Address(bytes, 16)
175
0
    {}
176
177
    /// @brief A constructor that creates an instance of the class out of a 16-byte array.
178
    /// @param bytes The address as 16-byte array in network byte order
179
    /// @param size The size of the array in bytes
180
    /// @throws std::invalid_argument If the provided buffer is null.
181
    /// @throws std::out_of_range If the provided size is smaller than 16 bytes.
182
    IPv6Address(const uint8_t* bytes, size_t size);
183
184
    /// A constructor that creates an instance of the class out of a 16-byte standard array.
185
    /// @param[in] bytes The address as 16-byte standard array in network byte order
186
    IPv6Address(const std::array<uint8_t, 16>& bytes) : m_Bytes(bytes)
187
0
    {}
188
189
    /// A constructor that creates an instance of the class out of std::string value.
190
    /// @param[in] addrAsString The std::string representation of the address
191
    /// @throws std::invalid_argument The provided string does not represent a valid IPv6 address.
192
    IPv6Address(const std::string& addrAsString);
193
194
    /// Returns a view of the IPv6 address as a 16-byte raw C-style array
195
    /// @return A non-owning pointer to 16-byte array representing the IPv6 address
196
    const uint8_t* toBytes() const
197
0
    {
198
0
      return m_Bytes.data();
199
0
    }
200
201
    /// Returns a view of the IPv6 address as a std::array of bytes
202
    /// @return A reference to a 16-byte standard array representing the IPv6 address
203
    const std::array<uint8_t, 16>& toByteArray() const
204
0
    {
205
0
      return m_Bytes;
206
0
    }
207
208
    /// Returns a std::string representation of the address
209
    /// @return A string representation of the address
210
    std::string toString() const;
211
212
    /// Determine whether the address is a multicast address
213
    /// @return True if an address is multicast
214
    bool isMulticast() const;
215
216
    /// Overload of the equal-to operator
217
    /// @param[in] rhs The object to compare with
218
    /// @return True if the addresses are equal, false otherwise
219
    bool operator==(const IPv6Address& rhs) const
220
0
    {
221
0
      return memcmp(toBytes(), rhs.toBytes(), sizeof(m_Bytes)) == 0;
222
0
    }
223
224
    /// Overload of the less-than operator
225
    /// @param[in] rhs The object to compare with
226
    /// @return True if the address value is lower than the other address value, false otherwise
227
    bool operator<(const IPv6Address& rhs) const
228
0
    {
229
0
      return memcmp(toBytes(), rhs.toBytes(), sizeof(m_Bytes)) < 0;
230
0
    }
231
232
    /// Overload of the not-equal-to operator
233
    /// @param[in] rhs The object to compare with
234
    /// @return True if the addresses are not equal, false otherwise
235
    bool operator!=(const IPv6Address& rhs) const
236
0
    {
237
0
      return !(*this == rhs);
238
0
    }
239
240
    /// Allocates a byte array and copies address value into it. Array deallocation is user responsibility
241
    /// @param[in] arr A pointer to where array will be allocated
242
    /// @param[out] length Returns the length in bytes of the array that was allocated
243
    /// @throws std::invalid_argument If the provided pointer is null.
244
    /// @deprecated Use copyToNewBuffer instead.
245
    PCPP_DEPRECATED("Use copyToNewBuffer instead.")
246
    void copyTo(uint8_t** arr, size_t& length) const;
247
248
    /// Gets a pointer to an already allocated byte array and copies the address value to it.
249
    /// This method assumes array allocated size is at least 16 (the size of an IPv6 address)
250
    /// @param[in] arr A pointer to the array which address will be copied to
251
    /// @remarks This method assumes that the provided array is at least 16 bytes long.
252
    /// Prefer using the copyTo(uint8_t* buffer, size_t size) method if the array length is not guaranteed to be 16
253
    /// bytes.
254
    void copyTo(uint8_t* arr) const
255
0
    {
256
0
      copyTo(arr, 16);
257
0
    }
258
259
    /// @brief Copies the address value to a user-provided buffer.
260
    ///
261
    /// This function supports querying. If the buffer is null and size is zero, it returns the required size.
262
    ///
263
    /// @param[in] buffer A pointer to the buffer where the address will be copied
264
    /// @param[in] size The size of the buffer in bytes
265
    /// @return The number of bytes copied to the buffer or the number of required bytes, which is always 16 for
266
    /// IPv6 addresses.
267
    /// @throws std::invalid_argument If the provided buffer is null and size is not zero.
268
    size_t copyTo(uint8_t* buffer, size_t size) const;
269
270
    /// @brief Allocates a new buffer and copies the address value to it.
271
    /// The user is responsible for deallocating the buffer.
272
    ///
273
    /// @param buffer A pointer to a pointer where the new buffer will be allocated
274
    /// @param size A reference to a size_t variable that will be updated with the size of the allocated buffer
275
    /// @return True if the buffer was successfully allocated and the address was copied, false otherwise.
276
    /// @throws std::invalid_argument If the buffer pointer is null.
277
    bool copyToNewBuffer(uint8_t** buffer, size_t& size) const;
278
279
    /// Checks whether the address matches a network.
280
    /// @param network An IPv6Network network
281
    /// @return True if the address matches the network or false otherwise
282
    bool matchNetwork(const IPv6Network& network) const;
283
284
    /// Checks whether the address matches a network.
285
    /// For example: this method will return true for address d6e5:83dc:0c58:bc5d:1449:5898:: and network
286
    /// which is one of:
287
    /// d6e5:83dc:0c58:bc5d::/64, d6e5:83dc:0c58:bc5d::/ffff:ffff:ffff:ffff::
288
    /// Another example: this method will return false for address d6e5:83dc:: and network which is one of:
289
    /// d6e5:83dc:0c58:bc5d::/64, d6e5:83dc:0c58:bc5d::/ffff:ffff:ffff:ffff::
290
    /// @param[in] network A string in one of these formats:
291
    ///  - IPV6_ADDRESS/Y where IPV6_ADDRESS is a valid IPv6 address and Y is a number between 0 and 128
292
    ///  - IPV6_ADDRESS/IPV6_NETMASK where IPV6_ADDRESS is a valid IPv6 address and IPV6_NETMASK is a valid
293
    ///    IPv6 netmask
294
    /// @return True if the address matches the network or false if it doesn't or if the network is invalid
295
    bool matchNetwork(const std::string& network) const;
296
297
    /// A static method that checks whether a string represents a valid IPv6 address
298
    /// @param[in] addrAsString The std::string representation of the address
299
    /// @return True if the address is valid, false otherwise
300
    static bool isValidIPv6Address(const std::string& addrAsString);
301
302
    /// A static value representing a zero value of IPv6 address, meaning address of value
303
    /// "0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0".
304
    static const IPv6Address Zero;
305
306
    /// A static value representing the lower bound of IPv6 multicast ranges. The bound is inclusive.
307
    /// MulticastRangeLowerBound is initialized to "ff00:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0".
308
    /// In order to check whether the address is a multicast address the isMulticast method can be used.
309
    static const IPv6Address MulticastRangeLowerBound;
310
311
  private:
312
    std::array<uint8_t, 16> m_Bytes = { 0 };
313
  };  // class IPv6Address
314
315
  /// @class IPAddress
316
  /// The class is a version-independent representation for an IP address
317
  class IPAddress
318
  {
319
  public:
320
    /// An enum representing the address type: IPv4 or IPv6
321
    enum AddressType : uint8_t
322
    {
323
      /// IPv4 address type
324
      IPv4AddressType,
325
      /// IPv6 address type
326
      IPv6AddressType
327
    };
328
329
    /// A default constructor that creates an instance of the class with unspecified IPv4 address
330
    IPAddress() : m_Type(IPv4AddressType)
331
0
    {}
332
333
    /// A constructor that creates an instance of the class out of IPv4Address.
334
    /// @param[in] addr A const reference to instance of IPv4Address
335
    IPAddress(const IPv4Address& addr) : m_Type(IPv4AddressType), m_IPv4(addr)
336
0
    {}
337
338
    /// A constructor that creates an instance of the class out of IPv6Address.
339
    /// @param[in] addr A const reference to instance of IPv6Address
340
    IPAddress(const IPv6Address& addr) : m_Type(IPv6AddressType), m_IPv6(addr)
341
0
    {}
342
343
    /// A constructor that creates an instance of the class out of std::string value
344
    /// @param[in] addrAsString The std::string representation of the address
345
    /// @throws std::invalid_argument The provided string does not represent a valid IPv4 or IPv6 address.
346
    IPAddress(const std::string& addrAsString);
347
348
    /// Overload of an assignment operator.
349
    /// @param[in] addr A const reference to instance of IPv4Address
350
    /// @return A reference to the assignee
351
    inline IPAddress& operator=(const IPv4Address& addr);
352
353
    /// Overload of an assignment operator.
354
    /// @param[in] addr A const reference to instance of IPv6Address
355
    /// @return A reference to the assignee
356
    inline IPAddress& operator=(const IPv6Address& addr);
357
358
    /// Gets the address type: IPv4 or IPv6
359
    /// @return The address type
360
    AddressType getType() const
361
0
    {
362
0
      return static_cast<AddressType>(m_Type);
363
0
    }
364
365
    /// Returns a std::string representation of the address
366
    /// @return A string representation of the address
367
    std::string toString() const
368
0
    {
369
0
      return (getType() == IPv4AddressType) ? m_IPv4.toString() : m_IPv6.toString();
370
0
    }
371
372
    /// @return Determine whether the object contains an IP version 4 address
373
    bool isIPv4() const
374
0
    {
375
0
      return getType() == IPv4AddressType;
376
0
    }
377
378
    /// @return Determine whether the object contains an IP version 6 address
379
    bool isIPv6() const
380
0
    {
381
0
      return getType() == IPv6AddressType;
382
0
    }
383
384
    /// Determine whether the address is a multicast address
385
    /// @return True if an address is multicast
386
    bool isMulticast() const
387
0
    {
388
0
      return (getType() == IPv4AddressType) ? m_IPv4.isMulticast() : m_IPv6.isMulticast();
389
0
    }
390
391
    /// Get a reference to IPv4 address instance
392
    /// @return The const reference to IPv4Address instance
393
    const IPv4Address& getIPv4() const
394
0
    {
395
0
      return m_IPv4;
396
0
    }
397
398
    /// Get a reference to IPv6 address instance
399
    /// @return The const reference to IPv6Address instance
400
    const IPv6Address& getIPv6() const
401
0
    {
402
0
      return m_IPv6;
403
0
    }
404
405
    /// @return True if the address is zero, false otherwise
406
    bool isZero() const
407
0
    {
408
0
      return (getType() == IPv4AddressType) ? m_IPv4 == IPv4Address::Zero : m_IPv6 == IPv6Address::Zero;
409
0
    }
410
411
    /// Overload of the equal-to operator
412
    /// @param[in] rhs The object to compare with
413
    /// @return True if the addresses are equal, false otherwise
414
    inline bool operator==(const IPAddress& rhs) const;
415
416
    /// Overload of the less-than operator
417
    /// @param[in] rhs The object to compare with
418
    /// @return True if the address value is lower than the other address value, false otherwise
419
    inline bool operator<(const IPAddress& rhs) const;
420
421
    /// Overload of the not-equal-to operator
422
    /// @param[in] rhs The object to compare with
423
    /// @return True if the addresses are not equal, false otherwise
424
    bool operator!=(const IPAddress& rhs) const
425
0
    {
426
0
      return !(*this == rhs);
427
0
    }
428
429
  private:
430
    uint8_t m_Type;
431
    IPv4Address m_IPv4;
432
    IPv6Address m_IPv6;
433
  };
434
435
  // implementation of inline methods
436
437
  bool IPAddress::operator==(const IPAddress& rhs) const
438
0
  {
439
0
    if (isIPv4())
440
0
    {
441
0
      return rhs.isIPv4() ? (m_IPv4 == rhs.m_IPv4) : false;
442
0
    }
443
0
444
0
    return rhs.isIPv6() ? m_IPv6 == rhs.m_IPv6 : false;
445
0
  }
446
447
  bool IPAddress::operator<(const IPAddress& rhs) const
448
0
  {
449
0
    if (isIPv4())
450
0
    {
451
0
      // treat IPv4 as less than IPv6
452
0
      // If current obj is IPv4 and other is IPv6 return true
453
0
      return rhs.isIPv4() ? (m_IPv4 < rhs.m_IPv4) : true;
454
0
    }
455
0
    return rhs.isIPv6() ? m_IPv6 < rhs.m_IPv6 : false;
456
0
  }
457
458
  IPAddress& IPAddress::operator=(const IPv4Address& addr)
459
0
  {
460
0
    m_Type = IPv4AddressType;
461
0
    m_IPv4 = addr;
462
0
    return *this;
463
0
  }
464
465
  IPAddress& IPAddress::operator=(const IPv6Address& addr)
466
0
  {
467
0
    m_Type = IPv6AddressType;
468
0
    m_IPv6 = addr;
469
0
    return *this;
470
0
  }
471
472
  /// @class IPv4Network
473
  /// A class representing IPv4 network definition
474
  class IPv4Network
475
  {
476
  public:
477
    /// A constructor that creates an instance of the class out of an address and a full prefix length,
478
    /// essentially making a network of consisting of only 1 address.
479
    /// @param address An address representing the network prefix.
480
    explicit IPv4Network(const IPv4Address& address) : IPv4Network(address, 32U)
481
0
    {}
482
483
    /// A constructor that creates an instance of the class out of an address representing the network prefix
484
    /// and a prefix length
485
    /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument
486
    /// exception is thrown
487
    /// @param prefixLen A number between 0 and 32 representing the prefix length.
488
    /// @throws std::invalid_argument Prefix length is out of acceptable range.
489
    IPv4Network(const IPv4Address& address, uint8_t prefixLen);
490
491
    /// A constructor that creates an instance of the class out of an address representing the network prefix
492
    /// and a netmask
493
    /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument
494
    /// exception is thrown
495
    /// @param netmask A string representing a netmask in the format of X.X.X.X, for example: 255.255.0.0.
496
    /// Please notice that netmasks that start with zeros are invalid, for example: 0.0.255.255. The only netmask
497
    /// starting with zeros that is valid is 0.0.0.0.
498
    /// @throws std::invalid_argument The provided netmask is invalid.
499
    IPv4Network(const IPv4Address& address, const std::string& netmask);
500
501
    /// A constructor that creates an instance of the class out of a string representing the network prefix and
502
    /// a prefix length or a netmask
503
    /// @param addressAndNetmask A string in one of these formats:
504
    ///  - X.X.X.X/Y where X.X.X.X is a valid IPv4 address representing the network prefix and Y is a number between
505
    ///    0 and 32 representing the network prefix
506
    ///  - X.X.X.X/Y.Y.Y.Y where X.X.X.X is a valid IPv4 address representing the network prefix and Y.Y.Y.Y is
507
    ///    a valid netmask
508
    /// @throws std::invalid_argument The provided string does not represent a valid address and netmask format.
509
    IPv4Network(const std::string& addressAndNetmask);
510
511
    /// @return The prefix length, for example: the prefix length of 10.10.10.10/255.0.0.0 is 8
512
    uint8_t getPrefixLen() const;
513
514
    /// @return The netmask, for example: the netmask of 10.10.10.10/8 is 255.0.0.0
515
    std::string getNetmask() const
516
0
    {
517
0
      return IPv4Address(m_Mask).toString();
518
0
    }
519
520
    /// @return The network prefix, for example: the network prefix of 10.10.10.10/16 is 10.10.0.0
521
    IPv4Address getNetworkPrefix() const
522
0
    {
523
0
      return m_NetworkPrefix;
524
0
    }
525
526
    /// @return The lowest non-reserved IPv4 address in this network, for example: the lowest address
527
    /// in 10.10.10.10/16 is 10.10.0.1
528
    IPv4Address getLowestAddress() const;
529
530
    /// @return The highest non-reserved IPv4 address in this network, for example: the highest address
531
    /// in 10.10.10.10/16 is 10.10.255.254
532
    IPv4Address getHighestAddress() const;
533
534
    /// @return The number of addresses in this network including reserved addresses, for example:
535
    /// the number of addresses in 10.10.0.0/24 is 256
536
    uint64_t getTotalAddressCount() const;
537
538
    /// @param address An IPv4 address
539
    /// @return True is the address belongs to the network, false otherwise or if the address isn't valid
540
    bool includes(const IPv4Address& address) const;
541
542
    /// @param network An IPv4 network
543
    /// @return True is the input network is completely included within this network, false otherwise, for example:
544
    /// 10.10.10.10/16 includes 10.10.10.10/24 but doesn't include 10.10.10.10/8
545
    bool includes(const IPv4Network& network) const;
546
547
    /// @return A string representation of the network in a format of NETWORK_PREFIX/PREFIX_LEN, for example:
548
    /// 192.168.0.0/16
549
    std::string toString() const;
550
551
  private:
552
    uint32_t m_NetworkPrefix{};
553
    uint32_t m_Mask{};
554
555
    static bool isValidNetmask(const IPv4Address& netmaskAddress);
556
    void initFromAddressAndPrefixLength(const IPv4Address& address, uint8_t prefixLen);
557
    void initFromAddressAndNetmask(const IPv4Address& address, const IPv4Address& netmaskAddress);
558
  };
559
560
  /// @class IPv6Network
561
  /// A class representing IPv6 network definition
562
  class IPv6Network
563
  {
564
  public:
565
    /// A constructor that creates an instance of the class out of an address and a full prefix length,
566
    /// essentially making a network of consisting of only 1 address.
567
    /// @param address An address representing the network prefix.
568
    explicit IPv6Network(const IPv6Address& address) : IPv6Network(address, 128U)
569
0
    {}
570
571
    /// A constructor that creates an instance of the class out of an address representing the network prefix
572
    /// and a prefix length
573
    /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument
574
    /// exception is thrown
575
    /// @param prefixLen A number between 0 and 128 representing the prefix length.
576
    /// @throws std::invalid_argument Prefix length is out of acceptable range.
577
    IPv6Network(const IPv6Address& address, uint8_t prefixLen);
578
579
    /// A constructor that creates an instance of the class out of an address representing the network prefix
580
    /// and a netmask
581
    /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument
582
    /// exception is thrown
583
    /// @param netmask A string representing a netmask in valid IPv6 format, for example: ffff:ffff::.
584
    /// Please notice that netmasks that start with zeros are invalid, for example: 0:ffff::. The only netmask
585
    /// starting with zeros that is valid is all zeros (::).
586
    /// @throws std::invalid_argument The provided netmask is invalid.
587
    IPv6Network(const IPv6Address& address, const std::string& netmask);
588
589
    /// A constructor that creates an instance of the class out of a string representing the network prefix and
590
    /// a prefix length or a netmask
591
    /// @param addressAndNetmask A string in one of these formats:
592
    ///  - IPV6_ADDRESS/Y where IPV6_ADDRESS is a valid IPv6 address representing the network prefix and Y is
593
    ///    a number between 0 and 128 representing the network prefix
594
    ///  - IPV6_ADDRESS/IPV6_NETMASK where IPV6_ADDRESS is a valid IPv6 address representing the network prefix
595
    ///    and IPV6_NETMASK is a valid IPv6 netmask
596
    /// @throws std::invalid_argument The provided string does not represent a valid address and netmask format.
597
    IPv6Network(const std::string& addressAndNetmask);
598
599
    /// @return The prefix length, for example: the prefix length of 3546::/ffff:: is 16
600
    uint8_t getPrefixLen() const;
601
602
    /// @return The netmask, for example: the netmask of 3546::/16 is ffff::
603
    std::string getNetmask() const
604
0
    {
605
0
      return IPv6Address(m_Mask).toString();
606
0
    }
607
608
    /// @return The network prefix, for example: the network prefix of 3546:f321::/16 is 3546::
609
    IPv6Address getNetworkPrefix() const
610
0
    {
611
0
      return { m_NetworkPrefix };
612
0
    }
613
614
    /// @return The lowest non-reserved IPv6 address in this network, for example: the lowest address in 3546::/16
615
    /// is 3546::1
616
    IPv6Address getLowestAddress() const;
617
618
    /// @return The highest IPv6 address in this network, for example: the highest address in 3546::/16 is
619
    /// 3546:ffff:ffff:ffff:ffff:ffff:ffff:ffff
620
    IPv6Address getHighestAddress() const;
621
622
    /// @return The number of addresses in this network, for example: the number of addresses in 16ff::/120 is 256.
623
    /// If the number of addresses exceeds the size of uint64_t a std::out_of_range exception is thrown
624
    uint64_t getTotalAddressCount() const;
625
626
    /// @param address An IPv6 address
627
    /// @return True is the address belongs to the network, false otherwise or if the address isn't valid
628
    bool includes(const IPv6Address& address) const;
629
630
    /// @param network An IPv6 network
631
    /// @return True is the input network is completely included within this network, false otherwise, for example:
632
    /// 3546::/64 includes 3546::/120 but doesn't include 3546::/16
633
    bool includes(const IPv6Network& network) const;
634
635
    /// @return A string representation of the network in a format of NETWORK_PREFIX/PREFIX_LEN, for example:
636
    /// fda7:9f81:6c23:275::/64
637
    std::string toString() const;
638
639
  private:
640
    uint8_t m_NetworkPrefix[16]{};
641
    uint8_t m_Mask[16]{};
642
643
    static bool isValidNetmask(const IPv6Address& netmaskAddress);
644
    void initFromAddressAndPrefixLength(const IPv6Address& address, uint8_t prefixLen);
645
    void initFromAddressAndNetmask(const IPv6Address& address, const IPv6Address& netmaskAddress);
646
  };
647
648
  /// @class IPNetwork
649
  /// A class representing version independent IP network definition, both IPv4 and IPv6 are included
650
  class IPNetwork
651
  {
652
  public:
653
    /// A constructor that creates an instance of the class out of an IP address and a full prefix length,
654
    /// essentially making a network of consisting of only 1 address.
655
    /// @param address An address representing the network prefix.
656
    explicit IPNetwork(const IPAddress& address) : IPNetwork(address, address.isIPv4() ? 32U : 128U)
657
0
    {}
658
659
    /// A constructor that creates an instance of the class out of an address representing the network prefix
660
    /// and a prefix length
661
    /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument
662
    /// exception is thrown
663
    /// @param prefixLen A number representing the prefix length. Allowed ranges are 0 - 32 for IPv4 networks and 0
664
    /// - 128 for IPv6 networks.
665
    /// @throws std::invalid_argument Prefix length is out of acceptable range.
666
    IPNetwork(const IPAddress& address, uint8_t prefixLen)
667
0
    {
668
0
      if (address.isIPv4())
669
0
      {
670
0
        m_IPv4Network = std::make_unique<IPv4Network>(address.getIPv4(), prefixLen);
671
0
      }
672
0
      else
673
0
      {
674
0
        m_IPv6Network = std::make_unique<IPv6Network>(address.getIPv6(), prefixLen);
675
0
      }
676
0
    }
677
678
    /// A constructor that creates an instance of the class out of an address representing the network prefix
679
    /// and a netmask
680
    /// @param address An address representing the network prefix. If the address is invalid std::invalid_argument
681
    /// exception is thrown
682
    /// @param netmask A string representing a netmask in valid format, for example: ffff:ffff:: for IPv6 networks
683
    /// or 255.255.0.0 for IPv4 networks.
684
    /// Please notice that netmasks that start with zeros are invalid, for example: 0:ffff:: or 0.255.255.255.
685
    /// The only netmask starting with zeros that is valid is all zeros (:: or 0.0.0.0).
686
    /// @throws std::invalid_argument The provided netmask is invalid.
687
    IPNetwork(const IPAddress& address, const std::string& netmask)
688
0
    {
689
0
      if (address.isIPv4())
690
0
      {
691
0
        m_IPv4Network = std::make_unique<IPv4Network>(address.getIPv4(), netmask);
692
0
      }
693
0
      else
694
0
      {
695
0
        m_IPv6Network = std::make_unique<IPv6Network>(address.getIPv6(), netmask);
696
0
      }
697
0
    }
698
699
    /// A constructor that creates an instance of the class out of a string representing the network prefix and
700
    /// a prefix length or a netmask
701
    /// @param addressAndNetmask A string in one of these formats:
702
    ///  - IP_ADDRESS/Y where IP_ADDRESS is a valid IP address representing the network prefix and Y is
703
    ///    a number representing the network prefix
704
    ///  - IP_ADDRESS/NETMASK where IP_ADDRESS is a valid IP address representing the network prefix and NETMASK
705
    ///    is a valid netmask for this type of network (IPv4 or IPv6 network)
706
    /// @throws std::invalid_argument The provided string does not represent a valid address and netmask format.
707
    IPNetwork(const std::string& addressAndNetmask)
708
0
    {
709
0
      try
710
0
      {
711
0
        m_IPv4Network = std::make_unique<IPv4Network>(addressAndNetmask);
712
0
      }
713
0
      catch (const std::invalid_argument&)
714
0
      {
715
0
        m_IPv6Network = std::make_unique<IPv6Network>(addressAndNetmask);
716
0
      }
717
0
    }
718
719
    /// A copy c'tor for this class
720
    /// @param other The instance to copy from
721
    IPNetwork(const IPNetwork& other)
722
0
    {
723
0
      if (other.m_IPv4Network)
724
0
      {
725
0
        m_IPv4Network = std::make_unique<IPv4Network>(*other.m_IPv4Network);
726
0
      }
727
0
728
0
      if (other.m_IPv6Network)
729
0
      {
730
0
        m_IPv6Network = std::make_unique<IPv6Network>(*other.m_IPv6Network);
731
0
      }
732
0
    }
733
734
    /// Overload of an assignment operator.
735
    /// @param[in] other An instance of IPNetwork to assign
736
    /// @return A reference to the assignee
737
    IPNetwork& operator=(const IPNetwork& other)
738
0
    {
739
0
      // NOLINTBEGIN(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator)
740
0
      if (other.isIPv4Network())
741
0
      {
742
0
        return this->operator=(*other.m_IPv4Network);
743
0
      }
744
0
745
0
      return this->operator=(*other.m_IPv6Network);
746
0
      // NOLINTEND(cppcoreguidelines-c-copy-assignment-signature,misc-unconventional-assign-operator)
747
0
    }
748
749
    /// Overload of an assignment operator.
750
    /// @param[in] other An instance of IPv4Network to assign
751
    /// @return A reference to the assignee
752
    IPNetwork& operator=(const IPv4Network& other)
753
0
    {
754
0
      // Create the new instance first to maintain strong exception guarantee.
755
0
      m_IPv4Network = std::make_unique<IPv4Network>(other);
756
0
      m_IPv6Network = nullptr;
757
0
      return *this;
758
0
    }
759
760
    /// Overload of an assignment operator.
761
    /// @param[in] other An instance of IPv6Network to assign
762
    /// @return A reference to the assignee
763
    IPNetwork& operator=(const IPv6Network& other)
764
0
    {
765
0
      // Create the new instance first to maintain strong exception guarantee.
766
0
      m_IPv6Network = std::make_unique<IPv6Network>(other);
767
0
      m_IPv4Network = nullptr;
768
0
      return *this;
769
0
    }
770
771
    /// @return The prefix length, for example: the prefix length of 3546::/ffff:: is 16, the prefix length of
772
    /// 10.10.10.10/255.0.0.0 is 8
773
    uint8_t getPrefixLen() const
774
0
    {
775
0
      return (m_IPv4Network != nullptr ? m_IPv4Network->getPrefixLen() : m_IPv6Network->getPrefixLen());
776
0
    }
777
778
    /// @return The netmask, for example: the netmask of 3546::/16 is ffff::, the netmask of 10.10.10.10/8 is
779
    /// 255.0.0.0
780
    std::string getNetmask() const
781
0
    {
782
0
      return (m_IPv4Network != nullptr ? m_IPv4Network->getNetmask() : m_IPv6Network->getNetmask());
783
0
    }
784
785
    /// @return The network prefix, for example: the network prefix of 3546:f321::/16 is 3546::, the network prefix
786
    /// of 10.10.10.10/16 is 10.10.0.0
787
    IPAddress getNetworkPrefix() const
788
0
    {
789
0
      return (m_IPv4Network != nullptr ? IPAddress(m_IPv4Network->getNetworkPrefix())
790
0
                                       : IPAddress(m_IPv6Network->getNetworkPrefix()));
791
0
    }
792
793
    /// @return The lowest non-reserved IP address in this network, for example: the lowest address in 3546::/16 is
794
    /// 3546::1, the lowest address in 10.10.10.10/16 is 10.10.0.1
795
    IPAddress getLowestAddress() const
796
0
    {
797
0
      return (m_IPv4Network != nullptr ? IPAddress(m_IPv4Network->getLowestAddress())
798
0
                                       : IPAddress(m_IPv6Network->getLowestAddress()));
799
0
    }
800
801
    /// @return The highest non-reserved IP address in this network, for example: the highest address in 3546::/16
802
    /// is 3546:ffff:ffff:ffff:ffff:ffff:ffff:ffff, the highest address in 10.10.10.10/16 is 10.10.255.254
803
    IPAddress getHighestAddress() const
804
0
    {
805
0
      return (m_IPv4Network != nullptr ? IPAddress(m_IPv4Network->getHighestAddress())
806
0
                                       : IPAddress(m_IPv6Network->getHighestAddress()));
807
0
    }
808
809
    /// @return The number of addresses in this network, for example: the number of addresses in 16ff::/120 is 256,
810
    /// the number of addresses in 10.10.0.0/24 is 256. If the number of addresses exceeds the size of uint64_t
811
    /// a std::out_of_range exception is thrown
812
    uint64_t getTotalAddressCount() const
813
0
    {
814
0
      return (m_IPv4Network != nullptr ? m_IPv4Network->getTotalAddressCount()
815
0
                                       : m_IPv6Network->getTotalAddressCount());
816
0
    }
817
818
    /// @return True if this is an IPv4 network, false otherwise
819
    bool isIPv4Network() const
820
0
    {
821
0
      return m_IPv4Network != nullptr;
822
0
    }
823
824
    /// @return True if this is an IPv6 network, false otherwise
825
    bool isIPv6Network() const
826
0
    {
827
0
      return m_IPv6Network != nullptr;
828
0
    }
829
830
    /// @param address An IP address
831
    /// @return True is the address belongs to the network, false otherwise or if the address isn't valid
832
    bool includes(const IPAddress& address) const
833
0
    {
834
0
      if (m_IPv4Network != nullptr)
835
0
      {
836
0
        if (address.isIPv6())
837
0
        {
838
0
          return false;
839
0
        }
840
0
841
0
        return m_IPv4Network->includes(address.getIPv4());
842
0
      }
843
0
844
0
      if (address.isIPv4())
845
0
      {
846
0
        return false;
847
0
      }
848
0
849
0
      return m_IPv6Network->includes(address.getIPv6());
850
0
    }
851
852
    /// @param network An IP network
853
    /// @return True is the input network is completely included within this network, false otherwise
854
    bool includes(const IPNetwork& network) const
855
0
    {
856
0
      if (m_IPv4Network != nullptr)
857
0
      {
858
0
        if (network.isIPv6Network())
859
0
        {
860
0
          return false;
861
0
        }
862
0
863
0
        return m_IPv4Network->includes(*network.m_IPv4Network);
864
0
      }
865
0
866
0
      if (network.isIPv4Network())
867
0
      {
868
0
        return false;
869
0
      }
870
0
871
0
      return m_IPv6Network->includes(*network.m_IPv6Network);
872
0
    }
873
874
    /// @return A string representation of the network in a format of NETWORK_PREFIX/PREFIX_LEN, for example:
875
    /// fda7:9f81:6c23:275::/64 or 192.168.0.0/16
876
    std::string toString() const
877
0
    {
878
0
      return (m_IPv4Network != nullptr ? m_IPv4Network->toString() : m_IPv6Network->toString());
879
0
    }
880
881
  private:
882
    std::unique_ptr<IPv4Network> m_IPv4Network;
883
    std::unique_ptr<IPv6Network> m_IPv6Network;
884
  };
885
886
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv4Address& ipv4Address)
887
0
  {
888
0
    oss << ipv4Address.toString();
889
0
    return oss;
890
0
  }
891
892
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv6Address& ipv6Address)
893
0
  {
894
0
    oss << ipv6Address.toString();
895
0
    return oss;
896
0
  }
897
898
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPAddress& ipAddress)
899
0
  {
900
0
    oss << ipAddress.toString();
901
0
    return oss;
902
0
  }
903
904
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv4Network& network)
905
0
  {
906
0
    oss << network.toString();
907
0
    return oss;
908
0
  }
909
910
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv6Network& network)
911
0
  {
912
0
    oss << network.toString();
913
0
    return oss;
914
0
  }
915
916
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPNetwork& network)
917
0
  {
918
0
    oss << network.toString();
919
0
    return oss;
920
0
  }
921
}  // namespace pcpp