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
/// @brief Returns true if `host` is an IPv4 or IPv6 address.
85
bool
IsIpAddress
(std::string_view host)
noexcept
;
86
87
/// @brief Same as @ref IsIpAddress, but slightly faster.
88
bool
IsNulTerminatedIpAddress
(
utils
::
zstring_view
host)
noexcept
;
89
90
/// @ingroup userver_containers
91
///
92
/// @brief Base class for IPv4/IPv6 network
93
template
<
IsAddressType
Address>
94
class
NetworkBase
final
{
95
public
:
96
using
AddressType = Address;
97
static
constexpr
unsigned
char
kMaximumPrefixLength = std::is_same_v<Address,
AddressV4
> ? 32 : 128;
98
99
NetworkBase()
noexcept
=
default
;
100
101
NetworkBase(
const
AddressType& address,
unsigned
short
prefix_length)
102
: address_(address),
103
prefix_length_(prefix_length)
104
{
105
if
(prefix_length > kMaximumPrefixLength) {
106
throw
std::out_of_range(fmt::format(
107
"{} prefix length is too large"
,
108
std::is_same_v<Address,
AddressV4
> ?
"NetworkV4"
:
"NetworkV6"
109
));
110
}
111
}
112
113
/// @brief Get the address address of network
114
AddressType
GetAddress
()
const
noexcept
{
return
address_; }
115
116
/// @brief Get prefix length of address network
117
unsigned
char
GetPrefixLength
()
const
noexcept
{
return
prefix_length_; }
118
119
/// @brief Returns true if the address is in network
120
bool
ContainsAddress
(
const
AddressType& address)
const
{
121
const
auto
network_bytes = address_.GetBytes();
122
const
auto
address_bytes = address.GetBytes();
123
124
std::uint8_t diff = 0;
125
for
(std::size_t byte_index = 0; byte_index < kMaximumPrefixLength / 8; ++byte_index) {
126
std::uint8_t mask_byte = 0;
127
if
(byte_index == prefix_length_ / 8) {
128
mask_byte = ~((1 << (8 - prefix_length_ % 8)) - 1);
129
}
130
if
(byte_index < prefix_length_ / 8) {
131
mask_byte = 255;
132
}
133
134
diff |= (network_bytes[byte_index] ^ address_bytes[byte_index]) & mask_byte;
135
}
136
return
!diff;
137
}
138
139
friend
bool
operator==(
const
NetworkBase<Address>& a,
const
NetworkBase<Address>& b)
noexcept
{
140
return
a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_;
141
}
142
143
private
:
144
AddressType address_;
145
unsigned
char
prefix_length_ = 0;
146
};
147
148
/// @ingroup userver_containers
149
///
150
/// @brief IPv4 network.
151
using
NetworkV4
= NetworkBase<
AddressV4
>;
152
153
/// @ingroup userver_containers
154
///
155
/// @brief IPv6 network.
156
using
NetworkV6
= NetworkBase<
AddressV6
>;
157
158
///@brief Create an IPv4 network from a string containing IP address and prefix
159
/// length.
160
/// @throw std::invalid_argument, AddressSystemError
161
NetworkV4
NetworkV4FromString
(std::string_view str);
162
163
/// @brief Create an IPv6 network from a string containing IP address and prefix
164
/// length.
165
NetworkV6
NetworkV6FromString
(std::string_view str);
166
167
///@brief Get the network as an address in dotted decimal format.
168
std::string
NetworkV4ToString
(
const
NetworkV4
& network);
169
170
/// @brief Get the network as an address in dotted decimal format.
171
std::string
NetworkV6ToString
(
const
NetworkV6
& network);
172
173
/// @brief Convert NetworkV4 to CIDR format
174
NetworkV4
TransformToCidrFormat
(
NetworkV4
network);
175
176
/// @brief Convert NetworkV4 to CIDR format
177
NetworkV6
TransformToCidrFormat
(
NetworkV6
network);
178
179
/// @ingroup userver_containers
180
///
181
/// @brief INET IPv4/IPv4 network
182
/// @warning InetNetwork class is deprecated. You should use InetNetwork class
183
/// via transformation function to/from NetworkV4/NetworkV6.
184
/// Use this class only if you need to work with INET PostgreSQL format.
185
class
InetNetwork
final
{
186
public
:
187
enum
class
AddressFamily :
unsigned
char
{ kIPv4 = AF_INET, kIPv6 = AF_INET6 };
188
189
// Default constructor: IPv4 address
190
InetNetwork();
191
InetNetwork(std::vector<
unsigned
char
>&& bytes,
unsigned
char
prefix_length, AddressFamily address_family);
192
193
/// @brief Get the address in bytes
194
const
std::vector<
unsigned
char
>&
GetBytes
()
const
noexcept
USERVER_IMPL_LIFETIME_BOUND {
return
bytes_; }
195
196
/// @brief Get the prefix length of network
197
unsigned
char
GetPrefixLength
()
const
noexcept
{
return
prefix_length_; }
198
199
/// @brief Get the address family
200
AddressFamily
GetAddressFamily
()
const
noexcept
{
return
address_family_; }
201
202
friend
bool
operator==(
const
InetNetwork& lhs,
const
InetNetwork& rhs) {
203
return
lhs.address_family_ == rhs.address_family_ && lhs.prefix_length_ == rhs.prefix_length_ &&
204
lhs.bytes_ == rhs.bytes_;
205
}
206
207
friend
bool
operator!=(
const
InetNetwork& lhs,
const
InetNetwork& rhs) {
return
!operator==(lhs, rhs); }
208
209
private
:
210
std::vector<
unsigned
char
> bytes_;
211
unsigned
char
prefix_length_;
212
AddressFamily address_family_;
213
};
214
215
/// @brief Convert InetNetwork to NetworkV4
216
NetworkV4
NetworkV4FromInetNetwork
(
const
InetNetwork& inet_network);
217
218
/// @brief Convert InetNetwork to NetworkV6
219
NetworkV6
NetworkV6FromInetNetwork
(
const
InetNetwork& inet_network);
220
221
/// @brief Convert NetworkV4 to InetNetwork
222
InetNetwork
NetworkV4ToInetNetwork
(
const
NetworkV4
& network);
223
224
/// @brief Convert NetworkV6 to InetNetwork
225
InetNetwork
NetworkV6ToInetNetwork
(
const
NetworkV6
& network);
226
227
/// @brief Invalid network or address
228
class
AddressSystemError
final
:
public
std::exception {
229
public
:
230
AddressSystemError(std::error_code code, std::string_view msg)
231
: msg_(msg),
232
code_(code)
233
{}
234
235
/// Operating system error code.
236
const
std::error_code&
Code
()
const
{
return
code_; }
237
238
const
char
* what()
const
noexcept
final
{
return
msg_.c_str(); }
239
240
private
:
241
std::string msg_;
242
std::error_code code_;
243
};
244
245
}
// namespace utils::ip
246
247
USERVER_NAMESPACE_END
userver
utils
ip.hpp
Generated on
for userver by
Doxygen
1.17.0