From 065a1641b242538073e92065e20fd788203108ab Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:17 +0300 Subject: 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_proxy_module.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/mail/ngx_mail_proxy_module.c') 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; } -- cgit From 6538d93067c07d446826f3d9b9cb9a3a01df0d0b Mon Sep 17 00:00:00 2001 From: Maxim Dounin Date: Fri, 5 Mar 2021 17:16:32 +0300 Subject: 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_proxy_module.c | 139 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 7 deletions(-) (limited to 'src/mail/ngx_mail_proxy_module.c') 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_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; } @@ -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); -- cgit