Split off listener functionality and move SSL initiation from service to listener. Put GWPROTOCOL in its own header file.

This commit is contained in:
counterpoint
2016-01-26 16:08:02 +00:00
parent 1f241a5ed1
commit e58148356d
15 changed files with 663 additions and 157 deletions

View File

@ -1,4 +1,4 @@
add_library(maxscale-common SHARED adminusers.c atomic.c buffer.c config.c dbusers.c dcb.c filter.c externcmd.c gwbitmask.c gwdirs.c gw_utils.c hashtable.c hint.c housekeeper.c load_utils.c maxscale_pcre2.c memlog.c modutil.c monitor.c poll.c random_jkiss.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c ${CMAKE_SOURCE_DIR}/log_manager/log_manager.cc ${CMAKE_SOURCE_DIR}/utils/skygw_utils.cc) add_library(maxscale-common SHARED adminusers.c atomic.c buffer.c config.c dbusers.c dcb.c filter.c externcmd.c gwbitmask.c gwdirs.c gw_utils.c hashtable.c hint.c housekeeper.c listener.c load_utils.c maxscale_pcre2.c memlog.c modutil.c monitor.c poll.c random_jkiss.c resultset.c secrets.c server.c service.c session.c spinlock.c thread.c users.c utils.c ${CMAKE_SOURCE_DIR}/log_manager/log_manager.cc ${CMAKE_SOURCE_DIR}/utils/skygw_utils.cc)
target_link_libraries(maxscale-common ${EMBEDDED_LIB} ${LZMA_LINK_FLAGS} ${PCRE2_LIBRARIES} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} ssl aio pthread crypt dl crypto inih z rt m stdc++) target_link_libraries(maxscale-common ${EMBEDDED_LIB} ${LZMA_LINK_FLAGS} ${PCRE2_LIBRARIES} ${PCRE_LINK_FLAGS} ${CURL_LIBRARIES} ssl aio pthread crypt dl crypto inih z rt m stdc++)

View File

