Merge branch 'nginx' (nginx-1.17.6).
Change-Id: Ide4fdcde0a608e4d9d398fc804a05de8b4b4c4d5
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 42f1877..2dcc1b3 100644
--- a/.hgtags
+++ b/.hgtags
@@ -444,3 +444,4 @@
ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3
ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4
9af0dddbddb2c368bfedd2801bc100ffad01e19b release-1.17.5
+de68d0d94320cbf033599c6f3ca37e5335c67fd7 release-1.17.6
diff --git a/BUILD b/BUILD
index c2e5c91..49cae0a 100644
--- a/BUILD
+++ b/BUILD
@@ -1520,5 +1520,5 @@
preinst = "@nginx_pkgoss//:debian_preinst",
prerm = "@nginx_pkgoss//:debian_prerm",
section = "httpd",
- version = "1.17.5",
+ version = "1.17.6",
)
diff --git a/build.bzl b/build.bzl
index 49060ce..bf99670 100644
--- a/build.bzl
+++ b/build.bzl
@@ -673,9 +673,9 @@
name = "nginx_pkgoss",
build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
_PKGOSS_BUILD_FILE_TAIL,
- commit = "8358ebc96da490c997960f08b03ffff6d33ad2a5", # nginx-1.17.5
+ commit = "1810c740c9f6b1a812969f53d517e6276afe2caf", # nginx-1.17.6
remote = "https://nginx.googlesource.com/nginx-pkgoss",
- shallow_since = "1571744169 +0300",
+ shallow_since = "1574167886 +0300",
)
def nginx_repositories_zlib(bind):
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 29738da..e0cb545 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,38 @@
<change_log title="nginx">
+<changes ver="1.17.6" date="2019-11-19">
+
+<change type="feature">
+<para lang="ru">
+переменные $proxy_protocol_server_addr и $proxy_protocol_server_port.
+</para>
+<para lang="en">
+the $proxy_protocol_server_addr and $proxy_protocol_server_port variables.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива limit_conn_dry_run.
+</para>
+<para lang="en">
+the "limit_conn_dry_run" directive.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+переменные $limit_req_status и $limit_conn_status.
+</para>
+<para lang="en">
+the $limit_req_status and $limit_conn_status variables.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.17.5" date="2019-10-22">
<change type="feature">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 6910a87..ae88860 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1017005
-#define NGINX_VERSION "1.17.5"
+#define nginx_version 1017006
+#define NGINX_VERSION "1.17.6"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index 5405962..ad6556d 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -147,8 +147,7 @@
socklen_t socklen;
ngx_str_t addr_text;
- ngx_str_t proxy_protocol_addr;
- in_port_t proxy_protocol_port;
+ ngx_proxy_protocol_t *proxy_protocol;
#if (NGX_SSL || NGX_COMPAT)
ngx_ssl_connection_t *ssl;
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index 78ff7a7..dc1ea66 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -26,6 +26,7 @@
typedef struct ngx_connection_s ngx_connection_t;
typedef struct ngx_thread_task_s ngx_thread_task_t;
typedef struct ngx_ssl_s ngx_ssl_t;
+typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t;
typedef struct ngx_ssl_connection_s ngx_ssl_connection_t;
typedef struct ngx_udp_connection_s ngx_udp_connection_t;
diff --git a/src/core/ngx_proxy_protocol.c b/src/core/ngx_proxy_protocol.c
index c3d7fd3..7a9e7f9 100644
--- a/src/core/ngx_proxy_protocol.c
+++ b/src/core/ngx_proxy_protocol.c
@@ -40,6 +40,10 @@
} ngx_proxy_protocol_inet6_addrs_t;
+static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p,
+ u_char *last, ngx_str_t *addr);
+static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last,
+ in_port_t *port, u_char sep);
static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
u_char *last);
@@ -47,9 +51,9 @@
u_char *
ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
{
- size_t len;
- u_char ch, *p, *addr, *port;
- ngx_int_t n;
+ size_t len;
+ u_char *p;
+ ngx_proxy_protocol_t *pp;
static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n";
@@ -83,73 +87,47 @@
}
p += 5;
- addr = p;
- for ( ;; ) {
- if (p == last) {
- goto invalid;
- }
-
- ch = *p++;
-
- if (ch == ' ') {
- break;
- }
-
- if (ch != ':' && ch != '.'
- && (ch < 'a' || ch > 'f')
- && (ch < 'A' || ch > 'F')
- && (ch < '0' || ch > '9'))
- {
- goto invalid;
- }
- }
-
- len = p - addr - 1;
- c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len);
-
- if (c->proxy_protocol_addr.data == NULL) {
+ pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
+ if (pp == NULL) {
return NULL;
}
- ngx_memcpy(c->proxy_protocol_addr.data, addr, len);
- c->proxy_protocol_addr.len = len;
-
- for ( ;; ) {
- if (p == last) {
- goto invalid;
- }
-
- if (*p++ == ' ') {
- break;
- }
- }
-
- port = p;
-
- for ( ;; ) {
- if (p == last) {
- goto invalid;
- }
-
- if (*p++ == ' ') {
- break;
- }
- }
-
- len = p - port - 1;
-
- n = ngx_atoi(port, len);
-
- if (n < 0 || n > 65535) {
+ p = ngx_proxy_protocol_read_addr(c, p, last, &pp->src_addr);
+ if (p == NULL) {
goto invalid;
}
- c->proxy_protocol_port = (in_port_t) n;
+ p = ngx_proxy_protocol_read_addr(c, p, last, &pp->dst_addr);
+ if (p == NULL) {
+ goto invalid;
+ }
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
- "PROXY protocol address: %V %d", &c->proxy_protocol_addr,
- c->proxy_protocol_port);
+ p = ngx_proxy_protocol_read_port(p, last, &pp->src_port, ' ');
+ if (p == NULL) {
+ goto invalid;
+ }
+
+ p = ngx_proxy_protocol_read_port(p, last, &pp->dst_port, CR);
+ if (p == NULL) {
+ goto invalid;
+ }
+
+ if (p == last) {
+ goto invalid;
+ }
+
+ if (*p++ != LF) {
+ goto invalid;
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "PROXY protocol src: %V %d, dst: %V %d",
+ &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
+
+ c->proxy_protocol = pp;
+
+ return p;
skip:
@@ -168,6 +146,82 @@
}
+static u_char *
+ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, u_char *last,
+ ngx_str_t *addr)
+{
+ size_t len;
+ u_char ch, *pos;
+
+ pos = p;
+
+ for ( ;; ) {
+ if (p == last) {
+ return NULL;
+ }
+
+ ch = *p++;
+
+ if (ch == ' ') {
+ break;
+ }
+
+ if (ch != ':' && ch != '.'
+ && (ch < 'a' || ch > 'f')
+ && (ch < 'A' || ch > 'F')
+ && (ch < '0' || ch > '9'))
+ {
+ return NULL;
+ }
+ }
+
+ len = p - pos - 1;
+
+ addr->data = ngx_pnalloc(c->pool, len);
+ if (addr->data == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(addr->data, pos, len);
+ addr->len = len;
+
+ return p;
+}
+
+
+static u_char *
+ngx_proxy_protocol_read_port(u_char *p, u_char *last, in_port_t *port,
+ u_char sep)
+{
+ size_t len;
+ u_char *pos;
+ ngx_int_t n;
+
+ pos = p;
+
+ for ( ;; ) {
+ if (p == last) {
+ return NULL;
+ }
+
+ if (*p++ == sep) {
+ break;
+ }
+ }
+
+ len = p - pos - 1;
+
+ n = ngx_atoi(pos, len);
+ if (n < 0 || n > 65535) {
+ return NULL;
+ }
+
+ *port = (in_port_t) n;
+
+ return p;
+}
+
+
u_char *
ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
{
@@ -219,7 +273,8 @@
size_t len;
socklen_t socklen;
ngx_uint_t version, command, family, transport;
- ngx_sockaddr_t sockaddr;
+ ngx_sockaddr_t src_sockaddr, dst_sockaddr;
+ ngx_proxy_protocol_t *pp;
ngx_proxy_protocol_header_t *header;
ngx_proxy_protocol_inet_addrs_t *in;
#if (NGX_HAVE_INET6)
@@ -266,6 +321,11 @@
return end;
}
+ pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
+ if (pp == NULL) {
+ return NULL;
+ }
+
family = header->family_transport >> 4;
switch (family) {
@@ -278,11 +338,16 @@
in = (ngx_proxy_protocol_inet_addrs_t *) buf;
- sockaddr.sockaddr_in.sin_family = AF_INET;
- sockaddr.sockaddr_in.sin_port = 0;
- memcpy(&sockaddr.sockaddr_in.sin_addr, in->src_addr, 4);
+ src_sockaddr.sockaddr_in.sin_family = AF_INET;
+ src_sockaddr.sockaddr_in.sin_port = 0;
+ memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4);
- c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in->src_port);
+ dst_sockaddr.sockaddr_in.sin_family = AF_INET;
+ dst_sockaddr.sockaddr_in.sin_port = 0;
+ memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4);
+
+ pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port);
+ pp->dst_port = ngx_proxy_protocol_parse_uint16(in->dst_port);
socklen = sizeof(struct sockaddr_in);
@@ -300,11 +365,16 @@
in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf;
- sockaddr.sockaddr_in6.sin6_family = AF_INET6;
- sockaddr.sockaddr_in6.sin6_port = 0;
- memcpy(&sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16);
+ src_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
+ src_sockaddr.sockaddr_in6.sin6_port = 0;
+ memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16);
- c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in6->src_port);
+ dst_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
+ dst_sockaddr.sockaddr_in6.sin6_port = 0;
+ memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16);
+
+ pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port);
+ pp->dst_port = ngx_proxy_protocol_parse_uint16(in6->dst_port);
socklen = sizeof(struct sockaddr_in6);
@@ -321,23 +391,32 @@
return end;
}
- c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
- if (c->proxy_protocol_addr.data == NULL) {
+ pp->src_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
+ if (pp->src_addr.data == NULL) {
return NULL;
}
- c->proxy_protocol_addr.len = ngx_sock_ntop(&sockaddr.sockaddr, socklen,
- c->proxy_protocol_addr.data,
- NGX_SOCKADDR_STRLEN, 0);
+ pp->src_addr.len = ngx_sock_ntop(&src_sockaddr.sockaddr, socklen,
+ pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0);
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
- "PROXY protocol v2 address: %V %d", &c->proxy_protocol_addr,
- c->proxy_protocol_port);
+ pp->dst_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
+ if (pp->dst_addr.data == NULL) {
+ return NULL;
+ }
+
+ pp->dst_addr.len = ngx_sock_ntop(&dst_sockaddr.sockaddr, socklen,
+ pp->dst_addr.data, NGX_SOCKADDR_STRLEN, 0);
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "PROXY protocol v2 src: %V %d, dst: %V %d",
+ &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
if (buf < end) {
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
"PROXY protocol v2 %z bytes of tlv ignored", end - buf);
}
+ c->proxy_protocol = pp;
+
return end;
}
diff --git a/src/core/ngx_proxy_protocol.h b/src/core/ngx_proxy_protocol.h
index fb848f6..b716220 100644
--- a/src/core/ngx_proxy_protocol.h
+++ b/src/core/ngx_proxy_protocol.h
@@ -16,6 +16,14 @@
#define NGX_PROXY_PROTOCOL_MAX_HEADER 107
+struct ngx_proxy_protocol_s {
+ ngx_str_t src_addr;
+ ngx_str_t dst_addr;
+ in_port_t src_port;
+ in_port_t dst_port;
+};
+
+
u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf,
u_char *last);
u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c
index 913d599..4e3e7d5 100644
--- a/src/http/modules/ngx_http_limit_conn_module.c
+++ b/src/http/modules/ngx_http_limit_conn_module.c
@@ -10,36 +10,49 @@
#include <ngx_http.h>
+#define NGX_HTTP_LIMIT_CONN_PASSED 1
+#define NGX_HTTP_LIMIT_CONN_REJECTED 2
+#define NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN 3
+
+
typedef struct {
- u_char color;
- u_char len;
- u_short conn;
- u_char data[1];
+ u_char color;
+ u_char len;
+ u_short conn;
+ u_char data[1];
} ngx_http_limit_conn_node_t;
typedef struct {
- ngx_shm_zone_t *shm_zone;
- ngx_rbtree_node_t *node;
+ ngx_shm_zone_t *shm_zone;
+ ngx_rbtree_node_t *node;
} ngx_http_limit_conn_cleanup_t;
typedef struct {
- ngx_rbtree_t *rbtree;
- ngx_http_complex_value_t key;
+ ngx_rbtree_t rbtree;
+ ngx_rbtree_node_t sentinel;
+} ngx_http_limit_conn_shctx_t;
+
+
+typedef struct {
+ ngx_http_limit_conn_shctx_t *sh;
+ ngx_slab_pool_t *shpool;
+ ngx_http_complex_value_t key;
} ngx_http_limit_conn_ctx_t;
typedef struct {
- ngx_shm_zone_t *shm_zone;
- ngx_uint_t conn;
+ ngx_shm_zone_t *shm_zone;
+ ngx_uint_t conn;
} ngx_http_limit_conn_limit_t;
typedef struct {
- ngx_array_t limits;
- ngx_uint_t log_level;
- ngx_uint_t status_code;
+ ngx_array_t limits;
+ ngx_uint_t log_level;
+ ngx_uint_t status_code;
+ ngx_flag_t dry_run;
} ngx_http_limit_conn_conf_t;
@@ -48,6 +61,8 @@
static void ngx_http_limit_conn_cleanup(void *data);
static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
+static ngx_int_t ngx_http_limit_conn_status_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
@@ -55,6 +70,7 @@
void *conf);
static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static ngx_int_t ngx_http_limit_conn_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
@@ -102,12 +118,19 @@
offsetof(ngx_http_limit_conn_conf_t, status_code),
&ngx_http_limit_conn_status_bounds },
+ { ngx_string("limit_conn_dry_run"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_limit_conn_conf_t, dry_run),
+ NULL },
+
ngx_null_command
};
static ngx_http_module_t ngx_http_limit_conn_module_ctx = {
- NULL, /* preconfiguration */
+ ngx_http_limit_conn_add_variables, /* preconfiguration */
ngx_http_limit_conn_init, /* postconfiguration */
NULL, /* create main configuration */
@@ -137,6 +160,22 @@
};
+static ngx_http_variable_t ngx_http_limit_conn_vars[] = {
+
+ { ngx_string("limit_conn_status"), NULL,
+ ngx_http_limit_conn_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
+ ngx_http_null_variable
+};
+
+
+static ngx_str_t ngx_http_limit_conn_status[] = {
+ ngx_string("PASSED"),
+ ngx_string("REJECTED"),
+ ngx_string("REJECTED_DRY_RUN")
+};
+
+
static ngx_int_t
ngx_http_limit_conn_handler(ngx_http_request_t *r)
{
@@ -144,7 +183,6 @@
uint32_t hash;
ngx_str_t key;
ngx_uint_t i;
- ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node;
ngx_pool_cleanup_t *cln;
ngx_http_limit_conn_ctx_t *ctx;
@@ -153,7 +191,7 @@
ngx_http_limit_conn_limit_t *limits;
ngx_http_limit_conn_cleanup_t *lccln;
- if (r->main->limit_conn_set) {
+ if (r->main->limit_conn_status) {
return NGX_DECLINED;
}
@@ -179,15 +217,13 @@
continue;
}
- r->main->limit_conn_set = 1;
+ r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_PASSED;
hash = ngx_crc32_short(key.data, key.len);
- shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
+ ngx_shmtx_lock(&ctx->shpool->mutex);
- ngx_shmtx_lock(&shpool->mutex);
-
- node = ngx_http_limit_conn_lookup(ctx->rbtree, &key, hash);
+ node = ngx_http_limit_conn_lookup(&ctx->sh->rbtree, &key, hash);
if (node == NULL) {
@@ -195,11 +231,20 @@
+ offsetof(ngx_http_limit_conn_node_t, data)
+ key.len;
- node = ngx_slab_alloc_locked(shpool, n);
+ node = ngx_slab_alloc_locked(ctx->shpool, n);
if (node == NULL) {
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_http_limit_conn_cleanup_all(r->pool);
+
+ if (lccf->dry_run) {
+ r->main->limit_conn_status =
+ NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN;
+ return NGX_DECLINED;
+ }
+
+ r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED;
+
return lccf->status_code;
}
@@ -210,7 +255,7 @@
lc->conn = 1;
ngx_memcpy(lc->data, key.data, key.len);
- ngx_rbtree_insert(ctx->rbtree, node);
+ ngx_rbtree_insert(&ctx->sh->rbtree, node);
} else {
@@ -218,13 +263,23 @@
if ((ngx_uint_t) lc->conn >= limits[i].conn) {
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_log_error(lccf->log_level, r->connection->log, 0,
- "limiting connections by zone \"%V\"",
+ "limiting connections%s by zone \"%V\"",
+ lccf->dry_run ? ", dry run," : "",
&limits[i].shm_zone->shm.name);
ngx_http_limit_conn_cleanup_all(r->pool);
+
+ if (lccf->dry_run) {
+ r->main->limit_conn_status =
+ NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN;
+ return NGX_DECLINED;
+ }
+
+ r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED;
+
return lccf->status_code;
}
@@ -234,7 +289,7 @@
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"limit conn: %08Xi %d", node->key, lc->conn);
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
cln = ngx_pool_cleanup_add(r->pool,
sizeof(ngx_http_limit_conn_cleanup_t));
@@ -338,17 +393,15 @@
{
ngx_http_limit_conn_cleanup_t *lccln = data;
- ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node;
ngx_http_limit_conn_ctx_t *ctx;
ngx_http_limit_conn_node_t *lc;
ctx = lccln->shm_zone->data;
- shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
node = lccln->node;
lc = (ngx_http_limit_conn_node_t *) &node->color;
- ngx_shmtx_lock(&shpool->mutex);
+ ngx_shmtx_lock(&ctx->shpool->mutex);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
"limit conn cleanup: %08Xi %d", node->key, lc->conn);
@@ -356,11 +409,11 @@
lc->conn--;
if (lc->conn == 0) {
- ngx_rbtree_delete(ctx->rbtree, node);
- ngx_slab_free_locked(shpool, node);
+ ngx_rbtree_delete(&ctx->sh->rbtree, node);
+ ngx_slab_free_locked(ctx->shpool, node);
}
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
}
@@ -386,8 +439,6 @@
ngx_http_limit_conn_ctx_t *octx = data;
size_t len;
- ngx_slab_pool_t *shpool;
- ngx_rbtree_node_t *sentinel;
ngx_http_limit_conn_ctx_t *ctx;
ctx = shm_zone->data;
@@ -406,48 +457,63 @@
return NGX_ERROR;
}
- ctx->rbtree = octx->rbtree;
+ ctx->sh = octx->sh;
+ ctx->shpool = octx->shpool;
return NGX_OK;
}
- shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+ ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
if (shm_zone->shm.exists) {
- ctx->rbtree = shpool->data;
+ ctx->sh = ctx->shpool->data;
return NGX_OK;
}
- ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
- if (ctx->rbtree == NULL) {
+ ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_conn_shctx_t));
+ if (ctx->sh == NULL) {
return NGX_ERROR;
}
- shpool->data = ctx->rbtree;
+ ctx->shpool->data = ctx->sh;
- sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
- if (sentinel == NULL) {
- return NGX_ERROR;
- }
-
- ngx_rbtree_init(ctx->rbtree, sentinel,
+ ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
ngx_http_limit_conn_rbtree_insert_value);
len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
- shpool->log_ctx = ngx_slab_alloc(shpool, len);
- if (shpool->log_ctx == NULL) {
+ ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
+ if (ctx->shpool->log_ctx == NULL) {
return NGX_ERROR;
}
- ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
+ ngx_sprintf(ctx->shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
&shm_zone->shm.name);
return NGX_OK;
}
+static ngx_int_t
+ngx_http_limit_conn_status_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ if (r->main->limit_conn_status == 0) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->len = ngx_http_limit_conn_status[r->main->limit_conn_status - 1].len;
+ v->data = ngx_http_limit_conn_status[r->main->limit_conn_status - 1].data;
+
+ return NGX_OK;
+}
+
+
static void *
ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
{
@@ -466,6 +532,7 @@
conf->log_level = NGX_CONF_UNSET_UINT;
conf->status_code = NGX_CONF_UNSET_UINT;
+ conf->dry_run = NGX_CONF_UNSET;
return conf;
}
@@ -485,6 +552,8 @@
ngx_conf_merge_uint_value(conf->status_code, prev->status_code,
NGX_HTTP_SERVICE_UNAVAILABLE);
+ ngx_conf_merge_value(conf->dry_run, prev->dry_run, 0);
+
return NGX_CONF_OK;
}
@@ -652,6 +721,25 @@
static ngx_int_t
+ngx_http_limit_conn_add_variables(ngx_conf_t *cf)
+{
+ ngx_http_variable_t *var, *v;
+
+ for (v = ngx_http_limit_conn_vars; v->name.len; v++) {
+ var = ngx_http_add_variable(cf, &v->name, v->flags);
+ if (var == NULL) {
+ return NGX_ERROR;
+ }
+
+ var->get_handler = v->get_handler;
+ var->data = v->data;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_limit_conn_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c
index 8064522..6bd3e6a 100644
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -10,6 +10,13 @@
#include <ngx_http.h>
+#define NGX_HTTP_LIMIT_REQ_PASSED 1
+#define NGX_HTTP_LIMIT_REQ_DELAYED 2
+#define NGX_HTTP_LIMIT_REQ_REJECTED 3
+#define NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN 4
+#define NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN 5
+
+
typedef struct {
u_char color;
u_char dummy;
@@ -65,6 +72,8 @@
static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx,
ngx_uint_t n);
+static ngx_int_t ngx_http_limit_req_status_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf);
static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
@@ -72,6 +81,7 @@
void *conf);
static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static ngx_int_t ngx_http_limit_req_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf);
@@ -131,7 +141,7 @@
static ngx_http_module_t ngx_http_limit_req_module_ctx = {
- NULL, /* preconfiguration */
+ ngx_http_limit_req_add_variables, /* preconfiguration */
ngx_http_limit_req_init, /* postconfiguration */
NULL, /* create main configuration */
@@ -161,6 +171,24 @@
};
+static ngx_http_variable_t ngx_http_limit_req_vars[] = {
+
+ { ngx_string("limit_req_status"), NULL,
+ ngx_http_limit_req_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
+ ngx_http_null_variable
+};
+
+
+static ngx_str_t ngx_http_limit_req_status[] = {
+ ngx_string("PASSED"),
+ ngx_string("DELAYED"),
+ ngx_string("REJECTED"),
+ ngx_string("DELAYED_DRY_RUN"),
+ ngx_string("REJECTED_DRY_RUN")
+};
+
+
static ngx_int_t
ngx_http_limit_req_handler(ngx_http_request_t *r)
{
@@ -173,7 +201,7 @@
ngx_http_limit_req_conf_t *lrcf;
ngx_http_limit_req_limit_t *limit, *limits;
- if (r->main->limit_req_set) {
+ if (r->main->limit_req_status) {
return NGX_DECLINED;
}
@@ -232,8 +260,6 @@
return NGX_DECLINED;
}
- r->main->limit_req_set = 1;
-
if (rc == NGX_BUSY || rc == NGX_ERROR) {
if (rc == NGX_BUSY) {
@@ -261,9 +287,12 @@
}
if (lrcf->dry_run) {
+ r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;
return NGX_DECLINED;
}
+ r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED;
+
return lrcf->status_code;
}
@@ -276,6 +305,7 @@
delay = ngx_http_limit_req_account(limits, n, &excess, &limit);
if (!delay) {
+ r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_PASSED;
return NGX_DECLINED;
}
@@ -285,9 +315,12 @@
excess / 1000, excess % 1000, &limit->shm_zone->shm.name);
if (lrcf->dry_run) {
+ r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN;
return NGX_DECLINED;
}
+ r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED;
+
if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -711,6 +744,25 @@
}
+static ngx_int_t
+ngx_http_limit_req_status_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ if (r->main->limit_req_status == 0) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->len = ngx_http_limit_req_status[r->main->limit_req_status - 1].len;
+ v->data = ngx_http_limit_req_status[r->main->limit_req_status - 1].data;
+
+ return NGX_OK;
+}
+
+
static void *
ngx_http_limit_req_create_conf(ngx_conf_t *cf)
{
@@ -996,6 +1048,25 @@
static ngx_int_t
+ngx_http_limit_req_add_variables(ngx_conf_t *cf)
+{
+ ngx_http_variable_t *var, *v;
+
+ for (v = ngx_http_limit_req_vars; v->name.len; v++) {
+ var = ngx_http_add_variable(cf, &v->name, v->flags);
+ if (var == NULL) {
+ return NGX_ERROR;
+ }
+
+ var->get_handler = v->get_handler;
+ var->data = v->data;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_limit_req_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c
index 7d3f2a9..9586ebe 100644
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -180,12 +180,11 @@
case NGX_HTTP_REALIP_PROXY:
- value = &r->connection->proxy_protocol_addr;
-
- if (value->len == 0) {
+ if (r->connection->proxy_protocol == NULL) {
return NGX_DECLINED;
}
+ value = &r->connection->proxy_protocol->src_addr;
xfwd = NULL;
break;
@@ -238,7 +237,7 @@
!= NGX_DECLINED)
{
if (rlcf->type == NGX_HTTP_REALIP_PROXY) {
- ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port);
+ ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port);
}
return ngx_http_realip_set_addr(r, &addr);
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 184c35e..f49a8d5 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -510,10 +510,10 @@
/*
* instead of using the request context data in
* ngx_http_limit_conn_module and ngx_http_limit_req_module
- * we use the single bits in the request structure
+ * we use the bit fields in the request structure
*/
- unsigned limit_conn_set:1;
- unsigned limit_req_set:1;
+ unsigned limit_conn_status:2;
+ unsigned limit_req_status:3;
unsigned limit_rate_set:1;
unsigned limit_rate_after_set:1;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 8cd6c9a..4179d21 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -199,10 +199,20 @@
{ ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
{ ngx_string("proxy_protocol_addr"), NULL,
- ngx_http_variable_proxy_protocol_addr, 0, 0, 0 },
+ ngx_http_variable_proxy_protocol_addr,
+ offsetof(ngx_proxy_protocol_t, src_addr), 0, 0 },
{ ngx_string("proxy_protocol_port"), NULL,
- ngx_http_variable_proxy_protocol_port, 0, 0, 0 },
+ ngx_http_variable_proxy_protocol_port,
+ offsetof(ngx_proxy_protocol_t, src_port), 0, 0 },
+
+ { ngx_string("proxy_protocol_server_addr"), NULL,
+ ngx_http_variable_proxy_protocol_addr,
+ offsetof(ngx_proxy_protocol_t, dst_addr), 0, 0 },
+
+ { ngx_string("proxy_protocol_server_port"), NULL,
+ ngx_http_variable_proxy_protocol_port,
+ offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
{ ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
@@ -1293,11 +1303,22 @@
ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
- v->len = r->connection->proxy_protocol_addr.len;
+ ngx_str_t *addr;
+ ngx_proxy_protocol_t *pp;
+
+ pp = r->connection->proxy_protocol;
+ if (pp == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ addr = (ngx_str_t *) ((char *) pp + data);
+
+ v->len = addr->len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
- v->data = r->connection->proxy_protocol_addr.data;
+ v->data = addr->data;
return NGX_OK;
}
@@ -1307,7 +1328,14 @@
ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
- ngx_uint_t port;
+ ngx_uint_t port;
+ ngx_proxy_protocol_t *pp;
+
+ pp = r->connection->proxy_protocol;
+ if (pp == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
v->len = 0;
v->valid = 1;
@@ -1319,7 +1347,7 @@
return NGX_ERROR;
}
- port = r->connection->proxy_protocol_port;
+ port = *(in_port_t *) ((char *) pp + data);
if (port > 0 && port < 65536) {
v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h
index 57e73e0..9e35832 100644
--- a/src/stream/ngx_stream.h
+++ b/src/stream/ngx_stream.h
@@ -226,6 +226,8 @@
unsigned stat_processing:1;
unsigned health_check:1;
+
+ unsigned limit_conn_status:2;
};
diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c
index b64a426..bae034a 100644
--- a/src/stream/ngx_stream_limit_conn_module.c
+++ b/src/stream/ngx_stream_limit_conn_module.c
@@ -10,35 +10,48 @@
#include <ngx_stream.h>
+#define NGX_STREAM_LIMIT_CONN_PASSED 1
+#define NGX_STREAM_LIMIT_CONN_REJECTED 2
+#define NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN 3
+
+
typedef struct {
- u_char color;
- u_char len;
- u_short conn;
- u_char data[1];
+ u_char color;
+ u_char len;
+ u_short conn;
+ u_char data[1];
} ngx_stream_limit_conn_node_t;
typedef struct {
- ngx_shm_zone_t *shm_zone;
- ngx_rbtree_node_t *node;
+ ngx_shm_zone_t *shm_zone;
+ ngx_rbtree_node_t *node;
} ngx_stream_limit_conn_cleanup_t;
typedef struct {
- ngx_rbtree_t *rbtree;
- ngx_stream_complex_value_t key;
+ ngx_rbtree_t rbtree;
+ ngx_rbtree_node_t sentinel;
+} ngx_stream_limit_conn_shctx_t;
+
+
+typedef struct {
+ ngx_stream_limit_conn_shctx_t *sh;
+ ngx_slab_pool_t *shpool;
+ ngx_stream_complex_value_t key;
} ngx_stream_limit_conn_ctx_t;
typedef struct {
- ngx_shm_zone_t *shm_zone;
- ngx_uint_t conn;
+ ngx_shm_zone_t *shm_zone;
+ ngx_uint_t conn;
} ngx_stream_limit_conn_limit_t;
typedef struct {
- ngx_array_t limits;
- ngx_uint_t log_level;
+ ngx_array_t limits;
+ ngx_uint_t log_level;
+ ngx_flag_t dry_run;
} ngx_stream_limit_conn_conf_t;
@@ -47,6 +60,8 @@
static void ngx_stream_limit_conn_cleanup(void *data);
static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool);
+static ngx_int_t ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s,
+ ngx_stream_variable_value_t *v, uintptr_t data);
static void *ngx_stream_limit_conn_create_conf(ngx_conf_t *cf);
static char *ngx_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
@@ -54,6 +69,7 @@
void *conf);
static char *ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static ngx_int_t ngx_stream_limit_conn_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_stream_limit_conn_init(ngx_conf_t *cf);
@@ -89,12 +105,19 @@
offsetof(ngx_stream_limit_conn_conf_t, log_level),
&ngx_stream_limit_conn_log_levels },
+ { ngx_string("limit_conn_dry_run"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_limit_conn_conf_t, dry_run),
+ NULL },
+
ngx_null_command
};
static ngx_stream_module_t ngx_stream_limit_conn_module_ctx = {
- NULL, /* preconfiguration */
+ ngx_stream_limit_conn_add_variables, /* preconfiguration */
ngx_stream_limit_conn_init, /* postconfiguration */
NULL, /* create main configuration */
@@ -121,6 +144,22 @@
};
+static ngx_stream_variable_t ngx_stream_limit_conn_vars[] = {
+
+ { ngx_string("limit_conn_status"), NULL,
+ ngx_stream_limit_conn_status_variable, 0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
+
+ ngx_stream_null_variable
+};
+
+
+static ngx_str_t ngx_stream_limit_conn_status[] = {
+ ngx_string("PASSED"),
+ ngx_string("REJECTED"),
+ ngx_string("REJECTED_DRY_RUN")
+};
+
+
static ngx_int_t
ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
{
@@ -128,7 +167,6 @@
uint32_t hash;
ngx_str_t key;
ngx_uint_t i;
- ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node;
ngx_pool_cleanup_t *cln;
ngx_stream_limit_conn_ctx_t *ctx;
@@ -159,13 +197,13 @@
continue;
}
+ s->limit_conn_status = NGX_STREAM_LIMIT_CONN_PASSED;
+
hash = ngx_crc32_short(key.data, key.len);
- shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
+ ngx_shmtx_lock(&ctx->shpool->mutex);
- ngx_shmtx_lock(&shpool->mutex);
-
- node = ngx_stream_limit_conn_lookup(ctx->rbtree, &key, hash);
+ node = ngx_stream_limit_conn_lookup(&ctx->sh->rbtree, &key, hash);
if (node == NULL) {
@@ -173,11 +211,20 @@
+ offsetof(ngx_stream_limit_conn_node_t, data)
+ key.len;
- node = ngx_slab_alloc_locked(shpool, n);
+ node = ngx_slab_alloc_locked(ctx->shpool, n);
if (node == NULL) {
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_stream_limit_conn_cleanup_all(s->connection->pool);
+
+ if (lccf->dry_run) {
+ s->limit_conn_status =
+ NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN;
+ return NGX_DECLINED;
+ }
+
+ s->limit_conn_status = NGX_STREAM_LIMIT_CONN_REJECTED;
+
return NGX_STREAM_SERVICE_UNAVAILABLE;
}
@@ -188,7 +235,7 @@
lc->conn = 1;
ngx_memcpy(lc->data, key.data, key.len);
- ngx_rbtree_insert(ctx->rbtree, node);
+ ngx_rbtree_insert(&ctx->sh->rbtree, node);
} else {
@@ -196,13 +243,23 @@
if ((ngx_uint_t) lc->conn >= limits[i].conn) {
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_log_error(lccf->log_level, s->connection->log, 0,
- "limiting connections by zone \"%V\"",
+ "limiting connections%s by zone \"%V\"",
+ lccf->dry_run ? ", dry run," : "",
&limits[i].shm_zone->shm.name);
ngx_stream_limit_conn_cleanup_all(s->connection->pool);
+
+ if (lccf->dry_run) {
+ s->limit_conn_status =
+ NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN;
+ return NGX_DECLINED;
+ }
+
+ s->limit_conn_status = NGX_STREAM_LIMIT_CONN_REJECTED;
+
return NGX_STREAM_SERVICE_UNAVAILABLE;
}
@@ -212,7 +269,7 @@
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
"limit conn: %08Xi %d", node->key, lc->conn);
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
cln = ngx_pool_cleanup_add(s->connection->pool,
sizeof(ngx_stream_limit_conn_cleanup_t));
@@ -317,17 +374,15 @@
{
ngx_stream_limit_conn_cleanup_t *lccln = data;
- ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node;
ngx_stream_limit_conn_ctx_t *ctx;
ngx_stream_limit_conn_node_t *lc;
ctx = lccln->shm_zone->data;
- shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
node = lccln->node;
lc = (ngx_stream_limit_conn_node_t *) &node->color;
- ngx_shmtx_lock(&shpool->mutex);
+ ngx_shmtx_lock(&ctx->shpool->mutex);
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0,
"limit conn cleanup: %08Xi %d", node->key, lc->conn);
@@ -335,11 +390,11 @@
lc->conn--;
if (lc->conn == 0) {
- ngx_rbtree_delete(ctx->rbtree, node);
- ngx_slab_free_locked(shpool, node);
+ ngx_rbtree_delete(&ctx->sh->rbtree, node);
+ ngx_slab_free_locked(ctx->shpool, node);
}
- ngx_shmtx_unlock(&shpool->mutex);
+ ngx_shmtx_unlock(&ctx->shpool->mutex);
}
@@ -365,8 +420,6 @@
ngx_stream_limit_conn_ctx_t *octx = data;
size_t len;
- ngx_slab_pool_t *shpool;
- ngx_rbtree_node_t *sentinel;
ngx_stream_limit_conn_ctx_t *ctx;
ctx = shm_zone->data;
@@ -385,48 +438,64 @@
return NGX_ERROR;
}
- ctx->rbtree = octx->rbtree;
+ ctx->sh = octx->sh;
+ ctx->shpool = octx->shpool;
return NGX_OK;
}
- shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+ ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
if (shm_zone->shm.exists) {
- ctx->rbtree = shpool->data;
+ ctx->sh = ctx->shpool->data;
return NGX_OK;
}
- ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
- if (ctx->rbtree == NULL) {
+ ctx->sh = ngx_slab_alloc(ctx->shpool,
+ sizeof(ngx_stream_limit_conn_shctx_t));
+ if (ctx->sh == NULL) {
return NGX_ERROR;
}
- shpool->data = ctx->rbtree;
+ ctx->shpool->data = ctx->sh;
- sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
- if (sentinel == NULL) {
- return NGX_ERROR;
- }
-
- ngx_rbtree_init(ctx->rbtree, sentinel,
+ ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
ngx_stream_limit_conn_rbtree_insert_value);
len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
- shpool->log_ctx = ngx_slab_alloc(shpool, len);
- if (shpool->log_ctx == NULL) {
+ ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
+ if (ctx->shpool->log_ctx == NULL) {
return NGX_ERROR;
}
- ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
+ ngx_sprintf(ctx->shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
&shm_zone->shm.name);
return NGX_OK;
}
+static ngx_int_t
+ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s,
+ ngx_stream_variable_value_t *v, uintptr_t data)
+{
+ if (s->limit_conn_status == 0) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->len = ngx_stream_limit_conn_status[s->limit_conn_status - 1].len;
+ v->data = ngx_stream_limit_conn_status[s->limit_conn_status - 1].data;
+
+ return NGX_OK;
+}
+
+
static void *
ngx_stream_limit_conn_create_conf(ngx_conf_t *cf)
{
@@ -444,6 +513,7 @@
*/
conf->log_level = NGX_CONF_UNSET_UINT;
+ conf->dry_run = NGX_CONF_UNSET;
return conf;
}
@@ -461,6 +531,8 @@
ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
+ ngx_conf_merge_value(conf->dry_run, prev->dry_run, 0);
+
return NGX_CONF_OK;
}
@@ -628,6 +700,25 @@
static ngx_int_t
+ngx_stream_limit_conn_add_variables(ngx_conf_t *cf)
+{
+ ngx_stream_variable_t *var, *v;
+
+ for (v = ngx_stream_limit_conn_vars; v->name.len; v++) {
+ var = ngx_stream_add_variable(cf, &v->name, v->flags);
+ if (var == NULL) {
+ return NGX_ERROR;
+ }
+
+ var->get_handler = v->get_handler;
+ var->data = v->data;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_stream_limit_conn_init(ngx_conf_t *cf)
{
ngx_stream_handler_pt *h;
diff --git a/src/stream/ngx_stream_realip_module.c b/src/stream/ngx_stream_realip_module.c
index 57b1ac2..603f597 100644
--- a/src/stream/ngx_stream_realip_module.c
+++ b/src/stream/ngx_stream_realip_module.c
@@ -108,7 +108,7 @@
c = s->connection;
- if (c->proxy_protocol_addr.len == 0) {
+ if (c->proxy_protocol == NULL) {
return NGX_DECLINED;
}
@@ -116,14 +116,14 @@
return NGX_DECLINED;
}
- if (ngx_parse_addr(c->pool, &addr, c->proxy_protocol_addr.data,
- c->proxy_protocol_addr.len)
+ if (ngx_parse_addr(c->pool, &addr, c->proxy_protocol->src_addr.data,
+ c->proxy_protocol->src_addr.len)
!= NGX_OK)
{
return NGX_DECLINED;
}
- ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port);
+ ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port);
return ngx_stream_realip_set_addr(s, &addr);
}
diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c
index d1526a9..8b59668 100644
--- a/src/stream/ngx_stream_variables.c
+++ b/src/stream/ngx_stream_variables.c
@@ -64,10 +64,20 @@
ngx_stream_variable_remote_port, 0, 0, 0 },
{ ngx_string("proxy_protocol_addr"), NULL,
- ngx_stream_variable_proxy_protocol_addr, 0, 0, 0 },
+ ngx_stream_variable_proxy_protocol_addr,
+ offsetof(ngx_proxy_protocol_t, src_addr), 0, 0 },
{ ngx_string("proxy_protocol_port"), NULL,
- ngx_stream_variable_proxy_protocol_port, 0, 0, 0 },
+ ngx_stream_variable_proxy_protocol_port,
+ offsetof(ngx_proxy_protocol_t, src_port), 0, 0 },
+
+ { ngx_string("proxy_protocol_server_addr"), NULL,
+ ngx_stream_variable_proxy_protocol_addr,
+ offsetof(ngx_proxy_protocol_t, dst_addr), 0, 0 },
+
+ { ngx_string("proxy_protocol_server_port"), NULL,
+ ngx_stream_variable_proxy_protocol_port,
+ offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
{ ngx_string("server_addr"), NULL,
ngx_stream_variable_server_addr, 0, 0, 0 },
@@ -557,11 +567,22 @@
ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data)
{
- v->len = s->connection->proxy_protocol_addr.len;
+ ngx_str_t *addr;
+ ngx_proxy_protocol_t *pp;
+
+ pp = s->connection->proxy_protocol;
+ if (pp == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ addr = (ngx_str_t *) ((char *) pp + data);
+
+ v->len = addr->len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
- v->data = s->connection->proxy_protocol_addr.data;
+ v->data = addr->data;
return NGX_OK;
}
@@ -571,7 +592,14 @@
ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data)
{
- ngx_uint_t port;
+ ngx_uint_t port;
+ ngx_proxy_protocol_t *pp;
+
+ pp = s->connection->proxy_protocol;
+ if (pp == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
v->len = 0;
v->valid = 1;
@@ -583,7 +611,7 @@
return NGX_ERROR;
}
- port = s->connection->proxy_protocol_port;
+ port = *(in_port_t *) ((char *) pp + data);
if (port > 0 && port < 65536) {
v->len = ngx_sprintf(v->data, "%ui", port) - v->data;