Coverage Report

Created: 2026-05-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Common++/header/IpAddress.h
Line
Count
Source
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
0
    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
0
    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_NetworkVariant = IPv4Network(address.getIPv4(), prefixLen);
671
0
      }
672
0
      else
673
0
      {
674
0
        m_NetworkVariant = 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_NetworkVariant = IPv4Network(address.getIPv4(), netmask);
692
0
      }
693
0
      else
694
0
      {
695
0
        m_NetworkVariant = 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_NetworkVariant = IPv4Network(addressAndNetmask);
712
0
      }
713
0
      catch (const std::invalid_argument&)
714
0
      {
715
0
        m_NetworkVariant = 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) : m_NetworkVariant(other.m_NetworkVariant)
722
0
    {}
723
724
    /// Overload of an assignment operator.
725
    /// @param[in] other An instance of IPNetwork to assign
726
    /// @return A reference to the assignee
727
    IPNetwork& operator=(const IPNetwork& other)
728
0
    {
729
0
      m_NetworkVariant = other.m_NetworkVariant;
730
0
      return *this;
731
0
    }
732
733
    /// Overload of an assignment operator.
734
    /// @param[in] other An instance of IPv4Network to assign
735
    /// @return A reference to the assignee
736
    IPNetwork& operator=(const IPv4Network& other)
737
0
    {
738
0
      m_NetworkVariant = other;
739
0
      return *this;
740
0
    }
741
742
    /// Overload of an assignment operator.
743
    /// @param[in] other An instance of IPv6Network to assign
744
    /// @return A reference to the assignee
745
    IPNetwork& operator=(const IPv6Network& other)
746
0
    {
747
0
      m_NetworkVariant = other;
748
0
      return *this;
749
0
    }
750
751
    /// @return The prefix length, for example: the prefix length of 3546::/ffff:: is 16, the prefix length of
752
    /// 10.10.10.10/255.0.0.0 is 8
753
    uint8_t getPrefixLen() const
754
0
    {
755
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
756
0
      if (ip4 != nullptr)
757
0
      {
758
0
        return ip4->getPrefixLen();
759
0
      }
760
0
761
0
      return m_NetworkVariant.getIPv6().getPrefixLen();
762
0
    }
763
764
    /// @return The netmask, for example: the netmask of 3546::/16 is ffff::, the netmask of 10.10.10.10/8 is
765
    /// 255.0.0.0
766
    std::string getNetmask() const
767
0
    {
768
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
769
0
      if (ip4 != nullptr)
770
0
      {
771
0
        return ip4->getNetmask();
772
0
      }
773
0
774
0
      return m_NetworkVariant.getIPv6().getNetmask();
775
0
    }
776
777
    /// @return The network prefix, for example: the network prefix of 3546:f321::/16 is 3546::, the network prefix
778
    /// of 10.10.10.10/16 is 10.10.0.0
779
    IPAddress getNetworkPrefix() const
780
0
    {
781
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
782
0
      if (ip4 != nullptr)
783
0
      {
784
0
        return IPAddress(ip4->getNetworkPrefix());
785
0
      }
786
0
787
0
      return IPAddress(m_NetworkVariant.getIPv6().getNetworkPrefix());
788
0
    }
789
790
    /// @return The lowest non-reserved IP address in this network, for example: the lowest address in 3546::/16 is
791
    /// 3546::1, the lowest address in 10.10.10.10/16 is 10.10.0.1
792
    IPAddress getLowestAddress() const
793
0
    {
794
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
795
0
      if (ip4 != nullptr)
796
0
      {
797
0
        return IPAddress(ip4->getLowestAddress());
798
0
      }
799
0
      return IPAddress(m_NetworkVariant.getIPv6().getLowestAddress());
800
0
    }
801
802
    /// @return The highest non-reserved IP address in this network, for example: the highest address in 3546::/16
803
    /// is 3546:ffff:ffff:ffff:ffff:ffff:ffff:ffff, the highest address in 10.10.10.10/16 is 10.10.255.254
804
    IPAddress getHighestAddress() const
805
0
    {
806
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
807
0
      if (ip4 != nullptr)
808
0
      {
809
0
        return IPAddress(ip4->getHighestAddress());
810
0
      }
811
0
812
0
      return IPAddress(m_NetworkVariant.getIPv6().getHighestAddress());
813
0
    }
