summaryrefslogtreecommitdiffhomepage
path: root/src/mail
diff options
context:
space:
mode:
authorSergey Kandaurov <pluknet@nginx.com>2021-03-10 15:39:01 +0300
committerSergey Kandaurov <pluknet@nginx.com>2021-03-10 15:39:01 +0300
commit02b52e4c0b71b960ce426ef80fefa359e5e6b42e (patch)
treeeb36f3f05641ada335fc88ff4f04d6e75555010c /src/mail
parentb7433b15fcdd97cc0d8b45407a4af1520663e54f (diff)
parent0026dded46da04b6b4522c5887bed5fceb4eda11 (diff)
downloadnginx-02b52e4c0b71b960ce426ef80fefa359e5e6b42e.tar.gz
nginx-02b52e4c0b71b960ce426ef80fefa359e5e6b42e.tar.bz2
Merged with the default branch.
Diffstat (limited to 'src/mail')
-rw-r--r--src/mail/ngx_mail.c2
-rw-r--r--src/mail/ngx_mail.h7
-rw-r--r--src/mail/ngx_mail_auth_http_module.c73
-rw-r--r--src/mail/ngx_mail_core_module.c5
-rw-r--r--src/mail/ngx_mail_handler.c135
-rw-r--r--src/mail/ngx_mail_imap_handler.c22
-rw-r--r--src/mail/ngx_mail_pop3_handler.c22
-rw-r--r--src/mail/ngx_mail_proxy_module.c169
-rw-r--r--src/mail/ngx_mail_realip_module.c269
-rw-r--r--src/mail/ngx_mail_smtp_handler.c22
-rw-r--r--src/mail/ngx_mail_ssl_module.c4
11 files changed, 695 insertions, 35 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 25ac432b0..b865a3b9e 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 {
@@ -176,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;
@@ -197,6 +200,7 @@ typedef struct {
ngx_uint_t mail_state;
+ unsigned ssl:1;
unsigned protocol:3;
unsigned blocked:1;
unsigned quit:1;
@@ -405,6 +409,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_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c
index 6b57358b4..06ded470a 100644
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -1224,22 +1224,49 @@ 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 (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 @@ 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 803a247d2..b9010535b 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 @@ 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 +132,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 +166,125 @@ 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 (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 @@ 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;
@@ -338,6 +458,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;
@@ -722,11 +844,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 3bf09ec3c..5dfdd7601 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;
}
@@ -130,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;
}
@@ -293,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 9310c2750..edfd98681 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;
}
@@ -145,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;
}
@@ -275,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..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,9 +247,25 @@ 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) {
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
return;
}
@@ -314,6 +347,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;
}
@@ -343,9 +381,25 @@ 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) {
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
return;
}
@@ -448,6 +502,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;
}
@@ -479,9 +538,25 @@ 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) {
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
return;
}
@@ -763,25 +838,103 @@ 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;
}
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_internal_server_error(s);
+ }
- ngx_mail_proxy_close_session(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 @@ 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;
@@ -1199,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);
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 <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 f1017e0d8..e68ceedfd 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;
}
@@ -456,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;
}
@@ -568,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);
}
}
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
}