diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/stream/ngx_stream_proxy_module.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 300bdf681..c358c8647 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -42,6 +42,7 @@ typedef struct { ngx_str_t ssl_ciphers; ngx_stream_complex_value_t *ssl_name; ngx_flag_t ssl_server_name; + ngx_array_t *ssl_alpn; ngx_flag_t ssl_verify; ngx_uint_t ssl_verify_depth; @@ -95,6 +96,8 @@ static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, #if (NGX_STREAM_SSL) static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s); +static char *ngx_stream_proxy_ssl_alpn_set_slot(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); static char *ngx_stream_proxy_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf, @@ -105,6 +108,7 @@ static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc); static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s); +static ngx_int_t ngx_stream_proxy_ssl_alpn(ngx_stream_session_t *s); static ngx_int_t ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s); static ngx_int_t ngx_stream_proxy_merge_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *conf, ngx_stream_proxy_srv_conf_t *prev); @@ -304,6 +308,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, ssl_server_name), NULL }, + { ngx_string("proxy_ssl_alpn"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_proxy_ssl_alpn_set_slot, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_ssl_verify"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -1044,6 +1055,61 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s) static char * +ngx_stream_proxy_ssl_alpn_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + ngx_stream_proxy_srv_conf_t *pscf = conf; + + ngx_str_t *value; + ngx_uint_t i; + ngx_stream_complex_value_t *cv; + ngx_stream_compile_complex_value_t ccv; + + if (pscf->ssl_alpn != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + pscf->ssl_alpn = ngx_array_create(cf->pool, cf->args->nelts - 1, + sizeof(ngx_stream_complex_value_t)); + if (pscf->ssl_alpn == NULL) { + return NGX_CONF_ERROR; + } + + cv = ngx_array_push_n(pscf->ssl_alpn, cf->args->nelts - 1); + + for (i = 1; i < cf->args->nelts; i++) { + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[i]; + ccv.complex_value = &cv[i - 1]; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv[i - 1].lengths == NULL && value[i].len > 255) { + return "protocol too long"; + } + } + + return NGX_CONF_OK; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"proxy_ssl_alpn\" directive requires " + "OpenSSL with ALPN support"); + + return NGX_CONF_ERROR; +#endif +} + + +static char * ngx_stream_proxy_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -1200,6 +1266,13 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s) } } + if (pscf->ssl_alpn) { + if (ngx_stream_proxy_ssl_alpn(s) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + } + if (pscf->ssl_certificate && pscf->ssl_certificate->value.len && (pscf->ssl_certificate->lengths @@ -1400,6 +1473,82 @@ done: static ngx_int_t +ngx_stream_proxy_ssl_alpn(ngx_stream_session_t *s) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + size_t len; + u_char *p, *buf; + ngx_str_t proto; + ngx_uint_t i; + ngx_connection_t *c; + ngx_stream_upstream_t *u; + ngx_stream_complex_value_t *cv; + ngx_stream_proxy_srv_conf_t *pscf; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + u = s->upstream; + c = u->peer.connection; + + len = 0; + + cv = pscf->ssl_alpn->elts; + + for (i = 0; i < pscf->ssl_alpn->nelts; i++) { + + if (ngx_stream_complex_value(s, &cv[i], &proto) != NGX_OK) { + return NGX_ERROR; + } + + if (proto.len == 0 || proto.len > 255) { + continue; + } + + len += 1 + proto.len; + } + + if (len == 0) { + return NGX_OK; + } + + buf = ngx_pnalloc(c->pool, len); + if (buf == NULL) { + return NGX_ERROR; + } + + p = buf; + + for (i = 0; i < pscf->ssl_alpn->nelts; i++) { + + if (ngx_stream_complex_value(s, &cv[i], &proto) != NGX_OK) { + return NGX_ERROR; + } + + if (proto.len == 0 || proto.len > 255) { + continue; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "upstream SSL ALPN: \"%V\"", &proto); + + *p++ = proto.len; + p = ngx_cpymem(p, proto.data, proto.len); + } + + if (SSL_set_alpn_protos(c->ssl->connection, buf, p - buf) != 0) { + ngx_ssl_error(NGX_LOG_ERR, c->log, 0, + "SSL_set_alpn_protos() failed"); + return NGX_ERROR; + } + +#endif + + return NGX_OK; +} + + +static ngx_int_t ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s) { ngx_str_t cert, key; @@ -2225,6 +2374,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->ssl_session_reuse = NGX_CONF_UNSET; conf->ssl_name = NGX_CONF_UNSET_PTR; conf->ssl_server_name = NGX_CONF_UNSET; + conf->ssl_alpn = NGX_CONF_UNSET_PTR; conf->ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; conf->ssl_certificate = NGX_CONF_UNSET_PTR; @@ -2300,6 +2450,8 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); + ngx_conf_merge_ptr_value(conf->ssl_alpn, prev->ssl_alpn, NULL); + ngx_conf_merge_value(conf->ssl_verify, prev->ssl_verify, 0); ngx_conf_merge_uint_value(conf->ssl_verify_depth, |