814
815
    /// @return The number of addresses in this network, for example: the number of addresses in 16ff::/120 is 256,
816
    /// the number of addresses in 10.10.0.0/24 is 256. If the number of addresses exceeds the size of uint64_t
817
    /// a std::out_of_range exception is thrown
818
    uint64_t getTotalAddressCount() const
819
0
    {
820
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
821
0
      if (ip4 != nullptr)
822
0
      {
823
0
        return ip4->getTotalAddressCount();
824
0
      }
825
0
      return m_NetworkVariant.getIPv6().getTotalAddressCount();
826
0
    }
827
828
    /// @return True if this is an IPv4 network, false otherwise
829
    bool isIPv4Network() const
830
0
    {
831
0
      return m_NetworkVariant.getType() == NetworkVariant::Type::IPv4;
832
0
    }
833
834
    /// @return True if this is an IPv6 network, false otherwise
835
    bool isIPv6Network() const
836
0
    {
837
0
      return m_NetworkVariant.getType() == NetworkVariant::Type::IPv6;
838
0
    }
839
840
    /// @param address An IP address
841
    /// @return True is the address belongs to the network, false otherwise or if the address isn't valid
842
    bool includes(const IPAddress& address) const
843
0
    {
844
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
845
0
      if (ip4 != nullptr)
846
0
      {
847
0
        if (address.isIPv6())
848
0
        {
849
0
          return false;
850
0
        }
851
0
        return ip4->includes(address.getIPv4());
852
0
      }
853
0
854
0
      if (address.isIPv4())
855
0
      {
856
0
        return false;
857
0
      }
858
0
859
0
      return m_NetworkVariant.getIPv6().includes(address.getIPv6());
860
0
    }
861
862
    /// @param network An IP network
863
    /// @return True is the input network is completely included within this network, false otherwise
864
    bool includes(const IPNetwork& network) const
865
0
    {
866
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
867
0
      if (ip4 != nullptr)
868
0
      {
869
0
        auto otherIp4 = network.m_NetworkVariant.tryGetIPv4();
870
0
        if (otherIp4 == nullptr)
871
0
        {
872
0
          return false;
873
0
        }
874
0
        return ip4->includes(*otherIp4);
875
0
      }
876
0
877
0
      auto& ip6 = m_NetworkVariant.getIPv6();
878
0
      auto otherIp6 = network.m_NetworkVariant.tryGetIPv6();
879
0
      if (otherIp6 == nullptr)
880
0
      {
881
0
        return false;
882
0
      }
883
0
      return ip6.includes(*otherIp6);
884
0
    }
885
886
    /// @return A string representation of the network in a format of NETWORK_PREFIX/PREFIX_LEN, for example:
887
    /// fda7:9f81:6c23:275::/64 or 192.168.0.0/16
888
    std::string toString() const
889
0
    {
890
0
      auto ip4 = m_NetworkVariant.tryGetIPv4();
891
0
      if (ip4)
892
0
      {
893
0
        return ip4->toString();
894
0
      }
895
896
0
      return m_NetworkVariant.getIPv6().toString();
897
0
    }
898
899
  private:
900
    // TODO: C++17 Replace with std::variant.
901
    class NetworkVariant
