MEDIUM: config: implement maxsslconn in the global section

SSL connections take a huge amount of memory, and unfortunately openssl
does not check malloc() returns and easily segfaults when too many
connections are used.

The only solution against this is to provide a global maxsslconn setting
to reject SSL connections above the limit in order to avoid reaching
unsafe limits.
This commit is contained in:
Willy Tarreau 2012-09-06 11:58:37 +02:00
parent cbaaec475c
commit 403edff4b8
5 changed files with 41 additions and 3 deletions

View File

@ -452,6 +452,7 @@ The following keywords are supported in the "global" section :
- maxconn
- maxconnrate
- maxpipes
- maxsslconn
- noepoll
- nokqueue
- nopoll
@ -672,6 +673,15 @@ maxpipes <number>
The splice code dynamically allocates and releases pipes, and can fall back
to standard copy, so setting this value too low may only impact performance.
maxsslconn <number>
Sets the maximum per-process number of concurrent SSL connections to
<number>. By default there is no SSL-specific limit, which means that the
global maxconn setting will apply to all connections. Setting this limit
avoids having openssl use too much memory and crash when malloc returns NULL
(since it unfortunately does not reliably check for such conditions). Note
that the limit applies both to incoming and outgoing connections, so one
connection which is deciphered then ciphered accounts for 2 SSL connections.
noepoll
Disables the use of the "epoll" event polling system on Linux. It is
equivalent to the command-line argument "-de". The next polling system

View File

@ -67,6 +67,9 @@ struct global {
int gid;
int nbproc;
int maxconn, hardmaxconn;
#ifdef USE_OPENSSL
int maxsslconn;
#endif
struct freq_ctr conn_per_sec;
int cps_lim, cps_max;
int maxpipes; /* max # of pipes */

View File

@ -720,6 +720,22 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_ALERT;
}
#endif /* SYSTEM_MAXCONN */
}
else if (!strcmp(args[0], "maxsslconn")) {
#ifdef USE_OPENSSL
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
global.maxsslconn = atol(args[1]);
#else
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' is not implemented.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
#endif
}
else if (!strcmp(args[0], "maxconnrate")) {
if (global.cps_lim != 0) {

View File

@ -129,6 +129,9 @@ struct global global = {
.sslcachesize = 20000,
#endif
},
#if defined (USE_OPENSSL) && defined(DEFAULT_MAXSSLCONN)
.maxsslconn = DEFAULT_MAXSSLCONN,
#endif
/* others NULL OK */
};

View File

@ -44,6 +44,7 @@
#include <types/global.h>
static int sslconns = 0;
void ssl_sock_infocbk(const SSL *ssl, int where, int ret)
{
@ -69,10 +70,12 @@ static int ssl_sock_init(struct connection *conn)
if (conn->data_ctx)
return 0;
if (global.maxsslconn && sslconns >= global.maxsslconn)
return -1;
/* If it is in client mode initiate SSL session
in connect state otherwise accept state */
if (target_srv(&conn->target)) {
/* Alloc a new SSL session ctx */
conn->data_ctx = SSL_new(target_srv(&conn->target)->ssl_ctx.ctx);
if (!conn->data_ctx)
@ -87,10 +90,11 @@ static int ssl_sock_init(struct connection *conn)
/* leave init state and start handshake */
conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
sslconns++;
return 0;
}
else if (target_client(&conn->target)) {
/* Alloc a new SSL session ctx */
conn->data_ctx = SSL_new(target_client(&conn->target)->ssl_ctx.ctx);
if (!conn->data_ctx)
@ -106,6 +110,8 @@ static int ssl_sock_init(struct connection *conn)
/* leave init state and start handshake */
conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
sslconns++;
return 0;
}
/* don't know how to handle such a target */
@ -339,8 +345,8 @@ static void ssl_sock_close(struct connection *conn) {
if (conn->data_ctx) {
SSL_free(conn->data_ctx);
conn->data_ctx = NULL;
sslconns--;
}
}
/* This function tries to perform a clean shutdown on an SSL connection, and in