[PATCH] Add proxy_protocol option to mail listener
Kees Bos
cornelis.bos at gmail.com
Fri Jul 7 13:38:02 UTC 2017
# HG changeset patch
# User Kees Bos <cornelis.bos at gmail.com>
# Date 1499422505 0
# Fri Jul 07 10:15:05 2017 +0000
# Node ID bc79b2baf494aabb889de1e5dbe3184ff0cb9bfa
# Parent 70e65bf8dfd7a8d39aae8ac3a209d426e6947735
Add proxy_protocol option to mail listener
Add support for the mail handlers. This enables the use of an upstream
loadbalancer/proxy (like haproxy) that connects with the proxy protocol.
The original ip (as exposed with the proxy protocol) will be used as
parameter for the 'Client-IP' in the authentication call.
Example config:
mail {
server_name mail.example.com;
auth_http localhost:9000/;
server {
listen 143 proxy_protocol;
protocol imap;
}
}
diff -r 70e65bf8dfd7 -r bc79b2baf494 src/mail/ngx_mail.c
--- a/src/mail/ngx_mail.c Tue Jul 04 18:50:41 2017 +0300
+++ b/src/mail/ngx_mail.c Fri Jul 07 10:15:05 2017 +0000
@@ -408,6 +408,7 @@
#if (NGX_MAIL_SSL)
addrs[i].conf.ssl = addr[i].opt.ssl;
#endif
+ addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen,
buf, NGX_SOCKADDR_STRLEN, 1);
@@ -457,6 +458,7 @@
#if (NGX_MAIL_SSL)
addrs6[i].conf.ssl = addr[i].opt.ssl;
#endif
+ addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
len = ngx_sock_ntop(&addr[i].opt.sockaddr.sockaddr, addr[i].opt.socklen,
buf, NGX_SOCKADDR_STRLEN, 1);
diff -r 70e65bf8dfd7 -r bc79b2baf494 src/mail/ngx_mail.h
--- a/src/mail/ngx_mail.h Tue Jul 04 18:50:41 2017 +0300
+++ b/src/mail/ngx_mail.h Fri Jul 07 10:15:05 2017 +0000
@@ -40,6 +40,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,6 +56,7 @@
ngx_mail_conf_ctx_t *ctx;
ngx_str_t addr_text;
ngx_uint_t ssl; /* unsigned ssl:1; */
+ unsigned proxy_protocol:1;
} ngx_mail_addr_conf_t;
typedef struct {
@@ -204,6 +206,8 @@
unsigned esmtp:1;
unsigned auth_method:3;
unsigned auth_wait:1;
+ unsigned ssl:1;
+ unsigned proxy_protocol:1;
ngx_str_t login;
ngx_str_t passwd;
diff -r 70e65bf8dfd7 -r bc79b2baf494 src/mail/ngx_mail_auth_http_module.c
--- a/src/mail/ngx_mail_auth_http_module.c Tue Jul 04 18:50:41 2017 +0300
+++ b/src/mail/ngx_mail_auth_http_module.c Fri Jul 07 10:15:05 2017 +0000
@@ -1142,6 +1142,7 @@
ngx_mail_ssl_conf_t *sslcf;
#endif
ngx_mail_core_srv_conf_t *cscf;
+ ngx_str_t *client_addr;
if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
return NULL;
@@ -1208,6 +1209,11 @@
#endif
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+ if (s->connection->proxy_protocol_addr.len) {
+ client_addr = &s->connection->proxy_protocol_addr;
+ } else {
+ client_addr = &s->connection->addr_text;
+ }
len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
+ sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
@@ -1221,7 +1227,7 @@
+ sizeof(CRLF) - 1
+ sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
+ sizeof(CRLF) - 1
- + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
+ + sizeof("Client-IP: ") - 1 + client_addr->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
@@ -1287,8 +1293,7 @@
s->login_attempt);
b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
- b->last = ngx_copy(b->last, s->connection->addr_text.data,
- s->connection->addr_text.len);
+ b->last = ngx_copy(b->last, client_addr->data, client_addr->len);
*b->last++ = CR; *b->last++ = LF;
if (s->host.len) {
diff -r 70e65bf8dfd7 -r bc79b2baf494 src/mail/ngx_mail_core_module.c
--- a/src/mail/ngx_mail_core_module.c Tue Jul 04 18:50:41 2017 +0300
+++ b/src/mail/ngx_mail_core_module.c Fri Jul 07 10:15:05 2017 +0000
@@ -574,6 +574,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 -r 70e65bf8dfd7 -r bc79b2baf494 src/mail/ngx_mail_handler.c
--- a/src/mail/ngx_mail_handler.c Tue Jul 04 18:50:41 2017 +0300
+++ b/src/mail/ngx_mail_handler.c Fri Jul 07 10:15:05 2017 +0000
@@ -12,7 +12,7 @@
static void ngx_mail_init_session(ngx_connection_t *c);
-
+static void ngx_mail_proxy_protocol_handler(ngx_event_t *rev);
#if (NGX_MAIL_SSL)
static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
@@ -143,6 +143,7 @@
ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
c->number, len, text, s->addr_text);
+ s->proxy_protocol = addr_conf->proxy_protocol;
ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
if (ctx == NULL) {
ngx_mail_close_connection(c);
@@ -165,16 +166,11 @@
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+ s->ssl = 0;
if (sslcf->enable) {
- c->log->action = "SSL handshaking";
-
- ngx_mail_ssl_init_connection(&sslcf->ssl, c);
- return;
- }
-
- if (addr_conf->ssl) {
-
- c->log->action = "SSL handshaking";
+ s->ssl = 1;
+ } else if (addr_conf->ssl) {
+ s->ssl = 1;
if (sslcf->ssl.ctx == NULL) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
@@ -183,11 +179,78 @@
ngx_mail_close_connection(c);
return;
}
+ }
+ }
+#endif
+
+ if (s->proxy_protocol) {
+ c->log->action = "reading PROXY protocol";
+ ngx_add_timer(c->read, cscf->timeout);
+ c->read->handler = ngx_mail_proxy_protocol_handler;
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_close_connection(c);
+ }
+ return;
+ }
+
+#if (NGX_MAIL_SSL)
+ if (s->ssl) {
+ ngx_mail_ssl_conf_t *sslcf;
+ c->log->action = "SSL handshaking";
+ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
ngx_mail_ssl_init_connection(&sslcf->ssl, c);
return;
}
+# endif
+ ngx_mail_init_session(c);
+}
+
+
+void
+ngx_mail_proxy_protocol_handler(ngx_event_t *rev)
+{
+ u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];
+ size_t size;
+ ssize_t n;
+ ngx_err_t err;
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
+
+ size = sizeof(buf);
+ c = rev->data;
+
+ n = recv(c->fd, (char *) buf, size, MSG_PEEK);
+ err = ngx_socket_errno;
+
+ if (n == -1) {
+ 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;
+ }
+ s = c->data;
+ s->proxy_protocol = 0;
+
+#if (NGX_MAIL_SSL)
+ {
+ ngx_mail_ssl_conf_t *sslcf;
+ if (s->ssl) {
+ c->log->action = "SSL handshaking";
+ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+ ngx_mail_ssl_init_connection(&sslcf->ssl, c);
+ return;
+ }
}
#endif
@@ -222,6 +285,20 @@
ngx_mail_session_t *s;
ngx_mail_core_srv_conf_t *cscf;
+ s = c->data;
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+ if (s->proxy_protocol) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "Has proxy_protocol");
+ c->log->action = "reading PROXY protocol";
+ ngx_add_timer(c->read, cscf->timeout);
+ c->read->handler = ngx_mail_proxy_protocol_handler;
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+ ngx_mail_close_connection(c);
+ }
+ return;
+ }
+
if (ngx_ssl_create_connection(ssl, c, 0) != NGX_OK) {
ngx_mail_close_connection(c);
return;
@@ -229,10 +306,6 @@
if (ngx_ssl_handshake(c) == NGX_AGAIN) {
- s = c->data;
-
- 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;
More information about the nginx-devel
mailing list