From 17e7c1ca53ad69374e83ec6b44f191e30ef0bc88 Mon Sep 17 00:00:00 2001 From: zhangdong <493738387@qq.com> Date: Fri, 25 Aug 2023 21:24:55 +0800 Subject: [PATCH] [fix](fqdn)Fqdn with ipv6 (#22454) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit now,`hostname_to_ip` only can resolve `ipv4`,Therefore, a method is provided to parse ipv4 or ipv6 based on parameters。 when `_heartbeat` call `hostname_to_ip`,Resolve to ipv4 or ipv6, determined by `BackendOptions.is_bind_ipv6` Decision Additionally, a method is provided to first attempt to parse the host into ipv4, and then try ipv6 if it fails --- be/src/agent/heartbeat_server.cpp | 6 +- be/src/util/network_util.cpp | 109 +++++++++++++++--------------- be/src/util/network_util.h | 11 +-- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/be/src/agent/heartbeat_server.cpp b/be/src/agent/heartbeat_server.cpp index d353692c9d..92b121414c 100644 --- a/be/src/agent/heartbeat_server.cpp +++ b/be/src/agent/heartbeat_server.cpp @@ -118,14 +118,16 @@ Status HeartbeatServer::_heartbeat(const TMasterInfo& master_info) { if (!is_valid_ip(master_info.backend_ip)) { //step2: resolve FQDN to IP std::string ip; - Status status = hostname_to_ip(master_info.backend_ip, ip); + Status status = + hostname_to_ip(master_info.backend_ip, ip, BackendOptions::is_bind_ipv6()); if (!status.ok()) { std::stringstream ss; ss << "can not get ip from fqdn: " << status.to_string(); LOG(WARNING) << ss.str(); return status; } - + LOG(INFO) << "master_info.backend_ip: " << master_info.backend_ip + << ", hostname_to_ip: " << ip; //step3: get all ips of the interfaces on this machine std::vector hosts; status = get_hosts(&hosts); diff --git a/be/src/util/network_util.cpp b/be/src/util/network_util.cpp index 6841e257a3..d80682d21e 100644 --- a/be/src/util/network_util.cpp +++ b/be/src/util/network_util.cpp @@ -72,70 +72,69 @@ Status get_hostname(std::string* hostname) { return Status::OK(); } -Status hostname_to_ip_addrs(const std::string& name, std::vector* addresses) { - addrinfo hints; - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_INET; // IPv4 addresses only - hints.ai_socktype = SOCK_STREAM; - - struct addrinfo* addr_info; - - if (getaddrinfo(name.c_str(), nullptr, &hints, &addr_info) != 0) { - return Status::InternalError("Could not find IPv4 address for: {}", name); - } - - addrinfo* it = addr_info; - - while (it != nullptr) { - char addr_buf[64]; - const char* result = - inet_ntop(AF_INET, &((sockaddr_in*)it->ai_addr)->sin_addr, addr_buf, 64); - - if (result == nullptr) { - freeaddrinfo(addr_info); - return Status::InternalError("Could not convert IPv4 address for: {}", name); - } - - // add address if not exists - std::string address = std::string(addr_buf); - if (std::find(addresses->begin(), addresses->end(), address) != addresses->end()) { - LOG(WARNING) << "Repeated ip addresses has been found for host: " << name - << ", ip address:" << address - << ", please check your network configuration"; - } else { - addresses->push_back(address); - } - it = it->ai_next; - } - - freeaddrinfo(addr_info); - return Status::OK(); -} - bool is_valid_ip(const std::string& ip) { unsigned char buf[sizeof(struct in6_addr)]; return (inet_pton(AF_INET6, ip.data(), buf) > 0) || (inet_pton(AF_INET, ip.data(), buf) > 0); } Status hostname_to_ip(const std::string& host, std::string& ip) { - std::vector addresses; - Status status = hostname_to_ip_addrs(host, &addresses); - if (!status.ok()) { - LOG(WARNING) << "status of hostname_to_ip_addrs was not ok, err is " << status.to_string(); + Status status = hostname_to_ipv4(host, ip); + if (status.ok()) { return status; } - if (addresses.size() != 1) { - std::stringstream ss; - std::copy(addresses.begin(), addresses.end(), std::ostream_iterator(ss, ",")); - LOG(WARNING) - << "the number of addresses could only be equal to 1, failed to get ip from host:" - << host << ", addresses:" << ss.str(); - return Status::InternalError( - "the number of addresses could only be equal to 1, failed to get ip from host: " - "{}, addresses:{}", - host, ss.str()); + return hostname_to_ipv6(host, ip); +} + +Status hostname_to_ip(const std::string& host, std::string& ip, bool ipv6) { + if (ipv6) { + return hostname_to_ipv6(host, ip); + } else { + return hostname_to_ipv4(host, ip); } - ip = addresses[0]; +} + +Status hostname_to_ipv4(const std::string& host, std::string& ip) { + addrinfo hints, *res; + in_addr addr; + + memset(&hints, 0, sizeof(addrinfo)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_INET; + int err = getaddrinfo(host.c_str(), NULL, &hints, &res); + if (err != 0) { + LOG(WARNING) << "failed to get ip from host: " << host << "err:" << gai_strerror(err); + return Status::InternalError("failed to get ip from host: {}, err: {}", host, + gai_strerror(err)); + } + + addr.s_addr = ((sockaddr_in*)(res->ai_addr))->sin_addr.s_addr; + ip = inet_ntoa(addr); + + freeaddrinfo(res); + return Status::OK(); +} + +Status hostname_to_ipv6(const std::string& host, std::string& ip) { + char ipstr2[128]; + struct sockaddr_in6* sockaddr_ipv6; + + struct addrinfo *answer, hint; + bzero(&hint, sizeof(hint)); + hint.ai_family = AF_INET6; + hint.ai_socktype = SOCK_STREAM; + + int err = getaddrinfo(host.c_str(), NULL, &hint, &answer); + if (err != 0) { + LOG(WARNING) << "failed to get ip from host: " << host << "err:" << gai_strerror(err); + return Status::InternalError("failed to get ip from host: {}, err: {}", host, + gai_strerror(err)); + } + + sockaddr_ipv6 = reinterpret_cast(answer->ai_addr); + inet_ntop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstr2, sizeof(ipstr2)); + ip = ipstr2; + fflush(NULL); + freeaddrinfo(answer); return Status::OK(); } diff --git a/be/src/util/network_util.h b/be/src/util/network_util.h index 55bbcd1130..a9541586ef 100644 --- a/be/src/util/network_util.h +++ b/be/src/util/network_util.h @@ -43,15 +43,16 @@ private: bool _is_loopback; }; -// Looks up all IP addresses associated with a given hostname. Returns -// an error status if any system call failed, otherwise OK. Even if OK -// is returned, addresses may still be of zero length. -Status hostname_to_ip_addrs(const std::string& name, std::vector* addresses); - bool is_valid_ip(const std::string& ip); Status hostname_to_ip(const std::string& host, std::string& ip); +Status hostname_to_ipv4(const std::string& host, std::string& ip); + +Status hostname_to_ipv6(const std::string& host, std::string& ip); + +Status hostname_to_ip(const std::string& host, std::string& ip, bool ipv6); + // Finds the first non-localhost IP address in the given list. Returns // true if such an address was found, false otherwise. bool find_first_non_localhost(const std::vector& addresses, std::string* addr);