diff --git a/Documentation/Changelog.md b/Documentation/Changelog.md index 52cc40b2d..4bb672149 100644 --- a/Documentation/Changelog.md +++ b/Documentation/Changelog.md @@ -49,6 +49,7 @@ For more details, please refer to: * MaxScale now supports IPv6 For more details, please refer to: +* [MariaDB MaxScale 2.1.11 Release Notes](Release-Notes/MaxScale-2.1.11-Release-Notes.md) * [MariaDB MaxScale 2.1.10 Release Notes](Release-Notes/MaxScale-2.1.10-Release-Notes.md) * [MariaDB MaxScale 2.1.9 Release Notes](Release-Notes/MaxScale-2.1.9-Release-Notes.md) * [MariaDB MaxScale 2.1.8 Release Notes](Release-Notes/MaxScale-2.1.8-Release-Notes.md) diff --git a/Documentation/Getting-Started/Configuration-Guide.md b/Documentation/Getting-Started/Configuration-Guide.md index ab049cfb9..060d5250b 100644 --- a/Documentation/Getting-Started/Configuration-Guide.md +++ b/Documentation/Getting-Started/Configuration-Guide.md @@ -15,9 +15,8 @@ plugin modules that tailor the behavior of the program. * [Global Settings](#global-settings) * [Service](#service) * [Server](#server) - * [Server and SSL](#server-and-ssl) * [Listener](#listener) - * [Listener and SSL](#listener-and-ssl) + * [TLS/SSL Encryption](#tlsssl-encryption) * [Router Modules](#routing-modules) * [Diagnostic Modules](#diagnostic-modules) * [Monitor Modules](#monitor-modules) @@ -198,13 +197,14 @@ auth_write_timeout=10 #### `query_retries` -The number of times an interrupted query will be retried. This feature was added -in MaxScale 2.1.10 and is disabled by default. +The number of times an interrupted internal query will be retried. This feature +was added in MaxScale 2.1.10 and is disabled by default. An interrupted query is any query that is interrupted by a network error. Connection timeouts are included in network errors and thus is it advisable to make sure that the value of `query_retry_timeout` is set to an -adequate value. +adequate value. Internal queries are only used to retrieve authentication data +and monitor the servers. #### `query_retry_timeout` @@ -1183,100 +1183,6 @@ Option string given to the authenticator module. The value of this parameter should be a comma-separated list of key-value pairs. See authenticator specific documentation for more details. -### Server and SSL - -This section describes configuration parameters for servers that control the -SSL/TLS encryption method and the various certificate files involved in it when -applied to back end servers. To enable SSL between MaxScale and a back end -server, you must configure the `ssl` parameter in the relevant server section to -the value `required` and provide the three files for `ssl_cert`, `ssl_key` and -`ssl_ca_cert`. After this, MaxScale connections to this server will be encrypted -with SSL. Attempts to connect to the server without using SSL will cause -failures. Hence, the database server in question must have been configured to be -able to accept SSL connections. - -#### `ssl` - -This enables SSL connections to the server, when set to `required`. If that is -done, the three certificate files mentioned below must also be supplied. -MaxScale connections to this server will then be encrypted with SSL. If this is -not possible, client connection attempts that rely on the server will fail. - -#### `ssl_key` - -A string giving a file path that identifies an existing readable file. The file -must be the SSL client private key MaxScale should use with the server. This -will be the private key that is used as the client side private key during a -MaxScale-server SSL handshake. This is currently a required parameter for SSL -enabled servers. - -#### `ssl_cert` - -A string giving a file path that identifies an existing readable file. The file -must be the SSL client certificate MaxScale should use with the server. This -will be the public certificate that is used as the client side certificate -during a MaxScale-server SSL handshake. This is a required parameter for SSL -enabled servers. The certificate must be compatible with the key defined above. - -#### `ssl_ca_cert` - -A string giving a file path that identifies an existing readable file. The file -must be the SSL Certificate Authority (CA) certificate for the CA that signed -the client certificate referred to in the previous parameter. It will be used to -verify that the client certificate is valid. This is a required parameter for -SSL enabled listeners. - -#### `ssl_version` - -This parameter controls the level of encryption used. Accepted values are: - - * TLSv10 - * TLSv11 - * TLSv12 - * MAX - -The default is to use the highest level of encryption available. For OpenSSL 1.0 -and newer this is TLSv1.2. Older versions use TLSv1.0 as the default transport -layer encryption. - -**Note:** It is highly recommended to leave this parameter to the default value - of _MAX_. This will guarantee that the strongest available encryption is used. - -#### `ssl_cert_verification_depth` - -The maximum length of the certificate authority chain that will be accepted. -Legal values are positive integers. Note that if the client is to submit an SSL -certificate, the `ssl_cert_verification_depth` parameter must not be 0. If no -value is specified, the default is 9. - -``` -# Example -ssl_cert_verification_depth=5 -``` - -**Example SSL enabled server configuration:** - -``` -[server1] -type=server -address=10.131.24.62 -port=3306 -protocol=MySQLBackend -#persistpoolmax=200 -persistmaxtime=3000 -ssl=required -ssl_version=TLSv10 -ssl_cert=/usr/local/mariadb/maxscale/ssl/crt.max-client.pem -ssl_key=/usr/local/mariadb/maxscale/ssl/key.max-client.pem -ssl_ca_cert=/usr/local/mariadb/maxscale/ssl/crt.ca.maxscale.pem - -``` - -This example configuration requires all connections to this server to be -encrypted with SSL. It also specifies that TLSv1.0 should be used as the -encryption method. The paths to the server certificate files and the Certificate -Authority file are also provided. - ### Listener The listener defines a port and protocol pair that is used to listen for @@ -1390,73 +1296,98 @@ This protocol module is currently still under development, it provides a means to create HTTP connections to MariaDB MaxScale for use by web browsers or RESTful API clients. -### Listener and SSL +### TLS/SSL encryption -This section describes configuration parameters for listeners that control the -SSL/TLS encryption method and the various certificate files involved in it. To -enable SSL from client to MaxScale, you must configure the `ssl` parameter to -the value `required` and provide the three files for `ssl_cert`, `ssl_key` and -`ssl_ca_cert`. After this, MySQL connections to this listener will be encrypted -with SSL. Attempts to connect to the listener with a non-SSL client will fail. -Note that the same service can have an SSL listener and a non-SSL listener if -you wish, although they must be on different ports. +This section describes configuration parameters for both servers and listeners +that control the TLS/SSL encryption method and the various certificate files +involved in it. + +To enable TLS/SSL for a listener or a server, you must set the `ssl` parameter +to `required` and provide the three files for `ssl_cert`, `ssl_key` and +`ssl_ca_cert`. + +After this, MaxScale connections between the server and/or the client will be +encrypted. Note that the database must be configured to use TLS/SSL connections +if backend connection encryption is used. When client-side encryption is +enabled, only encrypted connections to MaxScale can be created. #### `ssl` -This enables SSL connections to the listener, when set to `required`. If that is -done, the three certificate files mentioned below must also be supplied. Client -connections to this listener will then be encrypted with SSL. Non-SSL -connections will get an error when they try to connect to the listener. +This enables SSL connections when set to `required`. If enabled, the three +certificate files mentioned below must also be supplied. MaxScale connections +to will then be encrypted with TLS/SSL. #### `ssl_key` A string giving a file path that identifies an existing readable file. The file -must be the SSL private key the listener should use. This will be the private -key that is used as the server side private key during a client-server SSL -handshake. This is a required parameter for SSL enabled listeners. +must be the SSL client private key MaxScale should use. This is a required +parameter for SSL enabled configurations. #### `ssl_cert` A string giving a file path that identifies an existing readable file. The file -must be the SSL certificate the listener should use. This will be the public -certificate that is used as the server side certificate during a client-server -SSL handshake. This is a required parameter for SSL enabled listeners. The -certificate must be compatible with the key defined above. +must be the SSL client certificate MaxScale should use with the server. This is +a required parameter for SSL enabled configurations. The certificate must match +the key defined in `ssl_key`. #### `ssl_ca_cert` A string giving a file path that identifies an existing readable file. The file -must be the SSL Certificate Authority (CA) certificate for the CA that signed -the server certificate referred to in the previous parameter. It will be used to -verify that the server certificate is valid. This is a required parameter for -SSL enabled listeners. +must be the Certificate Authority (CA) certificate for the CA that signed the +certificate referred to in the previous parameter. It will be used to verify +that the certificate is valid. This is a required parameter for SSL enabled +configurations. #### `ssl_version` This parameter controls the level of encryption used. Accepted values are: + * TLSv10 * TLSv11 * TLSv12 * MAX -If possible, use TLSv12 for best security. Recent Linux systems will include a -version of OpenSSL that supports TLS version 1.2. Only if you are using -MaxScale on a system that does not have OpenSSL with support for this should -earlier versions be used. It is unlikely that TLS 1.1 will be available unless -TLS 1.2 is also available. MAX will use the best available version. +The default is to use the highest level of encryption available. For OpenSSL 1.0 +and newer this is TLSv1.2. Older versions use TLSv1.0 as the default transport +layer encryption. -#### `ssl_cert_verification_depth` +**Note:** It is highly recommended to leave this parameter to the default value + of _MAX_. This will guarantee that the strongest available encryption is used. + +#### `ssl_cert_verify_depth` The maximum length of the certificate authority chain that will be accepted. Legal values are positive integers. Note that if the client is to submit an SSL -certificate, the `ssl_cert_verification_depth` parameter must not be 0. If no +certificate, the `ssl_cert_verify_depth` parameter must not be 0. If no value is specified, the default is 9. +#### `ssl_verify_peer_certificate` + +Peer certificate verification. This functionality is enabled by default. + +When this feature is enabled, the certificate sent by the peer is verified +against the configured Certificate Authority. If you are using self-signed +certificates, disable this feature. + +**Example SSL enabled server configuration:** + ``` -# Example -ssl_cert_verification_depth=5 +[server1] +type=server +address=10.131.24.62 +port=3306 +protocol=MySQLBackend +ssl=required +ssl_cert=/usr/local/mariadb/maxscale/ssl/crt.max-client.pem +ssl_key=/usr/local/mariadb/maxscale/ssl/key.max-client.pem +ssl_ca_cert=/usr/local/mariadb/maxscale/ssl/crt.ca.maxscale.pem + ``` +This example configuration requires all connections to this server to be +encrypted with SSL. The paths to the certificate files and the Certificate +Authority file are also provided. + **Example SSL enabled listener configuration:** ``` @@ -1464,21 +1395,16 @@ ssl_cert_verification_depth=5 type=listener service=RW Split Router protocol=MySQLClient -address=10.131.218.83 port=3306 -authenticator=MySQL ssl=required ssl_cert=/usr/local/mariadb/maxscale/ssl/crt.maxscale.pem ssl_key=/usr/local/mariadb/maxscale/ssl/key.csr.maxscale.pem ssl_ca_cert=/usr/local/mariadb/maxscale/ssl/crt.ca.maxscale.pem -ssl_version=TLSv12 -ssl_cert_verify_depth=9 ``` -This example configuration requires all connections to be encrypted with SSL. It -also specifies that TLSv1.2 should be used as the encryption method. The paths -to the server certificate files and the Certificate Authority file are also -provided. +This example configuration requires all connections to be encrypted with +SSL. The paths to the certificate files and the Certificate Authority file are +also provided. ## Routing Modules diff --git a/Documentation/Release-Notes/MaxScale-2.1.11-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.1.11-Release-Notes.md new file mode 100644 index 000000000..837bfa22e --- /dev/null +++ b/Documentation/Release-Notes/MaxScale-2.1.11-Release-Notes.md @@ -0,0 +1,54 @@ +# MariaDB MaxScale 2.1.11 Release Notes -- 2017-11-21 + +Release 2.1.11 is a GA release. + +This document describes the changes in release 2.1.11, when compared +to release [2.1.10](MaxScale-2.1.10-Release-Notes.md). + +If you are upgrading from release 2.0, please also read the following +release notes: + +* [2.1.10](./MaxScale-2.1.10-Release-Notes.md) +* [2.1.9](./MaxScale-2.1.9-Release-Notes.md) +* [2.1.8](./MaxScale-2.1.8-Release-Notes.md) +* [2.1.7](./MaxScale-2.1.7-Release-Notes.md) +* [2.1.6](./MaxScale-2.1.6-Release-Notes.md) +* [2.1.5](./MaxScale-2.1.5-Release-Notes.md) +* [2.1.4](./MaxScale-2.1.4-Release-Notes.md) +* [2.1.3](./MaxScale-2.1.3-Release-Notes.md) +* [2.1.2](./MaxScale-2.1.2-Release-Notes.md) +* [2.1.1](./MaxScale-2.1.1-Release-Notes.md) +* [2.1.0](./MaxScale-2.1.0-Release-Notes.md) + +For any problems you encounter, please consider submitting a bug report at +[Jira](https://jira.mariadb.org). + +## Changed Features + +### Peer Certificate Verification + +The SSL peer certificate verification can now be disabled for servers and +listeners by adding `ssl_verify_peer_certificate=false` to the respective +definitions. + +## Bug fixes + +[Here is a list of bugs fixed in MaxScale 2.1.11.](https://jira.mariadb.org/issues/?jql=project%20%3D%20MXS%20AND%20issuetype%20%3D%20Bug%20AND%20status%20%3D%20Closed%20AND%20fixVersion%20%3D%202.1.11) + +* [MXS-1518](https://jira.mariadb.org/browse/MXS-1518) Wrong parameter name for ssl_cert_verify_depth +* [MXS-1500](https://jira.mariadb.org/browse/MXS-1500) Invalid characters in real_type schema field + +## Packaging + +RPM and Debian packages are provided for the Linux distributions supported by +MariaDB Enterprise. + +Packages can be downloaded [here](https://mariadb.com/resources/downloads). + +## Source Code + +The source code of MaxScale is tagged at GitHub with a tag, which is identical +with the version of MaxScale. For instance, the tag of version X.Y.Z of MaxScale +is maxscale-X.Y.Z. + +The source code is available [here](https://github.com/mariadb-corporation/MaxScale). diff --git a/Documentation/Routers/Avrorouter.md b/Documentation/Routers/Avrorouter.md index 7267160d0..dbdeacacd 100644 --- a/Documentation/Routers/Avrorouter.md +++ b/Documentation/Routers/Avrorouter.md @@ -221,6 +221,25 @@ and a short usage description of the client program. # Avro Schema Generator +If the CREATE TABLE statements for the tables aren't present in the current +binary logs, the schema files must be generated with a schema file +generator. There are currently two methods to generate the .avsc schema files. + +## Python Schema Generator + +``` +usage: cdc_schema.py [--help] [-h HOST] [-P PORT] [-u USER] [-p PASSWORD] DATABASE +``` + +The _cdc_schema.py_ executable is installed as a part of MaxScale. This is a +Python 3 script that generates Avro schema files from an existing database. + +The script will generate the .avsc schema files into the current directory. Run +the script for all required databases copy the generated .avsc files to the +directory where the avrorouter stores the .avro files (the value of `avrodir`). + +## Go Schema Generator + The _cdc_schema.go_ example Go program is provided with MaxScale. This file can be used to create Avro schemas for the avrorouter by connecting to a database and reading the table definitions. You can find the file in MaxScale's diff --git a/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md b/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md index e311e047e..91ae243db 100644 --- a/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md +++ b/Documentation/Upgrading/Upgrading-To-MaxScale-2.1.md @@ -7,6 +7,7 @@ For more information about MariaDB MaxScale 2.1, please refer to the [ChangeLog](../Changelog.md). For a complete list of changes in MaxScale 2.1, refer to the +* [MaxScale 2.1.11 Release Notes](../Release-Notes/MaxScale-2.1.11-Release-Notes.md) * [MaxScale 2.1.10 Release Notes](../Release-Notes/MaxScale-2.1.10-Release-Notes.md) * [MaxScale 2.1.9 Release Notes](../Release-Notes/MaxScale-2.1.9-Release-Notes.md). * [MaxScale 2.1.8 Release Notes](../Release-Notes/MaxScale-2.1.8-Release-Notes.md). diff --git a/VERSION21.cmake b/VERSION21.cmake index 8ebe7a010..42ce2974e 100644 --- a/VERSION21.cmake +++ b/VERSION21.cmake @@ -5,7 +5,7 @@ set(MAXSCALE_VERSION_MAJOR "2" CACHE STRING "Major version") set(MAXSCALE_VERSION_MINOR "1" CACHE STRING "Minor version") -set(MAXSCALE_VERSION_PATCH "10" CACHE STRING "Patch version") +set(MAXSCALE_VERSION_PATCH "11" CACHE STRING "Patch version") # This should only be incremented if a package is rebuilt set(MAXSCALE_BUILD_NUMBER 1 CACHE STRING "Release number") diff --git a/include/maxscale/config.h b/include/maxscale/config.h index e86759e49..42f7c5bbf 100644 --- a/include/maxscale/config.h +++ b/include/maxscale/config.h @@ -155,6 +155,7 @@ extern const char CN_SSL[]; extern const char CN_SSL_CA_CERT[]; extern const char CN_SSL_CERT[]; extern const char CN_SSL_CERT_VERIFY_DEPTH[]; +extern const char CN_SSL_VERIFY_PEER_CERTIFICATE[]; extern const char CN_SSL_KEY[]; extern const char CN_SSL_VERSION[]; extern const char CN_STRIP_DB_ESC[]; diff --git a/include/maxscale/protocol/mysql.h b/include/maxscale/protocol/mysql.h index 62b26e7ca..022bcfa03 100644 --- a/include/maxscale/protocol/mysql.h +++ b/include/maxscale/protocol/mysql.h @@ -374,6 +374,11 @@ static inline uint32_t MYSQL_GET_PAYLOAD_LEN(const uint8_t* header) return gw_mysql_get_byte3(header); } +static inline uint32_t MYSQL_GET_PACKET_LEN(const GWBUF* buffer) +{ + return MYSQL_GET_PAYLOAD_LEN(GWBUF_DATA(buffer)) + MYSQL_HEADER_LEN; +} + #define MYSQL_GET_ERRCODE(payload) (gw_mysql_get_byte2(&payload[5])) #define MYSQL_GET_STMTOK_NPARAM(payload) (gw_mysql_get_byte2(&payload[9])) #define MYSQL_GET_STMTOK_NATTR(payload) (gw_mysql_get_byte2(&payload[11])) diff --git a/include/maxscale/ssl.h b/include/maxscale/ssl.h index db006a1d5..a4eeaa73f 100644 --- a/include/maxscale/ssl.h +++ b/include/maxscale/ssl.h @@ -66,6 +66,7 @@ typedef struct ssl_listener char *ssl_key; /*< SSL private key */ char *ssl_ca_cert; /*< SSL CA certificate */ bool ssl_init_done; /*< If SSL has already been initialized for this service */ + bool ssl_verify_peer_certificate; /*< Enable peer certificate verification */ struct ssl_listener *next; /*< Next SSL configuration, currently used to store obsolete configurations */ } SSL_LISTENER; @@ -90,4 +91,7 @@ ssl_method_type_t string_to_ssl_method_type(const char* str); */ int ssl_authenticate_check_status(struct dcb *dcb); +// TODO: Move this to an internal ssl.h header +void write_ssl_config(int fd, SSL_LISTENER* ssl); + MXS_END_DECLS diff --git a/maxscale-system-test/CMakeLists.txt b/maxscale-system-test/CMakeLists.txt index 81cc529a5..7bf7875a7 100644 --- a/maxscale-system-test/CMakeLists.txt +++ b/maxscale-system-test/CMakeLists.txt @@ -512,6 +512,10 @@ add_test_executable(mxs1468.cpp mxs1468 mxs1468 LABELS REPL_BACKEND) # https://jira.mariadb.org/browse/MXS-1493 add_test_executable(verify_master_failure.cpp verify_master_failure verify_master_failure LABELS REPL_BACKEND) +# MXS-1476: priority value ignored when a Galera node rejoins with a lower wsrep_local_index than current master +# https://jira.mariadb.org/browse/MXS-1476 +add_test_executable(mxs1476.cpp mxs1476 mxs1476 LABELS GALERA_BACKEND) + # 'namedserverfilter' test add_test_executable(namedserverfilter.cpp namedserverfilter namedserverfilter LABELS namedserverfilter LIGHT REPL_BACKEND) diff --git a/maxscale-system-test/cnf/maxscale.cnf.template.mxs1476 b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1476 new file mode 100644 index 000000000..668a3fc83 --- /dev/null +++ b/maxscale-system-test/cnf/maxscale.cnf.template.mxs1476 @@ -0,0 +1,52 @@ +[maxscale] +threads=###threads### +retry_queries=1 + +[Galera Monitor] +type=monitor +module=galeramon +servers=server1,server2 +user=maxskysql +passwd=skysql +monitor_interval=1000 +root_node_as_master=false +use_priority=true +backend_connect_timeout=1 +backend_read_timeout=1 + +[RW Split Router] +type=service +router=readwritesplit +servers=server1,server2 +user=maxskysql +passwd=skysql + +[RW Split Listener] +type=listener +service=RW Split Router +protocol=MySQLClient +port=4006 + +[CLI] +type=service +router=cli + +[CLI Listener] +type=listener +service=CLI +protocol=maxscaled +socket=default + +[server1] +type=server +address=###galera_server_IP_1### +port=###galera_server_port_1### +protocol=MySQLBackend +priority=2 + +[server2] +type=server +address=###galera_server_IP_2### +port=###galera_server_port_2### +protocol=MySQLBackend +priority=1 diff --git a/maxscale-system-test/mxs1476.cpp b/maxscale-system-test/mxs1476.cpp new file mode 100644 index 000000000..7cca5a558 --- /dev/null +++ b/maxscale-system-test/mxs1476.cpp @@ -0,0 +1,63 @@ +/** + * MXS-1476: priority value ignored when a Galera node rejoins with a lower wsrep_local_index than current master + * + * https://jira.mariadb.org/browse/MXS-1476 + */ + +#include "testconnections.h" + +void do_test(TestConnections& test, int master, int slave) +{ + test.connect_maxscale(); + test.try_query(test.conn_rwsplit, "DROP TABLE IF EXISTS test.t1"); + test.try_query(test.conn_rwsplit, "CREATE TABLE test.t1 (id int)"); + test.try_query(test.conn_rwsplit, "INSERT INTO test.t1 VALUES (1)"); + + test.tprintf("Block a slave node and perform an insert"); + test.galera->block_node(slave); + sleep(5); + test.try_query(test.conn_rwsplit, "INSERT INTO test.t1 VALUES (1)"); + + test.tprintf("Unblock the slave node and perform another insert"); + test.galera->unblock_node(slave); + sleep(5); + test.try_query(test.conn_rwsplit, "INSERT INTO test.t1 VALUES (1)"); + test.close_maxscale_connections(); + + test.tprintf("Block the master node and perform an insert"); + test.galera->block_node(master); + sleep(5); + test.connect_maxscale(); + test.try_query(test.conn_rwsplit, "INSERT INTO test.t1 VALUES (1)"); + + test.tprintf("Unblock the master node and perform another insert (expecting failure)"); + test.galera->unblock_node(master); + sleep(5); + test.add_result(execute_query_silent(test.conn_rwsplit, "INSERT INTO test.t1 VALUES (1)") == 0, "Query should fail"); + test.close_maxscale_connections(); + + test.connect_maxscale(); + test.try_query(test.conn_rwsplit, "DROP TABLE test.t1"); +} + +int main(int argc, char** argv) +{ + TestConnections test(argc, argv); + test.galera->stop_node(2); + test.galera->stop_node(3); + + do_test(test, 1, 0); + + test.tprintf("Swap the priorities around and run the test again"); + test.ssh_maxscale(true, "sed -i 's/priority=1/priority=3/' /etc/maxscale.cnf;" + "sed -i 's/priority=2/priority=1/' /etc/maxscale.cnf;" + "sed -i 's/priority=3/priority=2/' /etc/maxscale.cnf;"); + test.restart_maxscale(); + + do_test(test, 0, 1); + + test.galera->start_node(2, ""); + test.galera->start_node(3, ""); + test.galera->fix_replication(); + return test.global_result; +} diff --git a/server/core/config.cc b/server/core/config.cc index 2bb3f5990..51008c356 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -134,6 +134,7 @@ const char CN_SSL[] = "ssl"; const char CN_SSL_CA_CERT[] = "ssl_ca_cert"; const char CN_SSL_CERT[] = "ssl_cert"; const char CN_SSL_CERT_VERIFY_DEPTH[] = "ssl_cert_verify_depth"; +const char CN_SSL_VERIFY_PEER_CERTIFICATE[] = "ssl_verify_peer_certificate"; const char CN_SSL_KEY[] = "ssl_key"; const char CN_SSL_VERSION[] = "ssl_version"; const char CN_STRIP_DB_ESC[] = "strip_db_esc"; @@ -231,6 +232,7 @@ const char *config_listener_params[] = CN_SSL_KEY, CN_SSL_VERSION, CN_SSL_CERT_VERIFY_DEPTH, + CN_SSL_VERIFY_PEER_CERTIFICATE, NULL }; @@ -279,6 +281,7 @@ const char *server_params[] = CN_SSL_KEY, CN_SSL_VERSION, CN_SSL_CERT_VERIFY_DEPTH, + CN_SSL_VERIFY_PEER_CERTIFICATE, CN_PROXY_PROTOCOL, NULL }; @@ -1688,6 +1691,8 @@ SSL_LISTENER* make_ssl_structure (CONFIG_CONTEXT *obj, bool require_cert, int *e ssl_version = config_get_value(obj->parameters, CN_SSL_VERSION); ssl_cert_verify_depth = config_get_value(obj->parameters, CN_SSL_CERT_VERIFY_DEPTH); new_ssl->ssl_init_done = false; + new_ssl->ssl_cert_verify_depth = 9; // Default of 9 as per Linux man page + new_ssl->ssl_verify_peer_certificate = true; if (ssl_version) { @@ -1710,12 +1715,20 @@ SSL_LISTENER* make_ssl_structure (CONFIG_CONTEXT *obj, bool require_cert, int *e local_errors++; } } - else + + if (ssl_verify_peer_certificate) { - /** - * Default of 9 as per Linux man page - */ - new_ssl->ssl_cert_verify_depth = 9; + int rv = config_truth_value(ssl_verify_peer_certificate); + if (rv == -1) + { + MXS_ERROR("Invalid parameter value for 'ssl_verify_peer_certificate" + " for service '%s': %s", obj->object, ssl_verify_peer_certificate); + local_errors++; + } + else + { + new_ssl->ssl_verify_peer_certificate = rv; + } } listener_set_certificates(new_ssl, ssl_cert, ssl_key, ssl_ca_cert); @@ -3493,6 +3506,7 @@ bool config_is_ssl_parameter(const char *key) CN_SSL_KEY, CN_SSL_VERSION, CN_SSL_CERT_VERIFY_DEPTH, + CN_SSL_VERIFY_PEER_CERTIFICATE, NULL }; diff --git a/server/core/listener.cc b/server/core/listener.cc index d8e007434..e715aaa3a 100644 --- a/server/core/listener.cc +++ b/server/core/listener.cc @@ -366,7 +366,7 @@ listener_init_SSL(SSL_LISTENER *ssl_listener) } /* Set to require peer (client) certificate verification */ - if (ssl_listener->ssl_cert_verify_depth) + if (ssl_listener->ssl_verify_peer_certificate) { SSL_CTX_set_verify(ssl_listener->ctx, SSL_VERIFY_PEER, NULL); } @@ -458,57 +458,7 @@ static bool create_listener_config(const SERV_LISTENER *listener, const char *fi if (listener->ssl) { - dprintf(file, "ssl=required\n"); - - if (listener->ssl->ssl_cert) - { - dprintf(file, "ssl_cert=%s\n", listener->ssl->ssl_cert); - } - - if (listener->ssl->ssl_key) - { - dprintf(file, "ssl_key=%s\n", listener->ssl->ssl_key); - } - - if (listener->ssl->ssl_ca_cert) - { - dprintf(file, "ssl_ca_cert=%s\n", listener->ssl->ssl_ca_cert); - } - if (listener->ssl->ssl_cert_verify_depth) - { - dprintf(file, "ssl_cert_verify_depth=%d\n", listener->ssl->ssl_cert_verify_depth); - } - - const char *version = NULL; - - switch (listener->ssl->ssl_method_type) - { -#ifndef OPENSSL_1_1 - case SERVICE_TLS10: - version = "TLSV10"; - break; -#endif -#ifdef OPENSSL_1_0 - case SERVICE_TLS11: - version = "TLSV11"; - break; - - case SERVICE_TLS12: - version = "TLSV12"; - break; -#endif - case SERVICE_SSL_TLS_MAX: - version = "MAX"; - break; - - default: - break; - } - - if (version) - { - dprintf(file, "ssl_version=%s\n", version); - } + write_ssl_config(file, listener->ssl); } close(file); diff --git a/server/core/server.cc b/server/core/server.cc index 1e416ce6c..51dd2cc2a 100644 --- a/server/core/server.cc +++ b/server/core/server.cc @@ -578,6 +578,7 @@ dprintServer(DCB *dcb, const SERVER *server) dcb_printf(dcb, "\tSSL method type: %s\n", ssl_method_type_to_string(l->ssl_method_type)); dcb_printf(dcb, "\tSSL certificate verification depth: %d\n", l->ssl_cert_verify_depth); + dcb_printf(dcb, "\tSSL peer verification : %s\n", l->ssl_verify_peer_certificate ? "true" : "false"); dcb_printf(dcb, "\tSSL certificate: %s\n", l->ssl_cert ? l->ssl_cert : "null"); dcb_printf(dcb, "\tSSL key: %s\n", @@ -1203,57 +1204,7 @@ static bool create_server_config(const SERVER *server, const char *filename) if (server->server_ssl) { - dprintf(file, "%s=required\n", CN_SSL); - - if (server->server_ssl->ssl_cert) - { - dprintf(file, "%s=%s\n", CN_SSL_CERT, server->server_ssl->ssl_cert); - } - - if (server->server_ssl->ssl_key) - { - dprintf(file, "%s=%s\n", CN_SSL_KEY, server->server_ssl->ssl_key); - } - - if (server->server_ssl->ssl_ca_cert) - { - dprintf(file, "%s=%s\n", CN_SSL_CA_CERT, server->server_ssl->ssl_ca_cert); - } - if (server->server_ssl->ssl_cert_verify_depth) - { - dprintf(file, "%s=%d\n", CN_SSL_CERT_VERIFY_DEPTH, server->server_ssl->ssl_cert_verify_depth); - } - - const char *version = NULL; - - switch (server->server_ssl->ssl_method_type) - { -#ifndef OPENSSL_1_1 - case SERVICE_TLS10: - version = "TLSV10"; - break; -#endif -#ifdef OPENSSL_1_0 - case SERVICE_TLS11: - version = "TLSV11"; - break; - - case SERVICE_TLS12: - version = "TLSV12"; - break; -#endif - case SERVICE_SSL_TLS_MAX: - version = "MAX"; - break; - - default: - break; - } - - if (version) - { - dprintf(file, "%s=%s\n", CN_SSL_VERSION, version); - } + write_ssl_config(file, server->server_ssl); } close(file); diff --git a/server/core/ssl.cc b/server/core/ssl.cc index 5b65fc663..9af4ea9cd 100644 --- a/server/core/ssl.cc +++ b/server/core/ssl.cc @@ -243,6 +243,39 @@ ssl_method_type_t string_to_ssl_method_type(const char* str) return SERVICE_SSL_UNKNOWN; } +void write_ssl_config(int fd, SSL_LISTENER* ssl) +{ + if (ssl) + { + dprintf(fd, "ssl=required\n"); + + if (ssl->ssl_cert) + { + dprintf(fd, "ssl_cert=%s\n", ssl->ssl_cert); + } + + if (ssl->ssl_key) + { + dprintf(fd, "ssl_key=%s\n", ssl->ssl_key); + } + + if (ssl->ssl_ca_cert) + { + dprintf(fd, "ssl_ca_cert=%s\n", ssl->ssl_ca_cert); + } + if (ssl->ssl_cert_verify_depth) + { + dprintf(fd, "ssl_cert_verify_depth=%d\n", ssl->ssl_cert_verify_depth); + } + + dprintf(fd, "ssl_verify_peer_certificate=%s\n", + ssl->ssl_verify_peer_certificate ? "true" : "false"); + + const char *version = ssl_method_type_to_string(ssl->ssl_method_type); + dprintf(fd, "ssl_version=%s\n", version); + } +} + int ssl_authenticate_check_status(DCB* dcb) { int rval = MXS_AUTH_FAILED; @@ -273,4 +306,4 @@ int ssl_authenticate_check_status(DCB* dcb) rval = MXS_AUTH_SSL_COMPLETE; } return rval; -} \ No newline at end of file +} diff --git a/server/modules/protocol/MySQL/MySQLClient/mysql_client.cc b/server/modules/protocol/MySQL/MySQLClient/mysql_client.cc index 58591ea1b..d9cf7f4cc 100644 --- a/server/modules/protocol/MySQL/MySQLClient/mysql_client.cc +++ b/server/modules/protocol/MySQL/MySQLClient/mysql_client.cc @@ -490,20 +490,23 @@ int gw_read_client_event(DCB* dcb) * */ case MXS_AUTH_STATE_MESSAGE_READ: - /* After this call read_buffer will point to freed data */ - dcb_readq_set(dcb, read_buffer); - if (nbytes_read < 3 || (0 == max_bytes && nbytes_read < - (int)(MYSQL_GET_PAYLOAD_LEN((uint8_t *) GWBUF_DATA(read_buffer)) + 4)) || - (0 != max_bytes && nbytes_read < max_bytes) || - (read_buffer = modutil_get_next_MySQL_packet(&dcb->readq)) == NULL) + if (nbytes_read < 3 || + (0 == max_bytes && nbytes_read < MYSQL_GET_PACKET_LEN(read_buffer)) || + (0 != max_bytes && nbytes_read < max_bytes)) { - return 0; + dcb_readq_append(dcb, read_buffer); } + else + { + if (nbytes_read > MYSQL_GET_PACKET_LEN(read_buffer)) + { + // We read more data than was needed + dcb_readq_append(dcb, read_buffer); + read_buffer = modutil_get_next_MySQL_packet(&dcb->readq); + } - ss_dassert(read_buffer); - nbytes_read = gwbuf_length(read_buffer); - - return_code = gw_read_do_authentication(dcb, read_buffer, nbytes_read); + return_code = gw_read_do_authentication(dcb, read_buffer, nbytes_read); + } break; /** @@ -1399,7 +1402,7 @@ static int gw_client_close(DCB *dcb) /** * Handle a hangup event on the client side descriptor. * - * We simply close the DCB, this will propogate the closure to any + * We simply close the DCB, this will propagate the closure to any * backend descriptors and perform the session cleanup. * * @param dcb The DCB of the connection @@ -1421,6 +1424,7 @@ static int gw_client_hangup_event(DCB *dcb) goto retblock; } + modutil_send_mysql_err_packet(dcb, 0, 0, 1927, "08S01", "Connection killed by MaxScale"); dcb_close(dcb); retblock: diff --git a/server/modules/routing/binlogrouter/blr.c b/server/modules/routing/binlogrouter/blr.c index ae6221655..241dfd6d8 100644 --- a/server/modules/routing/binlogrouter/blr.c +++ b/server/modules/routing/binlogrouter/blr.c @@ -831,6 +831,7 @@ createInstance(SERVICE *service, char **options) ssl_cfg->ssl_init_done = false; ssl_cfg->ssl_method_type = SERVICE_SSL_TLS_MAX; ssl_cfg->ssl_cert_verify_depth = 9; + ssl_cfg->ssl_verify_peer_certificate = true; /** Set SSL pointer in in server struct */ server->server_ssl = ssl_cfg;