summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/stream/ngx_stream_proxy_module.c152
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,