You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-07 02:42:49 +03:00
Workaround for CONC-417, MDEV-13492
At irregular intervals older windows versions (prior Windows 10) fail to establish a secure (TLS) connection and return errors SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED. This is a bug in windows schannel library and was only fixed in recent versions, also OpenSSL provided a workaround (see https://github.com/openssl/openssl/pull/1350). Since we are unable to fix this, we introduced a workaround for this problem. In case of an error during TLS handshake we check the errorcode and try to reconnect up to three times if the error code was SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED.
This commit is contained in:
@@ -91,6 +91,7 @@ typedef struct st_connection_handler
|
|||||||
|
|
||||||
struct st_mariadb_net_extension {
|
struct st_mariadb_net_extension {
|
||||||
enum enum_multi_status multi_status;
|
enum enum_multi_status multi_status;
|
||||||
|
int extended_errno;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct st_mariadb_session_state
|
struct st_mariadb_session_state
|
||||||
|
@@ -140,6 +140,7 @@ extern const char *SQLSTATE_UNKNOWN;
|
|||||||
(a)->net.last_errno= 0;\
|
(a)->net.last_errno= 0;\
|
||||||
strcpy((a)->net.sqlstate, "00000");\
|
strcpy((a)->net.sqlstate, "00000");\
|
||||||
(a)->net.last_error[0]= '\0';\
|
(a)->net.last_error[0]= '\0';\
|
||||||
|
(a)->net.extension->extended_errno= 0;\
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MYSQL_COUNT_ERROR (~(unsigned long long) 0)
|
#define MYSQL_COUNT_ERROR (~(unsigned long long) 0)
|
||||||
|
@@ -1020,7 +1020,7 @@ mysql_init(MYSQL *mysql)
|
|||||||
mysql->charset= mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
|
mysql->charset= mysql_find_charset_name(MARIADB_DEFAULT_CHARSET);
|
||||||
mysql->methods= &MARIADB_DEFAULT_METHODS;
|
mysql->methods= &MARIADB_DEFAULT_METHODS;
|
||||||
strcpy(mysql->net.sqlstate, "00000");
|
strcpy(mysql->net.sqlstate, "00000");
|
||||||
mysql->net.last_error[0]= mysql->net.last_errno= 0;
|
mysql->net.last_error[0]= mysql->net.last_errno= mysql->net.extension->extended_errno= 0;
|
||||||
|
|
||||||
if (ENABLED_LOCAL_INFILE != LOCAL_INFILE_MODE_OFF)
|
if (ENABLED_LOCAL_INFILE != LOCAL_INFILE_MODE_OFF)
|
||||||
mysql->options.client_flag|= CLIENT_LOCAL_FILES;
|
mysql->options.client_flag|= CLIENT_LOCAL_FILES;
|
||||||
@@ -1199,9 +1199,39 @@ mysql_real_connect(MYSQL *mysql, const char *host, const char *user,
|
|||||||
return my;
|
return my;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifndef HAVE_SCHANNEL
|
||||||
return mysql->methods->db_connect(mysql, host, user, passwd,
|
return mysql->methods->db_connect(mysql, host, user, passwd,
|
||||||
db, port, unix_socket, client_flag);
|
db, port, unix_socket, client_flag);
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
With older windows versions (prior Win 10) TLS connections periodically
|
||||||
|
fail with SEC_E_INVALID_TOKEN, SEC_E_BUFFER_TOO_SMALL or SEC_E_MESSAGE_ALTERED
|
||||||
|
error (see MDEV-13492). If the connect attempt returns on of these error codes
|
||||||
|
in mysql->net.extended_errno we will try to connect again (max. 3 times)
|
||||||
|
*/
|
||||||
|
#define MAX_SCHANNEL_CONNECT_ATTEMPTS 3
|
||||||
|
{
|
||||||
|
int ssl_retry= (mysql->options.use_ssl) ? MAX_SCHANNEL_CONNECT_ATTEMPTS : 1;
|
||||||
|
MYSQL *my= NULL;
|
||||||
|
while (ssl_retry)
|
||||||
|
{
|
||||||
|
if ((my= mysql->methods->db_connect(mysql, host, user, passwd,
|
||||||
|
db, port, unix_socket, client_flag)))
|
||||||
|
return my;
|
||||||
|
|
||||||
|
switch (mysql->net.extension->extended_errno) {
|
||||||
|
case SEC_E_INVALID_TOKEN:
|
||||||
|
case SEC_E_BUFFER_TOO_SMALL:
|
||||||
|
case SEC_E_MESSAGE_ALTERED:
|
||||||
|
ssl_retry--;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return my;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
|
MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
|
||||||
|
@@ -32,6 +32,10 @@ void ma_schannel_set_win_error(MARIADB_PVIO *pvio);
|
|||||||
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo)
|
void ma_schannel_set_sec_error(MARIADB_PVIO *pvio, DWORD ErrorNo)
|
||||||
{
|
{
|
||||||
MYSQL *mysql= pvio->mysql;
|
MYSQL *mysql= pvio->mysql;
|
||||||
|
|
||||||
|
if (ErrorNo != SEC_E_OK)
|
||||||
|
mysql->net.extension->extended_errno= ErrorNo;
|
||||||
|
|
||||||
switch(ErrorNo) {
|
switch(ErrorNo) {
|
||||||
case SEC_E_ILLEGAL_MESSAGE:
|
case SEC_E_ILLEGAL_MESSAGE:
|
||||||
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: The message received was unexpected or badly formatted");
|
pvio->set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: The message received was unexpected or badly formatted");
|
||||||
|
Reference in New Issue
Block a user