1 /*
2 * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2.0,
6 * as published by the Free Software Foundation.
7 *
8 * This program is also distributed with certain software (including
9 * but not limited to OpenSSL) that is licensed under separate terms,
10 * as designated in a particular file or component or in included license
11 * documentation. The authors of MySQL hereby grant you an additional
12 * permission to link the program and your derivative works with the
13 * separately licensed software that they have included with MySQL.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License, version 2.0, for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26 #include "xpl_server.h"
27 #include "xpl_session.h"
28 #include "mysql_show_variable_wrapper.h"
29
30 #include "ngs_common/string_formatter.h"
31 #include "ngs/thread.h"
32
33 #include "ngs/capabilities/configurator.h"
34 #include "ngs/capabilities/handler_readonly_value.h"
35 #include "cap_handles_expired_passwords.h"
36
37 #include "mysqlx_version.h"
38 #include "mysql_variables.h"
39 #include "xpl_client.h"
40
41 // needed for ip_to_hostname(), should probably be turned into a service
42 #include "hostname.h"
43
44
45 using namespace xpl;
46
Client(ngs::Connection_ptr connection,ngs::Server_interface & server,Client_id client_id,Protocol_monitor * pmon)47 Client::Client(ngs::Connection_ptr connection, ngs::Server_interface &server, Client_id client_id,
48 Protocol_monitor *pmon)
49 : ngs::Client(connection, server, client_id, *pmon),
50 m_supports_expired_passwords(false),
51 m_protocol_monitor(pmon)
52 {
53 if (m_protocol_monitor)
54 m_protocol_monitor->init(this);
55 }
56
57
~Client()58 Client::~Client()
59 {
60 ngs::free_object(m_protocol_monitor);
61 }
62
63
on_session_close(ngs::Session_interface & s)64 void Client::on_session_close(ngs::Session_interface &s)
65 {
66 ngs::Client::on_session_close(s);
67 if (s.state_before_close() != ngs::Session_interface::Authenticating)
68 {
69 ++Global_status_variables::instance().m_closed_sessions_count;
70 }
71 }
72
73
on_session_reset(ngs::Session_interface & s)74 void Client::on_session_reset(ngs::Session_interface &s)
75 {
76 ngs::Client::on_session_reset(s);
77 }
78
79
set_supports_expired_passwords(bool flag)80 void Client::set_supports_expired_passwords(bool flag)
81 {
82 m_supports_expired_passwords = flag;
83 }
84
supports_expired_passwords()85 bool Client::supports_expired_passwords()
86 {
87 return m_supports_expired_passwords;
88 }
89
capabilities_configurator()90 ngs::Capabilities_configurator *Client::capabilities_configurator()
91 {
92 ngs::Capabilities_configurator *caps = ngs::Client::capabilities_configurator();
93
94 // add our capabilities
95 caps->add_handler(ngs::allocate_shared<ngs::Capability_readonly_value>("node_type", "mysql"));
96 caps->add_handler(ngs::allocate_shared<Cap_handles_expired_passwords>(ngs::ref(*this)));
97
98 return caps;
99 }
100
get_session()101 ngs::shared_ptr<xpl::Session> Client::get_session()
102 {
103 return ngs::static_pointer_cast<xpl::Session>(session());
104 }
105
106
107 /** Close the client from another thread
108
109 This can be called from any thread, so care must be taken to not call
110 anything that's not thread safe from here.
111 */
kill()112 void Client::kill()
113 {
114 if (m_state == Client_accepted)
115 {
116 disconnect_and_trigger_close();
117 return;
118 }
119
120 m_session->on_kill();
121 ++Global_status_variables::instance().m_killed_sessions_count;
122 }
123
124
on_network_error(int error)125 void Client::on_network_error(int error)
126 {
127 ngs::Client::on_network_error(error);
128 if (error != 0)
129 ++Global_status_variables::instance().m_connection_errors_count;
130 }
131
132
on_server_shutdown()133 void Client::on_server_shutdown()
134 {
135 ngs::shared_ptr<ngs::Session_interface> local_copy = m_session;
136
137 if (local_copy)
138 local_copy->on_kill();
139
140 ngs::Client::on_server_shutdown();
141 }
142
143
on_auth_timeout()144 void Client::on_auth_timeout()
145 {
146 ngs::Client::on_auth_timeout();
147
148 ++Global_status_variables::instance().m_connection_errors_count;
149 }
150
151
is_handler_thd(THD * thd)152 bool Client::is_handler_thd(THD *thd)
153 {
154 ngs::shared_ptr<ngs::Session_interface> session = this->session();
155
156 return thd && session && (session->is_handled_by(thd));
157 }
158
159
get_status_ssl_cipher_list(st_mysql_show_var * var)160 void Client::get_status_ssl_cipher_list(st_mysql_show_var * var)
161 {
162 std::vector<std::string> ciphers = connection().options()->ssl_cipher_list();
163
164 mysqld::xpl_show_var(var).assign(ngs::join(ciphers, ":"));
165 }
166
167
resolve_hostname()168 std::string Client::resolve_hostname()
169 {
170 std::string result;
171 std::string socket_ip_string;
172 uint16 socket_port;
173
174 sockaddr_storage *addr = m_connection->peer_address(socket_ip_string, socket_port);
175
176 if (NULL == addr)
177 {
178 log_error("%s: get peer address failed, can't resolve IP to hostname", m_id);
179 return "";
180 }
181
182 char *hostname = NULL;
183 uint connect_errors = 0;
184 const int resolve_result = ip_to_hostname(addr, socket_ip_string.c_str(), &hostname, &connect_errors);
185
186 if (RC_BLOCKED_HOST == resolve_result) {
187 throw std::runtime_error("Host is blocked");
188 }
189
190 if (hostname) {
191 result = hostname;
192
193 if (!is_localhost(hostname))
194 my_free(hostname);
195 }
196
197 return result;
198 }
199
200
is_localhost(const char * hostname)201 bool Client::is_localhost(const char *hostname)
202 {
203 return hostname == mysqld::get_my_localhost();
204 }
205
206
init(Client * client)207 void Protocol_monitor::init(Client *client)
208 {
209 m_client = client;
210 }
211
212
213 namespace
214 {
215 template<xpl::Common_status_variables::Variable xpl::Common_status_variables::*variable>
update_status(ngs::shared_ptr<xpl::Session> session)216 inline void update_status(ngs::shared_ptr<xpl::Session> session)
217 {
218 if (session)
219 ++(session->get_status_variables().*variable);
220 ++(Global_status_variables::instance().*variable);
221 }
222
223
224 template<xpl::Common_status_variables::Variable xpl::Common_status_variables::*variable>
update_status(ngs::shared_ptr<xpl::Session> session,long param)225 inline void update_status(ngs::shared_ptr<xpl::Session> session, long param)
226 {
227 if (session)
228 (session->get_status_variables().*variable) += param;
229 (Global_status_variables::instance().*variable) += param;
230 }
231 } // namespace
232
233
on_notice_warning_send()234 void Protocol_monitor::on_notice_warning_send()
235 {
236 update_status<&Common_status_variables::m_notice_warning_sent>(m_client->get_session());
237 }
238
239
on_notice_other_send()240 void Protocol_monitor::on_notice_other_send()
241 {
242 update_status<&Common_status_variables::m_notice_other_sent>(m_client->get_session());
243 }
244
245
on_error_send()246 void Protocol_monitor::on_error_send()
247 {
248 update_status<&Common_status_variables::m_errors_sent>(m_client->get_session());
249 }
250
251
on_fatal_error_send()252 void Protocol_monitor::on_fatal_error_send()
253 {
254 ++Global_status_variables::instance().m_sessions_fatal_errors_count;
255 }
256
257
on_init_error_send()258 void Protocol_monitor::on_init_error_send()
259 {
260 ++Global_status_variables::instance().m_init_errors_count;
261 }
262
263
on_row_send()264 void Protocol_monitor::on_row_send()
265 {
266 update_status<&Common_status_variables::m_rows_sent>(m_client->get_session());
267 }
268
269
on_send(long bytes_transferred)270 void Protocol_monitor::on_send(long bytes_transferred)
271 {
272 update_status<&Common_status_variables::m_bytes_sent>(m_client->get_session(), bytes_transferred);
273 }
274
275
on_receive(long bytes_transferred)276 void Protocol_monitor::on_receive(long bytes_transferred)
277 {
278 update_status<&Common_status_variables::m_bytes_received>(m_client->get_session(), bytes_transferred);
279 }
280
281
on_error_unknown_msg_type()282 void Protocol_monitor::on_error_unknown_msg_type()
283 {
284 update_status<&Common_status_variables::m_errors_unknown_message_type>(m_client->get_session());
285 }
286