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