# HG changeset patch # User Kees Bos <cornelis....@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; _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel