[nginx] Mail: parsing of the PROXY protocol from clients.

Maxim Dounin mdounin at mdounin.ru
Fri Mar 5 15:31:54 UTC 2021


details:   https://hg.nginx.org/nginx/rev/12ea1de7d87c
branches:  
changeset: 7794:12ea1de7d87c
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Fri Mar 05 17:16:24 2021 +0300
description:
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.

diffstat:

 src/mail/ngx_mail.c                  |   2 +
 src/mail/ngx_mail.h                  |   4 +-
 src/mail/ngx_mail_auth_http_module.c |  31 +++++++++++
 src/mail/ngx_mail_core_module.c      |   5 +
 src/mail/ngx_mail_handler.c          |  94 ++++++++++++++++++++++++++++++++++-
 5 files changed, 132 insertions(+), 4 deletions(-)

diffs (228 lines):

diff -r 44ebeeceb70e -r 12ea1de7d87c src/mail/ngx_mail.c
--- a/src/mail/ngx_mail.c	Fri Mar 05 17:16:23 2021 +0300
+++ b/src/mail/ngx_mail.c	Fri Mar 05 17:16:24 2021 +0300
@@ -405,6 +405,7 @@ ngx_mail_add_addrs(ngx_conf_t *cf, ngx_m
 #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_
 #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 -r 44ebeeceb70e -r 12ea1de7d87c src/mail/ngx_mail.h
--- a/src/mail/ngx_mail.h	Fri Mar 05 17:16:23 2021 +0300
+++ b/src/mail/ngx_mail.h	Fri Mar 05 17:16:24 2021 +0300
@@ -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 {
diff -r 44ebeeceb70e -r 12ea1de7d87c src/mail/ngx_mail_auth_http_module.c
--- a/src/mail/ngx_mail_auth_http_module.c	Fri Mar 05 17:16:23 2021 +0300
+++ b/src/mail/ngx_mail_auth_http_module.c	Fri Mar 05 17:16:24 2021 +0300
@@ -1227,6 +1227,17 @@ ngx_mail_auth_http_create_request(ngx_ma
           + 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_ma
         *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 -r 44ebeeceb70e -r 12ea1de7d87c src/mail/ngx_mail_core_module.c
--- a/src/mail/ngx_mail_core_module.c	Fri Mar 05 17:16:23 2021 +0300
+++ b/src/mail/ngx_mail_core_module.c	Fri Mar 05 17:16:24 2021 +0300
@@ -548,6 +548,11 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
 #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 44ebeeceb70e -r 12ea1de7d87c src/mail/ngx_mail_handler.c
--- a/src/mail/ngx_mail_handler.c	Fri Mar 05 17:16:23 2021 +0300
+++ b/src/mail/ngx_mail_handler.c	Fri Mar 05 17:16:24 2021 +0300
@@ -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_
     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;
@@ -178,6 +195,76 @@ ngx_mail_init_connection(ngx_connection_
 
 
 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)
 {
     ngx_connection_t    *c;
@@ -242,9 +329,10 @@ ngx_mail_ssl_init_connection(ngx_ssl_t *
 
         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;
 


More information about the nginx-devel mailing list