diff --git a/src/Common/isLocalAddress.cpp b/src/Common/isLocalAddress.cpp index 8da281e3051..cecff489a22 100644 --- a/src/Common/isLocalAddress.cpp +++ b/src/Common/isLocalAddress.cpp @@ -1,29 +1,84 @@ #include +#include #include +#include #include -#include -#include +#include +#include #include namespace DB { +namespace ErrorCodes +{ + extern const int SYSTEM_ERROR; +} + +namespace +{ + +struct NetworkInterfaces +{ + ifaddrs * ifaddr; + NetworkInterfaces() + { + if (getifaddrs(&ifaddr) == -1) + { + throwFromErrno("Cannot getifaddrs", ErrorCodes::SYSTEM_ERROR); + } + } + + bool hasAddress(const Poco::Net::IPAddress & address) const + { + ifaddrs * iface; + for (iface = ifaddr; iface != nullptr; iface = iface->ifa_next) + { + auto family = iface->ifa_addr->sa_family; + std::optional interface_address; + switch (family) + { + /// We interested only in IP-adresses + case AF_INET: + { + interface_address.emplace(*(iface->ifa_addr)); + break; + } + case AF_INET6: + { + interface_address.emplace(&reinterpret_cast(iface->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); + break; + } + default: + continue; + } + + /** Compare the addresses without taking into account `scope`. + * Theoretically, this may not be correct - depends on `route` setting + * - through which interface we will actually access the specified address. + */ + if (interface_address->length() == address.length() + && 0 == memcmp(interface_address->addr(), address.addr(), address.length())) + return true; + } + return false; + } + + ~NetworkInterfaces() + { + freeifaddrs(ifaddr); + } +}; + +} + + bool isLocalAddress(const Poco::Net::IPAddress & address) { - static auto interfaces = Poco::Net::NetworkInterface::list(); - - return interfaces.end() != std::find_if(interfaces.begin(), interfaces.end(), - [&] (const Poco::Net::NetworkInterface & interface) - { - /** Compare the addresses without taking into account `scope`. - * Theoretically, this may not be correct - depends on `route` setting - * - through which interface we will actually access the specified address. - */ - return interface.address().length() == address.length() - && 0 == memcmp(interface.address().addr(), address.addr(), address.length()); - }); + NetworkInterfaces interfaces; + return interfaces.hasAddress(address); } bool isLocalAddress(const Poco::Net::SocketAddress & address, UInt16 clickhouse_port)