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.
This commit is contained in:
Maxim Dounin 2021-03-05 17:16:24 +03:00
parent 05d4191476
commit aa60a47253
5 changed files with 132 additions and 4 deletions

View File

@ -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;
}

View File

@ -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 {

View File

@ -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 */

View File

@ -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;

View File

@ -11,6 +11,7 @@
#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);
@ -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;