Merge pull request #62978 from ClickHouse/fix-grpc-ipv6-crash

gRPC: fix crash on IPv6 peer connection
This commit is contained in:
Konstantin Bogdanov 2024-04-27 06:22:41 +00:00 committed by GitHub
commit 64de52397e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 34 additions and 4 deletions

View File

@ -1,6 +1,7 @@
#include "GRPCServer.h" #include "GRPCServer.h"
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <Poco/Net/SocketAddress.h>
#if USE_GRPC #if USE_GRPC
#include <Columns/ColumnString.h> #include <Columns/ColumnString.h>
@ -320,8 +321,27 @@ namespace
Poco::Net::SocketAddress getClientAddress() const Poco::Net::SocketAddress getClientAddress() const
{ {
String peer = grpc_context.peer(); /// Returns a string like ipv4:127.0.0.1:55930 or ipv6:%5B::1%5D:55930
return Poco::Net::SocketAddress{peer.substr(peer.find(':') + 1)}; String uri_encoded_peer = grpc_context.peer();
constexpr const std::string_view ipv4_prefix = "ipv4:";
constexpr const std::string_view ipv6_prefix = "ipv6:";
bool ipv4 = uri_encoded_peer.starts_with(ipv4_prefix);
bool ipv6 = uri_encoded_peer.starts_with(ipv6_prefix);
if (!ipv4 && !ipv6)
throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected ipv4 or ipv6 protocol in peer address, got {}", uri_encoded_peer);
auto prefix = ipv4 ? ipv4_prefix : ipv6_prefix;
auto family = ipv4 ? Poco::Net::AddressFamily::Family::IPv4 : Poco::Net::AddressFamily::Family::IPv6;
uri_encoded_peer= uri_encoded_peer.substr(prefix.length());
String peer;
Poco::URI::decode(uri_encoded_peer, peer);
return Poco::Net::SocketAddress{family, peer};
} }
std::optional<String> getClientHeader(const String & key) const std::optional<String> getClientHeader(const String & key) const

View File

@ -27,6 +27,8 @@ if is_arm():
# Utilities # Utilities
IPV6_ADDRESS = "2001:3984:3989::1:1111"
config_dir = os.path.join(script_dir, "./configs") config_dir = os.path.join(script_dir, "./configs")
cluster = ClickHouseCluster(__file__) cluster = ClickHouseCluster(__file__)
node = cluster.add_instance( node = cluster.add_instance(
@ -36,12 +38,15 @@ node = cluster.add_instance(
env_variables={ env_variables={
"TSAN_OPTIONS": "report_atomic_races=0 " + os.getenv("TSAN_OPTIONS", default="") "TSAN_OPTIONS": "report_atomic_races=0 " + os.getenv("TSAN_OPTIONS", default="")
}, },
ipv6_address=IPV6_ADDRESS,
) )
main_channel = None main_channel = None
def create_channel(): def create_channel(hostname=None):
node_ip_with_grpc_port = cluster.get_instance_ip("node") + ":" + str(GRPC_PORT) if not hostname:
hostname = cluster.get_instance_ip("node")
node_ip_with_grpc_port = hostname + ":" + str(GRPC_PORT)
channel = grpc.insecure_channel(node_ip_with_grpc_port) channel = grpc.insecure_channel(node_ip_with_grpc_port)
grpc.channel_ready_future(channel).result(timeout=10) grpc.channel_ready_future(channel).result(timeout=10)
global main_channel global main_channel
@ -204,6 +209,11 @@ def test_select_one():
assert query("SELECT 1") == "1\n" assert query("SELECT 1") == "1\n"
def test_ipv6_select_one():
with create_channel(f"[{IPV6_ADDRESS}]") as channel:
assert query("SELECT 1", channel=channel) == "1\n"
def test_ordinary_query(): def test_ordinary_query():
assert query("SELECT count() FROM numbers(100)") == "100\n" assert query("SELECT count() FROM numbers(100)") == "100\n"