]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: config: implement maxsslconn in the global section
authorWilly Tarreau <w@1wt.eu>
Thu, 6 Sep 2012 09:58:37 +0000 (11:58 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 6 Sep 2012 10:10:43 +0000 (12:10 +0200)
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.

doc/configuration.txt
include/types/global.h
src/cfgparse.c
src/haproxy.c
src/ssl_sock.c

index 00a5238e114529bf656f536a4243a6a8a1723c63..e11b140f35de3a8ac8c2a0a5787df9b79008fc77 100644 (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
index bd8a06e81e5c50fd1ee98eeee04cabe55132c5a3..5775e27dcf6c4d7c42f14300636b80259ddb237d 100644 (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 */
index a15050355cd13ab431b1a09311a3306f5e4e4371..925013a35eb8d2016c838e32cf3aaafbefd718d2 100644 (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) {
index 7439a4c98c4567b824d2f32b4516f16a56f4519a..def0f3fb9bb9c7682d3941cdc40581f20cd01d07 100644 (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 */
 };
 
index cfe788d27366ce099af82de3ec81d65585d868df..69c409962fbe9a853549b65d8ca4d84575c1c7ac 100644 (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