MXS-1951: Fix port conflict detection

With the addition of SO_REUSEPORT support, it is no longer possible to
rely on the network stack to prevent multiple listeners from listening on
the same port. Without explicitly checking for the ports it would be
possible for two listeners from two different services to listen on the
same port in which case the service would be almost randomly chosen.
This commit is contained in:
Markus Mäkelä 2019-03-20 12:34:59 +02:00
parent df3b501563
commit 388e952c5f
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19
4 changed files with 43 additions and 2 deletions

View File

@ -319,6 +319,19 @@ SListener listener_find(const std::string& name);
*/
std::vector<SListener> listener_find_by_service(const SERVICE* service);
/**
* Find listener by configuration
*
* @param socket Optional path to a socket file
* @param address Address where the listener listens
* @param port The port on which the listener listens
*
* @return The matching listener if one was found
*/
SListener listener_find_by_config(const std::string& socket,
const std::string& address,
unsigned short port);
int listener_set_ssl_version(SSL_LISTENER* ssl_listener, const char* version);
void listener_set_certificates(SSL_LISTENER* ssl_listener, const std::string& cert,
const std::string& key, const std::string& ca_cert);

View File

@ -4087,7 +4087,7 @@ int create_new_listener(CONFIG_CONTEXT* obj)
address = "";
}
if (auto l = service_find_listener(service, socket, address, port))
if (auto l = listener_find_by_config(socket, address, port))
{
string socket_type = socket_defined ? "socket" : "port";
string socket_definition = socket_defined ? socket : obj->m_parameters.get_string(CN_PORT);

View File

@ -1154,7 +1154,7 @@ bool runtime_create_listener(Service* service,
{
config_runtime_error("Listener '%s' already exists", name);
}
else if (SListener l = service_find_listener(service, "", addr, u_port))
else if (SListener l = listener_find_by_config("", addr, u_port))
{
config_runtime_error("Listener '%s' already listens on [%s]:%u", l->name(), addr, u_port);
}

View File

@ -26,6 +26,7 @@
#include <mutex>
#include <sstream>
#include <string>
#include <unordered_set>
#include <maxscale/paths.h>
#include <maxscale/ssl.hh>
@ -275,6 +276,33 @@ std::vector<SListener> listener_find_by_service(const SERVICE* service)
return rval;
}
static bool is_all_iface(const std::string& a, const std::string& b)
{
std::unordered_set<std::string> addresses {"::", "0.0.0.0"};
return addresses.count(a) || addresses.count(b);
}
SListener listener_find_by_config(const std::string& socket,
const std::string& address,
unsigned short port)
{
SListener rval;
std::lock_guard<std::mutex> guard(listener_lock);
for (const auto& listener : all_listeners)
{
if (port == listener->port()
&& (listener->address() == address || listener->address() == socket
|| is_all_iface(listener->address(), address)))
{
rval = listener;
break;
}
}
return rval;
}
/**
* Set the maximum SSL/TLS version the listener will support
* @param ssl_listener Listener data to configure