Coverage Report

Created: 2025-07-11 07:47

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