userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
ip.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/utils/ip.hpp
4
/// @brief IPv4 and IPv6 addresses and networks
5
6
#
include
<
array
>
7
#
include
<
cstddef
>
8
#
include
<
cstdint
>
9
#
include
<
exception
>
10
#
include
<
string
>
11
#
include
<
string_view
>
12
#
include
<
system_error
>
13
#
include
<
vector
>
14
15
#
include
<
sys
/
socket
.
h
>
16
17
#
include
<
fmt
/
format
.
h
>
18
19
#
include
<
userver
/
compiler
/
impl
/
lifetime
.
hpp
>
20
#
include
<
userver
/
utils
/
zstring_view
.
hpp
>
21
22
USERVER_NAMESPACE_BEGIN
23
24
/// @brief IP address parsing, formatting, and related utilities.
25
namespace
utils
::
ip
{
26
27
/// @ingroup userver_containers
28
///
29
/// @brief Base class for IPv4/IPv6 addresses
30
template
<std::size_t N>
31
class
AddressBase
final
{
32
static_assert
(N == 4 || N == 16,
"Address can only be 4 or 16 bytes size"
);
33
34
public
:
35
static
constexpr
std::size_t kAddressSize = N;
36
using
BytesType = std::array<
unsigned
char
, N>;
37
38
AddressBase()
noexcept
: address_({0}) {}
39
explicit
AddressBase(
const
BytesType& address)
40
: address_(address)
41
{}
42
43
/// @brief Get the address in bytes, in network byte order.
44
const
BytesType&
GetBytes
()
const
noexcept
USERVER_IMPL_LIFETIME_BOUND {
return
address_; }
45
46
friend
bool
operator==(
const
AddressBase<N>& a1,
const
AddressBase<N>& a2)
noexcept
{
47
return
a1.address_ == a2.address_;
48
}
49
50
friend
bool
operator!=(
const
AddressBase<N>& a1,
const
AddressBase<N>& a2)
noexcept
{
51
return
a1.address_ != a2.address_;
52
}
53
54
private
:
55
BytesType address_;
56
};
57
58
/// @ingroup userver_containers
59
///
60
/// @brief IPv4 address in network bytes order
61
using
AddressV4
= AddressBase<4>;
62
63
/// @ingroup userver_containers
64
///
65
/// @brief IPv6 address in network bytes order
66
using
AddressV6
= AddressBase<16>;
67
68
template
<
typename
T>
69
concept
IsAddressType
= std::is_same_v<T,
AddressV4
> || std::is_same_v<T,
AddressV6
>;
70
71
/// @brief Create an IPv4 address from an IP address string in dotted decimal form.
72
/// @throw AddressSystemError
73
AddressV4
AddressV4FromString
(
utils
::
zstring_view
str);
74
75
/// @brief Create an IPv6 address from an IP address string in dotted decimal form.
76
AddressV6
AddressV6FromString
(
utils
::
zstring_view
str);
77
78
/// @brief Get the address as a string in dotted decimal format.
79
std::string
AddressV4ToString
(
const
AddressV4
& address);
80
81
/// @brief Get the address as a string in dotted decimal format.
82
std::string
AddressV6ToString
(
const
AddressV6
& address);
83
84
/// @ingroup userver_containers
85
///
86
/// @brief Base class for IPv4/IPv6 network
87
template
<
IsAddressType
Address>
88
class
NetworkBase
final
{
89
public
:
90
using
AddressType = Address;
91
static
constexpr
unsigned
char
kMaximumPrefixLength = std::is_same_v<Address,
AddressV4
> ? 32 : 128;
92
93
NetworkBase()
noexcept
=
default
;
94
95
NetworkBase(
const
AddressType& address,
unsigned
short
prefix_length)
96
: address_(address),
97
prefix_length_(prefix_length)
98
{
99
if
(prefix_length > kMaximumPrefixLength) {
100
throw
std::out_of_range(fmt::format(
101
"{} prefix length is too large"
,
102
std::is_same_v<Address,
AddressV4
> ?
"NetworkV4"
:
"NetworkV6"
103
));
104
}
105
}
106
107
/// @brief Get the address address of network
108
AddressType
GetAddress
()
const
noexcept
{
return
address_; }
109
110
/// @brief Get prefix length of address network
111
unsigned
char
GetPrefixLength
()
const
noexcept
{
return
prefix_length_; }
112
113
/// @brief Returns true if the address is in network
114
bool
ContainsAddress
(
const
AddressType& address)
const
{
115
const
auto
network_bytes = address_.GetBytes();
116
const
auto
address_bytes = address.GetBytes();
117
118
std::uint8_t diff = 0;
119
for
(std::size_t byte_index = 0; byte_index < kMaximumPrefixLength / 8; ++byte_index) {
120
std::uint8_t mask_byte = 0;
121
if
(byte_index == prefix_length_ / 8) {
122
mask_byte = ~((1 << (8 - prefix_length_ % 8)) - 1);
123
}
124
if
(byte_index < prefix_length_ / 8) {
125
mask_byte = 255;
126
}
127
128
diff |= (network_bytes[byte_index] ^ address_bytes[byte_index]) & mask_byte;
129
}
130
return
!diff;
131
}
132
133
friend
bool
operator==(
const
NetworkBase<Address>& a,
const
NetworkBase<Address>& b)
noexcept
{
134
return
a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;
135
}
136
137
private
:
138
AddressType address_;
139
unsigned
char
prefix_length_ = 0;
140
};
141
142
/// @ingroup userver_containers
143
///
144
/// @brief IPv4 network.
145
using
NetworkV4
= NetworkBase<
AddressV4
>;
146
147
/// @ingroup userver_containers
148
///
149
/// @brief IPv6 network.
150
using
NetworkV6
= NetworkBase<
AddressV6
>;
151
152
///@brief Create an IPv4 network from a string containing IP address and prefix
153
/// length.
154
/// @throw std::invalid_argument, AddressSystemError
155
NetworkV4
NetworkV4FromString
(std::string_view str);
156
157
/// @brief Create an IPv6 network from a string containing IP address and prefix
158
/// length.
159
NetworkV6
NetworkV6FromString
(std::string_view str);
160
161
///@brief Get the network as an address in dotted decimal format.
162
std::string
NetworkV4ToString
(
const
NetworkV4
& network);
163
164
/// @brief Get the network as an address in dotted decimal format.
165
std::string
NetworkV6ToString
(
const
NetworkV6
& network);
166
167
/// @brief Convert NetworkV4 to CIDR format
168
NetworkV4
TransformToCidrFormat
(
NetworkV4
network);
169
170
/// @brief Convert NetworkV4 to CIDR format
171
NetworkV6
TransformToCidrFormat
(
NetworkV6
network);
172
173
/// @ingroup userver_containers
174
///
175
/// @brief INET IPv4/IPv4 network
176
/// @warning InetNetwork class is deprecated. You should use InetNetwork class
177
/// via transformation function to/from NetworkV4/NetworkV6.
178
/// Use this class only if you need to work with INET PostgreSQL format.
179
class
InetNetwork
final
{
180
public
:
181
enum
class
AddressFamily :
unsigned
char
{ kIPv4 = AF_INET, kIPv6 = AF_INET6 };
182
183
// Default constructor: IPv4 address
184
InetNetwork();
185
InetNetwork(std::vector<
unsigned
char
>&& bytes,
unsigned
char
prefix_length, AddressFamily address_family);
186
187
/// @brief Get the address in bytes
188
const
std::vector<
unsigned
char
>&
GetBytes
()
const
noexcept
USERVER_IMPL_LIFETIME_BOUND {
return
bytes_; }
189
190
/// @brief Get the prefix length of network
191
unsigned
char
GetPrefixLength
()
const
noexcept
{
return
prefix_length_; }
192
193
/// @brief Get the address family
194
AddressFamily
GetAddressFamily
()
const
noexcept
{
return
address_family_; }
195
196
friend
bool
operator==(
const
InetNetwork& lhs,
const
InetNetwork& rhs) {
197
return
lhs.address_family_ == rhs.address_family_ && lhs.prefix_length_ == rhs.prefix_length_ &&
198
lhs.bytes_ == rhs.bytes_;
199
}
200
201
friend
bool
operator!=(
const
InetNetwork& lhs,
const
InetNetwork& rhs) {
return
!operator==(lhs, rhs); }
202
203
private
:
204
std::vector<
unsigned
char
> bytes_;
205
unsigned
char
prefix_length_;
206
AddressFamily address_family_;
207
};
208
209
/// @brief Convert InetNetwork to NetworkV4
210
NetworkV4
NetworkV4FromInetNetwork
(
const
InetNetwork& inet_network);
211
212
/// @brief Convert InetNetwork to NetworkV6
213
NetworkV6
NetworkV6FromInetNetwork
(
const
InetNetwork& inet_network);
214
215
/// @brief Convert NetworkV4 to InetNetwork
216
InetNetwork
NetworkV4ToInetNetwork
(
const
NetworkV4
& network);
217
218
/// @brief Convert NetworkV6 to InetNetwork
219
InetNetwork
NetworkV6ToInetNetwork
(
const
NetworkV6
& network);
220
221
/// @brief Invalid network or address
222
class
AddressSystemError
final
:
public
std::exception {
223
public
:
224
AddressSystemError(std::error_code code, std::string_view msg)
225
: msg_(msg),
226
code_(code)
227
{}
228
229
/// Operating system error code.
230
const
std::error_code&
Code
()
const
{
return
code_; }
231
232
const
char
* what()
const
noexcept
final
{
return
msg_.c_str(); }
233
234
private
:
235
std::string msg_;
236
std::error_code code_;
237
};
238
239
}
// namespace utils::ip
240
241
USERVER_NAMESPACE_END
userver
utils
ip.hpp
Generated on
for userver by
Doxygen
1.17.0