diff src/mail/ngx_mail_proxy_module.c @ 400:f1e2fab7a46c

Mail: smtp proxy without authentication. Activated by auth method "unauth" in smtp_auth directive. Waits for MAIL FROM and first RCPT TO from client, asks auth_http for backend with additional headers Auth-SMTP-Helo, Auth-SMTP-From, Auth-SMTP-To, and establishes connection to backend. Auth-SMTP-From/To currently contain full command (e.g. "mail from: <>"), this may change in future. The functionality was designed to take off load from real smtp servers. Additionally it may be used to implement pop-before-smtp authentication (but dont do it unless you really need it - use real auth instead). Current bug-features: - If only "unauth" method activated in config, other methods (e.g. plain, login) not advertised but accepted. Make sure your auth server handles this gracefully. - If backend server returns error on MAIL FROM / RCPT TO command while proxy tunnel setup, nginx will close connection to client with 4xx error. One may use proxy_pass_error_message directive to pass original error message to client. - Syntax of MAIL FROM / RCPT TO commands from client isn't checked.
author Maxim Dounin <mdounin@mdounin.ru>
date Sun, 22 Jul 2007 23:55:12 +0000
parents 2ceaee987f37
children 481e8f936572
line wrap: on
line diff
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -102,7 +102,8 @@ ngx_module_t  ngx_mail_proxy_module = {
 };
 
 
-static u_char  smtp_ok[] = "235 2.0.0 OK" CRLF;
+static u_char  smtp_auth_ok[] = "235 2.0.0 OK" CRLF;
+static u_char  smtp_ok[] = "250 2.0.0 OK" CRLF;
 
 
 void
@@ -516,11 +517,13 @@ ngx_mail_proxy_smtp_handler(ngx_event_t 
         p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
         *p++ = CR; *p = LF;
 
-        s->mail_state = pcf->xclient ? ngx_smtp_helo: ngx_smtp_noxclient;
+        s->mail_state = pcf->xclient ? ngx_smtp_helo_xclient :
+                        s->auth_method == NGX_MAIL_AUTH_UNAUTH ?
+                        ngx_smtp_helo_from : ngx_smtp_helo;
 
         break;
 
-    case ngx_smtp_helo:
+    case ngx_smtp_helo_xclient:
         ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
                        "mail proxy send xclient");
 
@@ -537,31 +540,77 @@ ngx_mail_proxy_smtp_handler(ngx_event_t 
             return;
         }
 
-        if (s->smtp_helo.len) {
-            line.len = ngx_sprintf(line.data,
-                           "XCLIENT PROTO=%sSMTP HELO=%V ADDR=%V LOGIN=%V "
-                           "NAME=[UNAVAILABLE]" CRLF,
-                           (s->esmtp ? "E" : ""), &s->smtp_helo,
-                           &s->connection->addr_text, &s->login)
-                       - line.data;
-        } else {
-            line.len = ngx_sprintf(line.data,
-                           "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V "
-                           "NAME=[UNAVAILABLE]" CRLF,
-                           &s->connection->addr_text, &s->login)
-                       - line.data;
+        line.len = ngx_sprintf(line.data,
+                       "XCLIENT PROTO=%sSMTP%s%V ADDR=%V%s%V "
+                       "NAME=[UNAVAILABLE]" CRLF,
+                       (s->esmtp ? "E" : ""), 
+                       (s->smtp_helo.len ? " HELO=" : ""), &s->smtp_helo,
+                       &s->connection->addr_text,
+                       (s->login.len ? " LOGIN=" : ""), &s->login)
+                   - line.data;
+
+        s->mail_state = s->auth_method == NGX_MAIL_AUTH_UNAUTH ?
+                        ngx_smtp_xclient_from : ngx_smtp_xclient;
+
+        break;
+
+    case ngx_smtp_helo_from:
+    case ngx_smtp_xclient_from:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+                       "mail proxy send mail from");
+
+        s->connection->log->action = "sending MAIL FROM to upstream";
+
+        line.len = s->smtp_from.len + sizeof(CRLF) - 1;
+        line.data = ngx_palloc(c->pool, line.len);
+        if (line.data == NULL) {
+            ngx_mail_proxy_internal_server_error(s);
+            return;
         }
 
-        s->mail_state = ngx_smtp_xclient;
+        p = ngx_cpymem(line.data, s->smtp_from.data, s->smtp_from.len);
+        *p++ = CR; *p = LF;
+
+        s->mail_state = ngx_smtp_from;
+
         break;
 
-    case ngx_smtp_noxclient:
+    case ngx_smtp_from:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+                       "mail proxy send rcpt to");
+
+        s->connection->log->action = "sending RCPT TO to upstream";
+
+        line.len = s->smtp_to.len + sizeof(CRLF) - 1;
+        line.data = ngx_palloc(c->pool, line.len);
+        if (line.data == NULL) {
+            ngx_mail_proxy_internal_server_error(s);
+            return;
+        }
+
+        p = ngx_cpymem(line.data, s->smtp_to.data, s->smtp_to.len);
+        *p++ = CR; *p = LF;
+
+        s->mail_state = ngx_smtp_to;
+
+        break;
+
+    case ngx_smtp_helo:
     case ngx_smtp_xclient:
+    case ngx_smtp_to:
 
-        ngx_memcpy(s->proxy->buffer->start, smtp_ok, sizeof(smtp_ok) - 1);
+        if (s->auth_method == NGX_MAIL_AUTH_UNAUTH) {
+            ngx_memcpy(s->proxy->buffer->start, smtp_ok, sizeof(smtp_ok) - 1);
+            s->proxy->buffer->last = s->proxy->buffer->start
+                + sizeof(smtp_ok) - 1;
+        } else {
+            ngx_memcpy(s->proxy->buffer->start, smtp_auth_ok,
+                       sizeof(smtp_auth_ok) - 1);
+            s->proxy->buffer->last = s->proxy->buffer->start
+                + sizeof(smtp_auth_ok) - 1;
+        }
 
         s->proxy->buffer->pos = s->proxy->buffer->start;
-        s->proxy->buffer->last = s->proxy->buffer->start + sizeof(smtp_ok) - 1;
 
         s->connection->read->handler = ngx_mail_proxy_handler;
         s->connection->write->handler = ngx_mail_proxy_handler;
@@ -701,15 +750,24 @@ ngx_mail_proxy_read_response(ngx_mail_se
         switch (state) {
 
         case ngx_smtp_helo:
-        case ngx_smtp_noxclient:
+        case ngx_smtp_helo_from:
+        case ngx_smtp_helo_xclient:
+        case ngx_smtp_from:
+        case ngx_smtp_to:
             if (p[0] == '2' && p[1] == '5' && p[2] == '0') {
                 return NGX_OK;
             }
             break;
 
         case ngx_smtp_start:
+            if (p[0] == '2' && p[1] == '2' && p[2] == '0') {
+                return NGX_OK;
+            }
+            break;
+
         case ngx_smtp_xclient:
-            if (p[0] == '2' && p[1] == '2' && p[2] == '0') {
+        case ngx_smtp_xclient_from:
+            if (p[0] == '2' && (p[1] == '2' || p[1] == '5') && p[2] == '0') {
                 return NGX_OK;
             }
             break;