Welcome! Log In Create A New Profile

Advanced

[PATCH] Add support for Proxy Protocol to mail SMTP

Maxim Vladimirsky
November 03, 2016 12:42PM
Hi Folks,

I was not sure if you would be interested in this, but decided to run it by
you anyway.

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 (http://docs.aws.amazon.com/elasticloadbalancing/latest/
classic/enable-proxy-protocol.html#proxy-protocol) 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.

Here it is:

# HG changeset patch
# User Maxim Vladimirskiy <maxim@mailgunhq.com>
# Date 1478116426 25200
# Wed Nov 02 12:53:46 2016 -0700
# Node ID fcb527c8ade6db113acbee677f321fa0249348a2
# Parent 0fba3ed4e7eba474e3f518763d9e02851c9ff024
Add support for Proxy Protocol to mail SMTP

When nginx is not the first proxy in a proxy chain it needs to be able to
understand the Proxy Protocol Header to retrieve client IP and pass it
downstream in an XCLIENT command. With these changes one can do
that by setting `proxy_protocol on;` in the mail module config.

diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail.h
--- a/src/mail/ngx_mail.h Wed Nov 02 20:05:21 2016 +0300
+++ b/src/mail/ngx_mail.h Wed Nov 02 12:53:46 2016 -0700
@@ -185,6 +185,7 @@
void **ctx;
void **main_conf;
void **srv_conf;
+ ngx_mail_addr_conf_t *addr_conf;

ngx_resolver_ctx_t *resolver_ctx;

diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail_handler.c
--- a/src/mail/ngx_mail_handler.c Wed Nov 02 20:05:21 2016 +0300
+++ b/src/mail/ngx_mail_handler.c Wed Nov 02 12:53:46 2016 -0700
@@ -9,9 +9,12 @@
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_mail.h>
+#include <ngx_mail_proxy_module.h>


static void ngx_mail_init_session(ngx_connection_t *c);
+static void ngx_mail_proxy_protocol_handler(ngx_event_t *rev);
+static void ngx_mail_init_session_handler(ngx_event_t *rev);

#if (NGX_MAIL_SSL)
static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t
*c);
@@ -34,6 +37,8 @@
ngx_mail_session_t *s;
ngx_mail_addr_conf_t *addr_conf;
ngx_mail_core_srv_conf_t *cscf;
+ ngx_mail_proxy_conf_t *pcf;
+ ngx_event_t *rev;
u_char text[NGX_SOCKADDR_STRLEN];
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
@@ -128,6 +133,7 @@

s->main_conf = addr_conf->ctx->main_conf;
s->srv_conf = addr_conf->ctx->srv_conf;
+ s->addr_conf = addr_conf;

s->addr_text = &addr_conf->addr_text;

@@ -159,10 +165,31 @@

c->log_error = NGX_ERROR_INFO;

+ rev = c->read;
+
+ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+ if (pcf->proxy_protocol) {
+ rev->handler = ngx_mail_proxy_protocol_handler;
+ ngx_mail_proxy_protocol_handler(rev);
+ return;
+ }
+
+ ngx_mail_init_session_handler(rev);
+}
+
+
+static void
+ngx_mail_init_session_handler(ngx_event_t *rev)
+{
+ ngx_connection_t *c;
+
+ c = rev->data;
+
#if (NGX_MAIL_SSL)
- {
ngx_mail_ssl_conf_t *sslcf;
+ ngx_mail_session_t *s;

+ s = c->data;
sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);

if (sslcf->enable) {
@@ -172,7 +199,7 @@
return;
}

- if (addr_conf->ssl) {
+ if (s->addr_conf->ssl) {

c->log->action = "SSL handshaking";

@@ -187,8 +214,6 @@
ngx_mail_ssl_init_connection(&sslcf->ssl, c);
return;
}
-
- }
#endif

ngx_mail_init_session(c);
@@ -898,3 +923,73 @@

return p;
}
+
+
+static void
+ngx_mail_proxy_protocol_handler(ngx_event_t *rev)
+{
+ ngx_mail_session_t *s;
+ ngx_mail_core_srv_conf_t *cscf;
+ u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];
+ size_t size;
+ ssize_t n;
+ ngx_connection_t *c;
+
+ c = rev->data;
+ s = c->data;
+
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
+ "read proxy protocol header");
+
+ if (rev->timedout) {
+ ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed
out");
+ ngx_mail_close_connection(c);
+ return;
+ }
+
+ if (c->close) {
+ ngx_mail_close_connection(c);
+ return;
+ }
+
+ n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http recv(): %z", n);
+
+ if (n == -1) {
+ if (ngx_socket_errno == NGX_EAGAIN) {
+ rev->ready = 0;
+
+ if (!rev->timer_set) {
+ ngx_add_timer(rev, cscf->timeout);
+ ngx_reusable_connection(c, 1);
+ }
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ ngx_mail_close_connection(c);
+ }
+ return;
+ }
+
+ ngx_connection_error(c, ngx_socket_errno, "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;
+ }
+
+ // Purge the Proxy Protocol header from the network buffer.
+ size = p - buf;
+ if (c->recv(c, buf, size) != (ssize_t) size) {
+ ngx_mail_close_connection(c);
+ return;
+ }
+
+ ngx_mail_init_session_handler(rev);
+}
\ No newline at end of file
diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail_proxy_module.c
--- a/src/mail/ngx_mail_proxy_module.c Wed Nov 02 20:05:21 2016 +0300
+++ b/src/mail/ngx_mail_proxy_module.c Wed Nov 02 12:53:46 2016 -0700
@@ -10,15 +10,7 @@
#include <ngx_event.h>
#include <ngx_event_connect.h>
#include <ngx_mail.h>
-
-
-typedef struct {
- ngx_flag_t enable;
- ngx_flag_t pass_error_message;
- ngx_flag_t xclient;
- size_t buffer_size;
- ngx_msec_t timeout;
-} ngx_mail_proxy_conf_t;
+#include <ngx_mail_proxy_module.h>


