ClickHouse/src/Common/isLocalAddress.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

136 lines
3.8 KiB
C++
Raw Normal View History

#include <Common/isLocalAddress.h>
2021-05-17 15:31:44 +00:00
#include <ifaddrs.h>
#include <cstring>
2021-05-17 16:29:11 +00:00
#include <optional>
2021-10-02 07:13:14 +00:00
#include <base/types.h>
2021-05-17 15:31:44 +00:00
#include <Common/Exception.h>
#include <Poco/Net/IPAddress.h>
#include <Poco/Net/SocketAddress.h>
namespace DB
{
2021-05-17 15:31:44 +00:00
namespace ErrorCodes
{
extern const int SYSTEM_ERROR;
}
namespace
{
2021-05-17 15:31:44 +00:00
struct NetworkInterfaces
{
ifaddrs * ifaddr;
2021-05-17 15:31:44 +00:00
NetworkInterfaces()
{
if (getifaddrs(&ifaddr) == -1)
{
throwFromErrno("Cannot getifaddrs", ErrorCodes::SYSTEM_ERROR);
}
}
bool hasAddress(const Poco::Net::IPAddress & address) const
{
ifaddrs * iface;
2021-05-17 15:31:44 +00:00
for (iface = ifaddr; iface != nullptr; iface = iface->ifa_next)
{
/// Point-to-point (VPN) addresses may have NULL ifa_addr
if (!iface->ifa_addr)
continue;
2021-05-17 16:18:38 +00:00
auto family = iface->ifa_addr->sa_family;
2021-05-17 15:31:44 +00:00
std::optional<Poco::Net::IPAddress> interface_address;
switch (family)
{
/// We interested only in IP-adresses
case AF_INET:
{
2021-05-17 16:18:38 +00:00
interface_address.emplace(*(iface->ifa_addr));
2021-05-17 15:31:44 +00:00
break;
}
case AF_INET6:
{
interface_address.emplace(&reinterpret_cast<const struct sockaddr_in6*>(iface->ifa_addr)->sin6_addr, sizeof(struct in6_addr));
2021-05-17 15:31:44 +00:00
break;
}
default:
continue;
}
2021-05-17 15:32:34 +00:00
2021-05-17 16:29:11 +00:00
/** 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.
*/
2021-05-17 15:31:44 +00:00
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)
{
2021-05-20 03:24:42 +00:00
/** 127.0.0.1 is treat as local address unconditionally.
* ::1 is also treat as local address unconditionally.
*
* 127.0.0.{2..255} are not treat as local addresses, because they are used in tests
* to emulate distributed queries across localhost.
*
* But 127.{0,1}.{0,1}.{0,1} are treat as local addresses,
* because they are used in Debian for localhost.
*/
if (address.isLoopback())
{
if (address.family() == Poco::Net::AddressFamily::IPv4)
{
2021-05-21 05:21:19 +00:00
/// The address is located in memory in big endian form (network byte order).
const unsigned char * digits = static_cast<const unsigned char *>(address.addr());
2021-05-21 05:17:54 +00:00
if (digits[0] == 127
&& digits[1] <= 1
&& digits[2] <= 1
&& digits[3] <= 1)
2021-05-20 03:24:42 +00:00
{
return true;
}
}
else if (address.family() == Poco::Net::AddressFamily::IPv6)
{
return true;
}
}
2021-05-17 15:31:44 +00:00
NetworkInterfaces interfaces;
return interfaces.hasAddress(address);
}
2021-05-20 03:24:42 +00:00
bool isLocalAddress(const Poco::Net::SocketAddress & address, UInt16 clickhouse_port)
{
return clickhouse_port == address.port() && isLocalAddress(address.host());
}
size_t getHostNameDifference(const std::string & local_hostname, const std::string & host)
{
2022-03-21 14:55:01 +00:00
/// FIXME should we replace it with Levenstein distance? (we already have it in NamePrompter)
size_t hostname_difference = 0;
for (size_t i = 0; i < std::min(local_hostname.length(), host.length()); ++i)
if (local_hostname[i] != host[i])
++hostname_difference;
return hostname_difference;
}
}