Skip to content

Commit c1df291

Browse files
committed
Fix error with IPv6 in host param
1 parent 87933e4 commit c1df291

File tree

5 files changed

+67
-16
lines changed

5 files changed

+67
-16
lines changed

src/Client/ClientBase.h

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -246,22 +246,11 @@ class ClientBase : public Poco::Util::Application, public IHints<2, ClientBase>
246246
String host_with_port;
247247
in >> host_with_port;
248248
DB::DNSResolver & resolver = DB::DNSResolver::instance();
249-
try
250-
{
251-
Poco::Net::SocketAddress address = resolver.resolveAddress(host_with_port);
252-
hostPort.host = address.host().toString();
253-
hostPort.port = address.port();
254-
}
255-
catch (const Exception & e)
256-
{
257-
if (e.message() == "Missing port number")
258-
{
259-
hostPort.host = resolver.resolveHost(host_with_port).toString();
260-
hostPort.port = std::nullopt;
261-
return in;
262-
}
263-
throw;
264-
}
249+
std::pair<Poco::Net::IPAddress, std::optional<UInt16>>
250+
host_and_port = resolver.resolveHostOrAddress(host_with_port);
251+
hostPort.host = host_and_port.first.toString();
252+
hostPort.port = host_and_port.second;
253+
265254
return in;
266255
}
267256
};

src/Common/DNSResolver.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,45 @@ Poco::Net::SocketAddress DNSResolver::resolveAddress(const std::string & host, U
202202
return Poco::Net::SocketAddress(impl->cache_host(host).front(), port);
203203
}
204204

205+
std::pair<Poco::Net::IPAddress, std::optional<UInt16>> DNSResolver::resolveHostOrAddress(const std::string & host_and_port)
206+
{
207+
Poco::Net::IPAddress ip;
208+
209+
size_t number_of_colons = std::count(host_and_port.begin(), host_and_port.end(), ':');
210+
if (number_of_colons > 1)
211+
{
212+
/// IPv6 host
213+
if (host_and_port.starts_with('['))
214+
{
215+
size_t close_bracket_pos = host_and_port.find(']');
216+
assert(close_bracket_pos != std::string::npos);
217+
ip = resolveHost(host_and_port.substr(0, close_bracket_pos));
218+
219+
if (close_bracket_pos == host_and_port.size() - 1)
220+
return {ip, std::nullopt};
221+
if (host_and_port[close_bracket_pos + 1] != ':')
222+
throw Exception("Missing delimiter between host and port", ErrorCodes::BAD_ARGUMENTS);
223+
224+
unsigned int port;
225+
if (!Poco::NumberParser::tryParseUnsigned(host_and_port.substr(close_bracket_pos + 2), port))
226+
throw Exception("Port must be numeric", ErrorCodes::BAD_ARGUMENTS);
227+
if (port > 0xFFFF)
228+
throw Exception("Port must be less 0xFFFF", ErrorCodes::BAD_ARGUMENTS);
229+
return {ip, port};
230+
}
231+
return {resolveHost(host_and_port), std::nullopt};
232+
}
233+
else if (number_of_colons == 1)
234+
{
235+
/// IPv4 host with port
236+
Poco::Net::SocketAddress socket = resolveAddress(host_and_port);
237+
return {socket.host(), socket.port()};
238+
}
239+
240+
/// IPv4 host
241+
return {resolveHost(host_and_port), std::nullopt};
242+
}
243+
205244
String DNSResolver::reverseResolve(const Poco::Net::IPAddress & address)
206245
{
207246
if (impl->disable_cache)

src/Common/DNSResolver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ class DNSResolver : private boost::noncopyable
3434

3535
Poco::Net::SocketAddress resolveAddress(const std::string & host, UInt16 port);
3636

37+
/// Accepts host names like 'example.com'/'example.com:port' or '127.0.0.1'/'127.0.0.1:port' or '::1'/'[::1]:port'
38+
/// and resolves its IP and port, if port is set
39+
std::pair<Poco::Net::IPAddress, std::optional<UInt16>> resolveHostOrAddress(const std::string & host_and_port);
40+
3741
/// Accepts host IP and resolves its host name
3842
String reverseResolve(const Poco::Net::IPAddress & address);
3943

tests/queries/0_stateless/02100_multiple_hosts_command_line_set.reference

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@
66
1
77
1
88
1
9+
1
10+
1
11+
1

tests/queries/0_stateless/02100_multiple_hosts_command_line_set.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,19 @@ error="$(${CLICKHOUSE_CLIENT} --host "${CLICKHOUSE_HOST}" --port "${not_alive_po
3333
${CLICKHOUSE_CLIENT} --host "${CLICKHOUSE_HOST}:${not_alive_port}" "${CLICKHOUSE_HOST}" --query "SELECT 1";
3434
${CLICKHOUSE_CLIENT} --host "${CLICKHOUSE_HOST}:${CLICKHOUSE_PORT_TCP}" --port "${not_alive_port}" --query "SELECT 1";
3535

36+
ipv6_host_without_brackets="2001:3984:3989::1:1000"
37+
exception_msg="Code: 210. DB::NetException: Connection refused (${ipv6_host_without_brackets}). (NETWORK_ERROR)
38+
"
39+
error="$(${CLICKHOUSE_CLIENT} --host "${ipv6_host_without_brackets}" --query "SELECT 1" 2>&1 > /dev/null)"
40+
[ "${error}" == "${exception_msg}" ]; echo "$?"
41+
42+
ipv6_host_with_brackets="[2001:3984:3989::1:1000]"
43+
exception_msg="Code: 210. DB::NetException: Connection refused (${ipv6_host_with_brackets}). (NETWORK_ERROR)
44+
"
45+
error="$(${CLICKHOUSE_CLIENT} --host "${ipv6_host_with_brackets}" --query "SELECT 1" 2>&1 > /dev/null)"
46+
[ "${error}" == "${exception_msg}" ]; echo "$?"
47+
48+
exception_msg="Code: 210. DB::NetException: Connection refused (${ipv6_host_with_brackets}:${not_alive_port}). (NETWORK_ERROR)
49+
"
50+
error="$(${CLICKHOUSE_CLIENT} --host "${ipv6_host_with_brackets}:${not_alive_port}" --query "SELECT 1" 2>&1 > /dev/null)"
51+
[ "${error}" == "${exception_msg}" ]; echo "$?"

0 commit comments

Comments
 (0)