From mdounin at mdounin.ru Wed Jul 2 02:00:33 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Wed, 02 Jul 2025 05:00:33 +0300 Subject: [PATCH 1 of 2] Limit conn: fixed counter leak on memory allocation errors Message-ID: # HG changeset patch # User Maxim Dounin # Date 1751421418 -10800 # Wed Jul 02 04:56:58 2025 +0300 # Node ID be87e6012ac4fdea00597d075dcfe116beecdef2 # Parent 1588a8af97be86864f9c4da50d328527de14ae21 Limit conn: fixed counter leak on memory allocation errors. Previously, if ngx_pool_cleanup_add() failed, already incremented connection counter was left as is, eventually resulting in unexpected connection limiting or shared memory exhaustion. Fix is to decrement the counter by calling the cleanup handler with data on stack. diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -60,6 +60,8 @@ static ngx_rbtree_node_t *ngx_http_limit ngx_str_t *key, uint32_t hash); static void ngx_http_limit_conn_cleanup(void *data); static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node); static ngx_int_t ngx_http_limit_conn_status_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -294,6 +296,7 @@ ngx_http_limit_conn_handler(ngx_http_req cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_conn_cleanup_t)); if (cln == NULL) { + ngx_http_limit_conn_cleanup_node(limits[i].shm_zone, node); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -433,6 +436,19 @@ ngx_http_limit_conn_cleanup_all(ngx_pool } +static void +ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node) +{ + ngx_http_limit_conn_cleanup_t lccln; + + lccln.shm_zone = shm_zone; + lccln.node = node; + + ngx_http_limit_conn_cleanup(&lccln); +} + + static ngx_int_t ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) { diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c --- a/src/stream/ngx_stream_limit_conn_module.c +++ b/src/stream/ngx_stream_limit_conn_module.c @@ -59,6 +59,8 @@ static ngx_rbtree_node_t *ngx_stream_lim ngx_str_t *key, uint32_t hash); static void ngx_stream_limit_conn_cleanup(void *data); static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node); static ngx_int_t ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); @@ -274,6 +276,7 @@ ngx_stream_limit_conn_handler(ngx_stream cln = ngx_pool_cleanup_add(s->connection->pool, sizeof(ngx_stream_limit_conn_cleanup_t)); if (cln == NULL) { + ngx_stream_limit_conn_cleanup_node(limits[i].shm_zone, node); return NGX_ERROR; } @@ -414,6 +417,19 @@ ngx_stream_limit_conn_cleanup_all(ngx_po } +static void +ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node) +{ + ngx_stream_limit_conn_cleanup_t lccln; + + lccln.shm_zone = shm_zone; + lccln.node = node; + + ngx_stream_limit_conn_cleanup(&lccln); +} + + static ngx_int_t ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) { From mdounin at mdounin.ru Wed Jul 2 02:00:34 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Wed, 02 Jul 2025 05:00:34 +0300 Subject: [PATCH 2 of 2] Mail: limit_conn module In-Reply-To: References: Message-ID: <51e61f74584c40b0b316.1751421634@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1751421436 -10800 # Wed Jul 02 04:57:16 2025 +0300 # Node ID 51e61f74584c40b0b3164b15491804ec8976432e # Parent be87e6012ac4fdea00597d075dcfe116beecdef2 Mail: limit_conn module. The limit_conn module limits connections after auth_http authentication, so it can use the user name updated by the authentication server, and headers returned by the authentication server. Mostly usable to limit number of connections from a particular authenticated client. Configuration is similar to the one in HTTP, but since there are no variables in mail, limit_conn_zone can use the following restricted set of keys: - $remote_addr, client address; - $remote_user, user name supplied during authentication; - $auth_http_*, auth_http response header field. For example: limit_conn_zone $auth_http_limit_key zone=one:1m; limit_conn one 10; If the limit is hit, the following errors are returned for IMAP, POP3, and SMTP (and the connection is closed): NO [UNAVAILABLE] Too many connections -ERR [SYS/TEMP] Too many connections 454 4.7.0 Too many connections For IMAP, the "[UNAVAILABLE]" response code (RFC 5530) is used. For POP3, the "[SYS/TEMP]" extended response code (RFC 2449, RFC 3206) is used, and the default capabilities list is updated with RESP-CODES to ensure that extended response codes can be properly recognized by clients. At least Apple Mail (both on macOS and iOS) is able to recognize the response codes being used, and won't show password prompt if the limit is hit. Still, many clients won't be able to. In particular, Thunderbird is known to show a generic error dialog with options to try again or enter a new password, and Outlook always asks for a new password. As such, it is not recommended to configure limits which are low enough to be hit by well-behaving clients. diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -1032,6 +1032,12 @@ if [ $MAIL != NO ]; then ngx_module_srcs=src/mail/ngx_mail_realip_module.c . auto/module + + ngx_module_name=ngx_mail_limit_conn_module + ngx_module_deps= + ngx_module_srcs=src/mail/ngx_mail_limit_conn_module.c + + . auto/module fi diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -449,7 +449,10 @@ char *ngx_mail_capabilities(ngx_conf_t * /* STUB */ void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer); void ngx_mail_auth_http_init(ngx_mail_session_t *s); +ngx_int_t ngx_mail_auth_http_header_value(ngx_mail_session_t *s, + ngx_str_t *name, ngx_str_t *value); ngx_int_t ngx_mail_realip_handler(ngx_mail_session_t *s); +ngx_int_t ngx_mail_limit_conn_handler(ngx_mail_session_t *s); /**/ diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -57,6 +57,8 @@ struct ngx_mail_auth_http_ctx_s { time_t sleep; + ngx_list_t headers; + ngx_pool_t *pool; }; @@ -196,6 +198,14 @@ ngx_mail_auth_http_init(ngx_mail_session return; } + if (ngx_list_init(&ctx->headers, pool, 8, sizeof(ngx_table_elt_t)) + != NGX_OK) + { + ngx_destroy_pool(ctx->pool); + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module); ctx->peer.sockaddr = ahcf->peer->sockaddr; @@ -467,11 +477,12 @@ static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, ngx_mail_auth_http_ctx_t *ctx) { - u_char *p; - time_t timer; - size_t len, size; - ngx_int_t rc, port, n; - ngx_addr_t *peer; + u_char *p; + time_t timer; + size_t len, size; + ngx_int_t rc, port, n; + ngx_addr_t *peer; + ngx_table_elt_t *h; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http process headers"); @@ -481,20 +492,24 @@ ngx_mail_auth_http_process_headers(ngx_m if (rc == NGX_OK) { -#if (NGX_DEBUG) - { - ngx_str_t key, value; + /* a header line has been parsed successfully */ - key.len = ctx->header_name_end - ctx->header_name_start; - key.data = ctx->header_name_start; - value.len = ctx->header_end - ctx->header_start; - value.data = ctx->header_start; + h = ngx_list_push(&ctx->headers); + if (h == NULL) { + ngx_close_connection(ctx->peer.connection); + ngx_destroy_pool(ctx->pool); + ngx_mail_session_internal_server_error(s); + return; + } + + h->key.len = ctx->header_name_end - ctx->header_name_start; + h->key.data = ctx->header_name_start; + h->value.len = ctx->header_end - ctx->header_start; + h->value.data = ctx->header_start; ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http header: \"%V: %V\"", - &key, &value); - } -#endif + &h->key, &h->value); len = ctx->header_name_end - ctx->header_name_start; @@ -881,6 +896,13 @@ ngx_mail_auth_http_process_headers(ngx_m ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len); + /* check connection limits */ + + if (ngx_mail_limit_conn_handler(s) != NGX_OK) { + ngx_destroy_pool(ctx->pool); + return; + } + ngx_destroy_pool(ctx->pool); ngx_mail_proxy_init(s, peer); @@ -1590,6 +1612,107 @@ ngx_mail_auth_http_escape(ngx_pool_t *po } +ngx_int_t +ngx_mail_auth_http_header_value(ngx_mail_session_t *s, ngx_str_t *name, + ngx_str_t *value) +{ + u_char *p, ch; + size_t len; + ngx_uint_t i, n; + ngx_list_part_t *part; + ngx_table_elt_t *header, *h, **ph; + ngx_mail_auth_http_ctx_t *ctx; + + ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module); + + ph = &h; + len = 0; + + part = &ctx->headers.part; + header = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].key.len != name->len) { + continue; + } + + for (n = 0; n < name->len; n++) { + ch = header[i].key.data[n]; + + if (ch >= 'A' && ch <= 'Z') { + ch |= 0x20; + + } else if (ch == '-') { + ch = '_'; + } + + if (name->data[n] != ch) { + break; + } + } + + + if (n != name->len) { + continue; + } + + len += header[i].value.len + 2; + + *ph = &header[i]; + ph = &header[i].next; + } + + *ph = NULL; + + if (h == NULL) { + value->len = 0; + value->data = NULL; + return NGX_OK; + } + + len -= 2; + + if (h->next == NULL) { + *value = h->value; + return NGX_OK; + } + + p = ngx_pnalloc(ctx->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + value->len = len; + value->data = p; + + for ( ;; ) { + + p = ngx_copy(p, h->value.data, h->value.len); + + if (h->next == NULL) { + break; + } + + *p++ = ','; *p++ = ' '; + + h = h->next; + } + + return NGX_OK; +} + + static void * ngx_mail_auth_http_create_conf(ngx_conf_t *cf) { diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/mail/ngx_mail_limit_conn_module.c copy from src/http/modules/ngx_http_limit_conn_module.c copy to src/mail/ngx_mail_limit_conn_module.c --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/mail/ngx_mail_limit_conn_module.c @@ -1,18 +1,19 @@ /* * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin * Copyright (C) Nginx, Inc. */ #include #include -#include +#include -#define NGX_HTTP_LIMIT_CONN_PASSED 1 -#define NGX_HTTP_LIMIT_CONN_REJECTED 2 -#define NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN 3 +#define NGX_MAIL_LIMIT_CONN_REMOTE_USER 1 +#define NGX_MAIL_LIMIT_CONN_REMOTE_ADDR 2 +#define NGX_MAIL_LIMIT_CONN_AUTH_HTTP 3 typedef struct { @@ -20,63 +21,62 @@ typedef struct { u_char len; u_short conn; u_char data[1]; -} ngx_http_limit_conn_node_t; +} ngx_mail_limit_conn_node_t; typedef struct { ngx_shm_zone_t *shm_zone; ngx_rbtree_node_t *node; -} ngx_http_limit_conn_cleanup_t; +} ngx_mail_limit_conn_cleanup_t; typedef struct { ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; -} ngx_http_limit_conn_shctx_t; +} ngx_mail_limit_conn_shctx_t; typedef struct { - ngx_http_limit_conn_shctx_t *sh; + ngx_mail_limit_conn_shctx_t *sh; ngx_slab_pool_t *shpool; - ngx_http_complex_value_t key; -} ngx_http_limit_conn_ctx_t; + ngx_str_t key; + ngx_uint_t key_type; +} ngx_mail_limit_conn_ctx_t; typedef struct { ngx_shm_zone_t *shm_zone; ngx_uint_t conn; -} ngx_http_limit_conn_limit_t; +} ngx_mail_limit_conn_limit_t; typedef struct { 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; +} ngx_mail_limit_conn_conf_t; -static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, +static ngx_int_t ngx_mail_limit_conn_key(ngx_mail_session_t *s, + ngx_mail_limit_conn_ctx_t *ctx, ngx_str_t *key); +static void ngx_mail_limit_conn_send_error(ngx_mail_session_t *s); +static ngx_rbtree_node_t *ngx_mail_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash); -static void ngx_http_limit_conn_cleanup(void *data); -static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); -static void ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, +static void ngx_mail_limit_conn_cleanup(void *data); +static ngx_inline void ngx_mail_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_mail_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, ngx_rbtree_node_t *node); -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, +static void *ngx_mail_limit_conn_create_conf(ngx_conf_t *cf); +static char *ngx_mail_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, +static char *ngx_mail_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, +static char *ngx_mail_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); -static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { +static ngx_conf_enum_t ngx_mail_limit_conn_log_levels[] = { { ngx_string("info"), NGX_LOG_INFO }, { ngx_string("notice"), NGX_LOG_NOTICE }, { ngx_string("warn"), NGX_LOG_WARN }, @@ -85,72 +85,56 @@ static ngx_conf_enum_t ngx_http_limit_c }; -static ngx_conf_num_bounds_t ngx_http_limit_conn_status_bounds = { - ngx_conf_check_num_bounds, 400, 599 -}; - - -static ngx_command_t ngx_http_limit_conn_commands[] = { +static ngx_command_t ngx_mail_limit_conn_commands[] = { { ngx_string("limit_conn_zone"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, - ngx_http_limit_conn_zone, + NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE2, + ngx_mail_limit_conn_zone, 0, 0, NULL }, { ngx_string("limit_conn"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_http_limit_conn, - NGX_HTTP_LOC_CONF_OFFSET, + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2, + ngx_mail_limit_conn, + NGX_MAIL_SRV_CONF_OFFSET, 0, NULL }, { ngx_string("limit_conn_log_level"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_limit_conn_conf_t, log_level), - &ngx_http_limit_conn_log_levels }, - - { ngx_string("limit_conn_status"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_limit_conn_conf_t, status_code), - &ngx_http_limit_conn_status_bounds }, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_limit_conn_conf_t, log_level), + &ngx_mail_limit_conn_log_levels }, { ngx_string("limit_conn_dry_run"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_limit_conn_conf_t, dry_run), + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_limit_conn_conf_t, dry_run), NULL }, ngx_null_command }; -static ngx_http_module_t ngx_http_limit_conn_module_ctx = { - ngx_http_limit_conn_add_variables, /* preconfiguration */ - ngx_http_limit_conn_init, /* postconfiguration */ +static ngx_mail_module_t ngx_mail_limit_conn_module_ctx = { + NULL, /* protocol */ NULL, /* create main configuration */ NULL, /* init main configuration */ - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_limit_conn_create_conf, /* create location configuration */ - ngx_http_limit_conn_merge_conf /* merge location configuration */ + ngx_mail_limit_conn_create_conf, /* create server configuration */ + ngx_mail_limit_conn_merge_conf /* merge server configuration */ }; -ngx_module_t ngx_http_limit_conn_module = { +ngx_module_t ngx_mail_limit_conn_module = { NGX_MODULE_V1, - &ngx_http_limit_conn_module_ctx, /* module context */ - ngx_http_limit_conn_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ + &ngx_mail_limit_conn_module_ctx, /* module context */ + ngx_mail_limit_conn_commands, /* module directives */ + NGX_MAIL_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ @@ -162,24 +146,13 @@ ngx_module_t ngx_http_limit_conn_module }; -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 u_char pop3_error[] = "-ERR [SYS/TEMP] Too many connections" CRLF; +static u_char imap_error[] = "NO [UNAVAILABLE] Too many connections" CRLF; +static u_char smtp_error[] = "454 4.7.0 Too many connections" CRLF; -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) +ngx_int_t +ngx_mail_limit_conn_handler(ngx_mail_session_t *s) { size_t n; uint32_t hash; @@ -187,24 +160,23 @@ ngx_http_limit_conn_handler(ngx_http_req ngx_uint_t i; ngx_rbtree_node_t *node; ngx_pool_cleanup_t *cln; - ngx_http_limit_conn_ctx_t *ctx; - ngx_http_limit_conn_node_t *lc; - ngx_http_limit_conn_conf_t *lccf; - ngx_http_limit_conn_limit_t *limits; - ngx_http_limit_conn_cleanup_t *lccln; + ngx_mail_limit_conn_ctx_t *ctx; + ngx_mail_limit_conn_node_t *lc; + ngx_mail_limit_conn_conf_t *lccf; + ngx_mail_limit_conn_limit_t *limits; + ngx_mail_limit_conn_cleanup_t *lccln; - if (r->main->limit_conn_status) { - return NGX_DECLINED; - } + s->connection->log->action = NULL; - lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module); + lccf = ngx_mail_get_module_srv_conf(s, ngx_mail_limit_conn_module); limits = lccf->limits.elts; for (i = 0; i < lccf->limits.nelts; i++) { ctx = limits[i].shm_zone->data; - if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (ngx_mail_limit_conn_key(s, ctx, &key) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return NGX_ERROR; } if (key.len == 0) { @@ -212,45 +184,40 @@ ngx_http_limit_conn_handler(ngx_http_req } if (key.len > 255) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "the value of the \"%V\" key " "is more than 255 bytes: \"%V\"", - &ctx->key.value, &key); + &ctx->key, &key); continue; } - r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_PASSED; - hash = ngx_crc32_short(key.data, key.len); ngx_shmtx_lock(&ctx->shpool->mutex); - node = ngx_http_limit_conn_lookup(&ctx->sh->rbtree, &key, hash); + node = ngx_mail_limit_conn_lookup(&ctx->sh->rbtree, &key, hash); if (node == NULL) { n = offsetof(ngx_rbtree_node_t, color) - + offsetof(ngx_http_limit_conn_node_t, data) + + offsetof(ngx_mail_limit_conn_node_t, data) + key.len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); - ngx_http_limit_conn_cleanup_all(r->pool); + ngx_mail_limit_conn_cleanup_all(s->connection->pool); if (lccf->dry_run) { - r->main->limit_conn_status = - NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN; - return NGX_DECLINED; + return NGX_OK; } - r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED; - - return lccf->status_code; + ngx_mail_session_internal_server_error(s); + return NGX_ERROR; } - lc = (ngx_http_limit_conn_node_t *) &node->color; + lc = (ngx_mail_limit_conn_node_t *) &node->color; node->key = hash; lc->len = (u_char) key.len; @@ -261,62 +228,135 @@ ngx_http_limit_conn_handler(ngx_http_req } else { - lc = (ngx_http_limit_conn_node_t *) &node->color; + lc = (ngx_mail_limit_conn_node_t *) &node->color; if ((ngx_uint_t) lc->conn >= limits[i].conn) { ngx_shmtx_unlock(&ctx->shpool->mutex); - ngx_log_error(lccf->log_level, r->connection->log, 0, + ngx_log_error(lccf->log_level, s->connection->log, 0, "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); + ngx_mail_limit_conn_cleanup_all(s->connection->pool); if (lccf->dry_run) { - r->main->limit_conn_status = - NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN; - return NGX_DECLINED; + return NGX_OK; } - r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED; - - return lccf->status_code; + ngx_mail_limit_conn_send_error(s); + return NGX_BUSY; } lc->conn++; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "limit conn: %08Xi %d", node->key, lc->conn); ngx_shmtx_unlock(&ctx->shpool->mutex); - cln = ngx_pool_cleanup_add(r->pool, - sizeof(ngx_http_limit_conn_cleanup_t)); + cln = ngx_pool_cleanup_add(s->connection->pool, + sizeof(ngx_mail_limit_conn_cleanup_t)); if (cln == NULL) { - ngx_http_limit_conn_cleanup_node(limits[i].shm_zone, node); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + ngx_mail_limit_conn_cleanup_node(limits[i].shm_zone, node); + ngx_mail_session_internal_server_error(s); + return NGX_ERROR; } - cln->handler = ngx_http_limit_conn_cleanup; + cln->handler = ngx_mail_limit_conn_cleanup; lccln = cln->data; lccln->shm_zone = limits[i].shm_zone; lccln->node = node; } - return NGX_DECLINED; + return NGX_OK; +} + + +static ngx_int_t +ngx_mail_limit_conn_key(ngx_mail_session_t *s, ngx_mail_limit_conn_ctx_t *ctx, + ngx_str_t *key) +{ + ngx_str_t name; + + switch (ctx->key_type) { + + case NGX_MAIL_LIMIT_CONN_REMOTE_USER: + *key = s->login; + break; + + case NGX_MAIL_LIMIT_CONN_REMOTE_ADDR: + *key = s->connection->addr_text; + break; + + case NGX_MAIL_LIMIT_CONN_AUTH_HTTP: + + name.len = ctx->key.len - (sizeof("$auth_http_") - 1); + name.data = ctx->key.data + (sizeof("$auth_http_") - 1); + + if (ngx_mail_auth_http_header_value(s, &name, key) != NGX_OK) { + return NGX_ERROR; + } + + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, + "limit conn key: \"%V\"", key); + + return NGX_OK; } static void -ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp, +ngx_mail_limit_conn_send_error(ngx_mail_session_t *s) +{ + u_char *p, *err; + size_t len; + + switch (s->protocol) { + + case NGX_MAIL_POP3_PROTOCOL: + ngx_str_set(&s->out, pop3_error); + break; + + case NGX_MAIL_IMAP_PROTOCOL: + len = s->tag.len + sizeof(imap_error) - 1; + + err = ngx_pnalloc(s->connection->pool, len); + if (err == NULL) { + ngx_mail_session_internal_server_error(s); + return; + } + + p = ngx_cpymem(err, s->tag.data, s->tag.len); + ngx_memcpy(p, imap_error, sizeof(imap_error) - 1); + + s->out.len = len; + s->out.data = err; + + break; + + default: /* NGX_MAIL_SMTP_PROTOCOL */ + ngx_str_set(&s->out, smtp_error); + break; + } + + s->quit = 1; + + ngx_mail_send(s->connection->write); +} + + +static void +ngx_mail_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { ngx_rbtree_node_t **p; - ngx_http_limit_conn_node_t *lcn, *lcnt; + ngx_mail_limit_conn_node_t *lcn, *lcnt; for ( ;; ) { @@ -330,8 +370,8 @@ ngx_http_limit_conn_rbtree_insert_value( } else { /* node->key == temp->key */ - lcn = (ngx_http_limit_conn_node_t *) &node->color; - lcnt = (ngx_http_limit_conn_node_t *) &temp->color; + lcn = (ngx_mail_limit_conn_node_t *) &node->color; + lcnt = (ngx_mail_limit_conn_node_t *) &temp->color; p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 0) ? &temp->left : &temp->right; @@ -353,11 +393,11 @@ ngx_http_limit_conn_rbtree_insert_value( static ngx_rbtree_node_t * -ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash) +ngx_mail_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash) { ngx_int_t rc; ngx_rbtree_node_t *node, *sentinel; - ngx_http_limit_conn_node_t *lcn; + ngx_mail_limit_conn_node_t *lcn; node = rbtree->root; sentinel = rbtree->sentinel; @@ -376,7 +416,7 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t /* hash == node->key */ - lcn = (ngx_http_limit_conn_node_t *) &node->color; + lcn = (ngx_mail_limit_conn_node_t *) &node->color; rc = ngx_memn2cmp(key->data, lcn->data, key->len, (size_t) lcn->len); @@ -392,21 +432,21 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t static void -ngx_http_limit_conn_cleanup(void *data) +ngx_mail_limit_conn_cleanup(void *data) { - ngx_http_limit_conn_cleanup_t *lccln = data; + ngx_mail_limit_conn_cleanup_t *lccln = data; ngx_rbtree_node_t *node; - ngx_http_limit_conn_ctx_t *ctx; - ngx_http_limit_conn_node_t *lc; + ngx_mail_limit_conn_ctx_t *ctx; + ngx_mail_limit_conn_node_t *lc; ctx = lccln->shm_zone->data; node = lccln->node; - lc = (ngx_http_limit_conn_node_t *) &node->color; + lc = (ngx_mail_limit_conn_node_t *) &node->color; ngx_shmtx_lock(&ctx->shpool->mutex); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, lccln->shm_zone->shm.log, 0, "limit conn cleanup: %08Xi %d", node->key, lc->conn); lc->conn--; @@ -421,14 +461,14 @@ ngx_http_limit_conn_cleanup(void *data) static ngx_inline void -ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool) +ngx_mail_limit_conn_cleanup_all(ngx_pool_t *pool) { ngx_pool_cleanup_t *cln; cln = pool->cleanup; - while (cln && cln->handler == ngx_http_limit_conn_cleanup) { - ngx_http_limit_conn_cleanup(cln->data); + while (cln && cln->handler == ngx_mail_limit_conn_cleanup) { + ngx_mail_limit_conn_cleanup(cln->data); cln = cln->next; } @@ -437,39 +477,39 @@ ngx_http_limit_conn_cleanup_all(ngx_pool static void -ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, +ngx_mail_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, ngx_rbtree_node_t *node) { - ngx_http_limit_conn_cleanup_t lccln; + ngx_mail_limit_conn_cleanup_t lccln; lccln.shm_zone = shm_zone; lccln.node = node; - ngx_http_limit_conn_cleanup(&lccln); + ngx_mail_limit_conn_cleanup(&lccln); } static ngx_int_t -ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) +ngx_mail_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) { - ngx_http_limit_conn_ctx_t *octx = data; + ngx_mail_limit_conn_ctx_t *octx = data; size_t len; - ngx_http_limit_conn_ctx_t *ctx; + ngx_mail_limit_conn_ctx_t *ctx; ctx = shm_zone->data; if (octx) { - if (ctx->key.value.len != octx->key.value.len - || ngx_strncmp(ctx->key.value.data, octx->key.value.data, - ctx->key.value.len) + if (ctx->key.len != octx->key.len + || ngx_strncmp(ctx->key.data, octx->key.data, + ctx->key.len) != 0) { ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "limit_conn_zone \"%V\" uses the \"%V\" key " "while previously it used the \"%V\" key", - &shm_zone->shm.name, &ctx->key.value, - &octx->key.value); + &shm_zone->shm.name, &ctx->key, + &octx->key); return NGX_ERROR; } @@ -487,7 +527,7 @@ ngx_http_limit_conn_init_zone(ngx_shm_zo return NGX_OK; } - ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_conn_shctx_t)); + ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_mail_limit_conn_shctx_t)); if (ctx->sh == NULL) { return NGX_ERROR; } @@ -495,7 +535,7 @@ ngx_http_limit_conn_init_zone(ngx_shm_zo ctx->shpool->data = ctx->sh; ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, - ngx_http_limit_conn_rbtree_insert_value); + ngx_mail_limit_conn_rbtree_insert_value); len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len; @@ -511,31 +551,12 @@ ngx_http_limit_conn_init_zone(ngx_shm_zo } -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_mail_limit_conn_create_conf(ngx_conf_t *cf) { - if (r->main->limit_conn_status == 0) { - v->not_found = 1; - return NGX_OK; - } + ngx_mail_limit_conn_conf_t *conf; - 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) -{ - ngx_http_limit_conn_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_conf_t)); + conf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_limit_conn_conf_t)); if (conf == NULL) { return NULL; } @@ -547,7 +568,6 @@ ngx_http_limit_conn_create_conf(ngx_conf */ conf->log_level = NGX_CONF_UNSET_UINT; - conf->status_code = NGX_CONF_UNSET_UINT; conf->dry_run = NGX_CONF_UNSET; return conf; @@ -555,19 +575,16 @@ ngx_http_limit_conn_create_conf(ngx_conf static char * -ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child) +ngx_mail_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child) { - ngx_http_limit_conn_conf_t *prev = parent; - ngx_http_limit_conn_conf_t *conf = child; + ngx_mail_limit_conn_conf_t *prev = parent; + ngx_mail_limit_conn_conf_t *conf = child; if (conf->limits.elts == NULL) { conf->limits = prev->limits; } ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); - 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; @@ -575,30 +592,37 @@ ngx_http_limit_conn_merge_conf(ngx_conf_ static char * -ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_mail_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *p; - ssize_t size; - ngx_str_t *value, name, s; - ngx_uint_t i; - ngx_shm_zone_t *shm_zone; - ngx_http_limit_conn_ctx_t *ctx; - ngx_http_compile_complex_value_t ccv; + u_char *p; + ssize_t size; + ngx_str_t *value, name, s; + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_mail_limit_conn_ctx_t *ctx; value = cf->args->elts; - ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t)); + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_limit_conn_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + if (ngx_strcmp(value[1].data, "$remote_user") == 0) { + ctx->key = value[1]; + ctx->key_type = NGX_MAIL_LIMIT_CONN_REMOTE_USER; + + } else if (ngx_strcmp(value[1].data, "$remote_addr") == 0) { + ctx->key = value[1]; + ctx->key_type = NGX_MAIL_LIMIT_CONN_REMOTE_ADDR; - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = &ctx->key; + } else if (ngx_strncmp(value[1].data, "$auth_http_", 11) == 0) { + ctx->key = value[1]; + ctx->key_type = NGX_MAIL_LIMIT_CONN_AUTH_HTTP; - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); return NGX_CONF_ERROR; } @@ -654,7 +678,7 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, } shm_zone = ngx_shared_memory_add(cf, &name, size, - &ngx_http_limit_conn_module); + &ngx_mail_limit_conn_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } @@ -664,11 +688,11 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V \"%V\" is already bound to key \"%V\"", - &cmd->name, &name, &ctx->key.value); + &cmd->name, &name, &ctx->key); return NGX_CONF_ERROR; } - shm_zone->init = ngx_http_limit_conn_init_zone; + shm_zone->init = ngx_mail_limit_conn_init_zone; shm_zone->data = ctx; return NGX_CONF_OK; @@ -676,11 +700,11 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, static char * -ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_mail_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_shm_zone_t *shm_zone; - ngx_http_limit_conn_conf_t *lccf = conf; - ngx_http_limit_conn_limit_t *limit, *limits; + ngx_mail_limit_conn_conf_t *lccf = conf; + ngx_mail_limit_conn_limit_t *limit, *limits; ngx_str_t *value; ngx_int_t n; @@ -689,7 +713,7 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_ value = cf->args->elts; shm_zone = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_limit_conn_module); + &ngx_mail_limit_conn_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } @@ -698,7 +722,7 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_ if (limits == NULL) { if (ngx_array_init(&lccf->limits, cf->pool, 1, - sizeof(ngx_http_limit_conn_limit_t)) + sizeof(ngx_mail_limit_conn_limit_t)) != NGX_OK) { return NGX_CONF_ERROR; @@ -734,41 +758,3 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_ return NGX_CONF_OK; } - - -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; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_limit_conn_handler; - - return NGX_OK; -} diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -21,6 +21,7 @@ static ngx_str_t ngx_mail_pop3_default_ ngx_string("TOP"), ngx_string("USER"), ngx_string("UIDL"), + ngx_string("RESP-CODES"), ngx_null_string }; From mdounin at mdounin.ru Wed Jul 2 04:48:39 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Wed, 02 Jul 2025 07:48:39 +0300 Subject: [PATCH] Added nginx_is_free macro to simplify version detection Message-ID: <3da75a6d4086f48211fa.1751431719@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1751431259 -10800 # Wed Jul 02 07:40:59 2025 +0300 # Node ID 3da75a6d4086f48211fa2fbdd1538b5ebedc21bb # Parent 51e61f74584c40b0b3164b15491804ec8976432e Added nginx_is_free macro to simplify version detection. diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -12,6 +12,8 @@ #define nginx_version 1029000 #define NGINX_VERSION "1.29.0" +#define nginx_is_free 1 + #define NGINX_NAME "freenginx" #define NGINX_VER NGINX_NAME "/" NGINX_VERSION From mdounin at mdounin.ru Wed Jul 2 15:42:39 2025 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 2 Jul 2025 18:42:39 +0300 Subject: [PATCH] Added nginx_is_free macro to simplify version detection In-Reply-To: <3da75a6d4086f48211fa.1751431719@vm-bsd.mdounin.ru> References: <3da75a6d4086f48211fa.1751431719@vm-bsd.mdounin.ru> Message-ID: Hello! On Wed, Jul 02, 2025 at 07:48:39AM +0300, Maxim Dounin wrote: > # HG changeset patch > # User Maxim Dounin > # Date 1751431259 -10800 > # Wed Jul 02 07:40:59 2025 +0300 > # Node ID 3da75a6d4086f48211fa2fbdd1538b5ebedc21bb > # Parent 51e61f74584c40b0b3164b15491804ec8976432e > Added nginx_is_free macro to simplify version detection. > > diff --git a/src/core/nginx.h b/src/core/nginx.h > --- a/src/core/nginx.h > +++ b/src/core/nginx.h > @@ -12,6 +12,8 @@ > #define nginx_version 1029000 > #define NGINX_VERSION "1.29.0" > > +#define nginx_is_free 1 > + > #define NGINX_NAME "freenginx" > #define NGINX_VER NGINX_NAME "/" NGINX_VERSION > > Looking more into this, I tend to think that probably "freenginx" would be a better name for the macro. As such, relevant version detection for modules which want to be compatible with both freenginx and F5 NGINX would, for example, following ngx_http_request_t change from start_sec / start_msec to start_time in 9379:2edfdf15f9b4, would be: #if (defined freenginx && nginx_version >= 1029000) ... use r->start_time #else ... use r->start_sec #endif Updated patch: # HG changeset patch # User Maxim Dounin # Date 1751470888 -10800 # Wed Jul 02 18:41:28 2025 +0300 # Node ID 57344996566867d9843671cfd413ce51d3c4d507 # Parent 51e61f74584c40b0b3164b15491804ec8976432e Added freenginx macro to simplify version detection. For modules which want to be compatible with both freenginx and F5 NGINX relevant version detection for the r->start_time change in 9379:2edfdf15f9b4 would look like: #if (defined freenginx && nginx_version >= 1029000) ... use r->start_time #else ... use r->start_sec #endif Requested by Georgy Shelkovy, https://github.com/freenginx/nginx/issues/12 diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -12,6 +12,8 @@ #define nginx_version 1029000 #define NGINX_VERSION "1.29.0" +#define freenginx 1 + #define NGINX_NAME "freenginx" #define NGINX_VER NGINX_NAME "/" NGINX_VERSION -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Thu Jul 3 04:45:48 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Thu, 03 Jul 2025 07:45:48 +0300 Subject: [nginx] Added freenginx macro to simplify version detection. Message-ID: details: http://freenginx.org/hg/nginx/rev/a1dd1c5d8e86 branches: changeset: 9387:a1dd1c5d8e86 user: Maxim Dounin date: Thu Jul 03 07:44:39 2025 +0300 description: Added freenginx macro to simplify version detection. For modules which want to be compatible with both freenginx and F5 NGINX relevant version detection for the r->start_time change in 9379:2edfdf15f9b4 would look like: #if (defined freenginx && nginx_version >= 1029000) ... use r->start_time #else ... use r->start_sec #endif Requested by Georgy Shelkovy, https://github.com/freenginx/nginx/issues/12 diffstat: src/core/nginx.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (12 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -12,6 +12,8 @@ #define nginx_version 1029000 #define NGINX_VERSION "1.29.0" +#define freenginx 1 + #define NGINX_NAME "freenginx" #define NGINX_VER NGINX_NAME "/" NGINX_VERSION From mdounin at mdounin.ru Thu Jul 3 17:34:06 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 03 Jul 2025 20:34:06 +0300 Subject: [PATCH] Fixed use-after-free on exit with error logging rate limiting Message-ID: <2a0e8ad40bbae617e633.1751564046@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1751526252 -10800 # Thu Jul 03 10:04:12 2025 +0300 # Node ID 2a0e8ad40bbae617e6339627dcbe3895c93bcf45 # Parent a1dd1c5d8e862723fd4850464da851228ff9d95c Fixed use-after-free on exit with error logging rate limiting. Error logging rate limiting as introduced in 9299:2706b60dc225 (1.27.2) wasn't disabled for exit-time logging, and the log->limit structure for the default file log, which is allocated from the cycle pool, was accessed during logging after the cycle pool was destroyed. Notably, this resulted in segmentation faults on worker process exit on Alpine Linux. Fix is to explicitly clear ngx_exit_log.limit for exit-time logging. diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -684,6 +684,7 @@ ngx_master_process_exit(ngx_cycle_t *cyc ngx_exit_log.file = &ngx_exit_log_file; ngx_exit_log.next = NULL; ngx_exit_log.writer = NULL; + ngx_exit_log.limit = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; @@ -984,6 +985,7 @@ ngx_worker_process_exit(ngx_cycle_t *cyc ngx_exit_log.file = &ngx_exit_log_file; ngx_exit_log.next = NULL; ngx_exit_log.writer = NULL; + ngx_exit_log.limit = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; From mdounin at mdounin.ru Fri Jul 4 23:45:28 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 05 Jul 2025 02:45:28 +0300 Subject: [nginx] Fixed use-after-free on exit with error logging rate lim... Message-ID: details: http://freenginx.org/hg/nginx/rev/2a0e8ad40bba branches: changeset: 9388:2a0e8ad40bba user: Maxim Dounin date: Thu Jul 03 10:04:12 2025 +0300 description: Fixed use-after-free on exit with error logging rate limiting. Error logging rate limiting as introduced in 9299:2706b60dc225 (1.27.2) wasn't disabled for exit-time logging, and the log->limit structure for the default file log, which is allocated from the cycle pool, was accessed during logging after the cycle pool was destroyed. Notably, this resulted in segmentation faults on worker process exit on Alpine Linux. Fix is to explicitly clear ngx_exit_log.limit for exit-time logging. diffstat: src/os/unix/ngx_process_cycle.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (19 lines): diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -684,6 +684,7 @@ ngx_master_process_exit(ngx_cycle_t *cyc ngx_exit_log.file = &ngx_exit_log_file; ngx_exit_log.next = NULL; ngx_exit_log.writer = NULL; + ngx_exit_log.limit = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; @@ -984,6 +985,7 @@ ngx_worker_process_exit(ngx_cycle_t *cyc ngx_exit_log.file = &ngx_exit_log_file; ngx_exit_log.next = NULL; ngx_exit_log.writer = NULL; + ngx_exit_log.limit = NULL; ngx_exit_cycle.log = &ngx_exit_log; ngx_exit_cycle.files = ngx_cycle->files; From mdounin at mdounin.ru Mon Jul 7 04:29:40 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:29:40 +0300 Subject: [nginx] Limit conn: fixed counter leak on memory allocation errors. Message-ID: details: http://freenginx.org/hg/nginx/rev/722e252fcabe branches: changeset: 9389:722e252fcabe user: Maxim Dounin date: Mon Jul 07 04:34:18 2025 +0300 description: Limit conn: fixed counter leak on memory allocation errors. Previously, if ngx_pool_cleanup_add() failed, already incremented connection counter was left as is, eventually resulting in unexpected connection limiting or shared memory exhaustion. Fix is to decrement the counter by calling the cleanup handler with data on stack. diffstat: src/http/modules/ngx_http_limit_conn_module.c | 16 ++++++++++++++++ src/stream/ngx_stream_limit_conn_module.c | 16 ++++++++++++++++ 2 files changed, 32 insertions(+), 0 deletions(-) diffs (80 lines): diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -60,6 +60,8 @@ static ngx_rbtree_node_t *ngx_http_limit ngx_str_t *key, uint32_t hash); static void ngx_http_limit_conn_cleanup(void *data); static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node); static ngx_int_t ngx_http_limit_conn_status_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -294,6 +296,7 @@ ngx_http_limit_conn_handler(ngx_http_req cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_conn_cleanup_t)); if (cln == NULL) { + ngx_http_limit_conn_cleanup_node(limits[i].shm_zone, node); return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -433,6 +436,19 @@ ngx_http_limit_conn_cleanup_all(ngx_pool } +static void +ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node) +{ + ngx_http_limit_conn_cleanup_t lccln; + + lccln.shm_zone = shm_zone; + lccln.node = node; + + ngx_http_limit_conn_cleanup(&lccln); +} + + static ngx_int_t ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) { diff --git a/src/stream/ngx_stream_limit_conn_module.c b/src/stream/ngx_stream_limit_conn_module.c --- a/src/stream/ngx_stream_limit_conn_module.c +++ b/src/stream/ngx_stream_limit_conn_module.c @@ -59,6 +59,8 @@ static ngx_rbtree_node_t *ngx_stream_lim ngx_str_t *key, uint32_t hash); static void ngx_stream_limit_conn_cleanup(void *data); static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node); static ngx_int_t ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); @@ -274,6 +276,7 @@ ngx_stream_limit_conn_handler(ngx_stream cln = ngx_pool_cleanup_add(s->connection->pool, sizeof(ngx_stream_limit_conn_cleanup_t)); if (cln == NULL) { + ngx_stream_limit_conn_cleanup_node(limits[i].shm_zone, node); return NGX_ERROR; } @@ -414,6 +417,19 @@ ngx_stream_limit_conn_cleanup_all(ngx_po } +static void +ngx_stream_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, + ngx_rbtree_node_t *node) +{ + ngx_stream_limit_conn_cleanup_t lccln; + + lccln.shm_zone = shm_zone; + lccln.node = node; + + ngx_stream_limit_conn_cleanup(&lccln); +} + + static ngx_int_t ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) { From mdounin at mdounin.ru Mon Jul 7 04:29:40 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:29:40 +0300 Subject: [nginx] Mail: limit_conn module. Message-ID: details: http://freenginx.org/hg/nginx/rev/9fa6118103ca branches: changeset: 9390:9fa6118103ca user: Maxim Dounin date: Mon Jul 07 04:34:22 2025 +0300 description: Mail: limit_conn module. The limit_conn module limits connections after auth_http authentication, so it can use the user name updated by the authentication server, and headers returned by the authentication server. Mostly usable to limit number of connections from a particular authenticated client. Configuration is similar to the one in HTTP, but since there are no variables in mail, limit_conn_zone can use the following restricted set of keys: - $remote_addr, client address; - $remote_user, user name supplied during authentication; - $auth_http_*, auth_http response header field. For example: limit_conn_zone $auth_http_limit_key zone=one:1m; limit_conn one 10; If the limit is hit, the following errors are returned for IMAP, POP3, and SMTP (and the connection is closed): NO [UNAVAILABLE] Too many connections -ERR [SYS/TEMP] Too many connections 454 4.7.0 Too many connections For IMAP, the "[UNAVAILABLE]" response code (RFC 5530) is used. For POP3, the "[SYS/TEMP]" extended response code (RFC 2449, RFC 3206) is used, and the default capabilities list is updated with RESP-CODES to ensure that extended response codes can be properly recognized by clients. At least Apple Mail (both on macOS and iOS) is able to recognize the response codes being used, and won't show password prompt if the limit is hit. Still, many clients won't be able to. In particular, Thunderbird is known to show a generic error dialog with options to try again or enter a new password, and Outlook always asks for a new password. As such, it is not recommended to configure limits which are low enough to be hit by well-behaving clients. diffstat: auto/modules | 6 + src/mail/ngx_mail.h | 3 + src/mail/ngx_mail_auth_http_module.c | 153 ++++++++++- src/mail/ngx_mail_limit_conn_module.c | 464 ++++++++++++++++----------------- src/mail/ngx_mail_pop3_module.c | 1 + 5 files changed, 373 insertions(+), 254 deletions(-) diffs (1091 lines): diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -1032,6 +1032,12 @@ if [ $MAIL != NO ]; then ngx_module_srcs=src/mail/ngx_mail_realip_module.c . auto/module + + ngx_module_name=ngx_mail_limit_conn_module + ngx_module_deps= + ngx_module_srcs=src/mail/ngx_mail_limit_conn_module.c + + . auto/module fi diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -449,7 +449,10 @@ char *ngx_mail_capabilities(ngx_conf_t * /* STUB */ void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer); void ngx_mail_auth_http_init(ngx_mail_session_t *s); +ngx_int_t ngx_mail_auth_http_header_value(ngx_mail_session_t *s, + ngx_str_t *name, ngx_str_t *value); ngx_int_t ngx_mail_realip_handler(ngx_mail_session_t *s); +ngx_int_t ngx_mail_limit_conn_handler(ngx_mail_session_t *s); /**/ diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -57,6 +57,8 @@ struct ngx_mail_auth_http_ctx_s { time_t sleep; + ngx_list_t headers; + ngx_pool_t *pool; }; @@ -196,6 +198,14 @@ ngx_mail_auth_http_init(ngx_mail_session return; } + if (ngx_list_init(&ctx->headers, pool, 8, sizeof(ngx_table_elt_t)) + != NGX_OK) + { + ngx_destroy_pool(ctx->pool); + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_set_ctx(s, ctx, ngx_mail_auth_http_module); ctx->peer.sockaddr = ahcf->peer->sockaddr; @@ -467,11 +477,12 @@ static void ngx_mail_auth_http_process_headers(ngx_mail_session_t *s, ngx_mail_auth_http_ctx_t *ctx) { - u_char *p; - time_t timer; - size_t len, size; - ngx_int_t rc, port, n; - ngx_addr_t *peer; + u_char *p; + time_t timer; + size_t len, size; + ngx_int_t rc, port, n; + ngx_addr_t *peer; + ngx_table_elt_t *h; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http process headers"); @@ -481,20 +492,24 @@ ngx_mail_auth_http_process_headers(ngx_m if (rc == NGX_OK) { -#if (NGX_DEBUG) - { - ngx_str_t key, value; + /* a header line has been parsed successfully */ - key.len = ctx->header_name_end - ctx->header_name_start; - key.data = ctx->header_name_start; - value.len = ctx->header_end - ctx->header_start; - value.data = ctx->header_start; + h = ngx_list_push(&ctx->headers); + if (h == NULL) { + ngx_close_connection(ctx->peer.connection); + ngx_destroy_pool(ctx->pool); + ngx_mail_session_internal_server_error(s); + return; + } + + h->key.len = ctx->header_name_end - ctx->header_name_start; + h->key.data = ctx->header_name_start; + h->value.len = ctx->header_end - ctx->header_start; + h->value.data = ctx->header_start; ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "mail auth http header: \"%V: %V\"", - &key, &value); - } -#endif + &h->key, &h->value); len = ctx->header_name_end - ctx->header_name_start; @@ -881,6 +896,13 @@ ngx_mail_auth_http_process_headers(ngx_m ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len); + /* check connection limits */ + + if (ngx_mail_limit_conn_handler(s) != NGX_OK) { + ngx_destroy_pool(ctx->pool); + return; + } + ngx_destroy_pool(ctx->pool); ngx_mail_proxy_init(s, peer); @@ -1590,6 +1612,107 @@ ngx_mail_auth_http_escape(ngx_pool_t *po } +ngx_int_t +ngx_mail_auth_http_header_value(ngx_mail_session_t *s, ngx_str_t *name, + ngx_str_t *value) +{ + u_char *p, ch; + size_t len; + ngx_uint_t i, n; + ngx_list_part_t *part; + ngx_table_elt_t *header, *h, **ph; + ngx_mail_auth_http_ctx_t *ctx; + + ctx = ngx_mail_get_module_ctx(s, ngx_mail_auth_http_module); + + ph = &h; + len = 0; + + part = &ctx->headers.part; + header = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].key.len != name->len) { + continue; + } + + for (n = 0; n < name->len; n++) { + ch = header[i].key.data[n]; + + if (ch >= 'A' && ch <= 'Z') { + ch |= 0x20; + + } else if (ch == '-') { + ch = '_'; + } + + if (name->data[n] != ch) { + break; + } + } + + + if (n != name->len) { + continue; + } + + len += header[i].value.len + 2; + + *ph = &header[i]; + ph = &header[i].next; + } + + *ph = NULL; + + if (h == NULL) { + value->len = 0; + value->data = NULL; + return NGX_OK; + } + + len -= 2; + + if (h->next == NULL) { + *value = h->value; + return NGX_OK; + } + + p = ngx_pnalloc(ctx->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + value->len = len; + value->data = p; + + for ( ;; ) { + + p = ngx_copy(p, h->value.data, h->value.len); + + if (h->next == NULL) { + break; + } + + *p++ = ','; *p++ = ' '; + + h = h->next; + } + + return NGX_OK; +} + + static void * ngx_mail_auth_http_create_conf(ngx_conf_t *cf) { diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/mail/ngx_mail_limit_conn_module.c copy from src/http/modules/ngx_http_limit_conn_module.c copy to src/mail/ngx_mail_limit_conn_module.c --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/mail/ngx_mail_limit_conn_module.c @@ -1,18 +1,19 @@ /* * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin * Copyright (C) Nginx, Inc. */ #include #include -#include +#include -#define NGX_HTTP_LIMIT_CONN_PASSED 1 -#define NGX_HTTP_LIMIT_CONN_REJECTED 2 -#define NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN 3 +#define NGX_MAIL_LIMIT_CONN_REMOTE_USER 1 +#define NGX_MAIL_LIMIT_CONN_REMOTE_ADDR 2 +#define NGX_MAIL_LIMIT_CONN_AUTH_HTTP 3 typedef struct { @@ -20,63 +21,62 @@ typedef struct { u_char len; u_short conn; u_char data[1]; -} ngx_http_limit_conn_node_t; +} ngx_mail_limit_conn_node_t; typedef struct { ngx_shm_zone_t *shm_zone; ngx_rbtree_node_t *node; -} ngx_http_limit_conn_cleanup_t; +} ngx_mail_limit_conn_cleanup_t; typedef struct { ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; -} ngx_http_limit_conn_shctx_t; +} ngx_mail_limit_conn_shctx_t; typedef struct { - ngx_http_limit_conn_shctx_t *sh; + ngx_mail_limit_conn_shctx_t *sh; ngx_slab_pool_t *shpool; - ngx_http_complex_value_t key; -} ngx_http_limit_conn_ctx_t; + ngx_str_t key; + ngx_uint_t key_type; +} ngx_mail_limit_conn_ctx_t; typedef struct { ngx_shm_zone_t *shm_zone; ngx_uint_t conn; -} ngx_http_limit_conn_limit_t; +} ngx_mail_limit_conn_limit_t; typedef struct { 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; +} ngx_mail_limit_conn_conf_t; -static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, +static ngx_int_t ngx_mail_limit_conn_key(ngx_mail_session_t *s, + ngx_mail_limit_conn_ctx_t *ctx, ngx_str_t *key); +static void ngx_mail_limit_conn_send_error(ngx_mail_session_t *s); +static ngx_rbtree_node_t *ngx_mail_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash); -static void ngx_http_limit_conn_cleanup(void *data); -static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); -static void ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, +static void ngx_mail_limit_conn_cleanup(void *data); +static ngx_inline void ngx_mail_limit_conn_cleanup_all(ngx_pool_t *pool); +static void ngx_mail_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, ngx_rbtree_node_t *node); -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, +static void *ngx_mail_limit_conn_create_conf(ngx_conf_t *cf); +static char *ngx_mail_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, +static char *ngx_mail_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, +static char *ngx_mail_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); -static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { +static ngx_conf_enum_t ngx_mail_limit_conn_log_levels[] = { { ngx_string("info"), NGX_LOG_INFO }, { ngx_string("notice"), NGX_LOG_NOTICE }, { ngx_string("warn"), NGX_LOG_WARN }, @@ -85,72 +85,56 @@ static ngx_conf_enum_t ngx_http_limit_c }; -static ngx_conf_num_bounds_t ngx_http_limit_conn_status_bounds = { - ngx_conf_check_num_bounds, 400, 599 -}; - - -static ngx_command_t ngx_http_limit_conn_commands[] = { +static ngx_command_t ngx_mail_limit_conn_commands[] = { { ngx_string("limit_conn_zone"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, - ngx_http_limit_conn_zone, + NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE2, + ngx_mail_limit_conn_zone, 0, 0, NULL }, { ngx_string("limit_conn"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_http_limit_conn, - NGX_HTTP_LOC_CONF_OFFSET, + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE2, + ngx_mail_limit_conn, + NGX_MAIL_SRV_CONF_OFFSET, 0, NULL }, { ngx_string("limit_conn_log_level"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_limit_conn_conf_t, log_level), - &ngx_http_limit_conn_log_levels }, - - { ngx_string("limit_conn_status"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_limit_conn_conf_t, status_code), - &ngx_http_limit_conn_status_bounds }, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_limit_conn_conf_t, log_level), + &ngx_mail_limit_conn_log_levels }, { ngx_string("limit_conn_dry_run"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_limit_conn_conf_t, dry_run), + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_limit_conn_conf_t, dry_run), NULL }, ngx_null_command }; -static ngx_http_module_t ngx_http_limit_conn_module_ctx = { - ngx_http_limit_conn_add_variables, /* preconfiguration */ - ngx_http_limit_conn_init, /* postconfiguration */ +static ngx_mail_module_t ngx_mail_limit_conn_module_ctx = { + NULL, /* protocol */ NULL, /* create main configuration */ NULL, /* init main configuration */ - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_limit_conn_create_conf, /* create location configuration */ - ngx_http_limit_conn_merge_conf /* merge location configuration */ + ngx_mail_limit_conn_create_conf, /* create server configuration */ + ngx_mail_limit_conn_merge_conf /* merge server configuration */ }; -ngx_module_t ngx_http_limit_conn_module = { +ngx_module_t ngx_mail_limit_conn_module = { NGX_MODULE_V1, - &ngx_http_limit_conn_module_ctx, /* module context */ - ngx_http_limit_conn_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ + &ngx_mail_limit_conn_module_ctx, /* module context */ + ngx_mail_limit_conn_commands, /* module directives */ + NGX_MAIL_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ @@ -162,24 +146,13 @@ ngx_module_t ngx_http_limit_conn_module }; -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 u_char pop3_error[] = "-ERR [SYS/TEMP] Too many connections" CRLF; +static u_char imap_error[] = "NO [UNAVAILABLE] Too many connections" CRLF; +static u_char smtp_error[] = "454 4.7.0 Too many connections" CRLF; -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) +ngx_int_t +ngx_mail_limit_conn_handler(ngx_mail_session_t *s) { size_t n; uint32_t hash; @@ -187,24 +160,23 @@ ngx_http_limit_conn_handler(ngx_http_req ngx_uint_t i; ngx_rbtree_node_t *node; ngx_pool_cleanup_t *cln; - ngx_http_limit_conn_ctx_t *ctx; - ngx_http_limit_conn_node_t *lc; - ngx_http_limit_conn_conf_t *lccf; - ngx_http_limit_conn_limit_t *limits; - ngx_http_limit_conn_cleanup_t *lccln; + ngx_mail_limit_conn_ctx_t *ctx; + ngx_mail_limit_conn_node_t *lc; + ngx_mail_limit_conn_conf_t *lccf; + ngx_mail_limit_conn_limit_t *limits; + ngx_mail_limit_conn_cleanup_t *lccln; - if (r->main->limit_conn_status) { - return NGX_DECLINED; - } + s->connection->log->action = NULL; - lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module); + lccf = ngx_mail_get_module_srv_conf(s, ngx_mail_limit_conn_module); limits = lccf->limits.elts; for (i = 0; i < lccf->limits.nelts; i++) { ctx = limits[i].shm_zone->data; - if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + if (ngx_mail_limit_conn_key(s, ctx, &key) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return NGX_ERROR; } if (key.len == 0) { @@ -212,45 +184,40 @@ ngx_http_limit_conn_handler(ngx_http_req } if (key.len > 255) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "the value of the \"%V\" key " "is more than 255 bytes: \"%V\"", - &ctx->key.value, &key); + &ctx->key, &key); continue; } - r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_PASSED; - hash = ngx_crc32_short(key.data, key.len); ngx_shmtx_lock(&ctx->shpool->mutex); - node = ngx_http_limit_conn_lookup(&ctx->sh->rbtree, &key, hash); + node = ngx_mail_limit_conn_lookup(&ctx->sh->rbtree, &key, hash); if (node == NULL) { n = offsetof(ngx_rbtree_node_t, color) - + offsetof(ngx_http_limit_conn_node_t, data) + + offsetof(ngx_mail_limit_conn_node_t, data) + key.len; node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); - ngx_http_limit_conn_cleanup_all(r->pool); + ngx_mail_limit_conn_cleanup_all(s->connection->pool); if (lccf->dry_run) { - r->main->limit_conn_status = - NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN; - return NGX_DECLINED; + return NGX_OK; } - r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED; - - return lccf->status_code; + ngx_mail_session_internal_server_error(s); + return NGX_ERROR; } - lc = (ngx_http_limit_conn_node_t *) &node->color; + lc = (ngx_mail_limit_conn_node_t *) &node->color; node->key = hash; lc->len = (u_char) key.len; @@ -261,62 +228,135 @@ ngx_http_limit_conn_handler(ngx_http_req } else { - lc = (ngx_http_limit_conn_node_t *) &node->color; + lc = (ngx_mail_limit_conn_node_t *) &node->color; if ((ngx_uint_t) lc->conn >= limits[i].conn) { ngx_shmtx_unlock(&ctx->shpool->mutex); - ngx_log_error(lccf->log_level, r->connection->log, 0, + ngx_log_error(lccf->log_level, s->connection->log, 0, "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); + ngx_mail_limit_conn_cleanup_all(s->connection->pool); if (lccf->dry_run) { - r->main->limit_conn_status = - NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN; - return NGX_DECLINED; + return NGX_OK; } - r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED; - - return lccf->status_code; + ngx_mail_limit_conn_send_error(s); + return NGX_BUSY; } lc->conn++; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, "limit conn: %08Xi %d", node->key, lc->conn); ngx_shmtx_unlock(&ctx->shpool->mutex); - cln = ngx_pool_cleanup_add(r->pool, - sizeof(ngx_http_limit_conn_cleanup_t)); + cln = ngx_pool_cleanup_add(s->connection->pool, + sizeof(ngx_mail_limit_conn_cleanup_t)); if (cln == NULL) { - ngx_http_limit_conn_cleanup_node(limits[i].shm_zone, node); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + ngx_mail_limit_conn_cleanup_node(limits[i].shm_zone, node); + ngx_mail_session_internal_server_error(s); + return NGX_ERROR; } - cln->handler = ngx_http_limit_conn_cleanup; + cln->handler = ngx_mail_limit_conn_cleanup; lccln = cln->data; lccln->shm_zone = limits[i].shm_zone; lccln->node = node; } - return NGX_DECLINED; + return NGX_OK; +} + + +static ngx_int_t +ngx_mail_limit_conn_key(ngx_mail_session_t *s, ngx_mail_limit_conn_ctx_t *ctx, + ngx_str_t *key) +{ + ngx_str_t name; + + switch (ctx->key_type) { + + case NGX_MAIL_LIMIT_CONN_REMOTE_USER: + *key = s->login; + break; + + case NGX_MAIL_LIMIT_CONN_REMOTE_ADDR: + *key = s->connection->addr_text; + break; + + case NGX_MAIL_LIMIT_CONN_AUTH_HTTP: + + name.len = ctx->key.len - (sizeof("$auth_http_") - 1); + name.data = ctx->key.data + (sizeof("$auth_http_") - 1); + + if (ngx_mail_auth_http_header_value(s, &name, key) != NGX_OK) { + return NGX_ERROR; + } + + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, + "limit conn key: \"%V\"", key); + + return NGX_OK; } static void -ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp, +ngx_mail_limit_conn_send_error(ngx_mail_session_t *s) +{ + u_char *p, *err; + size_t len; + + switch (s->protocol) { + + case NGX_MAIL_POP3_PROTOCOL: + ngx_str_set(&s->out, pop3_error); + break; + + case NGX_MAIL_IMAP_PROTOCOL: + len = s->tag.len + sizeof(imap_error) - 1; + + err = ngx_pnalloc(s->connection->pool, len); + if (err == NULL) { + ngx_mail_session_internal_server_error(s); + return; + } + + p = ngx_cpymem(err, s->tag.data, s->tag.len); + ngx_memcpy(p, imap_error, sizeof(imap_error) - 1); + + s->out.len = len; + s->out.data = err; + + break; + + default: /* NGX_MAIL_SMTP_PROTOCOL */ + ngx_str_set(&s->out, smtp_error); + break; + } + + s->quit = 1; + + ngx_mail_send(s->connection->write); +} + + +static void +ngx_mail_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { ngx_rbtree_node_t **p; - ngx_http_limit_conn_node_t *lcn, *lcnt; + ngx_mail_limit_conn_node_t *lcn, *lcnt; for ( ;; ) { @@ -330,8 +370,8 @@ ngx_http_limit_conn_rbtree_insert_value( } else { /* node->key == temp->key */ - lcn = (ngx_http_limit_conn_node_t *) &node->color; - lcnt = (ngx_http_limit_conn_node_t *) &temp->color; + lcn = (ngx_mail_limit_conn_node_t *) &node->color; + lcnt = (ngx_mail_limit_conn_node_t *) &temp->color; p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 0) ? &temp->left : &temp->right; @@ -353,11 +393,11 @@ ngx_http_limit_conn_rbtree_insert_value( static ngx_rbtree_node_t * -ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash) +ngx_mail_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash) { ngx_int_t rc; ngx_rbtree_node_t *node, *sentinel; - ngx_http_limit_conn_node_t *lcn; + ngx_mail_limit_conn_node_t *lcn; node = rbtree->root; sentinel = rbtree->sentinel; @@ -376,7 +416,7 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t /* hash == node->key */ - lcn = (ngx_http_limit_conn_node_t *) &node->color; + lcn = (ngx_mail_limit_conn_node_t *) &node->color; rc = ngx_memn2cmp(key->data, lcn->data, key->len, (size_t) lcn->len); @@ -392,21 +432,21 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t static void -ngx_http_limit_conn_cleanup(void *data) +ngx_mail_limit_conn_cleanup(void *data) { - ngx_http_limit_conn_cleanup_t *lccln = data; + ngx_mail_limit_conn_cleanup_t *lccln = data; ngx_rbtree_node_t *node; - ngx_http_limit_conn_ctx_t *ctx; - ngx_http_limit_conn_node_t *lc; + ngx_mail_limit_conn_ctx_t *ctx; + ngx_mail_limit_conn_node_t *lc; ctx = lccln->shm_zone->data; node = lccln->node; - lc = (ngx_http_limit_conn_node_t *) &node->color; + lc = (ngx_mail_limit_conn_node_t *) &node->color; ngx_shmtx_lock(&ctx->shpool->mutex); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, lccln->shm_zone->shm.log, 0, "limit conn cleanup: %08Xi %d", node->key, lc->conn); lc->conn--; @@ -421,14 +461,14 @@ ngx_http_limit_conn_cleanup(void *data) static ngx_inline void -ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool) +ngx_mail_limit_conn_cleanup_all(ngx_pool_t *pool) { ngx_pool_cleanup_t *cln; cln = pool->cleanup; - while (cln && cln->handler == ngx_http_limit_conn_cleanup) { - ngx_http_limit_conn_cleanup(cln->data); + while (cln && cln->handler == ngx_mail_limit_conn_cleanup) { + ngx_mail_limit_conn_cleanup(cln->data); cln = cln->next; } @@ -437,39 +477,39 @@ ngx_http_limit_conn_cleanup_all(ngx_pool static void -ngx_http_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, +ngx_mail_limit_conn_cleanup_node(ngx_shm_zone_t *shm_zone, ngx_rbtree_node_t *node) { - ngx_http_limit_conn_cleanup_t lccln; + ngx_mail_limit_conn_cleanup_t lccln; lccln.shm_zone = shm_zone; lccln.node = node; - ngx_http_limit_conn_cleanup(&lccln); + ngx_mail_limit_conn_cleanup(&lccln); } static ngx_int_t -ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) +ngx_mail_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) { - ngx_http_limit_conn_ctx_t *octx = data; + ngx_mail_limit_conn_ctx_t *octx = data; size_t len; - ngx_http_limit_conn_ctx_t *ctx; + ngx_mail_limit_conn_ctx_t *ctx; ctx = shm_zone->data; if (octx) { - if (ctx->key.value.len != octx->key.value.len - || ngx_strncmp(ctx->key.value.data, octx->key.value.data, - ctx->key.value.len) + if (ctx->key.len != octx->key.len + || ngx_strncmp(ctx->key.data, octx->key.data, + ctx->key.len) != 0) { ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, "limit_conn_zone \"%V\" uses the \"%V\" key " "while previously it used the \"%V\" key", - &shm_zone->shm.name, &ctx->key.value, - &octx->key.value); + &shm_zone->shm.name, &ctx->key, + &octx->key); return NGX_ERROR; } @@ -487,7 +527,7 @@ ngx_http_limit_conn_init_zone(ngx_shm_zo return NGX_OK; } - ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_conn_shctx_t)); + ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_mail_limit_conn_shctx_t)); if (ctx->sh == NULL) { return NGX_ERROR; } @@ -495,7 +535,7 @@ ngx_http_limit_conn_init_zone(ngx_shm_zo ctx->shpool->data = ctx->sh; ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, - ngx_http_limit_conn_rbtree_insert_value); + ngx_mail_limit_conn_rbtree_insert_value); len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len; @@ -511,31 +551,12 @@ ngx_http_limit_conn_init_zone(ngx_shm_zo } -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_mail_limit_conn_create_conf(ngx_conf_t *cf) { - if (r->main->limit_conn_status == 0) { - v->not_found = 1; - return NGX_OK; - } + ngx_mail_limit_conn_conf_t *conf; - 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) -{ - ngx_http_limit_conn_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_conf_t)); + conf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_limit_conn_conf_t)); if (conf == NULL) { return NULL; } @@ -547,7 +568,6 @@ ngx_http_limit_conn_create_conf(ngx_conf */ conf->log_level = NGX_CONF_UNSET_UINT; - conf->status_code = NGX_CONF_UNSET_UINT; conf->dry_run = NGX_CONF_UNSET; return conf; @@ -555,19 +575,16 @@ ngx_http_limit_conn_create_conf(ngx_conf static char * -ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child) +ngx_mail_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child) { - ngx_http_limit_conn_conf_t *prev = parent; - ngx_http_limit_conn_conf_t *conf = child; + ngx_mail_limit_conn_conf_t *prev = parent; + ngx_mail_limit_conn_conf_t *conf = child; if (conf->limits.elts == NULL) { conf->limits = prev->limits; } ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); - 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; @@ -575,30 +592,37 @@ ngx_http_limit_conn_merge_conf(ngx_conf_ static char * -ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_mail_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - u_char *p; - ssize_t size; - ngx_str_t *value, name, s; - ngx_uint_t i; - ngx_shm_zone_t *shm_zone; - ngx_http_limit_conn_ctx_t *ctx; - ngx_http_compile_complex_value_t ccv; + u_char *p; + ssize_t size; + ngx_str_t *value, name, s; + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_mail_limit_conn_ctx_t *ctx; value = cf->args->elts; - ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t)); + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_limit_conn_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } - ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + if (ngx_strcmp(value[1].data, "$remote_user") == 0) { + ctx->key = value[1]; + ctx->key_type = NGX_MAIL_LIMIT_CONN_REMOTE_USER; + + } else if (ngx_strcmp(value[1].data, "$remote_addr") == 0) { + ctx->key = value[1]; + ctx->key_type = NGX_MAIL_LIMIT_CONN_REMOTE_ADDR; - ccv.cf = cf; - ccv.value = &value[1]; - ccv.complex_value = &ctx->key; + } else if (ngx_strncmp(value[1].data, "$auth_http_", 11) == 0) { + ctx->key = value[1]; + ctx->key_type = NGX_MAIL_LIMIT_CONN_AUTH_HTTP; - if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); return NGX_CONF_ERROR; } @@ -654,7 +678,7 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, } shm_zone = ngx_shared_memory_add(cf, &name, size, - &ngx_http_limit_conn_module); + &ngx_mail_limit_conn_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } @@ -664,11 +688,11 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V \"%V\" is already bound to key \"%V\"", - &cmd->name, &name, &ctx->key.value); + &cmd->name, &name, &ctx->key); return NGX_CONF_ERROR; } - shm_zone->init = ngx_http_limit_conn_init_zone; + shm_zone->init = ngx_mail_limit_conn_init_zone; shm_zone->data = ctx; return NGX_CONF_OK; @@ -676,11 +700,11 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, static char * -ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_mail_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_shm_zone_t *shm_zone; - ngx_http_limit_conn_conf_t *lccf = conf; - ngx_http_limit_conn_limit_t *limit, *limits; + ngx_mail_limit_conn_conf_t *lccf = conf; + ngx_mail_limit_conn_limit_t *limit, *limits; ngx_str_t *value; ngx_int_t n; @@ -689,7 +713,7 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_ value = cf->args->elts; shm_zone = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_limit_conn_module); + &ngx_mail_limit_conn_module); if (shm_zone == NULL) { return NGX_CONF_ERROR; } @@ -698,7 +722,7 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_ if (limits == NULL) { if (ngx_array_init(&lccf->limits, cf->pool, 1, - sizeof(ngx_http_limit_conn_limit_t)) + sizeof(ngx_mail_limit_conn_limit_t)) != NGX_OK) { return NGX_CONF_ERROR; @@ -734,41 +758,3 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_ return NGX_CONF_OK; } - - -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; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_limit_conn_handler; - - return NGX_OK; -} diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -21,6 +21,7 @@ static ngx_str_t ngx_mail_pop3_default_ ngx_string("TOP"), ngx_string("USER"), ngx_string("UIDL"), + ngx_string("RESP-CODES"), ngx_null_string }; From mdounin at mdounin.ru Mon Jul 7 04:30:38 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:30:38 +0300 Subject: [PATCH 1 of 7] Documented limit_rate algorithm change to leaky bucket Message-ID: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1751859352 -10800 # Mon Jul 07 06:35:52 2025 +0300 # Node ID 4a0383b1afeda8765269b7901213d7668dbd4a27 # Parent 7c3d7c4768e8b84f641592760ce0bfc9731af5b3 Documented limit_rate algorithm change to leaky bucket. diff --git a/xml/en/docs/http/ngx_http_core_module.xml b/xml/en/docs/http/ngx_http_core_module.xml --- a/xml/en/docs/http/ngx_http_core_module.xml +++ b/xml/en/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="110">
@@ -1093,12 +1093,9 @@ Please note that this will limit access if in location -Limits the rate of response transmission to a client. +Limits the rate of response transmission to the client. The rate is specified in bytes per second. The zero value disables rate limiting. - The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit. @@ -1159,8 +1156,9 @@ directives. 0.8.0 -Sets the initial amount after which the further transmission -of a response to a client will be rate limited. +Specifies the allowed size of data bursts +after which the further transmission of a response to the client +will be rate limited. Parameter value can contain variables (1.17.0). @@ -1175,6 +1173,15 @@ location /flv/ { + + +Prior to version 1.29.0, +this directive controlled the initial amount of data +sent without rate limiting +rather than the size of bursts. + + + diff --git a/xml/ru/docs/http/ngx_http_core_module.xml b/xml/ru/docs/http/ngx_http_core_module.xml --- a/xml/ru/docs/http/ngx_http_core_module.xml +++ b/xml/ru/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="110">
@@ -1090,9 +1090,6 @@ limit_except GET { ???????????? ???????? ???????? ?????? ???????. ???????? ???????? ? ?????? ? ???????. ???????? 0 ????????? ??????????? ????????. - ??????????? ??????????????? ?? ??????, ???????, ???? ?????? ???????????? ??????? ??? ??????????, ????????? ???????? ????? ????? ???? ????????? ???????????. @@ -1152,8 +1149,9 @@ server { 0.8.0 -?????? ????????? ????? ??????, ????? ???????? ???????? ???????? -?????????????? ???????? ???????? ?????? ???????. +?????? ?????????? ?????? ????????? ??? ???????? ??????, +??? ?????????? ???????? ???????? ?????????????? ???????? +???????? ?????? ???????. ? ???????? ????????? ????? ???????????? ?????????? (1.17.0). @@ -1168,6 +1166,15 @@ location /flv/ { + + +?? ?????? 1.29.0 +??? ????????? ???????? ????????? ????? ??????, +???????????? ??? ??????????? ????????, +? ?? ?????? ?????????. + + + From mdounin at mdounin.ru Mon Jul 7 04:30:39 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:30:39 +0300 Subject: [PATCH 2 of 7] Documented limit_rate and limit_rate_after in mail proxy In-Reply-To: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> References: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> Message-ID: <1b81369bbf4f9467e6d0.1751862639@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1751859363 -10800 # Mon Jul 07 06:36:03 2025 +0300 # Node ID 1b81369bbf4f9467e6d0650bf1b55abea4369ddc # Parent 4a0383b1afeda8765269b7901213d7668dbd4a27 Documented limit_rate and limit_rate_after in mail proxy. diff --git a/xml/en/docs/mail/ngx_mail_core_module.xml b/xml/en/docs/mail/ngx_mail_core_module.xml --- a/xml/en/docs/mail/ngx_mail_core_module.xml +++ b/xml/en/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="25">
@@ -74,6 +74,48 @@ mail {
+ +rate +0 +mail +server +1.29.0 + + +Limits the rate of transmission to the client. +The rate is specified in bytes per second. +The zero value disables rate limiting. +The limit is set per a connection, and so if a client simultaneously opens +two connections, the overall rate will be twice as much +as the specified limit. + + + +Example: + +limit_rate 10m; +limit_rate_after 100m; + + + + + + + +size +0 +mail +server +1.29.0 + + +Specifies the allowed size of data bursts +after which further transmission to the client will be rate limited. + + + + + address:port diff --git a/xml/ru/docs/mail/ngx_mail_core_module.xml b/xml/ru/docs/mail/ngx_mail_core_module.xml --- a/xml/ru/docs/mail/ngx_mail_core_module.xml +++ b/xml/ru/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="25">
@@ -74,6 +74,49 @@ mail {
+ +???????? +0 +mail +server +1.29.0 + + +???????????? ???????? ???????? ?????? ???????. +???????? ???????? ? ?????? ? ???????. +???????? 0 ????????? ??????????? ????????. +??????????? ??????????????? ?? ??????????, ???????, ???? ?????? ???????????? +??????? ??? ??????????, ????????? ???????? ????? ????? ???? +????????? ???????????. + + + +??????: + +limit_rate 10m; +limit_rate_after 100m; + + + + + + + +?????? +0 +mail +server +1.29.0 + + +?????? ?????????? ?????? ????????? ??? ???????? ??????, +??? ?????????? ???????? ???????? ?????????????? ???????? +???????? ?????? ???????. + + + + + ?????:???? From mdounin at mdounin.ru Mon Jul 7 04:30:40 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:30:40 +0300 Subject: [PATCH 3 of 7] Fixed some articles in lingering close documentation In-Reply-To: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> References: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> Message-ID: # HG changeset patch # User Maxim Dounin # Date 1751860824 -10800 # Mon Jul 07 07:00:24 2025 +0300 # Node ID b27605822bd1debade53f18223b604974e156127 # Parent 1b81369bbf4f9467e6d0650bf1b55abea4369ddc Fixed some articles in lingering close documentation. diff --git a/xml/en/docs/http/ngx_http_core_module.xml b/xml/en/docs/http/ngx_http_core_module.xml --- a/xml/en/docs/http/ngx_http_core_module.xml +++ b/xml/en/docs/http/ngx_http_core_module.xml @@ -1204,9 +1204,9 @@ Controls how nginx closes client connect The default value ?on? instructs nginx to wait for and -process additional data from a client -before fully closing a connection, but only -if heuristics suggests that a client may be sending more data. +process additional data from the client +before fully closing the connection, but only +if heuristics suggests that the client may be sending more data. @@ -1240,7 +1240,7 @@ the directive must be specified on the < When is in effect, this directive specifies the maximum time during which nginx -will process (read and ignore) additional data coming from a client. +will process (read and ignore) additional data coming from the client. After that, the connection will be closed, even if there will be more data. From mdounin at mdounin.ru Mon Jul 7 04:30:41 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:30:41 +0300 Subject: [PATCH 4 of 7] Documented lingering close in mail proxy In-Reply-To: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> References: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> Message-ID: <52042c2613a020b951bb.1751862641@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1751860828 -10800 # Mon Jul 07 07:00:28 2025 +0300 # Node ID 52042c2613a020b951bbf3e2bd77513a79b8f7a2 # Parent b27605822bd1debade53f18223b604974e156127 Documented lingering close in mail proxy. diff --git a/xml/en/docs/mail/ngx_mail_core_module.xml b/xml/en/docs/mail/ngx_mail_core_module.xml --- a/xml/en/docs/mail/ngx_mail_core_module.xml +++ b/xml/en/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="26">
@@ -116,6 +116,72 @@ after which further transmission to the + +on | off +on +mail +server +1.29.0 + + +Controls how nginx closes client connections +in case of errors, notably +authentication errors. + + + +The default value ?on? instructs nginx to +wait for and +process additional data from the client +before fully closing the connection. + + + +The value ?off? tells nginx to do not wait for +more data and close the connection immediately. + + + + + + +time +30s +mail +server +1.29.0 + + +When is in effect, +this directive specifies the maximum time during which nginx +will process (read and ignore) additional data coming from the client. +After that, the connection will be closed, even if there will be +more data. + + + + + + +time +5s +mail +server +1.29.0 + + +When is in effect, this directive specifies +the maximum waiting time for more client data to arrive. +If data are not received during this time, the connection is closed. +Otherwise, the data are read and ignored, and nginx starts waiting +for more data again. +The ?wait-read-ignore? cycle is repeated, but no longer than specified by the + directive. + + + + + address:port diff --git a/xml/ru/docs/mail/ngx_mail_core_module.xml b/xml/ru/docs/mail/ngx_mail_core_module.xml --- a/xml/ru/docs/mail/ngx_mail_core_module.xml +++ b/xml/ru/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="26">
@@ -117,6 +117,74 @@ limit_rate_after 100m; + +on | off +on +mail +server +location +1.29.0 + + +????????? ????????? ?????????? ? ????????? +? ?????? ??????, ? ????????? +?????? ??????????????. + + + +?? ????????? ?? ????????? ?on? nginx ????? +????? ? +???????????? ?????????????? ??????, +??????????? ?? ???????, ????? ?????? ????????? ??????????. + + + +?? ????????? ?off? nginx ?? ????? ????? ??????????? +?????????????? ?????? ? ????? ?? ??????? ??????????. + + + + + + +????? +30s +mail +server +1.29.0 + + +???? ????????? , +??? ????????? ?????? ???????????? ?????, ? ??????? ???????? nginx +????? ???????????? (?????? ? ????????????) ?????????????? ??????, +??????????? ?? ???????. +?? ?????????? ????? ??????? ?????????? ????? ???????, ???? ???? +????? ??? ??????. + + + + + + +????? +5s +mail +server +1.29.0 + + +???? ????????? , ??? ????????? ?????? +???????????? ????? ???????? ??????????? ?????????????? ?????? ?? ???????. +???? ? ??????? ????? ??????? ?????? ?? ???? ????????, ?????????? ???????????. +? ????????? ?????? ?????? ???????? ? ????????????, ? nginx ????? +???? ??????????? ??????. +???? ??????-??????-????????????? ???????????, ?? ?? ?????? ??? ?????? +?????????? . + + + + + ?????:???? From mdounin at mdounin.ru Mon Jul 7 04:30:42 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:30:42 +0300 Subject: [PATCH 5 of 7] Typo fixed In-Reply-To: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> References: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> Message-ID: # HG changeset patch # User Maxim Dounin # Date 1751860850 -10800 # Mon Jul 07 07:00:50 2025 +0300 # Node ID d14a134efcea212983096ada295d5c54bf99a2d6 # Parent 52042c2613a020b951bbf3e2bd77513a79b8f7a2 Typo fixed. diff --git a/xml/ru/docs/http/ngx_http_core_module.xml b/xml/ru/docs/http/ngx_http_core_module.xml --- a/xml/ru/docs/http/ngx_http_core_module.xml +++ b/xml/ru/docs/http/ngx_http_core_module.xml @@ -2394,7 +2394,7 @@ location / { ?????? ??????? ??? ???????? ?????? ???????. ??????? ??????????????? ?? ?? ??? ???????? ??????, -? ?????? ????? ????? ?????????? ????????. +? ?????? ????? ????? ?????????? ??????. ???? ?? ????????? ????? ??????? ?????? ?????? ?? ??????, ?????????? ????? ???????. From mdounin at mdounin.ru Mon Jul 7 04:30:43 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:30:43 +0300 Subject: [PATCH 6 of 7] Documented send_min_rate and client_body_min_rate In-Reply-To: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> References: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> Message-ID: # HG changeset patch # User Maxim Dounin # Date 1751861409 -10800 # Mon Jul 07 07:10:09 2025 +0300 # Node ID eb9401e437d9415a25fc2b48caecd6bf9b863594 # Parent d14a134efcea212983096ada295d5c54bf99a2d6 Documented send_min_rate and client_body_min_rate. diff --git a/xml/en/docs/http/ngx_http_core_module.xml b/xml/en/docs/http/ngx_http_core_module.xml --- a/xml/en/docs/http/ngx_http_core_module.xml +++ b/xml/en/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="111">
@@ -356,6 +356,34 @@ variable, to save the number of copy ope + +rate +0 +http +server +location +1.29.0 + + +Specifies the minimum required rate for reading client request body, +in bytes per second. +For example: + +client_body_min_rate 10k; + + + + +If the client request body reading rate +since the timeout was last set +is below this value, +the timeout will not be updated on read operations, +and the request will be terminated when the timeout expires. + + + + + path @@ -395,8 +423,10 @@ a path to a temporary file might look li Defines a timeout for reading client request body. The timeout is set only for a period between two successive read operations, not for the transmission of the whole request body. -If a client does not transmit anything within this time, the -request is terminated with the +If no data is received within this time, +or the amount of data is insufficient to maintain +the minimum rate, +the request is terminated with the error. @@ -2387,6 +2417,34 @@ This directive is ignored on Linux, Sola + +rate +0 +http +server +location +1.29.0 + + +Specifies the minimum required data transmission rate to the client, +in bytes per second. +For example: + +send_min_rate 10k; + + + + +If the average transmission rate +since the send timeout was last set +is below this value, +the timeout will not be updated on write operations, +and the connection will be closed when the timeout expires. + + + + + time 60s @@ -2398,7 +2456,9 @@ This directive is ignored on Linux, Sola Sets a timeout for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. -If the client does not receive anything within this time, +If no data is sent within this time, +or the amount of data is insufficient to maintain +the minimum rate, the connection is closed. diff --git a/xml/ru/docs/http/ngx_http_core_module.xml b/xml/ru/docs/http/ngx_http_core_module.xml --- a/xml/ru/docs/http/ngx_http_core_module.xml +++ b/xml/ru/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="111">
@@ -354,6 +354,34 @@ chunked encoding, ???????? ?? ?????????? ?????????. + +???????? +0 +http +server +location +1.29.0 + + +?????? ??????????? ????????? ???????? ?????? ???? ??????? ???????, +? ?????? ? ???????. +????????: + +client_body_min_rate 10k; + + + + +???? ??????? ???????? ?????? ???? ??????? ??????? +? ??????? ????????? ????????? ???????? +???? ????????? ????????, +??????? ?? ????? ??????????? ??? ????????? ??????, +? ?? ????????? ???????? ????????? ??????? ????? ??????????. + + + + + ???? @@ -393,6 +421,8 @@ client_body_temp_path /spool/nginx/clien ??????? ??????????????? ?? ?? ??? ???????? ???? ???????, ? ?????? ????? ????? ????????????????? ?????????? ??????. ???? ?? ????????? ????? ??????? ?????? ?????? ?? ????????, +??? ?????????? ?????????? ?? ??????? ?????? ????? ???????????? ??? ??????????? +??????????? ????????, ????????? ??????? ???????????? ? ??????? . @@ -2384,6 +2414,34 @@ location / { + +???????? +0 +http +server +location +1.29.0 + + +?????? ??????????? ????????? ???????? ???????? ?????? ???????, +? ?????? ? ???????. +????????: + +send_min_rate 10k; + + + + +???? ??????? ???????? ???????? ?????? +? ??????? ????????? ????????? ???????? +???? ?????????????? ????????, +??????? ?? ????? ??????????? ??? ????????? ??????, +? ?? ????????? ???????? ?????????? ????? ???????. + + + + + ????? 60s @@ -2396,6 +2454,8 @@ location / { ??????? ??????????????? ?? ?? ??? ???????? ??????, ? ?????? ????? ????? ?????????? ??????. ???? ?? ????????? ????? ??????? ?????? ?????? ?? ??????, +??? ?????????? ?????????? ??????? ?????? ????? ???????????? ??? ??????????? +??????????? ????????, ?????????? ????? ???????. From mdounin at mdounin.ru Mon Jul 7 04:30:44 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Mon, 07 Jul 2025 07:30:44 +0300 Subject: [PATCH 7 of 7] Documented ngx_mail_limit_conn_module In-Reply-To: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> References: <4a0383b1afeda8765269.1751862638@vm-bsd.mdounin.ru> Message-ID: <46810dc719ce8f470cd8.1751862644@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1751862129 -10800 # Mon Jul 07 07:22:09 2025 +0300 # Node ID 46810dc719ce8f470cd843c03f8c63bd8a61e495 # Parent eb9401e437d9415a25fc2b48caecd6bf9b863594 Documented ngx_mail_limit_conn_module. diff --git a/xml/en/GNUmakefile b/xml/en/GNUmakefile --- a/xml/en/GNUmakefile +++ b/xml/en/GNUmakefile @@ -89,6 +89,7 @@ REFS = \ mail/ngx_mail_auth_http_module \ mail/ngx_mail_core_module \ mail/ngx_mail_imap_module \ + mail/ngx_mail_limit_conn_module \ mail/ngx_mail_pop3_module \ mail/ngx_mail_proxy_module \ mail/ngx_mail_realip_module \ diff --git a/xml/en/docs/index.xml b/xml/en/docs/index.xml --- a/xml/en/docs/index.xml +++ b/xml/en/docs/index.xml @@ -8,7 +8,7 @@
@@ -454,6 +454,11 @@ ngx_mail_realip_module + +ngx_mail_limit_conn_module + + + ngx_mail_ssl_module diff --git a/xml/en/docs/http/ngx_http_limit_conn_module.xml b/xml/en/docs/mail/ngx_mail_limit_conn_module.xml copy from xml/en/docs/http/ngx_http_limit_conn_module.xml copy to xml/en/docs/mail/ngx_mail_limit_conn_module.xml --- a/xml/en/docs/http/ngx_http_limit_conn_module.xml +++ b/xml/en/docs/mail/ngx_mail_limit_conn_module.xml @@ -2,28 +2,30 @@ - + rev="1">
-The ngx_http_limit_conn_module module is used to -limit the number of connections per the defined key, in -particular, the number of connections from a single IP address. +The ngx_mail_limit_conn_module module (1.29.0) +is used to limit the number of connections per the defined key, +in particular, the number of connections from an authenticated client. -Not all connections are counted. -A connection is counted only if it has a request being processed by the server -and the whole request header has already been read. +Connections are limited after +authentication, +so the user name updated by the authentication server can be used as a key, +as well as arbitrary authentication server response header fields.
@@ -33,8 +35,8 @@ and the whole request header has already -http { - limit_conn_zone $binary_remote_addr zone=addr:10m; +mail { + limit_conn_zone $remote_user zone=user:10m; ... @@ -42,9 +44,9 @@ http { ... - location /download/ { - limit_conn addr 1; - } + limit_conn user 10; + } +} @@ -56,48 +58,47 @@ http { zone number -http +mail server -location Sets the shared memory zone and the maximum allowed number of connections for a given key value. -When this limit is exceeded, the server will return the -error -in reply to a request. +When this limit is exceeded, the server will return a protocol-specific +error and close the connection. For example, the directives -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=user:10m; server { - location /download/ { - limit_conn addr 1; - } + limit_conn user 5; -allow only one connection per an IP address at a time. - -In HTTP/2 and HTTP/3, -each concurrent request is considered a separate connection. - +allow only at most 5 connections for an authenticated user at a time. + + + +Note that not all email clients support the response codes being used, +and might show password prompt to the user. +Therefore, it is not recommended to configure limits which are low enough +to be exceeded by well-behaving clients. There could be several limit_conn directives. For example, the following configuration will limit the number -of connections to the server per a client IP and, at the same time, -the total number of connections to the virtual server: +of connections per user, and, at the same time, number of connections +for all users in the particular domain, as provided by the authentication +server: -limit_conn_zone $binary_remote_addr zone=perip:10m; -limit_conn_zone $server_name zone=perserver:10m; +limit_conn_zone $remote_user zone=user:10m; +limit_conn_zone $auth_http_domain zone=domain:10m; server { ... - limit_conn perip 10; - limit_conn perserver 100; + limit_conn user 5; + limit_conn domain 100; } - @@ -112,10 +113,8 @@ defined on the current level. on | off off -http +mail server -location -1.17.6 Enables the dry run mode. @@ -134,10 +133,8 @@ as usual. warn | error error -http +mail server -location -0.8.18 Sets the desired logging level for cases when the server @@ -147,104 +144,68 @@ limits the number of connections. - -code -503 -http -server -location -1.3.15 - - -Sets the status code to return in response to rejected requests. - - - - - key zone=name:size -http +mail Sets parameters for a shared memory zone that will keep states for various keys. In particular, the state includes the current number of connections. -The key can contain text, variables, and their combination. -Requests with an empty key value are not accounted. - -Prior to version 1.7.6, a key could contain exactly one variable. - + + + +The key can be one of the following: + + + +$remote_addr + +client address + + +$remote_user + +user name supplied during authentication + + +$auth_http_name + +arbitrary authentication server response header field; +the last part of a variable name is the field name converted +to lower case with dashes replaced by underscores + + + + +Connections with an empty key value are not accounted. + + + Usage example: -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=addr:10m; -Here, a client IP address serves as a key. -Note that instead of $remote_addr, the -$binary_remote_addr variable is used here. -The $remote_addr variable?s size can -vary from 7 to 15 bytes. -The stored state occupies either -32 or 64 bytes of memory on 32-bit platforms and always 64 -bytes on 64-bit platforms. -The $binary_remote_addr variable?s size -is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses. -The stored state always occupies 32 or 64 bytes -on 32-bit platforms and 64 bytes on 64-bit platforms. +Here, the user name serves as a key. + + + +On 32-bit platforms a stored state occupies +32 bytes for keys up to 12 bytes, +64 bytes for keys from 13 to 44 bytes. +On 64-bit platforms a stored state occupies +64 bytes for keys up to 28 bytes. One megabyte zone can keep about 32 thousand 32-byte states or about 16 thousand 64-byte states. -If the zone storage is exhausted, the server will return the -error -to all further requests. - - - - - - - - name - $variable - size - -http - - -This directive was made obsolete in version 1.1.8 -and was removed in version 1.7.6. -An equivalent directive -with a changed syntax should be used instead: - -limit_conn_zone -$variable -zone=name:size; - +If the zone storage is exhausted, +the server will return an error and close the connection.
- -
- - - - -$limit_conn_status - -keeps the result of limiting the number of connections (1.17.6): -PASSED, -REJECTED, or -REJECTED_DRY_RUN - - - - - -
-
diff --git a/xml/en/docs/mail/ngx_mail_pop3_module.xml b/xml/en/docs/mail/ngx_mail_pop3_module.xml --- a/xml/en/docs/mail/ngx_mail_pop3_module.xml +++ b/xml/en/docs/mail/ngx_mail_pop3_module.xml @@ -78,7 +78,7 @@ will not be automatically included in extension ... -TOP USER UIDL +TOP USER UIDL RESP-CODES mail server @@ -107,6 +107,13 @@ The current list of standardized extensi www.iana.org. + + +Prior to version 1.29.0, the default value was +TOP USER UIDL. + + +
diff --git a/xml/ru/GNUmakefile b/xml/ru/GNUmakefile --- a/xml/ru/GNUmakefile +++ b/xml/ru/GNUmakefile @@ -79,6 +79,7 @@ REFS = \ mail/ngx_mail_auth_http_module \ mail/ngx_mail_core_module \ mail/ngx_mail_imap_module \ + mail/ngx_mail_limit_conn_module \ mail/ngx_mail_pop3_module \ mail/ngx_mail_proxy_module \ mail/ngx_mail_realip_module \ diff --git a/xml/ru/docs/index.xml b/xml/ru/docs/index.xml --- a/xml/ru/docs/index.xml +++ b/xml/ru/docs/index.xml @@ -8,7 +8,7 @@
@@ -460,6 +460,11 @@ ngx_mail_realip_module + +ngx_mail_limit_conn_module + + + ngx_mail_ssl_module diff --git a/xml/ru/docs/http/ngx_http_limit_conn_module.xml b/xml/ru/docs/mail/ngx_mail_limit_conn_module.xml copy from xml/ru/docs/http/ngx_http_limit_conn_module.xml copy to xml/ru/docs/mail/ngx_mail_limit_conn_module.xml --- a/xml/ru/docs/http/ngx_http_limit_conn_module.xml +++ b/xml/ru/docs/mail/ngx_mail_limit_conn_module.xml @@ -2,27 +2,31 @@ - + rev="1">
-?????? ngx_http_limit_conn_module ????????? ?????????? -????? ?????????? ?? ????????? ?????, ? ?????????, ????? ?????????? ? ?????? -IP-??????. +?????? ngx_mail_limit_conn_module (1.29.0) +????????? ?????????? ????? ?????????? ?? ????????? ?????, +? ?????????, ????? ?????????? ?? ?????? ???????????????????? ????????????. -??????????? ?? ??? ??????????, ? ???? ??, ? ??????? ??????? -???????, ?????????????? ????????, ? ????????? ??????? ??? ????????. +?????????? ?????????????? ????? +??????????????, +??? ??? ? ???????? ????? ????? ?????????????? ??? ????????????, +???????????? ???????? ??????????????, +? ????? ???????????? ???? ????????? ?????? ??????? ??????????????.
@@ -32,8 +36,8 @@ IP-??????. -http { - limit_conn_zone $binary_remote_addr zone=addr:10m; +mail { + limit_conn_zone $remote_user zone=user:10m; ... @@ -41,9 +45,9 @@ http { ... - location /download/ { - limit_conn addr 1; - } + limit_conn user 10; + } +} @@ -55,48 +59,47 @@ http { ???? ????? -http +mail server -location ?????? ???? ??????????? ?????? ? ??????????? ?????????? ????? ?????????? ??? ?????? ???????? ?????. -??? ?????????? ????? ????? ? ????? ?? ?????? ?????? ?????? -??????. +??? ?????????? ????? ????? ?????? ?????? ?????? ? ??????? ??????????. ????????, ????????? -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=user:10m; server { - location /download/ { - limit_conn addr 1; - } + limit_conn user 5; -????????? ???????????? ???????????? ?? ????? ?????? ?????????? ? ?????? -IP-??????. - -? HTTP/2 ? HTTP/3 -?????? ???????????? ?????? ????????? ????????? ???????????. - +????????? ???????????? ???????????? ?? ????? ???? ?????????? +?? ?????? ???????????????????? ????????????. + + + +??????? ????? ? ????, ??? +?? ??? ???????? ??????? ???????????? ???????????? ???? ???????, +? ????? ?????????? ???????????? ???????? ?????? ??????. +??????? ?? ????????????? ????????????? ??????? ?????? ???????????, +????? ?????????? ????????? ???????? ???? ????????? ?????????. ???????? limit_conn ????? ???? ?????????. -????????, ????????? ???????????? ???????????? ????? ?????????? ? ???????? -? ?????? ??????????? IP-?????? ? ? ?? ?? ????? ???????????? ????? ????? -?????????? ? ??????????? ????????: +????????, ????????? ???????????? ???????????? ????? ?????????? +?? ?????? ???????????? ? ? ?? ?? ????? ???????????? ????? ?????????? +??? ???? ????????????? ? ??????, ???????????? ???????? ??????????????: -limit_conn_zone $binary_remote_addr zone=perip:10m; -limit_conn_zone $server_name zone=perserver:10m; +limit_conn_zone $remote_user zone=user:10m; +limit_conn_zone $auth_http_domain zone=domain:10m; server { ... - limit_conn perip 10; - limit_conn perserver 100; + limit_conn user 5; + limit_conn domain 100; } - @@ -110,10 +113,8 @@ server { on | off off -http +mail server -location -1.17.6 ???????? ????? ???????? ???????. @@ -132,10 +133,8 @@ server { warn | error error -http +mail server -location -0.8.18 ?????? ???????? ??????? ?????? ? ??? ??????? ??????????? @@ -145,104 +144,67 @@ server { - -??? -503 -http -server -location -1.3.15 - - -????????? ?????????????? ??? ??????, ???????????? ??? ?????????? ????????. - - - - - ???? zone=????????:?????? -http +mail ?????? ????????? ???? ??????????? ??????, ??????? ?????? ????????? ??? ?????? ???????? ?????. ????????? ? ????????? ???????? ??????? ????? ??????????. -? ???????? ????? ????? ???????????? ?????, ?????????? ? ?? ??????????. + + + +? ???????? ????? ????? ????????????: + + + +$remote_addr + +????? ??????? + + +$remote_user + +??? ????????????, ?????????????? ??? ?????????????? + + +$auth_http_??? + +???????????? ???? ????????? ?????? ??????? ??????????????; +????????? ????? ????? ?????????? ????????????? ????? ????, ???????????? +? ??????? ????????, ? ??????? ???????? ???? ?? ??????? ????????????? + + + + ??????? ? ?????? ????????? ????? ?? ???????????. - -?? ?????? 1.7.6 ? ???????? ????? ????? ???? ?????? ????? ???? ??????????. - + + + ?????? ?????????????: -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=user:10m; -????? ? ???????? ????? ???????????? IP-????? ???????. -???????? ????????, ??? ?????? ?????????? $remote_addr -???????????? ?????????? $binary_remote_addr. -????? ???????? ?????????? $remote_addr ????? ?????????? -?? 7 ?? 15 ????, ??? ???? ?????? ????????? ????????? ?????????? -???? 32, ???? 64 ????? ?? 32-?????? ?????????? ? ?????? 64 -????? ?? 64-??????. -????? ???????? ?????????? $binary_remote_addr ?????? -????? 4 ?????? ??? IPv4-??????? ??? 16 ?????? ??? IPv6-???????. -??? ???? ?????? ????????? ?????? ????? 32 ??? 64 ?????? -?? 32-?????? ?????????? ? 64 ?????? ?? 64-??????. +????? ? ???????? ????? ???????????? ??? ????????????. + + + +?????? ????????? ?? 32-?????? ?????????? +????? 32 ?????? ??? ?????? ?????? ?? 12 ???? ????????????, +? 64 ?????? ??? ?????? ?? 13 ?? 44 ????. +?????? ????????? ?? 64-?????? ?????????? +????? 64 ?????? ??? ?????? ?????? ?? 28 ???? ????????????. ? ???? ???????? 1 ???????? ????? ???????????? ????? 32 ????? ????????? ???????? 32 ????? ??? 16 ????? ????????? ???????? 64 ?????. -??? ???????????? ???? ? ????? ?? ??????????? ??????? ?????? ????? -?????????? -??????. - - - - - - - - ???????? - $?????????? - ?????? - -http - - -??? ????????? ???????? ? ?????? 1.1.8 -? ???? ??????? ? ?????? 1.7.6. -?????? ??? ??????? -???????????? ??????????? ????????? -? ?????????? ???????????: - -limit_conn_zone -$?????????? -zone=????????:??????; - +??? ???????????? ???? ?????? ?????? ?????? ? ??????? ??????????.
- -
- - - - -$limit_conn_status - -?????? ????????? ??????????? ????? ?????????? (1.17.6): -PASSED, -REJECTED ??? -REJECTED_DRY_RUN - - - - - -
-
diff --git a/xml/ru/docs/mail/ngx_mail_pop3_module.xml b/xml/ru/docs/mail/ngx_mail_pop3_module.xml --- a/xml/ru/docs/mail/ngx_mail_pop3_module.xml +++ b/xml/ru/docs/mail/ngx_mail_pop3_module.xml @@ -78,7 +78,7 @@ ?????????? ... -TOP USER UIDL +TOP USER UIDL RESP-CODES mail server @@ -108,6 +108,13 @@ www.iana.org. + + +?? ?????? 1.29.0 ?? ????????? ?????????????? ???????? +TOP USER UIDL. + + +
From mdounin at mdounin.ru Mon Jul 7 23:16:22 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 02:16:22 +0300 Subject: [nginx-site] Documented limit_rate algorithm change to leaky buc... Message-ID: details: http://freenginx.org/hg/nginx-site/rev/4a0383b1afed branches: changeset: 3104:4a0383b1afed user: Maxim Dounin date: Mon Jul 07 06:35:52 2025 +0300 description: Documented limit_rate algorithm change to leaky bucket. diffstat: xml/en/docs/http/ngx_http_core_module.xml | 21 ++++++++++++++------- xml/ru/docs/http/ngx_http_core_module.xml | 19 +++++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diffs (104 lines): diff --git a/xml/en/docs/http/ngx_http_core_module.xml b/xml/en/docs/http/ngx_http_core_module.xml --- a/xml/en/docs/http/ngx_http_core_module.xml +++ b/xml/en/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="110">
@@ -1093,12 +1093,9 @@ Please note that this will limit access if in location -Limits the rate of response transmission to a client. +Limits the rate of response transmission to the client. The rate is specified in bytes per second. The zero value disables rate limiting. - The limit is set per a request, and so if a client simultaneously opens two connections, the overall rate will be twice as much as the specified limit. @@ -1159,8 +1156,9 @@ directives. 0.8.0 -Sets the initial amount after which the further transmission -of a response to a client will be rate limited. +Specifies the allowed size of data bursts +after which the further transmission of a response to the client +will be rate limited. Parameter value can contain variables (1.17.0). @@ -1175,6 +1173,15 @@ location /flv/ { + + +Prior to version 1.29.0, +this directive controlled the initial amount of data +sent without rate limiting +rather than the size of bursts. + + + diff --git a/xml/ru/docs/http/ngx_http_core_module.xml b/xml/ru/docs/http/ngx_http_core_module.xml --- a/xml/ru/docs/http/ngx_http_core_module.xml +++ b/xml/ru/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="110">
@@ -1090,9 +1090,6 @@ limit_except GET { ???????????? ???????? ???????? ?????? ???????. ???????? ???????? ? ?????? ? ???????. ???????? 0 ????????? ??????????? ????????. - ??????????? ??????????????? ?? ??????, ???????, ???? ?????? ???????????? ??????? ??? ??????????, ????????? ???????? ????? ????? ???? ????????? ???????????. @@ -1152,8 +1149,9 @@ server { 0.8.0 -?????? ????????? ????? ??????, ????? ???????? ???????? ???????? -?????????????? ???????? ???????? ?????? ???????. +?????? ?????????? ?????? ????????? ??? ???????? ??????, +??? ?????????? ???????? ???????? ?????????????? ???????? +???????? ?????? ???????. ? ???????? ????????? ????? ???????????? ?????????? (1.17.0). @@ -1168,6 +1166,15 @@ location /flv/ { + + +?? ?????? 1.29.0 +??? ????????? ???????? ????????? ????? ??????, +???????????? ??? ??????????? ????????, +? ?? ?????? ?????????. + + + From mdounin at mdounin.ru Mon Jul 7 23:16:22 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 02:16:22 +0300 Subject: [nginx-site] Documented limit_rate and limit_rate_after in mail ... Message-ID: details: http://freenginx.org/hg/nginx-site/rev/1b81369bbf4f branches: changeset: 3105:1b81369bbf4f user: Maxim Dounin date: Mon Jul 07 06:36:03 2025 +0300 description: Documented limit_rate and limit_rate_after in mail proxy. diffstat: xml/en/docs/mail/ngx_mail_core_module.xml | 44 +++++++++++++++++++++++++++++- xml/ru/docs/mail/ngx_mail_core_module.xml | 45 ++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 2 deletions(-) diffs (123 lines): diff --git a/xml/en/docs/mail/ngx_mail_core_module.xml b/xml/en/docs/mail/ngx_mail_core_module.xml --- a/xml/en/docs/mail/ngx_mail_core_module.xml +++ b/xml/en/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="25">
@@ -74,6 +74,48 @@ mail {
+ +rate +0 +mail +server +1.29.0 + + +Limits the rate of transmission to the client. +The rate is specified in bytes per second. +The zero value disables rate limiting. +The limit is set per a connection, and so if a client simultaneously opens +two connections, the overall rate will be twice as much +as the specified limit. + + + +Example: + +limit_rate 10m; +limit_rate_after 100m; + + + + + + + +size +0 +mail +server +1.29.0 + + +Specifies the allowed size of data bursts +after which further transmission to the client will be rate limited. + + + + + address:port diff --git a/xml/ru/docs/mail/ngx_mail_core_module.xml b/xml/ru/docs/mail/ngx_mail_core_module.xml --- a/xml/ru/docs/mail/ngx_mail_core_module.xml +++ b/xml/ru/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="25">
@@ -74,6 +74,49 @@ mail {
+ +???????? +0 +mail +server +1.29.0 + + +???????????? ???????? ???????? ?????? ???????. +???????? ???????? ? ?????? ? ???????. +???????? 0 ????????? ??????????? ????????. +??????????? ??????????????? ?? ??????????, ???????, ???? ?????? ???????????? +??????? ??? ??????????, ????????? ???????? ????? ????? ???? +????????? ???????????. + + + +??????: + +limit_rate 10m; +limit_rate_after 100m; + + + + + + + +?????? +0 +mail +server +1.29.0 + + +?????? ?????????? ?????? ????????? ??? ???????? ??????, +??? ?????????? ???????? ???????? ?????????????? ???????? +???????? ?????? ???????. + + + + + ?????:???? From mdounin at mdounin.ru Mon Jul 7 23:16:22 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 02:16:22 +0300 Subject: [nginx-site] Fixed some articles in lingering close documentation. Message-ID: details: http://freenginx.org/hg/nginx-site/rev/b27605822bd1 branches: changeset: 3106:b27605822bd1 user: Maxim Dounin date: Mon Jul 07 07:00:24 2025 +0300 description: Fixed some articles in lingering close documentation. diffstat: xml/en/docs/http/ngx_http_core_module.xml | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-) diffs (25 lines): diff --git a/xml/en/docs/http/ngx_http_core_module.xml b/xml/en/docs/http/ngx_http_core_module.xml --- a/xml/en/docs/http/ngx_http_core_module.xml +++ b/xml/en/docs/http/ngx_http_core_module.xml @@ -1204,9 +1204,9 @@ Controls how nginx closes client connect The default value ?on? instructs nginx to wait for and -process additional data from a client -before fully closing a connection, but only -if heuristics suggests that a client may be sending more data. +process additional data from the client +before fully closing the connection, but only +if heuristics suggests that the client may be sending more data. @@ -1240,7 +1240,7 @@ the directive must be specified on the < When is in effect, this directive specifies the maximum time during which nginx -will process (read and ignore) additional data coming from a client. +will process (read and ignore) additional data coming from the client. After that, the connection will be closed, even if there will be more data. From mdounin at mdounin.ru Mon Jul 7 23:16:22 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 02:16:22 +0300 Subject: [nginx-site] Documented lingering close in mail proxy. Message-ID: details: http://freenginx.org/hg/nginx-site/rev/52042c2613a0 branches: changeset: 3107:52042c2613a0 user: Maxim Dounin date: Mon Jul 07 07:00:28 2025 +0300 description: Documented lingering close in mail proxy. diffstat: xml/en/docs/mail/ngx_mail_core_module.xml | 68 +++++++++++++++++++++++++++++- xml/ru/docs/mail/ngx_mail_core_module.xml | 70 ++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 2 deletions(-) diffs (172 lines): diff --git a/xml/en/docs/mail/ngx_mail_core_module.xml b/xml/en/docs/mail/ngx_mail_core_module.xml --- a/xml/en/docs/mail/ngx_mail_core_module.xml +++ b/xml/en/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="26">
@@ -116,6 +116,72 @@ after which further transmission to the + +on | off +on +mail +server +1.29.0 + + +Controls how nginx closes client connections +in case of errors, notably +authentication errors. + + + +The default value ?on? instructs nginx to +wait for and +process additional data from the client +before fully closing the connection. + + + +The value ?off? tells nginx to do not wait for +more data and close the connection immediately. + + + + + + +time +30s +mail +server +1.29.0 + + +When is in effect, +this directive specifies the maximum time during which nginx +will process (read and ignore) additional data coming from the client. +After that, the connection will be closed, even if there will be +more data. + + + + + + +time +5s +mail +server +1.29.0 + + +When is in effect, this directive specifies +the maximum waiting time for more client data to arrive. +If data are not received during this time, the connection is closed. +Otherwise, the data are read and ignored, and nginx starts waiting +for more data again. +The ?wait-read-ignore? cycle is repeated, but no longer than specified by the + directive. + + + + + address:port diff --git a/xml/ru/docs/mail/ngx_mail_core_module.xml b/xml/ru/docs/mail/ngx_mail_core_module.xml --- a/xml/ru/docs/mail/ngx_mail_core_module.xml +++ b/xml/ru/docs/mail/ngx_mail_core_module.xml @@ -10,7 +10,7 @@ + rev="26">
@@ -117,6 +117,74 @@ limit_rate_after 100m; + +on | off +on +mail +server +location +1.29.0 + + +????????? ????????? ?????????? ? ????????? +? ?????? ??????, ? ????????? +?????? ??????????????. + + + +?? ????????? ?? ????????? ?on? nginx ????? +????? ? +???????????? ?????????????? ??????, +??????????? ?? ???????, ????? ?????? ????????? ??????????. + + + +?? ????????? ?off? nginx ?? ????? ????? ??????????? +?????????????? ?????? ? ????? ?? ??????? ??????????. + + + + + + +????? +30s +mail +server +1.29.0 + + +???? ????????? , +??? ????????? ?????? ???????????? ?????, ? ??????? ???????? nginx +????? ???????????? (?????? ? ????????????) ?????????????? ??????, +??????????? ?? ???????. +?? ?????????? ????? ??????? ?????????? ????? ???????, ???? ???? +????? ??? ??????. + + + + + + +????? +5s +mail +server +1.29.0 + + +???? ????????? , ??? ????????? ?????? +???????????? ????? ???????? ??????????? ?????????????? ?????? ?? ???????. +???? ? ??????? ????? ??????? ?????? ?? ???? ????????, ?????????? ???????????. +? ????????? ?????? ?????? ???????? ? ????????????, ? nginx ????? +???? ??????????? ??????. +???? ??????-??????-????????????? ???????????, ?? ?? ?????? ??? ?????? +?????????? . + + + + + ?????:???? From mdounin at mdounin.ru Mon Jul 7 23:16:23 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 02:16:23 +0300 Subject: [nginx-site] Typo fixed. Message-ID: details: http://freenginx.org/hg/nginx-site/rev/d14a134efcea branches: changeset: 3108:d14a134efcea user: Maxim Dounin date: Mon Jul 07 07:00:50 2025 +0300 description: Typo fixed. diffstat: xml/ru/docs/http/ngx_http_core_module.xml | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/xml/ru/docs/http/ngx_http_core_module.xml b/xml/ru/docs/http/ngx_http_core_module.xml --- a/xml/ru/docs/http/ngx_http_core_module.xml +++ b/xml/ru/docs/http/ngx_http_core_module.xml @@ -2394,7 +2394,7 @@ location / { ?????? ??????? ??? ???????? ?????? ???????. ??????? ??????????????? ?? ?? ??? ???????? ??????, -? ?????? ????? ????? ?????????? ????????. +? ?????? ????? ????? ?????????? ??????. ???? ?? ????????? ????? ??????? ?????? ?????? ?? ??????, ?????????? ????? ???????. From mdounin at mdounin.ru Mon Jul 7 23:16:23 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 02:16:23 +0300 Subject: [nginx-site] Documented send_min_rate and client_body_min_rate. Message-ID: details: http://freenginx.org/hg/nginx-site/rev/eb9401e437d9 branches: changeset: 3109:eb9401e437d9 user: Maxim Dounin date: Mon Jul 07 07:10:09 2025 +0300 description: Documented send_min_rate and client_body_min_rate. diffstat: xml/en/docs/http/ngx_http_core_module.xml | 68 +++++++++++++++++++++++++++++- xml/ru/docs/http/ngx_http_core_module.xml | 62 +++++++++++++++++++++++++++- 2 files changed, 125 insertions(+), 5 deletions(-) diffs (206 lines): diff --git a/xml/en/docs/http/ngx_http_core_module.xml b/xml/en/docs/http/ngx_http_core_module.xml --- a/xml/en/docs/http/ngx_http_core_module.xml +++ b/xml/en/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="111">
@@ -356,6 +356,34 @@ variable, to save the number of copy ope + +rate +0 +http +server +location +1.29.0 + + +Specifies the minimum required rate for reading client request body, +in bytes per second. +For example: + +client_body_min_rate 10k; + + + + +If the client request body reading rate +since the timeout was last set +is below this value, +the timeout will not be updated on read operations, +and the request will be terminated when the timeout expires. + + + + + path @@ -395,8 +423,10 @@ a path to a temporary file might look li Defines a timeout for reading client request body. The timeout is set only for a period between two successive read operations, not for the transmission of the whole request body. -If a client does not transmit anything within this time, the -request is terminated with the +If no data is received within this time, +or the amount of data is insufficient to maintain +the minimum rate, +the request is terminated with the error. @@ -2387,6 +2417,34 @@ This directive is ignored on Linux, Sola + +rate +0 +http +server +location +1.29.0 + + +Specifies the minimum required data transmission rate to the client, +in bytes per second. +For example: + +send_min_rate 10k; + + + + +If the average transmission rate +since the send timeout was last set +is below this value, +the timeout will not be updated on write operations, +and the connection will be closed when the timeout expires. + + + + + time 60s @@ -2398,7 +2456,9 @@ This directive is ignored on Linux, Sola Sets a timeout for transmitting a response to the client. The timeout is set only between two successive write operations, not for the transmission of the whole response. -If the client does not receive anything within this time, +If no data is sent within this time, +or the amount of data is insufficient to maintain +the minimum rate, the connection is closed. diff --git a/xml/ru/docs/http/ngx_http_core_module.xml b/xml/ru/docs/http/ngx_http_core_module.xml --- a/xml/ru/docs/http/ngx_http_core_module.xml +++ b/xml/ru/docs/http/ngx_http_core_module.xml @@ -10,7 +10,7 @@ + rev="111">
@@ -354,6 +354,34 @@ chunked encoding, ???????? ?? ?????????? ?????????. + +???????? +0 +http +server +location +1.29.0 + + +?????? ??????????? ????????? ???????? ?????? ???? ??????? ???????, +? ?????? ? ???????. +????????: + +client_body_min_rate 10k; + + + + +???? ??????? ???????? ?????? ???? ??????? ??????? +? ??????? ????????? ????????? ???????? +???? ????????? ????????, +??????? ?? ????? ??????????? ??? ????????? ??????, +? ?? ????????? ???????? ????????? ??????? ????? ??????????. + + + + + ???? @@ -393,6 +421,8 @@ client_body_temp_path /spool/nginx/clien ??????? ??????????????? ?? ?? ??? ???????? ???? ???????, ? ?????? ????? ????? ????????????????? ?????????? ??????. ???? ?? ????????? ????? ??????? ?????? ?????? ?? ????????, +??? ?????????? ?????????? ?? ??????? ?????? ????? ???????????? ??? ??????????? +??????????? ????????, ????????? ??????? ???????????? ? ??????? . @@ -2384,6 +2414,34 @@ location / { + +???????? +0 +http +server +location +1.29.0 + + +?????? ??????????? ????????? ???????? ???????? ?????? ???????, +? ?????? ? ???????. +????????: + +send_min_rate 10k; + + + + +???? ??????? ???????? ???????? ?????? +? ??????? ????????? ????????? ???????? +???? ?????????????? ????????, +??????? ?? ????? ??????????? ??? ????????? ??????, +? ?? ????????? ???????? ?????????? ????? ???????. + + + + + ????? 60s @@ -2396,6 +2454,8 @@ location / { ??????? ??????????????? ?? ?? ??? ???????? ??????, ? ?????? ????? ????? ?????????? ??????. ???? ?? ????????? ????? ??????? ?????? ?????? ?? ??????, +??? ?????????? ?????????? ??????? ?????? ????? ???????????? ??? ??????????? +??????????? ????????, ?????????? ????? ???????. From mdounin at mdounin.ru Mon Jul 7 23:16:23 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 02:16:23 +0300 Subject: [nginx-site] Documented ngx_mail_limit_conn_module. Message-ID: details: http://freenginx.org/hg/nginx-site/rev/46810dc719ce branches: changeset: 3110:46810dc719ce user: Maxim Dounin date: Mon Jul 07 07:22:09 2025 +0300 description: Documented ngx_mail_limit_conn_module. diffstat: xml/en/GNUmakefile | 1 + xml/en/docs/index.xml | 7 +- xml/en/docs/mail/ngx_mail_limit_conn_module.xml | 201 +++++++++-------------- xml/en/docs/mail/ngx_mail_pop3_module.xml | 9 +- xml/ru/GNUmakefile | 1 + xml/ru/docs/index.xml | 7 +- xml/ru/docs/mail/ngx_mail_limit_conn_module.xml | 200 +++++++++-------------- xml/ru/docs/mail/ngx_mail_pop3_module.xml | 9 +- 8 files changed, 192 insertions(+), 243 deletions(-) diffs (741 lines): diff --git a/xml/en/GNUmakefile b/xml/en/GNUmakefile --- a/xml/en/GNUmakefile +++ b/xml/en/GNUmakefile @@ -89,6 +89,7 @@ REFS = \ mail/ngx_mail_auth_http_module \ mail/ngx_mail_core_module \ mail/ngx_mail_imap_module \ + mail/ngx_mail_limit_conn_module \ mail/ngx_mail_pop3_module \ mail/ngx_mail_proxy_module \ mail/ngx_mail_realip_module \ diff --git a/xml/en/docs/index.xml b/xml/en/docs/index.xml --- a/xml/en/docs/index.xml +++ b/xml/en/docs/index.xml @@ -8,7 +8,7 @@
@@ -454,6 +454,11 @@ ngx_mail_realip_module + +ngx_mail_limit_conn_module + + + ngx_mail_ssl_module diff --git a/xml/en/docs/http/ngx_http_limit_conn_module.xml b/xml/en/docs/mail/ngx_mail_limit_conn_module.xml copy from xml/en/docs/http/ngx_http_limit_conn_module.xml copy to xml/en/docs/mail/ngx_mail_limit_conn_module.xml --- a/xml/en/docs/http/ngx_http_limit_conn_module.xml +++ b/xml/en/docs/mail/ngx_mail_limit_conn_module.xml @@ -2,28 +2,30 @@ - + rev="1">
-The ngx_http_limit_conn_module module is used to -limit the number of connections per the defined key, in -particular, the number of connections from a single IP address. +The ngx_mail_limit_conn_module module (1.29.0) +is used to limit the number of connections per the defined key, +in particular, the number of connections from an authenticated client. -Not all connections are counted. -A connection is counted only if it has a request being processed by the server -and the whole request header has already been read. +Connections are limited after +authentication, +so the user name updated by the authentication server can be used as a key, +as well as arbitrary authentication server response header fields.
@@ -33,8 +35,8 @@ and the whole request header has already -http { - limit_conn_zone $binary_remote_addr zone=addr:10m; +mail { + limit_conn_zone $remote_user zone=user:10m; ... @@ -42,9 +44,9 @@ http { ... - location /download/ { - limit_conn addr 1; - } + limit_conn user 10; + } +} @@ -56,48 +58,47 @@ http { zone number -http +mail server -location Sets the shared memory zone and the maximum allowed number of connections for a given key value. -When this limit is exceeded, the server will return the -error -in reply to a request. +When this limit is exceeded, the server will return a protocol-specific +error and close the connection. For example, the directives -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=user:10m; server { - location /download/ { - limit_conn addr 1; - } + limit_conn user 5; -allow only one connection per an IP address at a time. - -In HTTP/2 and HTTP/3, -each concurrent request is considered a separate connection. - +allow only at most 5 connections for an authenticated user at a time. + + + +Note that not all email clients support the response codes being used, +and might show password prompt to the user. +Therefore, it is not recommended to configure limits which are low enough +to be exceeded by well-behaving clients. There could be several limit_conn directives. For example, the following configuration will limit the number -of connections to the server per a client IP and, at the same time, -the total number of connections to the virtual server: +of connections per user, and, at the same time, number of connections +for all users in the particular domain, as provided by the authentication +server: -limit_conn_zone $binary_remote_addr zone=perip:10m; -limit_conn_zone $server_name zone=perserver:10m; +limit_conn_zone $remote_user zone=user:10m; +limit_conn_zone $auth_http_domain zone=domain:10m; server { ... - limit_conn perip 10; - limit_conn perserver 100; + limit_conn user 5; + limit_conn domain 100; } - @@ -112,10 +113,8 @@ defined on the current level. on | off off -http +mail server -location -1.17.6 Enables the dry run mode. @@ -134,10 +133,8 @@ as usual. warn | error error -http +mail server -location -0.8.18 Sets the desired logging level for cases when the server @@ -147,104 +144,68 @@ limits the number of connections. - -code -503 -http -server -location -1.3.15 - - -Sets the status code to return in response to rejected requests. - - - - - key zone=name:size -http +mail Sets parameters for a shared memory zone that will keep states for various keys. In particular, the state includes the current number of connections. -The key can contain text, variables, and their combination. -Requests with an empty key value are not accounted. - -Prior to version 1.7.6, a key could contain exactly one variable. - + + + +The key can be one of the following: + + + +$remote_addr + +client address + + +$remote_user + +user name supplied during authentication + + +$auth_http_name + +arbitrary authentication server response header field; +the last part of a variable name is the field name converted +to lower case with dashes replaced by underscores + + + + +Connections with an empty key value are not accounted. + + + Usage example: -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=addr:10m; -Here, a client IP address serves as a key. -Note that instead of $remote_addr, the -$binary_remote_addr variable is used here. -The $remote_addr variable?s size can -vary from 7 to 15 bytes. -The stored state occupies either -32 or 64 bytes of memory on 32-bit platforms and always 64 -bytes on 64-bit platforms. -The $binary_remote_addr variable?s size -is always 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses. -The stored state always occupies 32 or 64 bytes -on 32-bit platforms and 64 bytes on 64-bit platforms. +Here, the user name serves as a key. + + + +On 32-bit platforms a stored state occupies +32 bytes for keys up to 12 bytes, +64 bytes for keys from 13 to 44 bytes. +On 64-bit platforms a stored state occupies +64 bytes for keys up to 28 bytes. One megabyte zone can keep about 32 thousand 32-byte states or about 16 thousand 64-byte states. -If the zone storage is exhausted, the server will return the -error -to all further requests. - - - - - - - - name - $variable - size - -http - - -This directive was made obsolete in version 1.1.8 -and was removed in version 1.7.6. -An equivalent directive -with a changed syntax should be used instead: - -limit_conn_zone -$variable -zone=name:size; - +If the zone storage is exhausted, +the server will return an error and close the connection.
- -
- - - - -$limit_conn_status - -keeps the result of limiting the number of connections (1.17.6): -PASSED, -REJECTED, or -REJECTED_DRY_RUN - - - - - -
-
diff --git a/xml/en/docs/mail/ngx_mail_pop3_module.xml b/xml/en/docs/mail/ngx_mail_pop3_module.xml --- a/xml/en/docs/mail/ngx_mail_pop3_module.xml +++ b/xml/en/docs/mail/ngx_mail_pop3_module.xml @@ -78,7 +78,7 @@ will not be automatically included in extension ... -TOP USER UIDL +TOP USER UIDL RESP-CODES mail server @@ -107,6 +107,13 @@ The current list of standardized extensi www.iana.org. + + +Prior to version 1.29.0, the default value was +TOP USER UIDL. + + +
diff --git a/xml/ru/GNUmakefile b/xml/ru/GNUmakefile --- a/xml/ru/GNUmakefile +++ b/xml/ru/GNUmakefile @@ -79,6 +79,7 @@ REFS = \ mail/ngx_mail_auth_http_module \ mail/ngx_mail_core_module \ mail/ngx_mail_imap_module \ + mail/ngx_mail_limit_conn_module \ mail/ngx_mail_pop3_module \ mail/ngx_mail_proxy_module \ mail/ngx_mail_realip_module \ diff --git a/xml/ru/docs/index.xml b/xml/ru/docs/index.xml --- a/xml/ru/docs/index.xml +++ b/xml/ru/docs/index.xml @@ -8,7 +8,7 @@
@@ -460,6 +460,11 @@ ngx_mail_realip_module + +ngx_mail_limit_conn_module + + + ngx_mail_ssl_module diff --git a/xml/ru/docs/http/ngx_http_limit_conn_module.xml b/xml/ru/docs/mail/ngx_mail_limit_conn_module.xml copy from xml/ru/docs/http/ngx_http_limit_conn_module.xml copy to xml/ru/docs/mail/ngx_mail_limit_conn_module.xml --- a/xml/ru/docs/http/ngx_http_limit_conn_module.xml +++ b/xml/ru/docs/mail/ngx_mail_limit_conn_module.xml @@ -2,27 +2,31 @@ - + rev="1">
-?????? ngx_http_limit_conn_module ????????? ?????????? -????? ?????????? ?? ????????? ?????, ? ?????????, ????? ?????????? ? ?????? -IP-??????. +?????? ngx_mail_limit_conn_module (1.29.0) +????????? ?????????? ????? ?????????? ?? ????????? ?????, +? ?????????, ????? ?????????? ?? ?????? ???????????????????? ????????????. -??????????? ?? ??? ??????????, ? ???? ??, ? ??????? ??????? -???????, ?????????????? ????????, ? ????????? ??????? ??? ????????. +?????????? ?????????????? ????? +??????????????, +??? ??? ? ???????? ????? ????? ?????????????? ??? ????????????, +???????????? ???????? ??????????????, +? ????? ???????????? ???? ????????? ?????? ??????? ??????????????.
@@ -32,8 +36,8 @@ IP-??????. -http { - limit_conn_zone $binary_remote_addr zone=addr:10m; +mail { + limit_conn_zone $remote_user zone=user:10m; ... @@ -41,9 +45,9 @@ http { ... - location /download/ { - limit_conn addr 1; - } + limit_conn user 10; + } +} @@ -55,48 +59,47 @@ http { ???? ????? -http +mail server -location ?????? ???? ??????????? ?????? ? ??????????? ?????????? ????? ?????????? ??? ?????? ???????? ?????. -??? ?????????? ????? ????? ? ????? ?? ?????? ?????? ?????? -??????. +??? ?????????? ????? ????? ?????? ?????? ?????? ? ??????? ??????????. ????????, ????????? -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=user:10m; server { - location /download/ { - limit_conn addr 1; - } + limit_conn user 5; -????????? ???????????? ???????????? ?? ????? ?????? ?????????? ? ?????? -IP-??????. - -? HTTP/2 ? HTTP/3 -?????? ???????????? ?????? ????????? ????????? ???????????. - +????????? ???????????? ???????????? ?? ????? ???? ?????????? +?? ?????? ???????????????????? ????????????. + + + +??????? ????? ? ????, ??? +?? ??? ???????? ??????? ???????????? ???????????? ???? ???????, +? ????? ?????????? ???????????? ???????? ?????? ??????. +??????? ?? ????????????? ????????????? ??????? ?????? ???????????, +????? ?????????? ????????? ???????? ???? ????????? ?????????. ???????? limit_conn ????? ???? ?????????. -????????, ????????? ???????????? ???????????? ????? ?????????? ? ???????? -? ?????? ??????????? IP-?????? ? ? ?? ?? ????? ???????????? ????? ????? -?????????? ? ??????????? ????????: +????????, ????????? ???????????? ???????????? ????? ?????????? +?? ?????? ???????????? ? ? ?? ?? ????? ???????????? ????? ?????????? +??? ???? ????????????? ? ??????, ???????????? ???????? ??????????????: -limit_conn_zone $binary_remote_addr zone=perip:10m; -limit_conn_zone $server_name zone=perserver:10m; +limit_conn_zone $remote_user zone=user:10m; +limit_conn_zone $auth_http_domain zone=domain:10m; server { ... - limit_conn perip 10; - limit_conn perserver 100; + limit_conn user 5; + limit_conn domain 100; } - @@ -110,10 +113,8 @@ server { on | off off -http +mail server -location -1.17.6 ???????? ????? ???????? ???????. @@ -132,10 +133,8 @@ server { warn | error error -http +mail server -location -0.8.18 ?????? ???????? ??????? ?????? ? ??? ??????? ??????????? @@ -145,104 +144,67 @@ server { - -??? -503 -http -server -location -1.3.15 - - -????????? ?????????????? ??? ??????, ???????????? ??? ?????????? ????????. - - - - - ???? zone=????????:?????? -http +mail ?????? ????????? ???? ??????????? ??????, ??????? ?????? ????????? ??? ?????? ???????? ?????. ????????? ? ????????? ???????? ??????? ????? ??????????. -? ???????? ????? ????? ???????????? ?????, ?????????? ? ?? ??????????. + + + +? ???????? ????? ????? ????????????: + + + +$remote_addr + +????? ??????? + + +$remote_user + +??? ????????????, ?????????????? ??? ?????????????? + + +$auth_http_??? + +???????????? ???? ????????? ?????? ??????? ??????????????; +????????? ????? ????? ?????????? ????????????? ????? ????, ???????????? +? ??????? ????????, ? ??????? ???????? ???? ?? ??????? ????????????? + + + + ??????? ? ?????? ????????? ????? ?? ???????????. - -?? ?????? 1.7.6 ? ???????? ????? ????? ???? ?????? ????? ???? ??????????. - + + + ?????? ?????????????: -limit_conn_zone $binary_remote_addr zone=addr:10m; +limit_conn_zone $remote_user zone=user:10m; -????? ? ???????? ????? ???????????? IP-????? ???????. -???????? ????????, ??? ?????? ?????????? $remote_addr -???????????? ?????????? $binary_remote_addr. -????? ???????? ?????????? $remote_addr ????? ?????????? -?? 7 ?? 15 ????, ??? ???? ?????? ????????? ????????? ?????????? -???? 32, ???? 64 ????? ?? 32-?????? ?????????? ? ?????? 64 -????? ?? 64-??????. -????? ???????? ?????????? $binary_remote_addr ?????? -????? 4 ?????? ??? IPv4-??????? ??? 16 ?????? ??? IPv6-???????. -??? ???? ?????? ????????? ?????? ????? 32 ??? 64 ?????? -?? 32-?????? ?????????? ? 64 ?????? ?? 64-??????. +????? ? ???????? ????? ???????????? ??? ????????????. + + + +?????? ????????? ?? 32-?????? ?????????? +????? 32 ?????? ??? ?????? ?????? ?? 12 ???? ????????????, +? 64 ?????? ??? ?????? ?? 13 ?? 44 ????. +?????? ????????? ?? 64-?????? ?????????? +????? 64 ?????? ??? ?????? ?????? ?? 28 ???? ????????????. ? ???? ???????? 1 ???????? ????? ???????????? ????? 32 ????? ????????? ???????? 32 ????? ??? 16 ????? ????????? ???????? 64 ?????. -??? ???????????? ???? ? ????? ?? ??????????? ??????? ?????? ????? -?????????? -??????. - - - - - - - - ???????? - $?????????? - ?????? - -http - - -??? ????????? ???????? ? ?????? 1.1.8 -? ???? ??????? ? ?????? 1.7.6. -?????? ??? ??????? -???????????? ??????????? ????????? -? ?????????? ???????????: - -limit_conn_zone -$?????????? -zone=????????:??????; - +??? ???????????? ???? ?????? ?????? ?????? ? ??????? ??????????.
- -
- - - - -$limit_conn_status - -?????? ????????? ??????????? ????? ?????????? (1.17.6): -PASSED, -REJECTED ??? -REJECTED_DRY_RUN - - - - - -
-
diff --git a/xml/ru/docs/mail/ngx_mail_pop3_module.xml b/xml/ru/docs/mail/ngx_mail_pop3_module.xml --- a/xml/ru/docs/mail/ngx_mail_pop3_module.xml +++ b/xml/ru/docs/mail/ngx_mail_pop3_module.xml @@ -78,7 +78,7 @@ ?????????? ... -TOP USER UIDL +TOP USER UIDL RESP-CODES mail server @@ -108,6 +108,13 @@ www.iana.org. + + +?? ?????? 1.29.0 ?? ????????? ?????????????? ???????? +TOP USER UIDL. + + +
From mdounin at mdounin.ru Tue Jul 8 00:25:31 2025 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 8 Jul 2025 03:25:31 +0300 Subject: freenginx-1.29.0 changes draft Message-ID: Hello! Changes with freenginx 1.29.0 08 Jul 2025 *) Change: the "directio" directive now works when returning responses from cache. *) Change: the "limit_rate" directive now uses the leaky bucket algorithm, allowing more accurate enforcement of the specified rate; the "limit_rate_after" directive specifies the allowed size of traffic bursts. *) Change: the $request_time variable now remains correct on system time changes. *) Feature: the "send_min_rate" and "client_body_min_rate" directives. *) Feature: the "limit_rate" and "limit_rate_after" directives in the mail proxy module. *) Feature: the "lingering_close", "lingering_time", and "lingering_timeout" directives in the mail proxy module. *) Feature: connection limiting in the mail proxy module. *) Workaround: the "send_timeout" directive might not work when the kernel TCP memory limit was reached on Linux. *) Workaround: gcc 15.1 compatibility. *) Bugfix: a segmentation fault might occur in a worker process if the "proxy_ssl_password_file" directive was used in the stream module; the bug had appeared in 1.23.1. *) Bugfix: a segmentation fault might occur in a worker process on shutdown; the bug had appeared in 1.27.2. *) Bugfix: in the "open_file_cache" directive. ????????? ? freenginx 1.29.0 08.07.2025 *) ?????????: ?????? ????????? directio ???????? ??? ???????, ???????????? ?? ????. *) ?????????: ?????? ????????? limit_rate ?????????? ???????? leaky bucket, ??? ????????? ????? ????? ???????????? ???????? ????????; ????????? limit_rate_after ?????? ?????????? ?????? ????????? ???????. *) ?????????: ?????? ?????????? $request_time ???????? ?????????? ??? ?????????? ?????????? ???????. *) ??????????: ????????? send_min_rate ? client_body_min_rate. *) ??????????: ????????? limit_rate ? limit_rate_after ? ???????? ??????-???????. *) ??????????: ????????? lingering_close, lingering_time ? lingering_timeout ? ???????? ??????-???????. *) ??????????: ??????????? ?????????? ?????????? ? ???????? ??????-???????. *) ?????????: ??? ?????????? ??????????? ???? ?? ?????????? TCP ?????? ????????? "send_timeout" ????? ?? ????????. *) ?????????: ????????????? ? gcc 15.1. *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, ???? ?????????????? ????????? proxy_ssl_password_file ? ?????? stream; ?????? ????????? ? 1.23.1. *) ???????????: ??? ?????????? ???????? ???????? ??? ????????? segmentation fault; ?????? ???????? ? 1.27.2. *) ???????????: ? ????????? open_file_cache. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Tue Jul 8 11:37:48 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 14:37:48 +0300 Subject: [nginx] Updated OpenSSL used for win32 builds. Message-ID: details: http://freenginx.org/hg/nginx/rev/165617f19694 branches: changeset: 9391:165617f19694 user: Maxim Dounin date: Tue Jul 08 06:34:01 2025 +0300 description: Updated OpenSSL used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-3.0.16 +OPENSSL = openssl-3.0.17 ZLIB = zlib-1.3.1 PCRE = pcre2-10.45 From mdounin at mdounin.ru Tue Jul 8 11:37:48 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 14:37:48 +0300 Subject: [nginx] freenginx-1.29.0-RELEASE Message-ID: details: http://freenginx.org/hg/nginx/rev/441d59c1052d branches: changeset: 9392:441d59c1052d user: Maxim Dounin date: Tue Jul 08 14:32:27 2025 +0300 description: freenginx-1.29.0-RELEASE diffstat: docs/xml/nginx/changes.xml | 133 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 133 insertions(+), 0 deletions(-) diffs (143 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -7,6 +7,139 @@
+ + + + +?????? ????????? directio +???????? ??? ???????, ???????????? ?? ????. + + +the "directio" directive +now works when returning responses from cache. + + + + + +?????? ????????? limit_rate ?????????? ???????? leaky bucket, +??? ????????? ????? ????? ???????????? ???????? ????????; +????????? limit_rate_after ?????? ?????????? ?????? ????????? ???????. + + +the "limit_rate" directive now uses the leaky bucket algorithm, +allowing more accurate enforcement of the specified rate; +the "limit_rate_after" directive specifies the allowed size of traffic bursts. + + + + + +?????? ?????????? $request_time +???????? ?????????? ??? ?????????? ?????????? ???????. + + +the $request_time variable now +remains correct on system time changes. + + + + + +????????? send_min_rate ? client_body_min_rate. + + +the "send_min_rate" and "client_body_min_rate" directives. + + + + + +????????? limit_rate ? limit_rate_after ? ???????? ??????-???????. + + +the "limit_rate" and "limit_rate_after" directives in the mail proxy module. + + + + + +????????? lingering_close, lingering_time ? lingering_timeout +? ???????? ??????-???????. + + +the "lingering_close", "lingering_time", and "lingering_timeout" directives +in the mail proxy module. + + + + + +??????????? ?????????? ?????????? ? ???????? ??????-???????. + + +connection limiting in the mail proxy module. + + + + + +??? ?????????? ??????????? ???? ?? ?????????? TCP ?????? +????????? "send_timeout" ????? ?? ????????. + + +the "send_timeout" directive might not work +when the kernel TCP memory limit was reached on Linux. + + + + + +????????????? ? gcc 15.1. + + +gcc 15.1 compatibility. + + + + + +? ??????? ???????? ??? ????????? segmentation fault, +???? ?????????????? ????????? proxy_ssl_password_file +? ?????? stream; +?????? ????????? ? 1.23.1. + + +a segmentation fault might occur in a worker process +if the "proxy_ssl_password_file" directive was used +in the stream module; +the bug had appeared in 1.23.1. + + + + + +??? ?????????? ???????? ???????? ??? ????????? segmentation fault; +?????? ????????? ? 1.27.2. + + +a segmentation fault might occur in a worker process on shutdown; +the bug had appeared in 1.27.2. + + + + + +? ????????? open_file_cache. + + +in the "open_file_cache" directive. + + + + + + From mdounin at mdounin.ru Tue Jul 8 11:37:48 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 14:37:48 +0300 Subject: [nginx] release-1.29.0 tag Message-ID: details: http://freenginx.org/hg/nginx/rev/918faf0c610d branches: changeset: 9393:918faf0c610d user: Maxim Dounin date: Tue Jul 08 14:32:28 2025 +0300 description: release-1.29.0 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -485,3 +485,4 @@ 665f7a7675cf4620c5d05cbcabdf72e6afe18b80 3e58802df709d487e366809eef77f6424433d187 release-1.27.4 e5a159b0c3821bf4e93b8e9ee34604238c93fd2a release-1.27.5 6731069e4b635d9dca49d6de04f0241cf3d856dd release-1.27.6 +441d59c1052d602143764a5765d65c51388c1d7b release-1.29.0 From mdounin at mdounin.ru Tue Jul 8 11:38:22 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Tue, 08 Jul 2025 14:38:22 +0300 Subject: [nginx-site] freenginx-1.29.0 Message-ID: details: http://freenginx.org/hg/nginx-site/rev/3a560618c4cd branches: changeset: 3111:3a560618c4cd user: Maxim Dounin date: Tue Jul 08 14:36:04 2025 +0300 description: freenginx-1.29.0 diffstat: text/en/CHANGES | 38 ++++++++++++++++++++++++++++++++++++++ text/ru/CHANGES.ru | 39 +++++++++++++++++++++++++++++++++++++++ xml/index.xml | 16 ++++++++++++++++ xml/versions.xml | 2 +- 4 files changed, 94 insertions(+), 1 deletions(-) diffs (131 lines): diff --git a/text/en/CHANGES b/text/en/CHANGES --- a/text/en/CHANGES +++ b/text/en/CHANGES @@ -1,4 +1,42 @@ +Changes with freenginx 1.29.0 08 Jul 2025 + + *) Change: the "directio" directive now works when returning responses + from cache. + + *) Change: the "limit_rate" directive now uses the leaky bucket + algorithm, allowing more accurate enforcement of the specified rate; + the "limit_rate_after" directive specifies the allowed size of + traffic bursts. + + *) Change: the $request_time variable now remains correct on system time + changes. + + *) Feature: the "send_min_rate" and "client_body_min_rate" directives. + + *) Feature: the "limit_rate" and "limit_rate_after" directives in the + mail proxy module. + + *) Feature: the "lingering_close", "lingering_time", and + "lingering_timeout" directives in the mail proxy module. + + *) Feature: connection limiting in the mail proxy module. + + *) Workaround: the "send_timeout" directive might not work when the + kernel TCP memory limit was reached on Linux. + + *) Workaround: gcc 15.1 compatibility. + + *) Bugfix: a segmentation fault might occur in a worker process if the + "proxy_ssl_password_file" directive was used in the stream module; + the bug had appeared in 1.23.1. + + *) Bugfix: a segmentation fault might occur in a worker process on + shutdown; the bug had appeared in 1.27.2. + + *) Bugfix: in the "open_file_cache" directive. + + Changes with freenginx 1.27.6 15 Apr 2025 *) Workaround: the X25519MLKEM768 group name was not shown in the diff --git a/text/ru/CHANGES.ru b/text/ru/CHANGES.ru --- a/text/ru/CHANGES.ru +++ b/text/ru/CHANGES.ru @@ -1,4 +1,43 @@ +????????? ? freenginx 1.29.0 08.07.2025 + + *) ?????????: ?????? ????????? directio ???????? ??? ???????, + ???????????? ?? ????. + + *) ?????????: ?????? ????????? limit_rate ?????????? ???????? leaky + bucket, ??? ????????? ????? ????? ???????????? ???????? ????????; + ????????? limit_rate_after ?????? ?????????? ?????? ????????? + ???????. + + *) ?????????: ?????? ?????????? $request_time ???????? ?????????? ??? + ?????????? ?????????? ???????. + + *) ??????????: ????????? send_min_rate ? client_body_min_rate. + + *) ??????????: ????????? limit_rate ? limit_rate_after ? ???????? + ??????-???????. + + *) ??????????: ????????? lingering_close, lingering_time ? + lingering_timeout ? ???????? ??????-???????. + + *) ??????????: ??????????? ?????????? ?????????? ? ???????? + ??????-???????. + + *) ?????????: ??? ?????????? ??????????? ???? ?? ?????????? TCP ?????? + ????????? "send_timeout" ????? ?? ????????. + + *) ?????????: ????????????? ? gcc 15.1. + + *) ???????????: ? ??????? ???????? ??? ????????? segmentation fault, + ???? ?????????????? ????????? proxy_ssl_password_file ? ?????? + stream; ?????? ????????? ? 1.23.1. + + *) ???????????: ??? ?????????? ???????? ???????? ??? ????????? + segmentation fault; ?????? ????????? ? 1.27.2. + + *) ???????????: ? ????????? open_file_cache. + + ????????? ? freenginx 1.27.6 15.04.2025 *) ?????????: ??? ????????????? OpenSSL 3.5 ? ?????????? $ssl_curve ? diff --git a/xml/index.xml b/xml/index.xml --- a/xml/index.xml +++ b/xml/index.xml @@ -8,6 +8,22 @@ + + +freenginx-1.29.0 +mainline version has been released, +featuring +improved handling of network memory pressure conditions on Linux, + +support in cache, + +and +connection +limiting in the mail proxy module, +and more. + + + freenginx-1.28.0 diff --git a/xml/versions.xml b/xml/versions.xml --- a/xml/versions.xml +++ b/xml/versions.xml @@ -9,7 +9,7 @@ - + From mdounin at mdounin.ru Wed Jul 9 03:20:15 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 09 Jul 2025 06:20:15 +0300 Subject: [nginx-site] Adjusted varindex generation. Message-ID: details: http://freenginx.org/hg/nginx-site/rev/67f4c17a2b88 branches: changeset: 3112:67f4c17a2b88 user: Maxim Dounin date: Tue Jul 08 21:09:01 2025 +0300 description: Adjusted varindex generation. Pseudo-variables in ngx_mail_limit_conn_module do not have @id attributes, yet varindex anyway tried to link them. Fix is to require @id attribute on when looking for variables. diffstat: xsls/varindex.xsls | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/xsls/varindex.xsls b/xsls/varindex.xsls --- a/xsls/varindex.xsls +++ b/xsls/varindex.xsls @@ -32,7 +32,7 @@ X:template = "modules" { X:template = "module" { X:var module="@name" - X:for-each "document(@name)//tag-name/var" { + X:for-each "document(@name)//tag-name[@id]/var" { !!; } } From mdounin at mdounin.ru Wed Jul 9 03:20:15 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 09 Jul 2025 06:20:15 +0300 Subject: [nginx-site] Regenerated. Message-ID: details: http://freenginx.org/hg/nginx-site/rev/ce5de7d6dccd branches: changeset: 3113:ce5de7d6dccd user: Maxim Dounin date: Tue Jul 08 21:09:40 2025 +0300 description: Regenerated. diffstat: xslt/varindex.xslt | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/xslt/varindex.xslt b/xslt/varindex.xslt --- a/xslt/varindex.xslt +++ b/xslt/varindex.xslt @@ -30,7 +30,7 @@ - + From mdounin at mdounin.ru Thu Jul 10 11:16:09 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Thu, 10 Jul 2025 14:16:09 +0300 Subject: [PATCH] Win32: fixed time_t size for 32-bit builds with MSVC Message-ID: # HG changeset patch # User Maxim Dounin # Date 1752146087 -10800 # Thu Jul 10 14:14:47 2025 +0300 # Node ID a66da54900004f1e8509a6a50786707ab192472c # Parent 918faf0c610d6eaec6ade0bb5f2ca379b74f0365 Win32: fixed time_t size for 32-bit builds with MSVC. Starting with MSVC 2005, 64-bit time_t is used by default, including 32-bit builds (unless _USE_32BIT_TIME_T is explicitly defined). However, the code assumed 32-bit time_t. With current code, this shouldn't cause any negative effects, as various related sizes are only used for values which are expected to fit into 32 bits. Still, using correct size is obviously preferred, and also will work after 2038. Fix is to explicitly check MSVC version, and assume 64-bit time_t for recent enough versions. diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -217,15 +217,26 @@ typedef int sig_atomic_t #define NGX_PTR_SIZE 8 #define NGX_SIZE_T_LEN (sizeof("-9223372036854775808") - 1) #define NGX_MAX_SIZE_T_VALUE 9223372036854775807 + +#else + +#define NGX_PTR_SIZE 4 +#define NGX_SIZE_T_LEN (sizeof("-2147483648") - 1) +#define NGX_MAX_SIZE_T_VALUE 2147483647 + +#endif + + +#if (defined _WIN64 || (_MSC_VER >= 1400 && !defined _USE_32BIT_TIME_T)) + +/* MSVC 2005 uses 64-bit time_t on 32-bit platforms by default */ + #define NGX_TIME_T_LEN (sizeof("-9223372036854775808") - 1) #define NGX_TIME_T_SIZE 8 #define NGX_MAX_TIME_T_VALUE 9223372036854775807 #else -#define NGX_PTR_SIZE 4 -#define NGX_SIZE_T_LEN (sizeof("-2147483648") - 1) -#define NGX_MAX_SIZE_T_VALUE 2147483647 #define NGX_TIME_T_LEN (sizeof("-2147483648") - 1) #define NGX_TIME_T_SIZE 4 #define NGX_MAX_TIME_T_VALUE 2147483647 From mdounin at mdounin.ru Fri Jul 11 09:51:44 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Fri, 11 Jul 2025 12:51:44 +0300 Subject: [nginx-tests] Tests: workaround for IO::Socket::SSL sysread() is... Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/0b27b42aef05 branches: changeset: 2011:0b27b42aef05 user: Maxim Dounin date: Fri Jul 11 12:49:19 2025 +0300 description: Tests: workaround for IO::Socket::SSL sysread() issue. IO::Socket::SSL 2.091 to 2.094 fails to clear buffer in sysread() on EOF (https://github.com/noxxi/p5-io-socket-ssl/issues/171), the issue is fixed in IO::Socket::SSL 2.095. As a as a workaround for the affected versions, we set the buffer explicitly to an empty string if sysread() returns 0. diffstat: lib/Test/Nginx/Stream.pm | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diffs (17 lines): diff --git a/lib/Test/Nginx/Stream.pm b/lib/Test/Nginx/Stream.pm --- a/lib/Test/Nginx/Stream.pm +++ b/lib/Test/Nginx/Stream.pm @@ -114,6 +114,13 @@ sub read { while (IO::Select->new($s)->can_read($extra{read_timeout} || 8)) { my $n = $s->sysread($buf, 1024); next if !defined $n && $!{EWOULDBLOCK}; + + # IO::Socket::SSL 2.091 to 2.094 fails to clear buffer on EOF + # (https://github.com/noxxi/p5-io-socket-ssl/issues/171); + # as a workaround, we set it explicitly to an empty string + + $buf = '' if defined $n && $n == 0; + last; } From mdounin at mdounin.ru Tue Jul 15 13:50:28 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Tue, 15 Jul 2025 16:50:28 +0300 Subject: [PATCH] Worked around EINVAL from shutdown() on NetBSD Message-ID: # HG changeset patch # User Maxim Dounin # Date 1752506823 -10800 # Mon Jul 14 18:27:03 2025 +0300 # Node ID cf229ea45d3469b20449dcbdafd3e29ed2632805 # Parent a66da54900004f1e8509a6a50786707ab192472c Worked around EINVAL from shutdown() on NetBSD. If a connection was reset by the client, shutdown() on NetBSD returns EINVAL, leading to test failures, as seen in the ssl_conf_command.t test. Fix is to ignore EINVAL from shutdown() on NetBSD, similarly to how we do with EINVAL from setsockopt() on Solaris. diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1619,11 +1619,9 @@ ngx_connection_error(ngx_connection_t *c return 0; } -#if (NGX_SOLARIS) if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) { return 0; } -#endif if (err == NGX_EMSGSIZE && c->log_error == NGX_ERROR_IGNORE_EMSGSIZE) { return 0; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3579,6 +3579,10 @@ ngx_http_set_lingering_close(ngx_connect } if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { +#if (defined __NetBSD__) + /* NetBSD returns EINVAL if the connection was reset */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif ngx_connection_error(c, ngx_socket_errno, ngx_shutdown_socket_n " failed"); ngx_http_close_request(r, 0); diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -805,6 +805,10 @@ ngx_http_v2_lingering_close(ngx_connecti } if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { +#if (defined __NetBSD__) + /* NetBSD returns EINVAL if the connection was reset */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif ngx_connection_error(c, ngx_socket_errno, ngx_shutdown_socket_n " failed"); ngx_http_close_connection(c); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -1330,6 +1330,10 @@ ngx_mail_lingering_close(ngx_connection_ } if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { +#if (defined __NetBSD__) + /* NetBSD returns EINVAL if the connection was reset */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif ngx_connection_error(c, ngx_socket_errno, ngx_shutdown_socket_n " failed"); ngx_mail_close_connection(c); From mdounin at mdounin.ru Sat Jul 19 02:59:15 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 05:59:15 +0300 Subject: [nginx] Version bump. Message-ID: details: http://freenginx.org/hg/nginx/rev/23085777155d branches: changeset: 9394:23085777155d user: Maxim Dounin date: Sat Jul 19 05:56:30 2025 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1029000 -#define NGINX_VERSION "1.29.0" +#define nginx_version 1029001 +#define NGINX_VERSION "1.29.1" #define freenginx 1 From mdounin at mdounin.ru Sat Jul 19 02:59:15 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 05:59:15 +0300 Subject: [nginx] Win32: fixed time_t size for 32-bit builds with MSVC. Message-ID: details: http://freenginx.org/hg/nginx/rev/8d1dd903e480 branches: changeset: 9395:8d1dd903e480 user: Maxim Dounin date: Sat Jul 19 05:57:34 2025 +0300 description: Win32: fixed time_t size for 32-bit builds with MSVC. Starting with MSVC 2005, 64-bit time_t is used by default, including 32-bit builds (unless _USE_32BIT_TIME_T is explicitly defined). However, the code assumed 32-bit time_t. With current code, this shouldn't cause any negative effects, as various related sizes are only used for values which are expected to fit into 32 bits. Still, using correct size is obviously preferred, and also will work after 2038. Fix is to explicitly check MSVC version, and assume 64-bit time_t for recent enough versions. diffstat: src/os/win32/ngx_win32_config.h | 17 ++++++++++++++--- 1 files changed, 14 insertions(+), 3 deletions(-) diffs (33 lines): diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -217,15 +217,26 @@ typedef int sig_atomic_t #define NGX_PTR_SIZE 8 #define NGX_SIZE_T_LEN (sizeof("-9223372036854775808") - 1) #define NGX_MAX_SIZE_T_VALUE 9223372036854775807 + +#else + +#define NGX_PTR_SIZE 4 +#define NGX_SIZE_T_LEN (sizeof("-2147483648") - 1) +#define NGX_MAX_SIZE_T_VALUE 2147483647 + +#endif + + +#if (defined _WIN64 || (_MSC_VER >= 1400 && !defined _USE_32BIT_TIME_T)) + +/* MSVC 2005 uses 64-bit time_t on 32-bit platforms by default */ + #define NGX_TIME_T_LEN (sizeof("-9223372036854775808") - 1) #define NGX_TIME_T_SIZE 8 #define NGX_MAX_TIME_T_VALUE 9223372036854775807 #else -#define NGX_PTR_SIZE 4 -#define NGX_SIZE_T_LEN (sizeof("-2147483648") - 1) -#define NGX_MAX_SIZE_T_VALUE 2147483647 #define NGX_TIME_T_LEN (sizeof("-2147483648") - 1) #define NGX_TIME_T_SIZE 4 #define NGX_MAX_TIME_T_VALUE 2147483647 From mdounin at mdounin.ru Sat Jul 19 02:59:15 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 05:59:15 +0300 Subject: [nginx] Worked around EINVAL from shutdown() on NetBSD. Message-ID: details: http://freenginx.org/hg/nginx/rev/e0792bb674b0 branches: changeset: 9396:e0792bb674b0 user: Maxim Dounin date: Sat Jul 19 05:57:53 2025 +0300 description: Worked around EINVAL from shutdown() on NetBSD. If a connection was reset by the client, shutdown() on NetBSD returns EINVAL, leading to test failures, as seen in the ssl_conf_command.t test. Fix is to ignore EINVAL from shutdown() on NetBSD, similarly to how we do with EINVAL from setsockopt() on Solaris. diffstat: src/core/ngx_connection.c | 2 -- src/http/ngx_http_request.c | 4 ++++ src/http/v2/ngx_http_v2.c | 4 ++++ src/mail/ngx_mail_handler.c | 4 ++++ 4 files changed, 12 insertions(+), 2 deletions(-) diffs (57 lines): diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1619,11 +1619,9 @@ ngx_connection_error(ngx_connection_t *c return 0; } -#if (NGX_SOLARIS) if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) { return 0; } -#endif if (err == NGX_EMSGSIZE && c->log_error == NGX_ERROR_IGNORE_EMSGSIZE) { return 0; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -3579,6 +3579,10 @@ ngx_http_set_lingering_close(ngx_connect } if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { +#if (defined __NetBSD__) + /* NetBSD returns EINVAL if the connection was reset */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif ngx_connection_error(c, ngx_socket_errno, ngx_shutdown_socket_n " failed"); ngx_http_close_request(r, 0); diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -805,6 +805,10 @@ ngx_http_v2_lingering_close(ngx_connecti } if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { +#if (defined __NetBSD__) + /* NetBSD returns EINVAL if the connection was reset */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif ngx_connection_error(c, ngx_socket_errno, ngx_shutdown_socket_n " failed"); ngx_http_close_connection(c); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -1330,6 +1330,10 @@ ngx_mail_lingering_close(ngx_connection_ } if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { +#if (defined __NetBSD__) + /* NetBSD returns EINVAL if the connection was reset */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif ngx_connection_error(c, ngx_socket_errno, ngx_shutdown_socket_n " failed"); ngx_mail_close_connection(c); From mdounin at mdounin.ru Sat Jul 19 03:15:05 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 06:15:05 +0300 Subject: [PATCH 1 of 5] Tests: improved proxy_unfinished.t performance Message-ID: # HG changeset patch # User Maxim Dounin # Date 1752891869 -10800 # Sat Jul 19 05:24:29 2025 +0300 # Node ID b04d3b7129f628b1f8c82701b740d333d7bf60dc # Parent 0b27b42aef05eebd9d180c7ada585ea6ae3da538 Tests: improved proxy_unfinished.t performance. There is no real reasons to use "for (1 .. 10000) { print ... }" loops in the test server, yet they require a lot of CPU, leading to occasional test failures on slow hosts. Accordingly, such constructs were changed to prints with large buffers instead. diff --git a/proxy_unfinished.t b/proxy_unfinished.t --- a/proxy_unfinished.t +++ b/proxy_unfinished.t @@ -216,9 +216,7 @@ sub http_daemon { "Cache-Control: max-age=300" . CRLF . "Connection: close" . CRLF . CRLF; - for (1 .. 10000) { - print $client ("X" x 98) . CRLF; - } + print $client (("X" x 98) . CRLF) x 10000; print $client "unfinished" . CRLF; } elsif ($uri eq '/big/ok') { @@ -228,9 +226,7 @@ sub http_daemon { "Cache-Control: max-age=300" . CRLF . "Connection: close" . CRLF . CRLF; - for (1 .. 10000) { - print $client ("X" x 98) . CRLF; - } + print $client (("X" x 98) . CRLF) x 10000; print $client "finished" . CRLF; } elsif ($uri eq '/chunked') { From mdounin at mdounin.ru Sat Jul 19 03:15:06 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 06:15:06 +0300 Subject: [PATCH 2 of 5] Tests: reduced ssl.t pipelining test time In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1752891898 -10800 # Sat Jul 19 05:24:58 2025 +0300 # Node ID a93d11a64ed526a847d531dae657d23b41550395 # Parent b04d3b7129f628b1f8c82701b740d333d7bf60dc Tests: reduced ssl.t pipelining test time. Doing 1000 pipelined requests might require significant time, as seen on NetBSD with debugging enabled, and might cause occasional failures on slow hosts. To mitigate, the test changed to do only 100 requests instead. diff --git a/ssl.t b/ssl.t --- a/ssl.t +++ b/ssl.t @@ -250,17 +250,17 @@ like(get_body('/body', '0123456789', 20, # pipelined requests $s = get_ssl_socket(8085); -my $req = < $s) || ""; $s = undef; -is(() = $r =~ /(200 OK)/g, 1000, 'pipelined requests'); +is(() = $r =~ /(200 OK)/g, 100, 'pipelined requests'); # OpenSSL 3.0 error "unexpected eof while reading" seen as a critical error From mdounin at mdounin.ru Sat Jul 19 03:15:07 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 06:15:07 +0300 Subject: [PATCH 3 of 5] Tests: improved h2_priority.t In-Reply-To: References: Message-ID: <0f089661084dfb37a525.1752894907@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1752891914 -10800 # Sat Jul 19 05:25:14 2025 +0300 # Node ID 0f089661084dfb37a525fb33221dab288985be6e # Parent a93d11a64ed526a847d531dae657d23b41550395 Tests: improved h2_priority.t. Tests in h2_priority.t do not tolerate extra data being split over multiple HTTP/2 frames, yet this can happen if writing to the socket buffer blocks and then a small amount of data (1 byte) remains in the HTTP/2 connection queue due to flow control: when the window is opened again, this 1 byte will be sent in a separate frame, and the remaining bytes will be read and sent afterwards. Failures due to this issue were observed during testing on OpenBSD, and might be easily reproduced on other platforms with small enough socket buffers. Fix is to use output_buffers large enough to read the full response, so the remaining bytes are always sent in a single HTTP/2 frame. diff --git a/h2_priority.t b/h2_priority.t --- a/h2_priority.t +++ b/h2_priority.t @@ -40,6 +40,7 @@ http { listen 127.0.0.1:8080; server_name localhost; http2 on; + output_buffers 3 32k; } } From mdounin at mdounin.ru Sat Jul 19 03:15:08 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 06:15:08 +0300 Subject: [PATCH 4 of 5] Tests: fixed ssl_certificates.t with LibreSSL client In-Reply-To: References: Message-ID: <05796ad34858cbaaa6d6.1752894908@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1752891917 -10800 # Sat Jul 19 05:25:17 2025 +0300 # Node ID 05796ad34858cbaaa6d63b405d873be6df9d0c08 # Parent 0f089661084dfb37a525fb33221dab288985be6e Tests: fixed ssl_certificates.t with LibreSSL client. When Net::SSLeay is built with LibreSSL, it is not possible to control signature algorithms sent to the server, which results in incorrect certificate selection with TLSv1.3. Notably, with LibreSSL on server an ECDSA certificate is always used, and with OpenSSL an RSA certificate. Following 2005:00307a7f3cad, TODO in a test expecting an RSA certificate is no longer used for LibreSSL 4.0.0 and above. This works with OpenSSL on the server, but breaks when LibreSSL is used on the server. Fix is to mark the test as TODO when LibreSSL (any version) is used both on the server and by the Net::SSLeay library. diff --git a/ssl_certificates.t b/ssl_certificates.t --- a/ssl_certificates.t +++ b/ssl_certificates.t @@ -99,6 +99,10 @@ local $TODO = 'broken TLSv1.3 sigalgs in if $t->has_module('LibreSSL') && !$t->has_feature('libressl:4.0.0') && test_tls13(); +local $TODO = 'no TLSv1.3 sigalgs in Net::SSLeay (LibreSSL)' + if Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER") + && $t->has_module('LibreSSL') + && test_tls13(); like(cert('RSA'), qr/CN=rsa/, 'ssl cert RSA'); From mdounin at mdounin.ru Sat Jul 19 03:15:09 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Sat, 19 Jul 2025 06:15:09 +0300 Subject: [PATCH 5 of 5] Tests: style In-Reply-To: References: Message-ID: # HG changeset patch # User Maxim Dounin # Date 1752891920 -10800 # Sat Jul 19 05:25:20 2025 +0300 # Node ID d28c6b8eb29137664e5e949aeef01863082462ce # Parent 05796ad34858cbaaa6d63b405d873be6df9d0c08 Tests: style. diff --git a/ssl_certificates.t b/ssl_certificates.t --- a/ssl_certificates.t +++ b/ssl_certificates.t @@ -78,7 +78,7 @@ my $d = $t->testdir(); system("openssl ecparam -genkey -out $d/ec.key -name prime256v1 " . ">>$d/openssl.out 2>&1") == 0 or die "Can't create EC pem: $!\n"; system("openssl genrsa -out $d/rsa.key 2048 >>$d/openssl.out 2>&1") == 0 - or die "Can't create RSA pem: $!\n"; + or die "Can't create RSA pem: $!\n"; foreach my $name ('ec', 'rsa') { system("openssl req -x509 -new -key $d/$name.key " diff --git a/ssl_sni_sessions.t b/ssl_sni_sessions.t --- a/ssl_sni_sessions.t +++ b/ssl_sni_sessions.t @@ -115,7 +115,7 @@ plan(skip_all => 'no TLSv1.3 sessions, o plan(skip_all => 'no TLSv1.3 sessions, old IO::Socket::SSL') if $IO::Socket::SSL::VERSION < 2.061 && test_tls13(); plan(skip_all => 'no TLSv1.3 sessions in LibreSSL') - if $t->has_module('LibreSSL') && test_tls13(); + if $t->has_module('LibreSSL') && test_tls13(); plan(skip_all => 'no TLSv1.3 sessions in Net::SSLeay (LibreSSL)') if Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER") && test_tls13(); plan(skip_all => 'no TLS 1.3 session cache in BoringSSL') From mdounin at mdounin.ru Mon Jul 21 21:31:45 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Tue, 22 Jul 2025 00:31:45 +0300 Subject: [PATCH] Tests: adjusted proxy_cache_use_stale.t times Message-ID: <0b65f4c779066132ebb7.1753133505@vm-bsd.mdounin.ru> # HG changeset patch # User Maxim Dounin # Date 1753124770 -10800 # Mon Jul 21 22:06:10 2025 +0300 # Node ID 0b65f4c779066132ebb782923c8f3b3a0c03904a # Parent d28c6b8eb29137664e5e949aeef01863082462ce Tests: adjusted proxy_cache_use_stale.t times. Previously, "stale-while-revalidate=10" was used in tests where stale response should be usable till the end of the test. This is, however, might be not enough on slow hosts, leading to occasional failures. Fix is to use "stale-while-revalidate=20" instead. diff --git a/proxy_cache_use_stale.t b/proxy_cache_use_stale.t --- a/proxy_cache_use_stale.t +++ b/proxy_cache_use_stale.t @@ -132,7 +132,7 @@ http { } location /t9.html { - add_header Cache-Control "max-age=1, stale-while-revalidate=10"; + add_header Cache-Control "max-age=1, stale-while-revalidate=20"; } } } @@ -157,23 +157,23 @@ EOF like(get('/t.html', 'max-age=1, stale-if-error=5'), qr/MISS/, 'stale-if-error'); like(http_get('/t.html?e=1'), qr/HIT/, 's-i-e - cached'); -like(get('/t2.html', 'max-age=1, stale-while-revalidate=10'), qr/MISS/, +like(get('/t2.html', 'max-age=1, stale-while-revalidate=20'), qr/MISS/, 'stale-while-revalidate'); like(http_get('/t2.html'), qr/HIT/, 's-w-r - cached'); get('/tt.html', 'max-age=1, stale-if-error=3'); get('/t3.html', 'max-age=1, stale-while-revalidate=2'); -get('/t4.html', 'max-age=1, stale-while-revalidate=10'); -get('/t5.html', 'max-age=1, stale-while-revalidate=10'); -get('/t6.html', 'max-age=1, stale-while-revalidate=10'); -get('/t7.html', 'max-age=1, stale-while-revalidate=10'); +get('/t4.html', 'max-age=1, stale-while-revalidate=20'); +get('/t5.html', 'max-age=1, stale-while-revalidate=20'); +get('/t6.html', 'max-age=1, stale-while-revalidate=20'); +get('/t7.html', 'max-age=1, stale-while-revalidate=20'); http_get('/ssi.html'); get('/updating/t.html', 'max-age=1'); get('/updating/t2.html', 'max-age=1, stale-while-revalidate=2'); get('/updating/tt.html', 'max-age=1, stale-if-error=5'); -get('/t8.html', 'stale-while-revalidate=10'); -get('/escape.htm%6C', 'max-age=1, stale-while-revalidate=10'); -get('/regexp.html', 'max-age=1, stale-while-revalidate=10'); +get('/t8.html', 'stale-while-revalidate=20'); +get('/escape.htm%6C', 'max-age=1, stale-while-revalidate=20'); +get('/regexp.html', 'max-age=1, stale-while-revalidate=20'); sleep 2; From mdounin at mdounin.ru Wed Jul 23 18:55:11 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 23 Jul 2025 21:55:11 +0300 Subject: [nginx-tests] Tests: improved proxy_unfinished.t performance. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/b04d3b7129f6 branches: changeset: 2012:b04d3b7129f6 user: Maxim Dounin date: Sat Jul 19 05:24:29 2025 +0300 description: Tests: improved proxy_unfinished.t performance. There is no real reasons to use "for (1 .. 10000) { print ... }" loops in the test server, yet they require a lot of CPU, leading to occasional test failures on slow hosts. Accordingly, such constructs were changed to prints with large buffers instead. diffstat: proxy_unfinished.t | 8 ++------ 1 files changed, 2 insertions(+), 6 deletions(-) diffs (25 lines): diff --git a/proxy_unfinished.t b/proxy_unfinished.t --- a/proxy_unfinished.t +++ b/proxy_unfinished.t @@ -216,9 +216,7 @@ sub http_daemon { "Cache-Control: max-age=300" . CRLF . "Connection: close" . CRLF . CRLF; - for (1 .. 10000) { - print $client ("X" x 98) . CRLF; - } + print $client (("X" x 98) . CRLF) x 10000; print $client "unfinished" . CRLF; } elsif ($uri eq '/big/ok') { @@ -228,9 +226,7 @@ sub http_daemon { "Cache-Control: max-age=300" . CRLF . "Connection: close" . CRLF . CRLF; - for (1 .. 10000) { - print $client ("X" x 98) . CRLF; - } + print $client (("X" x 98) . CRLF) x 10000; print $client "finished" . CRLF; } elsif ($uri eq '/chunked') { From mdounin at mdounin.ru Wed Jul 23 18:55:12 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 23 Jul 2025 21:55:12 +0300 Subject: [nginx-tests] Tests: reduced ssl.t pipelining test time. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/a93d11a64ed5 branches: changeset: 2013:a93d11a64ed5 user: Maxim Dounin date: Sat Jul 19 05:24:58 2025 +0300 description: Tests: reduced ssl.t pipelining test time. Doing 1000 pipelined requests might require significant time, as seen on NetBSD with debugging enabled, and might cause occasional failures on slow hosts. To mitigate, the test changed to do only 100 requests instead. diffstat: ssl.t | 14 +++++++------- 1 files changed, 7 insertions(+), 7 deletions(-) diffs (28 lines): diff --git a/ssl.t b/ssl.t --- a/ssl.t +++ b/ssl.t @@ -250,17 +250,17 @@ like(get_body('/body', '0123456789', 20, # pipelined requests $s = get_ssl_socket(8085); -my $req = < $s) || ""; $s = undef; -is(() = $r =~ /(200 OK)/g, 1000, 'pipelined requests'); +is(() = $r =~ /(200 OK)/g, 100, 'pipelined requests'); # OpenSSL 3.0 error "unexpected eof while reading" seen as a critical error From mdounin at mdounin.ru Wed Jul 23 18:55:12 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 23 Jul 2025 21:55:12 +0300 Subject: [nginx-tests] Tests: improved h2_priority.t. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/0f089661084d branches: changeset: 2014:0f089661084d user: Maxim Dounin date: Sat Jul 19 05:25:14 2025 +0300 description: Tests: improved h2_priority.t. Tests in h2_priority.t do not tolerate extra data being split over multiple HTTP/2 frames, yet this can happen if writing to the socket buffer blocks and then a small amount of data (1 byte) remains in the HTTP/2 connection queue due to flow control: when the window is opened again, this 1 byte will be sent in a separate frame, and the remaining bytes will be read and sent afterwards. Failures due to this issue were observed during testing on OpenBSD, and might be easily reproduced on other platforms with small enough socket buffers. Fix is to use output_buffers large enough to read the full response, so the remaining bytes are always sent in a single HTTP/2 frame. diffstat: h2_priority.t | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff --git a/h2_priority.t b/h2_priority.t --- a/h2_priority.t +++ b/h2_priority.t @@ -40,6 +40,7 @@ http { listen 127.0.0.1:8080; server_name localhost; http2 on; + output_buffers 3 32k; } } From mdounin at mdounin.ru Wed Jul 23 18:55:12 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 23 Jul 2025 21:55:12 +0300 Subject: [nginx-tests] Tests: fixed ssl_certificates.t with LibreSSL client. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/05796ad34858 branches: changeset: 2015:05796ad34858 user: Maxim Dounin date: Sat Jul 19 05:25:17 2025 +0300 description: Tests: fixed ssl_certificates.t with LibreSSL client. When Net::SSLeay is built with LibreSSL, it is not possible to control signature algorithms sent to the server, which results in incorrect certificate selection with TLSv1.3. Notably, with LibreSSL on server an ECDSA certificate is always used, and with OpenSSL an RSA certificate. Following 2005:00307a7f3cad, TODO in a test expecting an RSA certificate is no longer used for LibreSSL 4.0.0 and above. This works with OpenSSL on the server, but breaks when LibreSSL is used on the server. Fix is to mark the test as TODO when LibreSSL (any version) is used both on the server and by the Net::SSLeay library. diffstat: ssl_certificates.t | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diffs (14 lines): diff --git a/ssl_certificates.t b/ssl_certificates.t --- a/ssl_certificates.t +++ b/ssl_certificates.t @@ -99,6 +99,10 @@ local $TODO = 'broken TLSv1.3 sigalgs in if $t->has_module('LibreSSL') && !$t->has_feature('libressl:4.0.0') && test_tls13(); +local $TODO = 'no TLSv1.3 sigalgs in Net::SSLeay (LibreSSL)' + if Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER") + && $t->has_module('LibreSSL') + && test_tls13(); like(cert('RSA'), qr/CN=rsa/, 'ssl cert RSA'); From mdounin at mdounin.ru Wed Jul 23 18:55:12 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 23 Jul 2025 21:55:12 +0300 Subject: [nginx-tests] Tests: style. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/d28c6b8eb291 branches: changeset: 2016:d28c6b8eb291 user: Maxim Dounin date: Sat Jul 19 05:25:20 2025 +0300 description: Tests: style. diffstat: ssl_certificates.t | 2 +- ssl_sni_sessions.t | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff --git a/ssl_certificates.t b/ssl_certificates.t --- a/ssl_certificates.t +++ b/ssl_certificates.t @@ -78,7 +78,7 @@ my $d = $t->testdir(); system("openssl ecparam -genkey -out $d/ec.key -name prime256v1 " . ">>$d/openssl.out 2>&1") == 0 or die "Can't create EC pem: $!\n"; system("openssl genrsa -out $d/rsa.key 2048 >>$d/openssl.out 2>&1") == 0 - or die "Can't create RSA pem: $!\n"; + or die "Can't create RSA pem: $!\n"; foreach my $name ('ec', 'rsa') { system("openssl req -x509 -new -key $d/$name.key " diff --git a/ssl_sni_sessions.t b/ssl_sni_sessions.t --- a/ssl_sni_sessions.t +++ b/ssl_sni_sessions.t @@ -115,7 +115,7 @@ plan(skip_all => 'no TLSv1.3 sessions, o plan(skip_all => 'no TLSv1.3 sessions, old IO::Socket::SSL') if $IO::Socket::SSL::VERSION < 2.061 && test_tls13(); plan(skip_all => 'no TLSv1.3 sessions in LibreSSL') - if $t->has_module('LibreSSL') && test_tls13(); + if $t->has_module('LibreSSL') && test_tls13(); plan(skip_all => 'no TLSv1.3 sessions in Net::SSLeay (LibreSSL)') if Net::SSLeay::constant("LIBRESSL_VERSION_NUMBER") && test_tls13(); plan(skip_all => 'no TLS 1.3 session cache in BoringSSL') From mdounin at mdounin.ru Wed Jul 23 18:55:12 2025 From: mdounin at mdounin.ru (=?iso-8859-1?q?Maxim_Dounin?=) Date: Wed, 23 Jul 2025 21:55:12 +0300 Subject: [nginx-tests] Tests: adjusted proxy_cache_use_stale.t times. Message-ID: details: http://freenginx.org/hg/nginx-tests/rev/0b65f4c77906 branches: changeset: 2017:0b65f4c77906 user: Maxim Dounin date: Mon Jul 21 22:06:10 2025 +0300 description: Tests: adjusted proxy_cache_use_stale.t times. Previously, "stale-while-revalidate=10" was used in tests where stale response should be usable till the end of the test. This is, however, might be not enough on slow hosts, leading to occasional failures. Fix is to use "stale-while-revalidate=20" instead. diffstat: proxy_cache_use_stale.t | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diffs (44 lines): diff --git a/proxy_cache_use_stale.t b/proxy_cache_use_stale.t --- a/proxy_cache_use_stale.t +++ b/proxy_cache_use_stale.t @@ -132,7 +132,7 @@ http { } location /t9.html { - add_header Cache-Control "max-age=1, stale-while-revalidate=10"; + add_header Cache-Control "max-age=1, stale-while-revalidate=20"; } } } @@ -157,23 +157,23 @@ EOF like(get('/t.html', 'max-age=1, stale-if-error=5'), qr/MISS/, 'stale-if-error'); like(http_get('/t.html?e=1'), qr/HIT/, 's-i-e - cached'); -like(get('/t2.html', 'max-age=1, stale-while-revalidate=10'), qr/MISS/, +like(get('/t2.html', 'max-age=1, stale-while-revalidate=20'), qr/MISS/, 'stale-while-revalidate'); like(http_get('/t2.html'), qr/HIT/, 's-w-r - cached'); get('/tt.html', 'max-age=1, stale-if-error=3'); get('/t3.html', 'max-age=1, stale-while-revalidate=2'); -get('/t4.html', 'max-age=1, stale-while-revalidate=10'); -get('/t5.html', 'max-age=1, stale-while-revalidate=10'); -get('/t6.html', 'max-age=1, stale-while-revalidate=10'); -get('/t7.html', 'max-age=1, stale-while-revalidate=10'); +get('/t4.html', 'max-age=1, stale-while-revalidate=20'); +get('/t5.html', 'max-age=1, stale-while-revalidate=20'); +get('/t6.html', 'max-age=1, stale-while-revalidate=20'); +get('/t7.html', 'max-age=1, stale-while-revalidate=20'); http_get('/ssi.html'); get('/updating/t.html', 'max-age=1'); get('/updating/t2.html', 'max-age=1, stale-while-revalidate=2'); get('/updating/tt.html', 'max-age=1, stale-if-error=5'); -get('/t8.html', 'stale-while-revalidate=10'); -get('/escape.htm%6C', 'max-age=1, stale-while-revalidate=10'); -get('/regexp.html', 'max-age=1, stale-while-revalidate=10'); +get('/t8.html', 'stale-while-revalidate=20'); +get('/escape.htm%6C', 'max-age=1, stale-while-revalidate=20'); +get('/regexp.html', 'max-age=1, stale-while-revalidate=20'); sleep 2; From mdounin at mdounin.ru Wed Jul 23 19:05:11 2025 From: mdounin at mdounin.ru (=?utf-8?q?Maxim_Dounin?=) Date: Wed, 23 Jul 2025 22:05:11 +0300 Subject: [PATCH] Fixed left-shifting of signed integers into the sign bit Message-ID: # HG changeset patch # User Maxim Dounin # Date 1753296799 -10800 # Wed Jul 23 21:53:19 2025 +0300 # Node ID bdfd605f661eea3d272caf1bd5d85e7c539394ca # Parent e0792bb674b06cbb3c8a68ebff8d32b06a99cb97 Fixed left-shifting of signed integers into the sign bit. If a bitwise left shift operation is used on a signed operand, and the resulting value cannot be represented in the result type, the behaviour is undefined. In all cases in question the result is converted to the appropriate unsigned type, and this doesn't cause any issues with known compilers. Still, avoiding undefined behaviour is generally a good idea, only needs a cast, and we already do this in multiple other places. See also 6627:ad736705a744 and 6626:b3682580c1bd. Prodded by UndefinedBehaviorSanitizer, "-fsanitize=shift". diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -507,7 +507,7 @@ ngx_cidr_match(struct sockaddr *sa, ngx_ p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; diff --git a/src/core/ngx_murmurhash.c b/src/core/ngx_murmurhash.c --- a/src/core/ngx_murmurhash.c +++ b/src/core/ngx_murmurhash.c @@ -19,7 +19,7 @@ ngx_murmur_hash2(u_char *data, size_t le k = data[0]; k |= data[1] << 8; k |= data[2] << 16; - k |= data[3] << 24; + k |= (uint32_t) data[3] << 24; k *= 0x5bd1e995; k ^= k >> 24; diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -2194,7 +2194,7 @@ ngx_resolver_process_a(ngx_resolver_t *r type = (an->type_hi << 8) + an->type_lo; class = (an->class_hi << 8) + an->class_lo; len = (an->len_hi << 8) + an->len_lo; - ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + ttl = ((uint32_t) an->ttl[0] << 24) + (an->ttl[1] << 16) + (an->ttl[2] << 8) + (an->ttl[3]); if (class != 1) { @@ -2356,7 +2356,7 @@ ngx_resolver_process_a(ngx_resolver_t *r if (type == NGX_RESOLVE_A) { - addr[j] = htonl((buf[i] << 24) + (buf[i + 1] << 16) + addr[j] = htonl(((uint32_t) buf[i] << 24) + (buf[i + 1] << 16) + (buf[i + 2] << 8) + (buf[i + 3])); if (++j == naddrs) { @@ -2736,7 +2736,7 @@ ngx_resolver_process_srv(ngx_resolver_t type = (an->type_hi << 8) + an->type_lo; class = (an->class_hi << 8) + an->class_lo; len = (an->len_hi << 8) + an->len_lo; - ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + ttl = ((uint32_t) an->ttl[0] << 24) + (an->ttl[1] << 16) + (an->ttl[2] << 8) + (an->ttl[3]); if (class != 1) { @@ -3142,7 +3142,7 @@ ngx_resolver_process_ptr(ngx_resolver_t goto invalid_in_addr_arpa; } - addr += octet << mask; + addr += (in_addr_t) octet << mask; i += len; } @@ -3301,7 +3301,7 @@ valid: type = (an->type_hi << 8) + an->type_lo; class = (an->class_hi << 8) + an->class_lo; len = (an->len_hi << 8) + an->len_lo; - ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16) + ttl = ((uint32_t) an->ttl[0] << 24) + (an->ttl[1] << 16) + (an->ttl[2] << 8) + (an->ttl[3]); if (class != 1) { diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -148,7 +148,7 @@ ngx_http_access_handler(ngx_http_request p = sin6->sin6_addr.s6_addr; if (alcf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - addr = p[12] << 24; + addr = (in_addr_t) p[12] << 24; addr += p[13] << 16; addr += p[14] << 8; addr += p[15]; diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -199,7 +199,7 @@ ngx_http_geo_cidr_variable(ngx_http_requ p = inaddr6->s6_addr; if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; @@ -272,7 +272,7 @@ ngx_http_geo_range_variable(ngx_http_req if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -266,7 +266,7 @@ ngx_http_geoip_addr(ngx_http_request_t * if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; diff --git a/src/stream/ngx_stream_access_module.c b/src/stream/ngx_stream_access_module.c --- a/src/stream/ngx_stream_access_module.c +++ b/src/stream/ngx_stream_access_module.c @@ -144,7 +144,7 @@ ngx_stream_access_handler(ngx_stream_ses p = sin6->sin6_addr.s6_addr; if (ascf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { - addr = p[12] << 24; + addr = (in_addr_t) p[12] << 24; addr += p[13] << 16; addr += p[14] << 8; addr += p[15]; diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c --- a/src/stream/ngx_stream_geo_module.c +++ b/src/stream/ngx_stream_geo_module.c @@ -190,7 +190,7 @@ ngx_stream_geo_cidr_variable(ngx_stream_ p = inaddr6->s6_addr; if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; @@ -263,7 +263,7 @@ ngx_stream_geo_range_variable(ngx_stream if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; diff --git a/src/stream/ngx_stream_geoip_module.c b/src/stream/ngx_stream_geoip_module.c --- a/src/stream/ngx_stream_geoip_module.c +++ b/src/stream/ngx_stream_geoip_module.c @@ -236,7 +236,7 @@ ngx_stream_geoip_addr(ngx_stream_session if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { p = inaddr6->s6_addr; - inaddr = p[12] << 24; + inaddr = (in_addr_t) p[12] << 24; inaddr += p[13] << 16; inaddr += p[14] << 8; inaddr += p[15]; From lafiel at elven.pw Sat Jul 26 17:48:51 2025 From: lafiel at elven.pw (Lafiel) Date: Sat, 26 Jul 2025 20:48:51 +0300 Subject: [nginx] Update mime-types In-Reply-To: <33cf12d6a7440f5538c60d38ff208870@elven.pw> References: <6fd7b4aae9f284157bcd51b2eb936b82@elven.pw> <33cf12d6a7440f5538c60d38ff208870@elven.pw> Message-ID: <25057fabce20e04e31c2db1426b7606f@elven.pw> Hello! Can you review latest patch? -- Best regards, Lafiel mailto:lafiel at elven.pw -------------- next part -------------- A non-text attachment was scrubbed... Name: 0xFAB0C3D2.asc Type: application/pgp-keys Size: 1839 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: OpenPGP digital signature URL: