<div dir="ltr"><span style="font-size:12.8px">Hi Folks,</span><br style="font-size:12.8px"><br style="font-size:12.8px"><span style="font-size:12.8px">I was not sure if you would be interested in this, but decided to run it by you anyway.</span><br style="font-size:12.8px"><br style="font-size:12.8px"><span style="font-size:12.8px">We need to run Nginx as an SMTP proxy sitting behind ELB in AWS, but we also want the upstream SMTP server to get the real client ip, so Nginx is configured to provide it via an XCLIENT command. However the stock version of Nginx provides ELB's ip instead, because it does not recognize the Proxy Protocol header (</span><a href="http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-proxy-protocol.html#proxy-protocol" target="_blank" style="font-size:12.8px">http://docs.aws.amazon.com/<wbr>elasticloadbalancing/latest/<wbr>classic/enable-proxy-protocol.<wbr>html#proxy-protocol</a><span style="font-size:12.8px">) sent to it by ELB. The following patch updates the mail module so that it can be configured to expect Proxy Protocol header by setting `proxy_protocol on`. In that case Proxy Protocol header is parsed, a client IP is retrieved and passed to an SMTP upstream in an XCLIENT command.</span><div style="font-size:12.8px"><br></div><div style="font-size:12.8px">Here it is:<br><br># HG changeset patch<br># User Maxim Vladimirskiy <<a href="mailto:maxim@mailgunhq.com" target="_blank">maxim@mailgunhq.com</a>><br># Date 1478116426 25200<br>#      Wed Nov 02 12:53:46 2016 -0700<br># Node ID fcb527c8ade6db113acbee677f321f<wbr>a0249348a2<br># Parent  <wbr>0fba3ed4e7eba474e3f518763d9e02<wbr>851c9ff024<br>Add support for Proxy Protocol to mail SMTP<br><br>When nginx is not the first proxy in a proxy chain it needs to be able to<br>understand the Proxy Protocol Header to retrieve client IP and pass it<br>downstream in an XCLIENT command. With these changes one can do<br>that by setting `proxy_protocol on;` in the mail module config.<br><br>diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail.h<br>--- a/src/mail/ngx_mail.h  Wed Nov 02 20:05:21 2016 +0300<br>+++ b/src/mail/ngx_mail.h  Wed Nov 02 12:53:46 2016 -0700<br>@@ -185,6 +185,7 @@<br>     void                  **ctx;<br>     void                  **main_conf;<br>     void                  **srv_conf;<br>+    ngx_mail_addr_conf_t   *addr_conf;<br> <br>     ngx_resolver_ctx_t     *resolver_ctx;<br> <br>diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail_handler.c<br>--- a/src/mail/ngx_mail_handler.c  Wed Nov 02 20:05:21 2016 +0300<br>+++ b/src/mail/ngx_mail_handler.c  Wed Nov 02 12:53:46 2016 -0700<br>@@ -9,9 +9,12 @@<br> #include <ngx_core.h><br> #include <ngx_event.h><br> #include <ngx_mail.h><br>+#include <ngx_mail_proxy_module.h><br> <br> <br> static void ngx_mail_init_session(ngx_<wbr>connection_t *c);<br>+static void ngx_mail_proxy_protocol_<wbr>handler(ngx_event_t *rev);<br>+static void ngx_mail_init_session_handler(<wbr>ngx_event_t *rev);<br> <br> #if (NGX_MAIL_SSL)<br> static void ngx_mail_ssl_init_connection(<wbr>ngx_ssl_t *ssl, ngx_connection_t *c);<br>@@ -34,6 +37,8 @@<br>     ngx_mail_session_t        *s;<br>     ngx_mail_addr_conf_t      *addr_conf;<br>     ngx_mail_core_srv_conf_t  *cscf;<br>+    ngx_mail_proxy_conf_t     *pcf;<br>+    ngx_event_t               *rev;<br>     u_char                     text[NGX_SOCKADDR_STRLEN];<br> #if (NGX_HAVE_INET6)<br>     struct sockaddr_in6       *sin6;<br>@@ -128,6 +133,7 @@<br> <br>     s->main_conf = addr_conf->ctx->main_conf;<br>     s->srv_conf = addr_conf->ctx->srv_conf;<br>+    s->addr_conf = addr_conf;<br> <br>     s->addr_text = &addr_conf->addr_text;<br> <br>@@ -159,10 +165,31 @@<br> <br>     c->log_error = NGX_ERROR_INFO;<br> <br>+    rev = c->read;<br>+<br>+    pcf = ngx_mail_get_module_srv_conf(<wbr>s, ngx_mail_proxy_module);<br>+    if (pcf->proxy_protocol) {<br>+        rev->handler = ngx_mail_proxy_protocol_<wbr>handler;<br>+        ngx_mail_proxy_protocol_<wbr>handler(rev);<br>+        return;<br>+    }<br>+<br>+    ngx_mail_init_session_<wbr>handler(rev);<br>+}<br>+<br>+<br>+static void<br>+ngx_mail_init_session_<wbr>handler(ngx_event_t *rev)<br>+{<br>+    ngx_connection_t  *c;<br>+<br>+    c = rev->data;<br>+<br> #if (NGX_MAIL_SSL)<br>-    {<br>     ngx_mail_ssl_conf_t  *sslcf;<br>+    ngx_mail_session_t   *s;<br> <br>+    s = c->data;<br>     sslcf = ngx_mail_get_module_srv_conf(<wbr>s, ngx_mail_ssl_module);<br> <br>     if (sslcf->enable) {<br>@@ -172,7 +199,7 @@<br>         return;<br>     }<br> <br>-    if (addr_conf->ssl) {<br>+    if (s->addr_conf->ssl) {<br> <br>         c->log->action = "SSL handshaking";<br> <br>@@ -187,8 +214,6 @@<br>         ngx_mail_ssl_init_connection(<wbr>&sslcf->ssl, c);<br>         return;<br>     }<br>-<br>-    }<br> #endif<br> <br>     ngx_mail_init_session(c);<br>@@ -898,3 +923,73 @@<br> <br>     return p;<br> }<br>+<br>+<br>+static void<br>+ngx_mail_proxy_protocol_<wbr>handler(ngx_event_t *rev)<br>+{<br>+    ngx_mail_session_t        *s;<br>+    ngx_mail_core_srv_conf_t  *cscf;<br>+    u_char                    *p, buf[NGX_PROXY_PROTOCOL_MAX_<wbr>HEADER + 1];<br>+    size_t                     size;<br>+    ssize_t                    n;<br>+    ngx_connection_t          *c;<br>+<br>+    c = rev->data;<br>+    s = c->data;<br>+<br>+    cscf = ngx_mail_get_module_srv_conf(<wbr>s, ngx_mail_core_module);<br>+<br>+    ngx_log_debug0(NGX_LOG_DEBUG_<wbr>HTTP, rev->log, 0,<br>+                   "read proxy protocol header");<br>+<br>+    if (rev->timedout) {<br>+        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");<br>+        ngx_mail_close_connection(c);<br>+        return;<br>+    }<br>+<br>+    if (c->close) {<br>+        ngx_mail_close_connection(c);<br>+        return;<br>+    }<br>+<br>+    n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK);<br>+<br>+    ngx_log_debug1(NGX_LOG_DEBUG_<wbr>HTTP, rev->log, 0, "http recv(): %z", n);<br>+<br>+    if (n == -1) {<br>+        if (ngx_socket_errno == NGX_EAGAIN) {<br>+            rev->ready = 0;<br>+<br>+            if (!rev->timer_set) {<br>+                ngx_add_timer(rev, cscf->timeout);<br>+                ngx_reusable_connection(c, 1);<br>+            }<br>+<br>+            if (ngx_handle_read_event(rev, 0) != NGX_OK) {<br>+                ngx_mail_close_connection(c);<br>+            }<br>+            return;<br>+        }<br>+<br>+        ngx_connection_error(c, ngx_socket_errno, "recv() failed");<br>+        ngx_mail_close_connection(c);<br>+        return;<br>+    }<br>+<br>+    p = ngx_proxy_protocol_read(c, buf, buf + n);<br>+    if (p == NULL) {<br>+        ngx_mail_close_connection(c);<br>+        return;<br>+    }<br>+<br>+    // Purge the Proxy Protocol header from the network buffer.<br>+    size = p - buf;<br>+    if (c->recv(c, buf, size) != (ssize_t) size) {<br>+        ngx_mail_close_connection(c);<br>+        return;<br>+    }<br>+<br>+    ngx_mail_init_session_<wbr>handler(rev);<br>+}<br>\ No newline at end of file<br>diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail_proxy_<wbr>module.c<br>--- a/src/mail/ngx_mail_proxy_<wbr>module.c Wed Nov 02 20:05:21 2016 +0300<br>+++ b/src/mail/ngx_mail_proxy_<wbr>module.c Wed Nov 02 12:53:46 2016 -0700<br>@@ -10,15 +10,7 @@<br> #include <ngx_event.h><br> #include <ngx_event_connect.h><br> #include <ngx_mail.h><br>-<br>-<br>-typedef struct {<br>-    ngx_flag_t  enable;<br>-    ngx_flag_t  pass_error_message;<br>-    ngx_flag_t  xclient;<br>-    size_t      buffer_size;<br>-    ngx_msec_t  timeout;<br>-} ngx_mail_proxy_conf_t;<br>+#include <ngx_mail_proxy_module.h><br> <br> <br> static void ngx_mail_proxy_block_read(ngx_<wbr>event_t *rev);<br>@@ -74,6 +66,13 @@<br>       offsetof(ngx_mail_proxy_conf_<wbr>t, xclient),<br>       NULL },<br> <br>+    { ngx_string("proxy_protocol"),<br>+      NGX_MAIL_MAIN_CONF|NGX_MAIL_<wbr>SRV_CONF|NGX_CONF_FLAG,<br>+      ngx_conf_set_flag_slot,<br>+      NGX_MAIL_SRV_CONF_OFFSET,<br>+      offsetof(ngx_mail_proxy_conf_<wbr>t, proxy_protocol),<br>+      NULL },<br>+<br>       ngx_null_command<br> };<br> <br>@@ -456,6 +455,7 @@<br>     ngx_mail_session_t        *s;<br>     ngx_mail_proxy_conf_t     *pcf;<br>     ngx_mail_core_srv_conf_t  *cscf;<br>+    ngx_str_t                  client_addr;<br> <br>     ngx_log_debug0(NGX_LOG_DEBUG_<wbr>MAIL, rev->log, 0,<br>                    "mail proxy smtp auth handler");<br>@@ -525,9 +525,12 @@<br> <br>         s->connection->log->action = "sending XCLIENT to upstream";<br> <br>-        line.len = sizeof("XCLIENT ADDR= LOGIN= NAME="<br>-                          CRLF) - 1<br>-                   + s->connection->addr_text.len + s->login.len + s->host.len;<br>+        client_addr = s->connection->addr_text;<br>+        if (s->connection->proxy_<wbr>protocol_addr.data != NULL) {<br>+            client_addr = s->connection->proxy_protocol_<wbr>addr;<br>+        }<br>+        line.len = sizeof("XCLIENT ADDR= LOGIN= NAME=" CRLF) - 1<br>+                   + client_addr.len + s->login.len + s->host.len;<br> <br> #if (NGX_HAVE_INET6)<br>         if (s->connection->sockaddr->sa_<wbr>family == AF_INET6) {<br>@@ -549,9 +552,7 @@<br>         }<br> #endif<br> <br>-        p = ngx_copy(p, s->connection->addr_text.data,<br>-                     s->connection->addr_text.len);<br>-<br>+        p = ngx_copy(p, client_addr.data, client_addr.len);<br>         if (s->login.len) {<br>             p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1);<br>             p = ngx_copy(p, s->login.data, s->login.len);<br>@@ -1099,6 +1100,7 @@<br>     pcf->enable = NGX_CONF_UNSET;<br>     pcf->pass_error_message = NGX_CONF_UNSET;<br>     pcf->xclient = NGX_CONF_UNSET;<br>+    pcf->proxy_protocol = NGX_CONF_UNSET;<br>     pcf->buffer_size = NGX_CONF_UNSET_SIZE;<br>     pcf->timeout = NGX_CONF_UNSET_MSEC;<br> <br>@@ -1115,6 +1117,7 @@<br>     ngx_conf_merge_value(conf-><wbr>enable, prev->enable, 0);<br>     ngx_conf_merge_value(conf-><wbr>pass_error_message, prev->pass_error_message, 0);<br>     ngx_conf_merge_value(conf-><wbr>xclient, prev->xclient, 1);<br>+    ngx_conf_merge_value(conf-><wbr>proxy_protocol, prev->proxy_protocol, 0);<br>     ngx_conf_merge_size_value(<wbr>conf->buffer_size, prev->buffer_size,<br>                               (size_t) ngx_pagesize);<br>     ngx_conf_merge_msec_value(<wbr>conf->timeout, prev->timeout, 24 * 60 * 60000);<br>diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail_proxy_<wbr>module.h<br>--- /dev/null  Thu Jan 01 00:00:00 1970 +0000<br>+++ b/src/mail/ngx_mail_proxy_<wbr>module.h Wed Nov 02 12:53:46 2016 -0700<br>@@ -0,0 +1,29 @@<br>+<br>+/*<br>+ * Copyright (C) Igor Sysoev<br>+ * Copyright (C) Nginx, Inc.<br>+ */<br>+<br>+<br>+#ifndef _NGX_MAIL_PROXY_MODULE_H_<wbr>INCLUDED_<br>+#define _NGX_MAIL_PROXY_MODULE_H_<wbr>INCLUDED_<br>+<br>+<br>+#include <ngx_config.h><br>+#include <ngx_core.h><br>+<br>+<br>+typedef struct {<br>+    ngx_flag_t  enable;<br>+    ngx_flag_t  pass_error_message;<br>+    ngx_flag_t  xclient;<br>+    ngx_flag_t  proxy_protocol;<br>+    size_t      buffer_size;<br>+    ngx_msec_t  timeout;<br>+} ngx_mail_proxy_conf_t;<br>+<br>+<br>+extern ngx_module_t  ngx_mail_proxy_module;<br>+<br>+<br>+#endif /* _NGX_MAIL_PROXY_MODULE_H_<wbr>INCLUDED_ */<br><br><div><br></div>Cheers<br>Maxim Vladimirskiy<br>GitHub Profile: <a href="https://github.com/horkhe" target="_blank">https://github.com/horkhe</a></div></div>