SSL and fast_forward : handling of SSL_ERROR_SYSCALL

pull/4062/head
René Cannaò 3 years ago
parent 4c21a6d8c7
commit 43d65cae60

@ -567,6 +567,8 @@ void ClickHouse_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t
query_no_space[query_no_space_length]=0;
}
proxy_debug(PROXY_DEBUG_SQLITE, 4, "Received query on Session %p , thread_session_id %u : %s\n", sess, sess->thread_session_id, query_no_space);
if (sess->session_type == PROXYSQL_SESSION_CLICKHOUSE) {
if (!strncasecmp("SET ", query_no_space, 4)) {

@ -3588,7 +3588,7 @@ bool MySQL_Thread::process_data_on_data_stream(MySQL_Data_Stream *myds, unsigned
int sslhp = SSL_has_pending(myds->ssl);
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p: in fast_forward mode and SSL read %d bytes , SSL_pending: %d bytes , SSL_has_pending: %d\n", myds->sess, rb, sslp, sslhp);
*/
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, DataStream=%p -- in fast_forward mode and SSL read %d bytes\n", myds->sess, myds, rb);
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, DataStream=%p , thread_session_id=%u -- in fast_forward mode and SSL read %d bytes\n", myds->sess, myds, myds->sess->thread_session_id, rb);
while (rb == 16384) {
rb = myds->read_from_net();
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, DataStream=%p -- in fast_forward mode and SSL read %d bytes\n", myds->sess, myds, rb);

@ -629,13 +629,12 @@ int MySQL_Data_Stream::read_from_net() {
}
} else {
int ssl_ret=SSL_get_error(ssl, r);
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, Datastream=%p -- SSL_get_error(): %d , errno: %d\n", sess, this, ssl_ret, errno);
if (ssl_ret!=SSL_ERROR_WANT_READ && ssl_ret!=SSL_ERROR_WANT_WRITE) shut_soft();
if (r==0) { // we couldn't read any data
if (ssl_ret == SSL_ERROR_SYSCALL && (errno == EINTR || errno == EAGAIN)) {
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, Datastream=%p -- SSL_get_error() is SSL_ERROR_SYSCALL, errno: %d\n", sess, this, errno);
// the read was interrupted, do nothing
} else {
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, Datastream=%p -- session_id: %u , SSL_get_error(): %d , errno: %d\n", sess, this, sess->thread_session_id, ssl_ret, errno);
if (ssl_ret == SSL_ERROR_SYSCALL && (errno == EINTR || errno == EAGAIN)) {
// the read was interrupted, do nothing
proxy_debug(PROXY_DEBUG_NET, 5, "Session=%p, Datastream=%p -- SSL_get_error() is SSL_ERROR_SYSCALL, errno: %d\n", sess, this, errno);
} else {
if (r==0) { // we couldn't read any data
if (revents==1) {
// revents returns 1 , but recv() returns 0 , so there is no data.
// Therefore the socket is already closed
@ -643,6 +642,8 @@ int MySQL_Data_Stream::read_from_net() {
shut_soft();
}
}
if (ssl_ret!=SSL_ERROR_WANT_READ && ssl_ret!=SSL_ERROR_WANT_WRITE) shut_soft();
// it seems we end in shut_soft() anyway
}
}
} else {
@ -673,11 +674,13 @@ int MySQL_Data_Stream::write_to_net() {
if (encrypted) {
bytes_io = SSL_write (ssl, queue_r_ptr(queueOUT), s);
//proxy_info("Used SSL_write to write %d bytes\n", bytes_io);
proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: SSL_write() wrote %d bytes . queueOUT before: %u\n", sess, this, bytes_io, queue_data(queueOUT));
if (ssl_write_len || wbio_ssl->num_write > wbio_ssl->num_read) {
//proxy_info("ssl_write_len = %d , num_write = %d , num_read = %d\n", ssl_write_len , wbio_ssl->num_write , wbio_ssl->num_read);
char buf[MY_SSL_BUFFER];
do {
n = BIO_read(wbio_ssl, buf, sizeof(buf));
proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: BIO_read() read %d bytes\n", sess, this, n);
//proxy_info("BIO read = %d\n", n);
if (n > 0) {
//proxy_info("Setting %d byte in queue encrypted\n", n);
@ -690,8 +693,10 @@ int MySQL_Data_Stream::write_to_net() {
}
} while (n>0);
}
proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: current ssl_write_len is %lu bytes\n", sess, this, ssl_write_len);
if (ssl_write_len) {
n = write(fd, ssl_write_buf, ssl_write_len);
proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: write() wrote %d bytes in FD %d\n", sess, this, n, fd);
//proxy_info("Calling write() on SSL: %d\n", n);
if (n>0) {
if ((size_t)n < ssl_write_len) {
@ -722,6 +727,7 @@ int MySQL_Data_Stream::write_to_net() {
#else
bytes_io = send(fd, queue_r_ptr(queueOUT), s, MSG_NOSIGNAL);
#endif
proxy_debug(PROXY_DEBUG_NET, 7, "Session=%p, Datastream=%p: send() wrote %d bytes in FD %d\n", sess, this, bytes_io, fd);
}
if (encrypted) {
//proxy_info("bytes_io: %d\n", bytes_io);

@ -372,6 +372,7 @@ void SQLite3_Server_session_handler(MySQL_Session *sess, void *_pa, PtrSize_t *p
query_no_space[query_no_space_length]=0;
}
proxy_debug(PROXY_DEBUG_SQLITE, 4, "Received query on Session %p , thread_session_id %u : %s\n", sess, sess->thread_session_id, query_no_space);
{
SQLite3_Session *sqlite_sess = (SQLite3_Session *)sess->thread->gen_args;

@ -18,6 +18,8 @@ Several bugs were identified and fixed while developing this test:
- several memory corruption in SSL and fast_forward
- SQLite3 Server stops working if the user is a fast_forward user
- potential stalls with large resultset
- connections being closed because of interrupted syscall in SSL (SSL_ERROR_SYSCALL)
*/
@ -64,10 +66,11 @@ std::vector<std::string> queries_SQL2 = {
"INSERT INTO tbl1459 SELECT NULL , i1 + id, i2 + id FROM tbl1459",
};
std::vector<unsigned long long int> queries_limits = {
1, 10, 20, 27, 103, 169, 320, 450, 512, 619, 915, 1022,
1033, 1145, 1516, 1920, 2034, 5014, 9932, 10111
1033, 1145, 1516, 1920, 2034, 5014, 9932, 10111,
11033, 11145, 12516, 11920, 12034, 15014, 19932,
21033, 21145, 22516, 21920, 22034, 25014, 29932
};
@ -80,8 +83,9 @@ int run_queries_sets(std::vector<std::string>& queries, MYSQL *my, const std::st
return 0;
}
#define ITER 4
#define ITER1 10
// ITER2 is big because we iterate many times in case SSL_ERROR_SYSCALL (interrupted syscall, that is normally a rare event) is triggered
#define ITER2 20
int main(int argc, char** argv) {
CommandLine cl;
@ -89,7 +93,10 @@ int main(int argc, char** argv) {
if(cl.getEnv())
return exit_status();
plan(5*ITER+5*ITER*queries_limits.size());
unsigned int p = 0;
p += 5*ITER1;
p += (5-3)*ITER2*queries_limits.size(); // only on encrypted backend connections
plan(p);
diag("Testing SSL and fast_forward");
MYSQL* mysqladmin = mysql_init(NULL);
@ -106,10 +113,10 @@ int main(int argc, char** argv) {
for (int i = 0 ; i<5 ; i++) {
mysqls[i] = NULL;
}
// We will loop ITER times.
// We will loop ITER1 times.
// On each iteration we create 5 connections with different configuration and run a simple SELECT 1
for (int it = 0 ; it<ITER ; it++) {
for (int it = 0 ; it<ITER1 ; it++) {
diag("We will reconfigure ProxySQL to use SQLite3 Server on hostgroup 1459, IP 127.0.0.1 and port 6030");
if (run_queries_sets(queries_set1, mysqladmin, "Running on Admin"))
@ -128,7 +135,7 @@ int main(int argc, char** argv) {
}
MYSQL_QUERY(mysqls[0], "select 1");
MYSQL_RES* result = mysql_store_result(mysqls[0]);
ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 1");
ok(mysql_num_rows(result) == 1, "Line %d: Select statement should be executed on connection 1" , __LINE__);
mysql_free_result(result);
@ -150,7 +157,7 @@ int main(int argc, char** argv) {
}
MYSQL_QUERY(mysqls[1], "select 1");
result = mysql_store_result(mysqls[1]);
ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 2");
ok(mysql_num_rows(result) == 1, "Line %d: Select statement should be executed on connection 2" , __LINE__);
mysql_free_result(result);
@ -170,7 +177,7 @@ int main(int argc, char** argv) {
}
MYSQL_QUERY(mysqls[2], "select 1");
result = mysql_store_result(mysqls[2]);
ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 3");
ok(mysql_num_rows(result) == 1, "Line %d: Select statement should be executed on connection 3" , __LINE__);
mysql_free_result(result);
@ -189,7 +196,7 @@ int main(int argc, char** argv) {
}
MYSQL_QUERY(mysqls[3], "select 1");
result = mysql_store_result(mysqls[3]);
ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 4");
ok(mysql_num_rows(result) == 1, "Line %d: Select statement should be executed on connection 4" , __LINE__);
mysql_free_result(result);
@ -209,11 +216,11 @@ int main(int argc, char** argv) {
}
MYSQL_QUERY(mysqls[4], "select 1");
result = mysql_store_result(mysqls[4]);
ok(mysql_num_rows(result) == 1, "Select statement should be executed on connection 5");
ok(mysql_num_rows(result) == 1, "Line %d: Select statement should be executed on connection 5" , __LINE__);
mysql_free_result(result);
if (it != ITER - 1) {
if (it != ITER1 - 1) {
for (int i = 0 ; i<5 ; i++) {
mysql_close(mysqls[i]);
}
@ -230,22 +237,29 @@ int main(int argc, char** argv) {
return exit_status();
}
for (int it = 0 ; it<ITER ; it++) {
for (int it = 0 ; it<ITER2 ; it++) {
// we now run each SELECT FROM tbl1459 on each connections
// we intentionally have the connections in the inner loop so to use all the connection through the test
for (auto it = queries_limits.begin(); it != queries_limits.end(); it++) {
unsigned long long int l = *it;
std::string q = "SELECT * FROM tbl1459 LIMIT " + std::to_string(l);
for (int i=0; i<5; i++) {
for (int i=3; i<5; i++) { // only on encrypted backend connections
MYSQL_QUERY(mysqls[i], q.c_str());
MYSQL_RES* result = mysql_store_result(mysqls[i]);
unsigned long long int rr = mysql_num_rows(result);
ok(rr == l, "Select statement on connection %d: expects %llu rows, returned %llu", i, l, rr);
ok(rr == l, "Line: %d: Select statement on connection %d (%lu): expects %llu rows, returned %llu", __LINE__, i, mysqls[i]->thread_id, l, rr);
mysql_free_result(result);
}
}
}
for (int i=0; i<5; i++) {
diag("Connection %d has thread_id: %lu", i, mysqls[i]->thread_id);
}
mysql_close(mysqladmin);
return exit_status();

Loading…
Cancel
Save