Skip to content

Commit 64b30ce

Browse files
committed
WIF - Utils - Introduce IP prefix
TG-36
1 parent 13913f8 commit 64b30ce

File tree

3 files changed

+232
-0
lines changed

3 files changed

+232
-0
lines changed

include/wif/utils/ipPrefix.hpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* @file
3+
* @author Richard Plny <[email protected]>
4+
* @brief IP prefix interface
5+
* Based on:
6+
* https://github.com/CESNET/nemea-modules-ng/blob/main/modules/whitelist/src/ipAddressPrefix.hpp
7+
*
8+
* SPDX-License-Identifier: BSD-3-Clause
9+
*/
10+
11+
#pragma once
12+
13+
#include "wif/storage/ipAddress.hpp"
14+
15+
namespace WIF {
16+
17+
/**
18+
* @brief Class representing an IP prefix (or an IP subnet)
19+
*/
20+
class IpPrefix {
21+
public:
22+
/**
23+
* @brief Max bit lenth of IPv4 prefix
24+
*/
25+
static constexpr size_t IPV4_MAX_PREFIX_LENGTH = 32;
26+
27+
/**
28+
* @brief Max bit lenth of IPv6 prefix
29+
*/
30+
static constexpr size_t IPV6_MAX_PREFIX_LENGTH = 128;
31+
32+
/**
33+
* @brief Construct a new IP Prefix object representing just 1 IP address
34+
*
35+
* @param address single IP address
36+
*/
37+
IpPrefix(const IpAddress& address);
38+
39+
/**
40+
* @brief Construct a new IP Prefix object
41+
* @param addressStr string representation of IP prefix
42+
* @param prefixLength number of bits of the prefix
43+
*/
44+
IpPrefix(const std::string& addressStr, size_t prefixLength);
45+
46+
/**
47+
* @brief Construct a new IP Prefix object
48+
* @param address IP prefix
49+
* @param prefixLength number of bits of the prefix
50+
*/
51+
IpPrefix(const IpAddress& address, size_t prefixLength);
52+
53+
/**
54+
* @brief Getter for the number of bits used by prefix
55+
* @return size_t number of bits of the prefix
56+
*/
57+
size_t prefixLength() const noexcept { return m_prefixLength; }
58+
59+
/**
60+
* @brief Getter for number of IP addresses in the prefix
61+
* @return size_t number of IP addresses in the prefix
62+
*/
63+
size_t size() const noexcept;
64+
65+
/**
66+
* @brief Getter for the prefix address
67+
* @return const IpAddress& prefix address
68+
*/
69+
const IpAddress& getPrefix() const noexcept { return m_prefixAddress; }
70+
71+
/**
72+
* @brief Getter for the prefix mask
73+
* @return const IpAddress& prefix mask
74+
*/
75+
const IpAddress& getMask() const noexcept { return m_prefixMask; }
76+
77+
/**
78+
* @brief Match IP prefix and check if IP address in part of the prefix
79+
* @param ipAddress to be matched
80+
* @return true if ipAddress is in this prefix
81+
* @return false otherwise
82+
*/
83+
bool match(const IpAddress& ipAddress) const noexcept;
84+
85+
/**
86+
* @brief Comparison operator <
87+
* @param l left operand
88+
* @param r right operand
89+
* @return bool true if l is less than r
90+
*/
91+
friend bool operator<(const IpPrefix& l, const IpPrefix& r);
92+
93+
/**
94+
* @brief Comparison operator <
95+
* Used for binary search of IP address in a vector of IP prefixes
96+
* @param l left operand
97+
* @param r right operand
98+
* @return bool true if l is less than r
99+
*/
100+
friend bool operator<(const IpAddress& l, const IpPrefix& r);
101+
102+
/**
103+
* @brief Comparison operator <
104+
* Used for binary search of IP address in a vector of IP prefixes
105+
* @param l left operand
106+
* @param r right operand
107+
* @return bool true if l is less than r
108+
*/
109+
friend bool operator<(const IpPrefix& l, const IpAddress& r);
110+
111+
private:
112+
IpAddress m_prefixAddress;
113+
IpAddress m_prefixMask;
114+
size_t m_prefixLength;
115+
};
116+
117+
} // namespace WIF

src/wif/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set(LIBWIF_SOURCES
1010
regex/regexPattern.cpp
1111
storage/flowFeatures.cpp
1212
storage/ipAddress.cpp
13+
utils/ipPrefix.cpp
1314
)
1415

