Merge branch 'nginx' (nginx-1.19.8).
Change-Id: I38faddb630d8f73659d9c01132999e6d58059ed3
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 139bd2f..316ef60 100644
--- a/.hgtags
+++ b/.hgtags
@@ -457,3 +457,4 @@
8e5b068f761cd512d10c9671fbde0b568c1fd08b release-1.19.5
f618488eb769e0ed74ef0d93cd118d2ad79ef94d release-1.19.6
3fa6e2095a7a51acc630517e1c27a7b7ac41f7b3 release-1.19.7
+8c65d21464aaa5923775f80c32474adc7a320068 release-1.19.8
diff --git a/BUILD b/BUILD
index 8f63498..55ed1ac 100644
--- a/BUILD
+++ b/BUILD
@@ -1075,6 +1075,7 @@
"src/mail/ngx_mail_core_module.c",
"src/mail/ngx_mail_handler.c",
"src/mail/ngx_mail_proxy_module.c",
+ "src/mail/ngx_mail_realip_module.c",
"src/mail/ngx_mail_ssl_module.c",
"src/mail/ngx_mail_ssl_module.h",
],
@@ -1536,5 +1537,5 @@
preinst = "@nginx_pkgoss//:debian_preinst",
prerm = "@nginx_pkgoss//:debian_prerm",
section = "httpd",
- version = "1.19.7",
+ version = "1.19.8",
)
diff --git a/auto/init b/auto/init
index 71fd93f..979d267 100644
--- a/auto/init
+++ b/auto/init
@@ -50,6 +50,8 @@
clean:
rm -rf Makefile $NGX_OBJS
+
+.PHONY: default clean
END
fi
diff --git a/auto/install b/auto/install
index c97b12b..fc61fa0 100644
--- a/auto/install
+++ b/auto/install
@@ -215,4 +215,6 @@
test -f $NGX_PID_PATH.oldbin
kill -QUIT \`cat $NGX_PID_PATH.oldbin\`
+
+.PHONY: build install modules upgrade
END
diff --git a/auto/modules b/auto/modules
index e9d2923..d56e2f6 100644
--- a/auto/modules
+++ b/auto/modules
@@ -985,6 +985,12 @@
ngx_module_srcs=src/mail/ngx_mail_proxy_module.c
. $NGX_AUTO/module
+
+ ngx_module_name=ngx_mail_realip_module
+ ngx_module_deps=
+ ngx_module_srcs=src/mail/ngx_mail_realip_module.c
+
+ . $NGX_AUTO/module
fi
diff --git a/auto/unix b/auto/unix
index c3276f2..e4f9159 100644
--- a/auto/unix
+++ b/auto/unix
@@ -727,19 +727,35 @@
. $NGX_AUTO/feature
-ngx_feature="sys_nerr"
-ngx_feature_name="NGX_SYS_NERR"
-ngx_feature_run=value
-ngx_feature_incs='#include <errno.h>
- #include <stdio.h>'
+# 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 <string.h>'
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"
. $NGX_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 <errno.h>
+ #include <stdio.h>'
+ ngx_feature_path=
+ ngx_feature_libs=
+ ngx_feature_test='printf("%d", sys_nerr);'
+ . $NGX_AUTO/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
# Cygiwn defines _sys_nerr
ngx_feature="_sys_nerr"
ngx_feature_name="NGX_SYS_NERR"
@@ -753,34 +769,6 @@
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 <errno.h>
- #include <string.h>
- #include <stdio.h>'
- 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);'
- . $NGX_AUTO/feature
-fi
-
-
ngx_feature="localtime_r()"
ngx_feature_name="NGX_HAVE_LOCALTIME_R"
ngx_feature_run=no
diff --git a/build.bzl b/build.bzl
index 1b74db3..76b3e06 100644
--- a/build.bzl
+++ b/build.bzl
@@ -673,9 +673,9 @@
name = "nginx_pkgoss",
build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
_PKGOSS_BUILD_FILE_TAIL,
- commit = "07ce85eee27f01a69cd70bb1f251e546f2fa750b", # nginx-1.19.7
+ commit = "f6674ffb8cbba3096aea8ad52951ce0eb71a0f31", # nginx-1.19.8
remote = "https://nginx.googlesource.com/nginx-pkgoss",
- shallow_since = "1613491796 +0300",
+ shallow_since = "1615305446 +0300",
)
def nginx_repositories_zlib(bind):
diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim
index 2d5ed06..88ec847 100644
--- a/contrib/vim/syntax/nginx.vim
+++ b/contrib/vim/syntax/nginx.vim
@@ -2414,26 +2414,26 @@
" 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"
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 6d407f0..1c7fb26 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,68 @@
<change_log title="nginx">
+<changes ver="1.19.8" date="2021-03-09">
+
+<change type="feature">
+<para lang="ru">
+в директиве proxy_cookie_flags теперь
+флаги можно задавать с помощью переменных.
+</para>
+<para lang="en">
+flags in the "proxy_cookie_flags" directive
+can now contain variables.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+параметр proxy_protocol в директиве listen,
+директивы proxy_protocol и set_real_ip_from
+в почтовом прокси-сервере.
+</para>
+<para lang="en">
+the "proxy_protocol" parameter of the "listen" directive,
+the "proxy_protocol" and "set_real_ip_from" directives
+in mail proxy.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+HTTP/2-соединения сразу закрывались
+при использовании "keepalive_timeout 0";
+ошибка появилась в 1.19.7.
+</para>
+<para lang="en">
+HTTP/2 connections were immediately closed
+when using "keepalive_timeout 0";
+the bug had appeared in 1.19.7.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+некоторые ошибки логгировались как неизвестные,
+если nginx был собран с glibc 2.32.
+</para>
+<para lang="en">
+some errors were logged as unknown
+if nginx was built with glibc 2.32.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в методе обработки соединений eventport.
+</para>
+<para lang="en">
+in the eventport method.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.19.7" date="2021-02-16">
<change type="change">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile
index 5c75505..3a2ef5b 100644
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -6,7 +6,7 @@
CC = cl
OBJS = objs.msvc8
-OPENSSL = openssl-1.1.1i
+OPENSSL = openssl-1.1.1j
ZLIB = zlib-1.2.11
PCRE = pcre-8.44
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 26b017e..0b9c56f 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1019007
-#define NGINX_VERSION "1.19.7"
+#define nginx_version 1019008
+#define NGINX_VERSION "1.19.8"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
index b96d25b..b97ddee 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -318,7 +318,7 @@
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;
}
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 2929a2e..69ec660 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -83,7 +83,7 @@
#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);
@@ -1037,26 +1037,52 @@
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);
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
@@ -1971,6 +1997,10 @@
#endif
SSL_CIPHER *cipher;
+ if (!(c->log->log_level & NGX_LOG_DEBUG_EVENT)) {
+ return;
+ }
+
cipher = SSL_get_current_cipher(c->ssl->connection);
if (cipher) {
@@ -4821,11 +4851,13 @@
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;
}
@@ -4873,11 +4905,13 @@
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;
}
@@ -4926,6 +4960,11 @@
}
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 */ }
@@ -4969,6 +5008,11 @@
}
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 */ }
@@ -5005,6 +5049,7 @@
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;
}
@@ -5043,6 +5088,7 @@
}
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;
}
@@ -5116,6 +5162,7 @@
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;
}
@@ -5160,6 +5207,7 @@
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;
}
@@ -5202,9 +5250,9 @@
}
#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) {
@@ -5239,7 +5287,7 @@
#if OPENSSL_VERSION_NUMBER > 0x10100000L
const
#endif
- ASN1_TIME *asn1time)
+ ASN1_TIME *asn1time, ngx_log_t *log)
{
BIO *bio;
char *value;
@@ -5255,6 +5303,7 @@
bio = BIO_new(BIO_s_mem());
if (bio == NULL) {
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0, "BIO_new() failed");
return NGX_ERROR;
}
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
index aa75765..f5bf575 100644
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -4841,9 +4841,9 @@
{
#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 e2bf547..c309ab9 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -56,7 +56,7 @@
#endif
} cookie;
- ngx_uint_t flags;
+ ngx_array_t flags_values;
ngx_uint_t regex;
} ngx_http_proxy_cookie_flags_t;
@@ -2923,12 +2923,14 @@
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;
@@ -2972,7 +2974,47 @@
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);
}
@@ -4544,8 +4586,8 @@
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)
@@ -4629,32 +4671,27 @@
}
}
- 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;
}
}
@@ -4906,9 +4943,9 @@
{
#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 b8ea065..8ec1415 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -1287,9 +1287,9 @@
{
#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 bf27326..1334f44 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -2398,9 +2398,9 @@
{
#ifndef SSL_CONF_FLAG_FILE
return "is not supported on this platform";
-#endif
-
+#else
return NGX_CONF_OK;
+#endif
}
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 98d4abd..ac3e869 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -239,6 +239,7 @@
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;
@@ -326,8 +327,10 @@
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;
diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c
index f17c2cc..890d815 100644
--- a/src/mail/ngx_mail.c
+++ b/src/mail/ngx_mail.c
@@ -405,6 +405,7 @@
#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 @@
#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 25ac432..b865a3b 100644
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -41,6 +41,7 @@
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 {
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 {
@@ -176,6 +178,7 @@
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;
@@ -197,6 +200,7 @@
ngx_uint_t mail_state;
+ unsigned ssl:1;
unsigned protocol:3;
unsigned blocked:1;
unsigned quit:1;
@@ -405,6 +409,7 @@
/* 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_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c
index 6b57358..06ded47 100644
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -1224,22 +1224,49 @@
+ 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 (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
+ + 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;
@@ -1298,6 +1325,26 @@
*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 e16d702..4083124 100644
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -548,6 +548,11 @@
#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 803a247..b901053 100644
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -11,6 +11,8 @@
#include <ngx_mail.h>
+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);
#if (NGX_MAIL_SSL)
@@ -26,6 +28,7 @@
{
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 +132,10 @@
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 +166,125 @@
c->log_error = NGX_ERROR_INFO;
+ 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;
+ }
+
+ rev->handler(rev);
+}
+
+
+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;
+ }
+
+ if (ngx_mail_realip_handler(s) != NGX_OK) {
+ ngx_mail_close_connection(c);
+ return;
+ }
+
+ ngx_mail_init_session_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);
@@ -215,9 +334,10 @@
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;
@@ -338,6 +458,8 @@
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;
@@ -722,11 +844,6 @@
}
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 3bf09ec..5dfdd76 100644
--- a/src/mail/ngx_mail_imap_handler.c
+++ b/src/mail/ngx_mail_imap_handler.c
@@ -123,6 +123,12 @@
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;
}
@@ -130,7 +136,16 @@
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;
}
@@ -293,6 +308,11 @@
}
}
+ 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 9310c27..edfd986 100644
--- a/src/mail/ngx_mail_pop3_handler.c
+++ b/src/mail/ngx_mail_pop3_handler.c
@@ -138,6 +138,12 @@
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;
}
@@ -145,7 +151,16 @@
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;
}
@@ -275,6 +290,11 @@
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 610f547..66aa0ba 100644
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -17,6 +17,7 @@
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_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 @@
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 @@
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 @@
return;
}
+ s->proxy->proxy_protocol = pcf->proxy_protocol;
+
s->out.len = 0;
switch (s->protocol) {
@@ -186,6 +197,12 @@
s->mail_state = ngx_smtp_start;
break;
}
+
+ if (rc == NGX_AGAIN) {
+ return;
+ }
+
+ ngx_mail_proxy_write_handler(p->upstream.connection->write);
}
@@ -230,9 +247,25 @@
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) {
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
return;
}
@@ -314,6 +347,11 @@
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;
}
@@ -343,9 +381,25 @@
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) {
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
return;
}
@@ -448,6 +502,11 @@
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;
}
@@ -479,9 +538,25 @@
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) {
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
return;
}
@@ -763,25 +838,103 @@
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;
}
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;
}
@@ -1182,6 +1335,7 @@
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;
@@ -1199,6 +1353,7 @@
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);
diff --git a/src/mail/ngx_mail_realip_module.c b/src/mail/ngx_mail_realip_module.c
new file mode 100644
index 0000000..c93d7d3
--- /dev/null
+++ b/src/mail/ngx_mail_realip_module.c
@@ -0,0 +1,269 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_mail.h>
+
+
+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;
+}
diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c
index f1017e0..e68ceed 100644
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -449,6 +449,12 @@
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;
}
@@ -456,7 +462,16 @@
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;
}
@@ -568,6 +583,11 @@
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);
}
}
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index d560bd6..7eae83e 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -682,7 +682,7 @@
{
#ifndef SSL_CONF_FLAG_FILE
return "is not supported on this platform";
-#endif
-
+#else
return NGX_CONF_OK;
+#endif
}
diff --git a/src/ngx_modules.c b/src/ngx_modules.c
index 304a2d1..2f1a4db 100644
--- a/src/ngx_modules.c
+++ b/src/ngx_modules.c
@@ -242,6 +242,7 @@
#if (NGX_MAIL)
extern ngx_module_t ngx_mail_auth_http_module;
extern ngx_module_t ngx_mail_proxy_module;
+extern ngx_module_t ngx_mail_realip_module;
#endif
#if (NGX_STREAM)
@@ -534,6 +535,7 @@
#if (NGX_MAIL)
&ngx_mail_auth_http_module,
&ngx_mail_proxy_module,
+ &ngx_mail_realip_module,
#endif
#if (NGX_STREAM)
@@ -828,6 +830,7 @@
#if (NGX_MAIL)
"ngx_mail_auth_http_module",
"ngx_mail_proxy_module",
+ "ngx_mail_realip_module",
#endif
#if (NGX_STREAM)
diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c
index e787b23..ca23b2d 100644
--- a/src/os/unix/ngx_errno.c
+++ b/src/os/unix/ngx_errno.c
@@ -9,6 +9,49 @@
#include <ngx_core.h>
+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,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 +78,13 @@
{
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 +99,92 @@
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 +193,8 @@
}
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;
@@ -85,3 +206,5 @@
return NGX_ERROR;
}
+
+#endif
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index 0c86083..01cda7a 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -1026,9 +1026,9 @@
{
#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 ccd359f..d8c0471 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -1061,9 +1061,9 @@
{
#ifndef SSL_CONF_FLAG_FILE
return "is not supported on this platform";
-#endif
-
+#else
return NGX_CONF_OK;
+#endif
}