MySQL 8.4.0
Source Code Documentation
netif.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_NET_TS_IMPL_NETIF_H_
27#define MYSQL_HARNESS_NET_TS_IMPL_NETIF_H_
28
29#include <algorithm> // find_if
30#include <forward_list>
31#include <list>
32#include <string>
33#include <string_view>
34
35#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
36 defined(__sun__)
37#define HAVE_IFADDRS_H
38#endif
39
40#ifdef HAVE_IFADDRS_H
41#include <ifaddrs.h> // getifaddr
42#include <net/if.h> // IFF_UP
43// linux/if.h defines
44//
45// - IFF_LOWER_UP
46// - IFF_DORMANT
47// - IFF_ECHO
48#include <netinet/in.h> // sockaddr_in
49#endif
50#if defined(_WIN32)
51// needs to be included before iphlpapi.h
52#include <winsock2.h>
53
54#pragma comment(lib, "iphlpapi.lib")
55#include <iphlpapi.h>
56#endif
57
60
61namespace net {
62
63/**
64 * flags of the network interface.
65 */
67 public:
68 // should be 'unsigned int' which should be least32
69 //
70 // ... on the other side there is SIOC[GS]LIFFFLAGS on solaris which makes the
71 // flags 64bit
72#ifdef _WIN32
73 using value_type = decltype(IP_ADAPTER_ADDRESSES::Flags);
74#else
75 using value_type = decltype(ifaddrs::ifa_flags);
76#endif
77
78 constexpr InterfaceFlag(value_type v) noexcept : v_{v} {}
79
80 constexpr value_type value() const { return v_; }
81
82 private:
84};
85
86/**
87 * networks of a network interface.
88 */
89template <class NetworkT>
91 public:
92 using value_type = NetworkT;
93 using container_type = std::list<value_type>;
94 using const_reference = const value_type &;
96 using const_iterator = typename container_type::const_iterator;
98 using difference_type = ptrdiff_t;
99 using size_type = size_t;
100
101 size_type max_size() const noexcept { return nets_.max_size(); }
102 bool empty() const noexcept { return nets_.empty(); }
103
104 const_iterator begin() const { return nets_.begin(); }
105 const_iterator end() const { return nets_.end(); }
106
107 void push_back(const value_type &v) { nets_.push_back(v); }
108
109 /**
110 * emplace an object in the container.
111 *
112 * object is created directly inplace in the container.
113 */
114 template <class... Args>
115 auto emplace_back(Args &&... args) {
116 return nets_.emplace_back(std::forward<Args>(args)...);
117 }
118
119 private:
121};
122
123/**
124 * an entry in the network interface result.
125 */
127 public:
129
130 NetworkInterfaceEntry(std::string id, std::string display_name,
132 : id_{std::move(id)},
134 flags_{flags} {}
135
136 std::string id() const { return id_; }
137 std::string display_name() const { return display_name_; }
138 flags_type flags() const { return flags_; }
139
141 return net_v4_s_;
142 }
143
145 return net_v4_s_;
146 }
147
149 return net_v6_s_;
150 }
151
153 return net_v6_s_;
154 }
155
156 private:
157 std::string id_;
158 std::string display_name_;
162};
163
164/**
165 * results of a NetworkInterfaceResolver::query().
166 */
168 public:
172 using const_iterator = typename std::forward_list<value_type>::const_iterator;
174 using difference_type = ptrdiff_t;
175 using size_type = size_t;
176
178
179 size_type size() const noexcept { return size_; }
180 size_type max_size() const noexcept { return results_.max_size(); }
181 bool empty() const noexcept { return results_.empty(); }
182
183 const_iterator begin() const { return results_.begin(); }
184 const_iterator end() const { return results_.end(); }
185 const_iterator cbegin() const { return results_.cbegin(); }
186 const_iterator cend() const { return results_.cend(); }
187
188 protected:
190
191#ifdef HAVE_IFADDRS_H
192 /**
193 * get the prefix length of a netmask.
194 *
195 * - on IPv6 addresses the prefix length may be 128 bit
196 * - on IPv4 addresses 32bit
197 *
198 * In '127.0.0.1/8', the /8 means:
199 *
200 * - number of consecutive bits set in the netmask starting from the MSB
201 *
202 * `/8` in IPv4: 255.0.0.0
203 * `/8` in IPv6: :ff00:...
204 */
205 template <class BytesClass>
206 static constexpr int get_prefix_len(const BytesClass &mask) {
207 // count prefix-len
208 int prefix_len{0};
209
210 // can't use for-range-loop here as .begin() isn't constexpr
211 for (size_t ndx{}; ndx < mask.size(); ++ndx) {
212 uint8_t mask_byte = mask[ndx];
213
214 for (uint8_t b = mask_byte; b & 0x80; b <<= 1, ++prefix_len)
215 ;
216
217 // if all bytes were set, check the next byte
218 if (mask_byte != 0xff) break;
219 }
220
221 return prefix_len;
222 }
223
224 NetworkInterfaceResults(ifaddrs *ifs) {
225 // cleanup the ifaddrs when done
226 struct scoped_ifaddrs {
227 constexpr scoped_ifaddrs(ifaddrs *captured_ifaddrs)
228 : ifaddrs_{captured_ifaddrs} {}
229 ~scoped_ifaddrs() {
230 if (ifaddrs_) ::freeifaddrs(ifaddrs_);
231 }
232 ifaddrs *ifaddrs_;
233 } sifs{ifs};
234
235 auto tail = results_.before_begin();
236
237 /*
238 * ifaddrs is a list of:
239 *
240 * - AF_INET, lo0, 127.0.0.1
241 * - AF_INET6, lo0, ::1
242 *
243 * the result we return is:
244 *
245 * lo0:
246 * - AF_INET, 127.0.0.1
247 * - AF_INET6, ::1
248 */
249 for (auto cur = ifs; cur != nullptr; cur = cur->ifa_next) {
250 // if the interface-name isn't found yet, insert it.
251 if ((results_.end() == std::find_if(results_.begin(), results_.end(),
252 [&cur](const auto &v) {
253 return v.id() == cur->ifa_name;
254 }))) {
255 // not found
256 tail = results_.emplace_after(tail, cur->ifa_name, cur->ifa_name,
257 cur->ifa_flags);
258 ++size_;
259 }
260
261 auto cur_res_it = std::find_if(
262 results_.begin(), results_.end(),
263 [&cur](const auto &v) { return v.id() == cur->ifa_name; });
264
265 if (cur->ifa_addr) {
266 // if a address family is assigned, capture it.
267 switch (cur->ifa_addr->sa_family) {
268 case AF_INET: {
269 auto *sa = reinterpret_cast<const sockaddr_in *>(cur->ifa_addr);
271
272 if (bytes.size() < sizeof(sa->sin_addr.s_addr)) std::terminate();
273 std::memcpy(bytes.data(), &(sa->sin_addr), sizeof(sa->sin_addr));
274
275 net::ip::address_v4 addr{bytes};
276
277 sa = reinterpret_cast<const sockaddr_in *>(cur->ifa_netmask);
278 if (bytes.size() < sizeof(sa->sin_addr.s_addr)) std::terminate();
279 std::memcpy(bytes.data(), &(sa->sin_addr.s_addr),
280 sizeof(sa->sin_addr.s_addr));
281 net::ip::address_v4 netmask{bytes};
282
283 auto prefix_len = get_prefix_len(netmask.to_bytes());
284 cur_res_it->v4_networks().emplace_back(addr, prefix_len);
285
286 // check get_prefix_len works for v4-addresses
287 static_assert(get_prefix_len(net::ip::address_v4::bytes_type(
288 0x80, 0x00, 0x00, 0x00)) == 1,
289 "");
290 static_assert(get_prefix_len(net::ip::address_v4::bytes_type(
291 0xff, 0x00, 0x00, 0x00)) == 8,
292 "");
293 static_assert(get_prefix_len(net::ip::address_v4::bytes_type(
294 0xff, 0x80, 0x00, 0x00)) == 9,
295 "");
296
297 // invalid case.
298 static_assert(get_prefix_len(net::ip::address_v4::bytes_type(
299 0x00, 0x80, 0x00, 0x00)) == 0,
300 "");
301
302 break;
303 }
304 case AF_INET6: {
305 auto *sa = reinterpret_cast<const sockaddr_in6 *>(cur->ifa_addr);
307
308 if (bytes.size() < sizeof(sa->sin6_addr.s6_addr)) std::terminate();
309
310 std::memcpy(bytes.data(), &(sa->sin6_addr.s6_addr),
311 sizeof(sa->sin6_addr.s6_addr));
312 net::ip::address_v6 addr{bytes, sa->sin6_scope_id};
313
314 sa = reinterpret_cast<const sockaddr_in6 *>(cur->ifa_netmask);
315 if (bytes.size() < sizeof(sa->sin6_addr.s6_addr)) std::terminate();
316 std::memcpy(bytes.data(), &(sa->sin6_addr.s6_addr),
317 sizeof(sa->sin6_addr.s6_addr));
318 net::ip::address_v6 netmask{bytes};
319
320 auto prefix_len = get_prefix_len(netmask.to_bytes());
321 cur_res_it->v6_networks().emplace_back(addr, prefix_len);
322
323 break;
324 }
325 default:
326 // ignore the other address-family types
327 break;
328 }
329 }
330 }
331 }
332
333#elif defined(_WIN32)
334 static stdx::expected<std::string, std::error_code> convert_wstring_to_utf8(
335 const std::wstring_view &ws) {
336 std::string out;
337
338 // first, call it with 0 to get the buffer length
339 auto out_len = WideCharToMultiByte(CP_UTF8, 0, ws.data(), ws.size(),
340 nullptr, 0, nullptr, nullptr);
341
342 if (0 == out_len) {
343 return stdx::unexpected(
344 std::error_code(GetLastError(), std::system_category()));
345 }
346
347 out.resize(out_len);
348
349 out_len =
350 WideCharToMultiByte(CP_UTF8, 0, ws.data(), ws.size(), &out.front(),
351 out.capacity(), nullptr, nullptr);
352 if (0 == out_len) {
353 return stdx::unexpected(
354 std::error_code(GetLastError(), std::system_category()));
355 }
356
357 out.resize(out_len);
358
359 return out;
360 }
361
363 std::unique_ptr<IP_ADAPTER_ADDRESSES, decltype(&free)> &&ifs) {
364 auto tail = results_.before_begin();
365
366 for (auto cur = ifs.get(); cur; cur = cur->Next) {
367 tail = results_.emplace_after(tail, std::string{cur->AdapterName},
368 convert_wstring_to_utf8(cur->Description)
369 .value_or("<invalid-wstring>"),
370 cur->Flags);
371 ++size_;
372
373 auto cur_res_it = std::find_if(
374 results_.begin(), results_.end(),
375 [&cur](const auto &v) { return v.id() == cur->AdapterName; });
376
377 for (auto cur_unicast_addr = cur->FirstUnicastAddress; cur_unicast_addr;
378 cur_unicast_addr = cur_unicast_addr->Next) {
379 if (cur_unicast_addr->Address.lpSockaddr->sa_family == AF_INET) {
380 auto *sa = reinterpret_cast<const sockaddr_in *>(
381 cur_unicast_addr->Address.lpSockaddr);
383 std::memcpy(bytes.data(), &(sa->sin_addr.s_addr),
384 sizeof(sa->sin_addr.s_addr));
385 net::ip::address_v4 addr{bytes};
386
387 cur_res_it->v4_networks().emplace_back(
388 addr, cur_unicast_addr->OnLinkPrefixLength);
389 } else {
390 auto *sa = reinterpret_cast<const sockaddr_in6 *>(
391 cur_unicast_addr->Address.lpSockaddr);
393 std::memcpy(bytes.data(), &(sa->sin6_addr.s6_addr),
394 sizeof(sa->sin6_addr.s6_addr));
395 net::ip::address_v6 addr{bytes, sa->sin6_scope_id};
396 cur_res_it->v6_networks().emplace_back(
397 addr, cur_unicast_addr->OnLinkPrefixLength);
398 }
399 }
400 }
401 }
402#endif
403
404 std::forward_list<value_type> results_;
405 size_t size_{0};
406};
407
409 public:
411#ifdef _WIN32
412 unsigned long ifs_size{0};
413 auto res =
414 ::GetAdaptersAddresses(AF_UNSPEC, 0, nullptr, nullptr, &ifs_size);
415
416 if (res != ERROR_BUFFER_OVERFLOW) {
417 return stdx::unexpected(
418 std::error_code{static_cast<int>(res), std::system_category()});
419 }
420
421 std::unique_ptr<IP_ADAPTER_ADDRESSES, decltype(&free)> ifs(
422 reinterpret_cast<IP_ADAPTER_ADDRESSES *>(malloc(ifs_size)), &free);
423
424 res = ::GetAdaptersAddresses(AF_UNSPEC, 0, nullptr, ifs.get(), &ifs_size);
425 if (ERROR_SUCCESS != res) {
426 return stdx::unexpected(
427 std::error_code{static_cast<int>(res), std::system_category()});
428 }
429
430 return NetworkInterfaceResults{std::move(ifs)};
431#else
432 ifaddrs *ifs = nullptr;
433
434 if (-1 == ::getifaddrs(&ifs)) {
436 }
437
438 return NetworkInterfaceResults{ifs};
439#endif
440 }
441};
442} // namespace net
443
444#endif
flags of the network interface.
Definition: netif.h:66
constexpr value_type value() const
Definition: netif.h:80
constexpr InterfaceFlag(value_type v) noexcept
Definition: netif.h:78
const value_type v_
Definition: netif.h:83
decltype(ifaddrs::ifa_flags) value_type
Definition: netif.h:75
an entry in the network interface result.
Definition: netif.h:126
NetworkInterfaceNetworks< net::ip::network_v6 > & v6_networks()
Definition: netif.h:148
const NetworkInterfaceNetworks< net::ip::network_v4 > & v4_networks() const
Definition: netif.h:144
NetworkInterfaceNetworks< net::ip::network_v6 > net_v6_s_
Definition: netif.h:161
std::string id_
Definition: netif.h:157
flags_type flags() const
Definition: netif.h:138
const NetworkInterfaceNetworks< net::ip::network_v6 > & v6_networks() const
Definition: netif.h:152
std::string display_name_
Definition: netif.h:158
NetworkInterfaceEntry(std::string id, std::string display_name, flags_type::value_type flags)
Definition: netif.h:130
NetworkInterfaceNetworks< net::ip::network_v4 > net_v4_s_
Definition: netif.h:160
flags_type flags_
Definition: netif.h:159
std::string display_name() const
Definition: netif.h:137
NetworkInterfaceNetworks< net::ip::network_v4 > & v4_networks()
Definition: netif.h:140
std::string id() const
Definition: netif.h:136
networks of a network interface.
Definition: netif.h:90
auto emplace_back(Args &&... args)
emplace an object in the container.
Definition: netif.h:115
std::list< value_type > container_type
Definition: netif.h:93
const_iterator end() const
Definition: netif.h:105
typename container_type::const_iterator const_iterator
Definition: netif.h:96
ptrdiff_t difference_type
Definition: netif.h:98
void push_back(const value_type &v)
Definition: netif.h:107
container_type nets_
Definition: netif.h:120
const value_type & const_reference
Definition: netif.h:94
value_type & reference
Definition: netif.h:95
const_iterator iterator
Definition: netif.h:97
NetworkT value_type
Definition: netif.h:92
size_t size_type
Definition: netif.h:99
bool empty() const noexcept
Definition: netif.h:102
const_iterator begin() const
Definition: netif.h:104
size_type max_size() const noexcept
Definition: netif.h:101
Definition: netif.h:408
stdx::expected< NetworkInterfaceResults, std::error_code > query()
Definition: netif.h:410
results of a NetworkInterfaceResolver::query().
Definition: netif.h:167
typename std::forward_list< value_type >::const_iterator const_iterator
Definition: netif.h:172
const_iterator cend() const
Definition: netif.h:186
const_iterator cbegin() const
Definition: netif.h:185
size_type size() const noexcept
Definition: netif.h:179
bool empty() const noexcept
Definition: netif.h:181
const_iterator begin() const
Definition: netif.h:183
const_iterator iterator
Definition: netif.h:173
ptrdiff_t difference_type
Definition: netif.h:174
size_type max_size() const noexcept
Definition: netif.h:180
const_iterator end() const
Definition: netif.h:184
size_t size_type
Definition: netif.h:175
std::forward_list< value_type > results_
Definition: netif.h:404
size_t size_
Definition: netif.h:405
Definition: internet.h:93
IPv6 address with scope_id.
Definition: internet.h:182
Definition: expected.h:284
#define malloc(A)
Definition: lexyy.cc:914
#define free(A)
Definition: lexyy.cc:915
static mi_bit_type mask[]
Definition: mi_packrec.cc:141
Container::const_iterator find_if(const Container &c, Find_if &&find_if)
Definition: generic.h:54
std::error_code last_error_code()
get last std::error_code for socket-errors.
Definition: socket_error.h:107
Definition: buffer.h:45
Definition: gcs_xcom_synode.h:64
unexpected(E) -> unexpected< E >
std::conditional_t< !std::is_array< T >::value, std::unique_ptr< T, detail::Deleter< T > >, std::conditional_t< detail::is_unbounded_array_v< T >, std::unique_ptr< T, detail::Array_deleter< std::remove_extent_t< T > > >, void > > unique_ptr
The following is a common type that is returned by all the ut::make_unique (non-aligned) specializati...
Definition: ut0new.h:2438
Definition: internet.h:96
Definition: internet.h:184