Welcome! Log In Create A New Profile

Advanced

[PATCH 2 of 3] Stream: virtual servers

Roman Arutyunyan
November 10, 2023 05:08AM
# HG changeset patch
# User Roman Arutyunyan <arut@nginx.com>
# Date 1699035295 -14400
# Fri Nov 03 22:14:55 2023 +0400
# Node ID 1d3464283405a4d8ac54caae9bf1815c723f04c5
# Parent 966331bb4936888ef2f034aa2700c130514d0b57
Stream: virtual servers.

Server name is taken either from ngx_stream_ssl_module or
ngx_stream_ssl_preread_module.

diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c
--- a/src/stream/ngx_stream.c
+++ b/src/stream/ngx_stream.c
@@ -16,16 +16,34 @@ static ngx_int_t ngx_stream_init_phases(
ngx_stream_core_main_conf_t *cmcf);
static ngx_int_t ngx_stream_init_phase_handlers(ngx_conf_t *cf,
ngx_stream_core_main_conf_t *cmcf);
-static ngx_int_t ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
- ngx_stream_listen_t *listen);
-static char *ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports);
+
+static ngx_int_t ngx_stream_add_addresses(ngx_conf_t *cf,
+ ngx_stream_core_srv_conf_t *cscf, ngx_stream_conf_port_t *port,
+ ngx_stream_listen_opt_t *lsopt);
+static ngx_int_t ngx_stream_add_address(ngx_conf_t *cf,
+ ngx_stream_core_srv_conf_t *cscf, ngx_stream_conf_port_t *port,
+ ngx_stream_listen_opt_t *lsopt);
+static ngx_int_t ngx_stream_add_server(ngx_conf_t *cf,
+ ngx_stream_core_srv_conf_t *cscf, ngx_stream_conf_addr_t *addr);
+
+static ngx_int_t ngx_stream_optimize_servers(ngx_conf_t *cf,
+ ngx_stream_core_main_conf_t *cmcf, ngx_array_t *ports);
+static ngx_int_t ngx_stream_server_names(ngx_conf_t *cf,
+ ngx_stream_core_main_conf_t *cmcf, ngx_stream_conf_addr_t *addr);
+static ngx_int_t ngx_stream_cmp_conf_addrs(const void *one, const void *two);
+static int ngx_libc_cdecl ngx_stream_cmp_dns_wildcards(const void *one,
+ const void *two);
+
+static ngx_int_t ngx_stream_init_listening(ngx_conf_t *cf,
+ ngx_stream_conf_port_t *port);
+static ngx_listening_t *ngx_stream_add_listening(ngx_conf_t *cf,
+ ngx_stream_conf_addr_t *addr);
static ngx_int_t ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport,
ngx_stream_conf_addr_t *addr);
#if (NGX_HAVE_INET6)
static ngx_int_t ngx_stream_add_addrs6(ngx_conf_t *cf,
ngx_stream_port_t *stport, ngx_stream_conf_addr_t *addr);
#endif
-static ngx_int_t ngx_stream_cmp_conf_addrs(const void *one, const void *two);


ngx_uint_t ngx_stream_max_module;
@@ -74,10 +92,8 @@ static char *
ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *rv;
- ngx_uint_t i, m, mi, s;
+ ngx_uint_t m, mi, s;
ngx_conf_t pcf;
- ngx_array_t ports;
- ngx_stream_listen_t *listen;
ngx_stream_module_t *module;
ngx_stream_conf_ctx_t *ctx;
ngx_stream_core_srv_conf_t **cscfp;
@@ -251,21 +267,13 @@ ngx_stream_block(ngx_conf_t *cf, ngx_com
return NGX_CONF_ERROR;
}

- if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_stream_conf_port_t))
- != NGX_OK)
- {
+ /* optimize the lists of ports, addresses and server names */
+
+ if (ngx_stream_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
return NGX_CONF_ERROR;
}

- listen = cmcf->listen.elts;
-
- for (i = 0; i < cmcf->listen.nelts; i++) {
- if (ngx_stream_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
- }
-
- return ngx_stream_optimize_servers(cf, &ports);
+ return NGX_CONF_OK;
}


@@ -377,73 +385,295 @@ ngx_stream_init_phase_handlers(ngx_conf_
}


-static ngx_int_t
-ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
- ngx_stream_listen_t *listen)
+ngx_int_t
+ngx_stream_add_listen(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf,
+ ngx_stream_listen_opt_t *lsopt)
{
- in_port_t p;
- ngx_uint_t i;
- struct sockaddr *sa;
- ngx_stream_conf_port_t *port;
- ngx_stream_conf_addr_t *addr;
+ in_port_t p;
+ ngx_uint_t i;
+ struct sockaddr *sa;
+ ngx_stream_conf_port_t *port;
+ ngx_stream_core_main_conf_t *cmcf;
+
+ cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);

- sa = listen->sockaddr;
+ if (cmcf->ports == NULL) {
+ cmcf->ports = ngx_array_create(cf->temp_pool, 2,
+ sizeof(ngx_stream_conf_port_t));
+ if (cmcf->ports == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ sa = lsopt->sockaddr;
p = ngx_inet_get_port(sa);

- port = ports->elts;
- for (i = 0; i < ports->nelts; i++) {
+ port = cmcf->ports->elts;
+ for (i = 0; i < cmcf->ports->nelts; i++) {

- if (p == port[i].port
- && listen->type == port[i].type
- && sa->sa_family == port[i].family)
+ if (p != port[i].port
+ || lsopt->type != port[i].type
+ || sa->sa_family != port[i].family)
{
- /* a port is already in the port list */
+ continue;
+ }

- port = &port[i];
- goto found;
- }
+ /* a port is already in the port list */
+
+ return ngx_stream_add_addresses(cf, cscf, &port[i], lsopt);
}

/* add a port to the port list */

- port = ngx_array_push(ports);
+ port = ngx_array_push(cmcf->ports);
if (port == NULL) {
return NGX_ERROR;
}

port->family = sa->sa_family;
- port->type = listen->type;
+ port->type = lsopt->type;
port->port = p;
+ port->addrs.elts = NULL;
+
+ return ngx_stream_add_address(cf, cscf, port, lsopt);
+}
+
+
+static ngx_int_t
+ngx_stream_add_addresses(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf,
+ ngx_stream_conf_port_t *port, ngx_stream_listen_opt_t *lsopt)
+{
+ ngx_uint_t i, default_server, proxy_protocol,
+ protocols, protocols_prev;
+ ngx_stream_conf_addr_t *addr;
+#if (NGX_STREAM_SSL)
+ ngx_uint_t ssl;
+#endif
+
+ /*
+ * we cannot compare whole sockaddr struct's as kernel
+ * may fill some fields in inherited sockaddr struct's
+ */
+
+ addr = port->addrs.elts;
+
+ for (i = 0; i < port->addrs.nelts; i++) {
+
+ if (ngx_cmp_sockaddr(lsopt->sockaddr, lsopt->socklen,
+ addr[i].opt.sockaddr,
+ addr[i].opt.socklen, 0)
+ != NGX_OK)
+ {
+ continue;
+ }
+
+ /* the address is already in the address list */
+
+ if (ngx_stream_add_server(cf, cscf, &addr[i]) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ /* preserve default_server bit during listen options overwriting */
+ default_server = addr[i].opt.default_server;
+
+ proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol;
+ protocols = lsopt->proxy_protocol;
+ protocols_prev = addr[i].opt.proxy_protocol;
+
+#if (NGX_STREAM_SSL)
+ ssl = lsopt->ssl || addr[i].opt.ssl;
+ protocols |= lsopt->ssl << 1;
+ protocols_prev |= addr[i].opt.ssl << 1;
+#endif
+
+ if (lsopt->set) {
+
+ if (addr[i].opt.set) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate listen options for %V",
+ &addr[i].opt.addr_text);
+ return NGX_ERROR;
+ }
+
+ addr[i].opt = *lsopt;
+ }
+
+ /* check the duplicate "default" server for this address:port */

- if (ngx_array_init(&port->addrs, cf->temp_pool, 2,
- sizeof(ngx_stream_conf_addr_t))
- != NGX_OK)
- {
- return NGX_ERROR;
+ if (lsopt->default_server) {
+
+ if (default_server) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "a duplicate default server for %V",
+ &addr[i].opt.addr_text);
+ return NGX_ERROR;
+ }
+
+ default_server = 1;
+ addr[i].default_server = cscf;
+ }
+
+ /* check for conflicting protocol options */
+
+ if ((protocols | protocols_prev) != protocols_prev) {
+
+ /* options added */
+
+ if ((addr[i].opt.set && !lsopt->set)
+ || addr[i].protocols_changed
+ || (protocols | protocols_prev) != protocols)
+ {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "protocol options redefined for %V",
+ &addr[i].opt.addr_text);
+ }
+
+ addr[i].protocols = protocols_prev;
+ addr[i].protocols_set = 1;
+ addr[i].protocols_changed = 1;
+
+ } else if ((protocols_prev | protocols) != protocols) {
+
+ /* options removed */
+
+ if (lsopt->set
+ || (addr[i].protocols_set && protocols != addr[i].protocols))
+ {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "protocol options redefined for %V",
+ &addr[i].opt.addr_text);
+ }
+
+ addr[i].protocols = protocols;
+ addr[i].protocols_set = 1;
+ addr[i].protocols_changed = 1;
+
+ } else {
+
+ /* the same options */
+
+ if ((lsopt->set && addr[i].protocols_changed)
+ || (addr[i].protocols_set && protocols != addr[i].protocols))
+ {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "protocol options redefined for %V",
+ &addr[i].opt.addr_text);
+ }
+
+ addr[i].protocols = protocols;
+ addr[i].protocols_set = 1;
+ }
+
+ addr[i].opt.default_server = default_server;
+ addr[i].opt.proxy_protocol = proxy_protocol;
+#if (NGX_STREAM_SSL)
+ addr[i].opt.ssl = ssl;
+#endif
+
+ return NGX_OK;
}

