[nginx] Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan
arut at nginx.com
Tue Mar 13 12:01:16 UTC 2018
details: http://hg.nginx.org/nginx/rev/79eb4f7b6725
branches:
changeset: 7227:79eb4f7b6725
user: Roman Arutyunyan <arut at nginx.com>
date: Mon Mar 12 16:03:08 2018 +0300
description:
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
The variable keeps a comma-separated list of protocol names from ALPN TLS
extension defined by RFC 7301.
diffstat:
src/stream/ngx_stream_ssl_preread_module.c | 128 +++++++++++++++++++++++++++-
1 files changed, 122 insertions(+), 6 deletions(-)
diffs (248 lines):
diff -r 0b1eb40de6da -r 79eb4f7b6725 src/stream/ngx_stream_ssl_preread_module.c
--- a/src/stream/ngx_stream_ssl_preread_module.c Wed Mar 07 18:28:12 2018 +0300
+++ b/src/stream/ngx_stream_ssl_preread_module.c Mon Mar 12 16:03:08 2018 +0300
@@ -17,10 +17,12 @@ typedef struct {
typedef struct {
size_t left;
size_t size;
+ size_t ext;
u_char *pos;
u_char *dst;
u_char buf[4];
ngx_str_t host;
+ ngx_str_t alpn;
ngx_log_t *log;
ngx_pool_t *pool;
ngx_uint_t state;
@@ -32,6 +34,8 @@ static ngx_int_t ngx_stream_ssl_preread_
ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last);
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(
+ ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf);
static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf);
static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent,
@@ -85,6 +89,9 @@ static ngx_stream_variable_t ngx_stream
{ ngx_string("ssl_preread_server_name"), NULL,
ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 },
+ { ngx_string("ssl_preread_alpn_protocols"), NULL,
+ ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 },
+
ngx_stream_null_variable
};
@@ -139,12 +146,14 @@ ngx_stream_ssl_preread_handler(ngx_strea
if (p[0] != 0x16) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: not a handshake");
+ ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
return NGX_DECLINED;
}
if (p[1] != 3) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: unsupported SSL version");
+ ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
return NGX_DECLINED;
}
@@ -158,6 +167,12 @@ ngx_stream_ssl_preread_handler(ngx_strea
p += 5;
rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len);
+
+ if (rc == NGX_DECLINED) {
+ ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
+ return NGX_DECLINED;
+ }
+
if (rc != NGX_AGAIN) {
return rc;
}
@@ -175,7 +190,7 @@ static ngx_int_t
ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
u_char *pos, u_char *last)
{
- size_t left, n, size;
+ size_t left, n, size, ext;
u_char *dst, *p;
enum {
@@ -192,7 +207,10 @@ ngx_stream_ssl_preread_parse_record(ngx_
sw_ext_header, /* extension_type, extension_data length */
sw_sni_len, /* SNI length */
sw_sni_host_head, /* SNI name_type, host_name length */
- sw_sni_host /* SNI host_name */
+ 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 */
} state;
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
@@ -201,6 +219,7 @@ ngx_stream_ssl_preread_parse_record(ngx_
state = ctx->state;
size = ctx->size;
left = ctx->left;
+ ext = ctx->ext;
dst = ctx->dst;
p = ctx->buf;
@@ -299,10 +318,18 @@ ngx_stream_ssl_preread_parse_record(ngx_
break;
case sw_ext_header:
- if (p[0] == 0 && p[1] == 0) {
+ if (p[0] == 0 && p[1] == 0 && ctx->host.data == NULL) {
/* SNI extension */
state = sw_sni_len;
- dst = NULL;
+ dst = p;
+ size = 2;
+ break;
+ }
+
+ if (p[0] == 0 && p[1] == 16 && ctx->alpn.data == NULL) {
+ /* ALPN extension */
+ state = sw_alpn_len;
+ dst = p;
size = 2;
break;
}
@@ -313,6 +340,7 @@ ngx_stream_ssl_preread_parse_record(ngx_
break;
case sw_sni_len:
+ ext = (p[0] << 8) + p[1];
state = sw_sni_host_head;
dst = p;
size = 3;
@@ -325,14 +353,21 @@ ngx_stream_ssl_preread_parse_record(ngx_
return NGX_DECLINED;
}
- state = sw_sni_host;
size = (p[1] << 8) + p[2];
+ if (ext < 3 + size) {
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
+ "ssl preread: SNI format error");
+ return NGX_DECLINED;
+ }
+ ext -= 3 + size;
+
ctx->host.data = ngx_pnalloc(ctx->pool, size);
if (ctx->host.data == NULL) {
return NGX_ERROR;
}
+ state = sw_sni_host;
dst = ctx->host.data;
break;
@@ -341,7 +376,64 @@ ngx_stream_ssl_preread_parse_record(ngx_
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: SNI hostname \"%V\"", &ctx->host);
- return NGX_OK;
+
+ state = sw_ext;
+ dst = NULL;
+ size = ext;
+ break;
+
+ case sw_alpn_len:
+ ext = (p[0] << 8) + p[1];
+
+ ctx->alpn.data = ngx_pnalloc(ctx->pool, ext);
+ if (ctx->alpn.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ state = sw_alpn_proto_len;
+ dst = p;
+ size = 1;
+ break;
+
+ case sw_alpn_proto_len:
+ size = p[0];
+
+ if (size == 0) {
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
+ "ssl preread: ALPN empty protocol");
+ return NGX_DECLINED;
+ }
+
+ if (ext < 1 + size) {
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
+ "ssl preread: ALPN format error");
+ return NGX_DECLINED;
+ }
+ ext -= 1 + size;
+
+ state = sw_alpn_proto_data;
+ dst = ctx->alpn.data + ctx->alpn.len;
+ break;
+
+ case sw_alpn_proto_data:
+ ctx->alpn.len += p[0];
+
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
+ "ssl preread: ALPN protocols \"%V\"", &ctx->alpn);
+
+ if (ext) {
+ ctx->alpn.data[ctx->alpn.len++] = ',';
+
+ state = sw_alpn_proto_len;
+ dst = p;
+ size = 1;
+ break;
+ }
+
+ state = sw_ext;
+ dst = NULL;
+ size = 0;
+ break;
}
if (left < size) {
@@ -354,6 +446,7 @@ ngx_stream_ssl_preread_parse_record(ngx_
ctx->state = state;
ctx->size = size;
ctx->left = left;
+ ctx->ext = ext;
ctx->dst = dst;
return NGX_AGAIN;
@@ -384,6 +477,29 @@ ngx_stream_ssl_preread_server_name_varia
static ngx_int_t
+ngx_stream_ssl_preread_alpn_protocols_variable(ngx_stream_session_t *s,
+ ngx_variable_value_t *v, uintptr_t data)
+{
+ 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;
+ }
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->len = ctx->alpn.len;
+ v->data = ctx->alpn.data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf)
{
ngx_stream_variable_t *var, *v;
More information about the nginx-devel
mailing list