@ -43,7 +43,8 @@
* 20/02/15 Markus Mäkelä Added connection_timeout parameter for services * 20/02/15 Markus Mäkelä Added connection_timeout parameter for services
* 05/03/15 Massimiliano Pinto Added notification_feedback support * 05/03/15 Massimiliano Pinto Added notification_feedback support
* 20/04/15 Guillaume Lefranc Added available_when_donor parameter * 20/04/15 Guillaume Lefranc Added available_when_donor parameter
* 22/04/15 Martin Brampton Added disable_master_role_setting parameter * 22/04/15 Martin Brampton Added disable_master_role_setting parameter
* 26/01/16 Martin Brampton Transfer SSL processing to listener
* *
* @endverbatim * @endverbatim
*/ */
@ -90,6 +91,8 @@ static void global_defaults();
static void feedback_defaults(); static void feedback_defaults();
static void check_config_objects(CONFIG_CONTEXT *context); static void check_config_objects(CONFIG_CONTEXT *context);
static int maxscale_getline(char** dest, int* size, FILE* file); static int maxscale_getline(char** dest, int* size, FILE* file);
static SSL_LISTENER *make_ssl_structure(CONFIG_CONTEXT *obj);
int config_truth_value(char *str); int config_truth_value(char *str);
int config_get_ifaddr(unsigned char *output); int config_get_ifaddr(unsigned char *output);
int config_get_release_string(char* release); int config_get_release_string(char* release);
@ -99,7 +102,7 @@ bool config_has_duplicate_sections(const char* config);
int create_new_service(CONFIG_CONTEXT *obj); int create_new_service(CONFIG_CONTEXT *obj);
int create_new_server(CONFIG_CONTEXT *obj); int create_new_server(CONFIG_CONTEXT *obj);
int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* monitorhash); int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* monitorhash);
int create_new_listener(CONFIG_CONTEXT *obj); int create_new_listener(CONFIG_CONTEXT *obj, bool startnow);
int create_new_filter(CONFIG_CONTEXT *obj); int create_new_filter(CONFIG_CONTEXT *obj);
int configure_new_service(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj); int configure_new_service(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj);
@ -150,6 +153,13 @@ static char *listener_params[] =
"port", "port",
"address", "address",
"socket", "socket",
"authenticator",
"ssl_cert",
"ssl_ca_cert",
"ssl",
"ssl_key",
"ssl_version",
"ssl_cert_verify_depth",
NULL NULL
}; };
@ -585,7 +595,7 @@ process_config_context(CONFIG_CONTEXT *context)
} }
else if (!strcmp(type, "listener")) else if (!strcmp(type, "listener"))
{ {
error_count += create_new_listener(obj); error_count += create_new_listener(obj, false);
} }
else if (!strcmp(type, "monitor")) else if (!strcmp(type, "monitor"))
{ {
@ -909,6 +919,7 @@ static struct
{ "log_info", LOG_INFO, NULL }, { "log_info", LOG_INFO, NULL },
{ NULL, 0 } { NULL, 0 }
}; };
/** /**
* Configuration handler for items in the global [MaxScale] section * Configuration handler for items in the global [MaxScale] section
* *
@ -1022,6 +1033,118 @@ handle_global_item(const char *name, const char *value)
return 1; return 1;
} }
/**
* Form an SSL structure from listener section parameters
*
* @param name The item name
* @param value The item value
* @return 0 on error
*/
static SSL_LISTENER *
make_ssl_structure (CONFIG_CONTEXT *obj)
{
char *ssl, *ssl_version, *ssl_cert, *ssl_key, *ssl_ca_cert, *ssl_cert_verify_depth;
SSL_LISTENER *new_ssl;
int error_count = 0;
ssl = config_get_value(obj->parameters, "ssl");
if (ssl && !strcmp(ssl, "required"))
{
if ((new_ssl = malloc(sizeof(SSL_LISTENER))) == NULL)
{
return NULL;
}
new_ssl->ssl_method_type = SERVICE_SSL_TLS_MAX;
ssl_cert = config_get_value(obj->parameters, "ssl_cert");
ssl_key = config_get_value(obj->parameters, "ssl_key");
ssl_ca_cert = config_get_value(obj->parameters, "ssl_ca_cert");
ssl_version = config_get_value(obj->parameters, "ssl_version");
ssl_cert_verify_depth = config_get_value(obj->parameters, "ssl_cert_verify_depth");
new_ssl->ssl_init_done = false;
if (ssl_version)
{
if (listener_set_ssl_version(new_ssl, ssl_version) != 0)
{
MXS_ERROR("Unknown parameter value for 'ssl_version' for"
" service '%s': %s", obj->object, ssl_version);
error_count++;
}
}
if (ssl_cert_verify_depth)
{
new_ssl->ssl_cert_verify_depth = atoi(ssl_cert_verify_depth);
if (new_ssl->ssl_cert_verify_depth < 0)
{
MXS_ERROR("Invalid parameter value for 'ssl_cert_verify_depth"
" for service '%s': %s", obj->object, ssl_cert_verify_depth);
new_ssl->ssl_cert_verify_depth = 0;
error_count++;
}
}
listener_set_certificates(new_ssl, ssl_cert, ssl_key, ssl_ca_cert);
if (new_ssl->ssl_cert == NULL)
{
error_count++;
MXS_ERROR("Server certificate missing for service '%s'."
"Please provide the path to the server certificate by adding "
"the ssl_cert=<path> parameter", obj->object);
}
if (new_ssl->ssl_ca_cert == NULL)
{
error_count++;
MXS_ERROR("CA Certificate missing for service '%s'."
"Please provide the path to the certificate authority "
"certificate by adding the ssl_ca_cert=<path> parameter",
obj->object);
}
if (new_ssl->ssl_key == NULL)
{
error_count++;
MXS_ERROR("Server private key missing for service '%s'. "
"Please provide the path to the server certificate key by "
"adding the ssl_key=<path> parameter",
obj->object);
}
if (access(new_ssl->ssl_ca_cert, F_OK) != 0)
{
MXS_ERROR("Certificate authority file for service '%s' not found: %s",
obj->object,
new_ssl->ssl_ca_cert);
error_count++;
}
if (access(new_ssl->ssl_cert, F_OK) != 0)
{
MXS_ERROR("Server certificate file for service '%s' not found: %s",
obj->object,
new_ssl->ssl_cert);
error_count++;
}
if (access(new_ssl->ssl_key, F_OK) != 0)
{
MXS_ERROR("Server private key file for service '%s' not found: %s",
obj->object,
new_ssl->ssl_key);
error_count++;
}
if (error_count == 0)
{
return new_ssl;
}
free(new_ssl);
}
return NULL;
}
/** /**
* Configuration handler for items in the feedback [feedback] section * Configuration handler for items in the feedback [feedback] section
* *
@ -1386,52 +1509,7 @@ process_config_update(CONFIG_CONTEXT *context)
} }
else if (!strcmp(type, "listener")) else if (!strcmp(type, "listener"))
{ {
char *service; create_new_listener(obj, true);
char *port;
char *protocol;
char *address;
char *socket;
service = config_get_value(obj->parameters, "service");
address = config_get_value(obj->parameters, "address");
port = config_get_value(obj->parameters, "port");
protocol = config_get_value(obj->parameters, "protocol");
socket = config_get_value(obj->parameters, "socket");
if (service && socket && protocol)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
{
ptr = ptr->next;
}
if (ptr &&
ptr->element &&
serviceHasProtocol(ptr->element, protocol, 0) == 0)
{
serviceAddProtocol(ptr->element, protocol, socket, 0);
serviceStartProtocol(ptr->element, protocol, 0);
}
}
if (service && port && protocol)
{
CONFIG_CONTEXT *ptr = context;
while (ptr && strcmp(ptr->object, service) != 0)
{
ptr = ptr->next;
}
if (ptr &&
ptr->element &&
serviceHasProtocol(ptr->element, protocol, atoi(port)) == 0)
{
serviceAddProtocol(ptr->element, protocol, address, atoi(port));
serviceStartProtocol(ptr->element, protocol, atoi(port));
}
}
} }
else if (strcmp(type, "server") != 0 && else if (strcmp(type, "server") != 0 &&
strcmp(type, "monitor") != 0 && strcmp(type, "monitor") != 0 &&
@ -2633,9 +2711,10 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE*
/** /**
* Create a new listener for a service * Create a new listener for a service
* @param obj Listener configuration context * @param obj Listener configuration context
* @param startnow If true, start the listener now
* @return Number of errors * @return Number of errors
*/ */
int create_new_listener(CONFIG_CONTEXT *obj) int create_new_listener(CONFIG_CONTEXT *obj, bool startnow)
{ {
int error_count = 0; int error_count = 0;
char *service_name = config_get_value(obj->parameters, "service"); char *service_name = config_get_value(obj->parameters, "service");
@ -2643,20 +2722,52 @@ int create_new_listener(CONFIG_CONTEXT *obj)
char *address = config_get_value(obj->parameters, "address"); char *address = config_get_value(obj->parameters, "address");
char *protocol = config_get_value(obj->parameters, "protocol"); char *protocol = config_get_value(obj->parameters, "protocol");
char *socket = config_get_value(obj->parameters, "socket"); char *socket = config_get_value(obj->parameters, "socket");
char *authenticator = config_get_value(obj->parameters, "authenticator");
if (service_name && protocol && (socket || port)) if (service_name && protocol && (socket || port))
{ {
SERVICE *service = service_find(service_name); SERVICE *service = service_find(service_name);
if (service) if (service)
{ {
SSL_LISTENER *ssl_info = make_ssl_structure(obj);
if (socket) if (socket)
{ {
serviceAddProtocol(service, protocol, socket, 0); if (serviceHasProtocol(service, protocol, 0))
{
MXS_ERROR("Listener '%s', for service '%s', socket %s, already have socket.",
obj->object,
service_name,
socket);
error_count++;
}
else
{
serviceAddProtocol(service, protocol, socket, 0, authenticator, ssl_info);
if (startnow)
{
serviceStartProtocol(service, protocol, 0);
}
}
} }
if (port) if (port)
{ {
serviceAddProtocol(service, protocol, address, atoi(port)); if (serviceHasProtocol(service, protocol, atoi(port)))
{
MXS_ERROR("Listener '%s', for service '%s', already have port %s.",
obj->object,
service_name,
port);
error_count++;
}
else
{
serviceAddProtocol(service, protocol, address, atoi(port), authenticator, ssl_info);
if (startnow)
{
serviceStartProtocol(service, protocol, atoi(port));
}
}
} }
} }
else else

276
server/core/listener.c Normal file
View File

@ -0,0 +1,276 @@
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright MariaDB Corporation Ab 2013-2014
*/
/**
* @file listener.c - Listener generic functions
*
* Listeners wait for new client connections and, if the connection is successful
* a new session is created. A listener typically knows about a port or a socket,
* and a few other things. It may know about SSL if it is expecting an SSL
* connection.
*
* @verbatim
* Revision History
*
* Date Who Description
* 26/01/16 Martin Brampton Initial implementation
*
* @endverbatim
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <listener.h>
#include <gw_protocol.h>
#include <log_manager.h>
static RSA *rsa_512 = NULL;
static RSA *rsa_1024 = NULL;
static RSA *tmp_rsa_callback(SSL *s, int is_export, int keylength);
/**
* Set the maximum SSL/TLS version the listener will support
* @param ssl_listener Listener data to configure
* @param version SSL/TLS version string
* @return 0 on success, -1 on invalid version string
*/
int
listener_set_ssl_version(SSL_LISTENER *ssl_listener, char* version)
{
if (strcasecmp(version,"SSLV3") == 0)
{
ssl_listener->ssl_method_type = SERVICE_SSLV3;
}
else if (strcasecmp(version,"TLSV10") == 0)
{
ssl_listener->ssl_method_type = SERVICE_TLS10;
}
#ifdef OPENSSL_1_0
else if (strcasecmp(version,"TLSV11") == 0)
{
ssl_listener->ssl_method_type = SERVICE_TLS11;
}
else if (strcasecmp(version,"TLSV12") == 0)
{
ssl_listener->ssl_method_type = SERVICE_TLS12;
}
#endif
else if (strcasecmp(version,"MAX") == 0)
{
ssl_listener->ssl_method_type = SERVICE_SSL_TLS_MAX;
}
else
{
return -1;
}
return 0;
}
/**
* Set the locations of the listener's SSL certificate, listener's private key
* and the CA certificate which both the client and the listener should trust.
* @param ssl_listener Listener data to configure
* @param cert SSL certificate
* @param key SSL private key
* @param ca_cert SSL CA certificate
*/
void
listener_set_certificates(SSL_LISTENER *ssl_listener, char* cert, char* key, char* ca_cert)
{
if (ssl_listener->ssl_cert)
{
free(ssl_listener->ssl_cert);
}
ssl_listener->ssl_cert = strdup(cert);
if (ssl_listener->ssl_key)
{
free(ssl_listener->ssl_key);
}
ssl_listener->ssl_key = strdup(key);
if (ssl_listener->ssl_ca_cert)
{
free(ssl_listener->ssl_ca_cert);
}
ssl_listener->ssl_ca_cert = strdup(ca_cert);
}
/**
* Initialize the listener's SSL context. This sets up the generated RSA
* encryption keys, chooses the listener encryption level and configures the
* listener certificate, private key and certificate authority file.
* @param ssl_listener Listener data to initialize
* @return 0 on success, -1 on error
*/
int
listener_init_SSL(SSL_LISTENER *ssl_listener)
{
DH* dh;
RSA* rsa;
if (!ssl_listener->ssl_init_done)
{
switch(ssl_listener->ssl_method_type)
{
case SERVICE_SSLV3:
ssl_listener->method = (SSL_METHOD*)SSLv3_server_method();
break;
case SERVICE_TLS10:
ssl_listener->method = (SSL_METHOD*)TLSv1_server_method();
break;
#ifdef OPENSSL_1_0
case SERVICE_TLS11:
ssl_listener->method = (SSL_METHOD*)TLSv1_1_server_method();
break;
case SERVICE_TLS12:
ssl_listener->method = (SSL_METHOD*)TLSv1_2_server_method();
break;
#endif
/** Rest of these use the maximum available SSL/TLS methods */
case SERVICE_SSL_MAX:
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
break;
case SERVICE_TLS_MAX:
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
break;
case SERVICE_SSL_TLS_MAX:
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
break;
default:
ssl_listener->method = (SSL_METHOD*)SSLv23_server_method();
break;
}
if ((ssl_listener->ctx = SSL_CTX_new(ssl_listener->method)) == NULL)
{
MXS_ERROR("SSL context initialization failed.");
return -1;
}
/** Enable all OpenSSL bug fixes */
SSL_CTX_set_options(ssl_listener->ctx,SSL_OP_ALL);
/** Generate the 512-bit and 1024-bit RSA keys */
if (rsa_512 == NULL)
{
rsa_512 = RSA_generate_key(512,RSA_F4,NULL,NULL);
if (rsa_512 == NULL)
{
MXS_ERROR("512-bit RSA key generation failed.");
return -1;
}
}
if (rsa_1024 == NULL)
{
rsa_1024 = RSA_generate_key(1024,RSA_F4,NULL,NULL);
if (rsa_1024 == NULL)
{
MXS_ERROR("1024-bit RSA key generation failed.");
return -1;
}
}
if (rsa_512 != NULL && rsa_1024 != NULL)
{
SSL_CTX_set_tmp_rsa_callback(ssl_listener->ctx,tmp_rsa_callback);
}
/** Load the server certificate */
if (SSL_CTX_use_certificate_file(ssl_listener->ctx, ssl_listener->ssl_cert, SSL_FILETYPE_PEM) <= 0)
{
MXS_ERROR("Failed to set server SSL certificate.");
return -1;
}
/* Load the private-key corresponding to the server certificate */
if (SSL_CTX_use_PrivateKey_file(ssl_listener->ctx, ssl_listener->ssl_key, SSL_FILETYPE_PEM) <= 0)
{
MXS_ERROR("Failed to set server SSL key.");
return -1;
}
/* Check if the server certificate and private-key matches */
if (!SSL_CTX_check_private_key(ssl_listener->ctx))
{
MXS_ERROR("Server SSL certificate and key do not match.");
return -1;
}
/* Load the RSA CA certificate into the SSL_CTX structure */
if (!SSL_CTX_load_verify_locations(ssl_listener->ctx, ssl_listener->ssl_ca_cert, NULL))
{
MXS_ERROR("Failed to set Certificate Authority file.");
return -1;
}
/* Set to require peer (client) certificate verification */
SSL_CTX_set_verify(ssl_listener->ctx,SSL_VERIFY_PEER,NULL);
/* Set the verification depth */
SSL_CTX_set_verify_depth(ssl_listener->ctx,ssl_listener->ssl_cert_verify_depth);
ssl_listener->ssl_init_done = true;
}
return 0;
}
/**
* The RSA key generation callback function for OpenSSL.
* @param s SSL structure
* @param is_export Not used
* @param keylength Length of the key
* @return Pointer to RSA structure
*/
static RSA *
tmp_rsa_callback(SSL *s, int is_export, int keylength)
{
RSA *rsa_tmp=NULL;
switch (keylength) {
case 512:
if (rsa_512)
{
rsa_tmp = rsa_512;
}
else
{
/* generate on the fly, should not happen in this example */
rsa_tmp = RSA_generate_key(keylength,RSA_F4,NULL,NULL);
rsa_512 = rsa_tmp; /* Remember for later reuse */
}
break;
case 1024:
if (rsa_1024)
{
rsa_tmp=rsa_1024;
}
break;
default:
/* Generating a key on the fly is very costly, so use what is there */
if (rsa_1024)
{
rsa_tmp=rsa_1024;
}
else
{
rsa_tmp=rsa_512; /* Use at least a shorter key */
}
}
return(rsa_tmp);
}

View File

@ -48,6 +48,8 @@
#include <errno.h> #include <errno.h>
#include <session.h> #include <session.h>
#include <service.h> #include <service.h>
#include <gw_protocol.h>
#include <listener.h>
#include <server.h> #include <server.h>
#include <router.h> #include <router.h>
#include <spinlock.h> #include <spinlock.h>
@ -218,7 +220,7 @@ service_isvalid(SERVICE *service)
* @return The number of listeners started * @return The number of listeners started
*/ */
static int static int
serviceStartPort(SERVICE *service, SERV_PROTOCOL *port) serviceStartPort(SERVICE *service, SERV_LISTENER *port)
{ {
int listeners = 0; int listeners = 0;
char config_bind[40]; char config_bind[40];
@ -232,6 +234,11 @@ serviceStartPort(SERVICE *service, SERV_PROTOCOL *port)
goto retblock; goto retblock;
} }
if (port->ssl)
{
listener_init_SSL(port->ssl);
}
if (strcmp(port->protocol, "MySQLClient") == 0) if (strcmp(port->protocol, "MySQLClient") == 0)
{ {
int loaded; int loaded;
@ -420,7 +427,7 @@ retblock:
*/ */
int serviceStartAllPorts(SERVICE* service) int serviceStartAllPorts(SERVICE* service)
{ {
SERV_PROTOCOL *port = service->ports; SERV_LISTENER *port = service->ports;
int listeners = 0; int listeners = 0;
while (!service->svc_do_shutdown && port) while (!service->svc_do_shutdown && port)
{ {
@ -507,7 +514,7 @@ serviceStart(SERVICE *service)
void void
serviceStartProtocol(SERVICE *service, char *protocol, int port) serviceStartProtocol(SERVICE *service, char *protocol, int port)
{ {
SERV_PROTOCOL *ptr; SERV_LISTENER *ptr;
ptr = service->ports; ptr = service->ports;
while (ptr) while (ptr)
@ -560,7 +567,7 @@ serviceStartAll()
int int
serviceStop(SERVICE *service) serviceStop(SERVICE *service)
{ {
SERV_PROTOCOL *port; SERV_LISTENER *port;
int listeners = 0; int listeners = 0;
port = service->ports; port = service->ports;
@ -592,7 +599,7 @@ serviceStop(SERVICE *service)
int int
serviceRestart(SERVICE *service) serviceRestart(SERVICE *service)
{ {
SERV_PROTOCOL *port; SERV_LISTENER *port;
int listeners = 0; int listeners = 0;
port = service->ports; port = service->ports;
@ -686,25 +693,20 @@ service_free(SERVICE *service)
* @return TRUE if the protocol/port could be added * @return TRUE if the protocol/port could be added
*/ */
int int
serviceAddProtocol(SERVICE *service, char *protocol, char *address, unsigned short port) serviceAddProtocol(SERVICE *service, char *protocol, char *address, unsigned short port, char *authenticator, SSL_LISTENER *ssl)
{ {
SERV_PROTOCOL *proto; SERV_LISTENER *proto;
if ((proto = (SERV_PROTOCOL *)malloc(sizeof(SERV_PROTOCOL))) == NULL) if ((proto = (SERV_LISTENER *)malloc(sizeof(SERV_LISTENER))) == NULL)
{ {
return 0; return 0;
} }
proto->listener = NULL; proto->listener = NULL;
proto->protocol = strdup(protocol); proto->protocol = strdup(protocol);
if (address) proto->address = address ? strdup(address) : NULL;
{
proto->address = strdup(address);
}
else
{
proto->address = NULL;
}
proto->port = port; proto->port = port;
proto->authenticator = authenticator ? strdup(authenticator) : NULL;
proto->ssl = ssl;
spinlock_acquire(&service->spin); spinlock_acquire(&service->spin);
proto->next = service->ports; proto->next = service->ports;
service->ports = proto; service->ports = proto;
@ -724,7 +726,7 @@ serviceAddProtocol(SERVICE *service, char *protocol, char *address, unsigned sho
int int
serviceHasProtocol(SERVICE *service, char *protocol, unsigned short port) serviceHasProtocol(SERVICE *service, char *protocol, unsigned short port)
{ {
SERV_PROTOCOL *proto; SERV_LISTENER *proto;
spinlock_acquire(&service->spin); spinlock_acquire(&service->spin);
proto = service->ports; proto = service->ports;
@ -1457,7 +1459,7 @@ void
dListListeners(DCB *dcb) dListListeners(DCB *dcb)
{ {
SERVICE *service; SERVICE *service;
SERV_PROTOCOL *lptr; SERV_LISTENER *lptr;
spinlock_acquire(&service_spin); spinlock_acquire(&service_spin);
service = allServices; service = allServices;
@ -1930,7 +1932,7 @@ serviceListenerRowCallback(RESULTSET *set, void *data)
char buf[20]; char buf[20];
RESULT_ROW *row; RESULT_ROW *row;
SERVICE *service; SERVICE *service;
SERV_PROTOCOL *lptr = NULL; SERV_LISTENER *lptr = NULL;
spinlock_acquire(&service_spin); spinlock_acquire(&service_spin);
service = allServices; service = allServices;
@ -2135,6 +2137,9 @@ int serviceInitSSL(SERVICE* service)
DH* dh; DH* dh;
RSA* rsa; RSA* rsa;
/* Pending removal in favour of processing in listener. */
return 0;
if (!service->ssl_init_done) if (!service->ssl_init_done)
{ {
switch(service->ssl_method_type) switch(service->ssl_method_type)

View File

@ -70,7 +70,7 @@ init_test_env(NULL);
ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation"); ss_info_dassert(0 != service_isvalid(service), "Service must be valid after creation");
ss_info_dassert(0 == strcmp("MyService", service_get_name(service)), "Service must have given name"); ss_info_dassert(0 == strcmp("MyService", service_get_name(service)), "Service must have given name");
ss_dfprintf(stderr, "\t..done\nAdding protocol testprotocol."); ss_dfprintf(stderr, "\t..done\nAdding protocol testprotocol.");
ss_info_dassert(0 != serviceAddProtocol(service, "testprotocol", "localhost", 9876), "Add Protocol should succeed"); ss_info_dassert(0 != serviceAddProtocol(service, "testprotocol", "localhost", 9876, "MySQL", NULL), "Add Protocol should succeed");
ss_info_dassert(0 != serviceHasProtocol(service, "testprotocol", 9876), "Service should have new protocol as requested"); ss_info_dassert(0 != serviceHasProtocol(service, "testprotocol", 9876), "Service should have new protocol as requested");
serviceStartProtocol(service, "testprotocol", 9876); serviceStartProtocol(service, "testprotocol", 9876);
mxs_log_flush_sync(); mxs_log_flush_sync();

View File

@ -19,13 +19,11 @@
*/ */
#include <spinlock.h> #include <spinlock.h>
#include <buffer.h> #include <buffer.h>
#include <gw_protocol.h>
#include <modinfo.h> #include <modinfo.h>
#include <gwbitmask.h> #include <gwbitmask.h>
#include <skygw_utils.h> #include <skygw_utils.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define ERRHANDLE #define ERRHANDLE
@ -59,50 +57,13 @@ struct service;
* 27/08/2014 Mark Riddoch Addition of write event queuing * 27/08/2014 Mark Riddoch Addition of write event queuing
* 23/09/2014 Mark Riddoch New poll processing queue * 23/09/2014 Mark Riddoch New poll processing queue
* 19/06/2015 Martin Brampton Provision of persistent connections * 19/06/2015 Martin Brampton Provision of persistent connections
* 20/01/2016 Martin Brampton Moved GWPROTOCOL to gw_protocol.h
* *
* @endverbatim * @endverbatim
*/ */
struct dcb; struct dcb;
/**
* @verbatim
* The operations that can be performed on the descriptor
*
* read EPOLLIN handler for the socket
* write MaxScale data write entry point
* write_ready EPOLLOUT handler for the socket, indicates
* that the socket is ready to send more data
* error EPOLLERR handler for the socket
* hangup EPOLLHUP handler for the socket
* accept Accept handler for listener socket only
* connect Create a connection to the specified server
* for the session pased in
* close MaxScale close entry point for the socket
* listen Create a listener for the protocol
* auth Authentication entry point
* session Session handling entry point
* @endverbatim
*
* This forms the "module object" for protocol modules within the gateway.
*
* @see load_module
*/
typedef struct gw_protocol
{
int (*read)(struct dcb *);
int (*write)(struct dcb *, GWBUF *);
int (*write_ready)(struct dcb *);
int (*error)(struct dcb *);
int (*hangup)(struct dcb *);
int (*accept)(struct dcb *);
int (*connect)(struct dcb *, struct server *, struct session *);
int (*close)(struct dcb *);
int (*listen)(struct dcb *, char *);
int (*auth)(struct dcb *, struct server *, struct session *, GWBUF *);
int (*session)(struct dcb *, void *);
} GWPROTOCOL;
/** /**
* The event queue structure used in the polling loop to maintain a queue * The event queue structure used in the polling loop to maintain a queue
* of events that need to be processed for the DCB. * of events that need to be processed for the DCB.
@ -128,13 +89,6 @@ typedef struct
unsigned long started; unsigned long started;
} DCBEVENTQ; } DCBEVENTQ;
/**
* The GWPROTOCOL version data. The following should be updated whenever
* the GWPROTOCOL structure is changed. See the rules defined in modinfo.h
* that define how these numbers should change.
*/
#define GWPROTOCOL_VERSION {1, 0, 0}
#define DCBFD_CLOSED -1 #define DCBFD_CLOSED -1
/** /**

View File

@ -0,0 +1,92 @@
#ifndef GW_PROTOCOL_H
#define GW_PROTOCOL_H
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright MariaDB Corporation Ab 2013-2014
*/
/**
* @file protocol.h
*
* The listener definitions for MaxScale
*
* @verbatim
* Revision History
*
* Date Who Description
* 22/01/16 Martin Brampton Initial implementation
*
* @endverbatim
*/
#include <buffer.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/dh.h>
struct dcb;
struct server;
struct session;
/**
* @verbatim
* The operations that can be performed on the descriptor
*
* read EPOLLIN handler for the socket
* write MaxScale data write entry point
* write_ready EPOLLOUT handler for the socket, indicates
* that the socket is ready to send more data
* error EPOLLERR handler for the socket
* hangup EPOLLHUP handler for the socket
* accept Accept handler for listener socket only
* connect Create a connection to the specified server
* for the session pased in
* close MaxScale close entry point for the socket
* listen Create a listener for the protocol
* auth Authentication entry point
* session Session handling entry point
* @endverbatim
*
* This forms the "module object" for protocol modules within the gateway.
*
* @see load_module
*/
typedef struct gw_protocol
{
int (*read)(struct dcb *);
int (*write)(struct dcb *, GWBUF *);
int (*write_ready)(struct dcb *);
int (*error)(struct dcb *);
int (*hangup)(struct dcb *);
int (*accept)(struct dcb *);
int (*connect)(struct dcb *, struct server *, struct session *);
int (*close)(struct dcb *);
int (*listen)(struct dcb *, char *);
int (*auth)(struct dcb *, struct server *, struct session *, GWBUF *);
int (*session)(struct dcb *, void *);
} GWPROTOCOL;
/**
* The GWPROTOCOL version data. The following should be updated whenever
* the GWPROTOCOL structure is changed. See the rules defined in modinfo.h
* that define how these numbers should change.
*/
#define GWPROTOCOL_VERSION {1, 0, 0}
#endif /* GW_PROTOCOL_H */

89
server/include/listener.h Normal file
View File

@ -0,0 +1,89 @@
#ifndef _LISTENER_H
#define _LISTENER_H
/*
* This file is distributed as part of the MariaDB Corporation MaxScale. It is free
* software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation,
* version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright MariaDB Corporation Ab 2013-2014
*/
/**
* @file listener.h
*
* The listener definitions for MaxScale
*
* @verbatim
* Revision History
*
* Date Who Description
* 19/01/16 Martin Brampton Initial implementation
*
* @endverbatim
*/
#include <gw_protocol.h>
#include <dcb.h>
enum
{
SERVICE_SSLV3,
SERVICE_TLS10,
#ifdef OPENSSL_1_0
SERVICE_TLS11,
SERVICE_TLS12,
#endif
SERVICE_SSL_MAX,
SERVICE_TLS_MAX,
SERVICE_SSL_TLS_MAX
};
/**
* The ssl_listener structure is used to aggregate the SSL configuration items
* and data for a particular listener
*/
typedef struct ssl_listener
{
SSL_CTX *ctx;
SSL_METHOD *method; /*< SSLv3 or TLS1.0/1.1/1.2 methods
* see: https://www.openssl.org/docs/ssl/SSL_CTX_new.html */
int ssl_cert_verify_depth; /*< SSL certificate verification depth */
int ssl_method_type; /*< Which of the SSLv3 or TLS1.0/1.1/1.2 methods to use */
char *ssl_cert; /*< SSL certificate */
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 */
} SSL_LISTENER;
/**
* The servlistener structure is used to link a service to the protocols that
* are used to support that service. It defines the name of the protocol module
* that should be loaded to support the client connection and the port that the
* protocol should use to listen for incoming client connections.
*/
typedef struct servlistener
{
char *protocol; /**< Protocol module to load */
unsigned short port; /**< Port to listen on */
char *address; /**< Address to listen with */
char *authenticator; /**< Name of authenticator */
SSL_LISTENER *ssl; /**< Structure of SSL data or NULL */
DCB *listener; /**< The DCB for the listener */
struct servlistener *next; /**< Next service protocol */
} SERV_LISTENER;
int listener_set_ssl_version(SSL_LISTENER *ssl_listener, char* version);
void listener_set_certificates(SSL_LISTENER *ssl_listener, char* cert, char* key, char* ca_cert);
int listener_init_SSL(SSL_LISTENER *ssl_listener);
#endif

View File

@ -19,9 +19,11 @@
*/ */
#include <time.h> #include <time.h>
#include <gw_protocol.h>
#include <spinlock.h> #include <spinlock.h>
#include <dcb.h> #include <dcb.h>
#include <server.h> #include <server.h>
#include <listener.h>
#include <filter.h> #include <filter.h>
#include <hashtable.h> #include <hashtable.h>
#include <resultset.h> #include <resultset.h>
@ -59,21 +61,6 @@ struct router;
struct router_object; struct router_object;
struct users; struct users;
/**
* The servprotocol structure is used to link a service to the protocols that
* are used to support that service. It defines the name of the protocol module
* that should be loaded to support the client connection and the port that the
* protocol should use to listen for incoming client connections.
*/
typedef struct servprotocol
{
char *protocol; /**< Protocol module to load */
unsigned short port; /**< Port to listen on */
char *address; /**< Address to listen with */
DCB *listener; /**< The DCB for the listener */
struct servprotocol *next; /**< Next service protocol */
} SERV_PROTOCOL;
/** /**
* The service statistics structure * The service statistics structure
*/ */
@ -120,19 +107,6 @@ typedef enum
SSL_REQUIRED SSL_REQUIRED
} ssl_mode_t; } ssl_mode_t;
enum
{
SERVICE_SSLV3,
SERVICE_TLS10,
#ifdef OPENSSL_1_0
SERVICE_TLS11,
SERVICE_TLS12,
#endif
SERVICE_SSL_MAX,
SERVICE_TLS_MAX,
SERVICE_SSL_TLS_MAX
};
#define DEFAULT_SSL_CERT_VERIFY_DEPTH 100 /*< The default certificate verification depth */ #define DEFAULT_SSL_CERT_VERIFY_DEPTH 100 /*< The default certificate verification depth */
#define SERVICE_MAX_RETRY_INTERVAL 3600 /*< The maximum interval between service start retries */ #define SERVICE_MAX_RETRY_INTERVAL 3600 /*< The maximum interval between service start retries */
@ -156,7 +130,7 @@ typedef struct service
{ {
char *name; /**< The service name */ char *name; /**< The service name */
int state; /**< The service state */ int state; /**< The service state */
SERV_PROTOCOL *ports; /**< Linked list of ports and protocols SERV_LISTENER *ports; /**< Linked list of ports and protocols
* that this service will listen on. * that this service will listen on.
*/ */
char *routerModule; /**< Name of router module to use */ char *routerModule; /**< Name of router module to use */
@ -218,7 +192,7 @@ extern SERVICE *service_alloc(const char *, const char *);
extern int service_free(SERVICE *); extern int service_free(SERVICE *);
extern SERVICE *service_find(char *); extern SERVICE *service_find(char *);
extern int service_isvalid(SERVICE *); extern int service_isvalid(SERVICE *);
extern int serviceAddProtocol(SERVICE *, char *, char *, unsigned short); extern int serviceAddProtocol(SERVICE *, char *, char *, unsigned short, char *, SSL_LISTENER *);
extern int serviceHasProtocol(SERVICE *, char *, unsigned short); extern int serviceHasProtocol(SERVICE *, char *, unsigned short);
extern void serviceAddBackend(SERVICE *, SERVER *); extern void serviceAddBackend(SERVICE *, SERVER *);
extern int serviceHasBackend(SERVICE *, SERVER *); extern int serviceHasBackend(SERVICE *, SERVER *);

View File

@ -38,6 +38,7 @@
*/ */
#include <httpd.h> #include <httpd.h>
#include <gw_protocol.h>
#include <gw.h> #include <gw.h>
#include <modinfo.h> #include <modinfo.h>
#include <log_manager.h> #include <log_manager.h>

View File

@ -21,6 +21,7 @@
#include <string.h> #include <string.h>
#include <dcb.h> #include <dcb.h>
#include <buffer.h> #include <buffer.h>
#include <gw_protocol.h>
#include <service.h> #include <service.h>
#include <session.h> #include <session.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>

View File

@ -50,6 +50,7 @@
* *
*/ */
#include <modinfo.h> #include <modinfo.h>
#include <gw_protocol.h>
MODULE_INFO info = MODULE_INFO info =
{ {

View File

@ -47,6 +47,7 @@
* 11/01/2016 Martin Brampton Remove SSL write code, now handled at lower level; * 11/01/2016 Martin Brampton Remove SSL write code, now handled at lower level;
* replace gwbuf_consume by gwbuf_free (multiple). * replace gwbuf_consume by gwbuf_free (multiple).
*/ */
#include <gw_protocol.h>
#include <skygw_utils.h> #include <skygw_utils.h>
#include <log_manager.h> #include <log_manager.h>
#include <mysql_client_server_protocol.h> #include <mysql_client_server_protocol.h>
@ -74,16 +75,15 @@ static int gw_MySQLWrite_client(DCB *dcb, GWBUF *queue);
static int gw_error_client_event(DCB *dcb); static int gw_error_client_event(DCB *dcb);
static int gw_client_close(DCB *dcb); static int gw_client_close(DCB *dcb);
static int gw_client_hangup_event(DCB *dcb); static int gw_client_hangup_event(DCB *dcb);
int gw_read_client_event_SSL(DCB* dcb); static int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message); static int MySQLSendHandshake(DCB* dcb);
int MySQLSendHandshake(DCB* dcb);
static int gw_mysql_do_authentication(DCB *dcb, GWBUF **queue); static int gw_mysql_do_authentication(DCB *dcb, GWBUF **queue);
static int route_by_statement(SESSION *, GWBUF **); static int route_by_statement(SESSION *, GWBUF **);
extern char* get_username_from_auth(char* ptr, uint8_t* data); extern char* get_username_from_auth(char* ptr, uint8_t* data);
extern int check_db_name_after_auth(DCB *, char *, int); extern int check_db_name_after_auth(DCB *, char *, int);
extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db,int); extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db,int);
int do_ssl_accept(MySQLProtocol* protocol); static int do_ssl_accept(MySQLProtocol* protocol);
/* /*
* The "module object" for the mysqld client protocol module. * The "module object" for the mysqld client protocol module.

View File

@ -23,6 +23,7 @@
#include <buffer.h> #include <buffer.h>
#include <service.h> #include <service.h>
#include <session.h> #include <session.h>
#include <gw_protocol.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <errno.h> #include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>

View File

@ -33,6 +33,7 @@
#include <modinfo.h> #include <modinfo.h>
#include <dcb.h> #include <dcb.h>
#include <buffer.h> #include <buffer.h>
#include <gw_protocol.h>
MODULE_INFO info = MODULE_INFO info =
{ {