902
    {
903
    public:
904
      enum class Type
905
      {
906
        IPv4,
907
        IPv6
908
      };
909
910
      NetworkVariant() : m_Type(Type::IPv4), m_IPv4Net(IPv4Address::Zero)
911
0
      {}
912
      NetworkVariant(IPv4Network const& net) : m_Type(Type::IPv4), m_IPv4Net(net)
913
0
      {}
914
      NetworkVariant(IPv6Network const& net) : m_Type(Type::IPv6), m_IPv6Net(net)
915
0
      {}
916
      ~NetworkVariant()
917
0
      {
918
0
        destroyActiveMem();
919
0
      }
920
921
      NetworkVariant& operator=(IPv4Network const& other)
922
0
      {
923
0
        swapTo(Type::IPv4);
924
0
        m_IPv4Net = other;
925
0
        return *this;
926
0
      }
927
      NetworkVariant& operator=(IPv6Network const& other)
928
0
      {
929
0
        swapTo(Type::IPv6);
930
0
        m_IPv6Net = other;
931
0
        return *this;
932
0
      }
933
      NetworkVariant& operator=(NetworkVariant const& other)
934
0
      {
935
0
        swapTo(other.m_Type);
936
0
        switch (other.m_Type)
937
0
        {
938
0
        case Type::IPv4:
939
0
          m_IPv4Net = other.m_IPv4Net;
940
0
          break;
941
0
        case Type::IPv6:
942
0
          m_IPv6Net = other.m_IPv6Net;
943
0
          break;
944
0
        }
945
0
        return *this;
946
0
      }
947
948
      Type getType() const noexcept
949
0
      {
950
0
        return m_Type;
951
0
      }
952
953
      IPv4Network& getIPv4()
954
0
      {
955
0
        throwIfNot(Type::IPv4);
956
0
        return m_IPv4Net;
957
0
      }
958
959
      IPv4Network const& getIPv4() const
960
0
      {
961
0
        throwIfNot(Type::IPv4);
962
0
        return m_IPv4Net;
963
0
      }
964
965
      IPv4Network* tryGetIPv4() noexcept
966
0
      {
967
0
        return (m_Type == Type::IPv4) ? &m_IPv4Net : nullptr;
968
0
      }
969
      IPv4Network const* tryGetIPv4() const noexcept
970
0
      {
971
0
        return (m_Type == Type::IPv4) ? &m_IPv4Net : nullptr;
972
0
      }
973
974
      IPv6Network& getIPv6()
975
0
      {
976
0
        throwIfNot(Type::IPv6);
977
0
        return m_IPv6Net;
978
0
      }
979
980
      IPv6Network const& getIPv6() const
981
0
      {
982
0
        throwIfNot(Type::IPv6);
983
0
        return m_IPv6Net;
984
0
      }
985
986
      IPv6Network* tryGetIPv6() noexcept
987
0
      {
988
0
        return (m_Type == Type::IPv6) ? &m_IPv6Net : nullptr;
989
0
      }
990
      IPv6Network const* tryGetIPv6() const noexcept
991
0
      {
992
0
        return (m_Type == Type::IPv6) ? &m_IPv6Net : nullptr;
993
0
      }
994
995
    private:
996
      void throwIfNot(Type type) const
997
0
      {
998
0
        if (type != m_Type)
999
0
        {
1000
0
          throw std::runtime_error("Bad variant access");
1001
0
        }
1002
0
      }
1003
1004
      void swapTo(Type newType) noexcept;
1005
      void destroyActiveMem() noexcept;
1006
1007
      Type m_Type;
1008
      union {
1009
        IPv4Network m_IPv4Net;
1010
        IPv6Network m_IPv6Net;
1011
      };
1012
    };
1013
1014
    NetworkVariant m_NetworkVariant;
1015
  };
1016
1017
  namespace literals
1018
  {
1019
    inline IPv4Address operator""_ipv4(const char* addrString, std::size_t size)
1020
0
    {
1021
0
      return IPv4Address(std::string(addrString, size));
1022
0
    }
1023
1024
    inline IPv6Address operator""_ipv6(const char* addrString, std::size_t size)
1025
0
    {
1026
0
      return IPv6Address(std::string(addrString, size));
1027
0
    }
1028
  }  // namespace literals
1029
1030
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv4Address& ipv4Address)
1031
0
  {
1032
0
    oss << ipv4Address.toString();
1033
0
    return oss;
1034
0
  }
1035
1036
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv6Address& ipv6Address)
1037
0
  {
1038
0
    oss << ipv6Address.toString();
1039
0
    return oss;
1040
0
  }
1041
1042
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPAddress& ipAddress)
1043
0
  {
1044
0
    oss << ipAddress.toString();
1045
0
    return oss;
1046
0
  }
1047
1048
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv4Network& network)
1049
0
  {
1050
0
    oss << network.toString();
1051
0
    return oss;
1052
0
  }
1053
1054
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPv6Network& network)
1055
0
  {
1056
0
    oss << network.toString();
1057
0
    return oss;
1058
0
  }
1059
1060
  inline std::ostream& operator<<(std::ostream& oss, const pcpp::IPNetwork& network)
1061
0
  {
1062
0
    oss << network.toString();
1063
0
    return oss;
1064
0
  }
1065
}  // namespace pcpp