[PATCH 2 of 3] Stream: virtual servers
Roman Arutyunyan
arut at nginx.com
Thu Dec 14 06:22:24 UTC 2023
Hi,
On Wed, Dec 13, 2023 at 05:40:09PM +0400, Sergey Kandaurov wrote:
>
> > On 10 Nov 2023, at 14:07, Roman Arutyunyan <arut at nginx.com> wrote:
> >
> > # HG changeset patch
> > # User Roman Arutyunyan <arut at 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.
> >
>
> You may want to consider mentioning here about various
> directives introduced in this change, for the reference.
ok
> > 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;
>
> Nitpicking:
> virtual servers support is largely based on the existing code
> in http module, and we'd like to keep it as similar as possible
> to reduce maintenance costs. Still, it has subtle differences.
> For example, http has a different declaration order in a similar
> code for ngx_http_block(). As part of this change, you may want
> to re-align this in stream to how it's done in http, up to you.
>
> > 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;
>
> Here and below you renamed "stport" (as in "stream port") back to
> "hport" (as in "http port"), which apparently doesn't belong here.
>
> > + 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;
>
> Nitpicking.
> Current code has the following initialization order:
>
> 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];
>
> Besides "type", it makes sense to keep this order in the new code, as well:
>
> ls->handler = ngx_stream_init_connection;
>
> ls->pool_size = 256;
>
> cscf = addr->default_server;
>
> ls->logp = cscf->error_log;
>
> > +
> > + 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
>
> This part is out of scope of this change, and apparently it won't compile.
>
> > +
> > + 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
>
> This introduces accept_filter, deferred_accept, and setfib fields,
> which is out of scope of this change. Anyway, this is useless
> without corresponding support in ngx_stream_core_listen().
We need to catch up with all such missing functionality in Stream in future.
> > +#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
>
> Besides introducing unused fields, this part reshuffles
> backlog .. type fields without a reason. It can be as minimal as:
>
> 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,9 +45,8 @@ 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;
>
> > - 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;
>
> This field is now unused.
>
> > + 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 */
>
> misaligned to the right side (off by one)
>
> > +} 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);
>
> This deserves two blank lines to divide configuration and
> runtime functions, and somewhat similar to http.
>
> > 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);
>
> This deserves a blank line.
>
> > +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);
>
> Apparently, it makes sense to reverse-order these functions
> to make them appear in the order they are called.
>
> >
> >
> > 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;
> > +}
>
> Same here.
>
> > +
> > +
> > 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);
> > +
> > +
>
> extra blank line
>
> > 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)
>
> I don't think we should reintroduce "default" legacy in stream.
>
> > + {
> > + 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;
>
> Note that here and below, setting lsopt.set is missing.
> This renders unusable duplicate socket-level listen parameter
> checks in ngx_stream_add_addresses().
>
> Aside from that, there are several unimproved error messages in
> ngx_stream_core_listen() such as "bind ipv6only is not supported".
> They were fixed once in http in 1b05b9bbcebf, but similar fixes
> were missed in mail at the time. Then stream was based on mail,
> they reappeared there. It makes sense to fix them separately.
Yes, this will be a part of the cathup process later.
> > 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;
>
>
> Note that your change keeps sslcf->listen,
> checked in ngx_stream_core_merge_srv_conf().
>
> Currently, without virtual servers support, this is perfectly
> fine because if you didn't specify the listen ssl parameter,
> then no need to create ssl context and check/load certificates.
> With virtual servers support though, sslcf->listen makes harm,
> because you cannot specify non-default servers with ssl
> parameter, but without certificates, which is pretty valid:
>
> server {
> listen 127.0.0.1:8091 ssl;
> server_name foo;
> return FOO;
>
> ssl_certificate_key localhost.key;
> ssl_certificate localhost.crt;
> }
>
> server {
> listen 127.0.0.1:8091 ssl;
> server_name bar;
> return BAR;
> }
>
> nginx: [emerg] no "ssl_certificate" is defined for the "listen ... ssl" directive
>
> So it should be removed and replaced with appropriate certificate checks
> in ngx_stream_core_merge_srv_conf(). I propose to take the checks from
> ngx_http_core_merge_srv_conf(). Additionally, this will buy us the missing
> "ssl_reject_handshake" functionality, to selectively disable SSL handshakes
> in virtual servers based on SNI.
>
> >
> > 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;
>
> wrong indentation
>
> > +
> > + 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;
>
> Note that stream (as well as mail) consistently uses sslcf naming
> for keeping ssl configuration, unlike in http. Probably it makes
> sense for a separate sweeping change with renaming sslcf to sscf.
Agree. Also, it makes sense to rename ngx_stream_ssl_conf_t to
ngx_stream_ssl_srv_conf_t.
> > + 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);
>
> Looks like a copy-paste error from http, where connection log
> is set based on the location configuration.
> Here it just makes sense to move setting sscf closer to its use.
>
> > +
> > + 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:
> > +
>
> The reject_handshake functionality is missing there,
> it could be added in this change or separately
> (see below for a proposed addendum).
>
> > 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);
>
> The server configuration is already obtained in
> ngx_stream_find_virtual_server(), no need to do this again.
>
> > +
> > + 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)
> > {
>
> Together, this makes the following update on top of your change:
>
> 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
> @@ -92,7 +92,7 @@ static char *
> ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
> {
> char *rv;
> - ngx_uint_t m, mi, s;
> + ngx_uint_t mi, m, s;
> ngx_conf_t pcf;
> ngx_stream_module_t *module;
> ngx_stream_conf_ctx_t *ctx;
> @@ -918,7 +918,7 @@ ngx_stream_init_listening(ngx_conf_t *cf
> {
> ngx_uint_t i, last, bind_wildcard;
> ngx_listening_t *ls;
> - ngx_stream_port_t *hport;
> + ngx_stream_port_t *stport;
> ngx_stream_conf_addr_t *addr;
>
> addr = port->addrs.elts;
> @@ -953,26 +953,26 @@ ngx_stream_init_listening(ngx_conf_t *cf
> return NGX_ERROR;
> }
>
> - hport = ngx_pcalloc(cf->pool, sizeof(ngx_stream_port_t));
> - if (hport == NULL) {
> + stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t));
You lost "c" in ngx_pcalloc() for no apparent reason.
> + if (stport == NULL) {
> return NGX_ERROR;
> }
>
> - ls->servers = hport;
> + ls->servers = stport;
>
> - hport->naddrs = i + 1;
> + stport->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) {
> + if (ngx_stream_add_addrs6(cf, stport, addr) != NGX_OK) {
> return NGX_ERROR;
> }
> break;
> #endif
> default: /* AF_INET */
> - if (ngx_stream_add_addrs(cf, hport, addr) != NGX_OK) {
> + if (ngx_stream_add_addrs(cf, stport, addr) != NGX_OK) {
> return NGX_ERROR;
> }
> break;
> @@ -1001,26 +1001,14 @@ ngx_stream_add_listening(ngx_conf_t *cf,
>
> ls->handler = ngx_stream_init_connection;
>
> + ls->pool_size = 256;
> +
> 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;
> @@ -1033,22 +1021,10 @@ ngx_stream_add_listening(ngx_conf_t *cf,
> 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
> @@ -1064,7 +1040,7 @@ ngx_stream_add_listening(ngx_conf_t *cf,
>
>
> static ngx_int_t
> -ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *hport,
> +ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport,
> ngx_stream_conf_addr_t *addr)
> {
> ngx_uint_t i;
> @@ -1072,15 +1048,15 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx
> 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) {
> + stport->addrs = ngx_pcalloc(cf->pool,
> + stport->naddrs * sizeof(ngx_stream_in_addr_t));
> + if (stport->addrs == NULL) {
> return NGX_ERROR;
> }
>
> - addrs = hport->addrs;
> + addrs = stport->addrs;
>
> - for (i = 0; i < hport->naddrs; i++) {
> + for (i = 0; i < stport->naddrs; i++) {
>
> sin = (struct sockaddr_in *) addr[i].opt.sockaddr;
> addrs[i].addr = sin->sin_addr.s_addr;
> @@ -1126,7 +1102,7 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx
> #if (NGX_HAVE_INET6)
>
> static ngx_int_t
> -ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *hport,
> +ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport,
> ngx_stream_conf_addr_t *addr)
> {
> ngx_uint_t i;
> @@ -1134,15 +1110,15 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ng
> 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) {
> + stport->addrs = ngx_pcalloc(cf->pool,
> + stport->naddrs * sizeof(ngx_stream_in6_addr_t));
> + if (stport->addrs == NULL) {
> return NGX_ERROR;
> }
>
> - addrs6 = hport->addrs;
> + addrs6 = stport->addrs;
>
> - for (i = 0; i < hport->naddrs; i++) {
> + for (i = 0; i < stport->naddrs; i++) {
>
> sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr;
> addrs6[i].addr6 = sin6->sin6_addr;
> 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
> @@ -53,30 +53,21 @@ typedef struct {
> #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
> -
> -#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
> - char *accept_filter;
> + int backlog;
> + int rcvbuf;
> + int sndbuf;
> +#if (NGX_HAVE_TCP_FASTOPEN)
> + int fastopen;
> #endif
> + int type;
> } ngx_stream_listen_opt_t;
>
>
> @@ -198,7 +189,6 @@ typedef struct {
>
> ngx_stream_virtual_names_t *virtual_names;
>
> - ngx_str_t addr_text;
> unsigned ssl:1;
> unsigned proxy_protocol:1;
> } ngx_stream_addr_conf_t;
> @@ -254,7 +244,7 @@ typedef struct {
> /* 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 */
> + /* array of ngx_stream_core_srv_conf_t */
> } ngx_stream_conf_addr_t;
>
>
> @@ -350,6 +340,8 @@ typedef struct {
>
> ngx_int_t ngx_stream_add_listen(ngx_conf_t *cf,
> ngx_stream_core_srv_conf_t *cscf, ngx_stream_listen_opt_t *lsopt);
> +
> +
Not sure if two lines look good here. I'd leave just one like below.
> 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);
> @@ -357,11 +349,11 @@ 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_validate_host(ngx_str_t *host, ngx_pool_t *pool,
> + ngx_uint_t alloc);
> 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);
> void ngx_stream_session_handler(ngx_event_t *rev);
> 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
> @@ -437,57 +437,6 @@ 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;
> @@ -579,6 +528,57 @@ ngx_stream_validate_host(ngx_str_t *host
> }
>
>
> +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;
> +}
> +
> +
> static ngx_int_t
> ngx_stream_core_preconfiguration(ngx_conf_t *cf)
> {
> @@ -625,7 +625,6 @@ ngx_stream_core_init_main_conf(ngx_conf_
> cmcf->server_names_hash_bucket_size =
> ngx_align(cmcf->server_names_hash_bucket_size, ngx_cacheline_size);
>
> -
In HTTP we do have this empty line.
> ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
> ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);
>
> @@ -864,7 +863,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
>
> ngx_str_t *value, size;
> ngx_url_t u;
> - ngx_uint_t i, n, backlog;
> + ngx_uint_t n, i, backlog;
> ngx_stream_listen_opt_t lsopt;
>
> cscf->listen = 1;
> @@ -903,9 +902,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
>
> for (i = 2; i < cf->args->nelts; i++) {
>
> - if (ngx_strcmp(value[i].data, "default_server") == 0
> - || ngx_strcmp(value[i].data, "default") == 0)
> - {
> + if (ngx_strcmp(value[i].data, "default_server") == 0) {
> lsopt.default_server = 1;
> continue;
> }
> @@ -918,6 +915,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> #endif
>
> if (ngx_strcmp(value[i].data, "bind") == 0) {
> + lsopt.set = 1;
> lsopt.bind = 1;
> continue;
> }
> @@ -925,6 +923,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> #if (NGX_HAVE_TCP_FASTOPEN)
> if (ngx_strncmp(value[i].data, "fastopen=", 9) == 0) {
> lsopt.fastopen = ngx_atoi(value[i].data + 9, value[i].len - 9);
> + lsopt.set = 1;
> lsopt.bind = 1;
>
> if (lsopt.fastopen == NGX_ERROR) {
> @@ -939,6 +938,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
>
> if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
> lsopt.backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
> + lsopt.set = 1;
> lsopt.bind = 1;
>
> if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {
> @@ -957,6 +957,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> size.data = value[i].data + 7;
>
> lsopt.rcvbuf = ngx_parse_size(&size);
> + lsopt.set = 1;
> lsopt.bind = 1;
>
> if (lsopt.rcvbuf == NGX_ERROR) {
> @@ -973,6 +974,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> size.data = value[i].data + 7;
>
> lsopt.sndbuf = ngx_parse_size(&size);
> + lsopt.set = 1;
> lsopt.bind = 1;
>
> if (lsopt.sndbuf == NGX_ERROR) {
> @@ -999,11 +1001,13 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> return NGX_CONF_ERROR;
> }
>
> + lsopt.set = 1;
> lsopt.bind = 1;
> +
> continue;
> #else
> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> - "bind ipv6only is not supported "
> + "ipv6only is not supported "
Let's update text in a separate patch.
> "on this platform");
> return NGX_CONF_ERROR;
> #endif
> @@ -1012,6 +1016,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> if (ngx_strcmp(value[i].data, "reuseport") == 0) {
> #if (NGX_HAVE_REUSEPORT)
> lsopt.reuseport = 1;
> + lsopt.set = 1;
> lsopt.bind = 1;
> #else
> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> @@ -1023,17 +1028,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
>
> if (ngx_strcmp(value[i].data, "ssl") == 0) {
> #if (NGX_STREAM_SSL)
> - ngx_stream_ssl_conf_t *sslcf;
> -
> - sslcf = ngx_stream_conf_get_module_srv_conf(cf,
> - ngx_stream_ssl_module);
> -
> - sslcf->listen = 1;
> - sslcf->file = cf->conf_file->file.name.data;
> - sslcf->line = cf->conf_file->line;
> -
> lsopt.ssl = 1;
> -
> continue;
> #else
> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> @@ -1119,6 +1114,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> #endif
> }
>
> + lsopt.set = 1;
> lsopt.bind = 1;
>
> continue;
> @@ -1139,7 +1135,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
> }
>
> ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> - "the invalid \"%V\" parameter", &value[i]);
> + "invalid parameter \"%V\"", &value[i]);
Again, text change.
> return NGX_CONF_ERROR;
> }
>
> @@ -1202,9 +1198,9 @@ ngx_stream_core_server_name(ngx_conf_t *
> {
> ngx_stream_core_srv_conf_t *cscf = conf;
>
> - u_char ch;
> - ngx_str_t *value;
> - ngx_uint_t i;
> + u_char ch;
> + ngx_str_t *value;
> + ngx_uint_t i;
> ngx_stream_server_name_t *sn;
>
> value = cf->args->elts;
> 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
> @@ -219,6 +219,13 @@ static ngx_command_t ngx_stream_ssl_com
> offsetof(ngx_stream_ssl_conf_t, conf_commands),
> &ngx_stream_ssl_conf_command_post },
>
> + { ngx_string("ssl_reject_handshake"),
> + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
> + ngx_conf_set_flag_slot,
> + NGX_STREAM_SRV_CONF_OFFSET,
> + offsetof(ngx_stream_ssl_conf_t, reject_handshake),
> + NULL },
> +
> { ngx_string("ssl_alpn"),
> NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
> ngx_stream_ssl_alpn,
> @@ -463,7 +470,7 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t
> const char *servername;
> ngx_connection_t *c;
> ngx_stream_session_t *s;
> - ngx_stream_ssl_conf_t *sscf;
> + ngx_stream_ssl_conf_t *sslcf;
Why? I though, you like "sscf" more :)
I suggest that we use the better name "sscf" here.
> ngx_stream_core_srv_conf_t *cscf;
>
> c = ngx_ssl_get_connection(ssl_conn);
> @@ -516,12 +523,12 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t
>
> 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) {
> + sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);
> +
> + if (sslcf->ssl.ctx) {
> + if (SSL_set_SSL_CTX(ssl_conn, sslcf->ssl.ctx) == NULL) {
> goto error;
> }
>
> @@ -530,18 +537,19 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t
> * 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(ssl_conn, SSL_CTX_get_verify_mode(sslcf->ssl.ctx),
> + SSL_CTX_get_verify_callback(sslcf->ssl.ctx));
>
> - SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx));
> + SSL_set_verify_depth(ssl_conn,
> + SSL_CTX_get_verify_depth(sslcf->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));
> + ~SSL_CTX_get_options(sslcf->ssl.ctx));
> #endif
>
> - SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx));
> + SSL_set_options(ssl_conn, SSL_CTX_get_options(sslcf->ssl.ctx));
>
> #ifdef SSL_OP_NO_RENEGOTIATION
> SSL_set_options(ssl_conn, SSL_OP_NO_RENEGOTIATION);
> @@ -550,6 +558,14 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t
>
> done:
>
> + sslcf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);
> +
> + if (sslcf->reject_handshake) {
> + c->ssl->handshake_rejected = 1;
> + *ad = SSL_AD_UNRECOGNIZED_NAME;
> + return SSL_TLSEXT_ERR_ALERT_FATAL;
> + }
> +
> return SSL_TLSEXT_ERR_OK;
>
> error:
> @@ -752,7 +768,6 @@ ngx_stream_ssl_create_conf(ngx_conf_t *c
> /*
> * set by ngx_pcalloc():
> *
> - * scf->listen = 0;
> * scf->protocols = 0;
> * scf->certificate_values = NULL;
> * scf->dhparam = { 0, NULL };
> @@ -771,6 +786,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *c
> scf->passwords = NGX_CONF_UNSET_PTR;
> scf->conf_commands = NGX_CONF_UNSET_PTR;
> scf->prefer_server_ciphers = NGX_CONF_UNSET;
> + scf->reject_handshake = NGX_CONF_UNSET;
> scf->verify = NGX_CONF_UNSET_UINT;
> scf->verify_depth = NGX_CONF_UNSET_UINT;
> scf->builtin_session_cache = NGX_CONF_UNSET;
> @@ -799,6 +815,8 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
> ngx_conf_merge_value(conf->prefer_server_ciphers,
> prev->prefer_server_ciphers, 0);
>
> + ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0);
> +
> ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
> (NGX_CONF_BITMASK_SET
> |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
> @@ -832,35 +850,21 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
>
> conf->ssl.log = cf->log;
>
> - if (!conf->listen) {
> - return NGX_CONF_OK;
> - }
> -
> - if (conf->certificates == NULL) {
> - ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
> - "no \"ssl_certificate\" is defined for "
> - "the \"listen ... ssl\" directive in %s:%ui",
> - conf->file, conf->line);
> - return NGX_CONF_ERROR;
> - }
> + if (conf->certificates) {
>
> - if (conf->certificate_keys == NULL) {
> - ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
> - "no \"ssl_certificate_key\" is defined for "
> - "the \"listen ... ssl\" directive in %s:%ui",
> - conf->file, conf->line);
> - return NGX_CONF_ERROR;
> - }
> + if (conf->certificate_keys == NULL
> + || conf->certificate_keys->nelts < conf->certificates->nelts)
> + {
> + ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
> + "no \"ssl_certificate_key\" is defined "
> + "for certificate \"%V\"",
> + ((ngx_str_t *) conf->certificates->elts)
> + + conf->certificates->nelts - 1);
> + return NGX_CONF_ERROR;
> + }
>
> - if (conf->certificate_keys->nelts < conf->certificates->nelts) {
> - ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
> - "no \"ssl_certificate_key\" is defined "
> - "for certificate \"%V\" and "
> - "the \"listen ... ssl\" directive in %s:%ui",
> - ((ngx_str_t *) conf->certificates->elts)
> - + conf->certificates->nelts - 1,
> - conf->file, conf->line);
> - return NGX_CONF_ERROR;
> + } else if (!conf->reject_handshake) {
> + return NGX_CONF_OK;
> }
>
> if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
> @@ -915,7 +919,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
> return NGX_CONF_ERROR;
> #endif
>
> - } else {
> + } else if (conf->certificates) {
>
> /* configure certificates */
>
> @@ -1014,6 +1018,10 @@ ngx_stream_ssl_compile_certificates(ngx_
> ngx_stream_complex_value_t *cv;
> ngx_stream_compile_complex_value_t ccv;
>
> + if (conf->certificates == NULL) {
> + return NGX_OK;
> + }
> +
> cert = conf->certificates->elts;
> key = conf->certificate_keys->elts;
> nelts = conf->certificates->nelts;
> @@ -1292,8 +1300,13 @@ ngx_stream_ssl_conf_command_check(ngx_co
> static ngx_int_t
> ngx_stream_ssl_init(ngx_conf_t *cf)
> {
> - ngx_stream_handler_pt *h;
> - ngx_stream_core_main_conf_t *cmcf;
> + ngx_uint_t a, p, s;
> + ngx_stream_handler_pt *h;
> + ngx_stream_ssl_conf_t *sslcf;
Again, let's use sscf here. This way the diff to http is smaller.
> + ngx_stream_conf_addr_t *addr;
> + ngx_stream_conf_port_t *port;
> + ngx_stream_core_srv_conf_t **cscfp, *cscf;
> + ngx_stream_core_main_conf_t *cmcf;
>
> cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
>
> @@ -1304,5 +1317,58 @@ ngx_stream_ssl_init(ngx_conf_t *cf)
>
> *h = ngx_stream_ssl_handler;
>
> + if (cmcf->ports == NULL) {
> + return NGX_OK;
> + }
> +
> + port = cmcf->ports->elts;
> + for (p = 0; p < cmcf->ports->nelts; p++) {
> +
> + addr = port[p].addrs.elts;
> + for (a = 0; a < port[p].addrs.nelts; a++) {
> +
> + if (!addr[a].opt.ssl) {
> + continue;
> + }
> +
> + cscf = addr[a].default_server;
> + sslcf = cscf->ctx->srv_conf[ngx_stream_ssl_module.ctx_index];
> +
> + if (sslcf->certificates) {
> + continue;
> + }
> +
> + if (!sslcf->reject_handshake) {
> + ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
> + "no \"ssl_certificate\" is defined for "
> + "the \"listen ... ssl\" directive in %s:%ui",
> + cscf->file_name, cscf->line);
> + return NGX_ERROR;
> + }
> +
> + /*
> + * if no certificates are defined in the default server,
> + * check all non-default server blocks
> + */
> +
> + cscfp = addr[a].servers.elts;
> + for (s = 0; s < addr[a].servers.nelts; s++) {
> +
> + cscf = cscfp[s];
> + sslcf = cscf->ctx->srv_conf[ngx_stream_ssl_module.ctx_index];
> +
> + if (sslcf->certificates || sslcf->reject_handshake) {
> + continue;
> + }
> +
> + ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
> + "no \"ssl_certificate\" is defined for "
> + "the \"listen ... ssl\" directive in %s:%ui",
> + cscf->file_name, cscf->line);
> + return NGX_ERROR;
> + }
> + }
> + }
> +
> return NGX_OK;
> }
> diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h
> --- a/src/stream/ngx_stream_ssl_module.h
> +++ b/src/stream/ngx_stream_ssl_module.h
> @@ -18,10 +18,10 @@ typedef struct {
> ngx_msec_t handshake_timeout;
>
> ngx_flag_t prefer_server_ciphers;
> + ngx_flag_t reject_handshake;
>
> ngx_ssl_t ssl;
>
> - ngx_uint_t listen;
> ngx_uint_t protocols;
>
> ngx_uint_t verify;
> @@ -53,9 +53,6 @@ typedef struct {
>
> ngx_flag_t session_tickets;
> ngx_array_t *session_ticket_keys;
> -
> - u_char *file;
> - ngx_uint_t line;
> } ngx_stream_ssl_conf_t;
>
>
> 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
> @@ -541,8 +541,6 @@ ngx_stream_ssl_preread_servername(ngx_st
>
> 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;
>
> --
> Sergey Kandaurov
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> https://mailman.nginx.org/mailman/listinfo/nginx-devel
New patch attached.
--
Roman Arutyunyan
-------------- next part --------------
# HG changeset patch
# User Roman Arutyunyan <arut at nginx.com>
# Date 1702532489 -14400
# Thu Dec 14 09:41:29 2023 +0400
# Node ID a390e18b664e7ba678417ef6e40d94c37e89c2f7
# Parent 844486cdd43a32d10b78493d7e7b80e9e2239d7e
Stream: virtual servers.
Server name is taken either from ngx_stream_ssl_module or
ngx_stream_ssl_preread_module.
The change adds "default" parameter to the "listen" directive, as well as the
following directives: "server_names_hash_max_size",
"server_names_hash_bucket_size", "server_name" and "ssl_reject_handshake".
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 mi, m, 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,265 @@ 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 *stport;
+ 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;
+ }
+
+ stport = ngx_pcalloc(cf->pool, sizeof(ngx_stream_port_t));
+ if (stport == NULL) {
+ return NGX_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_ERROR;
+ }
+ break;
+#endif
+ default: /* AF_INET */
+ if (ngx_stream_add_addrs(cf, stport, 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;
+
+ ls->pool_size = 256;
+
+ cscf = addr->default_server;
+
+ ls->logp = cscf->error_log;
+ ls->log.data = &ls->addr_text;
+ ls->log.handler = ngx_accept_log_error;
+
+ 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_INET6)
+ ls->ipv6only = addr->opt.ipv6only;
+#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 *stport,
+ 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;
+
+ 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.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 *stport,
+ 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;
+
+ stport->addrs = ngx_pcalloc(cf->pool,
+ stport->naddrs * sizeof(ngx_stream_in6_addr_t));
+ if (stport->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ addrs6 = stport->addrs;
+
+ for (i = 0; i < stport->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,9 +45,8 @@ 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;
@@ -69,50 +68,7 @@ typedef struct {
int fastopen;
#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 +109,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 +118,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 +143,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 +156,98 @@ 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;
+
+ 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 +263,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 +338,9 @@ 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);
@@ -291,6 +349,10 @@ ngx_int_t ngx_stream_core_preread_phase(
ngx_int_t ngx_stream_core_content_phase(ngx_stream_session_t *s,
ngx_stream_phase_handler_t *ph);
+ngx_int_t ngx_stream_validate_host(ngx_str_t *host, ngx_pool_t *pool,
+ ngx_uint_t alloc);
+ngx_int_t ngx_stream_find_virtual_server(ngx_stream_session_t *s,
+ ngx_str_t *host, ngx_stream_core_srv_conf_t **cscfp);
void ngx_stream_init_connection(ngx_connection_t *c);
void ngx_stream_session_handler(ngx_event_t *rev);
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,
@@ -418,6 +441,149 @@ ngx_stream_core_content_phase(ngx_stream
}
+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;
+}
+
+
+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;
+}
+
+
static ngx_int_t
ngx_stream_core_preconfiguration(ngx_conf_t *cf)
{
@@ -442,11 +608,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;
@@ -460,6 +623,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);
@@ -491,6 +662,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;
@@ -509,6 +687,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);
@@ -556,6 +737,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;
}
@@ -655,11 +867,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 n, i, backlog;
+ ngx_stream_listen_opt_t lsopt;
cscf->listen = 1;
@@ -680,51 +891,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) {
+ 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.set = 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.set = 1;
+ 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;
@@ -735,10 +943,11 @@ 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.set = 1;
+ 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;
@@ -753,10 +962,11 @@ 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.set = 1;
+ 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;
@@ -769,10 +979,11 @@ 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.set = 1;
+ 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;
@@ -784,10 +995,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,
@@ -796,7 +1007,9 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
return NGX_CONF_ERROR;
}
- ls->bind = 1;
+ lsopt.set = 1;
+ lsopt.bind = 1;
+
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -808,8 +1021,9 @@ 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.set = 1;
+ lsopt.bind = 1;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"reuseport is not supported "
@@ -820,17 +1034,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
if (ngx_strcmp(value[i].data, "ssl") == 0) {
#if (NGX_STREAM_SSL)
- ngx_stream_ssl_conf_t *sslcf;
-
- sslcf = ngx_stream_conf_get_module_srv_conf(cf,
- ngx_stream_ssl_module);
-
- sslcf->listen = 1;
- sslcf->file = cf->conf_file->file.name.data;
- sslcf->line = cf->conf_file->line;
-
- ls->ssl = 1;
-
+ lsopt.ssl = 1;
continue;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -843,10 +1047,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 {
@@ -865,8 +1069,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;
}
}
@@ -881,8 +1085,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;
}
}
@@ -892,19 +1096,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
@@ -916,7 +1120,8 @@ ngx_stream_core_listen(ngx_conf_t *cf, n
#endif
}
- ls->bind = 1;
+ lsopt.set = 1;
+ lsopt.bind = 1;
continue;
@@ -931,7 +1136,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;
}
@@ -940,27 +1145,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
@@ -977,40 +1182,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;
}
@@ -1023,6 +1200,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
@@ -219,6 +219,13 @@ static ngx_command_t ngx_stream_ssl_com
offsetof(ngx_stream_ssl_conf_t, conf_commands),
&ngx_stream_ssl_conf_command_post },
+ { ngx_string("ssl_reject_handshake"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_ssl_conf_t, reject_handshake),
+ NULL },
+
{ ngx_string("ssl_alpn"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
ngx_stream_ssl_alpn,
@@ -458,7 +465,112 @@ 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;
+
+ ngx_set_connection_log(c, cscf->error_log);
+
+ sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);
+
+ 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:
+
+ sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);
+
+ if (sscf->reject_handshake) {
+ c->ssl->handshake_rejected = 1;
+ *ad = SSL_AD_UNRECOGNIZED_NAME;
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
return SSL_TLSEXT_ERR_OK;
+
+error:
+
+ *ad = SSL_AD_INTERNAL_ERROR;
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
}
#endif
@@ -655,7 +767,6 @@ ngx_stream_ssl_create_conf(ngx_conf_t *c
/*
* set by ngx_pcalloc():
*
- * scf->listen = 0;
* scf->protocols = 0;
* scf->certificate_values = NULL;
* scf->dhparam = { 0, NULL };
@@ -674,6 +785,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *c
scf->passwords = NGX_CONF_UNSET_PTR;
scf->conf_commands = NGX_CONF_UNSET_PTR;
scf->prefer_server_ciphers = NGX_CONF_UNSET;
+ scf->reject_handshake = NGX_CONF_UNSET;
scf->verify = NGX_CONF_UNSET_UINT;
scf->verify_depth = NGX_CONF_UNSET_UINT;
scf->builtin_session_cache = NGX_CONF_UNSET;
@@ -702,6 +814,8 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
ngx_conf_merge_value(conf->prefer_server_ciphers,
prev->prefer_server_ciphers, 0);
+ ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0);
+
ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
@@ -735,35 +849,21 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
conf->ssl.log = cf->log;
- if (!conf->listen) {
- return NGX_CONF_OK;
- }
-
- if (conf->certificates == NULL) {
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "no \"ssl_certificate\" is defined for "
- "the \"listen ... ssl\" directive in %s:%ui",
- conf->file, conf->line);
- return NGX_CONF_ERROR;
- }
+ if (conf->certificates) {
- if (conf->certificate_keys == NULL) {
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "no \"ssl_certificate_key\" is defined for "
- "the \"listen ... ssl\" directive in %s:%ui",
- conf->file, conf->line);
- return NGX_CONF_ERROR;
- }
+ if (conf->certificate_keys == NULL
+ || conf->certificate_keys->nelts < conf->certificates->nelts)
+ {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate_key\" is defined "
+ "for certificate \"%V\"",
+ ((ngx_str_t *) conf->certificates->elts)
+ + conf->certificates->nelts - 1);
+ return NGX_CONF_ERROR;
+ }
- if (conf->certificate_keys->nelts < conf->certificates->nelts) {
- ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "no \"ssl_certificate_key\" is defined "
- "for certificate \"%V\" and "
- "the \"listen ... ssl\" directive in %s:%ui",
- ((ngx_str_t *) conf->certificates->elts)
- + conf->certificates->nelts - 1,
- conf->file, conf->line);
- return NGX_CONF_ERROR;
+ } else if (!conf->reject_handshake) {
+ return NGX_CONF_OK;
}
if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
@@ -818,7 +918,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
return NGX_CONF_ERROR;
#endif
- } else {
+ } else if (conf->certificates) {
/* configure certificates */
@@ -917,6 +1017,10 @@ ngx_stream_ssl_compile_certificates(ngx_
ngx_stream_complex_value_t *cv;
ngx_stream_compile_complex_value_t ccv;
+ if (conf->certificates == NULL) {
+ return NGX_OK;
+ }
+
cert = conf->certificates->elts;
key = conf->certificate_keys->elts;
nelts = conf->certificates->nelts;
@@ -1195,8 +1299,13 @@ ngx_stream_ssl_conf_command_check(ngx_co
static ngx_int_t
ngx_stream_ssl_init(ngx_conf_t *cf)
{
- ngx_stream_handler_pt *h;
- ngx_stream_core_main_conf_t *cmcf;
+ ngx_uint_t a, p, s;
+ ngx_stream_handler_pt *h;
+ ngx_stream_ssl_conf_t *sscf;
+ ngx_stream_conf_addr_t *addr;
+ ngx_stream_conf_port_t *port;
+ ngx_stream_core_srv_conf_t **cscfp, *cscf;
+ ngx_stream_core_main_conf_t *cmcf;
cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
@@ -1207,5 +1316,58 @@ ngx_stream_ssl_init(ngx_conf_t *cf)
*h = ngx_stream_ssl_handler;
+ if (cmcf->ports == NULL) {
+ return NGX_OK;
+ }
+
+ port = cmcf->ports->elts;
+ for (p = 0; p < cmcf->ports->nelts; p++) {
+
+ addr = port[p].addrs.elts;
+ for (a = 0; a < port[p].addrs.nelts; a++) {
+
+ if (!addr[a].opt.ssl) {
+ continue;
+ }
+
+ cscf = addr[a].default_server;
+ sscf = cscf->ctx->srv_conf[ngx_stream_ssl_module.ctx_index];
+
+ if (sscf->certificates) {
+ continue;
+ }
+
+ if (!sscf->reject_handshake) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate\" is defined for "
+ "the \"listen ... ssl\" directive in %s:%ui",
+ cscf->file_name, cscf->line);
+ return NGX_ERROR;
+ }
+
+ /*
+ * if no certificates are defined in the default server,
+ * check all non-default server blocks
+ */
+
+ cscfp = addr[a].servers.elts;
+ for (s = 0; s < addr[a].servers.nelts; s++) {
+
+ cscf = cscfp[s];
+ sscf = cscf->ctx->srv_conf[ngx_stream_ssl_module.ctx_index];
+
+ if (sscf->certificates || sscf->reject_handshake) {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"ssl_certificate\" is defined for "
+ "the \"listen ... ssl\" directive in %s:%ui",
+ cscf->file_name, cscf->line);
+ return NGX_ERROR;
+ }
+ }
+ }
+
return NGX_OK;
}
diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h
--- a/src/stream/ngx_stream_ssl_module.h
+++ b/src/stream/ngx_stream_ssl_module.h
@@ -18,10 +18,10 @@ typedef struct {
ngx_msec_t handshake_timeout;
ngx_flag_t prefer_server_ciphers;
+ ngx_flag_t reject_handshake;
ngx_ssl_t ssl;
- ngx_uint_t listen;
ngx_uint_t protocols;
ngx_uint_t verify;
@@ -53,9 +53,6 @@ typedef struct {
ngx_flag_t session_tickets;
ngx_array_t *session_ticket_keys;
-
- u_char *file;
- ngx_uint_t line;
} ngx_stream_ssl_conf_t;
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,54 @@ 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;
+
+ 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)
{
More information about the nginx-devel
mailing list