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

@ -43,7 +43,8 @@
* 20/02/15 Markus Mäkelä Added connection_timeout parameter for services
* 05/03/15 Massimiliano Pinto Added notification_feedback support
* 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
*/
@ -90,6 +91,8 @@ static void global_defaults();
static void feedback_defaults();
static void check_config_objects(CONFIG_CONTEXT *context);
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_get_ifaddr(unsigned char *output);
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_server(CONFIG_CONTEXT *obj);
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 configure_new_service(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj);
@ -150,6 +153,13 @@ static char *listener_params[] =
"port",
"address",
"socket",
"authenticator",
"ssl_cert",
"ssl_ca_cert",
"ssl",
"ssl_key",
"ssl_version",
"ssl_cert_verify_depth",
NULL
};
@ -585,7 +595,7 @@ process_config_context(CONFIG_CONTEXT *context)
}
else if (!strcmp(type, "listener"))
{
error_count += create_new_listener(obj);
error_count += create_new_listener(obj, false);
}
else if (!strcmp(type, "monitor"))
{
@ -909,6 +919,7 @@ static struct
{ "log_info", LOG_INFO, NULL },
{ NULL, 0 }
};
/**
* Configuration handler for items in the global [MaxScale] section
*
@ -1022,6 +1033,118 @@ handle_global_item(const char *name, const char *value)
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
*
@ -1386,52 +1509,7 @@ process_config_update(CONFIG_CONTEXT *context)
}
else if (!strcmp(type, "listener"))
{
char *service;
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));
}
}
create_new_listener(obj, true);
}
else if (strcmp(type, "server") != 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
* @param obj Listener configuration context
* @param startnow If true, start the listener now
* @return Number of errors
*/
int create_new_listener(CONFIG_CONTEXT *obj)
int create_new_listener(CONFIG_CONTEXT *obj, bool startnow)
{
int error_count = 0;
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 *protocol = config_get_value(obj->parameters, "protocol");
char *socket = config_get_value(obj->parameters, "socket");
char *authenticator = config_get_value(obj->parameters, "authenticator");
if (service_name && protocol && (socket || port))
{
SERVICE *service = service_find(service_name);
if (service)
{
SSL_LISTENER *ssl_info = make_ssl_structure(obj);
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)
{
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