mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-01-06 01:11:00 +01:00
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:
parent
cbaaec475c
commit
403edff4b8
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -129,6 +129,9 @@ struct global global = {
|
||||
.sslcachesize = 20000,
|
||||
#endif
|
||||
},
|
||||
#if defined (USE_OPENSSL) && defined(DEFAULT_MAXSSLCONN)
|
||||
.maxsslconn = DEFAULT_MAXSSLCONN,
|
||||
#endif
|
||||
/* others NULL OK */
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user