-found:
+ /* add the address to the addresses list that bound to this port */
+
+ return ngx_stream_add_address(cf, cscf, port, lsopt);
+}
+
+
+/*
+ * add the server address, the server names and the server core module
+ * configurations to the port list
+ */
+
+static ngx_int_t
+ngx_stream_add_address(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf,
+ ngx_stream_conf_port_t *port, ngx_stream_listen_opt_t *lsopt)
+{
+ ngx_stream_conf_addr_t *addr;
+
+ if (port->addrs.elts == NULL) {
+ if (ngx_array_init(&port->addrs, cf->temp_pool, 4,
+ sizeof(ngx_stream_conf_addr_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+ }

addr = ngx_array_push(&port->addrs);
if (addr == NULL) {
return NGX_ERROR;
}

- addr->opt = *listen;
+ addr->opt = *lsopt;
+ addr->protocols = 0;
+ addr->protocols_set = 0;
+ addr->protocols_changed = 0;
+ addr->hash.buckets = NULL;
+ addr->hash.size = 0;
+ addr->wc_head = NULL;
+ addr->wc_tail = NULL;
+#if (NGX_PCRE)
+ addr->nregex = 0;
+ addr->regex = NULL;
+#endif
+ addr->default_server = cscf;
+ addr->servers.elts = NULL;
+
+ return ngx_stream_add_server(cf, cscf, addr);
+}
+
+
+/* add the server core module configuration to the address:port */
+
+static ngx_int_t
+ngx_stream_add_server(ngx_conf_t *cf, ngx_stream_core_srv_conf_t *cscf,
+ ngx_stream_conf_addr_t *addr)
+{
+ ngx_uint_t i;
+ ngx_stream_core_srv_conf_t **server;
+
+ if (addr->servers.elts == NULL) {
+ if (ngx_array_init(&addr->servers, cf->temp_pool, 4,
+ sizeof(ngx_stream_core_srv_conf_t *))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ } else {
+ server = addr->servers.elts;
+ for (i = 0; i < addr->servers.nelts; i++) {
+ if (server[i] == cscf) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "a duplicate listen %V",
+ &addr->opt.addr_text);
+ return NGX_ERROR;
+ }
+ }
+ }
+
+ server = ngx_array_push(&addr->servers);
+ if (server == NULL) {
+ return NGX_ERROR;
+ }
+
+ *server = cscf;

return NGX_OK;
}


-static char *
-ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
+static ngx_int_t
+ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_stream_core_main_conf_t *cmcf,
+ ngx_array_t *ports)
{
- ngx_uint_t i, p, last, bind_wildcard;
- ngx_listening_t *ls;
- ngx_stream_port_t *stport;
- ngx_stream_conf_port_t *port;
- ngx_stream_conf_addr_t *addr;
- ngx_stream_core_srv_conf_t *cscf;
+ ngx_uint_t p, a;
+ ngx_stream_conf_port_t *port;
+ ngx_stream_conf_addr_t *addr;
+
+ if (ports == NULL) {
+ return NGX_OK;
+ }

port = ports->elts;
for (p = 0; p < ports->nelts; p++) {
@@ -451,175 +681,191 @@ ngx_stream_optimize_servers(ngx_conf_t *
ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
sizeof(ngx_stream_conf_addr_t), ngx_stream_cmp_conf_addrs);

- addr = port[p].addrs.elts;
- last = port[p].addrs.nelts;
-
/*
- * if there is the binding to the "*:port" then we need to bind()
- * to the "*:port" only and ignore the other bindings
+ * check whether all name-based servers have the same
+ * configuration as a default server for given address:port
*/

- if (addr[last - 1].opt.wildcard) {
- addr[last - 1].opt.bind = 1;
- bind_wildcard = 1;
+ addr = port[p].addrs.elts;
+ for (a = 0; a < port[p].addrs.nelts; a++) {

- } else {
- bind_wildcard = 0;
+ if (addr[a].servers.nelts > 1
+#if (NGX_PCRE)
+ || addr[a].default_server->captures
+#endif
+ )
+ {
+ if (ngx_stream_server_names(cf, cmcf, &addr[a]) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
}

- i = 0;
-
- while (i < last) {
-
- if (bind_wildcard && !addr[i].opt.bind) {
- i++;
- continue;
- }
-
- ls = ngx_create_listening(cf, addr[i].opt.sockaddr,
- addr[i].opt.socklen);
- if (ls == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ls->addr_ntop = 1;
- ls->handler = ngx_stream_init_connection;
- ls->pool_size = 256;
- ls->type = addr[i].opt.type;
-
- cscf = addr->opt.ctx->srv_conf[ngx_stream_core_module.ctx_index];
-
- ls->logp = cscf->error_log;
- ls->log.data = &ls->addr_text;
- ls->log.handler = ngx_accept_log_error;
-
- ls->backlog = addr[i].opt.backlog;
- ls->rcvbuf = addr[i].opt.rcvbuf;
- ls->sndbuf = addr[i].opt.sndbuf;
-
- ls->wildcard = addr[i].opt.wildcard;
-
- ls->keepalive = addr[i].opt.so_keepalive;
-#if (NGX_HAVE_KEEPALIVE_TUNABLE)
- ls->keepidle = addr[i].opt.tcp_keepidle;
- ls->keepintvl = addr[i].opt.tcp_keepintvl;
- ls->keepcnt = addr[i].opt.tcp_keepcnt;
-#endif
-
-#if (NGX_HAVE_INET6)
- ls->ipv6only = addr[i].opt.ipv6only;
-#endif
-
-#if (NGX_HAVE_TCP_FASTOPEN)
- ls->fastopen = addr[i].opt.fastopen;
-#endif
-
-#if (NGX_HAVE_REUSEPORT)
- ls->reuseport = addr[i].opt.reuseport;
-#endif
-
- stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t));
- if (stport == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ls->servers = stport;
-
- stport->naddrs = i + 1;
-
- switch (ls->sockaddr->sa_family) {
-#if (NGX_HAVE_INET6)
- case AF_INET6:
- if (ngx_stream_add_addrs6(cf, stport, addr) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
- break;
-#endif
- default: /* AF_INET */
- if (ngx_stream_add_addrs(cf, stport, addr) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
- break;
- }
-
- addr++;
- last--;
+ if (ngx_stream_init_listening(cf, &port[p]) != NGX_OK) {
+ return NGX_ERROR;
}
}

- return NGX_CONF_OK;
-}
-
-
-static ngx_int_t
-ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport,
- ngx_stream_conf_addr_t *addr)
-{
- ngx_uint_t i;
- struct sockaddr_in *sin;
- ngx_stream_in_addr_t *addrs;
-
- stport->addrs = ngx_pcalloc(cf->pool,
- stport->naddrs * sizeof(ngx_stream_in_addr_t));
- if (stport->addrs == NULL) {
- return NGX_ERROR;
- }
-
- addrs = stport->addrs;
-
- for (i = 0; i < stport->naddrs; i++) {
-
- sin = (struct sockaddr_in *) addr[i].opt.sockaddr;
- addrs[i].addr = sin->sin_addr.s_addr;
-
- addrs[i].conf.ctx = addr[i].opt.ctx;
-#if (NGX_STREAM_SSL)
- addrs[i].conf.ssl = addr[i].opt.ssl;
-#endif
- addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
- addrs[i].conf.addr_text = addr[i].opt.addr_text;
- }
-
return NGX_OK;
}


-#if (NGX_HAVE_INET6)
-
static ngx_int_t
-ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport,
+ngx_stream_server_names(ngx_conf_t *cf, ngx_stream_core_main_conf_t *cmcf,
ngx_stream_conf_addr_t *addr)
{
- ngx_uint_t i;
- struct sockaddr_in6 *sin6;
- ngx_stream_in6_addr_t *addrs6;
+ ngx_int_t rc;
+ ngx_uint_t n, s;
+ ngx_hash_init_t hash;
+ ngx_hash_keys_arrays_t ha;
+ ngx_stream_server_name_t *name;
+ ngx_stream_core_srv_conf_t **cscfp;
+#if (NGX_PCRE)
+ ngx_uint_t regex, i;

- stport->addrs = ngx_pcalloc(cf->pool,
- stport->naddrs * sizeof(ngx_stream_in6_addr_t));
- if (stport->addrs == NULL) {
+ regex = 0;
+#endif
+
+ ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t));
+
+ ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
+ if (ha.temp_pool == NULL) {
return NGX_ERROR;
}

- addrs6 = stport->addrs;
+ ha.pool = cf->pool;
+
+ if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
+ goto failed;
+ }
+
+ cscfp = addr->servers.elts;
+
+ for (s = 0; s < addr->servers.nelts; s++) {
+
+ name = cscfp[s]->server_names.elts;
+
+ for (n = 0; n < cscfp[s]->server_names.nelts; n++) {

- for (i = 0; i < stport->naddrs; i++) {
+#if (NGX_PCRE)
+ if (name[n].regex) {
+ regex++;
+ continue;
+ }
+#endif

- sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr;
- addrs6[i].addr6 = sin6->sin6_addr;
+ rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server,
+ NGX_HASH_WILDCARD_KEY);
+
+ if (rc == NGX_ERROR) {
+ goto failed;
+ }

- addrs6[i].conf.ctx = addr[i].opt.ctx;
-#if (NGX_STREAM_SSL)
- addrs6[i].conf.ssl = addr[i].opt.ssl;
-#endif
- addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
- addrs6[i].conf.addr_text = addr[i].opt.addr_text;
+ if (rc == NGX_DECLINED) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "invalid server name or wildcard \"%V\" on %V",
+ &name[n].name, &addr->opt.addr_text);
+ goto failed;
+ }
+
+ if (rc == NGX_BUSY) {
+ ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+ "conflicting server name \"%V\" on %V, ignored",
+ &name[n].name, &addr->opt.addr_text);
+ }
+ }
+ }
+
+ hash.key = ngx_hash_key_lc;
+ hash.max_size = cmcf->server_names_hash_max_size;
+ hash.bucket_size = cmcf->server_names_hash_bucket_size;
+ hash.name = "server_names_hash";
+ hash.pool = cf->pool;
+
+ if (ha.keys.nelts) {
+ hash.hash = &addr->hash;
+ hash.temp_pool = NULL;
+
+ if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) {
+ goto failed;
+ }
}

- return NGX_OK;
-}
+ if (ha.dns_wc_head.nelts) {
+
+ ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts,
+ sizeof(ngx_hash_key_t), ngx_stream_cmp_dns_wildcards);
+
+ hash.hash = NULL;
+ hash.temp_pool = ha.temp_pool;
+
+ if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts,
+ ha.dns_wc_head.nelts)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+
+ addr->wc_head = (ngx_hash_wildcard_t *) hash.hash;
+ }
+
+ if (ha.dns_wc_tail.nelts) {
+
+ ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts,
+ sizeof(ngx_hash_key_t), ngx_stream_cmp_dns_wildcards);
+
+ hash.hash = NULL;
+ hash.temp_pool = ha.temp_pool;
+
+ if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts,
+ ha.dns_wc_tail.nelts)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+
+ addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash;
+ }
+
+ ngx_destroy_pool(ha.temp_pool);
+
+#if (NGX_PCRE)
+
+ if (regex == 0) {
+ return NGX_OK;
+ }
+
+ addr->nregex = regex;
+ addr->regex = ngx_palloc(cf->pool,
+ regex * sizeof(ngx_stream_server_name_t));
+ if (addr->regex == NULL) {
+ return NGX_ERROR;
+ }
+
+ i = 0;
+
+ for (s = 0; s < addr->servers.nelts; s++) {
+
+ name = cscfp[s]->server_names.elts;
+
+ for (n = 0; n < cscfp[s]->server_names.nelts; n++) {
+ if (name[n].regex) {
+ addr->regex[i++] = name[n];
+ }
+ }
+ }

