Extra RTT on large certificates (again?)
Maxim Dounin
mdounin at mdounin.ru
Tue May 23 16:02:15 UTC 2017
Hello!
On Mon, May 22, 2017 at 10:34:11PM +0200, Albert Casademont wrote:
> Seems like the openssl devs are aware of the issue and welcoming PRs, AFAIK
> nothing's been done yet.
>
> https://mta.openssl.org/pipermail/openssl-users/2016-November/004835.html
Thanks for the link, it confirms what I already concluded from the
code. As mentioned there, quick-and-dirty solution would be
recompile OpenSSL with larger buffer size.
> > Thanks for the prompt response. Yes, we're using Openssl 1.1.0e at the
> > moment...That is unfortunate, what would you suggest doing? Report this to
> > the openssl devs? An extra RTT is quite painful.
With OpenSSL 1.1.0+ it is no longer possible to adjust handshake
buffer size as nginx used to do, and OpenSSL changes are needed to
make it possible again.
Another approach might be to mitigate extra RTT using TCP_NODELAY.
While result will be still non-optimal (as there will be
incomplete packets), it should be better than nothing.
Patch:
# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1495555095 -10800
# Tue May 23 18:58:15 2017 +0300
# Node ID 472c23c0a788646403074b359c30c4bbe860cbf6
# Parent 7943298d4ac09aae83ca8eef09bcf0a12c310505
SSL: set TCP_NODELAY on SSL connections earlier.
With OpenSSL 1.1.0+, the workaround for handshake buffer size as introduced
in a720f0b0e083 (ticket #413) no longer works, as OpenSSL no longer exposes
handshake buffers, see https://github.com/openssl/openssl/commit/2e7dc7cd688.
Moreover, it no longer possible to adjust handshake buffers at all now.
To avoid additional RTT if handshake uses more than 4k we now set TCP_NODELAY
on SSL connections before handshake. While this still results in sub-optimal
network utilization due to incomplete packets being sent, it seems to be
better than nothing.
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -623,14 +623,16 @@ ngx_http_create_request(ngx_connection_t
static void
ngx_http_ssl_handshake(ngx_event_t *rev)
{
- u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];
- size_t size;
- ssize_t n;
- ngx_err_t err;
- ngx_int_t rc;
- ngx_connection_t *c;
- ngx_http_connection_t *hc;
- ngx_http_ssl_srv_conf_t *sscf;
+ int tcp_nodelay;
+ u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];
+ size_t size;
+ ssize_t n;
+ ngx_err_t err;
+ ngx_int_t rc;
+ ngx_connection_t *c;
+ ngx_http_connection_t *hc;
+ ngx_http_ssl_srv_conf_t *sscf;
+ ngx_http_core_loc_conf_t *clcf;
c = rev->data;
hc = c->data;
@@ -712,6 +714,36 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
"https ssl handshake: 0x%02Xd", buf[0]);
+ clcf = ngx_http_get_module_loc_conf(hc->conf_ctx,
+ ngx_http_core_module);
+
+ if (clcf->tcp_nodelay
+ && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET)
+ {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay");
+
+ tcp_nodelay = 1;
+
+ if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
+ (const void *) &tcp_nodelay, sizeof(int))
+ == -1)
+ {
+#if (NGX_SOLARIS)
+ /* Solaris returns EINVAL if a socket has been shut down */
+ c->log_error = NGX_ERROR_IGNORE_EINVAL;
+#endif
+
+ ngx_connection_error(c, ngx_socket_errno,
+ "setsockopt(TCP_NODELAY) failed");
+
+ c->log_error = NGX_ERROR_INFO;
+ ngx_http_close_connection(c);
+ return;
+ }
+
+ c->tcp_nodelay = NGX_TCP_NODELAY_SET;
+ }
+
sscf = ngx_http_get_module_srv_conf(hc->conf_ctx,
ngx_http_ssl_module);
--
Maxim Dounin
http://nginx.org/
More information about the nginx-devel
mailing list