From fe6ff470b113c81288df34911901c59af4c074b7 Mon Sep 17 00:00:00 2001 From: henryzhx8 Date: Fri, 19 Jul 2024 09:42:31 +0800 Subject: [PATCH] fix core caused by concurrent use of non-thread-safe gethostbyname (#1611) * fix core caused by concurrent use of non-thread-safe gethostbyname --- core/common/MachineInfoUtil.cpp | 146 +++++++++++++++++--------------- 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/core/common/MachineInfoUtil.cpp b/core/common/MachineInfoUtil.cpp index d21343a2c3..47e0650fa7 100644 --- a/core/common/MachineInfoUtil.cpp +++ b/core/common/MachineInfoUtil.cpp @@ -13,31 +13,35 @@ // limitations under the License. #include "MachineInfoUtil.h" + #include #if defined(__linux__) -#include #include -#include -#include #include -#include -#include +#include #include -#include -#include +#include +#include +#include +#include + #include +#include +#include #elif defined(_MSC_VER) #include #include #endif -#include "logger/Logger.h" -#include "StringTools.h" -#include "FileSystemUtil.h" -#include #include #include #include +#include + +#include "FileSystemUtil.h" +#include "StringTools.h" +#include "logger/Logger.h" + #if defined(_MSC_VER) typedef LONG NTSTATUS, *PNTSTATUS; @@ -164,10 +168,10 @@ std::string GetHostName() { return std::string(hostname); } -std::list GetNicIpv4IPList() { +std::unordered_set GetNicIpv4IPSet() { struct ifaddrs* ifAddrStruct = NULL; void* tmpAddrPtr = NULL; - std::list ipList; + std::unordered_set ipSet; getifaddrs(&ifAddrStruct); for (struct ifaddrs* ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) { @@ -183,11 +187,11 @@ std::list GetNicIpv4IPList() { if (0 == strcmp("lo", ifa->ifa_name) || ip.empty() || StartWith(ip, "127.")) { continue; } - ipList.emplace_back(std::move(ip)); + ipSet.insert(std::move(ip)); } } freeifaddrs(ifAddrStruct); - return ipList; + return ipSet; } std::string GetHostIpByHostName() { @@ -199,64 +203,73 @@ std::string GetHostIpByHostName() { return ""; } - struct hostent* entry = gethostbyname(hostname.c_str()); - if (entry == NULL) { + struct addrinfo hints, *res = nullptr; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + int status = getaddrinfo(hostname.c_str(), NULL, &hints, &res); + if (status != 0 || res == nullptr) { + LOG_WARNING(sLogger, + ("failed get address info", "will use other methods to obtain ip")("errMsg", gai_strerror(status))); return ""; } + + std::vector addrs; + for (auto p = res; p != nullptr; p = p->ai_next) { + if (p->ai_family == AF_INET) { + addrs.emplace_back(*(struct sockaddr_in*)p->ai_addr); + } + } + freeaddrinfo(res); + + std::string firstIp; + char ipStr[INET_ADDRSTRLEN + 1] = ""; #if defined(__linux__) - int i = 0; - std::list ipList; - ipList = GetNicIpv4IPList(); - if (!ipList.empty()) { - int isExistValidIP = 0; - while (entry->h_addr_list[i] != NULL) { - struct in_addr addr; - memcpy(&addr, entry->h_addr_list[i], sizeof(struct in_addr)); - auto item = std::find(ipList.begin(), ipList.end(), inet_ntoa(addr)); - if (item != ipList.end()) { - isExistValidIP = 1; - break; - } - i++; + auto ipSet = GetNicIpv4IPSet(); + for (size_t i = 0; i < addrs.size(); ++i) { + auto p = inet_ntop(AF_INET, &addrs[i].sin_addr, ipStr, INET_ADDRSTRLEN); + if (p == nullptr) { + continue; } - if (0 == isExistValidIP) { - i = 0; + auto tmp = std::string(ipStr); + if (ipSet.find(tmp) != ipSet.end()) { + return tmp; + } + if (i == 0) { + firstIp = tmp; + if (ipSet.empty()) { + LOG_INFO(sLogger, ("no entry from getifaddrs", "use first entry from getaddrinfo")); + return firstIp; + } } } - struct in_addr* addr = (struct in_addr*)entry->h_addr_list[i]; - if (addr == NULL) { - return ""; - } - char* ipaddr = inet_ntoa(*addr); - if (ipaddr == NULL) { - return ""; - } - return std::string(ipaddr); #elif defined(_MSC_VER) - std::string ip; - while (*(entry->h_addr_list) != NULL) { - if (AF_INET == entry->h_addrtype) { - // According to RFC 1918 (http://www.faqs.org/rfcs/rfc1918.html), private IP ranges are as bellow: - // 10.0.0.0 - 10.255.255.255 (10/8 prefix) - // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) - // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) - // 100.*.*.* , 30.*.*.* - alibaba office network - std::string curIP = inet_ntoa(*(struct in_addr*)*entry->h_addr_list); - ip = curIP; - if (curIP.find("10.") == 0 || curIP.find("100.") == 0 || curIP.find("30.") == 0 - || curIP.find("192.168.") == 0 || curIP.find("172.16.") == 0 || curIP.find("172.17.") == 0 - || curIP.find("172.18.") == 0 || curIP.find("172.19.") == 0 || curIP.find("172.20.") == 0 - || curIP.find("172.21.") == 0 || curIP.find("172.22.") == 0 || curIP.find("172.23.") == 0 - || curIP.find("172.24.") == 0 || curIP.find("172.25.") == 0 || curIP.find("172.26.") == 0 - || curIP.find("172.27.") == 0 || curIP.find("172.28.") == 0 || curIP.find("172.29.") == 0 - || curIP.find("172.30.") == 0 || curIP.find("172.31.") == 0) { - return curIP; - } + for (size_t i = 0; i < addrs.size(); ++i) { + auto p = inet_ntop(AF_INET, &addrs[i].sin_addr, ipStr, INET_ADDRSTRLEN); + if (p == nullptr) { + continue; + } + auto tmp = std::string(ipStr); + // According to RFC 1918 (http://www.faqs.org/rfcs/rfc1918.html), private IP ranges are as bellow: + // 10.0.0.0 - 10.255.255.255 (10/8 prefix) + // 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) + // 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) + // 100.*.*.* , 30.*.*.* - alibaba office network + if (tmp.find("10.") == 0 || tmp.find("100.") == 0 || tmp.find("30.") == 0 || tmp.find("192.168.") == 0 + || tmp.find("172.16.") == 0 || tmp.find("172.17.") == 0 || tmp.find("172.18.") == 0 + || tmp.find("172.19.") == 0 || tmp.find("172.20.") == 0 || tmp.find("172.21.") == 0 + || tmp.find("172.22.") == 0 || tmp.find("172.23.") == 0 || tmp.find("172.24.") == 0 + || tmp.find("172.25.") == 0 || tmp.find("172.26.") == 0 || tmp.find("172.27.") == 0 + || tmp.find("172.28.") == 0 || tmp.find("172.29.") == 0 || tmp.find("172.30.") == 0 + || tmp.find("172.31.") == 0) { + return tmp; + } + if (i == 0) { + firstIp = tmp; } - entry->h_addr_list++; } - return ip; #endif + LOG_INFO(sLogger, ("no entry from getaddrinfo matches entry from getifaddrs", "use first entry from getaddrinfo")); + return firstIp; } std::string GetHostIpByInterface(const std::string& intf) { @@ -314,10 +327,9 @@ std::string GetAnyAvailableIP() { #if defined(__linux__) std::string retIP; char host[NI_MAXHOST]; - std::list ipList; - ipList = GetNicIpv4IPList(); - if (!ipList.empty()) { - for (std::string ip : ipList) { + auto ipSet = GetNicIpv4IPSet(); + if (!ipSet.empty()) { + for (auto& ip : ipSet) { struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_port = 0;