#endif

+ return NGX_OK;
+
+failed:
+
+ ngx_destroy_pool(ha.temp_pool);
+
+ return NGX_ERROR;
+}
+

static ngx_int_t
ngx_stream_cmp_conf_addrs(const void *one, const void *two)
@@ -630,12 +876,12 @@ ngx_stream_cmp_conf_addrs(const void *on
second = (ngx_stream_conf_addr_t *) two;

if (first->opt.wildcard) {
- /* a wildcard must be the last resort, shift it to the end */
+ /* a wildcard address must be the last resort, shift it to the end */
return 1;
}

if (second->opt.wildcard) {
- /* a wildcard must be the last resort, shift it to the end */
+ /* a wildcard address must be the last resort, shift it to the end */
return -1;
}

@@ -653,3 +899,289 @@ ngx_stream_cmp_conf_addrs(const void *on

return 0;
}
+
+
+static int ngx_libc_cdecl
+ngx_stream_cmp_dns_wildcards(const void *one, const void *two)
+{
+ ngx_hash_key_t *first, *second;
+
+ first = (ngx_hash_key_t *) one;
+ second = (ngx_hash_key_t *) two;
+
+ return ngx_dns_strcmp(first->key.data, second->key.data);
+}
+
+
+static ngx_int_t
+ngx_stream_init_listening(ngx_conf_t *cf, ngx_stream_conf_port_t *port)
+{
+ ngx_uint_t i, last, bind_wildcard;
+ ngx_listening_t *ls;
+ ngx_stream_port_t *hport;
+ ngx_stream_conf_addr_t *addr;
+
+ addr = port->addrs.elts;
+ last = port->addrs.nelts;
+
+ /*
+ * If there is a binding to an "*:port" then we need to bind() to
+ * the "*:port" only and ignore other implicit bindings. The bindings
+ * have been already sorted: explicit bindings are on the start, then
+ * implicit bindings go, and wildcard binding is in the end.
+ */
+
+ if (addr[last - 1].opt.wildcard) {
+ addr[last - 1].opt.bind = 1;
+ bind_wildcard = 1;
+
+ } else {
+ bind_wildcard = 0;
+ }
+
+ i = 0;
+
+ while (i < last) {
+
+ if (bind_wildcard && !addr[i].opt.bind) {
+ i++;
+ continue;
+ }
+
+ ls = ngx_stream_add_listening(cf, &addr[i]);
+ if (ls == NULL) {
+ return NGX_ERROR;
+ }
+
+ hport = ngx_pcalloc(cf->pool, sizeof(ngx_stream_port_t));
+ if (hport == NULL) {
+ return NGX_ERROR;
+ }
+
+ ls->servers = hport;
+
+ hport->naddrs = i + 1;
+
+ switch (ls->sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ if (ngx_stream_add_addrs6(cf, hport, addr) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ break;
+#endif
+ default: /* AF_INET */
+ if (ngx_stream_add_addrs(cf, hport, addr) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ break;
+ }
+
+ addr++;
+ last--;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_listening_t *
+ngx_stream_add_listening(ngx_conf_t *cf, ngx_stream_conf_addr_t *addr)
+{
+ ngx_listening_t *ls;
+ ngx_stream_core_srv_conf_t *cscf;
+
+ ls = ngx_create_listening(cf, addr->opt.sockaddr, addr->opt.socklen);
+ if (ls == NULL) {
+ return NULL;
+ }
+
+ ls->addr_ntop = 1;
+
+ ls->handler = ngx_stream_init_connection;
+
+ cscf = addr->default_server;
+ ls->pool_size = 256;
+
+ ls->logp = cscf->error_log;
+ ls->log.data = &ls->addr_text;
+ ls->log.handler = ngx_accept_log_error;
+
+#if (NGX_WIN32)
+ {
+ ngx_iocp_conf_t *iocpcf = NULL;
+
+ if (ngx_get_conf(cf->cycle->conf_ctx, ngx_events_module)) {
+ iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
+ }
+ if (iocpcf && iocpcf->acceptex_read) {
+ ls->post_accept_buffer_size = cscf->client_header_buffer_size;
+ }
+ }
+#endif
+
+ ls->type = addr->opt.type;
+ ls->backlog = addr->opt.backlog;
+ ls->rcvbuf = addr->opt.rcvbuf;
+ ls->sndbuf = addr->opt.sndbuf;
+
+ ls->keepalive = addr->opt.so_keepalive;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ ls->keepidle = addr->opt.tcp_keepidle;
+ ls->keepintvl = addr->opt.tcp_keepintvl;
+ ls->keepcnt = addr->opt.tcp_keepcnt;
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ ls->accept_filter = addr->opt.accept_filter;
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+ ls->deferred_accept = addr->opt.deferred_accept;
+#endif
+
+#if (NGX_HAVE_INET6)
+ ls->ipv6only = addr->opt.ipv6only;
+#endif
+
+#if (NGX_HAVE_SETFIB)
+ ls->setfib = addr->opt.setfib;
+#endif
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+ ls->fastopen = addr->opt.fastopen;
+#endif
+
+#if (NGX_HAVE_REUSEPORT)
+ ls->reuseport = addr->opt.reuseport;
+#endif
+
+ ls->wildcard = addr->opt.wildcard;
+
+ return ls;
+}
+
+
+static ngx_int_t
+ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *hport,
+ ngx_stream_conf_addr_t *addr)
+{
+ ngx_uint_t i;
+ struct sockaddr_in *sin;
+ ngx_stream_in_addr_t *addrs;
+ ngx_stream_virtual_names_t *vn;
+
+ hport->addrs = ngx_pcalloc(cf->pool,
+ hport->naddrs * sizeof(ngx_stream_in_addr_t));
+ if (hport->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ addrs = hport->addrs;
+
+ for (i = 0; i < hport->naddrs; i++) {
+
+ sin = (struct sockaddr_in *) addr[i].opt.sockaddr;
+ addrs[i].addr = sin->sin_addr.s_addr;
+ addrs[i].conf.default_server = addr[i].default_server;
+#if (NGX_STREAM_SSL)
+ addrs[i].conf.ssl = addr[i].opt.ssl;
+#endif
+ addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
+
+ if (addr[i].hash.buckets == NULL
+ && (addr[i].wc_head == NULL
+ || addr[i].wc_head->hash.buckets == NULL)
+ && (addr[i].wc_tail == NULL
+ || addr[i].wc_tail->hash.buckets == NULL)
+#if (NGX_PCRE)
+ && addr[i].nregex == 0
+#endif
+ )
+ {
+ continue;
+ }
+
+ vn = ngx_palloc(cf->pool, sizeof(ngx_stream_virtual_names_t));
+ if (vn == NULL) {
+ return NGX_ERROR;
+ }
+
+ addrs[i].conf.virtual_names = vn;
+
+ vn->names.hash = addr[i].hash;
+ vn->names.wc_head = addr[i].wc_head;
+ vn->names.wc_tail = addr[i].wc_tail;
+#if (NGX_PCRE)
+ vn->nregex = addr[i].nregex;
+ vn->regex = addr[i].regex;
+#endif
+ }
+
+ return NGX_OK;
+}
+
+
+#if (NGX_HAVE_INET6)
+
+static ngx_int_t
+ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *hport,
+ ngx_stream_conf_addr_t *addr)
+{
+ ngx_uint_t i;
+ struct sockaddr_in6 *sin6;
+ ngx_stream_in6_addr_t *addrs6;
+ ngx_stream_virtual_names_t *vn;
+
+ hport->addrs = ngx_pcalloc(cf->pool,
+ hport->naddrs * sizeof(ngx_stream_in6_addr_t));
+ if (hport->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ addrs6 = hport->addrs;
+
+ for (i = 0; i < hport->naddrs; i++) {
+
+ sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr;
+ addrs6[i].addr6 = sin6->sin6_addr;
+ addrs6[i].conf.default_server = addr[i].default_server;
+#if (NGX_STREAM_SSL)
+ addrs6[i].conf.ssl = addr[i].opt.ssl;
+#endif
+ addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
+
+ if (addr[i].hash.buckets == NULL
+ && (addr[i].wc_head == NULL
+ || addr[i].wc_head->hash.buckets == NULL)
+ && (addr[i].wc_tail == NULL
+ || addr[i].wc_tail->hash.buckets == NULL)
+#if (NGX_PCRE)
+ && addr[i].nregex == 0
+#endif
+ )
+ {
+ continue;
+ }
+
+ vn = ngx_palloc(cf->pool, sizeof(ngx_stream_virtual_names_t));
+ if (vn == NULL) {
+ return NGX_ERROR;
+ }
+
+ addrs6[i].conf.virtual_names = vn;
+
+ vn->names.hash = addr[i].hash;
+ vn->names.wc_head = addr[i].wc_head;
+ vn->names.wc_tail = addr[i].wc_tail;
+#if (NGX_PCRE)
+ vn->nregex = addr[i].nregex;
+ vn->regex = addr[i].regex;
+#endif
+ }
+
+ return NGX_OK;
+}
+
+#endif
diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h
--- a/src/stream/ngx_stream.h
+++ b/src/stream/ngx_stream.h
@@ -45,74 +45,39 @@ typedef struct {
socklen_t socklen;
ngx_str_t addr_text;

- /* server ctx */
- ngx_stream_conf_ctx_t *ctx;
-
+ unsigned set:1;
+ unsigned default_server:1;
unsigned bind:1;
unsigned wildcard:1;
unsigned ssl:1;
#if (NGX_HAVE_INET6)
unsigned ipv6only:1;
#endif
+ unsigned deferred_accept:1;
unsigned reuseport:1;
unsigned so_keepalive:2;
unsigned proxy_protocol:1;
+
+ int backlog;
+ int rcvbuf;
+ int sndbuf;
+ int type;
+#if (NGX_HAVE_SETFIB)
+ int setfib;
+#endif
+#if (NGX_HAVE_TCP_FASTOPEN)
+ int fastopen;
+#endif
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
int tcp_keepidle;
int tcp_keepintvl;
int tcp_keepcnt;
#endif
- int backlog;
- int rcvbuf;
- int sndbuf;
-#if (NGX_HAVE_TCP_FASTOPEN)
- int fastopen;
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ char *accept_filter;
#endif
- int type;
-} ngx_stream_listen_t;
-
-
-typedef struct {
- ngx_stream_conf_ctx_t *ctx;
- ngx_str_t addr_text;
- unsigned ssl:1;
- unsigned proxy_protocol:1;
-} ngx_stream_addr_conf_t;
-
-typedef struct {
- in_addr_t addr;
- ngx_stream_addr_conf_t conf;
-} ngx_stream_in_addr_t;
-
-
-#if (NGX_HAVE_INET6)
-
-typedef struct {
- struct in6_addr addr6;
- ngx_stream_addr_conf_t conf;
-} ngx_stream_in6_addr_t;
-
-#endif
-
-
-typedef struct {
- /* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */
- void *addrs;
- ngx_uint_t naddrs;
-} ngx_stream_port_t;
-
-
-typedef struct {
- int family;
- int type;
- in_port_t port;
- ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */
-} ngx_stream_conf_port_t;
-
-
-typedef struct {
- ngx_stream_listen_t opt;
-} ngx_stream_conf_addr_t;
+} ngx_stream_listen_opt_t;


typedef enum {
@@ -153,7 +118,6 @@ typedef struct {

typedef struct {
ngx_array_t servers; /* ngx_stream_core_srv_conf_t */
- ngx_array_t listen; /* ngx_stream_listen_t */

ngx_stream_phase_engine_t phase_engine;

@@ -163,16 +127,24 @@ typedef struct {
ngx_array_t prefix_variables; /* ngx_stream_variable_t */
ngx_uint_t ncaptures;

+ ngx_uint_t server_names_hash_max_size;
+ ngx_uint_t server_names_hash_bucket_size;
+
ngx_uint_t variables_hash_max_size;
ngx_uint_t variables_hash_bucket_size;

ngx_hash_keys_arrays_t *variables_keys;

+ ngx_array_t *ports;
+
ngx_stream_phase_t phases[NGX_STREAM_LOG_PHASE + 1];
} ngx_stream_core_main_conf_t;


typedef struct {
+ /* array of the ngx_stream_server_name_t, "server_name" directive */
+ ngx_array_t server_names;
+
ngx_stream_content_handler_pt handler;

ngx_stream_conf_ctx_t *ctx;
@@ -180,6 +152,8 @@ typedef struct {
u_char *file_name;
ngx_uint_t line;

+ ngx_str_t server_name;
+
ngx_flag_t tcp_nodelay;
size_t preread_buffer_size;
ngx_msec_t preread_timeout;
@@ -191,10 +165,99 @@ typedef struct {

ngx_msec_t proxy_protocol_timeout;

- ngx_uint_t listen; /* unsigned listen:1; */
+ unsigned listen:1;
+#if (NGX_PCRE)
+ unsigned captures:1;
+#endif
} ngx_stream_core_srv_conf_t;


+/* list of structures to find core_srv_conf quickly at run time */
+
+
+typedef struct {
+#if (NGX_PCRE)
+ ngx_stream_regex_t *regex;
+#endif
+ ngx_stream_core_srv_conf_t *server; /* virtual name server conf */
+ ngx_str_t name;
+} ngx_stream_server_name_t;
+
+
+typedef struct {
+ ngx_hash_combined_t names;
+
+ ngx_uint_t nregex;
+ ngx_stream_server_name_t *regex;
+} ngx_stream_virtual_names_t;
+
+
+typedef struct {
+ /* the default server configuration for this address:port */
+ ngx_stream_core_srv_conf_t *default_server;
+
+ ngx_stream_virtual_names_t *virtual_names;
+
+ ngx_str_t addr_text;
+ unsigned ssl:1;
+ unsigned proxy_protocol:1;
+} ngx_stream_addr_conf_t;
+
+
+typedef struct {
+ in_addr_t addr;
+ ngx_stream_addr_conf_t conf;
+} ngx_stream_in_addr_t;
+
+
+#if (NGX_HAVE_INET6)
+
+typedef struct {
+ struct in6_addr addr6;
+ ngx_stream_addr_conf_t conf;
+} ngx_stream_in6_addr_t;
+
+#endif
+
+
+typedef struct {
+ /* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */
+ void *addrs;
+ ngx_uint_t naddrs;
+} ngx_stream_port_t;
+
+
+typedef struct {
+ int family;
+ int type;
+ in_port_t port;
+ ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */
+} ngx_stream_conf_port_t;
+
+
+typedef struct {
+ ngx_stream_listen_opt_t opt;
+
+ unsigned protocols:3;
+ unsigned protocols_set:1;
+ unsigned protocols_changed:1;
+
+ ngx_hash_t hash;
+ ngx_hash_wildcard_t *wc_head;
+ ngx_hash_wildcard_t *wc_tail;
+
+#if (NGX_PCRE)
+ ngx_uint_t nregex;
+ ngx_stream_server_name_t *regex;
+#endif
+
+ /* the default server configuration for this address:port */
+ ngx_stream_core_srv_conf_t *default_server;
+ ngx_array_t servers;
+ /* array of ngx_stream_core_srv_conf_t */
+} ngx_stream_conf_addr_t;
+
+
struct ngx_stream_session_s {
uint32_t signature; /* "STRM" */

@@ -210,6 +273,8 @@ struct ngx_stream_session_s {
void **main_conf;
void **srv_conf;

+ ngx_stream_virtual_names_t *virtual_names;
+
ngx_stream_upstream_t *upstream;
ngx_array_t *upstream_states;
/* of ngx_stream_upstream_state_t */
@@ -283,6 +348,8 @@ typedef struct {
#define NGX_STREAM_WRITE_BUFFERED 0x10


+ngx_int_t ngx_stream_add_listen(ngx_conf_t *cf,
+ ngx_stream_core_srv_conf_t *cscf, ngx_stream_listen_opt_t *lsopt);
void ngx_stream_core_run_phases(ngx_stream_session_t *s);
ngx_int_t ngx_stream_core_generic_phase(ngx_stream_session_t *s,
ngx_stream_phase_handler_t *ph);
@@ -290,6 +357,10 @@ ngx_int_t ngx_stream_core_preread_phase(
ngx_stream_phase_handler_t *ph);
ngx_int_t ngx_stream_core_content_phase(ngx_stream_session_t *s,
ngx_stream_phase_handler_t *ph);
+ngx_int_t ngx_stream_find_virtual_server(ngx_stream_session_t *s,
+ ngx_str_t *host, ngx_stream_core_srv_conf_t **cscfp);
+ngx_int_t ngx_stream_validate_host(ngx_str_t *host, ngx_pool_t *pool,
+ ngx_uint_t alloc);


void ngx_stream_init_connection(ngx_connection_t *c);
diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c
--- a/src/stream/ngx_stream_core_module.c
+++ b/src/stream/ngx_stream_core_module.c
@@ -26,6 +26,8 @@ static char *ngx_stream_core_server(ngx_
void *conf);
static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_stream_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);

@@ -46,6 +48,20 @@ static ngx_command_t ngx_stream_core_co
offsetof(ngx_stream_core_main_conf_t, variables_hash_bucket_size),
NULL },

+ { ngx_string("server_names_hash_max_size"),
+ NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_STREAM_MAIN_CONF_OFFSET,
+ offsetof(ngx_stream_core_main_conf_t, server_names_hash_max_size),
+ NULL },
+
+ { ngx_string("server_names_hash_bucket_size"),
+ NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_STREAM_MAIN_CONF_OFFSET,
+ offsetof(ngx_stream_core_main_conf_t, server_names_hash_bucket_size),
+ NULL },
+
{ ngx_string("server"),
NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
ngx_stream_core_server,
@@ -60,6 +76,13 @@ static ngx_command_t ngx_stream_core_co
0,
NULL },

+ { ngx_string("server_name"),
+ NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
+ ngx_stream_core_server_name,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("error_log"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
ngx_stream_core_error_log,
@@ -413,6 +436,149 @@ ngx_stream_core_content_phase(ngx_stream
}


+ngx_int_t
+ngx_stream_find_virtual_server(ngx_stream_session_t *s,
+ ngx_str_t *host, ngx_stream_core_srv_conf_t **cscfp)
+{
+ ngx_stream_core_srv_conf_t *cscf;
+
+ if (s->virtual_names == NULL) {
+ return NGX_DECLINED;
+ }
+
+ cscf = ngx_hash_find_combined(&s->virtual_names->names,
+ ngx_hash_key(host->data, host->len),
+ host->data, host->len);
+
+ if (cscf) {
+ *cscfp = cscf;
+ return NGX_OK;
+ }
+
+#if (NGX_PCRE)
+
+ if (host->len && s->virtual_names->nregex) {
+ ngx_int_t n;
+ ngx_uint_t i;
+ ngx_stream_server_name_t *sn;
+
+ sn = s->virtual_names->regex;
+
+ for (i = 0; i < s->virtual_names->nregex; i++) {
+
+ n = ngx_stream_regex_exec(s, sn[i].regex, host);
+
+ if (n == NGX_DECLINED) {
+ continue;
+ }
+
+ if (n == NGX_OK) {
+ *cscfp = sn[i].server;
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+ }
+ }
+
+#endif /* NGX_PCRE */
+
+ return NGX_DECLINED;
+}
+
+
+ngx_int_t
+ngx_stream_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
+{
+ u_char *h, ch;
+ size_t i, dot_pos, host_len;
+
+ enum {
+ sw_usual = 0,
+ sw_literal,
+ sw_rest
+ } state;
+
+ dot_pos = host->len;
+ host_len = host->len;
+
+ h = host->data;
+
+ state = sw_usual;
+
+ for (i = 0; i < host->len; i++) {
+ ch = h[i];
+
+ switch (ch) {
+
+ case '.':
+ if (dot_pos == i - 1) {
+ return NGX_DECLINED;
+ }
+ dot_pos = i;
+ break;
+
+ case ':':
+ if (state == sw_usual) {
+ host_len = i;
+ state = sw_rest;
+ }
+ break;
+
+ case '[':
+ if (i == 0) {
+ state = sw_literal;
+ }
+ break;
+
+ case ']':
+ if (state == sw_literal) {
+ host_len = i + 1;
+ state = sw_rest;
+ }
+ break;
+
+ default:
+
+ if (ngx_path_separator(ch)) {
+ return NGX_DECLINED;
+ }
+
+ if (ch <= 0x20 || ch == 0x7f) {
+ return NGX_DECLINED;
+ }
+
+ if (ch >= 'A' && ch <= 'Z') {
+ alloc = 1;
+ }
+
+ break;
+ }
+ }
+
+ if (dot_pos == host_len - 1) {
+ host_len--;
+ }
+
+ if (host_len == 0) {
+ return NGX_DECLINED;
+ }
+
+ if (alloc) {
+ host->data = ngx_pnalloc(pool, host_len);
+ if (host->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_strlow(host->data, h, host_len);
+ }
+
+ host->len = host_len;
+
+ return NGX_OK;
+}
+
+
static ngx_int_t
ngx_stream_core_preconfiguration(ngx_conf_t *cf)
{
@@ -437,11 +603,8 @@ ngx_stream_core_create_main_conf(ngx_con
return NULL;
}

- if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_stream_listen_t))
- != NGX_OK)
- {
- return NULL;
- }
+ cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT;
+ cmcf->server_names_hash_bucket_size = NGX_CONF_UNSET_UINT;

cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;
@@ -455,6 +618,14 @@ ngx_stream_core_init_main_conf(ngx_conf_
{
ngx_stream_core_main_conf_t *cmcf = conf;

+ ngx_conf_init_uint_value(cmcf->server_names_hash_max_size, 512);
+ ngx_conf_init_uint_value(cmcf->server_names_hash_bucket_size,
+ ngx_cacheline_size);
+
+ cmcf->server_names_hash_bucket_size =
+ ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
+
+
ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);

@@ -486,6 +657,13 @@ ngx_stream_core_create_srv_conf(ngx_conf
* cscf->error_log = NULL;
*/

+ if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4,
+ sizeof(ngx_stream_server_name_t))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+
cscf->file_name = cf->conf_file->file.name.data;
cscf->line = cf->conf_file->line;
cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
@@ -504,6 +682,9 @@ ngx_stream_core_merge_srv_conf(ngx_conf_
ngx_stream_core_srv_conf_t *prev = parent;
ngx_stream_core_srv_conf_t *conf = child;

+ ngx_str_t name;
+ ngx_stream_server_name_t *sn;
+
ngx_conf_merge_msec_value(conf->resolver_timeout,
prev->resolver_timeout, 30000);

@@ -551,6 +732,37 @@ ngx_stream_core_merge_srv_conf(ngx_conf_
ngx_conf_merge_msec_value(conf->preread_timeout,
prev->preread_timeout, 30000);

+ if (conf->server_names.nelts == 0) {
+ /* the array has 4 empty preallocated elements, so push cannot fail */
+ sn = ngx_array_push(&conf->server_names);
+#if (NGX_PCRE)
+ sn->regex = NULL;
+#endif
+ sn->server = conf;
+ ngx_str_set(&sn->name, "");
+ }
+
+ sn = conf->server_names.elts;
+ name = sn[0].name;
+
+#if (NGX_PCRE)
+ if (sn->regex) {
+ name.len++;
+ name.data--;
+ } else
+#endif
+
+ if (name.data[0] == '.') {
+ name.len--;
+ name.data++;
+ }
+
+ conf->server_name.len = name.len;
+ conf->server_name.data = ngx_pstrdup(cf->pool, &name);
+ if (conf->server_name.data == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
return NGX_CONF_OK;
}

@@ -650,11 +862,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
{
ngx_stream_core_srv_conf_t *cscf = conf;

- ngx_str_t *value, size;
- ngx_url_t u;
- ngx_uint_t i, n, backlog;
- ngx_stream_listen_t *ls, *als, *nls;
- ngx_stream_core_main_conf_t *cmcf;
+ ngx_str_t *value, size;
+ ngx_url_t u;
+ ngx_uint_t i, n, backlog;
+ ngx_stream_listen_opt_t lsopt;

cscf->listen = 1;

@@ -675,51 +886,48 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
return NGX_CONF_ERROR;
}

- cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
-
- ls = ngx_array_push(&cmcf->listen);
- if (ls == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ngx_memzero(ls, sizeof(ngx_stream_listen_t));
+ ngx_memzero(&lsopt, sizeof(ngx_stream_listen_opt_t));

- ls->backlog = NGX_LISTEN_BACKLOG;
- ls->rcvbuf = -1;
- ls->sndbuf = -1;
- ls->type = SOCK_STREAM;
- ls->ctx = cf->ctx;
-
+ lsopt.backlog = NGX_LISTEN_BACKLOG;
+ lsopt.type = SOCK_STREAM;
+ lsopt.rcvbuf = -1;
+ lsopt.sndbuf = -1;
#if (NGX_HAVE_TCP_FASTOPEN)
- ls->fastopen = -1;
+ lsopt.fastopen = -1;
#endif
-
#if (NGX_HAVE_INET6)
- ls->ipv6only = 1;
+ lsopt.ipv6only = 1;
#endif

backlog = 0;

for (i = 2; i < cf->args->nelts; i++) {

+ if (ngx_strcmp(value[i].data, "default_server") == 0
+ || ngx_strcmp(value[i].data, "default") == 0)
+ {
+ lsopt.default_server = 1;
+ continue;
+ }
+
#if !(NGX_WIN32)
if (ngx_strcmp(value[i].data, "udp") == 0) {
- ls->type = SOCK_DGRAM;
+ lsopt.type = SOCK_DGRAM;
continue;
}
#endif

if (ngx_strcmp(value[i].data, "bind") == 0) {
- ls->bind = 1;
+ lsopt.bind = 1;
continue;
}

#if (NGX_HAVE_TCP_FASTOPEN)
if (ngx_strncmp(value[i].data, "fastopen=", 9) == 0) {
- ls->fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9);
- ls->bind = 1;
+ lsopt.fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9);
+ lsopt.bind = 1;

- if (ls->fastopen == NGX_ERROR) {
+ if (lsopt.fastopen == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid fastopen \"%V\"", &value[i]);
return NGX_CONF_ERROR;
@@ -730,10 +938,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
#endif

if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
- ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
- ls->bind = 1;
+ lsopt.backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
+ lsopt.bind = 1;

- if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
+ if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid backlog \"%V\"", &value[i]);
return NGX_CONF_ERROR;
@@ -748,10 +956,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
size.len = value[i].len - 7;
size.data = value[i].data + 7;

- ls->rcvbuf = ngx_parse_size(&size);
- ls->bind = 1;
+ lsopt.rcvbuf = ngx_parse_size(&size);
+ lsopt.bind = 1;

- if (ls->rcvbuf == NGX_ERROR) {
+ if (lsopt.rcvbuf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid rcvbuf \"%V\"", &value[i]);
return NGX_CONF_ERROR;
@@ -764,10 +972,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
size.len = value[i].len - 7;
size.data = value[i].data + 7;

- ls->sndbuf = ngx_parse_size(&size);
- ls->bind = 1;
+ lsopt.sndbuf = ngx_parse_size(&size);
+ lsopt.bind = 1;

- if (ls->sndbuf == NGX_ERROR) {
+ if (lsopt.sndbuf == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid sndbuf \"%V\"", &value[i]);
return NGX_CONF_ERROR;
@@ -779,10 +987,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
if (ngx_strcmp(&value[i].data[10], "n") == 0) {
- ls->ipv6only = 1;
+ lsopt.ipv6only = 1;

} else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
- ls->ipv6only = 0;
+ lsopt.ipv6only = 0;

} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -791,7 +999,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
return NGX_CONF_ERROR;
}

- ls->bind = 1;
+ lsopt.bind = 1;
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -803,8 +1011,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, n

if (ngx_strcmp(value[i].data, "reuseport") == 0) {
#if (NGX_HAVE_REUSEPORT)
- ls->reuseport = 1;
- ls->bind = 1;
+ lsopt.reuseport = 1;
+ lsopt.bind = 1;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"reuseport is not supported "
@@ -824,7 +1032,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
sslcf->file = cf->conf_file->file.name.data;
sslcf->line = cf->conf_file->line;

- ls->ssl = 1;
+ lsopt.ssl = 1;

continue;
#else
@@ -838,10 +1046,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {

if (ngx_strcmp(&value[i].data[13], "on") == 0) {
- ls->so_keepalive = 1;
+ lsopt.so_keepalive = 1;

} else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
- ls->so_keepalive = 2;
+ lsopt.so_keepalive = 2;

} else {

@@ -860,8 +1068,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
if (p > s.data) {
s.len = p - s.data;

- ls->tcp_keepidle = ngx_parse_time(&s, 1);
- if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
+ lsopt.tcp_keepidle = ngx_parse_time(&s, 1);
+ if (lsopt.tcp_keepidle == (time_t) NGX_ERROR) {
goto invalid_so_keepalive;
}
}
@@ -876,8 +1084,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
if (p > s.data) {
s.len = p - s.data;

- ls->tcp_keepintvl = ngx_parse_time(&s, 1);
- if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
+ lsopt.tcp_keepintvl = ngx_parse_time(&s, 1);
+ if (lsopt.tcp_keepintvl == (time_t) NGX_ERROR) {
goto invalid_so_keepalive;
}
}
@@ -887,19 +1095,19 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
if (s.data < end) {
s.len = end - s.data;

- ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
- if (ls->tcp_keepcnt == NGX_ERROR) {
+ lsopt.tcp_keepcnt = ngx_atoi(s.data, s.len);
+ if (lsopt.tcp_keepcnt == NGX_ERROR) {
goto invalid_so_keepalive;
}
}

- if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
- && ls->tcp_keepcnt == 0)
+ if (lsopt.tcp_keepidle == 0 && lsopt.tcp_keepintvl == 0
+ && lsopt.tcp_keepcnt == 0)
{
goto invalid_so_keepalive;
}

- ls->so_keepalive = 1;
+ lsopt.so_keepalive = 1;

#else

@@ -911,7 +1119,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
#endif
}

- ls->bind = 1;
+ lsopt.bind = 1;

continue;

@@ -926,7 +1134,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
}

if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) {
- ls->proxy_protocol = 1;
+ lsopt.proxy_protocol = 1;
continue;
}

@@ -935,27 +1143,27 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
return NGX_CONF_ERROR;
}

- if (ls->type == SOCK_DGRAM) {
+ if (lsopt.type == SOCK_DGRAM) {
if (backlog) {
return "\"backlog\" parameter is incompatible with \"udp\"";
}

#if (NGX_STREAM_SSL)
- if (ls->ssl) {
+ if (lsopt.ssl) {
return "\"ssl\" parameter is incompatible with \"udp\"";
}
#endif

- if (ls->so_keepalive) {
+ if (lsopt.so_keepalive) {
return "\"so_keepalive\" parameter is incompatible with \"udp\"";
}

- if (ls->proxy_protocol) {
+ if (lsopt.proxy_protocol) {
return "\"proxy_protocol\" parameter is incompatible with \"udp\"";
}

#if (NGX_HAVE_TCP_FASTOPEN)
- if (ls->fastopen != -1) {
+ if (lsopt.fastopen != -1) {
return "\"fastopen\" parameter is incompatible with \"udp\"";
}
#endif
@@ -972,40 +1180,12 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
}
}

- if (n != 0) {
- nls = ngx_array_push(&cmcf->listen);
- if (nls == NULL) {
- return NGX_CONF_ERROR;
- }
-
- *nls = *ls;
-
- } else {
- nls = ls;
- }
-
- nls->sockaddr = u.addrs[n].sockaddr;
- nls->socklen = u.addrs[n].socklen;
- nls->addr_text = u.addrs[n].name;
- nls->wildcard = ngx_inet_wildcard(nls->sockaddr);
+ lsopt.sockaddr = u.addrs[n].sockaddr;
+ lsopt.socklen = u.addrs[n].socklen;
+ lsopt.addr_text = u.addrs[n].name;
+ lsopt.wildcard = ngx_inet_wildcard(lsopt.sockaddr);

- als = cmcf->listen.elts;
-
- for (i = 0; i < cmcf->listen.nelts - 1; i++) {
- if (nls->type != als[i].type) {
- continue;
- }
-
- if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen,
- nls->sockaddr, nls->socklen, 1)
- != NGX_OK)
- {
- continue;
- }
-
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "duplicate \"%V\" address and port pair",
- &nls->addr_text);
+ if (ngx_stream_add_listen(cf, cscf, &lsopt) != NGX_OK) {
return NGX_CONF_ERROR;
}

@@ -1018,6 +1198,107 @@ ngx_stream_core_listen(ngx_conf_t *cf, n


static char *
+ngx_stream_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_stream_core_srv_conf_t *cscf = conf;
+
+ u_char ch;
+ ngx_str_t *value;
+ ngx_uint_t i;
+ ngx_stream_server_name_t *sn;
+
+ value = cf->args->elts;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ ch = value[i].data[0];
+
+ if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
+ || (ch == '.' && value[i].len < 2))
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "server name \"%V\" is invalid", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_strchr(value[i].data, '/')) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "server name \"%V\" has suspicious symbols",
+ &value[i]);
+ }
+
+ sn = ngx_array_push(&cscf->server_names);
+ if (sn == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+#if (NGX_PCRE)
+ sn->regex = NULL;
+#endif
+ sn->server = cscf;
+
+ if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
+ sn->name = cf->cycle->hostname;
+
+ } else {
+ sn->name = value[i];
+ }
+
+ if (value[i].data[0] != '~') {
+ ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
+ continue;
+ }
+
+#if (NGX_PCRE)
+ {
+ u_char *p;
+ ngx_regex_compile_t rc;
+ u_char errstr[NGX_MAX_CONF_ERRSTR];
+
+ if (value[i].len == 1) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "empty regex in server name \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ value[i].len--;
+ value[i].data++;
+
+ ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+ rc.pattern = value[i];
+ rc.err.len = NGX_MAX_CONF_ERRSTR;
+ rc.err.data = errstr;
+
+ for (p = value[i].data; p < value[i].data + value[i].len; p++) {
+ if (*p >= 'A' && *p <= 'Z') {
+ rc.options = NGX_REGEX_CASELESS;
+ break;
+ }
+ }
+
+ sn->regex = ngx_stream_regex_compile(cf, &rc);
+ if (sn->regex == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ sn->name = value[i];
+ cscf->captures = (rc.captures > 0);
+ }
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "using regex \"%V\" "
+ "requires PCRE library", &value[i]);
+
+ return NGX_CONF_ERROR;
+#endif
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
ngx_stream_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_stream_core_srv_conf_t *cscf = conf;
diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c
--- a/src/stream/ngx_stream_handler.c
+++ b/src/stream/ngx_stream_handler.c
@@ -30,6 +30,7 @@ ngx_stream_init_connection(ngx_connectio
struct sockaddr_in *sin;
ngx_stream_in_addr_t *addr;
ngx_stream_session_t *s;
+ ngx_stream_conf_ctx_t *ctx;
ngx_stream_addr_conf_t *addr_conf;
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
@@ -121,9 +122,12 @@ ngx_stream_init_connection(ngx_connectio
return;
}

+ ctx = addr_conf->default_server->ctx;
+
s->signature = NGX_STREAM_MODULE;
- s->main_conf = addr_conf->ctx->main_conf;
- s->srv_conf = addr_conf->ctx->srv_conf;
+ s->main_conf = ctx->main_conf;
+ s->srv_conf = ctx->srv_conf;
+ s->virtual_names = addr_conf->virtual_names;

#if (NGX_STREAM_SSL)
s->ssl = addr_conf->ssl;
@@ -144,7 +148,7 @@ ngx_stream_init_connection(ngx_connectio

ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA %sclient %*s connected to %V",
c->number, c->type == SOCK_DGRAM ? "udp " : "",
- len, text, &addr_conf->addr_text);
+ len, text, &c->listening->addr_text);

c->log->connection = c->number;
c->log->handler = ngx_stream_log_error;
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -458,7 +458,104 @@ ngx_stream_ssl_handshake_handler(ngx_con
static int
ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
{
+ ngx_int_t rc;
+ ngx_str_t host;
+ const char *servername;
+ ngx_connection_t *c;
+ ngx_stream_session_t *s;
+ ngx_stream_ssl_conf_t *sscf;
+ ngx_stream_core_srv_conf_t *cscf;
+
+ c = ngx_ssl_get_connection(ssl_conn);
+
+ if (c->ssl->handshaked) {
+ *ad = SSL_AD_NO_RENEGOTIATION;
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ s = c->data;
+
+ servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name);
+
+ if (servername == NULL) {
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "SSL server name: null");
+ goto done;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "SSL server name: \"%s\"", servername);
+
+ host.len = ngx_strlen(servername);
+
+ if (host.len == 0) {
+ goto done;
+ }
+
+ host.data = (u_char *) servername;
+
+ rc = ngx_stream_validate_host(&host, c->pool, 1);
+
+ if (rc == NGX_ERROR) {
+ goto error;
+ }
+
+ if (rc == NGX_DECLINED) {
+ goto done;
+ }
+
+ rc = ngx_stream_find_virtual_server(s, &host, &cscf);
+
+ if (rc == NGX_ERROR) {
+ goto error;
+ }
+
+ if (rc == NGX_DECLINED) {
+ goto done;
+ }
+
+ s->srv_conf = cscf->ctx->srv_conf;
+
+ sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);
+
+ ngx_set_connection_log(c, cscf->error_log);
+
+ if (sscf->ssl.ctx) {
+ if (SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx) == NULL) {
+ goto error;
+ }
+
+ /*
+ * SSL_set_SSL_CTX() only changes certs as of 1.0.0d
+ * adjust other things we care about
+ */
+
+ SSL_set_verify(ssl_conn, SSL_CTX_get_verify_mode(sscf->ssl.ctx),
+ SSL_CTX_get_verify_callback(sscf->ssl.ctx));
+
+ SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx));
+
+#if OPENSSL_VERSION_NUMBER >= 0x009080dfL
+ /* only in 0.9.8m+ */
+ SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) &
+ ~SSL_CTX_get_options(sscf->ssl.ctx));
+#endif
+
+ SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx));
+
+#ifdef SSL_OP_NO_RENEGOTIATION
+ SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION);
+#endif
+ }
+
+done:
+
return SSL_TLSEXT_ERR_OK;
+
+error:
+
+ *ad = SSL_AD_INTERNAL_ERROR;
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}

#endif
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
@@ -33,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_servername(ngx_stream_session_t *s,
+ ngx_str_t *servername);
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(
@@ -187,6 +189,10 @@ ngx_stream_ssl_preread_handler(ngx_strea
return NGX_DECLINED;
}

+ if (rc == NGX_OK) {
+ return ngx_stream_ssl_preread_servername(s, &ctx->host);
+ }
+
if (rc != NGX_AGAIN) {
return rc;
}
@@ -404,9 +410,6 @@ ngx_stream_ssl_preread_parse_record(ngx_
case sw_sni_host:
ctx->host.len = (p[1] << 8) + p[2];

- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
- "ssl preread: SNI hostname \"%V\"", &ctx->host);
-
state = sw_ext;
dst = NULL;
size = ext;
@@ -497,6 +500,56 @@ ngx_stream_ssl_preread_parse_record(ngx_


static ngx_int_t
+ngx_stream_ssl_preread_servername(ngx_stream_session_t *s,
+ ngx_str_t *servername)
+{
+ ngx_int_t rc;
+ ngx_str_t host;
+ ngx_connection_t *c;
+ ngx_stream_core_srv_conf_t *cscf;
+
+ c = s->connection;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "SSL preread server name: \"%V\"", servername);
+
+ if (servername->len == 0) {
+ return NGX_OK;
+ }
+
+ host = *servername;
+
+ rc = ngx_stream_validate_host(&host, c->pool, 1);
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (rc == NGX_DECLINED) {
+ return NGX_OK;
+ }
+
+ rc = ngx_stream_find_virtual_server(s, &host, &cscf);
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (rc == NGX_DECLINED) {
+ return NGX_OK;
+ }
+
+ s->srv_conf = cscf->ctx->srv_conf;
+
+ cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);
+
+ ngx_set_connection_log(c, cscf->error_log);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s,
ngx_variable_value_t *v, uintptr_t data)
{
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
https://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH 0 of 3] Stream connection handling updates

Roman Arutyunyan 638 November 10, 2023 05:08AM

[PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 76 November 10, 2023 05:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 66 December 12, 2023 08:18AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 57 December 13, 2023 09:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 68 December 13, 2023 10:52AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 52 December 27, 2023 09:36AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 49 January 04, 2024 11:04AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 40 January 18, 2024 08:44AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Roman Arutyunyan 37 January 18, 2024 10:08AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 37 January 18, 2024 11:16AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Maxim Dounin 35 January 18, 2024 02:46PM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Sergey Kandaurov 37 January 19, 2024 06:44AM

Re: [PATCH 1 of 3] Stream: socket peek in preread phase

Maxim Dounin 49 January 19, 2024 03:28PM

[PATCH 2 of 3] Stream: virtual servers

Roman Arutyunyan 90 November 10, 2023 05:08AM

Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 58 December 13, 2023 08:42AM

Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 61 December 14, 2023 12:36PM

[PATCH 0 of 6] Re: [PATCH 2 of 3] Stream: virtual servers

Sergey Kandaurov 62 December 15, 2023 10:40AM

[PATCH 1 of 6] Stream: using ngx_stream_ssl_srv_conf_t *sscf naming convention

Sergey Kandaurov 66 December 15, 2023 10:40AM

Re: [PATCH 1 of 6] Stream: using ngx_stream_ssl_srv_conf_t *sscf naming convention

Roman Arutyunyan 46 January 08, 2024 08:32AM

[PATCH 2 of 6] Overhauled some diagnostic messages missed in 1b05b9bbcebf

Sergey Kandaurov 58 December 15, 2023 10:40AM

Re: [PATCH 2 of 6] Overhauled some diagnostic messages missed in 1b05b9bbcebf

Roman Arutyunyan 43 January 09, 2024 08:16AM

[PATCH 3 of 6] Stream: reshuffled ngx_stream_listen_opt_t fields

Sergey Kandaurov 70 December 15, 2023 10:40AM

Re: [PATCH 3 of 6] Stream: reshuffled ngx_stream_listen_opt_t fields

Roman Arutyunyan 42 January 09, 2024 08:18AM

[PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 57 December 15, 2023 10:40AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Roman Arutyunyan 46 January 09, 2024 10:40AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 34 January 18, 2024 09:52AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Roman Arutyunyan 38 January 18, 2024 10:26AM

Re: [PATCH 4 of 6] Stream: the "deferred" parameter of the "listen" directive

Sergey Kandaurov 41 January 18, 2024 11:22AM

[PATCH 5 of 6] Stream: the "accept_filter" parameter of the "listen" directive

Sergey Kandaurov 71 December 15, 2023 10:40AM

Re: [PATCH 5 of 6] Stream: the "accept_filter" parameter of the "listen" directive

Roman Arutyunyan 39 January 11, 2024 07:42AM

[PATCH 6 of 6] Stream: the "setfib" parameter of the "listen" directive

Sergey Kandaurov 59 December 15, 2023 10:42AM

Re: [PATCH 6 of 6] Stream: the "setfib" parameter of the "listen" directive

Roman Arutyunyan 50 January 11, 2024 07:46AM

[PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 82 November 10, 2023 05:08AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 56 December 13, 2023 10:46AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 77 December 15, 2023 10:48AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 37 February 13, 2024 05:48AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 40 February 21, 2024 08:38AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 30 February 28, 2024 05:18AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Roman Arutyunyan 32 February 28, 2024 09:24AM

Re: [PATCH 3 of 3] Stream: ngx_stream_pass_module

Sergey Kandaurov 45 February 29, 2024 06:40AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 89
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready