From fbcc09e17ff6469aab31ae1df678534c50fb5181 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Sat, 20 Feb 2021 12:44:07 +0300 Subject: [PATCH 01/23] Version bump. --- src/core/nginx.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/nginx.h b/src/core/nginx.h index b926ba6fe..a72666cdd 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1019007 -#define NGINX_VERSION "1.19.7" +#define nginx_version 1019008 +#define NGINX_VERSION "1.19.8" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From 1bb89914d7ba97b18b5ce3cc353a90917da3eb29 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Sat, 20 Feb 2021 12:44:26 +0300 Subject: [PATCH 02/23] Configure: marked top-level make targets as phony. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported by Thibault Nélis. --- auto/init | 2 ++ auto/install | 2 ++ 2 files changed, 4 insertions(+) diff --git a/auto/init b/auto/init index 910f5294b..f816dfc4d 100644 --- a/auto/init +++ b/auto/init @@ -48,4 +48,6 @@ default: build clean: rm -rf Makefile $NGX_OBJS + +.PHONY: default clean END diff --git a/auto/install b/auto/install index d884487a1..c764fdd2f 100644 --- a/auto/install +++ b/auto/install @@ -215,4 +215,6 @@ upgrade: test -f $NGX_PID_PATH.oldbin kill -QUIT \`cat $NGX_PID_PATH.oldbin\` + +.PHONY: build install modules upgrade END From 60a8ed26f3120356b2d3e6639ffc932eb0cb8721 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 20 Feb 2021 18:02:49 +0300 Subject: [PATCH 03/23] SSL: X509_NAME_oneline() error handling. --- src/event/ngx_event_openssl.c | 42 ++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 93a6ae46e..b03c7ce86 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1019,21 +1019,43 @@ ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) depth = X509_STORE_CTX_get_error_depth(x509_store); sname = X509_get_subject_name(cert); - subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)"; + + if (sname) { + subject = X509_NAME_oneline(sname, NULL, 0); + if (subject == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, + "X509_NAME_oneline() failed"); + } + + } else { + subject = NULL; + } iname = X509_get_issuer_name(cert); - issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)"; + + if (iname) { + issuer = X509_NAME_oneline(iname, NULL, 0); + if (issuer == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, + "X509_NAME_oneline() failed"); + } + + } else { + issuer = NULL; + } ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, "verify:%d, error:%d, depth:%d, " "subject:\"%s\", issuer:\"%s\"", - ok, err, depth, subject, issuer); + ok, err, depth, + subject ? subject : "(none)", + issuer ? issuer : "(none)"); - if (sname) { + if (subject) { OPENSSL_free(subject); } - if (iname) { + if (issuer) { OPENSSL_free(issuer); } #endif @@ -4900,6 +4922,11 @@ ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, } p = X509_NAME_oneline(name, NULL, 0); + if (p == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_oneline() failed"); + X509_free(cert); + return NGX_ERROR; + } for (len = 0; p[len]; len++) { /* void */ } @@ -4943,6 +4970,11 @@ ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool, } p = X509_NAME_oneline(name, NULL, 0); + if (p == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_oneline() failed"); + X509_free(cert); + return NGX_ERROR; + } for (len = 0; p[len]; len++) { /* void */ } From 7ae100407c9b771e1067396baf1d013490b488f5 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 20 Feb 2021 18:02:54 +0300 Subject: [PATCH 04/23] SSL: added missed error reporting during variables evaluation. --- src/event/ngx_event_openssl.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index b03c7ce86..48b3192b1 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -83,7 +83,7 @@ static time_t ngx_ssl_parse_time( #if OPENSSL_VERSION_NUMBER > 0x10100000L const #endif - ASN1_TIME *asn1time); + ASN1_TIME *asn1time, ngx_log_t *log); static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -4817,11 +4817,13 @@ ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_print_ex() failed"); goto failed; } @@ -4869,11 +4871,13 @@ ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } if (X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253) < 0) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_NAME_print_ex() failed"); goto failed; } @@ -5011,6 +5015,7 @@ ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } @@ -5049,6 +5054,7 @@ ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } if (!X509_digest(cert, EVP_sha1(), buf, &len)) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "X509_digest() failed"); X509_free(cert); return NGX_ERROR; } @@ -5122,6 +5128,7 @@ ngx_ssl_get_client_v_start(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } @@ -5166,6 +5173,7 @@ ngx_ssl_get_client_v_end(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed"); X509_free(cert); return NGX_ERROR; } @@ -5208,9 +5216,9 @@ ngx_ssl_get_client_v_remain(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } #if OPENSSL_VERSION_NUMBER > 0x10100000L - end = ngx_ssl_parse_time(X509_get0_notAfter(cert)); + end = ngx_ssl_parse_time(X509_get0_notAfter(cert), c->log); #else - end = ngx_ssl_parse_time(X509_get_notAfter(cert)); + end = ngx_ssl_parse_time(X509_get_notAfter(cert), c->log); #endif if (end == (time_t) NGX_ERROR) { @@ -5245,7 +5253,7 @@ ngx_ssl_parse_time( #if OPENSSL_VERSION_NUMBER > 0x10100000L const #endif - ASN1_TIME *asn1time) + ASN1_TIME *asn1time, ngx_log_t *log) { BIO *bio; char *value; @@ -5261,6 +5269,7 @@ ngx_ssl_parse_time( bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "BIO_new() failed"); return NGX_ERROR; } From ef44627852ce831407d54c09d7a100e3ca41b9a6 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Sat, 20 Feb 2021 18:03:04 +0300 Subject: [PATCH 05/23] SSL: added check for debugging. If debugging is not enabled, there is no need to do extra work in ngx_ssl_verify_callback() and ngx_ssl_handshake_log(). --- src/event/ngx_event_openssl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 48b3192b1..d762d6b7f 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1014,6 +1014,10 @@ ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) c = ngx_ssl_get_connection(ssl_conn); + if (!(c->log->log_level & NGX_LOG_DEBUG_EVENT)) { + return 1; + } + cert = X509_STORE_CTX_get_current_cert(x509_store); err = X509_STORE_CTX_get_error(x509_store); depth = X509_STORE_CTX_get_error_depth(x509_store); @@ -1970,6 +1974,10 @@ ngx_ssl_handshake_log(ngx_connection_t *c) #endif SSL_CIPHER *cipher; + if (!(c->log->log_level & NGX_LOG_DEBUG_EVENT)) { + return; + } + cipher = SSL_get_current_cipher(c->ssl->connection); if (cipher) { From a74961f5529a79fed9cad66a04de98711705d6fd Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Thu, 25 Feb 2021 23:42:25 +0300 Subject: [PATCH 06/23] Contrib: vim syntax, default highlighting (ticket #2141). Using default highlighting makes it possible to easily overrule highlighting specified in the syntax file, see ":highlight-default" in vim help for details. --- contrib/vim/syntax/nginx.vim | 38 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 2d5ed060e..88ec847ac 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -2414,26 +2414,26 @@ syn keyword ngxDirectiveThirdParty contained ip2proxy_usage_type " highlight -hi link ngxComment Comment -hi link ngxParamComment Comment -hi link ngxListenComment Comment -hi link ngxVariable Identifier -hi link ngxVariableString PreProc -hi link ngxString String -hi link ngxListenString String +hi def link ngxComment Comment +hi def link ngxParamComment Comment +hi def link ngxListenComment Comment +hi def link ngxVariable Identifier +hi def link ngxVariableString PreProc +hi def link ngxString String +hi def link ngxListenString String -hi link ngxBoolean Boolean -hi link ngxDirectiveBlock Statement -hi link ngxDirectiveImportant Type -hi link ngxDirectiveListen Type -hi link ngxDirectiveControl Keyword -hi link ngxDirectiveError Constant -hi link ngxDirectiveDeprecated Error -hi link ngxDirective Identifier -hi link ngxDirectiveThirdParty Special -hi link ngxDirectiveThirdPartyDeprecated Error +hi def link ngxBoolean Boolean +hi def link ngxDirectiveBlock Statement +hi def link ngxDirectiveImportant Type +hi def link ngxDirectiveListen Type +hi def link ngxDirectiveControl Keyword +hi def link ngxDirectiveError Constant +hi def link ngxDirectiveDeprecated Error +hi def link ngxDirective Identifier +hi def link ngxDirectiveThirdParty Special +hi def link ngxDirectiveThirdPartyDeprecated Error -hi link ngxListenOptions Keyword -hi link ngxListenOptionsDeprecated Error +hi def link ngxListenOptions Keyword +hi def link ngxListenOptionsDeprecated Error let b:current_syntax = "nginx" From 0f5d0c5798eacb60407bcf0a76fc0b2c39e356bb Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 1 Mar 2021 17:31:28 +0300 Subject: [PATCH 07/23] HTTP/2: client_header_timeout before first request (ticket #2142). With this change, behaviour of HTTP/2 becomes even closer to HTTP/1.x, and client_header_timeout instead of keepalive_timeout is used before the first request is received. This fixes HTTP/2 connections being closed even before the first request if "keepalive_timeout 0;" was used in the configuration; the problem appeared in f790816a0e87 (1.19.7). --- src/http/v2/ngx_http_v2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index a59528494..005db0b8e 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -238,6 +238,7 @@ ngx_http_v2_init(ngx_event_t *rev) ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_main_conf_t *h2mcf; ngx_http_v2_connection_t *h2c; + ngx_http_core_srv_conf_t *cscf; c = rev->data; hc = c->data; @@ -325,8 +326,10 @@ ngx_http_v2_init(ngx_event_t *rev) rev->handler = ngx_http_v2_read_handler; c->write->handler = ngx_http_v2_write_handler; - if (c->read->timer_set) { - ngx_del_timer(c->read); + if (!rev->timer_set) { + cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, + ngx_http_core_module); + ngx_add_timer(rev, cscf->client_header_timeout); } c->idle = 1; From 71eb19da43e3382ce97a14b6d3cd564881da37e7 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 1 Mar 2021 20:00:43 +0300 Subject: [PATCH 08/23] Improved maximum errno detection. Previously, systems without sys_nerr (or _sys_nerr) were handled with an assumption that errors start at 0 and continuous. This is, however, not something POSIX requires, and not true on some platforms. Notably, on Linux, where sys_nerr is no longer available for newly linked binaries starting with glibc 2.32, there are gaps in error list, which used to stop us from properly detecting maximum errno. Further, on GNU/Hurd errors start at 0x40000001. With this change, maximum errno detection is moved to the runtime code, now able to ignore gaps, and also detects the first error if needed. This fixes observed "Unknown error" messages as seen on Linux with glibc 2.32 and on GNU/Hurd. --- auto/unix | 28 ------------- src/os/unix/ngx_errno.c | 91 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 34 deletions(-) diff --git a/auto/unix b/auto/unix index ff9697a4e..845e41fc6 100644 --- a/auto/unix +++ b/auto/unix @@ -753,34 +753,6 @@ if [ $ngx_found = no ]; then fi -if [ $ngx_found = no ]; then - - # Solaris has no sys_nerr - ngx_feature='maximum errno' - ngx_feature_name=NGX_SYS_NERR - ngx_feature_run=value - ngx_feature_incs='#include - #include - #include ' - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test='int n; - char *p; - for (n = 1; n < 1000; n++) { - errno = 0; - p = strerror(n); - if (errno == EINVAL - || p == NULL - || strncmp(p, "Unknown error", 13) == 0) - { - break; - } - } - printf("%d", n);' - . auto/feature -fi - - ngx_feature="localtime_r()" ngx_feature_name="NGX_HAVE_LOCALTIME_R" ngx_feature_run=no diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c index e787b2377..b3303bf6f 100644 --- a/src/os/unix/ngx_errno.c +++ b/src/os/unix/ngx_errno.c @@ -27,6 +27,8 @@ static ngx_str_t *ngx_sys_errlist; static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); +static ngx_err_t ngx_first_error; +static ngx_err_t ngx_last_error; u_char * @@ -34,8 +36,13 @@ ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) { ngx_str_t *msg; - msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]: - &ngx_unknown_error; + if (err >= ngx_first_error && err < ngx_last_error) { + msg = &ngx_sys_errlist[err - ngx_first_error]; + + } else { + msg = &ngx_unknown_error; + } + size = ngx_min(size, msg->len); return ngx_cpymem(errstr, msg->data, size); @@ -50,20 +57,92 @@ ngx_strerror_init(void) size_t len; ngx_err_t err; +#if (NGX_SYS_NERR) + ngx_first_error = 0; + ngx_last_error = NGX_SYS_NERR; + +#elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000) + + /* + * If number of errors is not known, and EPERM error code has large + * but reasonable value, guess possible error codes based on the error + * messages returned by strerror(), starting from EPERM. Notably, + * this covers GNU/Hurd, where errors start at 0x40000001. + */ + + for (err = EPERM; err > EPERM - 1000; err--) { + ngx_set_errno(0); + msg = strerror(err); + + if (errno == EINVAL + || msg == NULL + || strncmp(msg, "Unknown error", 13) == 0) + { + continue; + } + + ngx_first_error = err; + } + + for (err = EPERM; err < EPERM + 1000; err++) { + ngx_set_errno(0); + msg = strerror(err); + + if (errno == EINVAL + || msg == NULL + || strncmp(msg, "Unknown error", 13) == 0) + { + continue; + } + + ngx_last_error = err + 1; + } + +#else + + /* + * If number of errors is not known, guess it based on the error + * messages returned by strerror(). + */ + + ngx_first_error = 0; + + for (err = 0; err < 1000; err++) { + ngx_set_errno(0); + msg = strerror(err); + + if (errno == EINVAL + || msg == NULL + || strncmp(msg, "Unknown error", 13) == 0) + { + continue; + } + + ngx_last_error = err + 1; + } + +#endif + /* * ngx_strerror() is not ready to work at this stage, therefore, * malloc() is used and possible errors are logged using strerror(). */ - len = NGX_SYS_NERR * sizeof(ngx_str_t); + len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t); ngx_sys_errlist = malloc(len); if (ngx_sys_errlist == NULL) { goto failed; } - for (err = 0; err < NGX_SYS_NERR; err++) { + for (err = ngx_first_error; err < ngx_last_error; err++) { msg = strerror(err); + + if (msg == NULL) { + ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error; + continue; + } + len = ngx_strlen(msg); p = malloc(len); @@ -72,8 +151,8 @@ ngx_strerror_init(void) } ngx_memcpy(p, msg, len); - ngx_sys_errlist[err].len = len; - ngx_sys_errlist[err].data = p; + ngx_sys_errlist[err - ngx_first_error].len = len; + ngx_sys_errlist[err - ngx_first_error].data = p; } return NGX_OK; From 4c5a49ce4c756cee85b27f9fe501f52adc7b9f1f Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Mon, 1 Mar 2021 20:00:45 +0300 Subject: [PATCH 09/23] Introduced strerrordesc_np() support. The strerrordesc_np() function, introduced in glibc 2.32, provides an async-signal-safe way to obtain error messages. This makes it possible to avoid copying error messages. --- auto/unix | 28 +++++++++++++++++++------ src/os/unix/ngx_errno.c | 46 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/auto/unix b/auto/unix index 845e41fc6..9c402e787 100644 --- a/auto/unix +++ b/auto/unix @@ -727,17 +727,33 @@ ngx_feature_test="char buf[1]; struct iovec vec[1]; ssize_t n; . auto/feature -ngx_feature="sys_nerr" -ngx_feature_name="NGX_SYS_NERR" -ngx_feature_run=value -ngx_feature_incs='#include - #include ' +# strerrordesc_np(), introduced in glibc 2.32 + +ngx_feature="strerrordesc_np()" +ngx_feature_name="NGX_HAVE_STRERRORDESC_NP" +ngx_feature_run=no +ngx_feature_incs='#include ' ngx_feature_path= ngx_feature_libs= -ngx_feature_test='printf("%d", sys_nerr);' +ngx_feature_test="char *p; p = strerrordesc_np(0); + if (p == NULL) return 1" . auto/feature +if [ $ngx_found = no ]; then + + ngx_feature="sys_nerr" + ngx_feature_name="NGX_SYS_NERR" + ngx_feature_run=value + ngx_feature_incs='#include + #include ' + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test='printf("%d", sys_nerr);' + . auto/feature +fi + + if [ $ngx_found = no ]; then # Cygiwn defines _sys_nerr diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c index b3303bf6f..ca23b2d3f 100644 --- a/src/os/unix/ngx_errno.c +++ b/src/os/unix/ngx_errno.c @@ -9,6 +9,49 @@ #include +static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); + + +#if (NGX_HAVE_STRERRORDESC_NP) + +/* + * The strerrordesc_np() function, introduced in glibc 2.32, is + * async-signal-safe. This makes it possible to use it directly, + * without copying error messages. + */ + + +u_char * +ngx_strerror(ngx_err_t err, u_char *errstr, size_t size) +{ + size_t len; + const char *msg; + + msg = strerrordesc_np(err); + + if (msg == NULL) { + msg = (char *) ngx_unknown_error.data; + len = ngx_unknown_error.len; + + } else { + len = ngx_strlen(msg); + } + + size = ngx_min(size, len); + + return ngx_cpymem(errstr, msg, size); +} + + +ngx_int_t +ngx_strerror_init(void) +{ + return NGX_OK; +} + + +#else + /* * The strerror() messages are copied because: * @@ -26,7 +69,6 @@ static ngx_str_t *ngx_sys_errlist; -static ngx_str_t ngx_unknown_error = ngx_string("Unknown error"); static ngx_err_t ngx_first_error; static ngx_err_t ngx_last_error; @@ -164,3 +206,5 @@ failed: return NGX_ERROR; } + +#endif From a38a8438b8116d4f3674ea8a0cb194a8fb3f5622 Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Tue, 2 Mar 2021 00:58:24 +0300 Subject: [PATCH 10/23] Proxy: variables support in "proxy_cookie_flags" flags. --- src/http/modules/ngx_http_proxy_module.c | 91 +++++++++++++++++------- 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 77a1e0d7f..27266676d 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -56,7 +56,7 @@ typedef struct { #endif } cookie; - ngx_uint_t flags; + ngx_array_t flags_values; ngx_uint_t regex; } ngx_http_proxy_cookie_flags_t; @@ -2916,12 +2916,14 @@ static ngx_int_t ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, ngx_array_t *flags) { - ngx_str_t pattern; + ngx_str_t pattern, value; #if (NGX_PCRE) ngx_int_t rc; #endif - ngx_uint_t i; + ngx_uint_t i, m, f, nelts; ngx_keyval_t *attr; + ngx_conf_bitmask_t *mask; + ngx_http_complex_value_t *flags_values; ngx_http_proxy_cookie_flags_t *pcf; attr = attrs->elts; @@ -2965,7 +2967,47 @@ ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, return NGX_DECLINED; } - return ngx_http_proxy_edit_cookie_flags(r, attrs, pcf[i].flags); + nelts = pcf[i].flags_values.nelts; + flags_values = pcf[i].flags_values.elts; + + mask = ngx_http_proxy_cookie_flags_masks; + f = 0; + + for (i = 0; i < nelts; i++) { + + if (ngx_http_complex_value(r, &flags_values[i], &value) != NGX_OK) { + return NGX_ERROR; + } + + if (value.len == 0) { + continue; + } + + for (m = 0; mask[m].name.len != 0; m++) { + + if (mask[m].name.len != value.len + || ngx_strncasecmp(mask[m].name.data, value.data, value.len) + != 0) + { + continue; + } + + f |= mask[m].mask; + + break; + } + + if (mask[m].name.len == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "invalid proxy_cookie_flags flag \"%V\"", &value); + } + } + + if (f == 0) { + return NGX_DECLINED; + } + + return ngx_http_proxy_edit_cookie_flags(r, attrs, f); } @@ -4514,8 +4556,8 @@ ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_proxy_loc_conf_t *plcf = conf; ngx_str_t *value; - ngx_uint_t i, m; - ngx_conf_bitmask_t *mask; + ngx_uint_t i; + ngx_http_complex_value_t *cv; ngx_http_proxy_cookie_flags_t *pcf; ngx_http_compile_complex_value_t ccv; #if (NGX_PCRE) @@ -4599,32 +4641,27 @@ ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - mask = ngx_http_proxy_cookie_flags_masks; - pcf->flags = 0; + if (ngx_array_init(&pcf->flags_values, cf->pool, cf->args->nelts - 2, + sizeof(ngx_http_complex_value_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } for (i = 2; i < cf->args->nelts; i++) { - for (m = 0; mask[m].name.len != 0; m++) { - if (mask[m].name.len != value[i].len - || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0) - { - continue; - } - - if (pcf->flags & mask[m].mask) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate parameter \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - pcf->flags |= mask[m].mask; - - break; + cv = ngx_array_push(&pcf->flags_values); + if (cv == NULL) { + return NGX_CONF_ERROR; } - if (mask[m].name.len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[i]); + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[i]; + ccv.complex_value = cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } } From 797ac536fe2cc0a311a72ddb861784f320991beb Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:13 +0300 Subject: [PATCH 11/23] SSL: fixed build by Sun C with old OpenSSL versions. Sun C complains about "statement not reached" if a "return" is followed by additional statements. --- src/http/modules/ngx_http_grpc_module.c | 4 ++-- src/http/modules/ngx_http_proxy_module.c | 4 ++-- src/http/modules/ngx_http_ssl_module.c | 4 ++-- src/http/modules/ngx_http_uwsgi_module.c | 4 ++-- src/mail/ngx_mail_ssl_module.c | 4 ++-- src/stream/ngx_stream_proxy_module.c | 4 ++-- src/stream/ngx_stream_ssl_module.c | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index aa7576561..f5bf575c2 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -4841,9 +4841,9 @@ ngx_http_grpc_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { #ifndef SSL_CONF_FLAG_FILE return "is not supported on this platform"; -#endif - +#else return NGX_CONF_OK; +#endif } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 27266676d..a63c3ed54 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -4913,9 +4913,9 @@ ngx_http_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { #ifndef SSL_CONF_FLAG_FILE return "is not supported on this platform"; -#endif - +#else return NGX_CONF_OK; +#endif } diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index e062b03a1..a47d6963a 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -1274,9 +1274,9 @@ ngx_http_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { #ifndef SSL_CONF_FLAG_FILE return "is not supported on this platform"; -#endif - +#else return NGX_CONF_OK; +#endif } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index bf2732675..1334f44c9 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -2398,9 +2398,9 @@ ngx_http_uwsgi_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { #ifndef SSL_CONF_FLAG_FILE return "is not supported on this platform"; -#endif - +#else return NGX_CONF_OK; +#endif } diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index d560bd60c..7eae83e25 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -682,7 +682,7 @@ ngx_mail_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { #ifndef SSL_CONF_FLAG_FILE return "is not supported on this platform"; -#endif - +#else return NGX_CONF_OK; +#endif } diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 0c86083c5..01cda7a36 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -1026,9 +1026,9 @@ ngx_stream_proxy_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { #ifndef SSL_CONF_FLAG_FILE return "is not supported on this platform"; -#endif - +#else return NGX_CONF_OK; +#endif } diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index ccd359f3b..d8c0471ea 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -1061,9 +1061,9 @@ ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { #ifndef SSL_CONF_FLAG_FILE return "is not supported on this platform"; -#endif - +#else return NGX_CONF_OK; +#endif } From d5a31fdad50dbd28974cb0eb7f23948241a7559e Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:15 +0300 Subject: [PATCH 12/23] Events: fixed eventport handling in ngx_handle_read_event(). The "!rev->ready" test seems to be a typo, introduced in the original commit (719:f30b1a75fd3b). The ngx_handle_write_event() code properly tests for "rev->ready" instead. Due to this typo, read events might be unexpectedly removed during proxying after an event on the other part of the proxied connection. Catched by mail proxying tests. --- src/event/ngx_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 402a7f5e2..ed7b30bf3 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -318,7 +318,7 @@ ngx_handle_read_event(ngx_event_t *rev, ngx_uint_t flags) return NGX_OK; } - if (rev->oneshot && !rev->ready) { + if (rev->oneshot && rev->ready) { if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } From 8ed63c936c1493a25bdcb351a812de1ebac8b976 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:16 +0300 Subject: [PATCH 13/23] Mail: added missing event handling after blocking events. As long as a read event is blocked (ignored), ngx_handle_read_event() needs to be called to make sure no further notifications will be triggered when using level-triggered event methods, such as select() or poll(). --- src/mail/ngx_mail_imap_handler.c | 6 ++++++ src/mail/ngx_mail_pop3_handler.c | 6 ++++++ src/mail/ngx_mail_smtp_handler.c | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index 3bf09ec3c..e31e4d0c8 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -123,6 +123,12 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) if (s->out.len) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy"); s->blocked = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + return; } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index 9310c2750..019927d3d 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -138,6 +138,12 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) if (s->out.len) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "pop3 send handler busy"); s->blocked = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + return; } diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c index f1017e0d8..dcf658eef 100644 --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -449,6 +449,12 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) if (s->out.len) { ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy"); s->blocked = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + return; } From 065a1641b242538073e92065e20fd788203108ab Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:17 +0300 Subject: [PATCH 14/23] Mail: added missing event handling after reading data. If we need to be notified about further events, ngx_handle_read_event() needs to be called after a read event is processed. Without this, an event can be removed from the kernel and won't be reported again, notably when using oneshot event methods, such as eventport on Solaris. For consistency, existing ngx_handle_read_event() call removed from ngx_mail_read_command(), as this call only covers one of the code paths where ngx_mail_read_command() returns NGX_AGAIN. Instead, appropriate processing added to the callers, covering all code paths where NGX_AGAIN is returned. --- src/mail/ngx_mail_handler.c | 5 ----- src/mail/ngx_mail_imap_handler.c | 16 +++++++++++++++- src/mail/ngx_mail_pop3_handler.c | 16 +++++++++++++++- src/mail/ngx_mail_proxy_module.c | 30 ++++++++++++++++++++++++++++++ src/mail/ngx_mail_smtp_handler.c | 16 +++++++++++++++- 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 803a247d2..63ae4b003 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -722,11 +722,6 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) } if (n == NGX_AGAIN) { - if (ngx_handle_read_event(c->read, 0) != NGX_OK) { - ngx_mail_session_internal_server_error(s); - return NGX_ERROR; - } - if (s->buffer->pos == s->buffer->last) { return NGX_AGAIN; } diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index e31e4d0c8..5dfdd7601 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -136,7 +136,16 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) rc = ngx_mail_read_command(s, c); - if (rc == NGX_AGAIN || rc == NGX_ERROR) { + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + + return; + } + + if (rc == NGX_ERROR) { return; } @@ -299,6 +308,11 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) } } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_send(c->write); } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index 019927d3d..edfd98681 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -151,7 +151,16 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) rc = ngx_mail_read_command(s, c); - if (rc == NGX_AGAIN || rc == NGX_ERROR) { + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + + return; + } + + if (rc == NGX_ERROR) { return; } @@ -281,6 +290,11 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) s->arg_start = s->buffer->start; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_send(c->write); } } diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 610f54780..299cb2ad2 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -233,6 +233,11 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) rc = ngx_mail_proxy_read_response(s, 0); if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + return; } @@ -314,6 +319,11 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) return; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; } @@ -346,6 +356,11 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + return; } @@ -448,6 +463,11 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) return; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; } @@ -482,6 +502,11 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + return; } @@ -763,6 +788,11 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) return; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + s->proxy->buffer->pos = s->proxy->buffer->start; s->proxy->buffer->last = s->proxy->buffer->start; } diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c index dcf658eef..e68ceedfd 100644 --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -462,7 +462,16 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) rc = ngx_mail_read_command(s, c); - if (rc == NGX_AGAIN || rc == NGX_ERROR) { + if (rc == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + + return; + } + + if (rc == NGX_ERROR) { return; } @@ -574,6 +583,11 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev) s->arg_start = s->buffer->pos; } + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_session_internal_server_error(s); + return; + } + ngx_mail_send(c->write); } } From 7d4cd6cff428cb8717f8560a00f825d72b49f68a Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:19 +0300 Subject: [PATCH 15/23] Mail: postponed session initialization under accept mutex. Similarly to 40e8ce405859 in the stream module, this reduces the time accept mutex is held. This also simplifies following changes to introduce PROXY protocol support. --- src/mail/ngx_mail.h | 1 + src/mail/ngx_mail_handler.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index 25ac432b0..e5ecf3914 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -197,6 +197,7 @@ typedef struct { ngx_uint_t mail_state; + unsigned ssl:1; unsigned protocol:3; unsigned blocked:1; unsigned quit:1; diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 63ae4b003..f72eeaca6 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -11,6 +11,7 @@ #include +static void ngx_mail_init_session_handler(ngx_event_t *rev); static void ngx_mail_init_session(ngx_connection_t *c); #if (NGX_MAIL_SSL) @@ -26,6 +27,7 @@ ngx_mail_init_connection(ngx_connection_t *c) { size_t len; ngx_uint_t i; + ngx_event_t *rev; ngx_mail_port_t *port; struct sockaddr *sa; struct sockaddr_in *sin; @@ -129,6 +131,10 @@ ngx_mail_init_connection(ngx_connection_t *c) s->main_conf = addr_conf->ctx->main_conf; s->srv_conf = addr_conf->ctx->srv_conf; +#if (NGX_MAIL_SSL) + s->ssl = addr_conf->ssl; +#endif + s->addr_text = &addr_conf->addr_text; c->data = s; @@ -159,13 +165,34 @@ ngx_mail_init_connection(ngx_connection_t *c) c->log_error = NGX_ERROR_INFO; + rev = c->read; + rev->handler = ngx_mail_init_session_handler; + + if (ngx_use_accept_mutex) { + ngx_post_event(rev, &ngx_posted_events); + return; + } + + rev->handler(rev); +} + + +static void +ngx_mail_init_session_handler(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_mail_session_t *s; + + c = rev->data; + s = c->data; + #if (NGX_MAIL_SSL) { ngx_mail_ssl_conf_t *sslcf; sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); - if (sslcf->enable || addr_conf->ssl) { + if (sslcf->enable || s->ssl) { c->log->action = "SSL handshaking"; ngx_mail_ssl_init_connection(&sslcf->ssl, c); From 83de0868b1bb5275e51698545e2165782bb5421d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:20 +0300 Subject: [PATCH 16/23] Mail: fixed log action after SSL handshake. --- src/mail/ngx_mail_handler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index f72eeaca6..cf87a1774 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -365,6 +365,8 @@ ngx_mail_init_session(ngx_connection_t *c) s = c->data; + c->log->action = "sending client greeting line"; + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); s->protocol = cscf->protocol->type; From 72dcd5141b32fccdcd241cc031972f51874ceb41 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:23 +0300 Subject: [PATCH 17/23] Mail: made auth http creating request easier to extend. --- src/mail/ngx_mail_auth_http_module.c | 42 +++++++++++++++++++--------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 6b57358b4..810fc3e19 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1224,22 +1224,38 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len + sizeof(CRLF) - 1 + sizeof("Client-Host: ") - 1 + s->host.len + sizeof(CRLF) - 1 - + sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1 - + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + sizeof(CRLF) - 1 - + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + sizeof(CRLF) - 1 -#if (NGX_MAIL_SSL) - + sizeof("Auth-SSL: on" CRLF) - 1 - + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len - + sizeof(CRLF) - 1 - + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + sizeof(CRLF) - 1 -#endif + ahcf->header.len + sizeof(CRLF) - 1; + if (s->auth_method == NGX_MAIL_AUTH_NONE) { + len += sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SMTP-From: ") - 1 + s->smtp_from.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SMTP-To: ") - 1 + s->smtp_to.len + + sizeof(CRLF) - 1; + } + +#if (NGX_MAIL_SSL) + + if (c->ssl) { + len += sizeof("Auth-SSL: on" CRLF) - 1 + + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Subject: ") - 1 + subject.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Issuer: ") - 1 + issuer.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Serial: ") - 1 + serial.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Fingerprint: ") - 1 + fingerprint.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Cert: ") - 1 + cert.len + + sizeof(CRLF) - 1; + } + +#endif + b = ngx_create_temp_buf(pool, len); if (b == NULL) { return NULL; From 1fce224f01b5a9b503315bd24e99421e5ca5bd7c Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:24 +0300 Subject: [PATCH 18/23] Mail: parsing of the PROXY protocol from clients. Activated with the "proxy_protocol" parameter of the "listen" directive. Obtained information is passed to the auth_http script in Proxy-Protocol-Addr, Proxy-Protocol-Port, Proxy-Protocol-Server-Addr, and Proxy-Protocol-Server-Port headers. --- src/mail/ngx_mail.c | 2 + src/mail/ngx_mail.h | 4 +- src/mail/ngx_mail_auth_http_module.c | 31 +++++++++ src/mail/ngx_mail_core_module.c | 5 ++ src/mail/ngx_mail_handler.c | 94 +++++++++++++++++++++++++++- 5 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c index f17c2ccc3..890d8153a 100644 --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -405,6 +405,7 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport, #if (NGX_MAIL_SSL) addrs[i].conf.ssl = addr[i].opt.ssl; #endif + addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs[i].conf.addr_text = addr[i].opt.addr_text; } @@ -439,6 +440,7 @@ ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport, #if (NGX_MAIL_SSL) addrs6[i].conf.ssl = addr[i].opt.ssl; #endif + addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; addrs6[i].conf.addr_text = addr[i].opt.addr_text; } diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index e5ecf3914..a46522068 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -41,6 +41,7 @@ typedef struct { unsigned ipv6only:1; #endif unsigned so_keepalive:2; + unsigned proxy_protocol:1; #if (NGX_HAVE_KEEPALIVE_TUNABLE) int tcp_keepidle; int tcp_keepintvl; @@ -55,7 +56,8 @@ typedef struct { typedef struct { ngx_mail_conf_ctx_t *ctx; ngx_str_t addr_text; - ngx_uint_t ssl; /* unsigned ssl:1; */ + unsigned ssl:1; + unsigned proxy_protocol:1; } ngx_mail_addr_conf_t; typedef struct { diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 810fc3e19..06ded470a 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1227,6 +1227,17 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, + ahcf->header.len + sizeof(CRLF) - 1; + if (c->proxy_protocol) { + len += sizeof("Proxy-Protocol-Addr: ") - 1 + + c->proxy_protocol->src_addr.len + sizeof(CRLF) - 1 + + sizeof("Proxy-Protocol-Port: ") - 1 + + sizeof("65535") - 1 + sizeof(CRLF) - 1 + + sizeof("Proxy-Protocol-Server-Addr: ") - 1 + + c->proxy_protocol->dst_addr.len + sizeof(CRLF) - 1 + + sizeof("Proxy-Protocol-Server-Port: ") - 1 + + sizeof("65535") - 1 + sizeof(CRLF) - 1; + } + if (s->auth_method == NGX_MAIL_AUTH_NONE) { len += sizeof("Auth-SMTP-Helo: ") - 1 + s->smtp_helo.len + sizeof(CRLF) - 1 @@ -1314,6 +1325,26 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, *b->last++ = CR; *b->last++ = LF; } + if (c->proxy_protocol) { + b->last = ngx_cpymem(b->last, "Proxy-Protocol-Addr: ", + sizeof("Proxy-Protocol-Addr: ") - 1); + b->last = ngx_copy(b->last, c->proxy_protocol->src_addr.data, + c->proxy_protocol->src_addr.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_sprintf(b->last, "Proxy-Protocol-Port: %d" CRLF, + c->proxy_protocol->src_port); + + b->last = ngx_cpymem(b->last, "Proxy-Protocol-Server-Addr: ", + sizeof("Proxy-Protocol-Server-Addr: ") - 1); + b->last = ngx_copy(b->last, c->proxy_protocol->dst_addr.data, + c->proxy_protocol->dst_addr.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_sprintf(b->last, "Proxy-Protocol-Server-Port: %d" CRLF, + c->proxy_protocol->dst_port); + } + if (s->auth_method == NGX_MAIL_AUTH_NONE) { /* HELO, MAIL FROM, and RCPT TO can't contain CRLF, no need to escape */ diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index e16d70238..408312423 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -548,6 +548,11 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } + if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { + ls->proxy_protocol = 1; + continue; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[i]); return NGX_CONF_ERROR; diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index cf87a1774..50a44c782 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -11,6 +11,7 @@ #include +static void ngx_mail_proxy_protocol_handler(ngx_event_t *rev); static void ngx_mail_init_session_handler(ngx_event_t *rev); static void ngx_mail_init_session(ngx_connection_t *c); @@ -168,6 +169,22 @@ ngx_mail_init_connection(ngx_connection_t *c) rev = c->read; rev->handler = ngx_mail_init_session_handler; + if (addr_conf->proxy_protocol) { + c->log->action = "reading PROXY protocol"; + + rev->handler = ngx_mail_proxy_protocol_handler; + + if (!rev->ready) { + ngx_add_timer(rev, cscf->timeout); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_mail_close_connection(c); + } + + return; + } + } + if (ngx_use_accept_mutex) { ngx_post_event(rev, &ngx_posted_events); return; @@ -177,6 +194,76 @@ ngx_mail_init_connection(ngx_connection_t *c) } +static void +ngx_mail_proxy_protocol_handler(ngx_event_t *rev) +{ + u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + size_t size; + ssize_t n; + ngx_err_t err; + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; + + c = rev->data; + s = c->data; + + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, + "mail PROXY protocol handler"); + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + c->timedout = 1; + ngx_mail_close_connection(c); + return; + } + + n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK); + + err = ngx_socket_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "recv(): %z", n); + + if (n == -1) { + if (err == NGX_EAGAIN) { + rev->ready = 0; + + if (!rev->timer_set) { + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + ngx_add_timer(rev, cscf->timeout); + } + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_mail_close_connection(c); + } + + return; + } + + ngx_connection_error(c, err, "recv() failed"); + + ngx_mail_close_connection(c); + return; + } + + p = ngx_proxy_protocol_read(c, buf, buf + n); + + if (p == NULL) { + ngx_mail_close_connection(c); + return; + } + + size = p - buf; + + if (c->recv(c, buf, size) != (ssize_t) size) { + ngx_mail_close_connection(c); + return; + } + + ngx_mail_init_session_handler(rev); +} + + static void ngx_mail_init_session_handler(ngx_event_t *rev) { @@ -242,9 +329,10 @@ ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) s = c->data; - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - - ngx_add_timer(c->read, cscf->timeout); + if (!c->read->timer_set) { + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + ngx_add_timer(c->read, cscf->timeout); + } c->ssl->handler = ngx_mail_ssl_handshake_handler; From c2e22bcf325ee0031d1c86fbdfb79a2f8e1b4a7b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:29 +0300 Subject: [PATCH 19/23] Mail: realip module. When configured with the "set_real_ip_from", it can set client's IP address as visible in logs to the one obtained via the PROXY protocol. --- auto/modules | 6 + src/mail/ngx_mail.h | 1 + src/mail/ngx_mail_handler.c | 5 + src/mail/ngx_mail_realip_module.c | 269 ++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+) create mode 100644 src/mail/ngx_mail_realip_module.c diff --git a/auto/modules b/auto/modules index f1c63f3d5..f5a459783 100644 --- a/auto/modules +++ b/auto/modules @@ -985,6 +985,12 @@ if [ $MAIL != NO ]; then ngx_module_srcs=src/mail/ngx_mail_proxy_module.c . auto/module + + ngx_module_name=ngx_mail_realip_module + ngx_module_deps= + ngx_module_srcs=src/mail/ngx_mail_realip_module.c + + . auto/module fi diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index a46522068..030e128c9 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -408,6 +408,7 @@ char *ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); /* 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_realip_handler(ngx_mail_session_t *s); /**/ diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 50a44c782..b9010535b 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -260,6 +260,11 @@ ngx_mail_proxy_protocol_handler(ngx_event_t *rev) return; } + if (ngx_mail_realip_handler(s) != NGX_OK) { + ngx_mail_close_connection(c); + return; + } + ngx_mail_init_session_handler(rev); } diff --git a/src/mail/ngx_mail_realip_module.c b/src/mail/ngx_mail_realip_module.c new file mode 100644 index 000000000..c93d7d33c --- /dev/null +++ b/src/mail/ngx_mail_realip_module.c @@ -0,0 +1,269 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *from; /* array of ngx_cidr_t */ +} ngx_mail_realip_srv_conf_t; + + +static ngx_int_t ngx_mail_realip_set_addr(ngx_mail_session_t *s, + ngx_addr_t *addr); +static char *ngx_mail_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_mail_realip_create_srv_conf(ngx_conf_t *cf); +static char *ngx_mail_realip_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); + + +static ngx_command_t ngx_mail_realip_commands[] = { + + { ngx_string("set_real_ip_from"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_mail_realip_from, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_mail_module_t ngx_mail_realip_module_ctx = { + NULL, /* protocol */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_mail_realip_create_srv_conf, /* create server configuration */ + ngx_mail_realip_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_mail_realip_module = { + NGX_MODULE_V1, + &ngx_mail_realip_module_ctx, /* module context */ + ngx_mail_realip_commands, /* module directives */ + NGX_MAIL_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +ngx_int_t +ngx_mail_realip_handler(ngx_mail_session_t *s) +{ + ngx_addr_t addr; + ngx_connection_t *c; + ngx_mail_realip_srv_conf_t *rscf; + + rscf = ngx_mail_get_module_srv_conf(s, ngx_mail_realip_module); + + if (rscf->from == NULL) { + return NGX_OK; + } + + c = s->connection; + + if (c->proxy_protocol == NULL) { + return NGX_OK; + } + + if (ngx_cidr_match(c->sockaddr, rscf->from) != NGX_OK) { + return NGX_OK; + } + + if (ngx_parse_addr(c->pool, &addr, c->proxy_protocol->src_addr.data, + c->proxy_protocol->src_addr.len) + != NGX_OK) + { + return NGX_OK; + } + + ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port); + + return ngx_mail_realip_set_addr(s, &addr); +} + + +static ngx_int_t +ngx_mail_realip_set_addr(ngx_mail_session_t *s, ngx_addr_t *addr) +{ + size_t len; + u_char *p; + u_char text[NGX_SOCKADDR_STRLEN]; + ngx_connection_t *c; + + c = s->connection; + + len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text, + NGX_SOCKADDR_STRLEN, 0); + if (len == 0) { + return NGX_ERROR; + } + + p = ngx_pnalloc(c->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, text, len); + + c->sockaddr = addr->sockaddr; + c->socklen = addr->socklen; + c->addr_text.len = len; + c->addr_text.data = p; + + return NGX_OK; +} + + +static char * +ngx_mail_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_realip_srv_conf_t *rscf = conf; + + ngx_int_t rc; + ngx_str_t *value; + ngx_url_t u; + ngx_cidr_t c, *cidr; + ngx_uint_t i; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + value = cf->args->elts; + + if (rscf->from == NULL) { + rscf->from = ngx_array_create(cf->pool, 2, + sizeof(ngx_cidr_t)); + if (rscf->from == NULL) { + return NGX_CONF_ERROR; + } + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ngx_strcmp(value[1].data, "unix:") == 0) { + cidr = ngx_array_push(rscf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + cidr->family = AF_UNIX; + return NGX_CONF_OK; + } + +#endif + + rc = ngx_ptocidr(&value[1], &c); + + if (rc != NGX_ERROR) { + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", + &value[1]); + } + + cidr = ngx_array_push(rscf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + *cidr = c; + + return NGX_CONF_OK; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + u.host = value[1]; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in set_real_ip_from \"%V\"", + u.err, &u.host); + } + + return NGX_CONF_ERROR; + } + + cidr = ngx_array_push_n(rscf->from, u.naddrs); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(cidr, u.naddrs * sizeof(ngx_cidr_t)); + + for (i = 0; i < u.naddrs; i++) { + cidr[i].family = u.addrs[i].sockaddr->sa_family; + + switch (cidr[i].family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) u.addrs[i].sockaddr; + cidr[i].u.in6.addr = sin6->sin6_addr; + ngx_memset(cidr[i].u.in6.mask.s6_addr, 0xff, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) u.addrs[i].sockaddr; + cidr[i].u.in.addr = sin->sin_addr.s_addr; + cidr[i].u.in.mask = 0xffffffff; + break; + } + } + + return NGX_CONF_OK; +} + + +static void * +ngx_mail_realip_create_srv_conf(ngx_conf_t *cf) +{ + ngx_mail_realip_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_realip_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->from = NULL; + */ + + return conf; +} + + +static char * +ngx_mail_realip_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_mail_realip_srv_conf_t *prev = parent; + ngx_mail_realip_srv_conf_t *conf = child; + + if (conf->from == NULL) { + conf->from = prev->from; + } + + return NGX_CONF_OK; +} From 6538d93067c07d446826f3d9b9cb9a3a01df0d0b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:32 +0300 Subject: [PATCH 20/23] Mail: sending of the PROXY protocol to backends. Activated with the "proxy_protocol" directive. Can be combined with "listen ... proxy_protocol;" and "set_real_ip_from ...;" to pass client address provided to nginx in the PROXY protocol header. --- src/mail/ngx_mail.h | 1 + src/mail/ngx_mail_proxy_module.c | 141 +++++++++++++++++++++++++++++-- 2 files changed, 134 insertions(+), 8 deletions(-) diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index 030e128c9..b865a3b9e 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -178,6 +178,7 @@ typedef enum { typedef struct { ngx_peer_connection_t upstream; ngx_buf_t *buffer; + ngx_uint_t proxy_protocol; /* unsigned proxy_protocol:1; */ } ngx_mail_proxy_ctx_t; diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 299cb2ad2..66aa0ba09 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -17,6 +17,7 @@ typedef struct { ngx_flag_t pass_error_message; ngx_flag_t xclient; ngx_flag_t smtp_auth; + ngx_flag_t proxy_protocol; size_t buffer_size; ngx_msec_t timeout; } ngx_mail_proxy_conf_t; @@ -26,7 +27,8 @@ static void ngx_mail_proxy_block_read(ngx_event_t *rev); static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev); static void ngx_mail_proxy_imap_handler(ngx_event_t *rev); static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev); -static void ngx_mail_proxy_dummy_handler(ngx_event_t *ev); +static void ngx_mail_proxy_write_handler(ngx_event_t *wev); +static ngx_int_t ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s); static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s, ngx_uint_t state); static void ngx_mail_proxy_handler(ngx_event_t *ev); @@ -82,6 +84,13 @@ static ngx_command_t ngx_mail_proxy_commands[] = { offsetof(ngx_mail_proxy_conf_t, smtp_auth), NULL }, + { ngx_string("proxy_protocol"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_proxy_conf_t, proxy_protocol), + NULL }, + ngx_null_command }; @@ -156,7 +165,7 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) p->upstream.connection->pool = s->connection->pool; s->connection->read->handler = ngx_mail_proxy_block_read; - p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler; + p->upstream.connection->write->handler = ngx_mail_proxy_write_handler; pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module); @@ -167,6 +176,8 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) return; } + s->proxy->proxy_protocol = pcf->proxy_protocol; + s->out.len = 0; switch (s->protocol) { @@ -186,6 +197,12 @@ ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) s->mail_state = ngx_smtp_start; break; } + + if (rc == NGX_AGAIN) { + return; + } + + ngx_mail_proxy_write_handler(p->upstream.connection->write); } @@ -230,6 +247,17 @@ ngx_mail_proxy_pop3_handler(ngx_event_t *rev) return; } + if (s->proxy->proxy_protocol) { + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy pop3 busy"); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + return; + } + rc = ngx_mail_proxy_read_response(s, 0); if (rc == NGX_AGAIN) { @@ -353,6 +381,17 @@ ngx_mail_proxy_imap_handler(ngx_event_t *rev) return; } + if (s->proxy->proxy_protocol) { + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy imap busy"); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + return; + } + rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { @@ -499,6 +538,17 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) return; } + if (s->proxy->proxy_protocol) { + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "mail proxy smtp busy"); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return; + } + + return; + } + rc = ngx_mail_proxy_read_response(s, s->mail_state); if (rc == NGX_AGAIN) { @@ -799,19 +849,92 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) static void -ngx_mail_proxy_dummy_handler(ngx_event_t *wev) +ngx_mail_proxy_write_handler(ngx_event_t *wev) { ngx_connection_t *c; ngx_mail_session_t *s; - ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy dummy handler"); + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, wev->log, 0, "mail proxy write handler"); + + c = wev->data; + s = c->data; + + if (s->proxy->proxy_protocol) { + if (ngx_mail_proxy_send_proxy_protocol(s) != NGX_OK) { + return; + } + + s->proxy->proxy_protocol = 0; + } if (ngx_handle_write_event(wev, 0) != NGX_OK) { - c = wev->data; - s = c->data; - - ngx_mail_proxy_close_session(s); + ngx_mail_proxy_internal_server_error(s); } + + if (c->read->ready) { + ngx_post_event(c->read, &ngx_posted_events); + } +} + + +static ngx_int_t +ngx_mail_proxy_send_proxy_protocol(ngx_mail_session_t *s) +{ + u_char *p; + ssize_t n, size; + ngx_connection_t *c; + u_char buf[NGX_PROXY_PROTOCOL_MAX_HEADER]; + + s->connection->log->action = "sending PROXY protocol header to upstream"; + + ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, + "mail proxy send PROXY protocol header"); + + p = ngx_proxy_protocol_write(s->connection, buf, + buf + NGX_PROXY_PROTOCOL_MAX_HEADER); + if (p == NULL) { + ngx_mail_proxy_internal_server_error(s); + return NGX_ERROR; + } + + c = s->proxy->upstream.connection; + + size = p - buf; + + n = c->send(c, buf, size); + + if (n == NGX_AGAIN) { + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + ngx_mail_proxy_internal_server_error(s); + return NGX_ERROR; + } + + return NGX_AGAIN; + } + + if (n == NGX_ERROR) { + ngx_mail_proxy_internal_server_error(s); + return NGX_ERROR; + } + + if (n != size) { + + /* + * PROXY protocol specification: + * The sender must always ensure that the header + * is sent at once, so that the transport layer + * maintains atomicity along the path to the receiver. + */ + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "could not send PROXY protocol header at once"); + + ngx_mail_proxy_internal_server_error(s); + + return NGX_ERROR; + } + + return NGX_OK; } @@ -1212,6 +1335,7 @@ ngx_mail_proxy_create_conf(ngx_conf_t *cf) pcf->pass_error_message = NGX_CONF_UNSET; pcf->xclient = NGX_CONF_UNSET; pcf->smtp_auth = NGX_CONF_UNSET; + pcf->proxy_protocol = NGX_CONF_UNSET; pcf->buffer_size = NGX_CONF_UNSET_SIZE; pcf->timeout = NGX_CONF_UNSET_MSEC; @@ -1229,6 +1353,7 @@ ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0); ngx_conf_merge_value(conf->xclient, prev->xclient, 1); ngx_conf_merge_value(conf->smtp_auth, prev->smtp_auth, 0); + ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0); ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, (size_t) ngx_pagesize); ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000); From d6f18d95297afa17d7ec64a1cfbdcbaf93b4d2dc Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 9 Mar 2021 16:38:55 +0300 Subject: [PATCH 21/23] Updated OpenSSL used for win32 builds. --- misc/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/GNUmakefile b/misc/GNUmakefile index 5c7550558..3a2ef5bf1 100644 --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.1.1i +OPENSSL = openssl-1.1.1j ZLIB = zlib-1.2.11 PCRE = pcre-8.44 From 1b8771ddcbc53dee494aeae1449f3b6403e7299d Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 9 Mar 2021 18:27:50 +0300 Subject: [PATCH 22/23] nginx-1.19.8-RELEASE --- docs/xml/nginx/changes.xml | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 6d407f0bb..1c7fb26b1 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,68 @@ + + + + +в директиве proxy_cookie_flags теперь +флаги можно задавать с помощью переменных. + + +flags in the "proxy_cookie_flags" directive +can now contain variables. + + + + + +параметр proxy_protocol в директиве listen, +директивы proxy_protocol и set_real_ip_from +в почтовом прокси-сервере. + + +the "proxy_protocol" parameter of the "listen" directive, +the "proxy_protocol" and "set_real_ip_from" directives +in mail proxy. + + + + + +HTTP/2-соединения сразу закрывались +при использовании "keepalive_timeout 0"; +ошибка появилась в 1.19.7. + + +HTTP/2 connections were immediately closed +when using "keepalive_timeout 0"; +the bug had appeared in 1.19.7. + + + + + +некоторые ошибки логгировались как неизвестные, +если nginx был собран с glibc 2.32. + + +some errors were logged as unknown +if nginx was built with glibc 2.32. + + + + + +в методе обработки соединений eventport. + + +in the eventport method. + + + + + + From 0026dded46da04b6b4522c5887bed5fceb4eda11 Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Tue, 9 Mar 2021 18:27:51 +0300 Subject: [PATCH 23/23] release-1.19.8 tag --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 139bd2f16..316ef60a7 100644 --- a/.hgtags +++ b/.hgtags @@ -457,3 +457,4 @@ dc0cc425fa63a80315f6efb68697cadb6626cdf2 release-1.19.4 8e5b068f761cd512d10c9671fbde0b568c1fd08b release-1.19.5 f618488eb769e0ed74ef0d93cd118d2ad79ef94d release-1.19.6 3fa6e2095a7a51acc630517e1c27a7b7ac41f7b3 release-1.19.7 +8c65d21464aaa5923775f80c32474adc7a320068 release-1.19.8