Opened 5 years ago
Closed 5 years ago
#2159 closed defect (fixed)
Massmail problems with mail module
| Reported by: | Owned by: | ||
|---|---|---|---|
| Priority: | minor | Milestone: | |
| Component: | nginx-module | Version: | 1.18.x |
| Keywords: | smtp, mail | Cc: | |
| uname -a: | Linux mailtest01 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 GNU/Linux | ||
| nginx -V: |
nginx version: nginx/1.18.0
built by gcc 8.3.0 (Debian 8.3.0-6) built with OpenSSL 1.1.1d 10 Sep 2019 TLS SNI support enabled configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -fdebug-prefix-map=/data/builder/debuild/nginx-1.18.0/debian/debuild-base/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' |
||
Description
We encountered a problem when sending mass-mails thru NGINX. When sending a mail to more than (in our case) ~130 recipients, NGINX closes the connection during the SMTP connection without an error.
What we found is, that this error only occurs when TLS and pipelining is involved. If either TLS or pipelining is deactivated, sending the mail works.
Another workaround is to increase the smtp_client_buffer. On our test system the mempage size is 4k.
What we saw in a capture is that when we send a mail with 130 recipients and pipelining is activated, NGINX receives the recipient commands and accepts them with 250 2.0.0 OK but then closes the TCP connection with a FIN.
I think it would be better that the sender gets an error if there is a to small buffer size.
Change History (5)
comment:1 by , 5 years ago
| Status: | new → accepted |
|---|
comment:2 by , 5 years ago
We will try the patch next week.
Thank you very much for the fast response.
comment:5 by , 5 years ago
| Resolution: | → fixed |
|---|---|
| Status: | accepted → closed |
Thanks for testing, fix committed.

Thanks for the report, I think I see what is going on here.
When an SMTP command from the client cannot be read into the
smtp_client_bufferbuffer, nginx responds with "500 5.5.1 Invalid command" error and logs the "client sent too long command" error to the error log. But if the buffer is filled with pipelined SMTP commands and there is no free space in it, nginx might callrecv()with zero length while trying to parse an additional command from the buffer. If this happens,recv()returns 0 and nginx thinks that the client closed the connection, so it closes the connection as well.Please try the following patch, it should resolve this regardless of the
smtp_client_buffersize (since nginx is only interested in one RCPT TO command before it passes the connection to the backend server, default buffer size of 4k is expected to be enough).# HG changeset patch # User Maxim Dounin <mdounin@mdounin.ru> # Date 1617811333 -10800 # Wed Apr 07 19:02:13 2021 +0300 # Node ID 3d0102933b51fa7b9ca930442777a0e613a2ca8c # Parent ad5aa609ca30bb89f8b53f5a1d08bde5b964a3ac Mail: fixed reading with fully filled buffer (ticket #2159). With SMTP pipelining, ngx_mail_read_command() can be called with s->buffer without any space available, to parse additional commands received to the buffer on previous calls. Previously, this resulted in recv() being called with zero len, resulting in zero being returned, which was interpreted as a connection close by the client, so nginx silently closed connection. Fix is to avoid calling c->recv() if there is no free space in the buffer, but continue parsing of the already received commands. diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -833,20 +833,23 @@ ngx_mail_read_command(ngx_mail_session_t ngx_str_t l; ngx_mail_core_srv_conf_t *cscf; - n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); + if (s->buffer->last < s->buffer->end) { + + n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); - if (n == NGX_ERROR || n == 0) { - ngx_mail_close_connection(c); - return NGX_ERROR; - } + if (n == NGX_ERROR || n == 0) { + ngx_mail_close_connection(c); + return NGX_ERROR; + } - if (n > 0) { - s->buffer->last += n; - } + if (n > 0) { + s->buffer->last += n; + } - if (n == NGX_AGAIN) { - if (s->buffer->pos == s->buffer->last) { - return NGX_AGAIN; + if (n == NGX_AGAIN) { + if (s->buffer->pos == s->buffer->last) { + return NGX_AGAIN; + } } }Note that the patch is actually quite simple, though changes indentation of some code. Whitespace-agnostic version of the same patch is as follows:
diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -833,6 +833,8 @@ ngx_mail_read_command(ngx_mail_session_t ngx_str_t l; ngx_mail_core_srv_conf_t *cscf; + if (s->buffer->last < s->buffer->end) { + n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); if (n == NGX_ERROR || n == 0) { @@ -849,6 +851,7 @@ ngx_mail_read_command(ngx_mail_session_t return NGX_AGAIN; } } + } cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);