[nginx] Stream ssl_preread: $ssl_preread_protocol variable.

Roman Arutyunyan arut at nginx.com
Thu Jul 12 15:50:44 UTC 2018


details:   http://hg.nginx.org/nginx/rev/3dfc1584ad75
branches:  
changeset: 7314:3dfc1584ad75
user:      Roman Arutyunyan <arut at nginx.com>
date:      Wed Jul 11 17:56:51 2018 +0300
description:
Stream ssl_preread: $ssl_preread_protocol variable.

The variable keeps the latest SSL protocol version supported by the client.
The variable has the same format as $ssl_protocol.

The version is read from the client_version field of ClientHello.  If the
supported_versions extension is present in the ClientHello, then the version
is set to TLSv1.3.

diffstat:

 src/stream/ngx_stream_ssl_preread_module.c |  99 ++++++++++++++++++++++++++++-
 1 files changed, 93 insertions(+), 6 deletions(-)

diffs (168 lines):

diff -r e45f09198dab -r 3dfc1584ad75 src/stream/ngx_stream_ssl_preread_module.c
--- a/src/stream/ngx_stream_ssl_preread_module.c	Thu Jul 12 12:50:20 2018 +0300
+++ b/src/stream/ngx_stream_ssl_preread_module.c	Wed Jul 11 17:56:51 2018 +0300
@@ -21,6 +21,7 @@ typedef struct {
     u_char         *pos;
     u_char         *dst;
     u_char          buf[4];
+    u_char          version[2];
     ngx_str_t       host;
     ngx_str_t       alpn;
     ngx_log_t      *log;
@@ -32,6 +33,8 @@ typedef struct {
 static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s);
 static ngx_int_t ngx_stream_ssl_preread_parse_record(
     ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last);
+static ngx_int_t ngx_stream_ssl_preread_protocol_variable(
+    ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_stream_ssl_preread_server_name_variable(
     ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable(
@@ -86,6 +89,9 @@ ngx_module_t  ngx_stream_ssl_preread_mod
 
 static ngx_stream_variable_t  ngx_stream_ssl_preread_vars[] = {
 
+    { ngx_string("ssl_preread_protocol"), NULL,
+      ngx_stream_ssl_preread_protocol_variable, 0, 0, 0 },
+
     { ngx_string("ssl_preread_server_name"), NULL,
       ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 },
 
@@ -196,7 +202,8 @@ ngx_stream_ssl_preread_parse_record(ngx_
     enum {
         sw_start = 0,
         sw_header,          /* handshake msg_type, length */
-        sw_head_tail,       /* version, random */
+        sw_version,         /* client_version */
+        sw_random,          /* random */
         sw_sid_len,         /* session_id length */
         sw_sid,             /* session_id */
         sw_cs_len,          /* cipher_suites length */
@@ -210,7 +217,8 @@ ngx_stream_ssl_preread_parse_record(ngx_
         sw_sni_host,        /* SNI host_name */
         sw_alpn_len,        /* ALPN length */
         sw_alpn_proto_len,  /* ALPN protocol_name length */
-        sw_alpn_proto_data  /* ALPN protocol_name */
+        sw_alpn_proto_data, /* ALPN protocol_name */
+        sw_supver_len       /* supported_versions length */
     } state;
 
     ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
@@ -254,13 +262,19 @@ ngx_stream_ssl_preread_parse_record(ngx_
                 return NGX_DECLINED;
             }
 
-            state = sw_head_tail;
-            dst = NULL;
-            size = 34;
+            state = sw_version;
+            dst = ctx->version;
+            size = 2;
             left = (p[1] << 16) + (p[2] << 8) + p[3];
             break;
 
-        case sw_head_tail:
+        case sw_version:
+            state = sw_random;
+            dst = NULL;
+            size = 32;
+            break;
+
+        case sw_random:
             state = sw_sid_len;
             dst = p;
             size = 1;
@@ -334,6 +348,14 @@ ngx_stream_ssl_preread_parse_record(ngx_
                 break;
             }
 
+            if (p[0] == 0 && p[1] == 43) {
+                /* supported_versions extension */
+                state = sw_supver_len;
+                dst = p;
+                size = 1;
+                break;
+            }
+
             state = sw_ext;
             dst = NULL;
             size = (p[2] << 8) + p[3];
@@ -434,6 +456,19 @@ ngx_stream_ssl_preread_parse_record(ngx_
             dst = NULL;
             size = 0;
             break;
+
+        case sw_supver_len:
+            ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
+                           "ssl preread: supported_versions");
+
+            /* set TLSv1.3 */
+            ctx->version[0] = 3;
+            ctx->version[1] = 4;
+
+            state = sw_ext;
+            dst = NULL;
+            size = p[0];
+            break;
         }
 
         if (left < size) {
@@ -454,6 +489,58 @@ ngx_stream_ssl_preread_parse_record(ngx_
 
 
 static ngx_int_t
+ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s,
+    ngx_variable_value_t *v, uintptr_t data)
+{
+    ngx_str_t                      version;
+    ngx_stream_ssl_preread_ctx_t  *ctx;
+
+    ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
+
+    if (ctx == NULL) {
+        v->not_found = 1;
+        return NGX_OK;
+    }
+
+    /* SSL_get_version() format */
+
+    ngx_str_null(&version);
+
+    switch (ctx->version[0]) {
+    case 2:
+        ngx_str_set(&version, "SSLv2");
+        break;
+    case 3:
+        switch (ctx->version[1]) {
+        case 0:
+            ngx_str_set(&version, "SSLv3");
+            break;
+        case 1:
+            ngx_str_set(&version, "TLSv1");
+            break;
+        case 2:
+            ngx_str_set(&version, "TLSv1.1");
+            break;
+        case 3:
+            ngx_str_set(&version, "TLSv1.2");
+            break;
+        case 4:
+            ngx_str_set(&version, "TLSv1.3");
+            break;
+        }
+    }
+
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->len = version.len;
+    v->data = version.data;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s,
     ngx_variable_value_t *v, uintptr_t data)
 {


More information about the nginx-devel mailing list