static void ngx_mail_proxy_block_read(ngx_event_t *rev);
@@ -74,6 +66,13 @@
offsetof(ngx_mail_proxy_conf_t, xclient),
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
};

@@ -456,6 +455,7 @@
ngx_mail_session_t *s;
ngx_mail_proxy_conf_t *pcf;
ngx_mail_core_srv_conf_t *cscf;
+ ngx_str_t client_addr;

ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
"mail proxy smtp auth handler");
@@ -525,9 +525,12 @@

s->connection->log->action = "sending XCLIENT to upstream";

- line.len = sizeof("XCLIENT ADDR= LOGIN= NAME="
- CRLF) - 1
- + s->connection->addr_text.len + s->login.len +
s->host.len;
+ client_addr = s->connection->addr_text;
+ if (s->connection->proxy_protocol_addr.data != NULL) {
+ client_addr = s->connection->proxy_protocol_addr;
+ }
+ line.len = sizeof("XCLIENT ADDR= LOGIN= NAME=" CRLF) - 1
+ + client_addr.len + s->login.len + s->host.len;

#if (NGX_HAVE_INET6)
if (s->connection->sockaddr->sa_family == AF_INET6) {
@@ -549,9 +552,7 @@
}
#endif

- p = ngx_copy(p, s->connection->addr_text.data,
- s->connection->addr_text.len);
-
+ p = ngx_copy(p, client_addr.data, client_addr.len);
if (s->login.len) {
p = ngx_cpymem(p, " LOGIN=", sizeof(" LOGIN=") - 1);
p = ngx_copy(p, s->login.data, s->login.len);
@@ -1099,6 +1100,7 @@
pcf->enable = NGX_CONF_UNSET;
pcf->pass_error_message = NGX_CONF_UNSET;
pcf->xclient = NGX_CONF_UNSET;
+ pcf->proxy_protocol = NGX_CONF_UNSET;
pcf->buffer_size = NGX_CONF_UNSET_SIZE;
pcf->timeout = NGX_CONF_UNSET_MSEC;

@@ -1115,6 +1117,7 @@
ngx_conf_merge_value(conf->enable, prev->enable, 0);
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->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);
diff -r 0fba3ed4e7eb -r fcb527c8ade6 src/mail/ngx_mail_proxy_module.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mail/ngx_mail_proxy_module.h Wed Nov 02 12:53:46 2016 -0700
@@ -0,0 +1,29 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_MAIL_PROXY_MODULE_H_INCLUDED_
+#define _NGX_MAIL_PROXY_MODULE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ ngx_flag_t enable;
+ ngx_flag_t pass_error_message;
+ ngx_flag_t xclient;
+ ngx_flag_t proxy_protocol;
+ size_t buffer_size;
+ ngx_msec_t timeout;
+} ngx_mail_proxy_conf_t;
+
+
+extern ngx_module_t ngx_mail_proxy_module;
+
+
+#endif /* _NGX_MAIL_PROXY_MODULE_H_INCLUDED_ */


Cheers
Maxim Vladimirskiy
GitHub Profile: https://github.com/horkhe
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH] Add support for Proxy Protocol to mail SMTP

Maxim Vladimirsky 641 November 03, 2016 12:42PM

Re: [PATCH] Add support for Proxy Protocol to mail SMTP

Maxim Dounin 314 November 03, 2016 01:14PM

Re: [PATCH] Add support for Proxy Protocol to mail SMTP

Maxim Vladimirsky 281 November 03, 2016 01:42PM

Re: [PATCH] Add support for Proxy Protocol to mail SMTP

Maxim Vladimirsky 474 November 03, 2016 08:12PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 311
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready