-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Expand file tree
/
Copy pathConnectionParameters.cpp
More file actions
197 lines (167 loc) · 7.56 KB
/
Copy pathConnectionParameters.cpp
File metadata and controls
197 lines (167 loc) · 7.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#include <Client/ConnectionParameters.h>
#include <Core/Defines.h>
#include <Core/Protocol.h>
#include <IO/ConnectionTimeouts.h>
#include <Poco/Util/AbstractConfiguration.h>
#include <Common/Exception.h>
#include <Common/isLocalAddress.h>
#include <Common/DNSResolver.h>
#include <Client/ClientBaseHelpers.h>
#include <readpassphrase/readpassphrase.h>
namespace DB
{
namespace ErrorCodes
{
extern const int BAD_ARGUMENTS;
extern const int SUPPORT_IS_DISABLED;
}
namespace
{
bool enableSecureConnection(const Poco::Util::AbstractConfiguration & config, const std::string & connection_host,
const std::optional<UInt16> & connection_port = std::nullopt)
{
if (config.getBool("secure", false))
return true;
if (config.getBool("no-secure", false))
return false;
if (isCloudEndpoint(connection_host))
return true;
if (connection_port && connection_port.value() == DBMS_DEFAULT_SECURE_PORT)
return true;
return false;
}
}
ConnectionParameters ConnectionParameters::createForEmbedded(const String & user, const String & database)
{
auto connection_params = ConnectionParameters();
connection_params.host = "localhost";
connection_params.security = Protocol::Secure::Disable;
connection_params.password = "";
connection_params.user = user;
connection_params.default_database = database;
connection_params.compression = Protocol::Compression::Disable;
/// We don't need to configure the timeouts for the embedded client.
connection_params.timeouts.sync_request_timeout = Poco::Timespan(DBMS_DEFAULT_SYNC_REQUEST_TIMEOUT_SEC, 0);
return connection_params;
}
ConnectionParameters::ConnectionParameters(const Poco::Util::AbstractConfiguration & config,
const Host & host_,
const Database & database,
std::optional<UInt16> port_)
: host(host_)
, port(port_.value_or(getPortFromConfig(config, host_)))
, default_database(database)
{
security = enableSecureConnection(config, host_) ? Protocol::Secure::Enable : Protocol::Secure::Disable;
tls_sni_override = config.getString("tls-sni-override", "");
bind_host = config.getString("bind_host", "");
/// changed the default value to "default" to fix the issue when the user in the prompt is blank
user = config.getString("user", "default");
if (config.has("jwt"))
{
#if USE_JWT_CPP && USE_SSL
jwt = config.getString("jwt");
#else
throw Exception(ErrorCodes::SUPPORT_IS_DISABLED, "JWT is disabled, because ClickHouse is built without JWT or SSL support");
#endif
}
else if (config.has("ssh-key-file"))
{
#if USE_SSH
std::string filename = config.getString("ssh-key-file");
std::string passphrase;
if (config.has("ssh-key-passphrase"))
{
passphrase = config.getString("ssh-key-passphrase");
}
else
{
std::string prompt{"Enter your SSH private key passphrase (leave empty for no passphrase): "};
char buf[1000] = {};
if (auto * result = readpassphrase(prompt.c_str(), buf, sizeof(buf), 0))
passphrase = result;
}
SSHKey key = SSHKeyFactory::makePrivateKeyFromFile(filename, passphrase);
if (!key.isPrivate())
throw Exception(ErrorCodes::BAD_ARGUMENTS, "File {} did not contain a private key (is it a public key?)", filename);
ssh_private_key = std::move(key);
#else
throw Exception(ErrorCodes::SUPPORT_IS_DISABLED, "SSH is disabled, because ClickHouse is built without libssh");
#endif
}
else
{
bool password_prompt = false;
if (config.getBool("ask-password", false))
{
if (config.has("password"))
throw Exception(ErrorCodes::BAD_ARGUMENTS, "Specified both --password and --ask-password. Remove one of them");
password_prompt = true;
}
else
{
password = config.getString("password", "");
/// if the value of --password is omitted, the password will be set implicitly to "\n"
if (password == ASK_PASSWORD)
password_prompt = true;
}
if (password_prompt)
{
std::string prompt{"Password for user (" + user + "): "};
char buf[1000] = {};
if (auto * result = readpassphrase(prompt.c_str(), buf, sizeof(buf), 0))
password = result;
}
if (config.has("one-time-password"))
{
password += "+";
password += config.getString("one-time-password");
}
else if (config.getBool("ask-password-2fa", false))
{
std::string prompt{"TOTP for user (" + user + "): "};
char buf[1000] = {};
if (auto * result = readpassphrase(prompt.c_str(), buf, sizeof(buf), RPP_ECHO_ON))
password += "+" + std::string(result);
}
}
proto_send_chunked = config.getString("proto_caps.send", "notchunked");
proto_recv_chunked = config.getString("proto_caps.recv", "notchunked");
quota_key = config.getString("quota_key", "");
/// By default compression is disabled if address looks like localhost.
/// Avoid DNS request if the host is "localhost".
/// If ClickHouse is run under QEMU-user with a binary for a different architecture,
/// and there are all listed startup dependency shared libraries available, but not the runtime dependencies of glibc,
/// the glibc cannot open "plugins" for DNS resolving, and the DNS resolution does not work.
/// At the same time, I want clickhouse-local to always work, regardless.
/// TODO: get rid of glibc, or replace getaddrinfo to c-ares.
compression = config.getBool("compression", host != "localhost" && !isLocalAddress(DNSResolver::instance().resolveHostAllInOriginOrder(host).front()))
? Protocol::Compression::Enable : Protocol::Compression::Disable;
timeouts = ConnectionTimeouts()
.withConnectionTimeout(
Poco::Timespan(config.getInt("connect_timeout", DBMS_DEFAULT_CONNECT_TIMEOUT_SEC), 0))
.withSendTimeout(
Poco::Timespan(config.getInt("send_timeout", DBMS_DEFAULT_SEND_TIMEOUT_SEC), 0))
.withReceiveTimeout(
Poco::Timespan(config.getInt("receive_timeout", DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC), 0))
.withTCPKeepAliveTimeout(
Poco::Timespan(config.getInt("tcp_keep_alive_timeout", DEFAULT_TCP_KEEP_ALIVE_TIMEOUT), 0))
.withHandshakeTimeout(
Poco::Timespan(config.getInt("handshake_timeout_ms", DBMS_DEFAULT_RECEIVE_TIMEOUT_SEC * 1000) * 1000))
.withSyncRequestTimeout(
Poco::Timespan(config.getInt("sync_request_timeout", DBMS_DEFAULT_SYNC_REQUEST_TIMEOUT_SEC), 0));
}
ConnectionParameters::ConnectionParameters(const Poco::Util::AbstractConfiguration & config_, const Host & host_, const Database & database_)
: ConnectionParameters(config_, host_, database_, getPortFromConfig(config_, host_))
{
}
UInt16 ConnectionParameters::getPortFromConfig(const Poco::Util::AbstractConfiguration & config,
const std::string & connection_host)
{
bool is_secure = enableSecureConnection(config, connection_host);
return static_cast<UInt16>(config.getInt(
"port",
static_cast<UInt16>(
config.getInt(is_secure ? "tcp_port_secure" : "tcp_port", is_secure ? DBMS_DEFAULT_SECURE_PORT : DBMS_DEFAULT_PORT))));
}
}