1#include <Access/AllowedClientHosts.h>
2#include <Common/Exception.h>
3#include <common/SimpleCache.h>
4#include <Common/StringUtils/StringUtils.h>
5#include <IO/ReadHelpers.h>
6#include <Poco/Net/SocketAddress.h>
7#include <Poco/RegularExpression.h>
8#include <common/logger_useful.h>
9#include <ext/scope_guard.h>
10#include <boost/range/algorithm/find.hpp>
11#include <boost/range/algorithm/find_first_of.hpp>
12#include <boost/algorithm/string/predicate.hpp>
13#include <ifaddrs.h>
14
15
16namespace DB
17{
18namespace ErrorCodes
19{
20 extern const int DNS_ERROR;
21 extern const int IP_ADDRESS_NOT_ALLOWED;
22}
23
24namespace
25{
26 using IPAddress = Poco::Net::IPAddress;
27 using IPSubnet = AllowedClientHosts::IPSubnet;
28 const IPSubnet ALL_ADDRESSES{IPAddress{IPAddress::IPv6}, IPAddress{IPAddress::IPv6}};
29
30 const IPAddress & getIPV6Loopback()
31 {
32 static const IPAddress ip("::1");
33 return ip;
34 }
35
36 bool isIPV4LoopbackMappedToIPV6(const IPAddress & ip)
37 {
38 static const IPAddress prefix("::ffff:127.0.0.0");
39 /// 104 == 128 - 24, we have to reset the lowest 24 bits of 128 before comparing with `prefix`
40 /// (IPv4 loopback means any IP from 127.0.0.0 to 127.255.255.255).
41 return (ip & IPAddress(104, IPAddress::IPv6)) == prefix;
42 }
43
44 /// Converts an address to IPv6.
45 /// The loopback address "127.0.0.1" (or any "127.x.y.z") is converted to "::1".
46 IPAddress toIPv6(const IPAddress & ip)
47 {
48 IPAddress v6;
49 if (ip.family() == IPAddress::IPv6)
50 v6 = ip;
51 else
52 v6 = IPAddress("::ffff:" + ip.toString());
53
54 // ::ffff:127.XX.XX.XX -> ::1
55 if (isIPV4LoopbackMappedToIPV6(v6))
56 v6 = getIPV6Loopback();
57
58 return v6;
59 }
60
61 /// Converts a subnet to IPv6.
62 IPSubnet toIPv6(const IPSubnet & subnet)
63 {
64 IPSubnet v6;
65 if (subnet.prefix.family() == IPAddress::IPv6)
66 v6.prefix = subnet.prefix;
67 else
68 v6.prefix = IPAddress("::ffff:" + subnet.prefix.toString());
69
70 if (subnet.mask.family() == IPAddress::IPv6)
71 v6.mask = subnet.mask;
72 else
73 v6.mask = IPAddress(96, IPAddress::IPv6) | IPAddress("::ffff:" + subnet.mask.toString());
74
75 v6.prefix = v6.prefix & v6.mask;
76
77 // ::ffff:127.XX.XX.XX -> ::1
78 if (isIPV4LoopbackMappedToIPV6(v6.prefix))
79 v6 = {getIPV6Loopback(), IPAddress(128, IPAddress::IPv6)};
80
81 return v6;
82 }
83
84 /// Helper function for isAddressOfHost().
85 bool isAddressOfHostImpl(const IPAddress & address, const String & host)
86 {
87 IPAddress addr_v6 = toIPv6(address);
88
89 /// Resolve by hand, because Poco don't use AI_ALL flag but we need it.
90 addrinfo * ai_begin = nullptr;
91 SCOPE_EXIT(
92 {
93 if (ai_begin)
94 freeaddrinfo(ai_begin);
95 });
96
97 addrinfo hints;
98 memset(&hints, 0, sizeof(hints));
99 hints.ai_family = AF_UNSPEC;
100 hints.ai_flags |= AI_V4MAPPED | AI_ALL;
101
102 int err = getaddrinfo(host.c_str(), nullptr, &hints, &ai_begin);
103 if (err)
104 throw Exception("Cannot getaddrinfo(" + host + "): " + gai_strerror(err), ErrorCodes::DNS_ERROR);
105
106 for (const addrinfo * ai = ai_begin; ai; ai = ai->ai_next)
107 {
108 if (ai->ai_addrlen && ai->ai_addr)
109 {
110 if (ai->ai_family == AF_INET)
111 {
112 const auto & sin = *reinterpret_cast<const sockaddr_in *>(ai->ai_addr);
113 if (addr_v6 == toIPv6(IPAddress(&sin.sin_addr, sizeof(sin.sin_addr))))
114 {
115 return true;
116 }
117 }
118 else if (ai->ai_family == AF_INET6)
119 {
120 const auto & sin = *reinterpret_cast<const sockaddr_in6*>(ai->ai_addr);
121 if (addr_v6 == IPAddress(&sin.sin6_addr, sizeof(sin.sin6_addr), sin.sin6_scope_id))
122 {
123 return true;
124 }
125 }
126 }
127 }
128
129 return false;
130 }
131
132 /// Whether a specified address is one of the addresses of a specified host.
133 bool isAddressOfHost(const IPAddress & address, const String & host)
134 {
135 /// We need to cache DNS requests.
136 static SimpleCache<decltype(isAddressOfHostImpl), isAddressOfHostImpl> cache;
137 return cache(address, host);
138 }
139
140 /// Helper function for isAddressOfLocalhost().
141 std::vector<IPAddress> getAddressesOfLocalhostImpl()
142 {
143 std::vector<IPAddress> addresses;
144
145 ifaddrs * ifa_begin = nullptr;
146 SCOPE_EXIT({
147 if (ifa_begin)
148 freeifaddrs(ifa_begin);
149 });
150
151 int err = getifaddrs(&ifa_begin);
152 if (err)
153 return {getIPV6Loopback()};
154
155 for (const ifaddrs * ifa = ifa_begin; ifa; ifa = ifa->ifa_next)
156 {
157 if (!ifa->ifa_addr)
158 continue;
159 if (ifa->ifa_addr->sa_family == AF_INET)
160 {
161 const auto & sin = *reinterpret_cast<const sockaddr_in *>(ifa->ifa_addr);
162 addresses.push_back(toIPv6(IPAddress(&sin.sin_addr, sizeof(sin.sin_addr))));
163 }
164 else if (ifa->ifa_addr->sa_family == AF_INET6)
165 {
166 const auto & sin = *reinterpret_cast<const sockaddr_in6 *>(ifa->ifa_addr);
167 addresses.push_back(IPAddress(&sin.sin6_addr, sizeof(sin.sin6_addr), sin.sin6_scope_id));
168 }
169 }
170 return addresses;
171 }
172
173 /// Whether a specified address is one of the addresses of the localhost.
174 bool isAddressOfLocalhost(const IPAddress & address)
175 {
176 /// We need to cache DNS requests.
177 static const std::vector<IPAddress> local_addresses = getAddressesOfLocalhostImpl();
178 return boost::range::find(local_addresses, toIPv6(address)) != local_addresses.end();
179 }
180
181 /// Helper function for getHostByAddress().
182 String getHostByAddressImpl(const IPAddress & address)
183 {
184 Poco::Net::SocketAddress sock_addr(address, 0);
185
186 /// Resolve by hand, because Poco library doesn't have such functionality.
187 char host[1024];
188 int err = getnameinfo(sock_addr.addr(), sock_addr.length(), host, sizeof(host), nullptr, 0, NI_NAMEREQD);
189 if (err)
190 throw Exception("Cannot getnameinfo(" + address.toString() + "): " + gai_strerror(err), ErrorCodes::DNS_ERROR);
191
192 /// Check that PTR record is resolved back to client address
193 if (!isAddressOfHost(address, host))
194 throw Exception("Host " + String(host) + " isn't resolved back to " + address.toString(), ErrorCodes::DNS_ERROR);
195
196 return host;
197 }
198
199 /// Returns the host name by its address.
200 String getHostByAddress(const IPAddress & address)
201 {
202 /// We need to cache DNS requests.
203 static SimpleCache<decltype(getHostByAddressImpl), &getHostByAddressImpl> cache;
204 return cache(address);
205 }
206}
207
208
209String AllowedClientHosts::IPSubnet::toString() const
210{
211 unsigned int prefix_length = mask.prefixLength();
212 if (IPAddress{prefix_length, mask.family()} == mask)
213 return prefix.toString() + "/" + std::to_string(prefix_length);
214
215 return prefix.toString() + "/" + mask.toString();
216}
217
218
219AllowedClientHosts::AllowedClientHosts()
220{
221}
222
223
224AllowedClientHosts::AllowedClientHosts(AllAddressesTag)
225{
226 addAllAddresses();
227}
228
229
230AllowedClientHosts::~AllowedClientHosts() = default;
231
232
233AllowedClientHosts::AllowedClientHosts(const AllowedClientHosts & src)
234{
235 *this = src;
236}
237
238
239AllowedClientHosts & AllowedClientHosts::operator =(const AllowedClientHosts & src)
240{
241 addresses = src.addresses;
242 localhost = src.localhost;
243 subnets = src.subnets;
244 host_names = src.host_names;
245 host_regexps = src.host_regexps;
246 compiled_host_regexps.clear();
247 return *this;
248}
249
250
251AllowedClientHosts::AllowedClientHosts(AllowedClientHosts && src) = default;
252AllowedClientHosts & AllowedClientHosts::operator =(AllowedClientHosts && src) = default;
253
254
255void AllowedClientHosts::clear()
256{
257 addresses.clear();
258 localhost = false;
259 subnets.clear();
260 host_names.clear();
261 host_regexps.clear();
262 compiled_host_regexps.clear();
263}
264
265
266bool AllowedClientHosts::empty() const
267{
268 return addresses.empty() && subnets.empty() && host_names.empty() && host_regexps.empty();
269}
270
271
272void AllowedClientHosts::addAddress(const IPAddress & address)
273{
274 IPAddress addr_v6 = toIPv6(address);
275 if (boost::range::find(addresses, addr_v6) != addresses.end())
276 return;
277 addresses.push_back(addr_v6);
278 if (addr_v6.isLoopback())
279 localhost = true;
280}
281
282
283void AllowedClientHosts::addAddress(const String & address)
284{
285 addAddress(IPAddress{address});
286}
287
288
289void AllowedClientHosts::addSubnet(const IPSubnet & subnet)
290{
291 IPSubnet subnet_v6 = toIPv6(subnet);
292
293 if (subnet_v6.mask == IPAddress(128, IPAddress::IPv6))
294 {
295 addAddress(subnet_v6.prefix);
296 return;
297 }
298
299 if (boost::range::find(subnets, subnet_v6) == subnets.end())
300 subnets.push_back(subnet_v6);
301}
302
303
304void AllowedClientHosts::addSubnet(const IPAddress & prefix, const IPAddress & mask)
305{
306 addSubnet(IPSubnet{prefix, mask});
307}
308
309
310void AllowedClientHosts::addSubnet(const IPAddress & prefix, size_t num_prefix_bits)
311{
312 addSubnet(prefix, IPAddress(num_prefix_bits, prefix.family()));
313}
314
315
316void AllowedClientHosts::addSubnet(const String & subnet)
317{
318 size_t slash = subnet.find('/');
319 if (slash == String::npos)
320 {
321 addAddress(subnet);
322 return;
323 }
324
325 IPAddress prefix{String{subnet, 0, slash}};
326 String mask(subnet, slash + 1, subnet.length() - slash - 1);
327 if (std::all_of(mask.begin(), mask.end(), isNumericASCII))
328 addSubnet(prefix, parseFromString<UInt8>(mask));
329 else
330 addSubnet(prefix, IPAddress{mask});
331}
332
333
334void AllowedClientHosts::addHostName(const String & host_name)
335{
336 if (boost::range::find(host_names, host_name) != host_names.end())
337 return;
338 host_names.push_back(host_name);
339 if (boost::iequals(host_name, "localhost"))
340 localhost = true;
341}
342
343
344void AllowedClientHosts::addHostRegexp(const String & host_regexp)
345{
346 if (boost::range::find(host_regexps, host_regexp) == host_regexps.end())
347 host_regexps.push_back(host_regexp);
348}
349
350
351void AllowedClientHosts::addAllAddresses()
352{
353 clear();
354 addSubnet(ALL_ADDRESSES);
355}
356
357
358bool AllowedClientHosts::containsAllAddresses() const
359{
360 return (boost::range::find(subnets, ALL_ADDRESSES) != subnets.end())
361 || (boost::range::find(host_regexps, ".*") != host_regexps.end())
362 || (boost::range::find(host_regexps, "$") != host_regexps.end());
363}
364
365
366void AllowedClientHosts::checkContains(const IPAddress & address, const String & user_name) const
367{
368 if (!contains(address))
369 {
370 if (user_name.empty())
371 throw Exception("It's not allowed to connect from address " + address.toString(), ErrorCodes::IP_ADDRESS_NOT_ALLOWED);
372 else
373 throw Exception("User " + user_name + " is not allowed to connect from address " + address.toString(), ErrorCodes::IP_ADDRESS_NOT_ALLOWED);
374 }
375}
376
377
378bool AllowedClientHosts::contains(const IPAddress & address) const
379{
380 /// Check `ip_addresses`.
381 IPAddress addr_v6 = toIPv6(address);
382 if (boost::range::find(addresses, addr_v6) != addresses.end())
383 return true;
384
385 if (localhost && isAddressOfLocalhost(addr_v6))
386 return true;
387
388 /// Check `ip_subnets`.
389 for (const auto & subnet : subnets)
390 if ((addr_v6 & subnet.mask) == subnet.prefix)
391 return true;
392
393 /// Check `hosts`.
394 for (const String & host_name : host_names)
395 {
396 try
397 {
398 if (isAddressOfHost(addr_v6, host_name))
399 return true;
400 }
401 catch (const Exception & e)
402 {
403 if (e.code() != ErrorCodes::DNS_ERROR)
404 throw;
405 /// Try to ignore DNS errors: if host cannot be resolved, skip it and try next.
406 LOG_WARNING(
407 &Logger::get("AddressPatterns"),
408 "Failed to check if the allowed client hosts contain address " << address.toString() << ". " << e.displayText()
409 << ", code = " << e.code());
410 }
411 }
412
413 /// Check `host_regexps`.
414 try
415 {
416 String resolved_host = getHostByAddress(addr_v6);
417 if (!resolved_host.empty())
418 {
419 compileRegexps();
420 for (const auto & compiled_regexp : compiled_host_regexps)
421 {
422 Poco::RegularExpression::Match match;
423 if (compiled_regexp && compiled_regexp->match(resolved_host, match))
424 return true;
425 }
426 }
427 }
428 catch (const Exception & e)
429 {
430 if (e.code() != ErrorCodes::DNS_ERROR)
431 throw;
432 /// Try to ignore DNS errors: if host cannot be resolved, skip it and try next.
433 LOG_WARNING(
434 &Logger::get("AddressPatterns"),
435 "Failed to check if the allowed client hosts contain address " << address.toString() << ". " << e.displayText()
436 << ", code = " << e.code());
437 }
438
439 return false;
440}
441
442
443void AllowedClientHosts::compileRegexps() const
444{
445 if (compiled_host_regexps.size() == host_regexps.size())
446 return;
447 size_t old_size = compiled_host_regexps.size();
448 compiled_host_regexps.reserve(host_regexps.size());
449 for (size_t i = old_size; i != host_regexps.size(); ++i)
450 compiled_host_regexps.emplace_back(std::make_unique<Poco::RegularExpression>(host_regexps[i]));
451}
452
453
454bool operator ==(const AllowedClientHosts & lhs, const AllowedClientHosts & rhs)
455{
456 return (lhs.addresses == rhs.addresses) && (lhs.subnets == rhs.subnets) && (lhs.host_names == rhs.host_names)
457 && (lhs.host_regexps == rhs.host_regexps);
458}
459}
460