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