Re: Хотел бы сделать такие правила для SSL:

Roman Arutyunyan arut на nginx.com
Пт Мар 30 15:22:13 UTC 2018


On Fri, Mar 30, 2018 at 05:00:34PM +0300, Igor A. Ippolitov wrote:
> Сергей,
> 
> Если очень нужно, есть вариант использовать stream модуль для определения
> протокола, который хочет/может клиент.
> И в зависимости от клиента уже проксировать в разные бэкенды, где
> терминировать SSL.
> 
> Вариантов как это сделать два:
> 1) можно запатчить ssl preread, чтобы он экспортил переменные с протоколом.
> Теоретически, патч будет несложным (client hello уже разбирается для
> получения SNI)

Вот примерный патч, парсящий версию протокола в ssl_preread.

[..]

-- 
Roman Arutyunyan
----------- следущая часть -----------
# HG changeset patch
# User Roman Arutyunyan <arut на nginx.com>
# Date 1522420772 -10800
#      Fri Mar 30 17:39:32 2018 +0300
# Node ID 471f32ce0d8250a0fced5290796713b03d7d08d7
# Parent  416953ef04286401354000f624ad5561ca1ade57
Stream ssl_preread: $ssl_preread_protocol variable.

The variable keeps the highest SSL protocol version number supported by the
client.  The format is compatible with the $ssl_protocol variable.

For TLSv1.3 the list of SSL protocol versions supported by the client are passed
in the "supported_versions" extension not handled by this implementation.  The
version returned by $ssl_preread_protocol will likely be TLSv1.2 in this case.

diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c
--- a/src/stream/ngx_stream_ssl_preread_module.c
+++ b/src/stream/ngx_stream_ssl_preread_module.c
@@ -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 */
@@ -254,13 +261,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;
@@ -454,6 +467,55 @@ 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;
+        }
+    }
+
+    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)
 {


Подробная информация о списке рассылки nginx-ru