MINOR: ssl: add a new global option "tune.ssl.hard-maxrecord"

Low footprint client machines may not have enough memory to download a
complete 16KB TLS record at once. With the new option the maximum
record size can be defined on the server side.

Note: Before limiting the the record size on the server side, a client should
consider using the TLS Maximum Fragment Length Negotiation Extension defined
in RFC6066.

This patch fixes GitHub issue #1679.
This commit is contained in:
Thomas Prckl 2022-04-27 13:04:54 +02:00 committed by Willy Tarreau
parent 243e68b552
commit 10243938db
4 changed files with 29 additions and 13 deletions

View File

@ -1118,9 +1118,10 @@ The following keywords are supported in the "global" section :
- tune.sndbuf.client
- tune.sndbuf.server
- tune.ssl.cachesize
- tune.ssl.force-private-cache
- tune.ssl.hard-maxrecord
- tune.ssl.keylog
- tune.ssl.lifetime
- tune.ssl.force-private-cache
- tune.ssl.maxrecord
- tune.ssl.default-dh-param
- tune.ssl.ssl-ctx-cache-size
@ -2903,6 +2904,12 @@ tune.ssl.force-private-cache
this case, adding a first layer of hash-based load balancing before the SSL
layer might limit the impact of the lack of session sharing.
tune.ssl.hard-maxrecord <number>
Sets the maximum amount of bytes passed to SSL_write() at any time. Default
value 0 means there is no limit. In contrast to tune.ssl.maxrecord this
settings will not be adjusted dynamically. Smaller records may decrease
throughput, but may be required when dealing with low-footprint clients.
tune.ssl.keylog { on | off }
This option activates the logging of the TLS keys. It should be used with
care as it will consume more memory per SSL session and could decrease
@ -2950,18 +2957,19 @@ tune.ssl.lifetime <timeout>
being used for too long.
tune.ssl.maxrecord <number>
Sets the maximum amount of bytes passed to SSL_write() at a time. Default
value 0 means there is no limit. Over SSL/TLS, the client can decipher the
data only once it has received a full record. With large records, it means
that clients might have to download up to 16kB of data before starting to
process them. Limiting the value can improve page load times on browsers
located over high latency or low bandwidth networks. It is suggested to find
optimal values which fit into 1 or 2 TCP segments (generally 1448 bytes over
Ethernet with TCP timestamps enabled, or 1460 when timestamps are disabled),
keeping in mind that SSL/TLS add some overhead. Typical values of 1419 and
2859 gave good results during tests. Use "strace -e trace=write" to find the
best value. HAProxy will automatically switch to this setting after an idle
stream has been detected (see tune.idletimer above).
Sets the maximum amount of bytes passed to SSL_write() at the beginning of
the data transfer. Default value 0 means there is no limit. Over SSL/TLS,
the client can decipher the data only once it has received a full record.
With large records, it means that clients might have to download up to 16kB
of data before starting to process them. Limiting the value can improve page
load times on browsers located over high latency or low bandwidth networks.
It is suggested to find optimal values which fit into 1 or 2 TCP segments
(generally 1448 bytes over Ethernet with TCP timestamps enabled, or 1460 when
timestamps are disabled), keeping in mind that SSL/TLS add some overhead.
Typical values of 1419 and 2859 gave good results during tests. Use
"strace -e trace=write" to find the best value. HAProxy will automatically
switch to this setting after an idle stream has been detected (see
tune.idletimer above). See also tune.ssl.hard-maxrecord.
tune.ssl.default-dh-param <number>
Sets the maximum size of the Diffie-Hellman parameters used for generating

View File

@ -275,6 +275,7 @@ struct global_ssl {
int private_cache; /* Force to use a private session cache even if nbproc > 1 */
unsigned int life_time; /* SSL session lifetime in seconds */
unsigned int max_record; /* SSL max record size */
unsigned int hard_max_record; /* SSL max record size hard limit */
unsigned int default_dh_param; /* SSL maximum DH parameter size */
int ctx_cache; /* max number of entries in the ssl_ctx cache. */
int capture_buffer_size; /* Size of the capture buffer. */

View File

@ -268,6 +268,8 @@ static int ssl_parse_global_int(char **args, int section_type, struct proxy *cur
target = &global.tune.sslcachesize;
else if (strcmp(args[0], "tune.ssl.maxrecord") == 0)
target = (int *)&global_ssl.max_record;
else if (strcmp(args[0], "tune.ssl.hard-maxrecord") == 0)
target = (int *)&global_ssl.hard_max_record;
else if (strcmp(args[0], "tune.ssl.ssl-ctx-cache-size") == 0)
target = &global_ssl.ctx_cache;
else if (strcmp(args[0], "maxsslconn") == 0)
@ -1942,6 +1944,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "tune.ssl.force-private-cache", ssl_parse_global_private_cache },
{ CFG_GLOBAL, "tune.ssl.lifetime", ssl_parse_global_lifetime },
{ CFG_GLOBAL, "tune.ssl.maxrecord", ssl_parse_global_int },
{ CFG_GLOBAL, "tune.ssl.hard-maxrecord", ssl_parse_global_int },
{ CFG_GLOBAL, "tune.ssl.ssl-ctx-cache-size", ssl_parse_global_int },
{ CFG_GLOBAL, "tune.ssl.capture-cipherlist-size", ssl_parse_global_capture_buffer },
{ CFG_GLOBAL, "tune.ssl.capture-buffer-size", ssl_parse_global_capture_buffer },

View File

@ -122,6 +122,7 @@ struct global_ssl global_ssl = {
#ifdef DEFAULT_SSL_MAX_RECORD
.max_record = DEFAULT_SSL_MAX_RECORD,
#endif
.hard_max_record = 0,
.default_dh_param = SSL_DEFAULT_DH_PARAM,
.ctx_cache = DEFAULT_SSL_CTX_CACHE,
.capture_buffer_size = 0,
@ -6568,6 +6569,9 @@ static size_t ssl_sock_from_buf(struct connection *conn, void *xprt_ctx, const s
if (try > count)
try = count;
if (global_ssl.hard_max_record && try > global_ssl.hard_max_record)
try = global_ssl.hard_max_record;
if (!(flags & CO_SFL_STREAMER) &&
!(ctx->xprt_st & SSL_SOCK_SEND_UNLIMITED) &&
global_ssl.max_record && try > global_ssl.max_record) {