Hello community, here is the log from the commit of package nginx for openSUSE:Factory checked in at 2019-12-02 11:33:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/nginx (Old) and /work/SRC/openSUSE:Factory/.nginx.new.4691 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "nginx" Mon Dec 2 11:33:28 2019 rev:43 rq:752658 version:1.17.6 Changes: -------- --- /work/SRC/openSUSE:Factory/nginx/nginx.changes 2019-10-28 17:00:28.797766053 +0100 +++ /work/SRC/openSUSE:Factory/.nginx.new.4691/nginx.changes 2019-12-02 11:38:04.206457257 +0100 @@ -1,0 +2,10 @@ +Sat Nov 23 20:12:57 UTC 2019 - Marcus Rueckert <[email protected]> + +- Update to 1.17.6 + - Feature: the $proxy_protocol_server_addr and + $proxy_protocol_server_port variables. + - Feature: the "limit_conn_dry_run" directive. + - Feature: the $limit_req_status and $limit_conn_status + variables. + +------------------------------------------------------------------- Old: ---- nginx-1.17.5.tar.gz nginx-1.17.5.tar.gz.asc New: ---- nginx-1.17.6.tar.gz nginx-1.17.6.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ nginx.spec ++++++ --- /var/tmp/diff_new_pack.CYJgCo/_old 2019-12-02 11:38:04.814457385 +0100 +++ /var/tmp/diff_new_pack.CYJgCo/_new 2019-12-02 11:38:04.818457385 +0100 @@ -70,7 +70,7 @@ %define ngx_doc_dir %{_datadir}/doc/packages/%{name} # Name: nginx -Version: 1.17.5 +Version: 1.17.6 Release: 0 %define ngx_fancyindex_version 0.4.2 %define ngx_fancyindex_module_path ngx-fancyindex-%{ngx_fancyindex_version} ++++++ nginx-1.17.5.tar.gz -> nginx-1.17.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/CHANGES new/nginx-1.17.6/CHANGES --- old/nginx-1.17.5/CHANGES 2019-10-22 17:16:13.000000000 +0200 +++ new/nginx-1.17.6/CHANGES 2019-11-19 15:19:02.000000000 +0100 @@ -1,4 +1,14 @@ +Changes with nginx 1.17.6 19 Nov 2019 + + *) Feature: the $proxy_protocol_server_addr and + $proxy_protocol_server_port variables. + + *) Feature: the "limit_conn_dry_run" directive. + + *) Feature: the $limit_req_status and $limit_conn_status variables. + + Changes with nginx 1.17.5 22 Oct 2019 *) Feature: now nginx uses ioctl(FIONREAD), if available, to avoid diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/CHANGES.ru new/nginx-1.17.6/CHANGES.ru --- old/nginx-1.17.5/CHANGES.ru 2019-10-22 17:16:11.000000000 +0200 +++ new/nginx-1.17.6/CHANGES.ru 2019-11-19 15:19:01.000000000 +0100 @@ -1,4 +1,14 @@ +Изменения в nginx 1.17.6 19.11.2019 + + *) Добавление: переменные $proxy_protocol_server_addr и + $proxy_protocol_server_port. + + *) Добавление: директива limit_conn_dry_run. + + *) Добавление: переменные $limit_req_status и $limit_conn_status. + + Изменения в nginx 1.17.5 22.10.2019 *) Добавление: теперь nginx использует вызов ioctl(FIONREAD), если он diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/core/nginx.h new/nginx-1.17.6/src/core/nginx.h --- old/nginx-1.17.5/src/core/nginx.h 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/core/nginx.h 2019-11-19 15:18:58.000000000 +0100 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1017005 -#define NGINX_VERSION "1.17.5" +#define nginx_version 1017006 +#define NGINX_VERSION "1.17.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/core/ngx_connection.h new/nginx-1.17.6/src/core/ngx_connection.h --- old/nginx-1.17.5/src/core/ngx_connection.h 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/core/ngx_connection.h 2019-11-19 15:18:58.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/core/ngx_core.h new/nginx-1.17.6/src/core/ngx_core.h --- old/nginx-1.17.5/src/core/ngx_core.h 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/core/ngx_core.h 2019-11-19 15:18:58.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/core/ngx_proxy_protocol.c new/nginx-1.17.6/src/core/ngx_proxy_protocol.c --- old/nginx-1.17.5/src/core/ngx_proxy_protocol.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/core/ngx_proxy_protocol.c 2019-11-19 15:18:58.000000000 +0100 @@ -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,11 +87,77 @@ } p += 5; - addr = p; + + pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t)); + if (pp == NULL) { + return NULL; + } + + p = ngx_proxy_protocol_read_addr(c, p, last, &pp->src_addr); + if (p == NULL) { + goto invalid; + } + + p = ngx_proxy_protocol_read_addr(c, p, last, &pp->dst_addr); + if (p == NULL) { + goto invalid; + } + + 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: + + for ( /* void */ ; p < last - 1; p++) { + if (p[0] == CR && p[1] == LF) { + return p + 2; + } + } + +invalid: + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "broken header: \"%*s\"", (size_t) (last - buf), buf); + + return NULL; +} + + +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) { - goto invalid; + return NULL; } ch = *p++; @@ -101,70 +171,54 @@ && (ch < 'A' || ch > 'F') && (ch < '0' || ch > '9')) { - goto invalid; + return NULL; } } - len = p - addr - 1; - c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len); + len = p - pos - 1; - if (c->proxy_protocol_addr.data == NULL) { + addr->data = ngx_pnalloc(c->pool, len); + if (addr->data == NULL) { return NULL; } - ngx_memcpy(c->proxy_protocol_addr.data, addr, len); - c->proxy_protocol_addr.len = len; + ngx_memcpy(addr->data, pos, len); + addr->len = len; - for ( ;; ) { - if (p == last) { - goto invalid; - } + return p; +} - if (*p++ == ' ') { - break; - } - } - port = 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) { - goto invalid; + return NULL; } - if (*p++ == ' ') { + if (*p++ == sep) { break; } } - len = p - port - 1; - - n = ngx_atoi(port, len); + len = p - pos - 1; + n = ngx_atoi(pos, len); if (n < 0 || n > 65535) { - goto invalid; - } - - c->proxy_protocol_port = (in_port_t) n; - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, - "PROXY protocol address: %V %d", &c->proxy_protocol_addr, - c->proxy_protocol_port); - -skip: - - for ( /* void */ ; p < last - 1; p++) { - if (p[0] == CR && p[1] == LF) { - return p + 2; - } + return NULL; } -invalid: - - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "broken header: \"%*s\"", (size_t) (last - buf), buf); + *port = (in_port_t) n; - return NULL; + return p; } @@ -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); + + 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); - c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in->src_port); + 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); + + 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); - c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in6->src_port); + 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; + } + + pp->src_addr.len = ngx_sock_ntop(&src_sockaddr.sockaddr, socklen, + pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0); + + pp->dst_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN); + if (pp->dst_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); - - 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.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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/core/ngx_proxy_protocol.h new/nginx-1.17.6/src/core/ngx_proxy_protocol.h --- old/nginx-1.17.5/src/core/ngx_proxy_protocol.h 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/core/ngx_proxy_protocol.h 2019-11-19 15:18:58.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/http/modules/ngx_http_limit_conn_module.c new/nginx-1.17.6/src/http/modules/ngx_http_limit_conn_module.c --- old/nginx-1.17.5/src/http/modules/ngx_http_limit_conn_module.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/http/modules/ngx_http_limit_conn_module.c 2019-11-19 15:18:58.000000000 +0100 @@ -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(&shpool->mutex); + ngx_shmtx_lock(&ctx->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; } @@ -651,6 +720,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) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/http/modules/ngx_http_limit_req_module.c new/nginx-1.17.6/src/http/modules/ngx_http_limit_req_module.c --- old/nginx-1.17.5/src/http/modules/ngx_http_limit_req_module.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/http/modules/ngx_http_limit_req_module.c 2019-11-19 15:18:58.000000000 +0100 @@ -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) { @@ -995,6 +1047,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) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/http/modules/ngx_http_realip_module.c new/nginx-1.17.6/src/http/modules/ngx_http_realip_module.c --- old/nginx-1.17.5/src/http/modules/ngx_http_realip_module.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/http/modules/ngx_http_realip_module.c 2019-11-19 15:18:58.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/http/ngx_http_request.h new/nginx-1.17.6/src/http/ngx_http_request.h --- old/nginx-1.17.5/src/http/ngx_http_request.h 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/http/ngx_http_request.h 2019-11-19 15:18:58.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/http/ngx_http_variables.c new/nginx-1.17.6/src/http/ngx_http_variables.c --- old/nginx-1.17.5/src/http/ngx_http_variables.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/http/ngx_http_variables.c 2019-11-19 15:18:58.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/stream/ngx_stream.h new/nginx-1.17.6/src/stream/ngx_stream.h --- old/nginx-1.17.5/src/stream/ngx_stream.h 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/stream/ngx_stream.h 2019-11-19 15:18:58.000000000 +0100 @@ -226,6 +226,8 @@ unsigned stat_processing:1; unsigned health_check:1; + + unsigned limit_conn_status:2; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/stream/ngx_stream_limit_conn_module.c new/nginx-1.17.6/src/stream/ngx_stream_limit_conn_module.c --- old/nginx-1.17.5/src/stream/ngx_stream_limit_conn_module.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/stream/ngx_stream_limit_conn_module.c 2019-11-19 15:18:58.000000000 +0100 @@ -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; } - hash = ngx_crc32_short(key.data, key.len); + s->limit_conn_status = NGX_STREAM_LIMIT_CONN_PASSED; - shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; + hash = ngx_crc32_short(key.data, key.len); - ngx_shmtx_lock(&shpool->mutex); + ngx_shmtx_lock(&ctx->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; } @@ -627,6 +699,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) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/stream/ngx_stream_realip_module.c new/nginx-1.17.6/src/stream/ngx_stream_realip_module.c --- old/nginx-1.17.5/src/stream/ngx_stream_realip_module.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/stream/ngx_stream_realip_module.c 2019-11-19 15:18:58.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/nginx-1.17.5/src/stream/ngx_stream_variables.c new/nginx-1.17.6/src/stream/ngx_stream_variables.c --- old/nginx-1.17.5/src/stream/ngx_stream_variables.c 2019-10-22 17:16:08.000000000 +0200 +++ new/nginx-1.17.6/src/stream/ngx_stream_variables.c 2019-11-19 15:18:58.000000000 +0100 @@ -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;
