| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "utils/NetworkInterfaceInfo.h" |
| #include "utils/net/Socket.h" |
| #include "core/logging/LoggerConfiguration.h" |
| #ifdef WIN32 |
| #include <Windows.h> |
| #include <winsock2.h> |
| #include <iphlpapi.h> |
| #include <WS2tcpip.h> |
| #pragma comment(lib, "IPHLPAPI.lib") |
| #else |
| #include <unistd.h> |
| #include <netinet/in.h> |
| #include <sys/socket.h> |
| #include <net/if.h> |
| #include <arpa/inet.h> |
| #include <ifaddrs.h> |
| #endif |
| |
| namespace org::apache::nifi::minifi::utils { |
| |
| std::shared_ptr<core::logging::Logger> NetworkInterfaceInfo::logger_ = core::logging::LoggerFactory<NetworkInterfaceInfo>::getLogger(); |
| |
| #ifdef WIN32 |
| namespace { |
| std::string utf8_encode(const std::wstring& wstr) { |
| if (wstr.empty()) |
| return std::string(); |
| int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); |
| std::string result_string(size_needed, 0); |
| WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, result_string.data(), size_needed, nullptr, nullptr); |
| return result_string; |
| } |
| } |
| |
| NetworkInterfaceInfo::NetworkInterfaceInfo(const IP_ADAPTER_ADDRESSES* adapter) { |
| name_ = utf8_encode(adapter->FriendlyName); |
| for (auto unicast_address = adapter->FirstUnicastAddress; unicast_address != nullptr; unicast_address = unicast_address->Next) { |
| if (unicast_address->Address.lpSockaddr->sa_family == AF_INET) { |
| ip_v4_addresses_.push_back(net::sockaddr_ntop(unicast_address->Address.lpSockaddr)); |
| } else if (unicast_address->Address.lpSockaddr->sa_family == AF_INET6) { |
| ip_v6_addresses_.push_back(net::sockaddr_ntop(unicast_address->Address.lpSockaddr)); |
| } |
| } |
| running_ = adapter->OperStatus == IfOperStatusUp; |
| loopback_ = adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK; |
| } |
| #else |
| NetworkInterfaceInfo::NetworkInterfaceInfo(const struct ifaddrs* ifa) { |
| name_ = ifa->ifa_name; |
| if (ifa->ifa_addr->sa_family == AF_INET) { |
| ip_v4_addresses_.push_back(net::sockaddr_ntop(ifa->ifa_addr)); |
| } else if (ifa->ifa_addr->sa_family == AF_INET6) { |
| ip_v6_addresses_.push_back(net::sockaddr_ntop(ifa->ifa_addr)); |
| } |
| running_ = (ifa->ifa_flags & IFF_RUNNING); |
| loopback_ = (ifa->ifa_flags & IFF_LOOPBACK); |
| } |
| #endif |
| |
| namespace { |
| struct HasName { |
| explicit HasName(const std::string& name) : name_(name) {} |
| bool operator()(const NetworkInterfaceInfo& network_interface_info) { |
| return network_interface_info.getName() == name_; |
| } |
| const std::string& name_; |
| }; |
| } |
| |
| std::vector<NetworkInterfaceInfo> NetworkInterfaceInfo::getNetworkInterfaceInfos(const std::function<bool(const NetworkInterfaceInfo&)>& filter, |
| const std::optional<uint32_t> max_interfaces) { |
| std::vector<NetworkInterfaceInfo> network_adapters; |
| #ifdef WIN32 |
| ULONG buffer_length = sizeof(IP_ADAPTER_ADDRESSES); |
| auto get_adapters_err = GetAdaptersAddresses(0, 0, nullptr, nullptr, &buffer_length); |
| if (ERROR_BUFFER_OVERFLOW != get_adapters_err) { |
| logger_->log_error("GetAdaptersAddresses failed: %lu", get_adapters_err); |
| return network_adapters; |
| } |
| std::vector<char> bytes(buffer_length, 0); |
| IP_ADAPTER_ADDRESSES* adapter = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(bytes.data()); |
| get_adapters_err = GetAdaptersAddresses(0, 0, nullptr, adapter, &buffer_length); |
| if (NO_ERROR != get_adapters_err) { |
| logger_->log_error("GetAdaptersAddresses failed: %lu", get_adapters_err); |
| return network_adapters; |
| } |
| while (adapter != nullptr) { |
| NetworkInterfaceInfo interface_info(adapter); |
| if (filter(interface_info)) { |
| auto it = std::find_if(network_adapters.begin(), network_adapters.end(), HasName(interface_info.getName())); |
| if (it == network_adapters.end()) { |
| network_adapters.emplace_back(std::move(interface_info)); |
| } else { |
| interface_info.moveAddressesInto(*it); |
| } |
| } |
| if (max_interfaces.has_value() && network_adapters.size() >= max_interfaces.value()) |
| return network_adapters; |
| adapter = adapter->Next; |
| } |
| #else |
| struct ifaddrs* interface_addresses = nullptr; |
| auto cleanup = gsl::finally([&interface_addresses] { freeifaddrs(interface_addresses); }); |
| if (getifaddrs(&interface_addresses) == -1) { |
| logger_->log_error("getifaddrs failed: %s", std::strerror(errno)); |
| return network_adapters; |
| } |
| |
| for (struct ifaddrs* ifa = interface_addresses; ifa != nullptr; ifa = ifa->ifa_next) { |
| if (!ifa->ifa_addr) |
| continue; |
| NetworkInterfaceInfo interface_info(ifa); |
| if (filter(interface_info)) { |
| auto it = std::find_if(network_adapters.begin(), network_adapters.end(), HasName(interface_info.getName())); |
| if (it == network_adapters.end()) { |
| network_adapters.emplace_back(std::move(interface_info)); |
| } else { |
| interface_info.moveAddressesInto(*it); |
| } |
| } |
| if (max_interfaces.has_value() && network_adapters.size() >= max_interfaces.value()) |
| return network_adapters; |
| } |
| #endif |
| return network_adapters; |
| } |
| |
| namespace { |
| void move_append(std::vector<std::string> &&source, std::vector<std::string> &destination) { |
| destination.reserve(destination.size() + source.size()); |
| std::move(std::begin(source), std::end(source), std::back_inserter(destination)); |
| source.clear(); |
| } |
| } // namespace |
| |
| void NetworkInterfaceInfo::moveAddressesInto(NetworkInterfaceInfo& destination) { |
| move_append(std::move(ip_v4_addresses_), destination.ip_v4_addresses_); |
| move_append(std::move(ip_v6_addresses_), destination.ip_v6_addresses_); |
| } |
| |
| } // namespace org::apache::nifi::minifi::utils |