summaryrefslogtreecommitdiff
path: root/src/stream
diff options
context:
space:
mode:
Diffstat (limited to 'src/stream')
-rw-r--r--src/stream/ngx_stream.c89
-rw-r--r--src/stream/ngx_stream.h38
-rw-r--r--src/stream/ngx_stream_access_module.c451
-rw-r--r--src/stream/ngx_stream_core_module.c30
-rw-r--r--src/stream/ngx_stream_handler.c37
-rw-r--r--src/stream/ngx_stream_proxy_module.c178
-rw-r--r--src/stream/ngx_stream_ssl_module.c2
-rw-r--r--src/stream/ngx_stream_upstream.c2
-rw-r--r--src/stream/ngx_stream_upstream.h2
-rw-r--r--src/stream/ngx_stream_upstream_hash_module.c2
-rw-r--r--src/stream/ngx_stream_upstream_least_conn_module.c2
-rw-r--r--src/stream/ngx_stream_upstream_zone_module.c2
12 files changed, 754 insertions, 81 deletions
diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c
index 1c5e7a87c..3dce35ab7 100644
--- a/src/stream/ngx_stream.c
+++ b/src/stream/ngx_stream.c
@@ -204,6 +204,20 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
}
+ for (m = 0; ngx_modules[m]; m++) {
+ if (ngx_modules[m]->type != NGX_STREAM_MODULE) {
+ continue;
+ }
+
+ module = ngx_modules[m]->ctx;
+
+ if (module->postconfiguration) {
+ if (module->postconfiguration(cf) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+ }
+
*cf = pcf;
@@ -239,13 +253,13 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
struct sockaddr_in6 *sin6;
#endif
- sa = (struct sockaddr *) &listen->sockaddr;
+ sa = &listen->u.sockaddr;
switch (sa->sa_family) {
#if (NGX_HAVE_INET6)
case AF_INET6:
- sin6 = (struct sockaddr_in6 *) sa;
+ sin6 = &listen->u.sockaddr_in6;
p = sin6->sin6_port;
break;
#endif
@@ -257,7 +271,7 @@ ngx_stream_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
#endif
default: /* AF_INET */
- sin = (struct sockaddr_in *) sa;
+ sin = &listen->u.sockaddr_in;
p = sin->sin_port;
break;
}
@@ -297,23 +311,7 @@ found:
return NGX_ERROR;
}
- addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
- addr->socklen = listen->socklen;
- addr->ctx = listen->ctx;
- addr->bind = listen->bind;
- addr->wildcard = listen->wildcard;
- addr->so_keepalive = listen->so_keepalive;
-#if (NGX_HAVE_KEEPALIVE_TUNABLE)
- addr->tcp_keepidle = listen->tcp_keepidle;
- addr->tcp_keepintvl = listen->tcp_keepintvl;
- addr->tcp_keepcnt = listen->tcp_keepcnt;
-#endif
-#if (NGX_STREAM_SSL)
- addr->ssl = listen->ssl;
-#endif
-#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
- addr->ipv6only = listen->ipv6only;
-#endif
+ addr->opt = *listen;
return NGX_OK;
}
@@ -343,8 +341,8 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
* to the "*:port" only and ignore the other bindings
*/
- if (addr[last - 1].wildcard) {
- addr[last - 1].bind = 1;
+ if (addr[last - 1].opt.wildcard) {
+ addr[last - 1].opt.bind = 1;
bind_wildcard = 1;
} else {
@@ -355,12 +353,13 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
while (i < last) {
- if (bind_wildcard && !addr[i].bind) {
+ if (bind_wildcard && !addr[i].opt.bind) {
i++;
continue;
}
- ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
+ ls = ngx_create_listening(cf, &addr[i].opt.u.sockaddr,
+ addr[i].opt.socklen);
if (ls == NULL) {
return NGX_CONF_ERROR;
}
@@ -369,21 +368,27 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
ls->handler = ngx_stream_init_connection;
ls->pool_size = 256;
- cscf = addr->ctx->srv_conf[ngx_stream_core_module.ctx_index];
+ 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->keepalive = addr[i].so_keepalive;
+ ls->backlog = addr[i].opt.backlog;
+
+ ls->keepalive = addr[i].opt.so_keepalive;
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
- ls->keepidle = addr[i].tcp_keepidle;
- ls->keepintvl = addr[i].tcp_keepintvl;
- ls->keepcnt = addr[i].tcp_keepcnt;
+ 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 && defined IPV6_V6ONLY)
- ls->ipv6only = addr[i].ipv6only;
+ ls->ipv6only = addr[i].opt.ipv6only;
+#endif
+
+#if (NGX_HAVE_REUSEPORT)
+ ls->reuseport = addr[i].opt.reuseport;
#endif
stport = ngx_palloc(cf->pool, sizeof(ngx_stream_port_t));
@@ -444,15 +449,15 @@ ngx_stream_add_addrs(ngx_conf_t *cf, ngx_stream_port_t *stport,
for (i = 0; i < stport->naddrs; i++) {
- sin = (struct sockaddr_in *) addr[i].sockaddr;
+ sin = &addr[i].opt.u.sockaddr_in;
addrs[i].addr = sin->sin_addr.s_addr;
- addrs[i].conf.ctx = addr[i].ctx;
+ addrs[i].conf.ctx = addr[i].opt.ctx;
#if (NGX_STREAM_SSL)
- addrs[i].conf.ssl = addr[i].ssl;
+ addrs[i].conf.ssl = addr[i].opt.ssl;
#endif
- len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf,
+ len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf,
NGX_SOCKADDR_STRLEN, 1);
p = ngx_pnalloc(cf->pool, len);
@@ -493,15 +498,15 @@ ngx_stream_add_addrs6(ngx_conf_t *cf, ngx_stream_port_t *stport,
for (i = 0; i < stport->naddrs; i++) {
- sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
+ sin6 = &addr[i].opt.u.sockaddr_in6;
addrs6[i].addr6 = sin6->sin6_addr;
- addrs6[i].conf.ctx = addr[i].ctx;
+ addrs6[i].conf.ctx = addr[i].opt.ctx;
#if (NGX_STREAM_SSL)
- addrs6[i].conf.ssl = addr[i].ssl;
+ addrs6[i].conf.ssl = addr[i].opt.ssl;
#endif
- len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf,
+ len = ngx_sock_ntop(&addr[i].opt.u.sockaddr, addr[i].opt.socklen, buf,
NGX_SOCKADDR_STRLEN, 1);
p = ngx_pnalloc(cf->pool, len);
@@ -529,22 +534,22 @@ ngx_stream_cmp_conf_addrs(const void *one, const void *two)
first = (ngx_stream_conf_addr_t *) one;
second = (ngx_stream_conf_addr_t *) two;
- if (first->wildcard) {
+ if (first->opt.wildcard) {
/* a wildcard must be the last resort, shift it to the end */
return 1;
}
- if (second->wildcard) {
+ if (second->opt.wildcard) {
/* a wildcard must be the last resort, shift it to the end */
return -1;
}
- if (first->bind && !second->bind) {
+ if (first->opt.bind && !second->opt.bind) {
/* shift explicit bind()ed addresses to the start */
return -1;
}
- if (!first->bind && second->bind) {
+ if (!first->opt.bind && second->opt.bind) {
/* shift explicit bind()ed addresses to the start */
return 1;
}
diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h
index a10f68fff..b0eb7d4e5 100644
--- a/src/stream/ngx_stream.h
+++ b/src/stream/ngx_stream.h
@@ -31,7 +31,18 @@ typedef struct {
typedef struct {
- u_char sockaddr[NGX_SOCKADDRLEN];
+ union {
+ struct sockaddr sockaddr;
+ struct sockaddr_in sockaddr_in;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 sockaddr_in6;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ struct sockaddr_un sockaddr_un;
+#endif
+ u_char sockaddr_data[NGX_SOCKADDRLEN];
+ } u;
+
socklen_t socklen;
/* server ctx */
@@ -54,6 +65,7 @@ typedef struct {
int tcp_keepintvl;
int tcp_keepcnt;
#endif
+ int backlog;
} ngx_stream_listen_t;
@@ -96,31 +108,17 @@ typedef struct {
typedef struct {
- struct sockaddr *sockaddr;
- socklen_t socklen;
+ ngx_stream_listen_t opt;
+} ngx_stream_conf_addr_t;
- ngx_stream_conf_ctx_t *ctx;
- unsigned bind:1;
- unsigned wildcard:1;
-#if (NGX_STREAM_SSL)
- unsigned ssl:1;
-#endif
-#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
- unsigned ipv6only:1;
-#endif
- unsigned so_keepalive:2;
-#if (NGX_HAVE_KEEPALIVE_TUNABLE)
- int tcp_keepidle;
- int tcp_keepintvl;
- int tcp_keepcnt;
-#endif
-} ngx_stream_conf_addr_t;
+typedef ngx_int_t (*ngx_stream_access_pt)(ngx_stream_session_t *s);
typedef struct {
ngx_array_t servers; /* ngx_stream_core_srv_conf_t */
ngx_array_t listen; /* ngx_stream_listen_t */
+ ngx_stream_access_pt access_handler;
} ngx_stream_core_main_conf_t;
@@ -154,6 +152,8 @@ struct ngx_stream_session_s {
typedef struct {
+ ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
+
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
diff --git a/src/stream/ngx_stream_access_module.c b/src/stream/ngx_stream_access_module.c
new file mode 100644
index 000000000..64869d230
--- /dev/null
+++ b/src/stream/ngx_stream_access_module.c
@@ -0,0 +1,451 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_stream.h>
+
+
+typedef struct {
+ in_addr_t mask;
+ in_addr_t addr;
+ ngx_uint_t deny; /* unsigned deny:1; */
+} ngx_stream_access_rule_t;
+
+#if (NGX_HAVE_INET6)
+
+typedef struct {
+ struct in6_addr addr;
+ struct in6_addr mask;
+ ngx_uint_t deny; /* unsigned deny:1; */
+} ngx_stream_access_rule6_t;
+
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+typedef struct {
+ ngx_uint_t deny; /* unsigned deny:1; */
+} ngx_stream_access_rule_un_t;
+
+#endif
+
+typedef struct {
+ ngx_array_t *rules; /* array of ngx_stream_access_rule_t */
+#if (NGX_HAVE_INET6)
+ ngx_array_t *rules6; /* array of ngx_stream_access_rule6_t */
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ ngx_array_t *rules_un; /* array of ngx_stream_access_rule_un_t */
+#endif
+} ngx_stream_access_srv_conf_t;
+
+
+static ngx_int_t ngx_stream_access_handler(ngx_stream_session_t *s);
+static ngx_int_t ngx_stream_access_inet(ngx_stream_session_t *s,
+ ngx_stream_access_srv_conf_t *ascf, in_addr_t addr);
+#if (NGX_HAVE_INET6)
+static ngx_int_t ngx_stream_access_inet6(ngx_stream_session_t *s,
+ ngx_stream_access_srv_conf_t *ascf, u_char *p);
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+static ngx_int_t ngx_stream_access_unix(ngx_stream_session_t *s,
+ ngx_stream_access_srv_conf_t *ascf);
+#endif
+static ngx_int_t ngx_stream_access_found(ngx_stream_session_t *s,
+ ngx_uint_t deny);
+static char *ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static void *ngx_stream_access_create_srv_conf(ngx_conf_t *cf);
+static char *ngx_stream_access_merge_srv_conf(ngx_conf_t *cf,
+ void *parent, void *child);
+static ngx_int_t ngx_stream_access_init(ngx_conf_t *cf);
+
+
+static ngx_command_t ngx_stream_access_commands[] = {
+
+ { ngx_string("allow"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_stream_access_rule,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("deny"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_stream_access_rule,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+
+static ngx_stream_module_t ngx_stream_access_module_ctx = {
+ ngx_stream_access_init, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ ngx_stream_access_create_srv_conf, /* create server configuration */
+ ngx_stream_access_merge_srv_conf /* merge server configuration */
+};
+
+
+ngx_module_t ngx_stream_access_module = {
+ NGX_MODULE_V1,
+ &ngx_stream_access_module_ctx, /* module context */
+ ngx_stream_access_commands, /* module directives */
+ NGX_STREAM_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_stream_access_handler(ngx_stream_session_t *s)
+{
+ struct sockaddr_in *sin;
+ ngx_stream_access_srv_conf_t *ascf;
+#if (NGX_HAVE_INET6)
+ u_char *p;
+ in_addr_t addr;
+ struct sockaddr_in6 *sin6;
+#endif
+
+ ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_access_module);
+
+ switch (s->connection->sockaddr->sa_family) {
+
+ case AF_INET:
+ if (ascf->rules) {
+ sin = (struct sockaddr_in *) s->connection->sockaddr;
+ return ngx_stream_access_inet(s, ascf, sin->sin_addr.s_addr);
+ }
+ break;
+
+#if (NGX_HAVE_INET6)
+
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;
+ p = sin6->sin6_addr.s6_addr;
+
+ if (ascf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ addr = p[12] << 24;
+ addr += p[13] << 16;
+ addr += p[14] << 8;
+ addr += p[15];
+ return ngx_stream_access_inet(s, ascf, htonl(addr));
+ }
+
+ if (ascf->rules6) {
+ return ngx_stream_access_inet6(s, ascf, p);
+ }
+
+ break;
+
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ case AF_UNIX:
+ if (ascf->rules_un) {
+ return ngx_stream_access_unix(s, ascf);
+ }
+
+ break;
+
+#endif
+ }
+
+ return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_stream_access_inet(ngx_stream_session_t *s,
+ ngx_stream_access_srv_conf_t *ascf, in_addr_t addr)
+{
+ ngx_uint_t i;
+ ngx_stream_access_rule_t *rule;
+
+ rule = ascf->rules->elts;
+ for (i = 0; i < ascf->rules->nelts; i++) {
+
+ ngx_log_debug3(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
+ "access: %08XD %08XD %08XD",
+ addr, rule[i].mask, rule[i].addr);
+
+ if ((addr & rule[i].mask) == rule[i].addr) {
+ return ngx_stream_access_found(s, rule[i].deny);
+ }
+ }
+
+ return NGX_DECLINED;
+}
+
+
+#if (NGX_HAVE_INET6)
+
+static ngx_int_t
+ngx_stream_access_inet6(ngx_stream_session_t *s,
+ ngx_stream_access_srv_conf_t *ascf, u_char *p)
+{
+ ngx_uint_t n;
+ ngx_uint_t i;
+ ngx_stream_access_rule6_t *rule6;
+
+ rule6 = ascf->rules6->elts;
+ for (i = 0; i < ascf->rules6->nelts; i++) {
+
+#if (NGX_DEBUG)
+ {
+ size_t cl, ml, al;
+ u_char ct[NGX_INET6_ADDRSTRLEN];
+ u_char mt[NGX_INET6_ADDRSTRLEN];
+ u_char at[NGX_INET6_ADDRSTRLEN];
+
+ cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN);
+ ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN);
+ al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN);
+
+ ngx_log_debug6(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
+ "access: %*s %*s %*s", cl, ct, ml, mt, al, at);
+ }
+#endif
+
+ for (n = 0; n < 16; n++) {
+ if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) {
+ goto next;
+ }
+ }
+
+ return ngx_stream_access_found(s, rule6[i].deny);
+
+ next:
+ continue;
+ }
+
+ return NGX_DECLINED;
+}
+
+#endif
+
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+static ngx_int_t
+ngx_stream_access_unix(ngx_stream_session_t *s,
+ ngx_stream_access_srv_conf_t *ascf)
+{
+ ngx_uint_t i;
+ ngx_stream_access_rule_un_t *rule_un;
+
+ rule_un = ascf->rules_un->elts;
+ for (i = 0; i < ascf->rules_un->nelts; i++) {
+
+ /* TODO: check path */
+ if (1) {
+ return ngx_stream_access_found(s, rule_un[i].deny);
+ }
+ }
+
+ return NGX_DECLINED;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_stream_access_found(ngx_stream_session_t *s, ngx_uint_t deny)
+{
+ if (deny) {
+ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+ "access forbidden by rule");
+ return NGX_ABORT;
+ }
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_stream_access_srv_conf_t *ascf = conf;
+
+ ngx_int_t rc;
+ ngx_uint_t all;
+ ngx_str_t *value;
+ ngx_cidr_t cidr;
+ ngx_stream_access_rule_t *rule;
+#if (NGX_HAVE_INET6)
+ ngx_stream_access_rule6_t *rule6;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ ngx_stream_access_rule_un_t *rule_un;
+#endif
+
+ ngx_memzero(&cidr, sizeof(ngx_cidr_t));
+
+ value = cf->args->elts;
+
+ all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0);
+
+ if (!all) {
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) {
+ cidr.family = AF_UNIX;
+ rc = NGX_OK;
+
+ } else {
+ rc = ngx_ptocidr(&value[1], &cidr);
+ }
+
+#else
+ rc = ngx_ptocidr(&value[1], &cidr);
+#endif
+
+ if (rc == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (rc == NGX_DONE) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "low address bits of %V are meaningless", &value[1]);
+ }
+ }
+
+ if (cidr.family == AF_INET || all) {
+
+ if (ascf->rules == NULL) {
+ ascf->rules = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_stream_access_rule_t));
+ if (ascf->rules == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ rule = ngx_array_push(ascf->rules);
+ if (rule == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ rule->mask = cidr.u.in.mask;
+ rule->addr = cidr.u.in.addr;
+ rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
+ }
+
+#if (NGX_HAVE_INET6)
+ if (cidr.family == AF_INET6 || all) {
+
+ if (ascf->rules6 == NULL) {
+ ascf->rules6 = ngx_array_create(cf->pool, 4,
+ sizeof(ngx_stream_access_rule6_t));
+ if (ascf->rules6 == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ rule6 = ngx_array_push(ascf->rules6);
+ if (rule6 == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ rule6->mask = cidr.u.in6.mask;
+ rule6->addr = cidr.u.in6.addr;
+ rule6->deny = (value[0].data[0] == 'd') ? 1 : 0;
+ }
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ if (cidr.family == AF_UNIX || all) {
+
+ if (ascf->rules_un == NULL) {
+ ascf->rules_un = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_stream_access_rule_un_t));
+ if (ascf->rules_un == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ rule_un = ngx_array_push(ascf->rules_un);
+ if (rule_un == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0;
+ }
+#endif
+
+ return NGX_CONF_OK;
+}
+
+
+static void *
+ngx_stream_access_create_srv_conf(ngx_conf_t *cf)
+{
+ ngx_stream_access_srv_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_access_srv_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+ return conf;
+}
+
+
+static char *
+ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_stream_access_srv_conf_t *prev = parent;
+ ngx_stream_access_srv_conf_t *conf = child;
+
+ if (conf->rules == NULL
+#if (NGX_HAVE_INET6)
+ && conf->rules6 == NULL
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ && conf->rules_un == NULL
+#endif
+ ) {
+ conf->rules = prev->rules;
+#if (NGX_HAVE_INET6)
+ conf->rules6 = prev->rules6;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ conf->rules_un = prev->rules_un;
+#endif
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_stream_access_init(ngx_conf_t *cf)
+{
+ ngx_stream_core_main_conf_t *cmcf;
+
+ cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
+ cmcf->access_handler = ngx_stream_access_handler;
+
+ return NGX_OK;
+}
diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c
index c8d8e66bc..246f55c45 100644
--- a/src/stream/ngx_stream_core_module.c
+++ b/src/stream/ngx_stream_core_module.c
@@ -50,6 +50,8 @@ static ngx_command_t ngx_stream_core_commands[] = {
static ngx_stream_module_t ngx_stream_core_module_ctx = {
+ NULL, /* postconfiguration */
+
ngx_stream_core_create_main_conf, /* create main configuration */
NULL, /* init main configuration */
@@ -272,7 +274,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
for (i = 0; i < cmcf->listen.nelts; i++) {
- sa = (struct sockaddr *) ls[i].sockaddr;
+ sa = &ls[i].u.sockaddr;
if (sa->sa_family != u.family) {
continue;
@@ -284,7 +286,7 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
case AF_INET6:
off = offsetof(struct sockaddr_in6, sin6_addr);
len = 16;
- sin6 = (struct sockaddr_in6 *) sa;
+ sin6 = &ls[i].u.sockaddr_in6;
port = sin6->sin6_port;
break;
#endif
@@ -300,12 +302,14 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
default: /* AF_INET */
off = offsetof(struct sockaddr_in, sin_addr);
len = 4;
- sin = (struct sockaddr_in *) sa;
+ sin = &ls[i].u.sockaddr_in;
port = sin->sin_port;
break;
}
- if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) {
+ if (ngx_memcmp(ls[i].u.sockaddr_data + off, u.sockaddr + off, len)
+ != 0)
+ {
continue;
}
@@ -325,9 +329,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_memzero(ls, sizeof(ngx_stream_listen_t));
- ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);
+ ngx_memcpy(&ls->u.sockaddr, u.sockaddr, u.socklen);
ls->socklen = u.socklen;
+ ls->backlog = NGX_LISTEN_BACKLOG;
ls->wildcard = u.wildcard;
ls->ctx = cf->ctx;
@@ -342,12 +347,25 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
}
+ if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
+ ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
+ ls->bind = 1;
+
+ if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid backlog \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
struct sockaddr *sa;
u_char buf[NGX_SOCKADDR_STRLEN];
- sa = (struct sockaddr *) ls->sockaddr;
+ sa = &ls->u.sockaddr;
if (sa->sa_family == AF_INET6) {
diff --git a/src/stream/ngx_stream_handler.c b/src/stream/ngx_stream_handler.c
index 2be5183c1..e4538b241 100644
--- a/src/stream/ngx_stream_handler.c
+++ b/src/stream/ngx_stream_handler.c
@@ -23,20 +23,22 @@ static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c);
void
ngx_stream_init_connection(ngx_connection_t *c)
{
- u_char text[NGX_SOCKADDR_STRLEN];
- size_t len;
- ngx_uint_t i;
- struct sockaddr *sa;
- ngx_stream_port_t *port;
- struct sockaddr_in *sin;
- ngx_stream_in_addr_t *addr;
- ngx_stream_session_t *s;
- ngx_stream_addr_conf_t *addr_conf;
+ u_char text[NGX_SOCKADDR_STRLEN];
+ size_t len;
+ ngx_int_t rc;
+ ngx_uint_t i;
+ struct sockaddr *sa;
+ ngx_stream_port_t *port;
+ struct sockaddr_in *sin;
+ ngx_stream_in_addr_t *addr;
+ ngx_stream_session_t *s;
+ ngx_stream_addr_conf_t *addr_conf;
#if (NGX_HAVE_INET6)
- struct sockaddr_in6 *sin6;
- ngx_stream_in6_addr_t *addr6;
+ struct sockaddr_in6 *sin6;
+ ngx_stream_in6_addr_t *addr6;
#endif
- ngx_stream_core_srv_conf_t *cscf;
+ ngx_stream_core_srv_conf_t *cscf;
+ ngx_stream_core_main_conf_t *cmcf;
/* find the server configuration for the address:port */
@@ -143,6 +145,17 @@ ngx_stream_init_connection(ngx_connection_t *c)
c->log->action = "initializing connection";
c->log_error = NGX_ERROR_INFO;
+ cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
+
+ if (cmcf->access_handler) {
+ rc = cmcf->access_handler(s);
+
+ if (rc != NGX_OK && rc != NGX_DECLINED) {
+ ngx_stream_close_connection(c);
+ return;
+ }
+ }
+
#if (NGX_STREAM_SSL)
{
ngx_stream_ssl_conf_t *sslcf;
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index a34b7ceb9..8c88505db 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -21,6 +21,8 @@ typedef struct {
size_t upstream_buf_size;
ngx_uint_t next_upstream_tries;
ngx_flag_t next_upstream;
+ ngx_flag_t proxy_protocol;
+ ngx_addr_t *local;
#if (NGX_STREAM_SSL)
ngx_flag_t ssl_enable;
@@ -64,6 +66,9 @@ static char *ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent,
void *child);
static char *ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s);
#if (NGX_STREAM_SSL)
@@ -97,6 +102,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = {
0,
NULL },
+ { ngx_string("proxy_bind"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_stream_proxy_bind,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("proxy_connect_timeout"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
@@ -146,6 +158,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = {
offsetof(ngx_stream_proxy_srv_conf_t, next_upstream_timeout),
NULL },
+ { ngx_string("proxy_protocol"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol),
+ NULL },
+
#if (NGX_STREAM_SSL)
{ ngx_string("proxy_ssl"),
@@ -246,6 +265,8 @@ static ngx_command_t ngx_stream_proxy_commands[] = {
static ngx_stream_module_t ngx_stream_proxy_module_ctx = {
+ NULL, /* postconfiguration */
+
NULL, /* create main configuration */
NULL, /* init main configuration */
@@ -299,6 +320,8 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s)
u->peer.log = c->log;
u->peer.log_error = NGX_ERROR_ERR;
+ u->peer.local = pscf->local;
+
uscf = pscf->upstream;
if (uscf->peer.init(s, uscf) != NGX_OK) {
@@ -314,6 +337,8 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s)
u->peer.tries = pscf->next_upstream_tries;
}
+ u->proxy_protocol = pscf->proxy_protocol;
+
p = ngx_pnalloc(c->pool, pscf->downstream_buf_size);
if (p == NULL) {
ngx_stream_proxy_finalize(s, NGX_ERROR);
@@ -328,6 +353,29 @@ ngx_stream_proxy_handler(ngx_stream_session_t *s)
c->write->handler = ngx_stream_proxy_downstream_handler;
c->read->handler = ngx_stream_proxy_downstream_handler;
+ if (u->proxy_protocol
+#if (NGX_STREAM_SSL)
+ && pscf->ssl == NULL
+#endif
+ && pscf->downstream_buf_size >= NGX_PROXY_PROTOCOL_MAX_HEADER
+ )
+ {
+ /* optimization for a typical case */
+
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "stream proxy send PROXY protocol header");
+
+ p = ngx_proxy_protocol_write(c, u->downstream_buf.last,
+ u->downstream_buf.end);
+ if (p == NULL) {
+ ngx_stream_proxy_finalize(s, NGX_ERROR);
+ return;
+ }
+
+ u->downstream_buf.last = p;
+ u->proxy_protocol = 0;
+ }
+
if (ngx_stream_proxy_process(s, 0, 0) != NGX_OK) {
return;
}
@@ -403,10 +451,18 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
ngx_stream_upstream_t *u;
ngx_stream_proxy_srv_conf_t *pscf;
- pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);
-
u = s->upstream;
+ if (u->proxy_protocol) {
+ if (ngx_stream_proxy_send_proxy_protocol(s) != NGX_OK) {
+ return;
+ }
+
+ u->proxy_protocol = 0;
+ }
+
+ pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);
+
pc = u->peer.connection;
#if (NGX_STREAM_SSL)
@@ -460,6 +516,76 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
}
+static ngx_int_t
+ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s)
+{
+ u_char *p;
+ ssize_t n, size;
+ ngx_connection_t *c, *pc;
+ ngx_stream_upstream_t *u;
+ ngx_stream_proxy_srv_conf_t *pscf;
+ u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER];
+
+ c = s->connection;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "stream proxy send PROXY protocol header");
+
+ p = ngx_proxy_protocol_write(c, buf, buf + NGX_PROXY_PROTOCOL_MAX_HEADER);
+ if (p == NULL) {
+ ngx_stream_proxy_finalize(s, NGX_ERROR);
+ return NGX_ERROR;
+ }
+
+ u = s->upstream;
+
+ pc = u->peer.connection;
+
+ size = p - buf;
+
+ n = pc->send(pc, buf, size);
+
+ if (n == NGX_AGAIN) {
+ if (ngx_handle_write_event(pc->write, 0) != NGX_OK) {
+ ngx_stream_proxy_finalize(s, NGX_ERROR);
+ return NGX_ERROR;
+ }
+
+ pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);
+
+ ngx_add_timer(pc->write, pscf->timeout);
+
+ pc->write->handler = ngx_stream_proxy_connect_handler;
+
+ return NGX_AGAIN;
+ }
+
+ if (n == NGX_ERROR) {
+ ngx_stream_proxy_finalize(s, NGX_DECLINED);
+ return NGX_ERROR;
+ }
+
+ if (n != size) {
+
+ /*
+ * PROXY protocol specification:
+ * The sender must always ensure that the header
+ * is sent at once, so that the transport layer
+ * maintains atomicity along the path to the receiver.
+ */
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "could not send PROXY protocol header at once");
+
+ ngx_stream_proxy_finalize(s, NGX_DECLINED);
+
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
#if (NGX_STREAM_SSL)
static char *
@@ -1091,6 +1217,8 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf)
conf->upstream_buf_size = NGX_CONF_UNSET_SIZE;
conf->next_upstream_tries = NGX_CONF_UNSET_UINT;
conf->next_upstream = NGX_CONF_UNSET;
+ conf->proxy_protocol = NGX_CONF_UNSET;
+ conf->local = NGX_CONF_UNSET_PTR;
#if (NGX_STREAM_SSL)
conf->ssl_enable = NGX_CONF_UNSET;
@@ -1131,6 +1259,10 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->next_upstream, prev->next_upstream, 1);
+ ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0);
+
+ ngx_conf_merge_ptr_value(conf->local, prev->local, NULL);
+
#if (NGX_STREAM_SSL)
ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0);
@@ -1288,3 +1420,45 @@ ngx_stream_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
}
+
+
+static char *
+ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_stream_proxy_srv_conf_t *pscf = conf;
+
+ ngx_int_t rc;
+ ngx_str_t *value;
+
+ if (pscf->local != NGX_CONF_UNSET_PTR) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ pscf->local = NULL;
+ return NGX_CONF_OK;
+ }
+
+ pscf->local = ngx_palloc(cf->pool, sizeof(ngx_addr_t));
+ if (pscf->local == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ rc = ngx_parse_addr(cf->pool, pscf->local, value[1].data, value[1].len);
+
+ switch (rc) {
+ case NGX_OK:
+ pscf->local->name = value[1];
+ return NGX_CONF_OK;
+
+ case NGX_DECLINED:
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid address \"%V\"", &value[1]);
+ /* fall through */
+
+ default:
+ return NGX_CONF_ERROR;
+ }
+}
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index 4b27a1e3e..97a0fa972 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -132,6 +132,8 @@ static ngx_command_t ngx_stream_ssl_commands[] = {
static ngx_stream_module_t ngx_stream_ssl_module_ctx = {
+ NULL, /* postconfiguration */
+
NULL, /* create main configuration */
NULL, /* init main configuration */
diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c
index a991f8a9f..f21e17d76 100644
--- a/src/stream/ngx_stream_upstream.c
+++ b/src/stream/ngx_stream_upstream.c
@@ -39,6 +39,8 @@ static ngx_command_t ngx_stream_upstream_commands[] = {
static ngx_stream_module_t ngx_stream_upstream_module_ctx = {
+ NULL, /* postconfiguration */
+
ngx_stream_upstream_create_main_conf, /* create main configuration */
ngx_stream_upstream_init_main_conf, /* init main configuration */
diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h
index 83353edca..56325da02 100644
--- a/src/stream/ngx_stream_upstream.h
+++ b/src/stream/ngx_stream_upstream.h
@@ -86,6 +86,8 @@ typedef struct {
#if (NGX_STREAM_SSL)
ngx_str_t ssl_name;
#endif
+ ngx_uint_t proxy_protocol;
+ /* unsigned proxy_protocol:1; */
} ngx_stream_upstream_t;
diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c
index 88e74145f..56ff7d6e9 100644
--- a/src/stream/ngx_stream_upstream_hash_module.c
+++ b/src/stream/ngx_stream_upstream_hash_module.c
@@ -76,6 +76,8 @@ static ngx_command_t ngx_stream_upstream_hash_commands[] = {
static ngx_stream_module_t ngx_stream_upstream_hash_module_ctx = {
+ NULL, /* postconfiguration */
+
NULL, /* create main configuration */
NULL, /* init main configuration */
diff --git a/src/stream/ngx_stream_upstream_least_conn_module.c b/src/stream/ngx_stream_upstream_least_conn_module.c
index eae4b177d..677da4549 100644
--- a/src/stream/ngx_stream_upstream_least_conn_module.c
+++ b/src/stream/ngx_stream_upstream_least_conn_module.c
@@ -32,6 +32,8 @@ static ngx_command_t ngx_stream_upstream_least_conn_commands[] = {
static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = {
+ NULL, /* postconfiguration */
+
NULL, /* create main configuration */
NULL, /* init main configuration */
diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c
index 95a778f10..6025aee7d 100644
--- a/src/stream/ngx_stream_upstream_zone_module.c
+++ b/src/stream/ngx_stream_upstream_zone_module.c
@@ -32,6 +32,8 @@ static ngx_command_t ngx_stream_upstream_zone_commands[] = {
static ngx_stream_module_t ngx_stream_upstream_zone_module_ctx = {
+ NULL, /* postconfiguration */
+
NULL, /* create main configuration */
NULL, /* init main configuration */