1516
set(LIBWIF_LIBS

src/wif/utils/ipPrefix.cpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* @file
3+
* @author Richard Plny <[email protected]>
4+
* @brief IP prefix implementation
5+
*
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*/
8+
9+
#include "wif/utils/ipPrefix.hpp"
10+
11+
#include <climits>
12+
#include <cmath>
13+
#include <cstdint>
14+
#include <limits>
15+
16+
namespace {
17+
18+
void validatePrefixLength(size_t prefixLength, size_t maxPrefixLength)
19+
{
20+
if (prefixLength > maxPrefixLength) {
21+
throw std::invalid_argument(
22+
"IP prefix is too long. Given: " + std::to_string(prefixLength)
23+
+ ", max: " + std::to_string(maxPrefixLength));
24+
}
25+
}
26+
27+
WIF::IpAddress createIpV6MaskFromPrefix(size_t prefixLength)
28+
{
29+
uint8_t prefixBytes = prefixLength / 8;
30+
uint8_t prefixBits = prefixLength % 8;
31+
uint8_t data[16];
32+
33+
for (unsigned bytesIndex = 0; bytesIndex < prefixBytes; ++bytesIndex) {
34+
data[bytesIndex] = UINT8_MAX;
35+
}
36+
37+
if (prefixBits != 0U) {
38+
data[prefixBytes] = UINT8_MAX << (CHAR_BIT - prefixBits);
39+
}
40+
41+
return WIF::IpAddress(data, WIF::IpAddress::IpVersion::V6);
42+
}
43+
44+
} // namespace
45+
46+
namespace WIF {
47+
48+
IpPrefix::IpPrefix(const IpAddress& address)
49+
: IpPrefix(address, address.isIPv4() ? IPV4_MAX_PREFIX_LENGTH : IPV6_MAX_PREFIX_LENGTH)
50+
{
51+
}
52+
53+
IpPrefix::IpPrefix(const std::string& addressStr, size_t prefixLength)
54+
: IpPrefix(IpAddress(addressStr), prefixLength)
55+
{
56+
}
57+
58+
IpPrefix::IpPrefix(const IpAddress& address, size_t prefixLength)
59+
: m_prefixLength(prefixLength)
60+
{
61+
if (address.isIPv4()) {
62+
validatePrefixLength(prefixLength, IPV4_MAX_PREFIX_LENGTH);
63+
size_t shift = IPV4_MAX_PREFIX_LENGTH - prefixLength;
64+
m_prefixMask = IpAddress(std::numeric_limits<uint32_t>::max() << shift);
65+
} else {
66+
validatePrefixLength(prefixLength, IPV6_MAX_PREFIX_LENGTH);
67+
m_prefixMask = createIpV6MaskFromPrefix(prefixLength);
68+
}
69+
m_prefixAddress = address & m_prefixMask;
70+
}
71+
72+
size_t IpPrefix::size() const noexcept
73+
{
74+
if (m_prefixAddress.isIPv4()) {
75+
return std::pow(2, IPV4_MAX_PREFIX_LENGTH - m_prefixLength);
76+
} else {
77+
return std::pow(2, IPV6_MAX_PREFIX_LENGTH - m_prefixLength);
78+
}
79+
}
80+
81+
bool IpPrefix::match(const IpAddress& ipAddress) const noexcept
82+
{
83+
if (ipAddress.getVersion() != m_prefixAddress.getVersion()) {
84+
return false;
85+
}
86+
return (ipAddress & m_prefixMask) == m_prefixAddress;
87+
}
88+
89+
bool operator<(const IpPrefix& l, const IpPrefix& r)
90+
{
91+
// IPv4 is before IPv6
92+
if (l.m_prefixAddress.isIPv4() && r.m_prefixAddress.isIPv6()) {
93+
return true;
94+
} else if (l.m_prefixAddress.isIPv6() && r.m_prefixAddress.isIPv4()) {
95+
return false;
96+
} // Now we are sure that both prefixes have the same IP version
97+
98+
if (l.m_prefixAddress == r.m_prefixAddress) {
99+
return l.m_prefixLength < r.m_prefixLength;
100+
}
101+
return l.m_prefixAddress < r.m_prefixAddress;
102+
}
103+
104+
bool operator<(const IpAddress& l, const IpPrefix& r)
105+
{
106+
return l < r.m_prefixAddress;
107+
}
108+
109+
bool operator<(const IpPrefix& l, const IpAddress& r)
110+
{
111+
return l.m_prefixAddress < r;
112+
}
113+
114+
} // namespace WIF

0 commit comments

Comments
 (0)